| @@ -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", \ | |||
| @@ -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; | |||
| @@ -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*); | |||
| } | |||
| @@ -1,62 +1,127 @@ | |||
| #define _CRT_SECURE_NO_WARNINGS | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #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<u32, u32> 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<Key, u32> 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; | |||
| } | |||