Derive-C
Loading...
Searching...
No Matches
template.h File Reference
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <derive-c/core.h>
#include <derive-c/panic.h>
#include <derive-c/self.h>
#include <derive-c/structures/hashmap/utils.h>
Include dependency graph for template.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  KEY_ENTRY
 
struct  SELF
 
struct  KV_PAIR
 
struct  KV_PAIR_CONST
 

Macros

#define K   derive_c_parameter_key
 
#define K_DELETE   derive_c_parameter_key_delete
 
#define V   derive_c_parameter_value
 
#define V_DELETE   derive_c_parameter_value_delete
 
#define HASH   derive_c_parameter_hash
 
#define EQ   derive_c_parameter_eq
 
#define KEY_ENTRY   NAME(SELF, key_entry)
 
#define KV_PAIR   NAME(SELF, kv)
 
#define KV_PAIR_CONST   NAME(SELF, kv_const)
 

Functions

static SELF new_with_capacity_for (size_t capacity)
 
static SELF new ()
 
static SELF shallow_clone (SELF const *self)
 
static void delete (SELF *self)
 
static Vinsert (SELF *self, K key, V value)
 
static void extend_capacity_for (SELF *self, size_t expected_items)
 
static Vtry_insert (SELF *self, K key, V value)
 
static Vtry_write (SELF *self, K key)
 
static Vwrite (SELF *self, K key)
 
static V const * try_read (SELF const *self, K key)
 
static V const * read (SELF const *self, K key)
 
static bool try_remove (SELF *self, K key, V *destination)
 
static V remove (SELF *self, K key)
 
static void delete_entry (SELF *self, K key)
 
static size_t size (SELF const *self)
 
static KV_PAIR next (ITER *iter)
 
static size_t position (ITER const *iter)
 
static bool empty (ITER const *iter)
 
static ITER get_iter (SELF *self)
 
static KV_PAIR_CONST next (ITER_CONST *iter)
 
static size_t position (ITER_CONST const *iter)
 
static bool empty (ITER_CONST const *iter)
 
static ITER_CONST get_iter_const (SELF const *self)
 

Macro Definition Documentation

◆ EQ

#define EQ   derive_c_parameter_eq

Definition at line 43 of file template.h.

◆ HASH

#define HASH   derive_c_parameter_hash

Definition at line 36 of file template.h.

◆ K

#define K   derive_c_parameter_key

Definition at line 18 of file template.h.

◆ K_DELETE

#define K_DELETE   derive_c_parameter_key_delete

Definition at line 20 of file template.h.

◆ KEY_ENTRY

#define KEY_ENTRY   NAME(SELF, key_entry)

Definition at line 54 of file template.h.

◆ KV_PAIR

#define KV_PAIR   NAME(SELF, kv)

Definition at line 316 of file template.h.

◆ KV_PAIR_CONST

#define KV_PAIR_CONST   NAME(SELF, kv_const)

Definition at line 389 of file template.h.

◆ V

#define V   derive_c_parameter_value

Definition at line 28 of file template.h.

◆ V_DELETE

#define V_DELETE   derive_c_parameter_value_delete

Definition at line 30 of file template.h.

Function Documentation

◆ delete()

static void delete ( SELF * self)
static

Definition at line 371 of file template.h.

371 {
372 DEBUG_ASSERT(self);
373 ITER iter = NAME(SELF, get_iter)(self);
374
375 for (size_t i = 0; i < self->capacity; i++) {
376 if (self->keys[i].present) {
377 K_DELETE(&self->keys[i].key);
378 V_DELETE(&self->values[i]);
379 }
380 }
381
382 free(self->keys);
383 free(self->values);
384}
static ITER get_iter(SELF *self)
Definition template.h:305
#define V_DELETE
Definition template.h:25
#define NAME(pre, post)
Definition core.h:5
#define K_DELETE
Definition template.h:20
#define DEBUG_ASSERT(expr)
Definition panic.h:24
#define SELF
Definition self.h:4
bool present
Definition template.h:56
K key
Definition template.h:58
size_t capacity
Definition template.h:85
V * values
Definition template.h:67
KEY_ENTRY * keys
Definition template.h:66
Here is the call graph for this function:

◆ delete_entry()

static void delete_entry ( SELF * self,
K key )
static

Definition at line 306 of file template.h.

306 {
307 V value = NAME(SELF, remove)(self, key);
308 V_DELETE(&value);
309}
static V remove(SELF *self, INDEX index)
Definition template.h:231
#define V
Definition template.h:23
Here is the call graph for this function:

