diff --git a/error.hpp b/error.hpp index 7409e6b..c674633 100644 --- a/error.hpp +++ b/error.hpp @@ -53,11 +53,11 @@ auto create_error(const char* c_func_name, const char* c_file_name, #define create_generic_error(...) \ __create_error("generic", __VA_ARGS__) -#define assert(condition, format, ...) \ +#define assert(condition, ...) \ do { \ if (!(condition)) { \ char* msg; \ - print_to_string(&msg, format, __VA_ARGS__); \ + print_to_string(&msg, __VA_ARGS__); \ create_assertion_error("Assertion-error: %s\n" \ " condition: %s\n" \ " in: %s:%d", \ diff --git a/hashmap.hpp b/hashmap.hpp index 7c43f8e..afe1f96 100644 --- a/hashmap.hpp +++ b/hashmap.hpp @@ -44,7 +44,11 @@ struct Hash_Map { struct HM_Cell { key_type original; u64 hash; - bool deleted; + enum struct Occupancy : u8 { + Avaliable = 0, + Occupied, + Deleted + } occupancy; value_type object; }* data; @@ -55,20 +59,20 @@ struct Hash_Map { } void dealloc() { - free(data); - data = nullptr; - } + free(data); + data = nullptr; + } 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; HM_Cell cell = data[index]; - /* test if cell exists at that index */ - if (cell.original) { - /* check if strings match */ + /* 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)) { /* we found it, now check it it is deleted: */ - if (cell.deleted) { + if (cell.occupancy == HM_Cell::Occupancy::Deleted) { /* we found it but it was deleted, we */ /* dont have to check for collisions then */ return -1; @@ -77,16 +81,21 @@ struct Hash_Map { return index; } } else { - /* strings dont match, this means we have */ - /* a collision. We just search forward */ + /* 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; cell = data[new_idx]; - if (!cell.original) + /* If we find a avaliable cell while looking */ + /* forward, the object is not in the hm */ + if (cell.occupancy == HM_Cell::Occupancy::Avaliable) return -1; + /* If the objects don't match, keep looking */ if (!hm_objects_match(key, cell.original)) continue; - if (cell.deleted) + /* TODO(Felix): If the objects do match, */ + /* and it is deleted, we should return -1? */ + if (cell.occupancy == HM_Cell::Occupancy::Deleted) continue; return new_idx; } @@ -108,8 +117,11 @@ struct Hash_Map { key_type search_key_to_object(value_type v) { for (u32 i = 0; i < current_capacity; ++i) { - if (data[i].object == v && !data[i].deleted) + if (data[i].object == v && + data[i].occupancy == HM_Cell::Occupancy::Occupied) + { return data[i].original; + } } return nullptr; } @@ -120,7 +132,7 @@ struct Hash_Map { // QUESTION(Felix): Does it make sense to // ret.reserve(this->cell_count)? for (u32 i = 0; i < current_capacity; ++i) { - if (data[i].original && !data[i].deleted) + if (data[i].occupancy == HM_Cell::Occupancy::Occupied) ret.append(data[i].original); } return ret; @@ -142,15 +154,15 @@ struct Hash_Map { void delete_object(key_type key) { s32 index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key)); if (index != -1) { - data[index].deleted = true; + data[index].occupancy = HM_Cell::Occupancy::Deleted; } } void set_object(key_type key, value_type obj, u64 hash_val) { u32 index = hash_val % current_capacity; - /* if we the desired cell is just empty, write to it and done :) */ - if (!data[index].original) { + /* if we the desired cell is avaliable, write to it and done :) */ + if (data[index].occupancy == HM_Cell::Occupancy::Avaliable) { /* insert new cell into desired slot */ ++cell_count; } else { @@ -168,7 +180,7 @@ struct Hash_Map { /* insert all old items again */ for (u32 i = 0; i < current_capacity/4; ++i) { auto cell = old_data[i]; - if (cell.original) { + if (cell.occupancy == HM_Cell::Occupancy::Occupied) { set_object(cell.original, cell.object, cell.hash); } } @@ -180,7 +192,7 @@ struct Hash_Map { /* preventing gotos using lambdas! */ [&]{ for (u32 i = index; i < current_capacity; ++i) { - if (!data[i].original || + if (data[i].occupancy == HM_Cell::Occupancy::Avaliable || hm_objects_match(data[i].original, key)) { index = i; @@ -188,7 +200,7 @@ struct Hash_Map { } } for (u32 i = 0; i < index; ++i) { - if (!data[i].original || + if (data[i].occupancy == HM_Cell::Occupancy::Avaliable || hm_objects_match(data[i].original, key)) { index = i; @@ -199,7 +211,7 @@ struct Hash_Map { } } - data[index].deleted = false; + data[index].occupancy = HM_Cell::Occupancy::Occupied; data[index].original = key; data[index].hash = hash_val; data[index].object = obj; diff --git a/print.hpp b/print.hpp index 1a26e71..6ea1aa5 100644 --- a/print.hpp +++ b/print.hpp @@ -269,10 +269,14 @@ int maybe_fprintf(FILE* file, static_string format, int* pos, va_list* arg_list) // printf("\ntest:: len(%s) = %d\n", temp, writen_len+1); - writen_len = vfprintf(file, temp, *arg_list); - - // NOTE(Felix): For WSL Linux we have to manually overstep the - // used args + /// NOTE(Felix): Somehow we have to pass a copy of the list to vfprintf + // because otherwise it destroys it on some platforms :( + va_list arg_list_copy; + va_copy(arg_list_copy, *arg_list); + writen_len = vfprintf(file, temp, arg_list_copy); + va_end(arg_list_copy); + + // NOTE(Felix): maually overstep the args that vfprintf will have used for (int i = 0; i < used_arg_values; ++i) { va_arg(*arg_list, void*); } diff --git a/test.cpp b/test.cpp index 2585232..f5f3c21 100644 --- a/test.cpp +++ b/test.cpp @@ -1,62 +1,127 @@ #define _CRT_SECURE_NO_WARNINGS #include #include - #include "./types.hpp" -#include "./hooks.hpp" +u32 hm_hash(u32 u); +inline bool hm_objects_match(u32 a, u32 b); +struct Key; +u32 hm_hash(Key u); +inline bool hm_objects_match(Key a, Key b); + +#include "./error.hpp" +#include "./hooks.hpp" +#include "./hashmap.hpp" #include "./error.hpp" #include "./print.hpp" -int print_dots(FILE* f) { +u32 hm_hash(u32 u) { + return ((u64)u * 2654435761) % 4294967296; +} + +inline bool hm_objects_match(u32 a, u32 b) { + return a == b; +} + +struct Key { + int x; + int y; + int z; +}; + + +u32 hm_hash(Key u) { + return ((u.y ^ (u.x << 1)) >> 1) ^ u.z; +} + +inline bool hm_objects_match(Key a, Key b) { + return a.x == b.x + && a.y == b.y + && a.z == b.z; +} + + +auto print_dots(FILE* f) -> u32 { return print_to_file(f, "..."); } -void test_printer() { - // u32 arr[] = {1,2,3,4,1,1,3}; - // f32 f_arr[] = {1.1,2.1,3.2}; +auto test_printer() -> void { + u32 arr[] = {1,2,3,4,1,1,3}; + f32 f_arr[] = {1.1,2.1,3.2}; + - // init_printer(); - // register_printer("dots", print_dots, Printer_Function_Type::_void); + register_printer("dots", print_dots, Printer_Function_Type::_void); - // u32 u1 = -1; - // u64 u2 = -1; + u32 u1 = -1; + u64 u2 = -1; - // char* str; - // print_to_string(&str, " - %{dots[5]} %{->} <> %{->,2}\n", &u1, &arr, nullptr); - // print("---> %{->char}", str); + char* str; + print_to_string(&str, " - %{dots[5]} %{->} <> %{->,2}\n", &u1, &arr, nullptr); + print("---> %{->char}", str); - // print(" - %{dots[3]}\n"); - // print(" - %{u32} %{u64}\n", u1, u2); - // print(" - %{u32} %{u32} %{u32}\n", 2, 5, 7); - // print(" - %{f32} %{f32} %{f32}\n", 2.0, 5.0, 7.0); - // print(" - %{u32} %{bool} %{->char}\n", 2, true, "hello"); - // print(" - %{f32[3]}\n", f_arr); - // print(" - %{f32,3}\n", 44.9, 55.1, 66.2); - // print(" - %{u32[5]}\n", arr); - // print(" - %{u32[*]}\n", arr, 4); - // print(" - %{u32,5}\n", 1,2,3,4,1,2); - // print(" - %{unknown%d}\n", 1); - // print(" - %{s32,3}\n", -1,200,-300); - // print(" - %{->} <> %{->,2}\n", &u1, &arr, nullptr); + print(" - %{dots[3]}\n"); + print(" - %{u32} %{u64}\n", u1, u2); + print(" - %{u32} %{u32} %{u32}\n", 2, 5, 7); + print(" - %{f32} %{f32} %{f32}\n", 2.0, 5.0, 7.0); + print(" - %{u32} %{bool} %{->char}\n", 2, true, "hello"); + print(" - %{f32[3]}\n", f_arr); + print(" - %{f32,3}\n", 44.9, 55.1, 66.2); + print(" - %{u32[5]}\n", arr); + print(" - %{u32[*]}\n", arr, 4); + print(" - %{u32,5}\n", 1,2,3,4,1,2); + print(" - %{unknown%d}\n", 1); + print(" - %{s32,3}\n", -1,200,-300); + print(" - %{->} <> %{->,2}\n", &u1, &arr, nullptr); } -s32 main(s32 argc, char* argv[]) { +auto test_hm() -> void { + Hash_Map h1; + h1.alloc(); + defer { h1.dealloc(); }; + + h1.set_object(1, 2); + h1.set_object(2, 4); + h1.set_object(3, 6); + h1.set_object(4, 8); + + assert(h1.key_exists(1), "key shoud exist"); + assert(h1.key_exists(2), "key shoud exist"); + assert(h1.key_exists(3), "key shoud exist"); + assert(h1.key_exists(4), "key shoud exist"); + assert(!h1.key_exists(5), "key shoud not exist"); + + assert(h1.get_object(1) == 2, "value should be correct"); + assert(h1.get_object(2) == 4, "value should be correct"); + assert(h1.get_object(3) == 6, "value should be correct"); + assert(h1.get_object(4) == 8, "value should be correct"); + + + Hash_Map h2; + h2.alloc(); + defer { h2.dealloc(); }; + + h2.set_object({.x = 1, .y = 2, .z = 3}, 1); + h2.set_object({.x = 3, .y = 3, .z = 3}, 3); + + assert(h2.key_exists({.x = 1, .y = 2, .z = 3}), "key shoud exist"); + assert(h2.key_exists({.x = 3, .y = 3, .z = 3}), "key shoud exist"); - // test_printer(); + assert(h2.get_object({.x = 1, .y = 2, .z = 3}) == 1, "value should be correct"); + assert(h2.get_object({.x = 3, .y = 3, .z = 3}) == 3, "value should be correct"); + + +} + +s32 main(s32 argc, char* argv[]) { init_printer(); - create_generic_error("nothing to lex was found:\n" - " in %{color<}%{->char}%{>color}\n" - " at %{color<}%{->char}%{>color}\n" - "bottom text\n", - console_green, - "some file name", - console_cyan, - "yesssssss"); + + test_hm(); + + return 0; }