hashmap can now take non scalar types as keys
This commit is contained in:
@@ -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", \
|
||||
|
||||
+33
-21
@@ -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): 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): For WSL Linux we have to manually overstep the
|
||||
// used args
|
||||
// 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);
|
||||
|
||||
// u32 u1 = -1;
|
||||
// u64 u2 = -1;
|
||||
register_printer("dots", print_dots, Printer_Function_Type::_void);
|
||||
|
||||
u32 u1 = -1;
|
||||
u64 u2 = -1;
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
// 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);
|
||||
|
||||
}
|
||||
|
||||
s32 main(s32 argc, char* argv[]) {
|
||||
|
||||
// test_printer();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user