Fix inputs and add methods

This commit is contained in:
2026-05-07 13:55:02 +01:00
parent a77f75dcf4
commit 0f693a5de0
12 changed files with 500 additions and 93 deletions
+33 -1
View File
@@ -180,6 +180,8 @@ struct Scene {
element_pool[id]->click();
}
#warning "This does not take rotation into account \
reference and use reverse-transform on point then AABB check instead"
std::vector<uint64_t> elements_at(Vec2<float> position) {
std::vector<uint64_t> result;
@@ -211,6 +213,11 @@ struct App {
uint64_t current_scene_id = 0;
bool running = true;
Vec2<float> mouse_position = {-1, -1};
std::array<bool, 600> down_keys{};
std::vector<Key> pressed_keys;
std::vector<Key> released_keys;
Vec2<float> scroll = {0, 0};
std::string text = "";
void exit() {
running = false;
@@ -246,6 +253,11 @@ struct App {
Scene *scene = scene_pool[current_scene_id];
pressed_keys.clear();
released_keys.clear();
scroll = {0, 0};
text = "";
Event e;
while (window.poll(e)) {
switch (e.type) {
@@ -254,6 +266,12 @@ struct App {
break;
case Event::MOUSE_BUTTON_DOWN:
scene->click(e.mouse_button.position);
down_keys[e.mouse_button.button] = true;
pressed_keys.push_back(e.mouse_button.button);
break;
case Event::MOUSE_BUTTON_UP:
down_keys[e.mouse_button.button] = false;
released_keys.push_back(e.mouse_button.button);
break;
case Event::MOUSE_MOVE:
mouse_position = e.mouse_move.position;
@@ -261,10 +279,24 @@ struct App {
case Event::MOUSE_LEAVE:
mouse_position = {-1, -1};
break;
case Event::KEY_DOWN:
down_keys[e.key.key] = true;
pressed_keys.push_back(e.key.key);
break;
case Event::KEY_UP:
down_keys[e.key.key] = false;
released_keys.push_back(e.key.key);
break;
case Event::SCROLL:
scroll = e.scroll;
break;
case Event::TEXT_INPUT:
text += *e.text_input;
delete e.text_input;
break;
default:
break;
}
window.consume(e);
}
scene->update_scene(dt);
+85 -1
View File
@@ -134,6 +134,16 @@ static mrb_value image_hash(mrb_state *mrb, mrb_value self) {
return mrb_fixnum_value(id);
}
static mrb_value image_width(mrb_state *mrb, mrb_value self) {
uint64_t id = get_id_Image(mrb, self);
return mrb_float_value(mrb, window.get_image_size(id).x);
}
static mrb_value image_height(mrb_state *mrb, mrb_value self) {
uint64_t id = get_id_Image(mrb, self);
return mrb_float_value(mrb, window.get_image_size(id).y);
}
static void Animation_free(mrb_state *mrb, void *ptr) {
UNUSED(mrb);
uint64_t id = ((Wrapper *)ptr)->id;
@@ -578,6 +588,18 @@ static mrb_value element_text_click_through_set(mrb_state *mrb, mrb_value self)
return mrb_nil_value();
}
static mrb_value element_text_width(mrb_state *mrb, mrb_value self) {
uint64_t id = get_id_ElementText(mrb, self);
app::EText *element = (app::EText *)app::element_pool[id];
return mrb_float_value(mrb, element->size(&window).x);
}
static mrb_value element_text_height(mrb_state *mrb, mrb_value self) {
uint64_t id = get_id_ElementText(mrb, self);
app::EText *element = (app::EText *)app::element_pool[id];
return mrb_float_value(mrb, element->size(&window).y);
}
static void ElementRect_free(mrb_state *mrb, void *ptr) {
UNUSED(mrb);
uint64_t id = ((Wrapper *)ptr)->id;
@@ -1413,6 +1435,58 @@ static mrb_value app_mouse_position(mrb_state *mrb, mrb_value) {
return result;
}
static mrb_value app_is_down(mrb_state *mrb, mrb_value) {
mrb_sym key_sym;
mrb_get_args(mrb, "n", &key_sym);
std::string key_name = mrb_sym2name(mrb, key_sym);
Key key = get_key(key_name);
return mrb_bool_value(app_->down_keys[key]);
}
static mrb_value app_is_pressed(mrb_state *mrb, mrb_value) {
mrb_sym key_sym;
mrb_get_args(mrb, "n", &key_sym);
std::string key_name = mrb_sym2name(mrb, key_sym);
Key key = get_key(key_name);
for (Key pressed_key : app_->pressed_keys)
if (pressed_key == key)
return mrb_bool_value(true);
return mrb_bool_value(false);
}
static mrb_value app_is_released(mrb_state *mrb, mrb_value) {
mrb_sym key_sym;
mrb_get_args(mrb, "n", &key_sym);
std::string key_name = mrb_sym2name(mrb, key_sym);
Key key = get_key(key_name);
for (Key released_key : app_->released_keys)
if (released_key == key)
return mrb_bool_value(true);
return mrb_bool_value(false);
}
static mrb_value app_map_key(mrb_state *mrb, mrb_value) {
mrb_sym key_sym;
mrb_sym action_sym;
mrb_get_args(mrb, "nn", &key_sym, &action_sym);
std::string key_name = mrb_sym2name(mrb, key_sym);
std::string action_name = mrb_sym2name(mrb, action_sym);
set_action_mapping(action_name, key_name);
return mrb_nil_value();
}
static mrb_value app_scroll(mrb_state *mrb, mrb_value) {
Vec2<float> scroll = app_->scroll;
mrb_value result = mrb_hash_new(mrb);
HASH_SET(result, x, mrb_float_value(mrb, scroll.x));
HASH_SET(result, y, mrb_float_value(mrb, scroll.y));
return result;
}
static mrb_value app_text_input(mrb_state *mrb, mrb_value) {
return mrb_str_new_cstr(mrb, app_->text.c_str());
}
static mrb_value app_exit(mrb_state *, mrb_value) {
app_->exit();
return mrb_nil_value();
@@ -1428,6 +1502,8 @@ inline void setup() {
ADD_METHOD(Image, "==", image_equal, MRB_ARGS_REQ(1));
ADD_METHOD(Image, "eql?", image_equal, MRB_ARGS_REQ(1));
ADD_METHOD(Image, "hash", image_hash, MRB_ARGS_NONE());
ADD_METHOD(Image, "width", image_width, MRB_ARGS_NONE());
ADD_METHOD(Image, "height", image_height, MRB_ARGS_NONE());
DEF_CLASS(Animation, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1));
ADD_METHOD(Animation, "==", animation_equal, MRB_ARGS_REQ(1));
@@ -1463,6 +1539,8 @@ inline void setup() {
ADD_METHOD(ElementText, "z", element_text_z_get, MRB_ARGS_NONE());
ADD_METHOD(ElementText, "click_through=", element_text_click_through_set, MRB_ARGS_REQ(1));
ADD_METHOD(ElementText, "click_through", element_text_click_through_get, MRB_ARGS_NONE());
ADD_METHOD(ElementText, "width", element_text_width, MRB_ARGS_NONE());
ADD_METHOD(ElementText, "height", element_text_height, MRB_ARGS_NONE());
DEF_CLASS(ElementRect, MRB_ARGS_REQ(3) | MRB_ARGS_OPT(1));
ADD_METHOD(ElementRect, "==", element_rect_equal, MRB_ARGS_REQ(1));
@@ -1527,7 +1605,13 @@ inline void setup() {
ADD_MODULE_METHOD(App, "language=", app_language_set, MRB_ARGS_REQ(1));
ADD_MODULE_METHOD(App, "language", app_language_get, MRB_ARGS_NONE());
ADD_MODULE_METHOD(App, "mouse_position", app_mouse_position, MRB_ARGS_NONE());
ADD_MODULE_METHOD(App, "exit", app_exit, MRB_ARGS_NONE());
ADD_MODULE_METHOD(App, "down?", app_is_down, MRB_ARGS_REQ(1));
ADD_MODULE_METHOD(App, "pressed?", app_is_pressed, MRB_ARGS_REQ(1));
ADD_MODULE_METHOD(App, "released?", app_is_released, MRB_ARGS_REQ(1));
ADD_MODULE_METHOD(App, "map_key", app_map_key, MRB_ARGS_REQ(2));
ADD_MODULE_METHOD(App, "scroll", app_scroll, MRB_ARGS_NONE());
ADD_MODULE_METHOD(App, "text_input", app_text_input, MRB_ARGS_NONE());
ADD_MODULE_METHOD(App, "exit!", app_exit, MRB_ARGS_NONE());
}
} // namespace definitions
+219 -22
View File
@@ -40,6 +40,220 @@ inline Pool<Font> font_pool;
// Text pool
inline Pool<Text> text_pool;
enum Key : uint16_t {
Unknown = SDL_SCANCODE_UNKNOWN,
A = SDL_SCANCODE_A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Num0 = SDL_SCANCODE_0,
Num1,
Num2,
Num3,
Num4,
Num5,
Num6,
Num7,
Num8,
Num9,
Space = SDL_SCANCODE_SPACE,
Enter = SDL_SCANCODE_RETURN,
Escape = SDL_SCANCODE_ESCAPE,
Tab = SDL_SCANCODE_TAB,
Backspace = SDL_SCANCODE_BACKSPACE,
LeftShift = SDL_SCANCODE_LSHIFT,
RightShift = SDL_SCANCODE_RSHIFT,
LeftCtrl = SDL_SCANCODE_LCTRL,
RightCtrl = SDL_SCANCODE_RCTRL,
LeftAlt = SDL_SCANCODE_LALT,
RightAlt = SDL_SCANCODE_RALT,
CapsLock = SDL_SCANCODE_CAPSLOCK,
Up = SDL_SCANCODE_UP,
Down = SDL_SCANCODE_DOWN,
Left = SDL_SCANCODE_LEFT,
Right = SDL_SCANCODE_RIGHT,
Home = SDL_SCANCODE_HOME,
End = SDL_SCANCODE_END,
PageUp = SDL_SCANCODE_PAGEUP,
PageDown = SDL_SCANCODE_PAGEDOWN,
Delete = SDL_SCANCODE_DELETE,
Insert = SDL_SCANCODE_INSERT,
Minus = SDL_SCANCODE_MINUS,
Equals = SDL_SCANCODE_EQUALS,
LeftBracket = SDL_SCANCODE_LEFTBRACKET,
RightBracket = SDL_SCANCODE_RIGHTBRACKET,
Semicolon = SDL_SCANCODE_SEMICOLON,
Apostrophe = SDL_SCANCODE_APOSTROPHE,
Grave = SDL_SCANCODE_GRAVE,
Comma = SDL_SCANCODE_COMMA,
Period = SDL_SCANCODE_PERIOD,
Slash = SDL_SCANCODE_SLASH,
Backslash = SDL_SCANCODE_NONUSBACKSLASH,
F1 = SDL_SCANCODE_F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
MouseLeft = 513,
MouseMiddle,
MouseRight
};
constexpr std::pair<std::string, Key> KEY_NAMES[] = {
{"a", Key::A},
{"b", Key::B},
{"c", Key::C},
{"d", Key::D},
{"e", Key::E},
{"f", Key::F},
{"g", Key::G},
{"h", Key::H},
{"i", Key::I},
{"j", Key::J},
{"k", Key::K},
{"l", Key::L},
{"m", Key::M},
{"n", Key::N},
{"o", Key::O},
{"p", Key::P},
{"q", Key::Q},
{"r", Key::R},
{"s", Key::S},
{"t", Key::T},
{"u", Key::U},
{"v", Key::V},
{"w", Key::W},
{"x", Key::X},
{"y", Key::Y},
{"z", Key::Z},
{"num0", Key::Num0},
{"num1", Key::Num1},
{"num2", Key::Num2},
{"num3", Key::Num3},
{"num4", Key::Num4},
{"num5", Key::Num5},
{"num6", Key::Num6},
{"num7", Key::Num7},
{"num8", Key::Num8},
{"num9", Key::Num9},
{"space", Key::Space},
{"enter", Key::Enter},
{"escape", Key::Escape},
{"tab", Key::Tab},
{"backspace", Key::Backspace},
{"left_shift", Key::LeftShift},
{"right_shift", Key::RightShift},
{"left_ctrl", Key::LeftCtrl},
{"right_ctrl", Key::RightCtrl},
{"left_alt", Key::LeftAlt},
{"right_alt", Key::RightAlt},
{"capslock", Key::CapsLock},
{"up", Key::Up},
{"down", Key::Down},
{"left", Key::Left},
{"right", Key::Right},
{"home", Key::Home},
{"end", Key::End},
{"page_up", Key::PageUp},
{"page_down", Key::PageDown},
{"delete", Key::Delete},
{"insert", Key::Insert},
{"minus", Key::Minus},
{"equals", Key::Equals},
{"left_bracket", Key::LeftBracket},
{"right_bracket", Key::RightBracket},
{"semicolon", Key::Semicolon},
{"apostrophe", Key::Apostrophe},
{"grave", Key::Grave},
{"comma", Key::Comma},
{"period", Key::Period},
{"slash", Key::Slash},
{"backslash", Key::Backslash},
{"f1", Key::F1},
{"f2", Key::F2},
{"f3", Key::F3},
{"f4", Key::F4},
{"f5", Key::F5},
{"f6", Key::F6},
{"f7", Key::F7},
{"f8", Key::F8},
{"f9", Key::F9},
{"f10", Key::F10},
{"f11", Key::F11},
{"f12", Key::F12},
{"mouse_left", Key::MouseLeft},
{"mouse_middle", Key::MouseMiddle},
{"mouse_right", Key::MouseRight}
};
inline Key get_key_from_name(std::string_view name) {
for (const auto &[key_name, key] : KEY_NAMES)
if (key_name == name)
return key;
return Key::Unknown;
}
inline std::unordered_map<std::string, Key> action_key_map;
inline void set_action_mapping(const std::string &action_name, const std::string &key_name) {
Key key = get_key_from_name(key_name);
if (key != Key::Unknown)
action_key_map[action_name] = key;
}
inline Key get_key(std::string &name) {
auto it = action_key_map.find(name);
if (it != action_key_map.end())
return it->second;
return get_key_from_name(name);
}
struct Event {
enum Type {
NONE,
@@ -56,20 +270,15 @@ struct Event {
union {
struct {
uint32_t key;
Key key;
} key;
struct {
char *text;
uint32_t length;
} text_input;
std::string *text_input;
Vec2<float> scroll;
struct {
float x, y;
} scroll;
struct {
uint8_t button;
Key button;
Vec2<float> position;
} mouse_button;
@@ -125,16 +334,6 @@ public:
bool poll(Event &event); // returns true if an event was polled, false otherwise
// consumes an event, (mostly for text input, to free the text input buffer)
// but also so the user can decide when they're done with the event explicitly.
void consume(Event &event);
// Text input
// Starts accepting Unicode text input events, and stops acceptong normal key down/up events for those keys.
void start_text_input();
void stop_text_input();
// Clipboard get
// To be free'd by the caller after use.
@@ -190,8 +389,6 @@ private:
std::vector<struct RenderInstruction> render_instructions;
bool text_input_active;
void compute_transform();
bool mouse_in_window(const Vec2<float> real_position, Vec2<float> &virtual_position);
+12 -38
View File
@@ -12,7 +12,7 @@ bg_animation = Animation.new [bg_image1, bg_image2], fps: 5
App.language = :en
App.localize(:en, :btn_text, "Click %{name}!")
text = ElementText.new :btn_text, default_font, 0xFFFFFF, {name: "Me"}, position: {x: 50, y: 50}, z: 1, click_through: true, alpha: 1
text = ElementText.new :btn_text, default_font, 0xFFFF00, {name: "Me"}, position: {x: 50, y: 50}, z: 1, click_through: true, alpha: 1
rect = ElementRect.new 100, 25, 0xFF0000, position: {x: 50, y: 50}, z: 0, rotation: 60, scale: { x: 1.5, y: 1 }, alpha: 0.4
@@ -28,40 +28,7 @@ rect.on_click do
text.params!
end
=begin
input handling:
App.map_key(:space, :jump) # maps the space key to a :jump action (multiple keys can be mapped to the same action)
# all events here are in english ones, (so need to find which english key corresponds to the key in the current language of the keyboard)
key can be one of [:a..:z, :0..:9, :space, :enter, :shift, :ctrl, :alt, :tab, :backspace, :escape, :up, :down, :left, :right, :middle]
this can be checked anywhere using:
App.down?(:jump) # returns true if the jump action is currently being pressed
App.pressed?(:jump) # returns true if the jump action was just pressed this frame
App.released?(:jump) # returns true if the jump action was just released this frame
for wheel, you can use:
App.wheel # returns a hash with :x and :y values representing the wheel movement since the last frame (can be used for zooming, scrolling, etc.)
mouse position can be accessed with:
App.mouse_position # returns a hash with :x and :y values representing the current mouse position in the window
For localized input, you can use:
App.start_text_input!
App.text_input # returns the text typed this frame as a string (useful for text input fields, chat, etc.)
# can be multiple characters if the user types fast, so you should append it to a string variable to get the full input
App.stop_text_input!
=end
App.map_key :mouse_left, :press
main_scene.on_update do |delta_time|
# puts "Delta time: #{delta_time}ms"
@@ -69,13 +36,20 @@ main_scene.on_update do |delta_time|
# runs at 60fps, so you should see around 16-17ms being printed
el = main_scene.elements_at(App.mouse_position)
puts App.text_input if App.text_input != ""
next unless App.pressed?(:press)
puts "#{App.pressed?(:press)}, #{App.down?(:press)}, #{App.released?(:press)}"
for elem in el
if elem == image_element
#puts "Hovering over image element"
puts "Down over image element"
elsif elem == rect
#puts "Hovering over rect element"
puts "Down over rect element"
elsif elem == text
#puts "Hovering over text element"
puts "Down over text element"
end
end
+6 -31
View File
@@ -15,7 +15,7 @@ Window::Window(Vec2<float> size, const char *title) {
compute_transform();
text_input_active = false;
SDL_StartTextInput(window);
white_tex = SDL_CreateTexture(
renderer,
@@ -370,22 +370,17 @@ bool Window::poll(Event &event) {
case SDL_EVENT_KEY_DOWN:
event.type = Event::KEY_DOWN;
event.key.key = sdl_event.key.scancode;
event.key.key = (Key)sdl_event.key.scancode;
break;
case SDL_EVENT_KEY_UP:
event.type = Event::KEY_UP;
event.key.key = sdl_event.key.scancode;
event.key.key = (Key)sdl_event.key.scancode;
break;
case SDL_EVENT_TEXT_INPUT:
if (!text_input_active)
return false;
event.type = Event::TEXT_INPUT;
event.text_input.length = strlen(sdl_event.text.text);
event.text_input.text = (char *)malloc(event.text_input.length + 1);
strcpy(event.text_input.text, sdl_event.text.text);
event.text_input.text[event.text_input.length] = '\0';
event.text_input = new std::string(sdl_event.text.text);
break;
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
@@ -394,7 +389,7 @@ bool Window::poll(Event &event) {
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
event.type = Event::MOUSE_BUTTON_DOWN;
event.mouse_button.button = sdl_event.button.button;
event.mouse_button.button = (Key)(sdl_event.button.button + 512);
Vec2<float> virtual_position;
if (mouse_in_window({sdl_event.button.x, sdl_event.button.y}, virtual_position))
event.mouse_button.position = virtual_position;
@@ -404,7 +399,7 @@ bool Window::poll(Event &event) {
case SDL_EVENT_MOUSE_BUTTON_UP: {
event.type = Event::MOUSE_BUTTON_UP;
event.mouse_button.button = sdl_event.button.button;
event.mouse_button.button = (Key)(sdl_event.button.button + 512);
Vec2<float> virtual_position;
if (mouse_in_window({sdl_event.button.x, sdl_event.button.y}, virtual_position))
event.mouse_button.position = virtual_position;
@@ -444,26 +439,6 @@ bool Window::poll(Event &event) {
return false;
}
void Window::consume(Event &event) {
if (event.type == Event::TEXT_INPUT) {
free(event.text_input.text);
event.text_input.text = nullptr;
event.text_input.length = 0;
}
event.type = Event::NONE;
}
void Window::start_text_input() {
text_input_active = true;
SDL_StartTextInput(window);
}
void Window::stop_text_input() {
text_input_active = false;
SDL_StopTextInput(window);
}
const char *Window::paste() {
const char *clipboard_text = SDL_GetClipboardText();
if (clipboard_text == nullptr) {
Executable
BIN
View File
Binary file not shown.
+90
View File
@@ -0,0 +1,90 @@
#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
using namespace std::chrono;
int N = 1000000; // 1,000,000 tries
int L = 20; // string length
string random_string(size_t length) {
static const string chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static random_device rd;
static mt19937 gen(rd());
uniform_int_distribution<> dist(0, chars.size() - 1);
string s;
for (size_t i = 0; i < length; i++) {
s += chars[dist(gen)];
}
return s;
}
void test_array(int length) {
std::unordered_map<std::string, int> hash_map;
hash_map.reserve(length * 2); // Reserve more to avoid rehashing
std::vector<std::pair<std::string, int>> array;
array.reserve(length);
vector<string> keys;
for (int i = 0; i < length; ++i) {
string key = random_string(L);
keys.push_back(key);
hash_map[key] = i;
array.emplace_back(key, i);
}
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < N; ++i) {
string &key = keys[i % length];
auto it = hash_map.find(key);
volatile int value = it->second;
(void)value;
}
auto end = std::chrono::high_resolution_clock::now();
auto hash_duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < N; ++i) {
string &key = keys[i % length];
auto it = std::find_if(array.begin(), array.end(), [&key](const auto &pair) {
return pair.first == key;
});
volatile int value = it->second;
(void)value;
}
end = std::chrono::high_resolution_clock::now();
auto array_duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
std::cout << length << "," << hash_duration << "," << array_duration << "\n";
}
int main() {
std::cout << "elements,hash,array\n";
for (int length = 1; length <= 10; length++)
test_array(length);
for (int length = 10; length <= 100; length += 10)
test_array(length);
for (int length = 100; length <= 1000; length += 100)
test_array(length);
return 0;
}
+31
View File
@@ -0,0 +1,31 @@
elements,hash,array
1,53,36
2,57,49
3,83,65
4,99,84
5,117,99
6,132,115
7,145,128
8,163,141
9,174,156
10,191,167
10,190,169
20,339,306
30,74,442
40,71,579
50,78,719
60,74,874
70,75,1064
80,83,1244
90,83,1394
100,85,1477
100,86,1485
200,80,2912
300,82,4401
400,82,5946
500,83,7526
600,84,9256
700,86,10927
800,88,12828
900,89,14502
1000,90,16302
1 elements hash array
2 1 53 36
3 2 57 49
4 3 83 65
5 4 99 84
6 5 117 99
7 6 132 115
8 7 145 128
9 8 163 141
10 9 174 156
11 10 191 167
12 10 190 169
13 20 339 306
14 30 74 442
15 40 71 579
16 50 78 719
17 60 74 874
18 70 75 1064
19 80 83 1244
20 90 83 1394
21 100 85 1477
22 100 86 1485
23 200 80 2912
24 300 82 4401
25 400 82 5946
26 500 83 7526
27 600 84 9256
28 700 86 10927
29 800 88 12828
30 900 89 14502
31 1000 90 16302
Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

+24
View File
@@ -0,0 +1,24 @@
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv("benchmark.csv")
plt.figure(figsize=(10, 6))
plt.plot(df["elements"], df["hash"], marker='o', label="Hash map")
plt.plot(df["elements"], df["array"], marker='o', label="Array")
# LOG SCALE
plt.xscale("log")
plt.yscale("log")
plt.xlabel("Number of elements (log scale)")
plt.ylabel("Time (ms) (log scale)")
plt.title("Array vs Hash Map Lookup Performance")
plt.grid(True, which="both", linestyle="--", alpha=0.5)
plt.legend()
plt.show()
plt.savefig("benchmark.png", dpi=200, bbox_inches="tight")
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB