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(...) \
|
#define create_generic_error(...) \
|
||||||
__create_error("generic", __VA_ARGS__)
|
__create_error("generic", __VA_ARGS__)
|
||||||
|
|
||||||
#define assert(condition, format, ...) \
|
#define assert(condition, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (!(condition)) { \
|
if (!(condition)) { \
|
||||||
char* msg; \
|
char* msg; \
|
||||||
print_to_string(&msg, format, __VA_ARGS__); \
|
print_to_string(&msg, __VA_ARGS__); \
|
||||||
create_assertion_error("Assertion-error: %s\n" \
|
create_assertion_error("Assertion-error: %s\n" \
|
||||||
" condition: %s\n" \
|
" condition: %s\n" \
|
||||||
" in: %s:%d", \
|
" in: %s:%d", \
|
||||||
|
|||||||
+29
-17
@@ -44,7 +44,11 @@ struct Hash_Map {
|
|||||||
struct HM_Cell {
|
struct HM_Cell {
|
||||||
key_type original;
|
key_type original;
|
||||||
u64 hash;
|
u64 hash;
|
||||||
bool deleted;
|
enum struct Occupancy : u8 {
|
||||||
|
Avaliable = 0,
|
||||||
|
Occupied,
|
||||||
|
Deleted
|
||||||
|
} occupancy;
|
||||||
value_type object;
|
value_type object;
|
||||||
}* data;
|
}* data;
|
||||||
|
|
||||||
@@ -63,12 +67,12 @@ struct Hash_Map {
|
|||||||
// s32 index = hash_val & (current_capacity - 1);
|
// s32 index = hash_val & (current_capacity - 1);
|
||||||
s32 index = hash_val % current_capacity;
|
s32 index = hash_val % current_capacity;
|
||||||
HM_Cell cell = data[index];
|
HM_Cell cell = data[index];
|
||||||
/* test if cell exists at that index */
|
/* test if there is or was something there */
|
||||||
if (cell.original) {
|
if (cell.occupancy != HM_Cell::Occupancy::Avaliable) {
|
||||||
/* check if strings match */
|
/* check if objects match */
|
||||||
if (hm_objects_match(key, cell.original)) {
|
if (hm_objects_match(key, cell.original)) {
|
||||||
/* we found it, now check it it is deleted: */
|
/* 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 */
|
/* we found it but it was deleted, we */
|
||||||
/* dont have to check for collisions then */
|
/* dont have to check for collisions then */
|
||||||
return -1;
|
return -1;
|
||||||
@@ -77,16 +81,21 @@ struct Hash_Map {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* strings dont match, this means we have */
|
/* objects dont match, this means we have */
|
||||||
/* a collision. We just search forward */
|
/* a collision. We just search forward */
|
||||||
for (u32 i = 0; i < current_capacity; ++i) {
|
for (u32 i = 0; i < current_capacity; ++i) {
|
||||||
u32 new_idx = (i + index) % current_capacity;
|
u32 new_idx = (i + index) % current_capacity;
|
||||||
cell = data[new_idx];
|
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;
|
return -1;
|
||||||
|
/* If the objects don't match, keep looking */
|
||||||
if (!hm_objects_match(key, cell.original))
|
if (!hm_objects_match(key, cell.original))
|
||||||
continue;
|
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;
|
continue;
|
||||||
return new_idx;
|
return new_idx;
|
||||||
}
|
}
|
||||||
@@ -108,9 +117,12 @@ struct Hash_Map {
|
|||||||
|
|
||||||
key_type search_key_to_object(value_type v) {
|
key_type search_key_to_object(value_type v) {
|
||||||
for (u32 i = 0; i < current_capacity; ++i) {
|
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 data[i].original;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +132,7 @@ struct Hash_Map {
|
|||||||
// QUESTION(Felix): Does it make sense to
|
// QUESTION(Felix): Does it make sense to
|
||||||
// ret.reserve(this->cell_count)?
|
// ret.reserve(this->cell_count)?
|
||||||
for (u32 i = 0; i < current_capacity; ++i) {
|
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);
|
ret.append(data[i].original);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -142,15 +154,15 @@ struct Hash_Map {
|
|||||||
void delete_object(key_type key) {
|
void delete_object(key_type key) {
|
||||||
s32 index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
|
s32 index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
|
||||||
if (index != -1) {
|
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) {
|
void set_object(key_type key, value_type obj, u64 hash_val) {
|
||||||
u32 index = hash_val % current_capacity;
|
u32 index = hash_val % current_capacity;
|
||||||
|
|
||||||
/* if we the desired cell is just empty, write to it and done :) */
|
/* if we the desired cell is avaliable, write to it and done :) */
|
||||||
if (!data[index].original) {
|
if (data[index].occupancy == HM_Cell::Occupancy::Avaliable) {
|
||||||
/* insert new cell into desired slot */
|
/* insert new cell into desired slot */
|
||||||
++cell_count;
|
++cell_count;
|
||||||
} else {
|
} else {
|
||||||
@@ -168,7 +180,7 @@ struct Hash_Map {
|
|||||||
/* insert all old items again */
|
/* insert all old items again */
|
||||||
for (u32 i = 0; i < current_capacity/4; ++i) {
|
for (u32 i = 0; i < current_capacity/4; ++i) {
|
||||||
auto cell = old_data[i];
|
auto cell = old_data[i];
|
||||||
if (cell.original) {
|
if (cell.occupancy == HM_Cell::Occupancy::Occupied) {
|
||||||
set_object(cell.original, cell.object, cell.hash);
|
set_object(cell.original, cell.object, cell.hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,7 +192,7 @@ struct Hash_Map {
|
|||||||
/* preventing gotos using lambdas! */
|
/* preventing gotos using lambdas! */
|
||||||
[&]{
|
[&]{
|
||||||
for (u32 i = index; i < current_capacity; ++i) {
|
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))
|
hm_objects_match(data[i].original, key))
|
||||||
{
|
{
|
||||||
index = i;
|
index = i;
|
||||||
@@ -188,7 +200,7 @@ struct Hash_Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < index; ++i) {
|
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))
|
hm_objects_match(data[i].original, key))
|
||||||
{
|
{
|
||||||
index = i;
|
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].original = key;
|
||||||
data[index].hash = hash_val;
|
data[index].hash = hash_val;
|
||||||
data[index].object = obj;
|
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);
|
// 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
|
// NOTE(Felix): maually overstep the args that vfprintf will have used
|
||||||
// used args
|
|
||||||
for (int i = 0; i < used_arg_values; ++i) {
|
for (int i = 0; i < used_arg_values; ++i) {
|
||||||
va_arg(*arg_list, void*);
|
va_arg(*arg_list, void*);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,127 @@
|
|||||||
#define _CRT_SECURE_NO_WARNINGS
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "./types.hpp"
|
#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 "./error.hpp"
|
||||||
#include "./print.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, "...");
|
return print_to_file(f, "...");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_printer() {
|
auto test_printer() -> void {
|
||||||
// u32 arr[] = {1,2,3,4,1,1,3};
|
u32 arr[] = {1,2,3,4,1,1,3};
|
||||||
// f32 f_arr[] = {1.1,2.1,3.2};
|
f32 f_arr[] = {1.1,2.1,3.2};
|
||||||
|
|
||||||
// init_printer();
|
|
||||||
// register_printer("dots", print_dots, Printer_Function_Type::_void);
|
|
||||||
|
|
||||||
// u32 u1 = -1;
|
register_printer("dots", print_dots, Printer_Function_Type::_void);
|
||||||
// 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);
|
||||||
|
|
||||||
|
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[]) {
|
s32 main(s32 argc, char* argv[]) {
|
||||||
|
|
||||||
// test_printer();
|
|
||||||
|
|
||||||
init_printer();
|
init_printer();
|
||||||
create_generic_error("nothing to lex was found:\n"
|
|
||||||
" in %{color<}%{->char}%{>color}\n"
|
test_hm();
|
||||||
" at %{color<}%{->char}%{>color}\n"
|
|
||||||
"bottom text\n",
|
|
||||||
console_green,
|
|
||||||
"some file name",
|
|
||||||
console_cyan,
|
|
||||||
"yesssssss");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user