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,
40
HMDR_FIND
,
41
HMDR_REPLACE
,
42
HMDR_SWAP
,
43
}
HashMapDuplicateResolution
;
/*HMDR*/
44
45
typedef
enum
{
46
HMR_FAILED
= 0,
47
HMR_FOUND
,
48
HMR_REPLACED
,
49
HMR_SWAPPED
,
50
HMR_INSERTED
,
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, ¤t)) {\
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
src_c_new
hashmap.h
Generated by
1.8.18