◆ empty() [1/2]

static bool empty ( ITER const * iter)
static

Definition at line 353 of file template.h.

353 {
354 DEBUG_ASSERT(iter);
355 return iter->index >= iter->map->capacity;
356}
Here is the call graph for this function:

◆ empty() [2/2]

static bool empty ( ITER_CONST const * iter)
static

Definition at line 426 of file template.h.

426 {
427 DEBUG_ASSERT(iter);
428 return iter->index >= iter->map->capacity;
429}
Here is the call graph for this function:

◆ extend_capacity_for()

static void extend_capacity_for ( SELF * self,
size_t expected_items )
static

Definition at line 118 of file template.h.

118 {
119 DEBUG_ASSERT(self);
120 size_t target_capacity = apply_capacity_policy(expected_items);
121 if (target_capacity > self->capacity) {
122 SELF new_map = NAME(SELF, new_with_capacity_for)(expected_items);
123 for (size_t index = 0; index < self->capacity; index++) {
124 KEY_ENTRY* entry = &self->keys[index];
125 if (entry->present) {
126 NAME(SELF, insert)(&new_map, entry->key, self->values[index]);
127 }
128 }
129 free(self->keys);
130 free(self->values);
131 *self = new_map;
132 }
133}
static INDEX insert(SELF *self, V value)
Definition template.h:114
static SELF new_with_capacity_for(INDEX_TYPE items)
Definition template.h:99
#define KEY_ENTRY
Definition template.h:54
static size_t apply_capacity_policy(size_t capacity)
Definition utils.h:10
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_iter()

static ITER get_iter ( SELF * self)
static

Definition at line 358 of file template.h.

358 {
359 DEBUG_ASSERT(self);
360 size_t first_index = 0;
361 while (first_index < self->capacity && !self->keys[first_index].present) {
362 first_index++;
363 }
364 return (ITER){
365 .map = self,
366 .index = first_index,
367 .pos = 0,
368 };
369}
Here is the call graph for this function:

◆ get_iter_const()

static ITER_CONST get_iter_const ( SELF const * self)
static

Definition at line 431 of file template.h.

431 {
432 DEBUG_ASSERT(self);
433 size_t first_index = 0;
434 while (first_index < self->capacity && !self->keys[first_index].present) {
435 first_index++;
436 }
437 return (ITER_CONST){
438 .map = self,
439 .index = first_index,
440 .pos = 0,
441 };
442}
Here is the call graph for this function:

◆ insert()

static V * insert ( SELF * self,
K key,
V value )
static

Definition at line 188 of file template.h.

188 {
189 V* value_ptr = NAME(SELF, try_insert)(self, key, value);
190 ASSERT(value_ptr);
191 return value_ptr;
192}
static V * try_insert(SELF *self, K key, V value)
Definition template.h:135
#define ASSERT(expr,...)
Definition panic.h:15
Here is the call graph for this function:

◆ new()

static SELF new ( )
static

Definition at line 89 of file template.h.

static size_t const INITIAL_CAPACITY
Definition utils.h:22
Here is the call graph for this function:

◆ new_with_capacity_for()

static SELF new_with_capacity_for ( size_t capacity)
static

Definition at line 71 of file template.h.

71 {
72 ASSERT(capacity > 0);
73 size_t real_capacity = apply_capacity_policy(capacity);
74 ASSERT(real_capacity > 0);
75 // JUSTIFY: calloc of keys
76 // - A cheap way to get all precense flags as zeroed (os & allocater supported get zeroed page)
77 // - for the values, we do not need this (no precense checks are done on values)
78 KEY_ENTRY* keys = (KEY_ENTRY*)calloc(sizeof(KEY_ENTRY), real_capacity);
79 V* values = (V*)malloc(sizeof(V) * real_capacity);
80 ASSERT(keys && values);
81 return (SELF){
82 .capacity = real_capacity,
83 .items = 0,
84 .keys = keys,
85 .values = values,
86 };
87}
Here is the call graph for this function:

◆ next() [1/2]

static KV_PAIR next ( ITER * iter)
static

Definition at line 331 of file template.h.

331 {
332 DEBUG_ASSERT(iter);
333 if (iter->index < iter->map->capacity) {
334 KV_PAIR ret_val = {.key = &iter->map->keys[iter->index].key,
335 .value = &iter->map->values[iter->index]};
336 iter->pos++;
337 iter->index++;
338 while (iter->index < iter->map->capacity && !iter->map->keys[iter->index].present) {
339 iter->index++;
340 }
341
342 return ret_val;
343 } else {
344 return (KV_PAIR){.key = NULL, .value = NULL};
345 }
346}
#define KV_PAIR
Definition template.h:316
Here is the call graph for this function:

