NVMLib  very early alpha
A library to optimally use a Hybrid RAM setup.
hashmap.h
Go to the documentation of this file.
1 #ifndef __NVM_HASHMAP__
2 #define __NVM_HASHMAP__
3 
18 #include <stdbool.h>
19 #include <stdlib.h>
20 
21 typedef __uint128_t uint128_t;
22 typedef __uint64_t uint64_t;
23 typedef __uint32_t uint32_t;
24 typedef __uint16_t uint16_t;
25 typedef __uint8_t uint8_t;
26 
27 #define LOAD_FACTOR 0.8
28 
29 #define HASH_MAP(VALUE_TYPE) VALUE_TYPE##_hash_map
30 #define HASH_MAP_BUCKET(VALUE_TYPE) VALUE_TYPE##_hash_map_bucket
31 
32 #define HASH_MAP_INSERT(VALUE_TYPE) insert_into_##VALUE_TYPE##_hash_map
33 #define HASH_MAP_FIND(VALUE_TYPE) find_in_##VALUE_TYPE##_hash_map
34 #define HASH_MAP_CREATE(VALUE_TYPE) create_new_##VALUE_TYPE##_hash_map
35 #define HASH_MAP_ERASE(VALUE_TYPE) erase_from_##VALUE_TYPE##_hash_map
36 #define HASH_MAP_DESTROY(VALUE_TYPE) destroy_##VALUE_TYPE##_hash_map
37 
38 typedef enum {
39  HMDR_FAIL = 0,
44 
45 typedef enum {
51 } HashMapResult; /*HMR*/
52 
53 static inline size_t next_power_of_two(size_t i /*map->power_of_two + 1*/) {
54  --i;
55  i |= i >> 1;
56  i |= i >> 2;
57  i |= i >> 4;
58  i |= i >> 8;
59  i |= i >> 16;
60  i |= i >> 32;
61  ++i;
62  return i;
63 }
64 
69 static inline size_t index_for_hash(size_t hash, size_t shift, size_t pow_of_two) {
70  return ((11400714819323198485ul * hash) >> shift ) % pow_of_two;
71 }
72 
73 
74 #define _HASH_STRUCTURE(VALUE_TYPE)\
75 struct {\
76  size_t size; /*current size*/\
77  size_t power_of_two; /*capacity*/\
78  VALUE_TYPE *entries;\
79 }
80 
87 #define DECLARE_HASHMAP(VALUE_TYPE) \
88 \
89 /*\
90 * The structure of `root nodes` of each `bucket`\
91 */\
92 typedef _HASH_STRUCTURE(VALUE_TYPE) HASH_MAP_BUCKET(VALUE_TYPE);\
93 \
94 /*\
95 * The structure of `root node` `hash map`\
96 */\
97 typedef _HASH_STRUCTURE(HASH_MAP_BUCKET(VALUE_TYPE)) HASH_MAP(VALUE_TYPE);\
98 \
99 \
100 /*\
101 * Create new Hash map for the given type.\
102 * @retrun : the pointer to the created hash map\
103 */\
104 HASH_MAP(VALUE_TYPE)* create_new_##VALUE_TYPE##_hash_map();\
105 \
106 /*\
107 * Insert new value in to the hash map.\
108 * @param map : The map into which insertion is to be made\
109 * @param entry [In / Out] : The entry to be inserted. If duplicate,\
110  return pointer in here.\
111 */\
112 HashMapResult insert_into_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map, VALUE_TYPE **entry, HashMapDuplicateResolution dr);\
113 \
114 /*\
115 * Looks up an entry in the map\
116 * @param map : The map in which look up is to be made\
117 * @param entry [In / Out] : The entry to be searched. If found,\
118  return pointer in here.\
119 * @return : false, if the entry was not found.\
120 */\
121 bool find_in_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map, VALUE_TYPE **result_of_search);\
122 \
123 /*\
124 * Removes entry from the map\
125 * @param map : The map in which look up is to be made\
126 * @param entry [In / Out] : The entry to be removed. If found, delete it and \
127  return pointer to the deleted item here.\
128 * @return : false, if the entry didn't exist.\
129 */\
130 bool erase_from_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map, VALUE_TYPE *deleted_entry);\
131 \
132 /*\
133 * Destroys the table, i.e size of table = 0 and capacity = 0 after the call\
134 */\
135 void destroy_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map);
136 
137 
138 
139 
140 
152 #define DEFINE_HASHMAP(VALUE_TYPE, CMP, GET_HASH, FREE, REALLOC)\
153 \
154 \
155 void destroy_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map) {\
156  if (map->entries) {\
157  for (size_t i = 0; i < map->power_of_two; i++) {\
158  if(map->entries[i].entries) {\
159  FREE(map->entries[i].entries);\
160  }\
161  }\
162  }\
163  FREE(map->entries);\
164  FREE(map);\
165 }\
166 \
167 \
168 HASH_MAP(VALUE_TYPE)* create_new_##VALUE_TYPE##_hash_map() {\
169  HASH_MAP(VALUE_TYPE) *new_map = (HASH_MAP(VALUE_TYPE) *)malloc(sizeof(HASH_MAP(VALUE_TYPE)));\
170  new_map->size = 0;\
171  new_map->power_of_two = 2;\
172  HASH_MAP_BUCKET(VALUE_TYPE) *new_entries = REALLOC(NULL, 2 * sizeof(HASH_MAP_BUCKET(VALUE_TYPE)));\
173  memset(new_entries, 0, 2 * sizeof(HASH_MAP_BUCKET(VALUE_TYPE)));\
174  new_map->entries = new_entries;\
175  return new_map;\
176 }\
177 \
178 \
179 bool find_in_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map, VALUE_TYPE **result_of_search){\
180  if(!map->entries) {\
181  return false;\
182  }\
183  HASH_MAP_BUCKET(VALUE_TYPE) *bucket = &map->entries[index_for_hash(\
184  GET_HASH(*result_of_search), \
185  64 - __builtin_popcount(map->power_of_two-1), map->power_of_two)];\
186  for (size_t i = 0; i < bucket->size; i++) {\
187  if (!(CMP((&bucket->entries[i]), (*result_of_search)))) {\
188  *result_of_search = &bucket->entries[i];\
189  return true;\
190  }\
191  }\
192  return false;\
193 }\
194 \
195 \
196 bool erase_from_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map, VALUE_TYPE *deleted_entry){\
197  HASH_MAP_BUCKET(VALUE_TYPE) *bucket = &map->entries[index_for_hash(\
198  GET_HASH(deleted_entry),\
199  64 - __builtin_popcount(map->power_of_two-1), map->power_of_two)];\
200  for (size_t i = 0; i < bucket->size; i++) {\
201  if (CMP(deleted_entry, &bucket->entries[i]) == 0) {\
202  *deleted_entry = bucket->entries[i];\
203  memmove(&bucket->entries[i], &bucket->entries[i+1],\
204  (bucket->size - i - 1) * sizeof(HASH_MAP_BUCKET(VALUE_TYPE)));\
205  --bucket->size;\
206  if (!bucket->size){\
207  /* A bucket is now free */\
208  --map->size;\
209  }\
210  return true;\
211  }\
212  }\
213  return false;\
214 }\
215 \
216 \
217 VALUE_TYPE* actual_insert_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map, VALUE_TYPE *entry){\
218  HASH_MAP_BUCKET(VALUE_TYPE) *bucket = &map->entries[index_for_hash(\
219  GET_HASH(entry), \
220  64 - __builtin_popcount(map->power_of_two-1), map->power_of_two)];\
221  /* check if available to add */\
222  size_t old_size = bucket->size;\
223  if (bucket->power_of_two < old_size + 1) {\
224  size_t new_capacity = next_power_of_two(bucket->power_of_two + 1);\
225  bucket->entries = REALLOC(bucket->entries,new_capacity * sizeof(VALUE_TYPE));\
226  bucket->power_of_two = new_capacity;\
227  }\
228  VALUE_TYPE *result = &bucket->entries[old_size];\
229  *result = *entry;\
230  if (!old_size) {\
231  map->size++;\
232  }\
233  bucket->size++;\
234  return result;\
235 }\
236 \
237 \
238 void hash_map_##VALUE_TYPE##_ensure_size(HASH_MAP(VALUE_TYPE) *map, size_t capacity_required) {\
239  size_t capacity = (size_t)((double)map->power_of_two * LOAD_FACTOR);\
240  if (capacity_required <= capacity) {\
241  return;\
242  }\
243  size_t old_size = map->size;\
244  size_t old_power_of_two = map->power_of_two;\
245  HASH_MAP_BUCKET(VALUE_TYPE) *old_entries = map->entries;\
246  size_t new_size = next_power_of_two(map->power_of_two+1);\
247  HASH_MAP_BUCKET(VALUE_TYPE) *new_entries = REALLOC(NULL, \
248  new_size * sizeof(HASH_MAP_BUCKET(VALUE_TYPE)));\
249  if(!new_entries) {\
250  return;\
251  }\
252  memset(new_entries, 0, new_size * sizeof(HASH_MAP_BUCKET(VALUE_TYPE)));\
253  map->entries = new_entries;\
254  map->power_of_two = new_size;\
255  map->size = 0; /* needs to be reevaluated */\
256  \
257  if(old_size) {\
258  for (size_t i = 0; i < old_power_of_two; i++) {\
259  HASH_MAP_BUCKET(VALUE_TYPE) *bucket = &old_entries[i];\
260  for (size_t j = 0; j < bucket->size; j++) {\
261  actual_insert_##VALUE_TYPE##_hash_map(map, &bucket->entries[j]);\
262  }\
263  FREE(bucket->entries);\
264  }\
265  }\
266  FREE(old_entries);\
267 }\
268 \
269 \
270 HashMapResult insert_into_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map, VALUE_TYPE **entry,HashMapDuplicateResolution dr){\
271  HashMapResult result = HMR_FAILED;\
272  VALUE_TYPE *current = *entry, tmp;\
273  if (!HASH_MAP_FIND(VALUE_TYPE)(map, &current)) {\
274  current = *entry;\
275  result = HMR_INSERTED;\
276  } else {\
277  switch(dr) {\
278  case HMDR_FAIL:\
279  *entry = current;\
280  return HMR_FAILED;\
281  case HMDR_FIND:\
282  *entry = current;\
283  return HMR_FOUND;\
284  case HMDR_REPLACE:\
285  *current = **entry;\
286  *entry = current;\
287  return HMR_REPLACED;\
288  case HMDR_SWAP:\
289  tmp = *current;\
290  *current = **entry;\
291  **entry = tmp;\
292  *entry = current;\
293  return HMR_SWAPPED;\
294  default:\
295  return HMR_FAILED;\
296  }\
297  }\
298  if (!map->entries[index_for_hash(\
299  GET_HASH(current), \
300  64 - __builtin_popcount(map->power_of_two-1), \
301  map->power_of_two)].size) {\
302  /* New bucket is going to be filled */\
303  hash_map_##VALUE_TYPE##_ensure_size(map, map->size + 1);\
304  }\
305  VALUE_TYPE *inserted_entry = actual_insert_##VALUE_TYPE##_hash_map(map, current);\
306  if (result == HMR_INSERTED) {\
307  *entry = inserted_entry;\
308  }\
309  return result;\
310 }
311 
319 #define HASH_MAP_PRINT(VALUE_TYPE) print_##VALUE_TYPE##_hash_map
320 
321 #define HASH_MAP_PRINT_FUNC(VALUE_TYPE, PRINT_OBJ_FUNC) \
322 void print_##VALUE_TYPE##_hash_map(HASH_MAP(VALUE_TYPE) *map) {\
323  if(!map->entries){\
324  return;\
325  }\
326  for(size_t i = 0; i < map->power_of_two ; i++) {\
327  printf("%ld ---> ", i);\
328  HASH_MAP_BUCKET(VALUE_TYPE) *bucket = &map->entries[i];\
329  printf("size = %ld || ", bucket->size);\
330  for(int j = 0; j < bucket->size; j++) {\
331  PRINT_OBJ_FUNC(&bucket->entries[j]);\
332  printf(" | ");\
333  }\
334  printf("\n");\
335  }\
336  printf("\n");\
337 }
338 
339 #endif // !__NVM_HASHMAP__
HMR_FOUND
@ HMR_FOUND
Definition: hashmap.h:47
HMR_FAILED
@ HMR_FAILED
Definition: hashmap.h:46
uint8_t
__uint8_t uint8_t
Definition: hashmap.h:25
uint128_t
__uint128_t uint128_t
Definition: hashmap.h:21
HMDR_FAIL
@ HMDR_FAIL
Definition: hashmap.h:39
HashMapDuplicateResolution
HashMapDuplicateResolution
Definition: hashmap.h:38
next_power_of_two
static size_t next_power_of_two(size_t i)
Definition: hashmap.h:53
uint64_t
__uint64_t uint64_t
Definition: hashmap.h:22
HMDR_FIND
@ HMDR_FIND
Definition: hashmap.h:40
uint16_t
__uint16_t uint16_t
Definition: hashmap.h:24
HMDR_REPLACE
@ HMDR_REPLACE
Definition: hashmap.h:41
HMR_SWAPPED
@ HMR_SWAPPED
Definition: hashmap.h:49
hash
static uint64_t hash(const TOID(struct hashmap_tx) *hashmap, const TOID(struct buckets) *buckets, uint64_t value)
The hash function.
Definition: hashmap_tx.c:76
uint32_t
__uint32_t uint32_t
Definition: hashmap.h:23
HMR_REPLACED
@ HMR_REPLACED
Definition: hashmap.h:48
HashMapResult
HashMapResult
Definition: hashmap.h:45
HMR_INSERTED
@ HMR_INSERTED
Definition: hashmap.h:50
HMDR_SWAP
@ HMDR_SWAP
Definition: hashmap.h:42
index_for_hash
static size_t index_for_hash(size_t hash, size_t shift, size_t pow_of_two)
Fibonacci hashing 11400714819323198485ull = 2^64 / golden_ratio.
Definition: hashmap.h:69