kiba-engine
hash_table.c
1 #include <kiba/containers/hash_table.h>
2 
3 #include <kiba/core/hash.h>
4 #include <kiba/core/log.h>
5 #include <kiba/core/memory.h>
6 
7 #include <string.h> // TODO add memcmp to core lib
8 
9 hash_table_entry *hash_table_find_entry(hash_table *table, const void *key, usize key_size);
10 
11 b8 hash_table_create(hash_table *table, usize initial_capacity, f64 max_load, allocator *alloc) {
12  KB_ASSERT(table != KB_NULL, "table to populate must be a valid pointer");
13  KB_ASSERT(alloc != KB_NULL, "must be given valid allocator pointer");
14  KB_ASSERT(initial_capacity != 0, "initial capacity must not be 0");
15  KB_ASSERT(max_load <= 1.0 && max_load > 0.0, "max load must be in range (0, 1] but is {f64}", max_load);
16  table->size = 0;
17  table->capacity = initial_capacity;
18  table->max_load = max_load;
19  table->alloc = alloc;
20  table->data = allocator_allocate(alloc, initial_capacity * sizeof(hash_table_entry));
21  return table->data != KB_NULL;
22 }
23 
24 void hash_table_destroy(hash_table *table) {
25  KB_ASSERT(table != KB_NULL && table->alloc != KB_NULL && table->data != KB_NULL,
26  "table must have initialized state");
27  allocator_free(table->alloc, table->data);
28  memory_zero(table, sizeof(hash_table));
29 }
30 
31 b8 hash_table_set(hash_table *table, const void *key, usize key_size, uptr value) {
32  hash_table_entry *new_entry = hash_table_find_entry(table, key, key_size);
33  if (new_entry->key_size == 0) {
34  ++table->size;
35  if ((f64) table->size / (f64) table->capacity >= table->max_load) {
36  // reached max load -> migrate to larger hash table
37  hash_table new_table;
38  if (!hash_table_create(&new_table, table->capacity * 2, table->max_load, table->alloc)) {
39  KB_ERROR("could not expand hash table");
40  return false;
41  }
42  hash_table_for_each(*table) {
43  KB_ASSERT(hash_table_set(&new_table, entry->key, entry->key_size, entry->value),
44  "migration of old values must work");
45  }
46  KB_ASSERT(table->size == new_table.size + 1, "size between tables must not change");
47  allocator_free(table->alloc, table->data);
48  table->capacity = new_table.capacity;
49  table->data = new_table.data;
50  }
51  }
52  new_entry->key_size = key_size;
53  new_entry->key = (void *) key;
54  new_entry->value = value;
55  return true;
56 }
57 
58 b8 hash_table_get(hash_table *table, const void *key, usize key_size, void *value_ptr) {
59  hash_table_entry *entry = hash_table_find_entry(table, key, key_size);
60  if (entry->key_size != 0) {
61  memory_copy(value_ptr, &entry->value, sizeof(uptr));
62  return true;
63  }
64  return false;
65 }
66 
67 hash_table_entry *hash_table_find_entry(hash_table *table, const void *key, usize key_size) {
68  KB_ASSERT(table != KB_NULL && table->alloc != KB_NULL && table->data != KB_NULL,
69  "table must have initialized state");
70  KB_ASSERT(key != KB_NULL && key_size != 0, "a valid key must be provided");
71  u64 hash = hash_fnv_1a(key, key_size);
72  usize index = hash % table->capacity;
73  hash_table_entry *entry = table->data + index;
74  while (entry->key_size != 0
75  && !(key_size == entry->key_size && hash == entry->hash && memcmp(key, entry->key, key_size) == 0)) {
76  index = (index + 1) % table->capacity;
77  entry = table->data + index;
78  }
79  entry->hash = hash;
80  return entry;
81 }
void * allocator_allocate(allocator *alloc, usize size)
Allocate unaligned memory.
Definition: allocator.c:92
void allocator_free(allocator *alloc, void *mem)
Give back memory to the allocator.
Definition: allocator.c:134
void * memory_copy(void *dst, const void *src, usize size)
Copy memory.
Definition: memory.c:83
void * memory_zero(void *mem, usize size)
Zero out memory.
Definition: memory.c:79
Lightweight layer between platform and other engine components to enable tracing/monitoring.
#define KB_NULL
Value of an invalid ptr (nullptr).
Definition: defines.h:18
Logging system.
#define KB_ASSERT(expr,...)
Perform runtime assertion and log failures.
Definition: log.h:133
#define KB_ERROR(...)
Log entry with error log level.
Definition: log.h:142
Central allocator structure.
Definition: allocator.h:87
Definition: hash_table.h:7