diff --git a/hashmap.hpp b/hashmap.hpp index 2a016a9..7ace602 100644 --- a/hashmap.hpp +++ b/hashmap.hpp @@ -63,6 +63,15 @@ struct Hash_Map { } void alloc(u32 initial_capacity = 8) { + // round up to next pow of 2 + --initial_capacity; + initial_capacity |= initial_capacity >> 1; + initial_capacity |= initial_capacity >> 2; + initial_capacity |= initial_capacity >> 4; + initial_capacity |= initial_capacity >> 8; + initial_capacity |= initial_capacity >> 16; + ++initial_capacity; + // until here current_capacity = initial_capacity; cell_count = 0; data = (HM_Cell*)calloc(initial_capacity, sizeof(HM_Cell)); @@ -74,13 +83,14 @@ struct Hash_Map { } s32 get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) { - // s32 index = hash_val & (current_capacity - 1); - s32 index = hash_val % current_capacity; + ZoneScoped; + s32 index = hash_val & (current_capacity - 1); HM_Cell cell = data[index]; /* test if there is or was something there */ if (cell.occupancy != HM_Cell::Occupancy::Avaliable) { /* check if objects match */ if (hm_objects_match(key, cell.original)) { + ZoneScopedN("hm_objects_match check"); /* we found it, now check it it is deleted: */ if (cell.occupancy == HM_Cell::Occupancy::Deleted) { /* we found it but it was deleted, we */ @@ -94,7 +104,7 @@ struct Hash_Map { /* objects dont match, this means we have */ /* a collision. We just search forward */ for (u32 i = 0; i < current_capacity; ++i) { - u32 new_idx = (i + index) % current_capacity; + u32 new_idx = (i + index) & (current_capacity - 1); cell = data[new_idx]; /* If we find a avaliable cell while looking */ /* forward, the object is not in the hm */ @@ -122,6 +132,7 @@ struct Hash_Map { } bool key_exists(key_type key) { + ZoneScoped; return get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key)) != -1; } @@ -157,6 +168,7 @@ struct Hash_Map { } value_type get_object(key_type key) { + ZoneScoped; return get_object(key, hm_hash((key_type)key)); } @@ -181,7 +193,8 @@ struct Hash_Map { } void set_object(key_type key, value_type obj, u64 hash_val) { - u32 index = hash_val % current_capacity; + ZoneScoped; + u32 index = hash_val & (current_capacity - 1); /* if we the desired cell is avaliable, write to it and done :) */ if (data[index].occupancy == HM_Cell::Occupancy::Avaliable) { @@ -194,6 +207,7 @@ struct Hash_Map { } else { /* collision, check resize */ if ((cell_count*1.0f / current_capacity) > 0.666f) { + ZoneScopedN("HM Resize"); auto old_data = data; data = (HM_Cell*)calloc(current_capacity*4, sizeof(HM_Cell)); cell_count = 0; @@ -207,7 +221,7 @@ struct Hash_Map { } } free(old_data); - index = hash_val % current_capacity; + index = hash_val & (current_capacity - 1); } ++cell_count; /* search for empty slot for new cell starting at desired index; */ @@ -243,4 +257,19 @@ struct Hash_Map { u64 hash_val = hm_hash((key_type)key); set_object(key, obj, hash_val); } + + void dump_occupancy(const char* path) { + FILE* out = fopen(path, "w"); + defer { fclose(out); }; + for (u32 i = 0; i < current_capacity; ++i) { + if (data[i].occupancy == HM_Cell::Occupancy::Avaliable) { + fprintf(out, "%04u [FREE]\n", i); + } else if (data[i].occupancy == HM_Cell::Occupancy::Deleted) { + fprintf(out, "%04u [DELETED] hash: %llu (wants to be %llu)\n", i, data[i].hash, data[i].hash & (current_capacity - 1)); + } else { + fprintf(out, "%04u [OCCUPIED] hash: %llu (wants to be %llu)\n", i, data[i].hash, data[i].hash & (current_capacity - 1)); + } + } + + } }; diff --git a/hooks.hpp b/hooks.hpp index 4f640c8..51296af 100644 --- a/hooks.hpp +++ b/hooks.hpp @@ -20,33 +20,33 @@ struct Lambda // which will store a pointer to the function in m_Dispatcher. template static R Dispatch(void* target, Args... args) - { - return (*(S*)target)(args...); - } + { + return (*(S*)target)(args...); + } template Lambda(T&& target) : m_Dispatcher(&Dispatch::type>) , m_Target(&target) - { - } + { + } // Specialize for reference-to-function, to ensure that a valid pointer is // stored. using TargetFunctionRef = R(Args...); Lambda(TargetFunctionRef target) : m_Dispatcher(Dispatch) - { - static_assert(sizeof(void*) == sizeof target, - "It will not be possible to pass functions by reference on this platform. " - "Please use explicit function pointers i.e. foo(target) -> foo(&target)"); - m_Target = (void*)target; - } + { + static_assert(sizeof(void*) == sizeof target, + "It will not be possible to pass functions by reference on this platform. " + "Please use explicit function pointers i.e. foo(target) -> foo(&target)"); + m_Target = (void*)target; + } R operator()(Args... args) const - { - return m_Dispatcher(m_Target, args...); - } + { + return m_Dispatcher(m_Target, args...); + } }; diff --git a/macros.hpp b/macros.hpp index 94e9975..4280ab7 100644 --- a/macros.hpp +++ b/macros.hpp @@ -6,9 +6,12 @@ #define label(x, y) concat(x, y) #define line_label(x) label(x, __LINE__) +#ifndef min #define min(a, b) ((a) < (b)) ? (a) : (b) +#endif +#ifndef max #define max(a, b) ((a) > (b)) ? (a) : (b) - +#endif /** * Defer * diff --git a/print.hpp b/print.hpp index 569bec4..f88780e 100644 --- a/print.hpp +++ b/print.hpp @@ -7,6 +7,9 @@ #include #include +#ifdef FTB_WINDOWS +#include +#endif #include "platform.hpp" #include "hashmap.hpp" #include "hooks.hpp" diff --git a/test.cpp b/test.cpp index b5949f6..fbc412b 100644 --- a/test.cpp +++ b/test.cpp @@ -9,6 +9,9 @@ struct Key; u32 hm_hash(Key u); inline bool hm_objects_match(Key a, Key b); +#define ZoneScoped +#define ZoneScopedN(name) + #include "./error.hpp" #include "./hooks.hpp" #include "./hashmap.hpp" @@ -127,7 +130,7 @@ auto test_hm() -> void { s32 main(s32 argc, char* argv[]) { init_printer(); - test_printer(); + test_hm(); print("done.");