Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_hash.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
27#include "nilorea/n_common.h"
28#include "nilorea/n_log.h"
29#include "nilorea/n_hash.h"
30#include "nilorea/n_str.h"
31
32#include <pthread.h>
33#include <string.h>
34#include <strings.h>
35
36#ifdef __windows__
37#include <winsock.h>
38#else
39#include <arpa/inet.h>
40#endif
41
42/* Trie tree tables */
43
51 __n_assert(table, return NULL);
52
53 HASH_NODE* new_hash_node = NULL;
54 Malloc(new_hash_node, HASH_NODE, 1);
55 __n_assert(new_hash_node, n_log(LOG_ERR, "Could not allocate new_hash_node"); return NULL);
56 new_hash_node->key = NULL;
57 new_hash_node->hash_value = 0;
58 new_hash_node->data.ptr = NULL;
59 new_hash_node->destroy_func = NULL;
60 new_hash_node->children = NULL;
61 new_hash_node->is_leaf = 0;
62 new_hash_node->need_rehash = 0;
63 new_hash_node->alphabet_length = table->alphabet_length;
64
65 Malloc(new_hash_node->children, HASH_NODE*, table->alphabet_length);
66 __n_assert(new_hash_node->children, n_log(LOG_ERR, "Could not allocate new_hash_node"); Free(new_hash_node); return NULL);
67
68 /* n_log( LOG_DEBUG , "node: %d %c table: alpha: %d / offset %d" , key , key , table -> alphabet_length , table -> alphabet_offset ); */
69
70 for (size_t it = 0; it < table->alphabet_length; it++) {
71 new_hash_node->children[it] = NULL;
72 }
73 new_hash_node->is_leaf = 0;
74 new_hash_node->key_id = key;
75 return new_hash_node;
76} /* _ht_new_node_trie(...) */
77
84int _ht_is_leaf_node_trie(HASH_TABLE* table, const char* key) {
85 __n_assert(table, return -1);
86
87 /* checks if the prefix match of key and root is a leaf node */
88 HASH_NODE* node = table->root;
89 for (size_t it = 0; key[it]; it++) {
90 size_t index = (size_t)key[it] - table->alphabet_offset;
91 if (index >= table->alphabet_length) {
92 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
93 index = 0;
94 }
95 if (node->children[index]) {
96 node = node->children[index];
97 } else {
98 return 0;
99 }
100 }
101 return node->is_leaf;
102} /* _ht_is_leaf_node_trie(...) */
103
108void _ht_node_destroy(void* node) {
109 HASH_NODE* node_ptr = (HASH_NODE*)node;
110 __n_assert(node_ptr, return);
111 if (node_ptr->type == HASH_STRING) {
112 Free(node_ptr->data.string);
113 }
114 if (node_ptr->type == HASH_PTR) {
115 if (node_ptr->destroy_func && node_ptr->data.ptr) {
116 node_ptr->destroy_func(node_ptr->data.ptr);
117 }
118 /* No free by default. must be passed as a destroy_func
119 else
120 {
121 Free( node_ptr -> data . ptr );
122 }
123 */
124 }
125 FreeNoLog(node_ptr->key);
126 if (node_ptr->alphabet_length > 0) {
127 for (size_t it = 0; it < node_ptr->alphabet_length; it++) {
128 if (node_ptr->children[it]) {
129 _ht_node_destroy(node_ptr->children[it]);
130 }
131 }
132 Free(node_ptr->children);
133 }
134 Free(node_ptr);
135} /* _ht_node_destroy */
136
143size_t _ht_check_trie_divergence(HASH_TABLE* table, const char* key) {
144 __n_assert(table, return SIZE_MAX);
145 __n_assert(key, return SIZE_MAX);
146
147 HASH_NODE* node = table->root;
148
149 size_t last_index = 0;
150 for (size_t it = 0; key[it] != '\0'; it++) {
151 size_t index = (size_t)key[it] - table->alphabet_offset;
152 if (index >= table->alphabet_length) {
153 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
154 index = 0;
155 }
156 if (node->children[index]) {
157 /* child check */
158 for (size_t it2 = 0; it2 < table->alphabet_length; it2++) {
159 if (it2 != (unsigned)index && node->children[it2]) {
160 /* child found, update branch index */
161 last_index = it + 1;
162 break;
163 }
164 }
165 /* Go to the next child in the sequence */
166 node = node->children[index];
167 }
168 }
169 return last_index;
170} /* _ht_check_trie_divergence(...) */
171
178char* _ht_find_longest_prefix_trie(HASH_TABLE* table, const char* key) {
179 __n_assert(table, return NULL);
180 __n_assert(key, return NULL);
181
182 size_t len = strlen(key);
183
184 /* start with full key and backtrack to search for divergences */
185 char* longest_prefix = NULL;
186 Malloc(longest_prefix, char, len + 1);
187 __n_assert(longest_prefix, return NULL);
188 memcpy(longest_prefix, key, len);
189 /* memcpy does not add a null terminator; set it explicitly */
190 longest_prefix[len] = '\0';
191
192 /* check branching from the root */
193 size_t branch_index = _ht_check_trie_divergence(table, longest_prefix);
194 if (branch_index > 0 && branch_index != SIZE_MAX) {
195 /* truncate to the branch point */
196 longest_prefix[branch_index - 1] = '\0';
197 /* shrink the allocation; Realloc preserves the original pointer on
198 failure so the caller still gets a valid terminated string */
199 Realloc(longest_prefix, char, branch_index + 1);
200 }
201 return longest_prefix;
202} /* _ht_find_longest_prefix_trie(...) */
203
210int _ht_remove_trie(HASH_TABLE* table, const char* key) {
211 __n_assert(table, return FALSE);
212 __n_assert(table->root, return FALSE);
213 __n_assert(key, return FALSE);
214
215 /* stop if matching node not a leaf node */
216 if (!_ht_is_leaf_node_trie(table, key)) {
217 return FALSE;
218 }
219
220 HASH_NODE* node = table->root;
221 /* find the longest prefix string that is not the current key */
222 char* longest_prefix = _ht_find_longest_prefix_trie(table, key);
223 if (!longest_prefix) {
224 n_log(LOG_ERR, "couldn't find longest prefix for key %s", key);
225 return FALSE;
226 }
227 if (longest_prefix[0] == '\0') {
228 Free(longest_prefix);
229 return FALSE;
230 }
231 /* keep track of position in the tree */
232 size_t it = 0;
233 for (it = 0; longest_prefix[it] != '\0'; it++) {
234 size_t index = (size_t)longest_prefix[it] - table->alphabet_offset;
235 if (index >= table->alphabet_length) {
236 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
237 index = 0;
238 }
239 if (node->children[index] != NULL) {
240 /* common prefix, keep moving */
241 node = node->children[index];
242 } else {
243 /* not found */
244 Free(longest_prefix);
245 return FALSE;
246 }
247 }
248 /* deepest common node between the two strings */
249 /* deleting the sequence corresponding to key */
250 for (; key[it] != '\0'; it++) {
251 size_t index = (size_t)key[it] - table->alphabet_offset;
252 if (index >= table->alphabet_length) {
253 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
254 index = 0;
255 }
256 if (node->children[index]) {
257 /* delete the remaining sequence */
258 HASH_NODE* node_to_kill = node->children[index];
259 node->children[index] = NULL;
260 _ht_node_destroy(node_to_kill);
261 }
262 }
263 Free(longest_prefix);
264
265 table->nb_keys--;
266
267 return TRUE;
268} /* _ht_remove_trie(...) */
269
277int _ht_put_int_trie(HASH_TABLE* table, const char* key, HASH_INT_TYPE value) {
278 __n_assert(table, return FALSE);
279 __n_assert(key, return FALSE);
280
281 HASH_NODE* node = table->root;
282
283 for (size_t it = 0; key[it] != '\0'; it++) {
284 size_t index = (size_t)key[it] - table->alphabet_offset;
285 if (index >= table->alphabet_length) {
286 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
287 index = 0;
288 }
289 /* n_log( LOG_DEBUG , "index:%d" , index ); */
290 if (node->children[index] == NULL) {
291 /* create a node */
292 node->children[index] = _ht_new_node_trie(table, key[it]);
293 __n_assert(node->children[index], return FALSE);
294 } else {
295 /* nothing to do since node is existing */
296 }
297 /* go down a level, to the child referenced by index */
298 node = node->children[index];
299 }
300 /* At the end of the key, mark this node as the leaf node */
301 int was_leaf = node->is_leaf;
302 if (was_leaf) {
303 FreeNoLog(node->key);
304 }
305 node->is_leaf = 1;
306 /* Put the key */
307 node->key = strdup(key);
308 if (!node->key) {
309 n_log(LOG_ERR, "strdup failure for key [%s]", key);
310 table->nb_keys++; /* compensate for upcoming remove */
311 _ht_remove_trie(table, key);
312 return FALSE;
313 }
314 /* Put the value */
315 node->data.ival = value;
316 node->type = HASH_INT;
317
318 if (!was_leaf) {
319 table->nb_keys++;
320 }
321
322 return TRUE;
323} /* _ht_put_int_trie(...) */
324
332int _ht_put_double_trie(HASH_TABLE* table, const char* key, double value) {
333 __n_assert(table, return FALSE);
334 __n_assert(key, return FALSE);
335
336 HASH_NODE* node = table->root;
337
338 for (size_t it = 0; key[it] != '\0'; it++) {
339 size_t index = (size_t)key[it] - table->alphabet_offset;
340 if (index >= table->alphabet_length) {
341 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
342 index = 0;
343 }
344 if (node->children[index] == NULL) {
345 /* create a node */
346 node->children[index] = _ht_new_node_trie(table, key[it]);
347 __n_assert(node->children[index], return FALSE);
348 } else {
349 /* nothing to do since node is existing */
350 }
351 /* go down a level, to the child referenced by index */
352 node = node->children[index];
353 }
354 /* At the end of the key, mark this node as the leaf node */
355 int was_leaf = node->is_leaf;
356 if (was_leaf) {
357 FreeNoLog(node->key);
358 }
359 node->is_leaf = 1;
360 /* Put the key */
361 node->key = strdup(key);
362 if (!node->key) {
363 n_log(LOG_ERR, "strdup failure for key [%s]", key);
364 table->nb_keys++; /* compensate for upcoming remove */
365 _ht_remove_trie(table, key);
366 return FALSE;
367 }
368 /* Put the value */
369 node->data.fval = value;
370 node->type = HASH_DOUBLE;
371
372 if (!was_leaf) {
373 table->nb_keys++;
374 }
375
376 return TRUE;
377} /* _ht_put_double_trie(...) */
378
386// cppcheck-suppress constParameterCallback -- callback signature must match typedef
387int _ht_put_string_trie(HASH_TABLE* table, const char* key, char* string) {
388 __n_assert(table, return FALSE);
389 __n_assert(key, return FALSE);
390
391 HASH_NODE* node = table->root;
392
393 for (size_t it = 0; key[it] != '\0'; it++) {
394 size_t index = (size_t)key[it] - table->alphabet_offset;
395 if (index >= table->alphabet_length) {
396 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
397 index = 0;
398 }
399 if (node->children[index] == NULL) {
400 /* create a node */
401 node->children[index] = _ht_new_node_trie(table, key[it]);
402 __n_assert(node->children[index], return FALSE);
403 } else {
404 /* nothing to do since node is existing */
405 }
406 /* go down a level, to the child referenced by index */
407 node = node->children[index];
408 }
409 /* At the end of the key, mark this node as the leaf node */
410 int was_leaf = node->is_leaf;
411 if (was_leaf) {
412 FreeNoLog(node->key);
413 FreeNoLog(node->data.string);
414 }
415 node->is_leaf = 1;
416 /* Put the key */
417 node->key = strdup(key);
418 if (!node->key) {
419 n_log(LOG_ERR, "strdup failure for key [%s]", key);
420 table->nb_keys++; /* compensate for upcoming remove */
421 _ht_remove_trie(table, key);
422 return FALSE;
423 }
424 /* Put the value */
425 if (string) {
426 node->data.string = strdup(string);
427 if (!node->data.string) {
428 n_log(LOG_ERR, "strdup failure for value at key [%s]", key);
429 Free(node->key);
430 table->nb_keys++; /* compensate for upcoming remove */
431 _ht_remove_trie(table, key);
432 return FALSE;
433 }
434 } else {
435 node->data.string = NULL;
436 }
437
438 node->type = HASH_STRING;
439
440 if (!was_leaf) {
441 table->nb_keys++;
442 }
443
444 return TRUE;
445} /* _ht_put_string_trie(...) */
446
454int _ht_put_string_ptr_trie(HASH_TABLE* table, const char* key, char* string) {
455 __n_assert(table, return FALSE);
456 __n_assert(key, return FALSE);
457
458 HASH_NODE* node = table->root;
459
460 for (size_t it = 0; key[it] != '\0'; it++) {
461 size_t index = (size_t)key[it] - table->alphabet_offset;
462 if (index >= table->alphabet_length) {
463 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
464 index = 0;
465 }
466 if (node->children[index] == NULL) {
467 /* create a node */
468 node->children[index] = _ht_new_node_trie(table, key[it]);
469 __n_assert(node->children[index], return FALSE);
470 } else {
471 /* nothing to do since node is existing */
472 }
473 /* go down a level, to the child referenced by index */
474 node = node->children[index];
475 }
476 /* At the end of the key, mark this node as the leaf node */
477 int was_leaf = node->is_leaf;
478 if (was_leaf) {
479 FreeNoLog(node->key);
480 FreeNoLog(node->data.string);
481 }
482 node->is_leaf = 1;
483 /* Put the key - string pointer variant does not strdup the value, but key must be duplicated */
484 node->key = strdup(key);
485 if (!node->key) {
486 n_log(LOG_ERR, "strdup failure for key [%s]", key);
487 table->nb_keys++; /* compensate for upcoming remove */
488 _ht_remove_trie(table, key);
489 return FALSE;
490 }
491 /* Put the string pointer (not a copy - caller owns the string) */
492 node->data.string = string;
493 node->type = HASH_STRING;
494
495 if (!was_leaf) {
496 table->nb_keys++;
497 }
498
499 return TRUE;
500} /* _ht_put_string_ptr_trie(...) */
501
511int _ht_put_ptr_trie(HASH_TABLE* table, const char* key, void* ptr, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
512 __n_assert(table, return FALSE);
513 __n_assert(key, return FALSE);
514
515 HASH_NODE* node = table->root;
516
517 for (size_t it = 0; key[it] != '\0'; it++) {
518 size_t index = (size_t)key[it] - table->alphabet_offset;
519 if (index >= table->alphabet_length) {
520 n_log(LOG_ERR, "Invalid value %zu for character at position %zu of %s, set to 0", index, it, key);
521 index = 0;
522 }
523 if (node->children[index] == NULL) {
524 /* create a node */
525 node->children[index] = _ht_new_node_trie(table, key[it]);
526 __n_assert(node->children[index], return FALSE);
527 } else {
528 /* nothing to do since node is existing */
529 }
530 /* go down a level, to the child referenced by index */
531 node = node->children[index];
532 }
533 /* At the end of the key, mark this node as the leaf node */
534 int was_leaf = node->is_leaf;
535 if (was_leaf) {
536 FreeNoLog(node->key);
537 /* free old value if a destructor was set */
538 if (node->destroy_func && node->data.ptr) {
539 node->destroy_func(node->data.ptr);
540 }
541 }
542 node->is_leaf = 1;
543 /* Put the key */
544 node->key = strdup(key);
545 if (!node->key) {
546 n_log(LOG_ERR, "strdup failure for key [%s]", key);
547 table->nb_keys++; /* compensate for upcoming remove */
548 _ht_remove_trie(table, key);
549 return FALSE;
550 }
551 /* Put the value */
552 node->data.ptr = ptr;
553 node->destroy_func = destructor;
554 node->duplicate_func = duplicator;
555 node->type = HASH_PTR;
556
557 if (!was_leaf) {
558 table->nb_keys++;
559 }
560
561 return TRUE;
562} /* _ht_put_ptr_trie(...) */
563
571 __n_assert(table, return NULL);
572 __n_assert(key, return NULL);
573
574 HASH_NODE* node = NULL;
575
576 if (key[0] != '\0') {
577 node = table->root;
578 for (size_t it = 0; key[it] != '\0'; it++) {
579 size_t index = (size_t)key[it] - table->alphabet_offset;
580 if (index >= table->alphabet_length) {
581 n_log(LOG_DEBUG, "Invalid value %d for charater at index %d of %s, set to 0", index, it, key);
582 return NULL;
583 }
584 if (node->children[index] == NULL) {
585 /* not found */
586 return NULL;
587 }
588 node = node->children[index];
589 }
590 } else {
591 node = NULL;
592 }
593 return node;
594} /* _ht_get_node_trie(...) */
595
603int _ht_get_int_trie(HASH_TABLE* table, const char* key, HASH_INT_TYPE* val) {
604 __n_assert(table, return FALSE);
605 __n_assert(key, return FALSE);
606 if (strlen(key) == 0)
607 return FALSE;
608
609 HASH_NODE* node = _ht_get_node_trie(table, key);
610
611 if (!node || !node->is_leaf)
612 return FALSE;
613
614 if (node->type != HASH_INT) {
615 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_INT, key is type %s", key, ht_node_type(node));
616 return FALSE;
617 }
618
619 (*val) = node->data.ival;
620
621 return TRUE;
622} /* _ht_get_int_trie() */
623
631int _ht_get_double_trie(HASH_TABLE* table, const char* key, double* val) {
632 __n_assert(table, return FALSE);
633 __n_assert(key, return FALSE);
634 if (strlen(key) == 0)
635 return FALSE;
636
637 HASH_NODE* node = _ht_get_node_trie(table, key);
638
639 if (!node || !node->is_leaf)
640 return FALSE;
641
642 if (node->type != HASH_DOUBLE) {
643 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_DOUBLE, key is type %s", key, ht_node_type(node));
644 return FALSE;
645 }
646
647 (*val) = node->data.fval;
648
649 return TRUE;
650} /* _ht_get_double_trie() */
651
659int _ht_get_string_trie(HASH_TABLE* table, const char* key, char** val) {
660 __n_assert(table, return FALSE);
661 __n_assert(key, return FALSE);
662 if (strlen(key) == 0)
663 return FALSE;
664
665 HASH_NODE* node = _ht_get_node_trie(table, key);
666
667 if (!node || !node->is_leaf)
668 return FALSE;
669
670 if (node->type != HASH_STRING) {
671 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_STRING, key is type %s", key, ht_node_type(node));
672 return FALSE;
673 }
674
675 (*val) = node->data.string;
676
677 return TRUE;
678} /* _ht_get_string_trie() */
679
687int _ht_get_ptr_trie(HASH_TABLE* table, const char* key, void** val) {
688 __n_assert(table, return FALSE);
689 __n_assert(key, return FALSE);
690 if (strlen(key) == 0)
691 return FALSE;
692
693 HASH_NODE* node = _ht_get_node_trie(table, key);
694
695 if (!node || !node->is_leaf)
696 return FALSE;
697
698 if (node->type != HASH_PTR) {
699 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_PTR , key is type %s", key, ht_node_type(node));
700 return FALSE;
701 }
702
703 (*val) = node->data.ptr;
704
705 return TRUE;
706} /* _ht_get_ptr_trie() */
707
714 __n_assert(table, return FALSE);
715
716 _ht_node_destroy(table->root);
717
718 table->root = _ht_new_node_trie(table, '\0');
719
720 table->nb_keys = 0;
721 return TRUE;
722} /* _empty_ht_trie */
723
730 __n_assert(table && (*table), n_log(LOG_ERR, "Can't destroy table: already NULL"); return FALSE);
731
732 _ht_node_destroy((*table)->root);
733
734 Free((*table));
735
736 return TRUE;
737} /* _destroy_ht_trie */
738
745 if (!node)
746 return;
747
748 if (node->is_leaf) {
749 printf("key: %s, val: ", node->key);
750 switch (node->type) {
751 case HASH_INT:
752 printf("int: %ld", (long)node->data.ival);
753 break;
754 case HASH_DOUBLE:
755 printf("double: %f", node->data.fval);
756 break;
757 case HASH_PTR:
758 printf("ptr: %p", node->data.ptr);
759 break;
760 case HASH_STRING:
761 printf("%s", node->data.string);
762 break;
763 default:
764 printf("unknwow type %d", node->type);
765 break;
766 }
767 printf("\n");
768 }
769 for (size_t it = 0; it < table->alphabet_length; it++) {
770 _ht_print_trie_helper(table, node->children[it]);
771 }
772} /* _ht_print_trie_helper(...) */
773
779 __n_assert(table, return);
780 __n_assert(table->root, return);
781
782 HASH_NODE* node = table->root;
783
784 _ht_print_trie_helper(table, node);
785
786 return;
787} /* _ht_print_trie(...) */
788
795void _ht_search_trie_helper(LIST* results, HASH_NODE* node, int (*node_is_matching)(HASH_NODE* node)) {
796 if (!node)
797 return;
798
799 if (node->is_leaf) {
800 if (node_is_matching(node) == TRUE) {
801 list_push(results, strdup(node->key), &free);
802 }
803 }
804 for (size_t it = 0; it < node->alphabet_length; it++) {
805 _ht_search_trie_helper(results, node->children[it], node_is_matching);
806 }
807}
808
815LIST* _ht_search_trie(HASH_TABLE* table, int (*node_is_matching)(HASH_NODE* node)) {
816 __n_assert(table, return NULL);
817
819 __n_assert(results, return NULL);
820
821 _ht_search_trie_helper(results, table->root, node_is_matching);
822
823 if (results->nb_items < 1)
824 list_destroy(&results);
825
826 return results;
827} /* _ht_search_trie(...) */
828
836 __n_assert(results, return FALSE);
837
838 if (!node)
839 return FALSE;
840
841 for (size_t it = 0; it < node->alphabet_length; it++) {
842 _ht_depth_first_search(node->children[it], results);
843 }
844 if (node->is_leaf) {
845 if (results->nb_items < results->nb_max_items) {
846 return list_push(results, strdup(node->key), &free);
847 }
848 return TRUE;
849 }
850 return TRUE;
851} /* _ht_depth_first_search(...) */
852
853/* Classic hash table */
855#define ROTL64(x, r) (((x) << (r)) | ((x) >> (64 - (r))))
857#define ROTL32(x, r) (((x) << (r)) | ((x) >> (32 - (r))))
859#define BIG_CONSTANT(x) (x##LLU)
860
861/* NO-OP for little-endian platforms */
862#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
863#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
864#define BYTESWAP32(x) (x)
865#define BYTESWAP64(x) (x)
866#endif
867/* if __BYTE_ORDER__ is not predefined (like FreeBSD), use arch */
868#elif defined(__i386) || defined(__x86_64) || defined(__alpha) || defined(__vax)
869
870#define BYTESWAP32(x) (x)
871#define BYTESWAP64(x) (x)
872/* use __builtin_bswap32 if available */
873#elif defined(__GNUC__) || defined(__clang__)
874#ifdef __has_builtin
875#if __has_builtin(__builtin_bswap32)
876#define BYTESWAP32(x) __builtin_bswap32(x)
877#endif // __has_builtin(__builtin_bswap32)
878#if __has_builtin(__builtin_bswap64)
879#define BYTESWAP64(x) __builtin_bswap64(x)
880#endif // __has_builtin(__builtin_bswap64)
881#endif // __has_builtin
882#endif // defined(__GNUC__) || defined(__clang__)
883/* last resort (big-endian w/o __builtin_bswap) */
884#ifndef BYTESWAP32
886#define BYTESWAP32(x) ((((x) & 0xFF) << 24) | (((x) >> 24) & 0xFF) | (((x) & 0x0000FF00) << 8) | (((x) & 0x00FF0000) >> 8))
887#endif
888#ifndef BYTESWAP64
890#define BYTESWAP64(x) \
891 (((uint64_t)(x) << 56) | \
892 (((uint64_t)(x) << 40) & 0X00FF000000000000ULL) | \
893 (((uint64_t)(x) << 24) & 0X0000FF0000000000ULL) | \
894 (((uint64_t)(x) << 8) & 0X000000FF00000000ULL) | \
895 (((uint64_t)(x) >> 8) & 0X00000000FF000000ULL) | \
896 (((uint64_t)(x) >> 24) & 0X0000000000FF0000ULL) | \
897 (((uint64_t)(x) >> 40) & 0X000000000000FF00ULL) | \
898 ((uint64_t)(x) >> 56))
899#endif
900
907FORCE_INLINE uint32_t getblock32(const uint32_t* p, const size_t i) {
908 uint32_t result;
909 memcpy(&result, (const uint8_t*)p + i * 4, sizeof(result));
910 return BYTESWAP32(result);
911}
912
919FORCE_INLINE uint64_t getblock64(const uint64_t* p, const size_t i) {
920 uint64_t result;
921 memcpy(&result, (const uint8_t*)p + i * 8, sizeof(result));
922 return BYTESWAP64(result);
923}
924
930FORCE_INLINE uint32_t fmix32(uint32_t h) {
931 h ^= h >> 16;
932 h *= 0x85ebca6b;
933 h ^= h >> 13;
934 h *= 0xc2b2ae35;
935 h ^= h >> 16;
936
937 return h;
938} /* fmix32(...) */
939
945FORCE_INLINE uint64_t fmix64(uint64_t k) {
946 k ^= k >> 33;
947 k *= BIG_CONSTANT(0xff51afd7ed558ccd);
948 k ^= k >> 33;
949 k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
950 k ^= k >> 33;
951
952 return k;
953}
954
967// Safe forward-indexing version
968void MurmurHash3_x86_32(const void* key, const size_t len, const uint32_t seed, void* out) {
969 const uint8_t* data = (const uint8_t*)key;
970 const size_t nblocks = len / 4;
971
972 uint32_t h1 = seed;
973 const uint32_t c1 = 0xcc9e2d51;
974 const uint32_t c2 = 0x1b873593;
975
976 const uint32_t* blocks = (const uint32_t*)data;
977
978 for (size_t i = 0; i < nblocks; i++) {
979 uint32_t k1 = getblock32(blocks, i);
980 k1 *= c1;
981 k1 = ROTL32(k1, 15);
982 k1 *= c2;
983
984 h1 ^= k1;
985 h1 = ROTL32(h1, 13);
986 h1 = h1 * 5 + 0xe6546b64;
987 }
988
989 const uint8_t* tail = data + nblocks * 4;
990 uint32_t k1 = 0;
991 switch (len & 3) {
992 case 3:
993 k1 ^= (uint32_t)tail[2] << 16; /* fall through */
995 case 2:
996 k1 ^= (uint32_t)tail[1] << 8; /* fall through */
998 case 1:
999 k1 ^= (uint32_t)tail[0];
1000 k1 *= c1;
1001 k1 = ROTL32(k1, 15);
1002 k1 *= c2;
1003 h1 ^= k1;
1004 break;
1005 default:
1006 break;
1007 }
1008
1009 h1 ^= (uint32_t)len;
1010 h1 = fmix32(h1);
1011 *(uint32_t*)out = h1;
1012} /* MurmurHash3_x86_32 */
1013
1026void MurmurHash3_x86_128(const void* key, const size_t len, const uint32_t seed, void* out) {
1027 const uint8_t* data = (const uint8_t*)key;
1028 const size_t nblocks = len / 16;
1029
1030 uint32_t h1 = seed;
1031 uint32_t h2 = seed;
1032 uint32_t h3 = seed;
1033 uint32_t h4 = seed;
1034
1035 const uint32_t c1 = 0x239b961b;
1036 const uint32_t c2 = 0xab0e9789;
1037 const uint32_t c3 = 0x38b34ae5;
1038 const uint32_t c4 = 0xa1e38b93;
1039
1040 const uint32_t* blocks = (const uint32_t*)data;
1041
1042 for (size_t i = 0; i < nblocks; i++) {
1043 uint32_t k1 = getblock32(blocks, i * 4 + 0);
1044 uint32_t k2 = getblock32(blocks, i * 4 + 1);
1045 uint32_t k3 = getblock32(blocks, i * 4 + 2);
1046 uint32_t k4 = getblock32(blocks, i * 4 + 3);
1047
1048 k1 *= c1;
1049 k1 = ROTL32(k1, 15);
1050 k1 *= c2;
1051 h1 ^= k1;
1052 h1 = ROTL32(h1, 19);
1053 h1 += h2;
1054 h1 = h1 * 5 + 0x561ccd1b;
1055
1056 k2 *= c2;
1057 k2 = ROTL32(k2, 16);
1058 k2 *= c3;
1059 h2 ^= k2;
1060 h2 = ROTL32(h2, 17);
1061 h2 += h3;
1062 h2 = h2 * 5 + 0x0bcaa747;
1063
1064 k3 *= c3;
1065 k3 = ROTL32(k3, 17);
1066 k3 *= c4;
1067 h3 ^= k3;
1068 h3 = ROTL32(h3, 15);
1069 h3 += h4;
1070 h3 = h3 * 5 + 0x96cd1c35;
1071
1072 k4 *= c4;
1073 k4 = ROTL32(k4, 18);
1074 k4 *= c1;
1075 h4 ^= k4;
1076 h4 = ROTL32(h4, 13);
1077 h4 += h1;
1078 h4 = h4 * 5 + 0x32ac3b17;
1079 }
1080
1081 // tail
1082 const uint8_t* tail = data + nblocks * 16;
1083
1084 uint32_t k1 = 0, k2 = 0, k3 = 0, k4 = 0;
1085
1086 switch (len & 15) {
1087 case 15:
1088 k4 ^= (uint32_t)tail[14] << 16; /* fall through */
1090 case 14:
1091 k4 ^= (uint32_t)tail[13] << 8; /* fall through */
1093 case 13:
1094 k4 ^= (uint32_t)tail[12];
1095 k4 *= c4;
1096 k4 = ROTL32(k4, 18);
1097 k4 *= c1;
1098 h4 ^= k4;
1099 /* fall through */
1101 case 12:
1102 k3 ^= (uint32_t)tail[11] << 24; /* fall through */
1104 case 11:
1105 k3 ^= (uint32_t)tail[10] << 16; /* fall through */
1107 case 10:
1108 k3 ^= (uint32_t)tail[9] << 8; /* fall through */
1110 case 9:
1111 k3 ^= (uint32_t)tail[8];
1112 k3 *= c3;
1113 k3 = ROTL32(k3, 17);
1114 k3 *= c4;
1115 h3 ^= k3;
1116 /* fall through */
1118 case 8:
1119 k2 ^= (uint32_t)tail[7] << 24; /* fall through */
1121 case 7:
1122 k2 ^= (uint32_t)tail[6] << 16; /* fall through */
1124 case 6:
1125 k2 ^= (uint32_t)tail[5] << 8; /* fall through */
1127 case 5:
1128 k2 ^= (uint32_t)tail[4];
1129 k2 *= c2;
1130 k2 = ROTL32(k2, 16);
1131 k2 *= c3;
1132 h2 ^= k2;
1133 /* fall through */
1135 case 4:
1136 k1 ^= (uint32_t)tail[3] << 24; /* fall through */
1138 case 3:
1139 k1 ^= (uint32_t)tail[2] << 16; /* fall through */
1141 case 2:
1142 k1 ^= (uint32_t)tail[1] << 8; /* fall through */
1144 case 1:
1145 k1 ^= (uint32_t)tail[0];
1146 k1 *= c1;
1147 k1 = ROTL32(k1, 15);
1148 k1 *= c2;
1149 h1 ^= k1;
1150 break;
1151 default:
1152 break;
1153 }
1154
1155 // finalization
1156 h1 ^= (uint32_t)len;
1157 h2 ^= (uint32_t)len;
1158 h3 ^= (uint32_t)len;
1159 h4 ^= (uint32_t)len;
1160
1161 h1 += h2 + h3 + h4;
1162 h2 += h1;
1163 h3 += h1;
1164 h4 += h1;
1165
1166 h1 = fmix32(h1);
1167 h2 = fmix32(h2);
1168 h3 = fmix32(h3);
1169 h4 = fmix32(h4);
1170
1171 h1 += h2 + h3 + h4;
1172 h2 += h1;
1173 h3 += h1;
1174 h4 += h1;
1175
1176 ((uint32_t*)out)[0] = h1;
1177 ((uint32_t*)out)[1] = h2;
1178 ((uint32_t*)out)[2] = h3;
1179 ((uint32_t*)out)[3] = h4;
1180} /* MurmurHash3_x86_128(...) */
1181
1194void MurmurHash3_x64_128(const void* key, const size_t len, const uint64_t seed, void* out) {
1195 const uint8_t* data = (const uint8_t*)key;
1196 const size_t nblocks = len / 16;
1197
1198 uint64_t h1 = seed;
1199 uint64_t h2 = seed;
1200
1201 const uint64_t c1 = 0x87c37b91114253d5ULL;
1202 const uint64_t c2 = 0x4cf5ad432745937fULL;
1203
1204 // Body
1205 const uint64_t* blocks = (const uint64_t*)data;
1206 for (size_t i = 0; i < nblocks; i++) {
1207 uint64_t k1 = getblock64(blocks, i * 2 + 0);
1208 uint64_t k2 = getblock64(blocks, i * 2 + 1);
1209
1210 k1 *= c1;
1211 k1 = ROTL64(k1, 31);
1212 k1 *= c2;
1213 h1 ^= k1;
1214
1215 h1 = ROTL64(h1, 27);
1216 h1 += h2;
1217 h1 = h1 * 5 + 0x52dce729;
1218
1219 k2 *= c2;
1220 k2 = ROTL64(k2, 33);
1221 k2 *= c1;
1222 h2 ^= k2;
1223
1224 h2 = ROTL64(h2, 31);
1225 h2 += h1;
1226 h2 = h2 * 5 + 0x38495ab5;
1227 }
1228
1229 // Tail
1230 const uint8_t* tail = data + nblocks * 16;
1231
1232 uint64_t k1 = 0;
1233 uint64_t k2 = 0;
1234
1235 switch (len & 15) {
1236 case 15:
1237 k2 ^= ((uint64_t)tail[14]) << 48; /* fall through */
1239 case 14:
1240 k2 ^= ((uint64_t)tail[13]) << 40; /* fall through */
1242 case 13:
1243 k2 ^= ((uint64_t)tail[12]) << 32; /* fall through */
1245 case 12:
1246 k2 ^= ((uint64_t)tail[11]) << 24; /* fall through */
1248 case 11:
1249 k2 ^= ((uint64_t)tail[10]) << 16; /* fall through */
1251 case 10:
1252 k2 ^= ((uint64_t)tail[9]) << 8; /* fall through */
1254 case 9:
1255 k2 ^= ((uint64_t)tail[8]);
1256 k2 *= c2;
1257 k2 = ROTL64(k2, 33);
1258 k2 *= c1;
1259 h2 ^= k2;
1260 /* fall through */
1262 case 8:
1263 k1 ^= ((uint64_t)tail[7]) << 56; /* fall through */
1265 case 7:
1266 k1 ^= ((uint64_t)tail[6]) << 48; /* fall through */
1268 case 6:
1269 k1 ^= ((uint64_t)tail[5]) << 40; /* fall through */
1271 case 5:
1272 k1 ^= ((uint64_t)tail[4]) << 32; /* fall through */
1274 case 4:
1275 k1 ^= ((uint64_t)tail[3]) << 24; /* fall through */
1277 case 3:
1278 k1 ^= ((uint64_t)tail[2]) << 16; /* fall through */
1280 case 2:
1281 k1 ^= ((uint64_t)tail[1]) << 8; /* fall through */
1283 case 1:
1284 k1 ^= ((uint64_t)tail[0]);
1285 k1 *= c1;
1286 k1 = ROTL64(k1, 31);
1287 k1 *= c2;
1288 h1 ^= k1;
1289 break;
1290 default:
1291 break;
1292 }
1293
1294 // Finalization
1295 h1 ^= len;
1296 h2 ^= len;
1297
1298 h1 += h2;
1299 h2 += h1;
1300
1301 h1 = fmix64(h1);
1302 h2 = fmix64(h2);
1303
1304 h1 += h2;
1305 h2 += h1;
1306
1307 ((uint64_t*)out)[0] = h1;
1308 ((uint64_t*)out)[1] = h2;
1309} /* MurmurHash3_x64_128()*/
1310
1316char* ht_node_type(const HASH_NODE* node) {
1317 __n_assert(node, return "NULL_NODE");
1318
1319 switch (node->type) {
1320 case HASH_INT:
1321 return "HASH_INT";
1322 case HASH_DOUBLE:
1323 return "HASH_DOUBLE";
1324 case HASH_STRING:
1325 return "HASH_STRING";
1326 case HASH_PTR:
1327 return "HASH_PTR";
1328 default:
1329 return "HASH_UNKNOWN";
1330 }
1331} /* ht_node_type(...) */
1332
1339HASH_NODE* _ht_get_node(HASH_TABLE* table, const char* key) {
1340 HASH_VALUE hash_value[2] = {0, 0};
1341 size_t index = 0;
1342
1343 __n_assert(table, return NULL);
1344 __n_assert(key, return NULL);
1345
1346 if (key[0] == '\0')
1347 return NULL;
1348
1349 MurmurHash(key, strlen(key), table->seed, &hash_value);
1350 index = (hash_value[0]) % (table->size);
1351
1352 if (!table->hash_table[index]->start)
1353 return NULL;
1354
1355 list_foreach(list_node, table->hash_table[index]) {
1356 HASH_NODE* node_ptr = (HASH_NODE*)list_node->ptr;
1357 if (!strcmp(key, node_ptr->key)) {
1358 return node_ptr;
1359 }
1360 }
1361 return NULL;
1362} /* _ht_get_node() */
1363
1370HASH_NODE* _ht_new_node(const HASH_TABLE* table, const char* key) {
1371 __n_assert(table, return NULL);
1372 __n_assert(key, return NULL);
1373
1374 HASH_NODE* new_hash_node = NULL;
1375
1376 HASH_VALUE hash_value[2] = {0, 0};
1377
1378 if (strlen(key) == 0)
1379 return NULL;
1380
1381 MurmurHash(key, strlen(key), table->seed, &hash_value);
1382
1383 Malloc(new_hash_node, HASH_NODE, 1);
1384 __n_assert(new_hash_node, n_log(LOG_ERR, "Could not allocate new_hash_node"); return NULL);
1385 new_hash_node->key = strdup(key);
1386 new_hash_node->key_id = '\0';
1387 __n_assert(new_hash_node->key, n_log(LOG_ERR, "Could not allocate new_hash_node->key"); Free(new_hash_node); return NULL);
1388 new_hash_node->hash_value = hash_value[0];
1389 new_hash_node->data.ptr = NULL;
1390 new_hash_node->destroy_func = NULL;
1391 new_hash_node->children = NULL;
1392 new_hash_node->is_leaf = 0;
1393 new_hash_node->need_rehash = 0;
1394 new_hash_node->alphabet_length = 0;
1395
1396 return new_hash_node;
1397} /* _ht_new_node */
1398
1407 __n_assert(table, return NULL);
1408 __n_assert(key, return NULL);
1409
1410 HASH_NODE* new_hash_node = NULL;
1411 new_hash_node = _ht_new_node(table, key);
1412 if (new_hash_node) {
1413 new_hash_node->data.ival = value;
1414 new_hash_node->type = HASH_INT;
1415 } else {
1416 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1417 }
1418 return new_hash_node;
1419} /* _ht_new_int_node */
1420
1428HASH_NODE* _ht_new_double_node(HASH_TABLE* table, const char* key, double value) {
1429 __n_assert(table, return NULL);
1430 __n_assert(key, return NULL);
1431
1432 HASH_NODE* new_hash_node = NULL;
1433 new_hash_node = _ht_new_node(table, key);
1434 if (new_hash_node) {
1435 new_hash_node->data.fval = value;
1436 new_hash_node->type = HASH_DOUBLE;
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} /* _ht_new_double_node */
1442
1450HASH_NODE* _ht_new_string_node(HASH_TABLE* table, const char* key, const char* value) {
1451 __n_assert(table, return NULL);
1452 __n_assert(key, return NULL);
1453
1454 HASH_NODE* new_hash_node = NULL;
1455 new_hash_node = _ht_new_node(table, key);
1456 if (new_hash_node) {
1457 if (value)
1458 new_hash_node->data.string = strdup(value);
1459 else
1460 new_hash_node->data.string = NULL;
1461 new_hash_node->type = HASH_STRING;
1462 } else {
1463 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1464 }
1465 return new_hash_node;
1466}
1467
1475HASH_NODE* _ht_new_string_ptr_node(HASH_TABLE* table, const char* key, char* value) {
1476 __n_assert(table, return NULL);
1477 __n_assert(key, return NULL);
1478
1479 HASH_NODE* new_hash_node = NULL;
1480 new_hash_node = _ht_new_node(table, key);
1481 if (new_hash_node) {
1482 new_hash_node->data.string = value;
1483 new_hash_node->type = HASH_STRING;
1484 } else {
1485 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1486 }
1487 return new_hash_node;
1488}
1489
1499HASH_NODE* _ht_new_ptr_node(HASH_TABLE* table, const char* key, void* value, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
1500 __n_assert(table, return NULL);
1501 __n_assert(key, return NULL);
1502
1503 HASH_NODE* new_hash_node = NULL;
1504 new_hash_node = _ht_new_node(table, key);
1505 if (new_hash_node) {
1506 new_hash_node->data.ptr = value;
1507 new_hash_node->destroy_func = destructor;
1508 new_hash_node->duplicate_func = duplicator;
1509 new_hash_node->type = HASH_PTR;
1510 } else {
1511 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1512 }
1513 return new_hash_node;
1514}
1515
1523int _ht_put_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE value) {
1524 HASH_NODE* node_ptr = NULL;
1525
1526 __n_assert(table, return FALSE);
1527 __n_assert(key, return FALSE);
1528
1529 if ((node_ptr = _ht_get_node(table, key))) {
1530 if (node_ptr->type == HASH_INT) {
1531 node_ptr->data.ival = value;
1532 return TRUE;
1533 }
1534 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));
1535 return FALSE; /* key registered with another data type */
1536 }
1537
1538 int retcode = FALSE;
1539 node_ptr = _ht_new_int_node(table, key, value);
1540 if (node_ptr) {
1541 size_t index = (node_ptr->hash_value) % (table->size);
1542 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1543 if (retcode == TRUE) {
1544 table->nb_keys++;
1545 }
1546 }
1547 return retcode;
1548} /*_ht_put_int() */
1549
1557int _ht_put_double(HASH_TABLE* table, const char* key, double value) {
1558 HASH_NODE* node_ptr = NULL;
1559
1560 __n_assert(table, return FALSE);
1561 __n_assert(key, return FALSE);
1562
1563 if ((node_ptr = _ht_get_node(table, key))) {
1564 if (node_ptr->type == HASH_DOUBLE) {
1565 node_ptr->data.fval = value;
1566 return TRUE;
1567 }
1568 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));
1569 return FALSE; /* key registered with another data type */
1570 }
1571
1572 int retcode = FALSE;
1573 node_ptr = _ht_new_double_node(table, key, value);
1574 if (node_ptr) {
1575 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1576 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1577 if (retcode == TRUE) {
1578 table->nb_keys++;
1579 }
1580 }
1581 return retcode;
1582} /*_ht_put_double()*/
1583
1593int _ht_put_ptr(HASH_TABLE* table, const char* key, void* ptr, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
1594 HASH_NODE* node_ptr = NULL;
1595
1596 __n_assert(table, return FALSE);
1597 __n_assert(key, return FALSE);
1598
1599 if ((node_ptr = _ht_get_node(table, key))) {
1600 /* let's check the key isn't already assigned with another data type */
1601 if (node_ptr->type == HASH_PTR) {
1602 /* free the old value if a destructor is set */
1603 if (node_ptr->destroy_func && node_ptr->data.ptr) {
1604 node_ptr->destroy_func(node_ptr->data.ptr);
1605 }
1606 /* always update the pointer and function pointers */
1607 node_ptr->data.ptr = ptr;
1608 node_ptr->destroy_func = destructor;
1609 node_ptr->duplicate_func = duplicator;
1610 return TRUE;
1611 }
1612 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));
1613 return FALSE; /* key registered with another data type */
1614 }
1615
1616 int retcode = FALSE;
1617 node_ptr = _ht_new_ptr_node(table, key, ptr, destructor, duplicator);
1618 if (node_ptr) {
1619 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1620 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1621 if (retcode == TRUE) {
1622 table->nb_keys++;
1623 }
1624 }
1625 return retcode;
1626} /* _ht_put_ptr() */
1627
1635int _ht_put_string(HASH_TABLE* table, const char* key, char* string) {
1636 HASH_NODE* node_ptr = NULL;
1637
1638 __n_assert(table, return FALSE);
1639 __n_assert(key, return FALSE);
1640
1641 if ((node_ptr = _ht_get_node(table, key))) {
1642 /* let's check the key isn't already assigned with another data type */
1643 if (node_ptr->type == HASH_STRING) {
1644 char* new_str = NULL;
1645 if (string) {
1646 new_str = strdup(string);
1647 if (!new_str) {
1648 n_log(LOG_ERR, "could not strdup char *string at %p, didn't overwrite %s", string, key);
1649 return FALSE;
1650 }
1651 }
1652 Free(node_ptr->data.string);
1653 node_ptr->data.string = new_str;
1654 return TRUE;
1655 }
1656 n_log(LOG_ERR, "Can't add key[\"%s\"] with type HASH_STRING , key already exist with type %s", node_ptr->key, ht_node_type(node_ptr));
1657 return FALSE; /* key registered with another data type */
1658 }
1659
1660 int retcode = FALSE;
1661 node_ptr = _ht_new_string_node(table, key, string);
1662 if (node_ptr) {
1663 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1664 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1665 if (retcode == TRUE) {
1666 table->nb_keys++;
1667 }
1668 }
1669 return retcode;
1670} /*_ht_put_string */
1671
1679int _ht_put_string_ptr(HASH_TABLE* table, const char* key, char* string) {
1680 HASH_NODE* node_ptr = NULL;
1681
1682 __n_assert(table, return FALSE);
1683 __n_assert(key, return FALSE);
1684
1685 if ((node_ptr = _ht_get_node(table, key))) {
1686 /* let's check the key isn't already assigned with another data type */
1687 if (node_ptr->type == HASH_STRING) {
1688 Free(node_ptr->data.string);
1689 node_ptr->data.string = string;
1690 return TRUE;
1691 }
1692 n_log(LOG_ERR, "Can't add key[\"%s\"] with type HASH_STRING , key already exist with type %s", node_ptr->key, ht_node_type(node_ptr));
1693 return FALSE; /* key registered with another data type */
1694 }
1695
1696 int retcode = FALSE;
1697 node_ptr = _ht_new_string_ptr_node(table, key, string);
1698 if (node_ptr) {
1699 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1700 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1701 if (retcode == TRUE) {
1702 table->nb_keys++;
1703 }
1704 }
1705 return retcode;
1706} /*_ht_put_string_ptr */
1707
1715int _ht_get_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE* val) {
1716 __n_assert(table, return FALSE);
1717 __n_assert(key, return FALSE);
1718 if (strlen(key) == 0)
1719 return FALSE;
1720
1721 HASH_NODE* node = _ht_get_node(table, key);
1722
1723 if (!node)
1724 return FALSE;
1725
1726 if (node->type != HASH_INT) {
1727 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_INT, key is type %s", key, ht_node_type(node));
1728 return FALSE;
1729 }
1730
1731 (*val) = node->data.ival;
1732
1733 return TRUE;
1734} /* _ht_get_int() */
1735
1743int _ht_get_double(HASH_TABLE* table, const char* key, double* val) {
1744 __n_assert(table, return FALSE);
1745 __n_assert(key, return FALSE);
1746
1747 if (strlen(key) == 0)
1748 return FALSE;
1749
1750 HASH_NODE* node = _ht_get_node(table, key);
1751
1752 if (!node)
1753 return FALSE;
1754
1755 if (node->type != HASH_DOUBLE) {
1756 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_DOUBLE, key is type %s", key, ht_node_type(node));
1757 return FALSE;
1758 }
1759
1760 (*val) = node->data.fval;
1761
1762 return TRUE;
1763} /* _ht_get_double()*/
1764
1772int _ht_get_ptr(HASH_TABLE* table, const char* key, void** val) {
1773 __n_assert(table, return FALSE);
1774 __n_assert(key, return FALSE);
1775 if (strlen(key) == 0)
1776 return FALSE;
1777
1778 HASH_NODE* node = _ht_get_node(table, key);
1779 if (!node)
1780 return FALSE;
1781
1782 if (node->type != HASH_PTR) {
1783 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_PTR, key is type %s", key, ht_node_type(node));
1784 return FALSE;
1785 }
1786
1787 (*val) = node->data.ptr;
1788
1789 return TRUE;
1790} /* _ht_get_ptr() */
1791
1799int _ht_get_string(HASH_TABLE* table, const char* key, char** val) {
1800 __n_assert(table, return FALSE);
1801 __n_assert(key, return FALSE);
1802 if (strlen(key) == 0)
1803 return FALSE;
1804
1805 HASH_NODE* node = _ht_get_node(table, key);
1806 if (!node)
1807 return FALSE;
1808
1809 if (node->type != HASH_STRING) {
1810 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_STRING, key is type %s", key, ht_node_type(node));
1811 return FALSE;
1812 }
1813
1814 (*val) = node->data.string;
1815
1816 return TRUE;
1817} /* _ht_get_string() */
1818
1825int _ht_remove(HASH_TABLE* table, const char* key) {
1826 HASH_VALUE hash_value[2] = {0, 0};
1827 size_t index = 0;
1828
1829 HASH_NODE* node_ptr = NULL;
1830 LIST_NODE* node_to_kill = NULL;
1831
1832 __n_assert(table, return FALSE);
1833 __n_assert(key, return FALSE);
1834 if (strlen(key) == 0)
1835 return FALSE;
1836
1837 MurmurHash(key, strlen(key), table->seed, &hash_value);
1838 index = (hash_value[0]) % (table->size);
1839
1840 if (!table->hash_table[index]->start) {
1841 n_log(LOG_ERR, "Can't remove key[\"%s\"], table is empty", key);
1842 return FALSE;
1843 }
1844
1845 list_foreach(list_node, table->hash_table[index]) {
1846 node_ptr = (HASH_NODE*)list_node->ptr;
1847 /* if we found the same */
1848 if (!strcmp(key, node_ptr->key)) {
1849 node_to_kill = list_node;
1850 break;
1851 }
1852 }
1853 if (node_to_kill) {
1854 node_ptr = remove_list_node(table->hash_table[index], node_to_kill, HASH_NODE);
1855 _ht_node_destroy(node_ptr);
1856
1857 table->nb_keys--;
1858
1859 return TRUE;
1860 }
1861 n_log(LOG_ERR, "Can't delete key[\"%s\"]: inexisting key", key);
1862 return FALSE;
1863} /* ht_remove() */
1864
1871 __n_assert(table, return FALSE);
1872
1873 HASH_VALUE index = 0;
1874 for (index = 0; index < table->size; index++) {
1875 while (table->hash_table[index] && table->hash_table[index]->start) {
1876 HASH_NODE* hash_node = remove_list_node(table->hash_table[index], table->hash_table[index]->start, HASH_NODE);
1877 _ht_node_destroy(hash_node);
1878 }
1879 }
1880 table->nb_keys = 0;
1881 return TRUE;
1882} /* empty_ht */
1883
1890 __n_assert(table && (*table), n_log(LOG_ERR, "Can't destroy table: already NULL"); return FALSE);
1891
1892 if ((*table)->hash_table) {
1893 // empty_ht( (*table) );
1894
1895 HASH_VALUE it = 0;
1896 for (it = 0; it < (*table)->size; it++) {
1897 if ((*table)->hash_table[it])
1898 list_destroy(&(*table)->hash_table[it]);
1899 }
1900 Free((*table)->hash_table);
1901 }
1902 Free((*table));
1903 return TRUE;
1904} /* _destroy_ht */
1905
1910void _ht_print(HASH_TABLE* table) {
1911 __n_assert(table, return);
1912 __n_assert(table->hash_table, return);
1913 // cppcheck-suppress constVariablePointer -- node is generated by ht_foreach macro
1914 ht_foreach(node, table) {
1915 const HASH_NODE* ht_node = (const HASH_NODE*)node->ptr;
1916 printf("key:%s node:%s\n", ht_node->key, ht_node->key);
1917 }
1918
1919 return;
1920} /* _ht_print(...) */
1921
1928LIST* _ht_search(HASH_TABLE* table, int (*node_is_matching)(HASH_NODE* node)) {
1929 __n_assert(table, return NULL);
1930
1932 __n_assert(results, return NULL);
1933
1934 ht_foreach(node, table) {
1935 HASH_NODE* hnode = (HASH_NODE*)node->ptr;
1936 if (node_is_matching(hnode) == TRUE) {
1937 list_push(results, strdup(hnode->key), &free);
1938 }
1939 }
1940
1941 if (results->nb_items < 1)
1942 list_destroy(&results);
1943
1944 return results;
1945} /* _ht_search(...) */
1946
1947/* Hash tables function pointers and common table type functions */
1948
1955HASH_TABLE* new_ht_trie(size_t alphabet_length, size_t alphabet_offset) {
1956 HASH_TABLE* table = NULL;
1957
1958 Malloc(table, HASH_TABLE, 1);
1959 __n_assert(table, n_log(LOG_ERR, "Error allocating HASH_TABLE *table"); return NULL);
1960
1961 table->size = 0;
1962 table->seed = 0;
1963 table->nb_keys = 0;
1964 errno = 0;
1965 table->hash_table = NULL;
1966
1976 table->ht_remove = _ht_remove_trie;
1977 table->ht_search = _ht_search_trie;
1978 table->empty_ht = _empty_ht_trie;
1980 table->ht_print = _ht_print_trie;
1981
1982 table->alphabet_length = alphabet_length;
1983 table->alphabet_offset = alphabet_offset;
1984
1985 table->root = _ht_new_node_trie(table, '\0');
1986 if (!table->root) {
1987 n_log(LOG_ERR, "Couldn't allocate new_ht_trie with alphabet_length of %zu and alphabet offset of %zu", alphabet_length, alphabet_offset);
1988 Free(table);
1989 return NULL;
1990 }
1991 table->mode = HASH_TRIE;
1992
1993 return table;
1994} /* new_ht_trie */
1995
2001HASH_TABLE* new_ht(size_t size) {
2002 HASH_TABLE* table = NULL;
2003
2004 if (size < 1) {
2005 n_log(LOG_ERR, "Invalid size %zu for new_ht()", size);
2006 return NULL;
2007 }
2008 Malloc(table, HASH_TABLE, 1);
2009 __n_assert(table, n_log(LOG_ERR, "Error allocating HASH_TABLE *table"); return NULL);
2010
2011 table->size = size;
2012 table->seed = (uint32_t)rand() % 100000;
2013 table->nb_keys = 0;
2014 errno = 0;
2015 Malloc(table->hash_table, LIST*, size);
2016 // table -> hash_table = (LIST **)calloc( size, sizeof( LIST *) );
2017 __n_assert(table->hash_table, n_log(LOG_ERR, "Can't allocate table -> hash_table with size %zu !", size); Free(table); return NULL);
2018
2019 size_t it = 0;
2020 for (it = 0; it < size; it++) {
2022 // if no valid table then unroll previsouly created slots
2023 if (!table->hash_table[it]) {
2024 n_log(LOG_ERR, "Can't allocate table -> hash_table[ %d ] !", it);
2025 size_t it_delete = 0;
2026 for (it_delete = 0; it_delete < it; it_delete++) {
2027 list_destroy(&table->hash_table[it_delete]);
2028 }
2029 Free(table->hash_table);
2030 Free(table);
2031 return NULL;
2032 }
2033 }
2034 table->mode = HASH_CLASSIC;
2035
2036 table->ht_put_int = _ht_put_int;
2038 table->ht_put_ptr = _ht_put_ptr;
2041 table->ht_get_int = _ht_get_int;
2044 table->ht_get_ptr = _ht_get_ptr;
2045 table->ht_get_node = _ht_get_node;
2046 table->ht_remove = _ht_remove;
2047 table->ht_search = _ht_search;
2048 table->empty_ht = _empty_ht;
2049 table->destroy_ht = _destroy_ht;
2050 table->ht_print = _ht_print;
2051
2052 return table;
2053} /* new_ht(...) */
2054
2061HASH_NODE* ht_get_node(HASH_TABLE* table, const char* key) {
2062 __n_assert(table, return NULL);
2063 __n_assert(key, return NULL);
2064 return table->ht_get_node(table, key);
2065} /*ht_get_node(...) */
2066
2074int ht_get_double(HASH_TABLE* table, const char* key, double* val) {
2075 __n_assert(table, return FALSE);
2076 __n_assert(key, return FALSE);
2077 return table->ht_get_double(table, key, val);
2078} /* ht_get_double(...) */
2079
2087int ht_get_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE* val) {
2088 __n_assert(table, return FALSE);
2089 __n_assert(key, return FALSE);
2090 return table->ht_get_int(table, key, val);
2091} /* ht_get_int(...) */
2092
2100int ht_get_ptr(HASH_TABLE* table, const char* key, void** val) {
2101 __n_assert(table, return FALSE);
2102 __n_assert(key, return FALSE);
2103 return table->ht_get_ptr(table, key, val);
2104} /* ht_get_ptr(...) */
2105
2113int ht_get_string(HASH_TABLE* table, const char* key, char** val) {
2114 __n_assert(table, return FALSE);
2115 __n_assert(key, return FALSE);
2116 return table->ht_get_string(table, key, val);
2117} /* ht_get_string(...) */
2118
2126int ht_put_double(HASH_TABLE* table, const char* key, double value) {
2127 __n_assert(table, return FALSE);
2128 __n_assert(key, return FALSE);
2129 return table->ht_put_double(table, key, value);
2130} /* ht_put_double(...) */
2131
2139int ht_put_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE value) {
2140 __n_assert(table, return FALSE);
2141 __n_assert(key, return FALSE);
2142 return table->ht_put_int(table, key, value);
2143} /* ht_put_int(...) */
2144
2154int ht_put_ptr(HASH_TABLE* table, const char* key, void* ptr, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
2155 __n_assert(table, return FALSE);
2156 __n_assert(key, return FALSE);
2157 return table->ht_put_ptr(table, key, ptr, destructor, duplicator);
2158} /* ht_put_ptr(...) */
2159
2167int ht_put_string(HASH_TABLE* table, const char* key, char* string) {
2168 __n_assert(table, return FALSE);
2169 __n_assert(key, return FALSE);
2170 return table->ht_put_string(table, key, string);
2171} /* ht_put_string(...) */
2172
2180int ht_put_string_ptr(HASH_TABLE* table, const char* key, char* string) {
2181 __n_assert(table, return FALSE);
2182 __n_assert(key, return FALSE);
2183 return table->ht_put_string_ptr(table, key, string);
2184} /* ht_put_string_ptr(...) */
2185
2192int ht_remove(HASH_TABLE* table, const char* key) {
2193 __n_assert(table, return FALSE);
2194 __n_assert(key, return FALSE);
2195 return table->ht_remove(table, key);
2196} /* ht_remove(...) */
2197
2202void ht_print(HASH_TABLE* table) {
2203 __n_assert(table, return);
2204 table->ht_print(table);
2205 return;
2206} /* ht_print(...) */
2207
2214LIST* ht_search(HASH_TABLE* table, int (*node_is_matching)(HASH_NODE* node)) {
2215 __n_assert(table, return NULL);
2216 return table->ht_search(table, node_is_matching);
2217} /* ht_search(...) */
2218
2225 __n_assert(table, return FALSE);
2226 return table->empty_ht(table);
2227} /* empty_ht(...) */
2228
2235 __n_assert((*table), return FALSE);
2236 return (*table)->destroy_ht(table);
2237} /* destroy_ht(...) */
2238
2246 __n_assert(table, return NULL);
2247 __n_assert(table->mode == HASH_CLASSIC, return NULL);
2248
2249 size_t index = (hash_value) % (table->size);
2250 if (!table->hash_table[index]->start) {
2251 return NULL;
2252 }
2253
2254 list_foreach(list_node, table->hash_table[index]) {
2255 HASH_NODE* node_ptr = (HASH_NODE*)list_node->ptr;
2256 if (hash_value == node_ptr->hash_value) {
2257 return node_ptr;
2258 }
2259 }
2260 return NULL;
2261} /* ht_get_node_ex() */
2262
2270int ht_get_ptr_ex(HASH_TABLE* table, HASH_VALUE hash_value, void** val) {
2271 __n_assert(table, return FALSE);
2272 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2273
2274 HASH_NODE* node = ht_get_node_ex(table, hash_value);
2275 if (!node)
2276 return FALSE;
2277
2278 if (node->type != HASH_PTR) {
2279 n_log(LOG_ERR, "Can't get key[\"%zu\"] of type HASH_PTR, key is type %s", hash_value, ht_node_type(node));
2280 return FALSE;
2281 }
2282
2283 (*val) = node->data.ptr;
2284
2285 return TRUE;
2286} /* ht_get_ptr_ex() */
2287
2297int ht_put_ptr_ex(HASH_TABLE* table, HASH_VALUE hash_value, void* val, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
2298 __n_assert(table, return FALSE);
2299 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2300
2301 size_t index = 0;
2302 HASH_NODE* new_hash_node = NULL;
2303 HASH_NODE* node_ptr = NULL;
2304
2305 index = (hash_value) % (table->size);
2306
2307 /* we have some nodes here. Let's check if the key already exists */
2308 list_foreach(list_node, table->hash_table[index]) {
2309 node_ptr = (HASH_NODE*)list_node->ptr;
2310 /* if we found the same key we just replace the value and return */
2311 if (hash_value == node_ptr->hash_value) {
2312 /* let's check the key isn't already assigned with another data type */
2313 if (node_ptr->type == HASH_PTR) {
2314 if (node_ptr->destroy_func && node_ptr->data.ptr) {
2315 node_ptr->destroy_func(node_ptr->data.ptr);
2316 } else if (!node_ptr->destroy_func && node_ptr->data.ptr) {
2317 n_log(LOG_ERR, "Can't free previous key[\"%s\"] with type HASH_PTR , no hash node destroy func", node_ptr->key);
2318 }
2319 node_ptr->destroy_func = destructor;
2320 node_ptr->duplicate_func = duplicator;
2321 node_ptr->data.ptr = val;
2322 return TRUE;
2323 }
2324 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));
2325 return FALSE; /* key registered with another data type */
2326 }
2327 }
2328
2329 Malloc(new_hash_node, HASH_NODE, 1);
2330 __n_assert(new_hash_node, n_log(LOG_ERR, "Could not allocate new_hash_node"); return FALSE);
2331
2332 new_hash_node->key = NULL;
2333 new_hash_node->hash_value = hash_value;
2334 new_hash_node->data.ptr = val;
2335 new_hash_node->type = HASH_PTR;
2336 new_hash_node->destroy_func = destructor;
2337 new_hash_node->duplicate_func = duplicator;
2338
2339 table->nb_keys++;
2340
2341 return list_push(table->hash_table[index], new_hash_node, &_ht_node_destroy);
2342} /* ht_put_ptr_ex() */
2343
2350int ht_remove_ex(HASH_TABLE* table, HASH_VALUE hash_value) {
2351 __n_assert(table, return FALSE);
2352 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2353
2354 size_t index = 0;
2355 HASH_NODE* node_ptr = NULL;
2356 LIST_NODE* node_to_kill = NULL;
2357
2358 index = (hash_value) % (table->size);
2359 if (!table->hash_table[index]->start) {
2360 n_log(LOG_ERR, "Can't remove key[\"%zu\"], table is empty", hash_value);
2361 return FALSE;
2362 }
2363
2364 list_foreach(list_node, table->hash_table[index]) {
2365 node_ptr = (HASH_NODE*)list_node->ptr;
2366 /* if we found the same */
2367 if (hash_value == node_ptr->hash_value) {
2368 node_to_kill = list_node;
2369 break;
2370 }
2371 }
2372 if (node_to_kill) {
2373 node_ptr = remove_list_node(table->hash_table[index], node_to_kill, HASH_NODE);
2374 _ht_node_destroy(node_ptr);
2375
2376 table->nb_keys--;
2377
2378 return TRUE;
2379 }
2380 n_log(LOG_ERR, "Can't delete key[\"%zu\"]: inexisting key", hash_value);
2381 return FALSE;
2382} /* ht_remove_ex() */
2383
2391LIST* ht_get_completion_list(HASH_TABLE* table, const char* keybud, size_t max_results) {
2392 __n_assert(table, return NULL);
2393 __n_assert(keybud, return NULL);
2394
2395 LIST* results = new_generic_list(max_results);
2396 if (table->mode == HASH_TRIE) {
2397 HASH_NODE* node = _ht_get_node_trie(table, keybud);
2398 if (node) {
2399 if (list_push(results, strdup(keybud), &free) == TRUE) {
2400 _ht_depth_first_search(node, results);
2401 }
2402 } else {
2403 node = table->root;
2404 for (size_t it = 0; it < table->alphabet_length; it++) {
2405 if (node->children[it]) {
2406 char new_keybud[3] = "";
2407 new_keybud[0] = (char)(it + table->alphabet_offset);
2408 list_push(results, strdup(new_keybud), &free);
2409 }
2410 }
2411 }
2412 } else if (table->mode == HASH_CLASSIC) {
2413 ht_foreach(node, table) {
2414 HASH_NODE* hnode = (HASH_NODE*)node->ptr;
2415 if (strncasecmp(keybud, hnode->key, strlen(keybud)) == 0) {
2416 char* key = strdup(hnode->key);
2417 if (list_push(results, key, &free) == FALSE) {
2418 n_log(LOG_ERR, "not enough space in list or memory error, key %s not pushed !", key);
2419 Free(key);
2420 }
2421 }
2422 }
2423 } else {
2424 n_log(LOG_ERR, "unsupported mode %d", table->mode);
2425 list_destroy(&results);
2426 return NULL;
2427 }
2428 if (results && results->nb_items < 1)
2429 list_destroy(&results);
2430 return results;
2431} /* ht_get_completion_list(...) */
2432
2438int is_prime(size_t nb) {
2439 /* quick test for first primes */
2440 if (nb <= 1) return FALSE;
2441 if (nb <= 3) return TRUE;
2442
2443 /* skip middle five numbers in below loop */
2444 if ((nb % 2 == 0) || (nb % 3 == 0))
2445 return FALSE;
2446
2447 /* looping */
2448 for (size_t it = 5; it * it <= nb; it = it + 6) {
2449 if ((nb % it == 0) || (nb % (it + 2) == 0))
2450 return FALSE;
2451 }
2452 return TRUE;
2453} /* is_prime() */
2454
2460size_t next_prime(size_t nb) {
2461 if (nb <= 1)
2462 return 2;
2463
2464 size_t next_prime = nb;
2465 do {
2466 next_prime++;
2467 } while (is_prime(next_prime) == FALSE);
2468
2469 return next_prime;
2470} /* next_prime() */
2471
2478 __n_assert(table, return FALSE);
2479 if (table->mode != HASH_CLASSIC) {
2480 n_log(LOG_ERR, "unsupported table->mode (%d instead or %d)", table->mode, HASH_CLASSIC);
2481 return FALSE;
2482 }
2483 if (table->size == 0) return FALSE;
2484
2485 size_t nb_collisionned_lists = 0;
2486
2487 for (size_t hash_it = 0; hash_it < table->size; hash_it++) {
2488 if (table->hash_table[hash_it] && table->hash_table[hash_it]->nb_items > 1) {
2489 nb_collisionned_lists++;
2490 }
2491 }
2492 size_t collision_percentage = (100 * nb_collisionned_lists) / table->size;
2493 return (int)collision_percentage;
2494} /* ht_get_table_collision_percentage() */
2495
2502 __n_assert(table, return 0);
2503 if (table->mode != HASH_CLASSIC) {
2504 n_log(LOG_ERR, "unsupported table->mode (%d instead or %d)", table->mode, HASH_CLASSIC);
2505 return FALSE;
2506 }
2507
2508 size_t optimum_size = (size_t)((double)table->nb_keys * 1.3);
2509 if (is_prime(optimum_size) != TRUE)
2510 optimum_size = next_prime(optimum_size);
2511 return optimum_size;
2512} /* ht_get_optimal_size() */
2513
2520int ht_resize(HASH_TABLE** table, size_t size) {
2521 __n_assert((*table), return FALSE);
2522 if ((*table)->mode != HASH_CLASSIC) {
2523 n_log(LOG_ERR, "unsupported table->mode (%d instead or %d)", (*table)->mode, HASH_CLASSIC);
2524 return FALSE;
2525 }
2526 if (size < 1) {
2527 n_log(LOG_ERR, "invalid size %zu for hash table %p", size, (void*)(*table));
2528 return FALSE;
2529 }
2530 // cppcheck-suppress redundantAssignment -- macro-generated loop variable
2531 HT_FOREACH(node, (*table), { node->need_rehash = 1; });
2532
2533 if (size > (*table)->size) {
2534 if (Realloc((*table)->hash_table, LIST*, size) == FALSE) {
2535 return FALSE;
2536 }
2537 for (size_t it = (*table)->size; it < size; it++) {
2538 (*table)->hash_table[it] = new_generic_list(MAX_LIST_ITEMS);
2539 if (!(*table)->hash_table[it]) {
2540 n_log(LOG_ERR, "Can't allocate table -> hash_table[ %zu ] !", it);
2541 /* destroy newly added slots and shrink back */
2542 for (size_t it_delete = (*table)->size; it_delete < it; it_delete++) {
2543 list_destroy(&(*table)->hash_table[it_delete]);
2544 }
2545 /* best-effort rollback: shrink back to original size.
2546 Realloc preserves the pointer on failure, which is fine here. */
2547 Realloc((*table)->hash_table, LIST*, (*table)->size);
2548 return FALSE;
2549 }
2550 }
2551 /* rehash all marked nodes into their new positions */
2552 for (size_t it = 0; it < size; it++) {
2553 if ((*table)->hash_table[it]) {
2554 while ((*table)->hash_table[it]->start) {
2555 HASH_NODE* hash_node = (HASH_NODE*)(*table)->hash_table[it]->start->ptr;
2556 if (hash_node->need_rehash == 0)
2557 break;
2558 hash_node->need_rehash = 0;
2559 LIST_NODE* node = list_node_shift((*table)->hash_table[it]);
2560 node->next = node->prev = NULL;
2561 size_t index = (hash_node->hash_value) % (size);
2562 list_node_push((*table)->hash_table[index], node);
2563 }
2564 }
2565 }
2566 } else {
2567 /* rehash nodes that need it into the smaller index space */
2568 for (size_t it = 0; it < (*table)->size; it++) {
2569 if ((*table)->hash_table[it]) {
2570 while ((*table)->hash_table[it]->start) {
2571 HASH_NODE* hash_node = (HASH_NODE*)(*table)->hash_table[it]->start->ptr;
2572 if (hash_node->need_rehash == 0)
2573 break;
2574 hash_node->need_rehash = 0;
2575 LIST_NODE* node = list_node_shift((*table)->hash_table[it]);
2576 node->next = node->prev = NULL;
2577 size_t index = (hash_node->hash_value) % (size);
2578 list_node_push((*table)->hash_table[index], node);
2579 }
2580 }
2581 }
2582 /* destroy trailing slots that are now unused */
2583 for (size_t it = size; it < (*table)->size; it++) {
2584 list_destroy(&(*table)->hash_table[it]);
2585 }
2586 /* shrink the backing array; Realloc preserves the pointer on failure.
2587 Trailing slots have already been list_destroy'd so they are NULL.
2588 (*table)->size is updated below regardless, keeping the table
2589 consistent even if the allocator cannot shrink in-place. */
2590 Realloc((*table)->hash_table, LIST*, size);
2591 }
2592 (*table)->size = size;
2593
2594 return TRUE;
2595} /* ht_resize() */
2596
2603 __n_assert((*table), return FALSE);
2604 if ((*table)->mode != HASH_CLASSIC) {
2605 n_log(LOG_ERR, "unsupported table->mode (%d instead or %d)", (*table)->mode, HASH_CLASSIC);
2606 return FALSE;
2607 }
2608
2609 size_t optimal_size = ht_get_optimal_size((*table));
2610 if (optimal_size == FALSE) {
2611 return FALSE;
2612 }
2613
2614 int collision_percentage = ht_get_table_collision_percentage((*table));
2615 if (collision_percentage == FALSE)
2616 return FALSE;
2617
2618 int resize_result = ht_resize(table, optimal_size);
2619 if (resize_result == FALSE) {
2620 return FALSE;
2621 }
2622
2623 collision_percentage = ht_get_table_collision_percentage((*table));
2624 if (collision_percentage == FALSE) {
2625 return FALSE;
2626 }
2627
2628 return TRUE;
2629} /* ht_optimize() */
2630
2637 __n_assert(table, return NULL);
2638 HASH_TABLE* duplicated_table = NULL;
2639
2640 if (table->mode != HASH_CLASSIC) {
2641 n_log(LOG_ERR, "unsupported mode %d for table %p", table->mode, table);
2642 return NULL;
2643 }
2644
2645 duplicated_table = new_ht(table->size);
2646 if (!duplicated_table) {
2647 n_log(LOG_ERR, "couldn't allocate duplicated table of %zu elements", table->size);
2648 return NULL;
2649 }
2650
2651 ht_foreach(node, table) {
2652 HASH_NODE* hash_node = (HASH_NODE*)node->ptr;
2653 int has_succeeded = TRUE;
2654 switch (hash_node->type) {
2655 case HASH_INT:
2656 has_succeeded = ht_put_int(duplicated_table, hash_node->key, hash_node->data.ival);
2657 break;
2658 case HASH_DOUBLE:
2659 has_succeeded = ht_put_double(duplicated_table, hash_node->key, hash_node->data.fval);
2660 break;
2661 case HASH_PTR: {
2662 if (hash_node->duplicate_func && hash_node->data.ptr) {
2663 /* deep copy: new entry takes ownership with the same funcs */
2664 void* duplicated_ptr = hash_node->duplicate_func(hash_node->data.ptr);
2665 if (!duplicated_ptr) {
2666 n_log(LOG_ERR, "duplicate_func returned NULL for key [%s]", hash_node->key);
2667 has_succeeded = FALSE;
2668 break;
2669 }
2670 has_succeeded = ht_put_ptr(duplicated_table, hash_node->key, duplicated_ptr, hash_node->destroy_func, hash_node->duplicate_func);
2671 } else {
2672 /* shallow copy: pass NULL destroy/duplicate so the duplicate table
2673 does not take ownership; only the source table will free the pointer */
2674 has_succeeded = ht_put_ptr(duplicated_table, hash_node->key, hash_node->data.ptr, NULL, NULL);
2675 }
2676 } break;
2677 case HASH_STRING:
2678 has_succeeded = ht_put_string(duplicated_table, hash_node->key, hash_node->data.string);
2679 break;
2680 default:
2681 n_log(LOG_ERR, "unknown node type %d for key [%s], skipping", hash_node->type, hash_node->key);
2682 break;
2683 }
2684
2685 if (has_succeeded == FALSE) {
2686 n_log(LOG_ERR, "problem when trying to duplicate value in %p, duplication cancelled", table);
2687 destroy_ht(&duplicated_table);
2688 return NULL;
2689 }
2690 }
2691
2692 return duplicated_table;
2693}
static size_t max_results
char * key
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:271
#define FALL_THROUGH
set windows if true
Definition n_common.h:71
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:203
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:278
#define FORCE_INLINE
FORCE_INLINE portable macro.
Definition n_common.h:163
#define Realloc(__ptr, __struct, __size)
Realloc Handler to get errors.
Definition n_common.h:230
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:262
int(* ht_put_int)(struct HASH_TABLE *table, const char *key, int64_t val)
put an integer
Definition n_hash.h:157
size_t alphabet_length
HASH_TRIE mode: size of alphabet and so size of children allocated array.
Definition n_hash.h:133
int need_rehash
flag to mark a node for rehash
Definition n_hash.h:129
HASH_NODE *(* ht_get_node)(struct HASH_TABLE *table, const char *key)
get HASH_NODE at 'key' from table
Definition n_hash.h:155
char key_id
key id of the node if any
Definition n_hash.h:115
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:173
int(* ht_put_string)(struct HASH_TABLE *table, const char *key, char *val)
put an char *string
Definition n_hash.h:163
char * key
string key of the node if any, else NULL
Definition n_hash.h:113
int64_t ival
integral type
Definition n_hash.h:101
int(* ht_put_ptr)(struct HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr), void *(*duplicator)(void *ptr))
put a a pointer
Definition n_hash.h:161
int is_leaf
HASH_TRIE mode: does it have a value.
Definition n_hash.h:127
HASH_NODE * root
HASH_TRIE mode: Start of tree.
Definition n_hash.h:147
void * ptr
pointer type
Definition n_hash.h:105
union HASH_DATA data
data inside the node
Definition n_hash.h:121
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:171
int type
type of the node
Definition n_hash.h:119
int(* empty_ht)(struct HASH_TABLE *table)
empty a hash table.
Definition n_hash.h:179
LIST ** hash_table
HASH_CLASSIC mode: preallocated hash table.
Definition n_hash.h:145
size_t alphabet_offset
HASH_TRIE mode: offset to deduce to individual key digits.
Definition n_hash.h:151
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:169
size_t alphabet_length
HASH_TRIE mode: size of the alphabet.
Definition n_hash.h:149
void *(* duplicate_func)(void *ptr)
duplicator_func
Definition n_hash.h:125
unsigned int mode
hashing mode, murmurhash and classic HASH_MURMUR, or HASH_TRIE
Definition n_hash.h:153
size_t seed
table's seed
Definition n_hash.h:143
int(* destroy_ht)(struct HASH_TABLE **table)
destroy a hash table
Definition n_hash.h:181
int(* ht_put_string_ptr)(struct HASH_TABLE *table, const char *key, char *val)
put an char *string pointer
Definition n_hash.h:165
int(* ht_remove)(struct HASH_TABLE *table, const char *key)
remove given's key node from the table
Definition n_hash.h:175
void(* ht_print)(struct HASH_TABLE *table)
print table
Definition n_hash.h:183
char * string
char *type
Definition n_hash.h:107
int(* ht_put_double)(struct HASH_TABLE *table, const char *key, double val)
put a double
Definition n_hash.h:159
struct HASH_NODE ** children
HASH_TRIE mode: pointers to children.
Definition n_hash.h:131
HASH_VALUE hash_value
numeric key of the node if any, else < 0
Definition n_hash.h:117
double fval
double type
Definition n_hash.h:103
size_t size
size of the hash table
Definition n_hash.h:139
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:167
size_t nb_keys
total number of used keys in the table
Definition n_hash.h:141
LIST *(* ht_search)(struct HASH_TABLE *table, int(*node_is_matching)(HASH_NODE *node))
search elements given an expression
Definition n_hash.h:177
void(* destroy_func)(void *ptr)
destroy_func
Definition n_hash.h:123
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition n_hash.c:2100
#define ht_foreach(__ITEM_, __HASH_)
ForEach macro helper (classic / old)
Definition n_hash.h:191
LIST * ht_search(HASH_TABLE *table, int(*node_is_matching)(HASH_NODE *node))
seach table for matching nodes
Definition n_hash.c:2214
HASH_TABLE * ht_duplicate(HASH_TABLE *table)
duplicate a hash table (all pointers should have a duplicator func set)
Definition n_hash.c:2636
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition n_hash.c:2234
int ht_put_ptr_ex(HASH_TABLE *table, HASH_VALUE hash_value, void *val, void(*destructor)(void *ptr), void *(*duplicator)(void *ptr))
put a pointer value with given key in the targeted hash table (HASH_CLASSIC only)
Definition n_hash.c:2297
int ht_remove(HASH_TABLE *table, const char *key)
remove and delete node at key in table
Definition n_hash.c:2192
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:2245
#define HASH_PTR
value of pointer type inside the hash node
Definition n_hash.h:75
HASH_TABLE * new_ht(size_t size)
Create a hash table with the given size.
Definition n_hash.c:2001
#define MurmurHash(__key, __len, __seed, __out)
Murmur hash macro helper 64 bits.
Definition n_hash.h:90
int ht_get_table_collision_percentage(HASH_TABLE *table)
get table collision percentage (HASH_CLASSIC mode only)
Definition n_hash.c:2477
int ht_get_double(HASH_TABLE *table, const char *key, double *val)
get double at 'key' from 'table'
Definition n_hash.c:2074
#define HASH_DOUBLE
value of double type inside the hash node
Definition n_hash.h:71
int empty_ht(HASH_TABLE *table)
empty a table
Definition n_hash.c:2224
#define HASH_STRING
value of char * type inside the hash node
Definition n_hash.h:73
void ht_print(HASH_TABLE *table)
print contents of table
Definition n_hash.c:2202
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:2391
size_t HASH_VALUE
type of a HASH_VALUE
Definition n_hash.h:96
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:2126
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:2501
int ht_put_ptr(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr), void *(*duplicator)(void *ptr))
put an arbitrary pointer value with given key in the targeted hash table
Definition n_hash.c:2154
int ht_get_string(HASH_TABLE *table, const char *key, char **val)
get string at 'key' from 'table'
Definition n_hash.c:2113
int is_prime(size_t nb)
test if number is a prime number or not
Definition n_hash.c:2438
#define HASH_INT_TYPE
type of a HASH_INT in 64 bits
Definition n_hash.h:92
size_t next_prime(size_t nb)
compute next prime number after nb
Definition n_hash.c:2460
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:2167
int ht_resize(HASH_TABLE **table, size_t size)
rehash table according to size (HASH_CLASSIC mode only)
Definition n_hash.c:2520
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:1026
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:1194
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:2350
#define HASH_CLASSIC
Murmur hash using hash key string, hash key numeric value, index table with lists of elements.
Definition n_hash.h:79
int ht_get_int(HASH_TABLE *table, const char *key, int64_t *val)
get node at 'key' from 'table'
Definition n_hash.c:2087
HASH_NODE * ht_get_node(HASH_TABLE *table, const char *key)
get node at 'key' from 'table'
Definition n_hash.c:2061
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:1955
#define HASH_TRIE
TRIE tree using hash key string.
Definition n_hash.h:81
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:2139
int ht_optimize(HASH_TABLE **table)
try an automatic optimization of the table (HASH_CLASSIC mode only)
Definition n_hash.c:2602
char * ht_node_type(const HASH_NODE *node)
get the type of a node , text version
Definition n_hash.c:1316
#define HASH_INT
compatibility with existing rot func
Definition n_hash.h:69
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:968
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:2180
#define HT_FOREACH(__ITEM_, __HASH_,...)
ForEach macro helper.
Definition n_hash.h:215
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:2270
structure of a hash table node
Definition n_hash.h:111
structure of a hash table
Definition n_hash.h:137
size_t nb_max_items
Maximum number of items in the list.
Definition n_list.h:62
struct LIST_NODE * prev
pointer to the previous node
Definition n_list.h:53
LIST_NODE * start
pointer to the start of the list
Definition n_list.h:65
size_t nb_items
number of item currently in the list
Definition n_list.h:60
struct LIST_NODE * next
pointer to the next node
Definition n_list.h:51
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:227
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper, safe for node removal during iteration.
Definition n_list.h:88
#define remove_list_node(__LIST_, __NODE_, __TYPE_)
Remove macro helper for void pointer casting.
Definition n_list.h:97
LIST_NODE * list_node_shift(LIST *list)
Get a LIST_NODE pointer from the start of the list.
Definition n_list.c:169
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:547
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:36
#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:74
int list_node_push(LIST *list, LIST_NODE *node)
Add a filled node to the end of the list.
Definition n_list.c:116
Structure of a generic LIST container.
Definition n_list.h:58
Structure of a generic list node.
Definition n_list.h:43
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:88
#define LOG_DEBUG
debug-level messages
Definition n_log.h:83
#define LOG_ERR
error conditions
Definition n_log.h:75
Common headers and low-level functions & define.
HASH_NODE * _ht_new_node(const HASH_TABLE *table, const char *key)
node creation, HASH_CLASSIC mode
Definition n_hash.c:1370
void _ht_node_destroy(void *node)
destroy a HASH_NODE by first calling the HASH_NODE destructor
Definition n_hash.c:108
int _ht_put_ptr(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr), void *(*duplicator)(void *ptr))
put a pointer value with given key in the targeted hash table
Definition n_hash.c:1593
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:1715
int _destroy_ht(HASH_TABLE **table)
Free and set the table to NULL.
Definition n_hash.c:1889
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:1743
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:603
HASH_NODE * _ht_new_double_node(HASH_TABLE *table, const char *key, double value)
node creation, HASH_CLASSIC mode
Definition n_hash.c:1428
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:1557
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:1475
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:387
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:907
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:1772
HASH_NODE * _ht_new_node_trie(HASH_TABLE *table, const char key)
node creation, HASH_CLASSIC mode
Definition n_hash.c:50
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:835
HASH_NODE * _ht_new_int_node(HASH_TABLE *table, const char *key, int64_t value)
node creation, HASH_CLASSIC mode
Definition n_hash.c:1406
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:930
HASH_NODE * _ht_new_ptr_node(HASH_TABLE *table, const char *key, void *value, void(*destructor)(void *ptr), void *(*duplicator)(void *ptr))
node creation, HASH_CLASSIC mode, pointer to string value
Definition n_hash.c:1499
void _ht_print_trie(HASH_TABLE *table)
Generic print func call for trie trees.
Definition n_hash.c:778
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:659
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:277
int _ht_put_ptr_trie(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr), void *(*duplicator)(void *ptr))
put a pointer to the string value with given key in the targeted hash table [TRIE HASH TABLE)
Definition n_hash.c:511
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:744
HASH_NODE * _ht_get_node_trie(HASH_TABLE *table, const char *key)
retrieve a HASH_NODE at key from table
Definition n_hash.c:570
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:1635
HASH_NODE * _ht_new_string_node(HASH_TABLE *table, const char *key, const char *value)
node creation, HASH_CLASSIC mode, strdup of value
Definition n_hash.c:1450
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:454
void _ht_print(HASH_TABLE *table)
Generic print func call for classic hash tables.
Definition n_hash.c:1910
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:178
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:687
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:1799
int _empty_ht(HASH_TABLE *table)
Empty a hash table (CLASSIC mode)
Definition n_hash.c:1870
#define BIG_CONSTANT(x)
max unsigned long long
Definition n_hash.c:859
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:84
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:1679
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:815
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:143
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:332
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:1339
#define BYTESWAP64(x)
32 bits bytes swap
Definition n_hash.c:890
#define BYTESWAP32(x)
32 bits bytes swap
Definition n_hash.c:886
int _destroy_ht_trie(HASH_TABLE **table)
Free and set the table to NULL (TRIE mode)
Definition n_hash.c:729
int _empty_ht_trie(HASH_TABLE *table)
Empty a TRIE hash table.
Definition n_hash.c:713
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:631
int _ht_remove(HASH_TABLE *table, const char *key)
Remove a key from a hash table.
Definition n_hash.c:1825
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:919
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:1523
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:210
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:1928
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:795
#define ROTL64(x, r)
64 bit rotate left
Definition n_hash.c:855
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:945
#define ROTL32(x, r)
32 bit rotate left
Definition n_hash.c:857
Hash functions and table.
Generic log system.
N_STR and string function declaration.