◆ next() [2/2]

static KV_PAIR_CONST next ( ITER_CONST * iter)
static

Definition at line 404 of file template.h.

404 {
405 DEBUG_ASSERT(iter);
406 if (iter->index < iter->map->capacity) {
407 KV_PAIR_CONST ret_val = {.key = &iter->map->keys[iter->index].key,
408 .value = &iter->map->values[iter->index]};
409 iter->pos++;
410 iter->index++;
411 while (iter->index < iter->map->capacity && !iter->map->keys[iter->index].present) {
412 iter->index++;
413 }
414
415 return ret_val;
416 } else {
417 return (KV_PAIR_CONST){.key = NULL, .value = NULL};
418 }
419}
#define KV_PAIR_CONST
Definition template.h:389
Here is the call graph for this function:

◆ position() [1/2]

static size_t position ( ITER const * iter)
static

Definition at line 348 of file template.h.

348 {
349 DEBUG_ASSERT(iter);
350 return iter->pos;
351}
Here is the call graph for this function:

◆ position() [2/2]

static size_t position ( ITER_CONST const * iter)
static

Definition at line 421 of file template.h.

421 {
422 DEBUG_ASSERT(iter);
423 return iter->pos;
424}
Here is the call graph for this function:

◆ read()

static V const * read ( SELF const * self,
K key )
static

Definition at line 238 of file template.h.

238 {
239 V const* value = NAME(SELF, try_read)(self, key);
240 ASSERT(value);
241 return value;
242}
static V const * try_read(SELF const *self, INDEX index)
Definition template.h:162
Here is the call graph for this function:

◆ remove()

static V remove ( SELF * self,
K key )
static

Definition at line 300 of file template.h.

300 {
301 V value;
302 ASSERT(NAME(SELF, try_remove)(self, key, &value));
303 return value;
304}
static bool try_remove(SELF *self, INDEX index, V *destination)
Definition template.h:212
Here is the call graph for this function:

◆ shallow_clone()

static SELF shallow_clone ( SELF const * self)
static

Definition at line 91 of file template.h.

91 {
92 DEBUG_ASSERT(self);
93
94 // JUSTIFY: Naive copy
95 // - We could resize (potentially a smaller map) and rehash
96 // - Not confident it would be any better than just a copy.
97 // JUSTIFY: Individually copy keys
98 // - Many entries are zeroed, no need to copy uninit data
99
100 KEY_ENTRY* keys = (KEY_ENTRY*)calloc(sizeof(KEY_ENTRY), self->capacity);
101 V* values = (V*)malloc(sizeof(V) * self->capacity);
102 ASSERT(keys && values);
103
104 for (size_t i = 0; i < self->capacity; i++) {
105 if (self->keys[i].present) {
106 keys[i] = self->keys[i];
107 values[i] = self->values[i];
108 }
109 }
110
111 return (SELF){.capacity = self->capacity, .items = self->items, .keys = keys, .values = values};
112}
Here is the call graph for this function:

◆ size()

static size_t size ( SELF const * self)
static

Definition at line 311 of file template.h.

311 {
312 DEBUG_ASSERT(self);
313 return self->items;
314}
Here is the call graph for this function:

◆ try_insert()

static V * try_insert ( SELF * self,
K key,
V value )
static

Definition at line 135 of file template.h.

135 {
136 DEBUG_ASSERT(self);
137 if (apply_capacity_policy(self->items) > self->capacity / 2) {
138 NAME(SELF, extend_capacity_for)(self, self->items * 2);
139 }
140
141 uint16_t distance_from_desired = 0;
142 size_t hash = HASH(&key);
143 size_t index = modulus_capacity(hash, self->capacity);
144 V* placed_entry = NULL;
145 for (;;) {
146 KEY_ENTRY* entry = &self->keys[index];
147 DEBUG_ASSERT(distance_from_desired < self->capacity);
148
149 if (entry->present) {
150 if (EQ(&entry->key, &key)) {
151 return NULL;
152 }
153
154 if (entry->distance_from_desired < distance_from_desired) {
155 K switch_key = entry->key;
156 uint16_t switch_distance_from_desired = entry->distance_from_desired;
157 V switch_value = self->values[index];
158
159 entry->key = key;
160 entry->distance_from_desired = distance_from_desired;
161 self->values[index] = value;
162
163 key = switch_key;
164 distance_from_desired = switch_distance_from_desired;
165 value = switch_value;
166
167 if (!placed_entry) {
168 placed_entry = &self->values[index];
169 }
170 }
171
172 distance_from_desired++;
173 index = modulus_capacity(index + 1, self->capacity);
174 } else {
175 entry->present = true;
176 entry->distance_from_desired = distance_from_desired;
177 entry->key = key;
178 self->values[index] = value;
179 if (!placed_entry) {
180 placed_entry = &self->values[index];
181 }
182 self->items++;
183 return placed_entry;
184 }
185 }
186}
#define HASH
Definition template.h:36
#define K
Definition template.h:18
#define EQ
Definition template.h:43
static void extend_capacity_for(SELF *self, size_t expected_items)
Definition template.h:118
uint16_t distance_from_desired
Definition template.h:57
size_t items
Definition template.h:63
static size_t modulus_capacity(size_t index, size_t capacity)
Definition utils.h:15
Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_read()

