Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_hash.c
Go to the documentation of this file.
1
9#include "nilorea/n_common.h"
10#include "nilorea/n_log.h"
11#include "nilorea/n_hash.h"
12#include "nilorea/n_str.h"
13
14#include <pthread.h>
15#include <string.h>
16#include <strings.h>
17
18#ifdef __windows__
19#include <winsock.h>
20#else
21#include <arpa/inet.h>
22#endif
23
24/************ TRIE TREE TABLES ************/
25
33 __n_assert(table, return NULL);
34
35 HASH_NODE* new_hash_node = NULL;
36 Malloc(new_hash_node, HASH_NODE, 1);
37 __n_assert(new_hash_node, n_log(LOG_ERR, "Could not allocate new_hash_node"); return NULL);
38 new_hash_node->key = NULL;
39 new_hash_node->hash_value = 0;
40 new_hash_node->data.ptr = NULL;
41 new_hash_node->destroy_func = NULL;
42 new_hash_node->children = NULL;
43 new_hash_node->is_leaf = 0;
44 new_hash_node->need_rehash = 0;
45 new_hash_node->alphabet_length = table->alphabet_length;
46
47 Malloc(new_hash_node->children, HASH_NODE*, table->alphabet_length);
48 __n_assert(new_hash_node->children, n_log(LOG_ERR, "Could not allocate new_hash_node"); Free(new_hash_node); return NULL);
49
50 /* n_log( LOG_DEBUG , "node: %d %c table: alpha: %d / offset %d" , key , key , table -> alphabet_length , table -> alphabet_offset ); */
51
52 for (size_t it = 0; it < table->alphabet_length; it++) {
53 new_hash_node->children[it] = NULL;
54 }
55 new_hash_node->is_leaf = 0;
56 new_hash_node->key_id = key;
57 return new_hash_node;
58} /* _ht_new_node_trie(...) */
59
66int _ht_is_leaf_node_trie(HASH_TABLE* table, const char* key) {
67 __n_assert(table, return -1);
68
69 /* checks if the prefix match of key and root is a leaf node */
70 HASH_NODE* node = table->root;
71 for (size_t it = 0; key[it]; it++) {
72 size_t index = (size_t)key[it] - table->alphabet_offset;
73 if (index >= table->alphabet_length) {
74 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
75 index = 0;
76 }
77 if (node->children[index]) {
78 node = node->children[index];
79 }
80 }
81 return node->is_leaf;
82} /* _ht_is_leaf_node_trie(...) */
83
88void _ht_node_destroy(void* node) {
89 HASH_NODE* node_ptr = (HASH_NODE*)node;
90 __n_assert(node_ptr, return);
91 if (node_ptr->type == HASH_STRING) {
92 Free(node_ptr->data.string);
93 }
94 if (node_ptr->type == HASH_PTR) {
95 if (node_ptr->destroy_func && node_ptr->data.ptr) {
96 node_ptr->destroy_func(node_ptr->data.ptr);
97 }
98 /* No free by default. must be passed as a destroy_func
99 else
100 {
101 Free( node_ptr -> data . ptr );
102 }
103 */
104 }
105 FreeNoLog(node_ptr->key);
106 if (node_ptr->alphabet_length > 0) {
107 for (size_t it = 0; it < node_ptr->alphabet_length; it++) {
108 if (node_ptr->children[it]) {
109 _ht_node_destroy(node_ptr->children[it]);
110 }
111 }
112 Free(node_ptr->children);
113 }
114 Free(node_ptr)
115} /* _ht_node_destroy */
116
123size_t _ht_check_trie_divergence(HASH_TABLE* table, const char* key) {
124 __n_assert(table, return SIZE_MAX);
125 __n_assert(key, return SIZE_MAX);
126
127 HASH_NODE* node = table->root;
128
129 size_t last_index = 0;
130 for (size_t it = 0; key[it] != '\0'; it++) {
131 size_t index = (size_t)key[it] - table->alphabet_offset;
132 if (index >= table->alphabet_length) {
133 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
134 index = 0;
135 }
136 if (node->children[index]) {
137 /* child check */
138 for (size_t it2 = 0; it2 < table->alphabet_length; it2++) {
139 if (it2 != (unsigned)index && node->children[it2]) {
140 /* child found, update branch index */
141 last_index = it + 1;
142 break;
143 }
144 }
145 /* Go to the next child in the sequence */
146 node = node->children[index];
147 }
148 }
149 return last_index;
150} /* _ht_check_trie_divergence(...) */
151
158char* _ht_find_longest_prefix_trie(HASH_TABLE* table, const char* key) {
159 __n_assert(table, return NULL);
160 __n_assert(key, return NULL);
161
162 size_t len = strlen(key);
163
164 /* start with full key and backtrack to search for divergences */
165 char* longest_prefix = NULL;
166 Malloc(longest_prefix, char, len + 1);
167 __n_assert(longest_prefix, return NULL);
168 memcpy(longest_prefix, key, len);
169
170 /* check branching from the root */
171 size_t branch_index = _ht_check_trie_divergence(table, longest_prefix);
172 if (branch_index > 0 && branch_index != SIZE_MAX) {
173 /* there is branching, update the position to the longest match and update the longest prefix by the branch index length */
174 longest_prefix[branch_index - 1] = '\0';
175 Realloc(longest_prefix, char, (branch_index + 1));
176 if (!longest_prefix) {
177 n_log(LOG_ERR, "reallocation error, stopping find longest prefix");
178 return NULL;
179 }
180 __n_assert(longest_prefix, return NULL);
181 }
182 return longest_prefix;
183} /* _ht_find_longest_prefix_trie(...) */
184
191int _ht_remove_trie(HASH_TABLE* table, const char* key) {
192 __n_assert(table, return FALSE);
193 __n_assert(table->root, return FALSE);
194 __n_assert(key, return FALSE);
195
196 /* stop if matching node not a leaf node */
197 if (!_ht_is_leaf_node_trie(table, key)) {
198 return FALSE;
199 }
200
201 HASH_NODE* node = table->root;
202 /* find the longest prefix string that is not the current key */
203 char* longest_prefix = _ht_find_longest_prefix_trie(table, key);
204 if (longest_prefix && longest_prefix[0] == '\0') {
205 Free(longest_prefix);
206 return FALSE;
207 }
208 /* keep track of position in the tree */
209 size_t it = 0;
210 for (it = 0; longest_prefix[it] != '\0'; it++) {
211 size_t index = (size_t)longest_prefix[it] - table->alphabet_offset;
212 if (index >= table->alphabet_length) {
213 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
214 index = 0;
215 }
216 if (node->children[index] != NULL) {
217 /* common prefix, keep moving */
218 node = node->children[index];
219 } else {
220 /* not found */
221 Free(longest_prefix);
222 return FALSE;
223 }
224 }
225 /* deepest common node between the two strings */
226 /* deleting the sequence corresponding to key */
227 for (; key[it] != '\0'; it++) {
228 size_t index = (size_t)key[it] - table->alphabet_offset;
229 if (index >= table->alphabet_length) {
230 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
231 index = 0;
232 }
233 if (node->children[index]) {
234 /* delete the remaining sequence */
235 HASH_NODE* node_to_kill = node->children[index];
236 node->children[index] = NULL;
237 _ht_node_destroy(node_to_kill);
238 }
239 }
240 Free(longest_prefix);
241
242 table->nb_keys--;
243
244 return TRUE;
245} /* _ht_remove_trie(...) */
246
254int _ht_put_int_trie(HASH_TABLE* table, const char* key, HASH_INT_TYPE value) {
255 __n_assert(table, return FALSE);
256 __n_assert(key, return FALSE);
257
258 HASH_NODE* node = table->root;
259
260 for (size_t it = 0; key[it] != '\0'; it++) {
261 size_t index = (size_t)key[it] - table->alphabet_offset;
262 if (index >= table->alphabet_length) {
263 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
264 index = 0;
265 }
266 /* n_log( LOG_DEBUG , "index:%d" , index ); */
267 if (node->children[index] == NULL) {
268 /* create a node */
269 node->children[index] = _ht_new_node_trie(table, key[it]);
270 __n_assert(node->children[index], return FALSE);
271 } else {
272 /* nothing to do since node is existing */
273 }
274 /* go down a level, to the child referenced by index */
275 node = node->children[index];
276 }
277 /* At the end of the key, mark this node as the leaf node */
278 node->is_leaf = 1;
279 /* Put the key */
280 node->key = strdup(key);
281 if (!node->key) {
282 n_log(LOG_ERR, "strdup failure for key [%s]", key);
283 table->nb_keys++; /* compensate for upcoming remove */
284 _ht_remove_trie(table, key);
285 return FALSE;
286 }
287 /* Put the value */
288 node->data.ival = value;
289 node->type = HASH_INT;
290
291 table->nb_keys++;
292
293 return TRUE;
294} /* _ht_put_int_trie(...) */
295
303int _ht_put_double_trie(HASH_TABLE* table, const char* key, double value) {
304 __n_assert(table, return FALSE);
305 __n_assert(key, return FALSE);
306
307 HASH_NODE* node = table->root;
308
309 for (size_t it = 0; key[it] != '\0'; it++) {
310 size_t index = (size_t)key[it] - table->alphabet_offset;
311 if (index >= table->alphabet_length) {
312 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
313 index = 0;
314 }
315 if (node->children[index] == NULL) {
316 /* create a node */
317 node->children[index] = _ht_new_node_trie(table, key[it]);
318 __n_assert(node->children[index], return FALSE);
319 } else {
320 /* nothing to do since node is existing */
321 }
322 /* go down a level, to the child referenced by index */
323 node = node->children[index];
324 }
325 /* At the end of the key, mark this node as the leaf node */
326 node->is_leaf = 1;
327 /* Put the key */
328 node->key = strdup(key);
329 if (!node->key) {
330 n_log(LOG_ERR, "strdup failure for key [%s]", key);
331 table->nb_keys++; /* compensate for upcoming remove */
332 _ht_remove_trie(table, key);
333 return FALSE;
334 }
335 /* Put the value */
336 node->data.fval = value;
337 node->type = HASH_DOUBLE;
338
339 table->nb_keys++;
340
341 return TRUE;
342} /* _ht_put_double_trie(...) */
343
351int _ht_put_string_trie(HASH_TABLE* table, const char* key, char* string) {
352 __n_assert(table, return FALSE);
353 __n_assert(key, return FALSE);
354
355 HASH_NODE* node = table->root;
356
357 for (size_t it = 0; key[it] != '\0'; it++) {
358 size_t index = (size_t)key[it] - table->alphabet_offset;
359 if (index >= table->alphabet_length) {
360 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
361 index = 0;
362 }
363 if (node->children[index] == NULL) {
364 /* create a node */
365 node->children[index] = _ht_new_node_trie(table, key[it]);
366 __n_assert(node->children[index], return FALSE);
367 } else {
368 /* nothing to do since node is existing */
369 }
370 /* go down a level, to the child referenced by index */
371 node = node->children[index];
372 }
373 /* At the end of the key, mark this node as the leaf node */
374 node->is_leaf = 1;
375 /* Put the key */
376 node->key = strdup(key);
377 if (!node->key) {
378 n_log(LOG_ERR, "strdup failure for key [%s]", key);
379 table->nb_keys++; /* compensate for upcoming remove */
380 _ht_remove_trie(table, key);
381 return FALSE;
382 }
383 /* Put the value */
384 if (string) {
385 node->data.string = strdup(string);
386 if (!node->data.string) {
387 n_log(LOG_ERR, "strdup failure for value at key [%s]", key);
388 Free(node->key);
389 table->nb_keys++; /* compensate for upcoming remove */
390 _ht_remove_trie(table, key);
391 return FALSE;
392 }
393 } else {
394 node->data.string = NULL;
395 }
396
397 node->type = HASH_STRING;
398
399 table->nb_keys++;
400
401 return TRUE;
402} /* _ht_put_string_trie(...) */
403
411int _ht_put_string_ptr_trie(HASH_TABLE* table, const char* key, char* string) {
412 __n_assert(table, return FALSE);
413 __n_assert(key, return FALSE);
414
415 HASH_NODE* node = table->root;
416
417 for (size_t it = 0; key[it] != '\0'; it++) {
418 size_t index = (size_t)key[it] - table->alphabet_offset;
419 if (index >= table->alphabet_length) {
420 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
421 index = 0;
422 }
423 if (node->children[index] == NULL) {
424 /* create a node */
425 node->children[index] = _ht_new_node_trie(table, key[it]);
426 __n_assert(node->children[index], return FALSE);
427 } else {
428 /* nothing to do since node is existing */
429 }
430 /* go down a level, to the child referenced by index */
431 node = node->children[index];
432 }
433 /* At the end of the key, mark this node as the leaf node */
434 node->is_leaf = 1;
435 /* Put the key */
436 node->key = strdup(key);
437 if (!node->key) {
438 n_log(LOG_ERR, "strdup failure for key [%s]", key);
439 table->nb_keys++; /* compensate for upcoming remove */
440 _ht_remove_trie(table, key);
441 return FALSE;
442 }
443 /* Put the string */
444 node->data.string = string;
445 node->type = HASH_STRING;
446
447 table->nb_keys++;
448
449 return TRUE;
450} /* _ht_put_string_ptr_trie(...) */
451
460int _ht_put_ptr_trie(HASH_TABLE* table, const char* key, void* ptr, void (*destructor)(void* ptr)) {
461 __n_assert(table, return FALSE);
462 __n_assert(key, return FALSE);
463
464 HASH_NODE* node = table->root;
465
466 for (size_t it = 0; key[it] != '\0'; it++) {
467 size_t index = ((size_t)key[it] - table->alphabet_offset) % table->alphabet_length;
468 if (index >= table->alphabet_length) {
469 n_log(LOG_ERR, "Invalid value %u for charater at position %d of %s, set to 0", index, it, key);
470 index = 0;
471 }
472 if (node->children[index] == NULL) {
473 /* create a node */
474 node->children[index] = _ht_new_node_trie(table, key[it]);
475 __n_assert(node->children[index], return FALSE);
476 } else {
477 /* nothing to do since node is existing */
478 }
479 /* go down a level, to the child referenced by index */
480 node = node->children[index];
481 }
482 /* At the end of the key, mark this node as the leaf node */
483 node->is_leaf = 1;
484 /* Put the key */
485 node->key = strdup(key);
486 /* Put the value */
487 node->data.ptr = ptr;
488 if (destructor)
489 node->destroy_func = destructor;
490 node->type = HASH_PTR;
491
492 table->nb_keys++;
493
494 return TRUE;
495} /* _ht_put_ptr_trie(...) */
496
504 __n_assert(table, return NULL);
505 __n_assert(key, return NULL);
506
507 HASH_NODE* node = NULL;
508
509 if (key[0] != '\0') {
510 node = table->root;
511 for (size_t it = 0; key[it] != '\0'; it++) {
512 size_t index = (size_t)key[it] - table->alphabet_offset;
513 if (index >= table->alphabet_length) {
514 n_log(LOG_DEBUG, "Invalid value %d for charater at index %d of %s, set to 0", index, it, key);
515 return NULL;
516 }
517 if (node->children[index] == NULL) {
518 /* not found */
519 return NULL;
520 }
521 node = node->children[index];
522 }
523 } else {
524 node = NULL;
525 }
526 return node;
527} /* _ht_get_node_trie(...) */
528
536int _ht_get_int_trie(HASH_TABLE* table, const char* key, HASH_INT_TYPE* val) {
537 __n_assert(table, return FALSE);
538 __n_assert(key, return FALSE);
539 if (strlen(key) == 0)
540 return FALSE;
541
542 HASH_NODE* node = _ht_get_node_trie(table, key);
543
544 if (!node || !node->is_leaf)
545 return FALSE;
546
547 if (node->type != HASH_INT) {
548 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_INT, key is type %s", key, ht_node_type(node));
549 return FALSE;
550 }
551
552 (*val) = node->data.ival;
553
554 return TRUE;
555} /* _ht_get_int_trie() */
556
564int _ht_get_double_trie(HASH_TABLE* table, const char* key, double* val) {
565 __n_assert(table, return FALSE);
566 __n_assert(key, return FALSE);
567 if (strlen(key) == 0)
568 return FALSE;
569
570 HASH_NODE* node = _ht_get_node_trie(table, key);
571
572 if (!node || !node->is_leaf)
573 return FALSE;
574
575 if (node->type != HASH_DOUBLE) {
576 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_INT, key is type %s", key, ht_node_type(node));
577 return FALSE;
578 }
579
580 (*val) = node->data.fval;
581
582 return TRUE;
583} /* _ht_get_double_trie() */
584
592int _ht_get_string_trie(HASH_TABLE* table, const char* key, char** val) {
593 __n_assert(table, return FALSE);
594 __n_assert(key, return FALSE);
595 if (strlen(key) == 0)
596 return FALSE;
597
598 HASH_NODE* node = _ht_get_node_trie(table, key);
599
600 if (!node || !node->is_leaf)
601 return FALSE;
602
603 if (node->type != HASH_STRING) {
604 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_INT, key is type %s", key, ht_node_type(node));
605 return FALSE;
606 }
607
608 (*val) = node->data.string;
609
610 return TRUE;
611} /* _ht_get_string_trie() */
612
620int _ht_get_ptr_trie(HASH_TABLE* table, const char* key, void** val) {
621 __n_assert(table, return FALSE);
622 __n_assert(key, return FALSE);
623 if (strlen(key) == 0)
624 return FALSE;
625
626 HASH_NODE* node = _ht_get_node_trie(table, key);
627
628 if (!node || !node->is_leaf)
629 return FALSE;
630
631 if (node->type != HASH_PTR) {
632 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_PTR , key is type %s", key, ht_node_type(node));
633 return FALSE;
634 }
635
636 (*val) = node->data.ptr;
637
638 return TRUE;
639} /* _ht_get_ptr_trie() */
640
647 __n_assert(table, return FALSE);
648
649 _ht_node_destroy(table->root);
650
651 table->root = _ht_new_node_trie(table, '\0');
652
653 table->nb_keys = 0;
654 return TRUE;
655} /* _empty_ht_trie */
656
663 __n_assert(table && (*table), n_log(LOG_ERR, "Can't destroy table: already NULL"); return FALSE);
664
665 _ht_node_destroy((*table)->root);
666
667 Free((*table));
668
669 return TRUE;
670} /* _destroy_ht_trie */
671
678 if (!node)
679 return;
680
681 if (node->is_leaf) {
682 printf("key: %s, val: ", node->key);
683 switch (node->type) {
684 case HASH_INT:
685 printf("int: %ld", (long)node->data.ival);
686 break;
687 case HASH_DOUBLE:
688 printf("double: %f", node->data.fval);
689 break;
690 case HASH_PTR:
691 printf("ptr: %p", node->data.ptr);
692 break;
693 case HASH_STRING:
694 printf("%s", node->data.string);
695 break;
696 default:
697 printf("unknwow type %d", node->type);
698 break;
699 }
700 printf("\n");
701 }
702 for (size_t it = 0; it < table->alphabet_length; it++) {
703 _ht_print_trie_helper(table, node->children[it]);
704 }
705} /* _ht_print_trie_helper(...) */
706
712 __n_assert(table, return);
713 __n_assert(table->root, return);
714
715 HASH_NODE* node = table->root;
716
717 _ht_print_trie_helper(table, node);
718
719 return;
720} /* _ht_print_trie(...) */
721
728void _ht_search_trie_helper(LIST* results, HASH_NODE* node, int (*node_is_matching)(HASH_NODE* node)) {
729 if (!node)
730 return;
731
732 if (node->is_leaf) {
733 if (node_is_matching(node) == TRUE) {
734 list_push(results, strdup(node->key), &free);
735 }
736 }
737 for (size_t it = 0; it < node->alphabet_length; it++) {
738 _ht_search_trie_helper(results, node->children[it], node_is_matching);
739 }
740}
741
748LIST* _ht_search_trie(HASH_TABLE* table, int (*node_is_matching)(HASH_NODE* node)) {
749 __n_assert(table, return NULL);
750
752 __n_assert(results, return NULL);
753
754 _ht_search_trie_helper(results, table->root, node_is_matching);
755
756 if (results->nb_items < 1)
757 list_destroy(&results);
758
759 return results;
760} /* _ht_search_trie(...) */
761
769 __n_assert(results, return FALSE);
770
771 if (!node)
772 return FALSE;
773
774 for (size_t it = 0; it < node->alphabet_length; it++) {
775 _ht_depth_first_search(node->children[it], results);
776 }
777 if (node->is_leaf) {
778 if (results->nb_items < results->nb_max_items) {
779 return list_push(results, strdup(node->key), &free);
780 }
781 return TRUE;
782 }
783 return TRUE;
784} /* _ht_depth_first_search(...) */
785
786/************ CLASSIC HASH TABLE ************/
788#define ROTL64(x, r) (((x) << (r)) | ((x) >> (64 - (r))))
790#define ROTL32(x, r) (((x) << (r)) | ((x) >> (32 - (r))))
792#define BIG_CONSTANT(x) (x##LLU)
793
794/* NO-OP for little-endian platforms */
795#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
796#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
797#define BYTESWAP32(x) (x)
798#define BYTESWAP64(x) (x)
799#endif
800/* if __BYTE_ORDER__ is not predefined (like FreeBSD), use arch */
801#elif defined(__i386) || defined(__x86_64) || defined(__alpha) || defined(__vax)
802
803#define BYTESWAP32(x) (x)
804#define BYTESWAP64(x) (x)
805/* use __builtin_bswap32 if available */
806#elif defined(__GNUC__) || defined(__clang__)
807#ifdef __has_builtin
808#if __has_builtin(__builtin_bswap32)
809#define BYTESWAP32(x) __builtin_bswap32(x)
810#endif // __has_builtin(__builtin_bswap32)
811#if __has_builtin(__builtin_bswap64)
812#define BYTESWAP64(x) __builtin_bswap64(x)
813#endif // __has_builtin(__builtin_bswap64)
814#endif // __has_builtin
815#endif // defined(__GNUC__) || defined(__clang__)
816/* last resort (big-endian w/o __builtin_bswap) */
817#ifndef BYTESWAP32
819#define BYTESWAP32(x) ((((x) & 0xFF) << 24) | (((x) >> 24) & 0xFF) | (((x) & 0x0000FF00) << 8) | (((x) & 0x00FF0000) >> 8))
820#endif
821#ifndef BYTESWAP64
823#define BYTESWAP64(x) \
824 (((uint64_t)(x) << 56) | \
825 (((uint64_t)(x) << 40) & 0X00FF000000000000ULL) | \
826 (((uint64_t)(x) << 24) & 0X0000FF0000000000ULL) | \
827 (((uint64_t)(x) << 8) & 0X000000FF00000000ULL) | \
828 (((uint64_t)(x) >> 8) & 0X00000000FF000000ULL) | \
829 (((uint64_t)(x) >> 24) & 0X0000000000FF0000ULL) | \
830 (((uint64_t)(x) >> 40) & 0X000000000000FF00ULL) | \
831 ((uint64_t)(x) >> 56))
832#endif
833
840FORCE_INLINE uint32_t getblock32(const uint32_t* p, const size_t i) {
841 uint32_t result;
842 memcpy(&result, (const uint8_t*)p + i * 4, sizeof(result));
843 return BYTESWAP32(result);
844}
845
852FORCE_INLINE uint64_t getblock64(const uint64_t* p, const size_t i) {
853 uint64_t result;
854 memcpy(&result, (const uint8_t*)p + i * 8, sizeof(result));
855 return BYTESWAP64(result);
856}
857
863FORCE_INLINE uint32_t fmix32(uint32_t h) {
864 h ^= h >> 16;
865 h *= 0x85ebca6b;
866 h ^= h >> 13;
867 h *= 0xc2b2ae35;
868 h ^= h >> 16;
869
870 return h;
871} /* fmix32(...) */
872
878FORCE_INLINE uint64_t fmix64(uint64_t k) {
879 k ^= k >> 33;
880 k *= BIG_CONSTANT(0xff51afd7ed558ccd);
881 k ^= k >> 33;
882 k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
883 k ^= k >> 33;
884
885 return k;
886}
887
900// Safe forward-indexing version
901void MurmurHash3_x86_32(const void* key, const size_t len, const uint32_t seed, void* out) {
902 const uint8_t* data = (const uint8_t*)key;
903 const size_t nblocks = len / 4;
904
905 uint32_t h1 = seed;
906 const uint32_t c1 = 0xcc9e2d51;
907 const uint32_t c2 = 0x1b873593;
908
909 const uint32_t* blocks = (const uint32_t*)data;
910
911 for (size_t i = 0; i < nblocks; i++) {
912 uint32_t k1 = getblock32(blocks, i);
913 k1 *= c1;
914 k1 = ROTL32(k1, 15);
915 k1 *= c2;
916
917 h1 ^= k1;
918 h1 = ROTL32(h1, 13);
919 h1 = h1 * 5 + 0xe6546b64;
920 }
921
922 const uint8_t* tail = data + nblocks * 4;
923 uint32_t k1 = 0;
924 switch (len & 3) {
925 case 3:
926 k1 ^= (uint32_t)tail[2] << 16; /* fall through */
928 case 2:
929 k1 ^= (uint32_t)tail[1] << 8; /* fall through */
931 case 1:
932 k1 ^= (uint32_t)tail[0];
933 k1 *= c1;
934 k1 = ROTL32(k1, 15);
935 k1 *= c2;
936 h1 ^= k1;
937 break;
938 default:
939 break;
940 }
941
942 h1 ^= (uint32_t)len;
943 h1 = fmix32(h1);
944 *(uint32_t*)out = h1;
945} /* MurmurHash3_x86_32 */
946
959void MurmurHash3_x86_128(const void* key, const size_t len, const uint32_t seed, void* out) {
960 const uint8_t* data = (const uint8_t*)key;
961 const size_t nblocks = len / 16;
962
963 uint32_t h1 = seed;
964 uint32_t h2 = seed;
965 uint32_t h3 = seed;
966 uint32_t h4 = seed;
967
968 const uint32_t c1 = 0x239b961b;
969 const uint32_t c2 = 0xab0e9789;
970 const uint32_t c3 = 0x38b34ae5;
971 const uint32_t c4 = 0xa1e38b93;
972
973 const uint32_t* blocks = (const uint32_t*)data;
974
975 for (size_t i = 0; i < nblocks; i++) {
976 uint32_t k1 = getblock32(blocks, i * 4 + 0);
977 uint32_t k2 = getblock32(blocks, i * 4 + 1);
978 uint32_t k3 = getblock32(blocks, i * 4 + 2);
979 uint32_t k4 = getblock32(blocks, i * 4 + 3);
980
981 k1 *= c1;
982 k1 = ROTL32(k1, 15);
983 k1 *= c2;
984 h1 ^= k1;
985 h1 = ROTL32(h1, 19);
986 h1 += h2;
987 h1 = h1 * 5 + 0x561ccd1b;
988
989 k2 *= c2;
990 k2 = ROTL32(k2, 16);
991 k2 *= c3;
992 h2 ^= k2;
993 h2 = ROTL32(h2, 17);
994 h2 += h3;
995 h2 = h2 * 5 + 0x0bcaa747;
996
997 k3 *= c3;
998 k3 = ROTL32(k3, 17);
999 k3 *= c4;
1000 h3 ^= k3;
1001 h3 = ROTL32(h3, 15);
1002 h3 += h4;
1003 h3 = h3 * 5 + 0x96cd1c35;
1004
1005 k4 *= c4;
1006 k4 = ROTL32(k4, 18);
1007 k4 *= c1;
1008 h4 ^= k4;
1009 h4 = ROTL32(h4, 13);
1010 h4 += h1;
1011 h4 = h4 * 5 + 0x32ac3b17;
1012 }
1013
1014 // tail
1015 const uint8_t* tail = data + nblocks * 16;
1016
1017 uint32_t k1 = 0, k2 = 0, k3 = 0, k4 = 0;
1018
1019 switch (len & 15) {
1020 case 15:
1021 k4 ^= (uint32_t)tail[14] << 16; /* fall through */
1023 case 14:
1024 k4 ^= (uint32_t)tail[13] << 8; /* fall through */
1026 case 13:
1027 k4 ^= (uint32_t)tail[12];
1028 k4 *= c4;
1029 k4 = ROTL32(k4, 18);
1030 k4 *= c1;
1031 h4 ^= k4;
1032 /* fall through */
1034 case 12:
1035 k3 ^= (uint32_t)tail[11] << 24; /* fall through */
1037 case 11:
1038 k3 ^= (uint32_t)tail[10] << 16; /* fall through */
1040 case 10:
1041 k3 ^= (uint32_t)tail[9] << 8; /* fall through */
1043 case 9:
1044 k3 ^= (uint32_t)tail[8];
1045 k3 *= c3;
1046 k3 = ROTL32(k3, 17);
1047 k3 *= c4;
1048 h3 ^= k3;
1049 /* fall through */
1051 case 8:
1052 k2 ^= (uint32_t)tail[7] << 24; /* fall through */
1054 case 7:
1055 k2 ^= (uint32_t)tail[6] << 16; /* fall through */
1057 case 6:
1058 k2 ^= (uint32_t)tail[5] << 8; /* fall through */
1060 case 5:
1061 k2 ^= (uint32_t)tail[4];
1062 k2 *= c2;
1063 k2 = ROTL32(k2, 16);
1064 k2 *= c3;
1065 h2 ^= k2;
1066 /* fall through */
1068 case 4:
1069 k1 ^= (uint32_t)tail[3] << 24; /* fall through */
1071 case 3:
1072 k1 ^= (uint32_t)tail[2] << 16; /* fall through */
1074 case 2:
1075 k1 ^= (uint32_t)tail[1] << 8; /* fall through */
1077 case 1:
1078 k1 ^= (uint32_t)tail[0];
1079 k1 *= c1;
1080 k1 = ROTL32(k1, 15);
1081 k1 *= c2;
1082 h1 ^= k1;
1083 break;
1084 default:
1085 break;
1086 }
1087
1088 // finalization
1089 h1 ^= (uint32_t)len;
1090 h2 ^= (uint32_t)len;
1091 h3 ^= (uint32_t)len;
1092 h4 ^= (uint32_t)len;
1093
1094 h1 += h2 + h3 + h4;
1095 h2 += h1;
1096 h3 += h1;
1097 h4 += h1;
1098
1099 h1 = fmix32(h1);
1100 h2 = fmix32(h2);
1101 h3 = fmix32(h3);
1102 h4 = fmix32(h4);
1103
1104 h1 += h2 + h3 + h4;
1105 h2 += h1;
1106 h3 += h1;
1107 h4 += h1;
1108
1109 ((uint32_t*)out)[0] = h1;
1110 ((uint32_t*)out)[1] = h2;
1111 ((uint32_t*)out)[2] = h3;
1112 ((uint32_t*)out)[3] = h4;
1113} /* MurmurHash3_x86_128(...) */
1114
1127void MurmurHash3_x64_128(const void* key, const size_t len, const uint64_t seed, void* out) {
1128 const uint8_t* data = (const uint8_t*)key;
1129 const size_t nblocks = len / 16;
1130
1131 uint64_t h1 = seed;
1132 uint64_t h2 = seed;
1133
1134 const uint64_t c1 = 0x87c37b91114253d5ULL;
1135 const uint64_t c2 = 0x4cf5ad432745937fULL;
1136
1137 // Body
1138 const uint64_t* blocks = (const uint64_t*)data;
1139 for (size_t i = 0; i < nblocks; i++) {
1140 uint64_t k1 = getblock64(blocks, i * 2 + 0);
1141 uint64_t k2 = getblock64(blocks, i * 2 + 1);
1142
1143 k1 *= c1;
1144 k1 = ROTL64(k1, 31);
1145 k1 *= c2;
1146 h1 ^= k1;
1147
1148 h1 = ROTL64(h1, 27);
1149 h1 += h2;
1150 h1 = h1 * 5 + 0x52dce729;
1151
1152 k2 *= c2;
1153 k2 = ROTL64(k2, 33);
1154 k2 *= c1;
1155 h2 ^= k2;
1156
1157 h2 = ROTL64(h2, 31);
1158 h2 += h1;
1159 h2 = h2 * 5 + 0x38495ab5;
1160 }
1161
1162 // Tail
1163 const uint8_t* tail = data + nblocks * 16;
1164
1165 uint64_t k1 = 0;
1166 uint64_t k2 = 0;
1167
1168 switch (len & 15) {
1169 case 15:
1170 k2 ^= ((uint64_t)tail[14]) << 48; /* fall through */
1172 case 14:
1173 k2 ^= ((uint64_t)tail[13]) << 40; /* fall through */
1175 case 13:
1176 k2 ^= ((uint64_t)tail[12]) << 32; /* fall through */
1178 case 12:
1179 k2 ^= ((uint64_t)tail[11]) << 24; /* fall through */
1181 case 11:
1182 k2 ^= ((uint64_t)tail[10]) << 16; /* fall through */
1184 case 10:
1185 k2 ^= ((uint64_t)tail[9]) << 8; /* fall through */
1187 case 9:
1188 k2 ^= ((uint64_t)tail[8]);
1189 k2 *= c2;
1190 k2 = ROTL64(k2, 33);
1191 k2 *= c1;
1192 h2 ^= k2;
1193 /* fall through */
1195 case 8:
1196 k1 ^= ((uint64_t)tail[7]) << 56; /* fall through */
1198 case 7:
1199 k1 ^= ((uint64_t)tail[6]) << 48; /* fall through */
1201 case 6:
1202 k1 ^= ((uint64_t)tail[5]) << 40; /* fall through */
1204 case 5:
1205 k1 ^= ((uint64_t)tail[4]) << 32; /* fall through */
1207 case 4:
1208 k1 ^= ((uint64_t)tail[3]) << 24; /* fall through */
1210 case 3:
1211 k1 ^= ((uint64_t)tail[2]) << 16; /* fall through */
1213 case 2:
1214 k1 ^= ((uint64_t)tail[1]) << 8; /* fall through */
1216 case 1:
1217 k1 ^= ((uint64_t)tail[0]);
1218 k1 *= c1;
1219 k1 = ROTL64(k1, 31);
1220 k1 *= c2;
1221 h1 ^= k1;
1222 break;
1223 default:
1224 break;
1225 }
1226
1227 // Finalization
1228 h1 ^= len;
1229 h2 ^= len;
1230
1231 h1 += h2;
1232 h2 += h1;
1233
1234 h1 = fmix64(h1);
1235 h2 = fmix64(h2);
1236
1237 h1 += h2;
1238 h2 += h1;
1239
1240 ((uint64_t*)out)[0] = h1;
1241 ((uint64_t*)out)[1] = h2;
1242} /* MurmurHash3_x64_128()*/
1243
1250 static char* HASH_TYPE_STR[5] = {"HASH_INT", "HASH_DOUBLE", "HASH_STRING", "HASH_PTR", "HASH_UNKNOWN"};
1251
1252 __n_assert(node, return NULL);
1253
1254 if (node->type >= 0 && node->type < HASH_UNKNOWN)
1255 return HASH_TYPE_STR[node->type];
1256
1257 return NULL;
1258} /* ht_node_type(...) */
1259
1266HASH_NODE* _ht_get_node(HASH_TABLE* table, const char* key) {
1267 HASH_VALUE hash_value[2] = {0, 0};
1268 size_t index = 0;
1269
1270 HASH_NODE* node_ptr = NULL;
1271
1272 __n_assert(table, return NULL);
1273 __n_assert(key, return NULL);
1274
1275 if (key[0] == '\0')
1276 return NULL;
1277
1278 MurmurHash(key, strlen(key), table->seed, &hash_value);
1279 index = (hash_value[0]) % (table->size);
1280
1281 if (!table->hash_table[index]->start)
1282 return NULL;
1283
1284 list_foreach(list_node, table->hash_table[index]) {
1285 node_ptr = (HASH_NODE*)list_node->ptr;
1286 if (!strcmp(key, node_ptr->key)) {
1287 return node_ptr;
1288 }
1289 }
1290 return NULL;
1291} /* _ht_get_node() */
1292
1299HASH_NODE* _ht_new_node(HASH_TABLE* table, const char* key) {
1300 __n_assert(table, return NULL);
1301 __n_assert(key, return NULL);
1302
1303 HASH_NODE* new_hash_node = NULL;
1304
1305 HASH_VALUE hash_value[2] = {0, 0};
1306
1307 if (strlen(key) == 0)
1308 return NULL;
1309
1310 MurmurHash(key, strlen(key), table->seed, &hash_value);
1311
1312 Malloc(new_hash_node, HASH_NODE, 1);
1313 __n_assert(new_hash_node, n_log(LOG_ERR, "Could not allocate new_hash_node"); return NULL);
1314 new_hash_node->key = strdup(key);
1315 new_hash_node->key_id = '\0';
1316 __n_assert(new_hash_node->key, n_log(LOG_ERR, "Could not allocate new_hash_node->key"); Free(new_hash_node); return NULL);
1317 new_hash_node->hash_value = hash_value[0];
1318 new_hash_node->data.ptr = NULL;
1319 new_hash_node->destroy_func = NULL;
1320 new_hash_node->children = NULL;
1321 new_hash_node->is_leaf = 0;
1322 new_hash_node->need_rehash = 0;
1323 new_hash_node->alphabet_length = 0;
1324
1325 return new_hash_node;
1326} /* _ht_new_node */
1327
1336 __n_assert(table, return NULL);
1337 __n_assert(key, return NULL);
1338
1339 HASH_NODE* new_hash_node = NULL;
1340 new_hash_node = _ht_new_node(table, key);
1341 if (new_hash_node) {
1342 new_hash_node->data.ival = value;
1343 new_hash_node->type = HASH_INT;
1344 } else {
1345 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1346 }
1347 return new_hash_node;
1348} /* _ht_new_int_node */
1349
1357HASH_NODE* _ht_new_double_node(HASH_TABLE* table, const char* key, double value) {
1358 __n_assert(table, return NULL);
1359 __n_assert(key, return NULL);
1360
1361 HASH_NODE* new_hash_node = NULL;
1362 new_hash_node = _ht_new_node(table, key);
1363 if (new_hash_node) {
1364 new_hash_node->data.fval = value;
1365 new_hash_node->type = HASH_DOUBLE;
1366 } else {
1367 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1368 }
1369 return new_hash_node;
1370} /* _ht_new_double_node */
1371
1379HASH_NODE* _ht_new_string_node(HASH_TABLE* table, const char* key, char* value) {
1380 __n_assert(table, return NULL);
1381 __n_assert(key, return NULL);
1382
1383 HASH_NODE* new_hash_node = NULL;
1384 new_hash_node = _ht_new_node(table, key);
1385 if (new_hash_node) {
1386 if (value)
1387 new_hash_node->data.string = strdup(value);
1388 else
1389 new_hash_node->data.string = NULL;
1390 new_hash_node->type = HASH_STRING;
1391 } else {
1392 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1393 }
1394 return new_hash_node;
1395}
1396
1404HASH_NODE* _ht_new_string_ptr_node(HASH_TABLE* table, const char* key, char* value) {
1405 __n_assert(table, return NULL);
1406 __n_assert(key, return NULL);
1407
1408 HASH_NODE* new_hash_node = NULL;
1409 new_hash_node = _ht_new_node(table, key);
1410 if (new_hash_node) {
1411 new_hash_node->data.string = value;
1412 new_hash_node->type = HASH_STRING;
1413 } else {
1414 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1415 }
1416 return new_hash_node;
1417}
1418
1427HASH_NODE* _ht_new_ptr_node(HASH_TABLE* table, const char* key, void* value, void (*destructor)(void* ptr)) {
1428 __n_assert(table, return NULL);
1429 __n_assert(key, return NULL);
1430
1431 HASH_NODE* new_hash_node = NULL;
1432 new_hash_node = _ht_new_node(table, key);
1433 if (new_hash_node) {
1434 new_hash_node->data.ptr = value;
1435 new_hash_node->destroy_func = destructor;
1436 new_hash_node->type = HASH_PTR;
1437 } else {
1438 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1439 }
1440 return new_hash_node;
1441}
1442
1450int _ht_put_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE value) {
1451 HASH_NODE* node_ptr = NULL;
1452
1453 __n_assert(table, return FALSE);
1454 __n_assert(key, return FALSE);
1455
1456 if ((node_ptr = _ht_get_node(table, key))) {
1457 if (node_ptr->type == HASH_INT) {
1458 node_ptr->data.ival = value;
1459 return TRUE;
1460 }
1461 n_log(LOG_ERR, "Can't add key[\"%s\"] with type HASH_INT, key already exist with type %s", node_ptr->key, ht_node_type(node_ptr));
1462 return FALSE; /* key registered with another data type */
1463 }
1464
1465 int retcode = FALSE;
1466 node_ptr = _ht_new_int_node(table, key, value);
1467 if (node_ptr) {
1468 size_t index = (node_ptr->hash_value) % (table->size);
1469 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1470 if (retcode == TRUE) {
1471 table->nb_keys++;
1472 }
1473 }
1474 return retcode;
1475} /*_ht_put_int() */
1476
1484int _ht_put_double(HASH_TABLE* table, const char* key, double value) {
1485 HASH_NODE* node_ptr = NULL;
1486
1487 __n_assert(table, return FALSE);
1488 __n_assert(key, return FALSE);
1489
1490 if ((node_ptr = _ht_get_node(table, key))) {
1491 if (node_ptr->type == HASH_DOUBLE) {
1492 node_ptr->data.fval = value;
1493 return TRUE;
1494 }
1495 n_log(LOG_ERR, "Can't add key[\"%s\"] with type HASH_DOUBLE, key already exist with type %s", node_ptr->key, ht_node_type(node_ptr));
1496 return FALSE; /* key registered with another data type */
1497 }
1498
1499 int retcode = FALSE;
1500 node_ptr = _ht_new_double_node(table, key, value);
1501 if (node_ptr) {
1502 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1503 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1504 if (retcode == TRUE) {
1505 table->nb_keys++;
1506 }
1507 }
1508 return retcode;
1509} /*_ht_put_double()*/
1510
1519int _ht_put_ptr(HASH_TABLE* table, const char* key, void* ptr, void (*destructor)(void* ptr)) {
1520 HASH_NODE* node_ptr = NULL;
1521
1522 __n_assert(table, return FALSE);
1523 __n_assert(key, return FALSE);
1524
1525 if ((node_ptr = _ht_get_node(table, key))) {
1526 /* let's check the key isn't already assigned with another data type */
1527 if (node_ptr->type == HASH_PTR) {
1528 if (node_ptr->destroy_func) {
1529 node_ptr->destroy_func(node_ptr->data.ptr);
1530 node_ptr->data.ptr = ptr;
1531 node_ptr->destroy_func = destructor;
1532 }
1533 return TRUE;
1534 }
1535 n_log(LOG_ERR, "Can't add key[\"%s\"] with type HASH_PTR , key already exist with type %s", node_ptr->key, ht_node_type(node_ptr));
1536 return FALSE; /* key registered with another data type */
1537 }
1538
1539 int retcode = FALSE;
1540 node_ptr = _ht_new_ptr_node(table, key, ptr, destructor);
1541 if (node_ptr) {
1542 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1543 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1544 if (retcode == TRUE) {
1545 table->nb_keys++;
1546 }
1547 }
1548 return retcode;
1549} /* _ht_put_ptr() */
1550
1558int _ht_put_string(HASH_TABLE* table, const char* key, char* string) {
1559 HASH_NODE* node_ptr = NULL;
1560
1561 __n_assert(table, return FALSE);
1562 __n_assert(key, return FALSE);
1563
1564 if ((node_ptr = _ht_get_node(table, key))) {
1565 /* let's check the key isn't already assigned with another data type */
1566 if (node_ptr->type == HASH_STRING) {
1567 Free(node_ptr->data.string);
1568 node_ptr->data.string = strdup(string);
1569 return TRUE;
1570 }
1571 n_log(LOG_ERR, "Can't add key[\"%s\"] with type HASH_PTR , key already exist with type %s", node_ptr->key, ht_node_type(node_ptr));
1572 return FALSE; /* key registered with another data type */
1573 }
1574
1575 int retcode = FALSE;
1576 node_ptr = _ht_new_string_node(table, key, string);
1577 if (node_ptr) {
1578 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1579 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1580 if (retcode == TRUE) {
1581 table->nb_keys++;
1582 }
1583 }
1584 return retcode;
1585} /*_ht_put_string */
1586
1594int _ht_put_string_ptr(HASH_TABLE* table, const char* key, char* string) {
1595 HASH_NODE* node_ptr = NULL;
1596
1597 __n_assert(table, return FALSE);
1598 __n_assert(key, return FALSE);
1599
1600 if ((node_ptr = _ht_get_node(table, key))) {
1601 /* let's check the key isn't already assigned with another data type */
1602 if (node_ptr->type == HASH_STRING) {
1603 Free(node_ptr->data.string);
1604 node_ptr->data.string = string;
1605 return TRUE;
1606 }
1607 n_log(LOG_ERR, "Can't add key[\"%s\"] with type HASH_PTR , key already exist with type %s", node_ptr->key, ht_node_type(node_ptr));
1608 return FALSE; /* key registered with another data type */
1609 }
1610
1611 int retcode = FALSE;
1612 node_ptr = _ht_new_string_node(table, key, string);
1613 if (node_ptr) {
1614 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1615 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1616 if (retcode == TRUE) {
1617 table->nb_keys++;
1618 }
1619 }
1620 return retcode;
1621} /*_ht_put_string_ptr */
1622
1630int _ht_get_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE* val) {
1631 __n_assert(table, return FALSE);
1632 __n_assert(key, return FALSE);
1633 if (strlen(key) == 0)
1634 return FALSE;
1635
1636 HASH_NODE* node = _ht_get_node(table, key);
1637
1638 if (!node)
1639 return FALSE;
1640
1641 if (node->type != HASH_INT) {
1642 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_INT, key is type %s", key, ht_node_type(node));
1643 return FALSE;
1644 }
1645
1646 (*val) = node->data.ival;
1647
1648 return TRUE;
1649} /* _ht_get_int() */
1650
1658int _ht_get_double(HASH_TABLE* table, const char* key, double* val) {
1659 __n_assert(table, return FALSE);
1660 __n_assert(key, return FALSE);
1661
1662 if (strlen(key) == 0)
1663 return FALSE;
1664
1665 HASH_NODE* node = _ht_get_node(table, key);
1666
1667 if (!node)
1668 return FALSE;
1669
1670 if (node->type != HASH_DOUBLE) {
1671 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_DOUBLE, key is type %s", key, ht_node_type(node));
1672 return FALSE;
1673 }
1674
1675 (*val) = node->data.fval;
1676
1677 return TRUE;
1678} /* _ht_get_double()*/
1679
1687int _ht_get_ptr(HASH_TABLE* table, const char* key, void** val) {
1688 __n_assert(table, return FALSE);
1689 __n_assert(key, return FALSE);
1690 if (strlen(key) == 0)
1691 return FALSE;
1692
1693 HASH_NODE* node = _ht_get_node(table, key);
1694 if (!node)
1695 return FALSE;
1696
1697 if (node->type != HASH_PTR) {
1698 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_PTR, key is type %s", key, ht_node_type(node));
1699 return FALSE;
1700 }
1701
1702 (*val) = node->data.ptr;
1703
1704 return TRUE;
1705} /* _ht_get_ptr() */
1706
1714int _ht_get_string(HASH_TABLE* table, const char* key, char** val) {
1715 __n_assert(table, return FALSE);
1716 __n_assert(key, return FALSE);
1717 if (strlen(key) == 0)
1718 return FALSE;
1719
1720 HASH_NODE* node = _ht_get_node(table, key);
1721 if (!node)
1722 return FALSE;
1723
1724 if (node->type != HASH_STRING) {
1725 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_STRING, key is type %s", key, ht_node_type(node));
1726 return FALSE;
1727 }
1728
1729 (*val) = node->data.string;
1730
1731 return TRUE;
1732} /* _ht_get_string() */
1733
1740int _ht_remove(HASH_TABLE* table, const char* key) {
1741 HASH_VALUE hash_value[2] = {0, 0};
1742 size_t index = 0;
1743
1744 HASH_NODE* node_ptr = NULL;
1745 LIST_NODE* node_to_kill = NULL;
1746
1747 __n_assert(table, return FALSE);
1748 __n_assert(key, return FALSE);
1749 if (strlen(key) == 0)
1750 return FALSE;
1751
1752 MurmurHash(key, strlen(key), table->seed, &hash_value);
1753 index = (hash_value[0]) % (table->size);
1754
1755 if (!table->hash_table[index]->start) {
1756 n_log(LOG_ERR, "Can't remove key[\"%s\"], table is empty", key);
1757 return FALSE;
1758 }
1759
1760 list_foreach(list_node, table->hash_table[index]) {
1761 node_ptr = (HASH_NODE*)list_node->ptr;
1762 /* if we found the same */
1763 if (!strcmp(key, node_ptr->key)) {
1764 node_to_kill = list_node;
1765 break;
1766 }
1767 }
1768 if (node_to_kill) {
1769 node_ptr = remove_list_node(table->hash_table[index], node_to_kill, HASH_NODE);
1770 _ht_node_destroy(node_ptr);
1771
1772 table->nb_keys--;
1773
1774 return TRUE;
1775 }
1776 n_log(LOG_ERR, "Can't delete key[\"%s\"]: inexisting key", key);
1777 return FALSE;
1778} /* ht_remove() */
1779
1786 HASH_NODE* hash_node = NULL;
1787
1788 __n_assert(table, return FALSE);
1789
1790 HASH_VALUE index = 0;
1791 for (index = 0; index < table->size; index++) {
1792 while (table->hash_table[index] && table->hash_table[index]->start) {
1793 hash_node = remove_list_node(table->hash_table[index], table->hash_table[index]->start, HASH_NODE);
1794 _ht_node_destroy(hash_node);
1795 }
1796 }
1797 table->nb_keys = 0;
1798 return TRUE;
1799} /* empty_ht */
1800
1807 __n_assert(table && (*table), n_log(LOG_ERR, "Can't destroy table: already NULL"); return FALSE);
1808
1809 if ((*table)->hash_table) {
1810 // empty_ht( (*table) );
1811
1812 HASH_VALUE it = 0;
1813 for (it = 0; it < (*table)->size; it++) {
1814 if ((*table)->hash_table[it])
1815 list_destroy(&(*table)->hash_table[it]);
1816 }
1817 Free((*table)->hash_table);
1818 }
1819 Free((*table));
1820 return TRUE;
1821} /* _destroy_ht */
1822
1827void _ht_print(HASH_TABLE* table) {
1828 __n_assert(table, return);
1829 __n_assert(table->hash_table, return);
1830 ht_foreach(node, table) {
1831 printf("key:%s node:%s\n", ((HASH_NODE*)node->ptr)->key, ((HASH_NODE*)node->ptr)->key);
1832 }
1833
1834 return;
1835} /* _ht_print(...) */
1836
1843LIST* _ht_search(HASH_TABLE* table, int (*node_is_matching)(HASH_NODE* node)) {
1844 __n_assert(table, return NULL);
1845
1847 __n_assert(results, return NULL);
1848
1849 ht_foreach(node, table) {
1850 HASH_NODE* hnode = (HASH_NODE*)node->ptr;
1851 if (node_is_matching(hnode) == TRUE) {
1852 list_push(results, strdup(hnode->key), &free);
1853 }
1854 }
1855
1856 if (results->nb_items < 1)
1857 list_destroy(&results);
1858
1859 return results;
1860} /* _ht_search(...) */
1861
1862/************ HASH_TABLES FUNCTION POINTERS AND COMMON TABLE TYPE FUNCS ************/
1863
1870HASH_TABLE* new_ht_trie(size_t alphabet_length, size_t alphabet_offset) {
1871 HASH_TABLE* table = NULL;
1872
1873 Malloc(table, HASH_TABLE, 1);
1874 __n_assert(table, n_log(LOG_ERR, "Error allocating HASH_TABLE *table"); return NULL);
1875
1876 table->size = 0;
1877 table->seed = 0;
1878 table->nb_keys = 0;
1879 errno = 0;
1880 table->hash_table = NULL;
1881
1891 table->ht_remove = _ht_remove_trie;
1892 table->ht_search = _ht_search_trie;
1893 table->empty_ht = _empty_ht_trie;
1895 table->ht_print = _ht_print_trie;
1896
1897 table->alphabet_length = alphabet_length;
1898 table->alphabet_offset = alphabet_offset;
1899
1900 table->root = _ht_new_node_trie(table, '\0');
1901 if (!table->root) {
1902 n_log(LOG_ERR, "Couldn't allocate new_ht_trie with alphabet_length of %zu and alphabet offset of %d", alphabet_length, alphabet_offset);
1903 Free(table);
1904 return NULL;
1905 }
1906 table->mode = HASH_TRIE;
1907
1908 return table;
1909} /* new_ht_trie */
1910
1916HASH_TABLE* new_ht(size_t size) {
1917 HASH_TABLE* table = NULL;
1918
1919 if (size < 1) {
1920 n_log(LOG_ERR, "Invalide size %d for new_ht()", size);
1921 return NULL;
1922 }
1923 Malloc(table, HASH_TABLE, 1);
1924 __n_assert(table, n_log(LOG_ERR, "Error allocating HASH_TABLE *table"); return NULL);
1925
1926 table->size = size;
1927 table->seed = (uint32_t)rand() % 100000;
1928 table->nb_keys = 0;
1929 errno = 0;
1930 Malloc(table->hash_table, LIST*, size);
1931 // table -> hash_table = (LIST **)calloc( size, sizeof( LIST *) );
1932 __n_assert(table->hash_table, n_log(LOG_ERR, "Can't allocate table -> hash_table with size %d !", size); Free(table); return NULL);
1933
1934 size_t it = 0;
1935 for (it = 0; it < size; it++) {
1937 // if no valid table then unroll previsouly created slots
1938 if (!table->hash_table[it]) {
1939 n_log(LOG_ERR, "Can't allocate table -> hash_table[ %d ] !", it);
1940 size_t it_delete = 0;
1941 for (it_delete = 0; it_delete < it; it_delete++) {
1942 list_destroy(&table->hash_table[it_delete]);
1943 }
1944 Free(table->hash_table);
1945 Free(table);
1946 return NULL;
1947 }
1948 }
1949 table->mode = HASH_CLASSIC;
1950
1951 table->ht_put_int = _ht_put_int;
1953 table->ht_put_ptr = _ht_put_ptr;
1956 table->ht_get_int = _ht_get_int;
1959 table->ht_get_ptr = _ht_get_ptr;
1960 table->ht_get_node = _ht_get_node;
1961 table->ht_remove = _ht_remove;
1962 table->ht_search = _ht_search;
1963 table->empty_ht = _empty_ht;
1964 table->destroy_ht = _destroy_ht;
1965 table->ht_print = _ht_print;
1966
1967 return table;
1968} /* new_ht(...) */
1969
1976HASH_NODE* ht_get_node(HASH_TABLE* table, const char* key) {
1977 __n_assert(table, return FALSE);
1978 __n_assert(key, return FALSE);
1979 return table->ht_get_node(table, key);
1980} /*ht_get_node(...) */
1981
1989int ht_get_double(HASH_TABLE* table, const char* key, double* val) {
1990 __n_assert(table, return FALSE);
1991 __n_assert(key, return FALSE);
1992 return table->ht_get_double(table, key, val);
1993} /* ht_get_double(...) */
1994
2002int ht_get_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE* val) {
2003 __n_assert(table, return FALSE);
2004 __n_assert(key, return FALSE);
2005 return table->ht_get_int(table, key, val);
2006} /* ht_get_int(...) */
2007
2015int ht_get_ptr(HASH_TABLE* table, const char* key, void** val) {
2016 __n_assert(table, return FALSE);
2017 __n_assert(key, return FALSE);
2018 return table->ht_get_ptr(table, key, &(*val));
2019} /* ht_get_ptr(...) */
2020
2028int ht_get_string(HASH_TABLE* table, const char* key, char** val) {
2029 __n_assert(table, return FALSE);
2030 __n_assert(key, return FALSE);
2031 return table->ht_get_string(table, key, val);
2032} /* ht_get_string(...) */
2033
2041int ht_put_double(HASH_TABLE* table, const char* key, double value) {
2042 __n_assert(table, return FALSE);
2043 __n_assert(key, return FALSE);
2044 return table->ht_put_double(table, key, value);
2045} /* ht_put_double(...) */
2046
2054int ht_put_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE value) {
2055 __n_assert(table, return FALSE);
2056 __n_assert(key, return FALSE);
2057 return table->ht_put_int(table, key, value);
2058} /* ht_put_int(...) */
2059
2068int ht_put_ptr(HASH_TABLE* table, const char* key, void* ptr, void (*destructor)(void* ptr)) {
2069 __n_assert(table, return FALSE);
2070 __n_assert(key, return FALSE);
2071 return table->ht_put_ptr(table, key, ptr, destructor);
2072} /* ht_put_ptr(...) */
2073
2081int ht_put_string(HASH_TABLE* table, const char* key, char* string) {
2082 __n_assert(table, return FALSE);
2083 __n_assert(key, return FALSE);
2084 return table->ht_put_string(table, key, string);
2085} /* ht_put_string(...) */
2086
2094int ht_put_string_ptr(HASH_TABLE* table, const char* key, char* string) {
2095 __n_assert(table, return FALSE);
2096 __n_assert(key, return FALSE);
2097 return table->ht_put_string_ptr(table, key, string);
2098} /* ht_put_string_ptr(...) */
2099
2106int ht_remove(HASH_TABLE* table, const char* key) {
2107 __n_assert(table, return FALSE);
2108 __n_assert(key, return FALSE);
2109 return table->ht_remove(table, key);
2110} /* ht_remove(...) */
2111
2116void ht_print(HASH_TABLE* table) {
2117 __n_assert(table, return);
2118 table->ht_print(table);
2119 return;
2120} /* ht_print(...) */
2121
2128LIST* ht_search(HASH_TABLE* table, int (*node_is_matching)(HASH_NODE* node)) {
2129 __n_assert(table, return FALSE);
2130 return table->ht_search(table, node_is_matching);
2131} /* ht_search(...) */
2132
2139 __n_assert(table, return FALSE);
2140 return table->empty_ht(table);
2141} /* empty_ht(...) */
2142
2149 __n_assert((*table), return FALSE);
2150 return (*table)->destroy_ht(table);
2151} /* destroy_ht(...) */
2152
2160 __n_assert(table, return NULL);
2161 __n_assert(table->mode == HASH_CLASSIC, return NULL);
2162
2163 size_t index = 0;
2164 HASH_NODE* node_ptr = NULL;
2165
2166 index = (hash_value) % (table->size);
2167 if (!table->hash_table[index]->start) {
2168 return NULL;
2169 }
2170
2171 list_foreach(list_node, table->hash_table[index]) {
2172 node_ptr = (HASH_NODE*)list_node->ptr;
2173 if (hash_value == node_ptr->hash_value) {
2174 return node_ptr;
2175 }
2176 }
2177 return NULL;
2178} /* ht_get_node_ex() */
2179
2187int ht_get_ptr_ex(HASH_TABLE* table, HASH_VALUE hash_value, void** val) {
2188 __n_assert(table, return FALSE);
2189 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2190
2191 HASH_NODE* node = ht_get_node_ex(table, hash_value);
2192 if (!node)
2193 return FALSE;
2194
2195 if (node->type != HASH_PTR) {
2196 n_log(LOG_ERR, "Can't get key[\"%lld\"] of type HASH_PTR, key is type %s", hash_value, ht_node_type(node));
2197 return FALSE;
2198 }
2199
2200 (*val) = node->data.ptr;
2201
2202 return TRUE;
2203} /* ht_get_ptr_ex() */
2204
2213int ht_put_ptr_ex(HASH_TABLE* table, HASH_VALUE hash_value, void* val, void (*destructor)(void* ptr)) {
2214 __n_assert(table, return FALSE);
2215 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2216
2217 size_t index = 0;
2218 HASH_NODE* new_hash_node = NULL;
2219 HASH_NODE* node_ptr = NULL;
2220
2221 index = (hash_value) % (table->size);
2222
2223 /* we have some nodes here. Let's check if the key already exists */
2224 list_foreach(list_node, table->hash_table[index]) {
2225 node_ptr = (HASH_NODE*)list_node->ptr;
2226 /* if we found the same key we just replace the value and return */
2227 if (hash_value == node_ptr->hash_value) {
2228 /* let's check the key isn't already assigned with another data type */
2229 if (node_ptr->type == HASH_PTR) {
2230 if (list_node->destroy_func) {
2231 list_node->destroy_func(node_ptr->data.ptr);
2232 node_ptr->data.ptr = val;
2233 list_node->destroy_func = destructor;
2234 }
2235 return TRUE;
2236 }
2237 n_log(LOG_ERR, "Can't add key[\"%s\"] with type HASH_PTR , key already exist with type %s", node_ptr->key, ht_node_type(node_ptr));
2238 return FALSE; /* key registered with another data type */
2239 }
2240 }
2241
2242 Malloc(new_hash_node, HASH_NODE, 1);
2243 __n_assert(new_hash_node, n_log(LOG_ERR, "Could not allocate new_hash_node"); return FALSE);
2244
2245 new_hash_node->key = NULL;
2246 new_hash_node->hash_value = hash_value;
2247 new_hash_node->data.ptr = val;
2248 new_hash_node->type = HASH_PTR;
2249 new_hash_node->destroy_func = destructor;
2250
2251 table->nb_keys++;
2252
2253 return list_push(table->hash_table[index], new_hash_node, &_ht_node_destroy);
2254} /* ht_put_ptr_ex() */
2255
2262int ht_remove_ex(HASH_TABLE* table, HASH_VALUE hash_value) {
2263 __n_assert(table, return FALSE);
2264 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2265
2266 size_t index = 0;
2267 HASH_NODE* node_ptr = NULL;
2268 LIST_NODE* node_to_kill = NULL;
2269
2270 index = (hash_value) % (table->size);
2271 if (!table->hash_table[index]->start) {
2272 n_log(LOG_ERR, "Can't remove key[\"%d\"], table is empty", hash_value);
2273 return FALSE;
2274 }
2275
2276 list_foreach(list_node, table->hash_table[index]) {
2277 node_ptr = (HASH_NODE*)list_node->ptr;
2278 /* if we found the same */
2279 if (hash_value == node_ptr->hash_value) {
2280 node_to_kill = list_node;
2281 break;
2282 }
2283 }
2284 if (node_to_kill) {
2285 node_ptr = remove_list_node(table->hash_table[index], node_to_kill, HASH_NODE);
2286 _ht_node_destroy(node_ptr);
2287
2288 table->nb_keys--;
2289
2290 return TRUE;
2291 }
2292 n_log(LOG_ERR, "Can't delete key[\"%d\"]: inexisting key", hash_value);
2293 return FALSE;
2294} /* ht_remove_ex() */
2295
2303LIST* ht_get_completion_list(HASH_TABLE* table, const char* keybud, size_t max_results) {
2304 __n_assert(table, return NULL);
2305 __n_assert(keybud, return NULL);
2306
2307 LIST* results = new_generic_list(max_results);
2308 if (table->mode == HASH_TRIE) {
2309 HASH_NODE* node = _ht_get_node_trie(table, keybud);
2310 if (node) {
2311 if (list_push(results, strdup(keybud), &free) == TRUE) {
2312 _ht_depth_first_search(node, results);
2313 }
2314 } else {
2315 node = table->root;
2316 for (size_t it = 0; it < table->alphabet_length; it++) {
2317 if (node->children[it]) {
2318 char new_keybud[3] = "";
2319 new_keybud[0] = (char)(it + table->alphabet_offset);
2320 list_push(results, strdup(new_keybud), &free);
2321 }
2322 }
2323 }
2324 } else if (table->mode == HASH_CLASSIC) {
2325 ht_foreach(node, table) {
2326 HASH_NODE* hnode = (HASH_NODE*)node->ptr;
2327 if (strncasecmp(keybud, hnode->key, strlen(keybud)) == 0) {
2328 char* key = strdup(hnode->key);
2329 if (list_push(results, key, &free) == FALSE) {
2330 // n_log( LOG_ERR ,"not enough space in list or memory error, key %s not pushed !" , key );
2331 Free(key);
2332 }
2333 }
2334 }
2335 } else {
2336 n_log(LOG_ERR, "unsupported mode %d", table->mode);
2337 return NULL;
2338 }
2339 if (results && results->nb_items < 1)
2340 list_destroy(&results);
2341 return results;
2342} /* ht_get_completion_list(...) */
2343
2349int is_prime(size_t nb) {
2350 /* quick test for first primes */
2351 if (nb <= 1) return FALSE;
2352 if (nb <= 3) return TRUE;
2353
2354 /* skip middle five numbers in below loop */
2355 if ((nb % 2 == 0) || (nb % 3 == 0))
2356 return FALSE;
2357
2358 /* looping */
2359 for (size_t it = 5; it * it <= nb; it = it + 6) {
2360 if ((nb % it == 0) || (nb % (it + 2) == 0))
2361 return FALSE;
2362 }
2363 return TRUE;
2364} /* is_prime() */
2365
2371size_t next_prime(size_t nb) {
2372 if (nb <= 1)
2373 return 2;
2374
2375 size_t next_prime = nb;
2376 do {
2377 next_prime++;
2378 } while (is_prime(next_prime) == FALSE);
2379
2380 return next_prime;
2381} /* next_prime() */
2382
2389 __n_assert(table, return FALSE);
2390 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2391
2392 if (table->size == 0) return FALSE;
2393
2394 size_t nb_collisionned_lists = 0;
2395
2396 for (size_t hash_it = 0; hash_it < table->size; hash_it++) {
2397 if (table->hash_table[hash_it] && table->hash_table[hash_it]->nb_items > 1) {
2398 nb_collisionned_lists++;
2399 }
2400 }
2401 size_t collision_percentage = (100 * nb_collisionned_lists) / table->size;
2402 return (int)collision_percentage;
2403} /* ht_get_table_collision_percentage() */
2404
2411 __n_assert(table, return 0);
2412
2413 size_t optimum_size = (size_t)((double)table->nb_keys * 1.3);
2414 if (is_prime(optimum_size) != TRUE)
2415 optimum_size = next_prime(optimum_size);
2416 return optimum_size;
2417} /* ht_get_optimal_size() */
2418
2425int ht_resize(HASH_TABLE** table, size_t size) {
2426 __n_assert((*table), return FALSE);
2427
2428 if (size < 1) {
2429 n_log(LOG_ERR, "invalid size %d for hash table %p", size, (*table));
2430 return FALSE;
2431 }
2432 HT_FOREACH(node, (*table), { node->need_rehash = 1; });
2433
2434 if (size > (*table)->size) {
2435 Realloc((*table)->hash_table, LIST*, size);
2436 if (!(*table)->hash_table) {
2437 n_log(LOG_ERR, "Realloc did not augment the size the table !");
2438 } else {
2439 for (size_t it = (*table)->size; it < size; it++) {
2440 (*table)->hash_table[it] = new_generic_list(MAX_LIST_ITEMS);
2441 // if no valid table then unroll previsouly created slots
2442 if (!(*table)->hash_table[it]) {
2443 n_log(LOG_ERR, "Can't allocate table -> hash_table[ %d ] !", it);
2444 for (size_t it_delete = 0; it_delete < it; it_delete++) {
2445 list_destroy(&(*table)->hash_table[it_delete]);
2446 }
2447 Free((*table)->hash_table);
2448 Free((*table));
2449 return FALSE;
2450 }
2451 }
2452 for (size_t it = 0; it < size; it++) {
2453 if (((*table)->hash_table[it])) {
2454 while ((*table)->hash_table[it]->start) {
2455 HASH_NODE* hash_node = (HASH_NODE*)(*table)->hash_table[it]->start->ptr;
2456 if (hash_node->need_rehash == 0)
2457 break;
2458 hash_node->need_rehash = 0;
2459 LIST_NODE* node = list_node_shift((*table)->hash_table[it]);
2460 node->next = node->prev = NULL;
2461 size_t index = (hash_node->hash_value) % (size);
2462 list_node_push((*table)->hash_table[index], node);
2463 }
2464 }
2465 }
2466 }
2467 } else {
2468 for (size_t it = 0; it < (*table)->size; it++) {
2469 if (((*table)->hash_table[it])) {
2470 while ((*table)->hash_table[it]->start) {
2471 HASH_NODE* hash_node = (HASH_NODE*)(*table)->hash_table[it]->start->ptr;
2472 if (hash_node->need_rehash == 0)
2473 break;
2474 hash_node->need_rehash = 0;
2475 LIST_NODE* node = list_node_shift((*table)->hash_table[it]);
2476 node->next = node->prev = NULL;
2477 size_t index = (hash_node->hash_value) % (size);
2478 list_node_push((*table)->hash_table[index], node);
2479 }
2480 }
2481 }
2482 for (size_t it = size; it < (*table)->size; it++) {
2483 list_destroy(&(*table)->hash_table[it]);
2484 }
2485 Realloc((*table)->hash_table, LIST*, size);
2486 if (!(*table)->hash_table) {
2487 n_log(LOG_ERR, "Realloc did not reduce the resize the table !");
2488 }
2489 }
2490 (*table)->size = size;
2491
2492 return TRUE;
2493} /* ht_resize() */
2494
2501 __n_assert((*table), return FALSE);
2502
2503 size_t optimal_size = ht_get_optimal_size((*table));
2504 if (optimal_size == FALSE) {
2505 return FALSE;
2506 }
2507
2508 int collision_percentage = ht_get_table_collision_percentage((*table));
2509 if (collision_percentage == FALSE)
2510 return FALSE;
2511
2512 int resize_result = ht_resize(&(*table), optimal_size);
2513 if (resize_result == FALSE) {
2514 return FALSE;
2515 }
2516
2517 collision_percentage = ht_get_table_collision_percentage((*table));
2518 if (collision_percentage == FALSE) {
2519 return FALSE;
2520 }
2521
2522 return TRUE;
2523} /* ht_optimize() */
char * key
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:249
#define FALL_THROUGH
set windows if true
Definition n_common.h:53
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:185
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:256
#define FORCE_INLINE
FORCE_INLINE portable macro.
Definition n_common.h:145
#define Realloc(__ptr, __struct, __size)
Realloc Handler to get errors.
Definition n_common.h:211
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:240
int(* ht_put_int)(struct HASH_TABLE *table, const char *key, int64_t val)
put an integer
Definition n_hash.h:137
size_t alphabet_length
HASH_TRIE mode: size of alphabet and so size of children allocated array.
Definition n_hash.h:113
int need_rehash
flag to mark a node for rehash
Definition n_hash.h:109
HASH_NODE *(* ht_get_node)(struct HASH_TABLE *table, const char *key)
get HASH_NODE at 'key' from table
Definition n_hash.h:135
char key_id
key id of the node if any
Definition n_hash.h:97
int(* ht_get_string)(struct HASH_TABLE *table, const char *key, char **val)
get a char *string from a key's node
Definition n_hash.h:153
int(* ht_put_string)(struct HASH_TABLE *table, const char *key, char *val)
put an char *string
Definition n_hash.h:143
char * key
string key of the node if any, else NULL
Definition n_hash.h:95
int64_t ival
integral type
Definition n_hash.h:83
int is_leaf
HASH_TRIE mode: does it have a value.
Definition n_hash.h:107
HASH_NODE * root
HASH_TRIE mode: Start of tree.
Definition n_hash.h:127
void * ptr
pointer type
Definition n_hash.h:87
union HASH_DATA data
data inside the node
Definition n_hash.h:103
int(* ht_get_ptr)(struct HASH_TABLE *table, const char *key, void **val)
get a pointer from a key's node
Definition n_hash.h:151
int type
type of the node
Definition n_hash.h:101
int(* empty_ht)(struct HASH_TABLE *table)
empty a hash table.
Definition n_hash.h:159
LIST ** hash_table
HASH_CLASSIC mode: preallocated hash table.
Definition n_hash.h:125
size_t alphabet_offset
HASH_TRIE mode: offset to deduce to individual key digits.
Definition n_hash.h:131
int(* ht_get_double)(struct HASH_TABLE *table, const char *key, double *val)
get a double from a key's node
Definition n_hash.h:149
size_t alphabet_length
HASH_TRIE mode: size of the alphabet.
Definition n_hash.h:129
unsigned int mode
hashing mode, murmurhash and classic HASH_MURMUR, or HASH_TRIE
Definition n_hash.h:133
size_t seed
table's seed
Definition n_hash.h:123
int(* destroy_ht)(struct HASH_TABLE **table)
destroy a hash table
Definition n_hash.h:161
int(* ht_put_string_ptr)(struct HASH_TABLE *table, const char *key, char *val)
put an char *string pointer
Definition n_hash.h:145
int(* ht_remove)(struct HASH_TABLE *table, const char *key)
remove given's key node from the table
Definition n_hash.h:155
void(* ht_print)(struct HASH_TABLE *table)
print table
Definition n_hash.h:163
char * string
char *type
Definition n_hash.h:89
int(* ht_put_double)(struct HASH_TABLE *table, const char *key, double val)
put a double
Definition n_hash.h:139
struct HASH_NODE ** children
HASH_TRIE mode: pointers to children.
Definition n_hash.h:111
HASH_VALUE hash_value
numeric key of the node if any, else < 0
Definition n_hash.h:99
double fval
double type
Definition n_hash.h:85
size_t size
size of the hash table
Definition n_hash.h:119
int(* ht_put_ptr)(struct HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr))
put a a pointer
Definition n_hash.h:141
int(* ht_get_int)(struct HASH_TABLE *table, const char *key, int64_t *val)
get an int from a key's node
Definition n_hash.h:147
size_t nb_keys
total number of used keys in the table
Definition n_hash.h:121
LIST *(* ht_search)(struct HASH_TABLE *table, int(*node_is_matching)(HASH_NODE *node))
search elements given an expression
Definition n_hash.h:157
void(* destroy_func)(void *ptr)
destroy_func
Definition n_hash.h:105
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition n_hash.c:2015
#define ht_foreach(__ITEM_, __HASH_)
ForEach macro helper (classic / old)
Definition n_hash.h:171
int ht_put_ptr_ex(HASH_TABLE *table, HASH_VALUE hash_value, void *val, void(*destructor)(void *ptr))
put a pointer value with given key in the targeted hash table (HASH_CLASSIC only)
Definition n_hash.c:2213
char * ht_node_type(HASH_NODE *node)
get the type of a node , text version
Definition n_hash.c:1249
LIST * ht_search(HASH_TABLE *table, int(*node_is_matching)(HASH_NODE *node))
seach table for matching nodes
Definition n_hash.c:2128
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition n_hash.c:2148
int ht_remove(HASH_TABLE *table, const char *key)
remove and delete node at key in table
Definition n_hash.c:2106
HASH_NODE * ht_get_node_ex(HASH_TABLE *table, HASH_VALUE hash_value)
return the associated key's node inside the hash_table (HASH_CLASSIC only)
Definition n_hash.c:2159
#define HASH_PTR
value of pointer type inside the hash node
Definition n_hash.h:57
HASH_TABLE * new_ht(size_t size)
Create a hash table with the given size.
Definition n_hash.c:1916
#define MurmurHash(__key, __len, __seed, __out)
Murmur hash macro helper 64 bits.
Definition n_hash.h:72
int ht_get_table_collision_percentage(HASH_TABLE *table)
get table collision percentage (HASH_CLASSIC mode only)
Definition n_hash.c:2388
int ht_get_double(HASH_TABLE *table, const char *key, double *val)
get double at 'key' from 'table'
Definition n_hash.c:1989
#define HASH_DOUBLE
value of double type inside the hash node
Definition n_hash.h:53
int empty_ht(HASH_TABLE *table)
empty a table
Definition n_hash.c:2138
#define HASH_STRING
value of char * type inside the hash node
Definition n_hash.h:55
void ht_print(HASH_TABLE *table)
print contents of table
Definition n_hash.c:2116
LIST * ht_get_completion_list(HASH_TABLE *table, const char *keybud, size_t max_results)
get next matching keys in table tree
Definition n_hash.c:2303
size_t HASH_VALUE
type of a HASH_VALUE
Definition n_hash.h:78
int ht_put_double(HASH_TABLE *table, const char *key, double value)
put a double value with given key in the targeted hash table
Definition n_hash.c:2041
size_t ht_get_optimal_size(HASH_TABLE *table)
get optimal array size based on nb=(number_of_key*1.3) && if( !isprime(nb) )nb=nextprime(nb) (HASH_CL...
Definition n_hash.c:2410
int ht_get_string(HASH_TABLE *table, const char *key, char **val)
get string at 'key' from 'table'
Definition n_hash.c:2028
int is_prime(size_t nb)
test if number is a prime number or not
Definition n_hash.c:2349
#define HASH_INT_TYPE
type of a HASH_INT in 64 bits
Definition n_hash.h:74
size_t next_prime(size_t nb)
compute next prime number after nb
Definition n_hash.c:2371
int ht_put_string(HASH_TABLE *table, const char *key, char *string)
put a string value (copy/dup) with given key in the targeted hash table
Definition n_hash.c:2081
int ht_resize(HASH_TABLE **table, size_t size)
rehash table according to size (HASH_CLASSIC mode only)
Definition n_hash.c:2425
void MurmurHash3_x86_128(const void *key, const size_t len, const uint32_t seed, void *out)
MurmurHash3 was written by Austin Appleby, and is placed in the public domain.
Definition n_hash.c:959
void MurmurHash3_x64_128(const void *key, const size_t len, const uint64_t seed, void *out)
MurmurHash3 was written by Austin Appleby, and is placed in the public domain.
Definition n_hash.c:1127
int ht_remove_ex(HASH_TABLE *table, HASH_VALUE hash_value)
Remove a key from a hash table (HASH_CLASSIC only)
Definition n_hash.c:2262
#define HASH_CLASSIC
Murmur hash using hash key string, hash key numeric value, index table with lists of elements.
Definition n_hash.h:61
int ht_get_int(HASH_TABLE *table, const char *key, int64_t *val)
get node at 'key' from 'table'
Definition n_hash.c:2002
HASH_NODE * ht_get_node(HASH_TABLE *table, const char *key)
get node at 'key' from 'table'
Definition n_hash.c:1976
HASH_TABLE * new_ht_trie(size_t alphabet_length, size_t alphabet_offset)
create a TRIE hash table with the alphabet_size, each key value beeing decreased by alphabet_offset
Definition n_hash.c:1870
#define HASH_TRIE
TRIE tree using hash key string.
Definition n_hash.h:63
int ht_put_ptr(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr))
put a pointer to the string value with given key in the targeted hash table
Definition n_hash.c:2068
int ht_put_int(HASH_TABLE *table, const char *key, int64_t value)
put an integral value with given key in the targeted hash table
Definition n_hash.c:2054
int ht_optimize(HASH_TABLE **table)
try an automatic optimization of the table
Definition n_hash.c:2500
#define HASH_INT
compatibility with existing rot func
Definition n_hash.h:51
void MurmurHash3_x86_32(const void *key, const size_t len, const uint32_t seed, void *out)
MurmurHash3 was written by Austin Appleby, and is placed in the public domain.
Definition n_hash.c:901
int ht_put_string_ptr(HASH_TABLE *table, const char *key, char *string)
put a string value (pointer) with given key in the targeted hash table
Definition n_hash.c:2094
#define HT_FOREACH(__ITEM_, __HASH_,...)
ForEach macro helper.
Definition n_hash.h:195
int ht_get_ptr_ex(HASH_TABLE *table, HASH_VALUE hash_value, void **val)
Retrieve a pointer value in the hash table, at the given key.
Definition n_hash.c:2187
#define HASH_UNKNOWN
value of unknow type inside the hash node
Definition n_hash.h:59
structure of a hash table node
Definition n_hash.h:93
structure of a hash table
Definition n_hash.h:117
size_t nb_max_items
maximum number of item in the list.
Definition n_list.h:44
struct LIST_NODE * prev
pointer to the previous node
Definition n_list.h:35
LIST_NODE * start
pointer to the start of the list
Definition n_list.h:47
size_t nb_items
number of item currently in the list
Definition n_list.h:42
struct LIST_NODE * next
pointer to the next node
Definition n_list.h:33
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:200
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper.
Definition n_list.h:66
#define remove_list_node(__LIST_, __NODE_, __TYPE_)
Remove macro helper for void pointer casting.
Definition n_list.h:77
LIST_NODE * list_node_shift(LIST *list)
Get a LIST_NODE pointer from the start of the list.
Definition n_list.c:146
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:519
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:19
#define MAX_LIST_ITEMS
flag to pass to new_generic_list for the maximum possible number of item in a list
Definition n_list.h:56
int list_node_push(LIST *list, LIST_NODE *node)
Add a filled node to the end of the list.
Definition n_list.c:97
Structure of a generic LIST container.
Definition n_list.h:40
Structure of a generic list node.
Definition n_list.h:25
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:70
#define LOG_DEBUG
debug-level messages
Definition n_log.h:65
#define LOG_ERR
error conditions
Definition n_log.h:57
Common headers and low-level functions & define.
void _ht_node_destroy(void *node)
destroy a HASH_NODE by first calling the HASH_NODE destructor
Definition n_hash.c:88
int _ht_get_int(HASH_TABLE *table, const char *key, int64_t *val)
Retrieve an integral value in the hash table, at the given key.
Definition n_hash.c:1630
int _destroy_ht(HASH_TABLE **table)
Free and set the table to NULL.
Definition n_hash.c:1806
int _ht_get_double(HASH_TABLE *table, const char *key, double *val)
Retrieve a double value in the hash table, at the given key.
Definition n_hash.c:1658
int _ht_get_int_trie(HASH_TABLE *table, const char *key, int64_t *val)
Retrieve an integral value in the hash table, at the given key.
Definition n_hash.c:536
HASH_NODE * _ht_new_double_node(HASH_TABLE *table, const char *key, double value)
node creation, HASH_CLASSIC mode
Definition n_hash.c:1357
int _ht_put_double(HASH_TABLE *table, const char *key, double value)
put a double value with given key in the targeted hash table
Definition n_hash.c:1484
HASH_NODE * _ht_new_string_ptr_node(HASH_TABLE *table, const char *key, char *value)
node creation, HASH_CLASSIC mode, pointer to string value
Definition n_hash.c:1404
int _ht_put_string_trie(HASH_TABLE *table, const char *key, char *string)
put a duplicate of the string value with given key in the targeted hash table [TRIE HASH TABLE)
Definition n_hash.c:351
uint32_t getblock32(const uint32_t *p, const size_t i)
Block read - modified from murmur's author, ajusted byte endianess.
Definition n_hash.c:840
int _ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
Retrieve a pointer value in the hash table, at the given key.
Definition n_hash.c:1687
HASH_NODE * _ht_new_node_trie(HASH_TABLE *table, const char key)
node creation, HASH_CLASSIC mode
Definition n_hash.c:32
int _ht_depth_first_search(HASH_NODE *node, LIST *results)
recursive, helper for ht_get_completion_list, get the list of leaf starting from node
Definition n_hash.c:768
HASH_NODE * _ht_new_int_node(HASH_TABLE *table, const char *key, int64_t value)
node creation, HASH_CLASSIC mode
Definition n_hash.c:1335
uint32_t fmix32(uint32_t h)
Finalization mix - force all bits of a hash block to avalanche (from murmur's author)
Definition n_hash.c:863
void _ht_print_trie(HASH_TABLE *table)
Generic print func call for trie trees.
Definition n_hash.c:711
int _ht_get_string_trie(HASH_TABLE *table, const char *key, char **val)
Retrieve an char *string value in the hash table, at the given key.
Definition n_hash.c:592
int _ht_put_int_trie(HASH_TABLE *table, const char *key, int64_t value)
put an integral value with given key in the targeted hash table [TRIE HASH TABLE)
Definition n_hash.c:254
void _ht_print_trie_helper(HASH_TABLE *table, HASH_NODE *node)
Recursive function to print trie tree's keys and values.
Definition n_hash.c:677
HASH_NODE * _ht_get_node_trie(HASH_TABLE *table, const char *key)
retrieve a HASH_NODE at key from table
Definition n_hash.c:503
int _ht_put_string(HASH_TABLE *table, const char *key, char *string)
put a null terminated char *string with given key in the targeted hash table (copy of string)
Definition n_hash.c:1558
HASH_NODE * _ht_new_ptr_node(HASH_TABLE *table, const char *key, void *value, void(*destructor)(void *ptr))
node creation, HASH_CLASSIC mode, pointer to string value
Definition n_hash.c:1427
int _ht_put_string_ptr_trie(HASH_TABLE *table, const char *key, char *string)
put a pointer to the string value with given key in the targeted hash table [TRIE HASH TABLE)
Definition n_hash.c:411
int _ht_put_ptr(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr))
put a pointer value with given key in the targeted hash table
Definition n_hash.c:1519
void _ht_print(HASH_TABLE *table)
Generic print func call for classic hash tables.
Definition n_hash.c:1827
HASH_NODE * _ht_new_node(HASH_TABLE *table, const char *key)
node creation, HASH_CLASSIC mode
Definition n_hash.c:1299
char * _ht_find_longest_prefix_trie(HASH_TABLE *table, const char *key)
find the longest prefix string that is not the current key
Definition n_hash.c:158
int _ht_get_ptr_trie(HASH_TABLE *table, const char *key, void **val)
Retrieve a pointer value in the hash table, at the given key.
Definition n_hash.c:620
int _ht_get_string(HASH_TABLE *table, const char *key, char **val)
Retrieve a char *string value in the hash table, at the given key.
Definition n_hash.c:1714
int _empty_ht(HASH_TABLE *table)
Empty a hash table (CLASSIC mode)
Definition n_hash.c:1785
#define BIG_CONSTANT(x)
max unsigned long long
Definition n_hash.c:792
int _ht_is_leaf_node_trie(HASH_TABLE *table, const char *key)
Search a key and tell if it's holding a value (leaf)
Definition n_hash.c:66
int _ht_put_string_ptr(HASH_TABLE *table, const char *key, char *string)
put a null terminated char *string with given key in the targeted hash table (pointer)
Definition n_hash.c:1594
LIST * _ht_search_trie(HASH_TABLE *table, int(*node_is_matching)(HASH_NODE *node))
Search tree's keys and apply a matching func to put results in the list.
Definition n_hash.c:748
size_t _ht_check_trie_divergence(HASH_TABLE *table, const char *key)
check and return branching index in key if any
Definition n_hash.c:123
int _ht_put_double_trie(HASH_TABLE *table, const char *key, double value)
put a double value with given key in the targeted hash table [TRIE HASH TABLE)
Definition n_hash.c:303
HASH_NODE * _ht_get_node(HASH_TABLE *table, const char *key)
return the associated key's node inside the hash_table
Definition n_hash.c:1266
#define BYTESWAP64(x)
32 bits bytes swap
Definition n_hash.c:823
#define BYTESWAP32(x)
32 bits bytes swap
Definition n_hash.c:819
int _destroy_ht_trie(HASH_TABLE **table)
Free and set the table to NULL (TRIE mode)
Definition n_hash.c:662
int _ht_put_ptr_trie(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr))
put a pointer to the string value with given key in the targeted hash table [TRIE HASH TABLE)
Definition n_hash.c:460
int _empty_ht_trie(HASH_TABLE *table)
Empty a TRIE hash table.
Definition n_hash.c:646
int _ht_get_double_trie(HASH_TABLE *table, const char *key, double *val)
Retrieve an double value in the hash table, at the given key.
Definition n_hash.c:564
int _ht_remove(HASH_TABLE *table, const char *key)
Remove a key from a hash table.
Definition n_hash.c:1740
uint64_t getblock64(const uint64_t *p, const size_t i)
Block read - modified from murmur's author, ajusted byte endianess.
Definition n_hash.c:852
int _ht_put_int(HASH_TABLE *table, const char *key, int64_t value)
put an integral value with given key in the targeted hash table [CLASSIC HASH TABLE)
Definition n_hash.c:1450
int _ht_remove_trie(HASH_TABLE *table, const char *key)
Remove a key from a trie table and destroy the node.
Definition n_hash.c:191
LIST * _ht_search(HASH_TABLE *table, int(*node_is_matching)(HASH_NODE *node))
Search hash table's keys and apply a matching func to put results in the list.
Definition n_hash.c:1843
HASH_NODE * _ht_new_string_node(HASH_TABLE *table, const char *key, char *value)
node creation, HASH_CLASSIC mode, strdup of value
Definition n_hash.c:1379
void _ht_search_trie_helper(LIST *results, HASH_NODE *node, int(*node_is_matching)(HASH_NODE *node))
Recursive function to search tree's keys and apply a matching func to put results in the list.
Definition n_hash.c:728
#define ROTL64(x, r)
64 bit rotate left
Definition n_hash.c:788
uint64_t fmix64(uint64_t k)
Finalization mix - force all bits of a hash block to avalanche (from murmur's author)
Definition n_hash.c:878
#define ROTL32(x, r)
32 bit rotate left
Definition n_hash.c:790
Hash functions and table.
Generic log system.
N_STR and string function declaration.