static V const * try_read ( SELF const * self,
K key )
static

Definition at line 219 of file template.h.

219 {
220 DEBUG_ASSERT(self);
221 size_t hash = HASH(&key);
222 size_t index = modulus_capacity(hash, self->capacity);
223
224 for (;;) {
225 KEY_ENTRY* entry = &self->keys[index];
226 if (entry->present) {
227 if (EQ(&entry->key, &key)) {
228 return &self->values[index];
229 } else {
230 index = modulus_capacity(index + 1, self->capacity);
231 }
232 } else {
233 return NULL;
234 }
235 }
236}
Here is the call graph for this function:

◆ try_remove()

static bool try_remove ( SELF * self,
K key,
V * destination )
static

Definition at line 244 of file template.h.

244 {
245 DEBUG_ASSERT(self);
246 size_t hash = HASH(&key);
247 size_t index = modulus_capacity(hash, self->capacity);
248
249 for (;;) {
250 KEY_ENTRY* entry = &self->keys[index];
251 if (entry->present) {
252 if (EQ(&entry->key, &key)) {
253 self->items--;
254
255 *destination = self->values[index];
256 K_DELETE(&entry->key);
257
258 // NOTE: For robin hood hashing, we need probe chains to be unbroken
259 // - Need to find the entries that might use this chain (
260 // distance_to_desired > 0 until the next not-present or
261 // distance_to_desired=0 slot)
262 // hence we shift entries the left (being careful with modulus index)
263
264 size_t free_index = index;
265 KEY_ENTRY* free_entry = entry;
266
267 size_t check_index = modulus_capacity(free_index + 1, self->capacity);
268 KEY_ENTRY* check_entry = &self->keys[check_index];
269
270 while (check_entry->present && check_entry->distance_from_desired > 0) {
271 free_entry->key = check_entry->key;
272 free_entry->distance_from_desired = check_entry->distance_from_desired - 1;
273 self->values[free_index] = self->values[check_index];
274
275 free_index = check_index;
276 free_entry = check_entry;
277
278 check_index = modulus_capacity(free_index + 1, self->capacity);
279 check_entry = &self->keys[check_index];
280 }
281
282 // JUSTIFY: Only setting free entry to false
283 // - We remove, then shift down an index
284 // - The removed entry already has the flag set
285 // - the free entry was the last one removed/moved down an index, so it
286 // should be false.
287
288 free_entry->present = false;
289
290 return true;
291 } else {
292 index = modulus_capacity(index + 1, self->capacity);
293 }
294 } else {
295 return false;
296 }
297 }
298}
Here is the call graph for this function:

◆ try_write()

static V * try_write ( SELF * self,
K key )
static

Definition at line 194 of file template.h.

194 {
195 DEBUG_ASSERT(self);
196 size_t hash = HASH(&key);
197 size_t index = modulus_capacity(hash, self->capacity);
198
199 for (;;) {
200 KEY_ENTRY* entry = &self->keys[index];
201 if (entry->present) {
202 if (EQ(&entry->key, &key)) {
203 return &self->values[index];
204 } else {
205 index = modulus_capacity(index + 1, self->capacity);
206 }
207 } else {
208 return NULL;
209 }
210 }
211}
Here is the call graph for this function:

◆ write()

static V * write ( SELF * self,
K key )
static

Definition at line 213 of file template.h.

213 {
214 V* value = NAME(SELF, try_write)(self, key);
215 ASSERT(value);
216 return value;
217}
static V * try_write(SELF *self, INDEX index)
Definition template.h:144
Here is the call graph for this function: