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 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
28#include "nilorea/n_common.h"
29#include "nilorea/n_log.h"
30#include "nilorea/n_hash.h"
31#include "nilorea/n_str.h"
32
33#include <pthread.h>
34#include <string.h>
35#include <strings.h>
36
37#ifdef __windows__
38#include <winsock.h>
39#else
40#include <arpa/inet.h>
41#endif
42
43/* Trie tree tables */
44
52 __n_assert(table, return NULL);
53
54 HASH_NODE* new_hash_node = NULL;
55 Malloc(new_hash_node, HASH_NODE, 1);
56 __n_assert(new_hash_node, n_log(LOG_ERR, "Could not allocate new_hash_node"); return NULL);
57 new_hash_node->key = NULL;
58 new_hash_node->hash_value = 0;
59 new_hash_node->data.ptr = NULL;
60 new_hash_node->destroy_func = NULL;
61 new_hash_node->children = NULL;
62 new_hash_node->is_leaf = 0;
63 new_hash_node->need_rehash = 0;
64 new_hash_node->alphabet_length = table->alphabet_length;
65
66 Malloc(new_hash_node->children, HASH_NODE*, table->alphabet_length);
67 __n_assert(new_hash_node->children, n_log(LOG_ERR, "Could not allocate new_hash_node"); Free(new_hash_node); return NULL);
68
69 /* n_log( LOG_DEBUG , "node: %d %c table: alpha: %d / offset %d" , key , key , table -> alphabet_length , table -> alphabet_offset ); */
70
71 for (size_t it = 0; it < table->alphabet_length; it++) {
72 new_hash_node->children[it] = NULL;
73 }
74 new_hash_node->is_leaf = 0;
75 new_hash_node->key_id = key;
76 return new_hash_node;
77} /* _ht_new_node_trie(...) */
78
85int _ht_is_leaf_node_trie(HASH_TABLE* table, const char* key) {
86 __n_assert(table, return -1);
87
88 /* checks if the prefix match of key and root is a leaf node */
89 HASH_NODE* node = table->root;
90 for (size_t it = 0; key[it]; it++) {
91 size_t index = (size_t)key[it] - table->alphabet_offset;
92 if (index >= table->alphabet_length) {
93 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
94 index = 0;
95 }
96 if (node->children[index]) {
97 node = node->children[index];
98 } else {
99 return 0;
100 }
101 }
102 return node->is_leaf;
103} /* _ht_is_leaf_node_trie(...) */
104
109void _ht_node_destroy(void* node) {
110 HASH_NODE* node_ptr = (HASH_NODE*)node;
111 __n_assert(node_ptr, return);
112 if (node_ptr->type == HASH_STRING) {
113 Free(node_ptr->data.string);
114 }
115 if (node_ptr->type == HASH_PTR) {
116 if (node_ptr->destroy_func && node_ptr->data.ptr) {
117 node_ptr->destroy_func(node_ptr->data.ptr);
118 }
119 /* No free by default. must be passed as a destroy_func
120 else
121 {
122 Free( node_ptr -> data . ptr );
123 }
124 */
125 }
126 FreeNoLog(node_ptr->key);
127 if (node_ptr->alphabet_length > 0) {
128 for (size_t it = 0; it < node_ptr->alphabet_length; it++) {
129 if (node_ptr->children[it]) {
130 _ht_node_destroy(node_ptr->children[it]);
131 }
132 }
133 Free(node_ptr->children);
134 }
135 Free(node_ptr);
136} /* _ht_node_destroy */
137
144size_t _ht_check_trie_divergence(HASH_TABLE* table, const char* key) {
145 __n_assert(table, return SIZE_MAX);
146 __n_assert(key, return SIZE_MAX);
147 __n_assert(table->root, return SIZE_MAX);
148
149 HASH_NODE* node = table->root;
150
151 size_t last_index = 0;
152 /* `node` is non-null on entry (table->root checked above) and only ever
153 * gets reassigned from `node->children[index]` after that slot was
154 * verified non-null. We still gate the loop on `node` so the static
155 * analyzer narrows `node` to non-null at every dereference inside the
156 * body, older clang static analyzers (the one in Ubuntu's clang-tools
157 * package, used by CI) don't track that constraint through the
158 * children[] reassignment, even though it holds. */
159 for (size_t it = 0; node && key[it] != '\0'; it++) {
160 size_t index = (size_t)key[it] - table->alphabet_offset;
161 if (index >= table->alphabet_length) {
162 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
163 index = 0;
164 }
165 HASH_NODE* child = node->children[index];
166 if (child) {
167 /* child check */
168 for (size_t it2 = 0; it2 < table->alphabet_length; it2++) {
169 if (it2 != (unsigned)index && node->children[it2]) {
170 /* child found, update branch index */
171 last_index = it + 1;
172 break;
173 }
174 }
175 /* Go to the next child in the sequence */
176 node = child;
177 }
178 }
179 return last_index;
180} /* _ht_check_trie_divergence(...) */
181
188char* _ht_find_longest_prefix_trie(HASH_TABLE* table, const char* key) {
189 __n_assert(table, return NULL);
190 __n_assert(key, return NULL);
191
192 size_t len = strlen(key);
193
194 /* start with full key and backtrack to search for divergences */
195 char* longest_prefix = NULL;
196 Malloc(longest_prefix, char, len + 1);
197 __n_assert(longest_prefix, return NULL);
198 memcpy(longest_prefix, key, len);
199 /* memcpy does not add a null terminator; set it explicitly */
200 longest_prefix[len] = '\0';
201
202 /* check branching from the root */
203 size_t branch_index = _ht_check_trie_divergence(table, longest_prefix);
204 if (branch_index > 0 && branch_index != SIZE_MAX) {
205 /* truncate to the branch point */
206 longest_prefix[branch_index - 1] = '\0';
207 /* shrink the allocation; Realloc preserves the original pointer on
208 failure so the caller still gets a valid terminated string */
209 Realloc(longest_prefix, char, branch_index + 1);
210 }
211 return longest_prefix;
212} /* _ht_find_longest_prefix_trie(...) */
213
220int _ht_remove_trie(HASH_TABLE* table, const char* key) {
221 __n_assert(table, return FALSE);
222 __n_assert(table->root, return FALSE);
223 __n_assert(key, return FALSE);
224
225 /* stop if matching node not a leaf node */
226 if (!_ht_is_leaf_node_trie(table, key)) {
227 return FALSE;
228 }
229
230 HASH_NODE* node = table->root;
231 /* find the longest prefix string that is not the current key */
232 char* longest_prefix = _ht_find_longest_prefix_trie(table, key);
233 if (!longest_prefix) {
234 n_log(LOG_ERR, "couldn't find longest prefix for key %s", key);
235 return FALSE;
236 }
237 if (longest_prefix[0] == '\0') {
238 Free(longest_prefix);
239 return FALSE;
240 }
241 /* keep track of position in the tree */
242 size_t it = 0;
243 for (it = 0; longest_prefix[it] != '\0'; it++) {
244 size_t index = (size_t)longest_prefix[it] - table->alphabet_offset;
245 if (index >= table->alphabet_length) {
246 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
247 index = 0;
248 }
249 if (node->children[index] != NULL) {
250 /* common prefix, keep moving */
251 node = node->children[index];
252 } else {
253 /* not found */
254 Free(longest_prefix);
255 return FALSE;
256 }
257 }
258 /* deepest common node between the two strings */
259 /* deleting the sequence corresponding to key */
260 for (; 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 if (node->children[index]) {
267 /* delete the remaining sequence */
268 HASH_NODE* node_to_kill = node->children[index];
269 node->children[index] = NULL;
270 _ht_node_destroy(node_to_kill);
271 }
272 }
273 Free(longest_prefix);
274
275 table->nb_keys--;
276
277 return TRUE;
278} /* _ht_remove_trie(...) */
279
287int _ht_put_int_trie(HASH_TABLE* table, const char* key, HASH_INT_TYPE value) {
288 __n_assert(table, return FALSE);
289 __n_assert(key, return FALSE);
290
291 HASH_NODE* node = table->root;
292
293 for (size_t it = 0; key[it] != '\0'; it++) {
294 size_t index = (size_t)key[it] - table->alphabet_offset;
295 if (index >= table->alphabet_length) {
296 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
297 index = 0;
298 }
299 /* n_log( LOG_DEBUG , "index:%d" , index ); */
300 if (node->children[index] == NULL) {
301 /* create a node */
302 node->children[index] = _ht_new_node_trie(table, key[it]);
303 __n_assert(node->children[index], return FALSE);
304 } else {
305 /* nothing to do since node is existing */
306 }
307 /* go down a level, to the child referenced by index */
308 node = node->children[index];
309 }
310 /* At the end of the key, mark this node as the leaf node */
311 int was_leaf = node->is_leaf;
312 if (was_leaf) {
313 FreeNoLog(node->key);
314 }
315 node->is_leaf = 1;
316 /* Put the key */
317 node->key = strdup(key);
318 if (!node->key) {
319 n_log(LOG_ERR, "strdup failure for key [%s]", key);
320 table->nb_keys++; /* compensate for upcoming remove */
321 _ht_remove_trie(table, key);
322 return FALSE;
323 }
324 /* Put the value */
325 node->data.ival = value;
326 node->type = HASH_INT;
327
328 if (!was_leaf) {
329 table->nb_keys++;
330 }
331
332 return TRUE;
333} /* _ht_put_int_trie(...) */
334
342int _ht_put_double_trie(HASH_TABLE* table, const char* key, double value) {
343 __n_assert(table, return FALSE);
344 __n_assert(key, return FALSE);
345
346 HASH_NODE* node = table->root;
347
348 for (size_t it = 0; key[it] != '\0'; it++) {
349 size_t index = (size_t)key[it] - table->alphabet_offset;
350 if (index >= table->alphabet_length) {
351 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
352 index = 0;
353 }
354 if (node->children[index] == NULL) {
355 /* create a node */
356 node->children[index] = _ht_new_node_trie(table, key[it]);
357 __n_assert(node->children[index], return FALSE);
358 } else {
359 /* nothing to do since node is existing */
360 }
361 /* go down a level, to the child referenced by index */
362 node = node->children[index];
363 }
364 /* At the end of the key, mark this node as the leaf node */
365 int was_leaf = node->is_leaf;
366 if (was_leaf) {
367 FreeNoLog(node->key);
368 }
369 node->is_leaf = 1;
370 /* Put the key */
371 node->key = strdup(key);
372 if (!node->key) {
373 n_log(LOG_ERR, "strdup failure for key [%s]", key);
374 table->nb_keys++; /* compensate for upcoming remove */
375 _ht_remove_trie(table, key);
376 return FALSE;
377 }
378 /* Put the value */
379 node->data.fval = value;
380 node->type = HASH_DOUBLE;
381
382 if (!was_leaf) {
383 table->nb_keys++;
384 }
385
386 return TRUE;
387} /* _ht_put_double_trie(...) */
388
396// cppcheck-suppress constParameterCallback ; callback signature must match typedef
397int _ht_put_string_trie(HASH_TABLE* table, const char* key, char* string) {
398 __n_assert(table, return FALSE);
399 __n_assert(key, return FALSE);
400
401 HASH_NODE* node = table->root;
402
403 for (size_t it = 0; key[it] != '\0'; it++) {
404 size_t index = (size_t)key[it] - table->alphabet_offset;
405 if (index >= table->alphabet_length) {
406 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
407 index = 0;
408 }
409 if (node->children[index] == NULL) {
410 /* create a node */
411 node->children[index] = _ht_new_node_trie(table, key[it]);
412 __n_assert(node->children[index], return FALSE);
413 } else {
414 /* nothing to do since node is existing */
415 }
416 /* go down a level, to the child referenced by index */
417 node = node->children[index];
418 }
419 /* At the end of the key, mark this node as the leaf node */
420 int was_leaf = node->is_leaf;
421 if (was_leaf) {
422 FreeNoLog(node->key);
423 FreeNoLog(node->data.string);
424 }
425 node->is_leaf = 1;
426 /* Put the key */
427 node->key = strdup(key);
428 if (!node->key) {
429 n_log(LOG_ERR, "strdup failure for key [%s]", key);
430 table->nb_keys++; /* compensate for upcoming remove */
431 _ht_remove_trie(table, key);
432 return FALSE;
433 }
434 /* Put the value */
435 if (string) {
436 node->data.string = strdup(string);
437 if (!node->data.string) {
438 n_log(LOG_ERR, "strdup failure for value at key [%s]", key);
439 Free(node->key);
440 table->nb_keys++; /* compensate for upcoming remove */
441 _ht_remove_trie(table, key);
442 return FALSE;
443 }
444 } else {
445 node->data.string = NULL;
446 }
447
448 node->type = HASH_STRING;
449
450 if (!was_leaf) {
451 table->nb_keys++;
452 }
453
454 return TRUE;
455} /* _ht_put_string_trie(...) */
456
464int _ht_put_string_ptr_trie(HASH_TABLE* table, const char* key, char* string) {
465 __n_assert(table, return FALSE);
466 __n_assert(key, return FALSE);
467
468 HASH_NODE* node = table->root;
469
470 for (size_t it = 0; key[it] != '\0'; it++) {
471 size_t index = (size_t)key[it] - table->alphabet_offset;
472 if (index >= table->alphabet_length) {
473 n_log(LOG_ERR, "Invalid value %d for charater at position %d of %s, set to 0", index, it, key);
474 index = 0;
475 }
476 if (node->children[index] == NULL) {
477 /* create a node */
478 node->children[index] = _ht_new_node_trie(table, key[it]);
479 __n_assert(node->children[index], return FALSE);
480 } else {
481 /* nothing to do since node is existing */
482 }
483 /* go down a level, to the child referenced by index */
484 node = node->children[index];
485 }
486 /* At the end of the key, mark this node as the leaf node */
487 int was_leaf = node->is_leaf;
488 if (was_leaf) {
489 FreeNoLog(node->key);
490 FreeNoLog(node->data.string);
491 }
492 node->is_leaf = 1;
493 /* Put the key - string pointer variant does not strdup the value, but key must be duplicated */
494 node->key = strdup(key);
495 if (!node->key) {
496 n_log(LOG_ERR, "strdup failure for key [%s]", key);
497 table->nb_keys++; /* compensate for upcoming remove */
498 _ht_remove_trie(table, key);
499 return FALSE;
500 }
501 /* Put the string pointer (not a copy - caller owns the string) */
502 node->data.string = string;
503 node->type = HASH_STRING;
504
505 if (!was_leaf) {
506 table->nb_keys++;
507 }
508
509 return TRUE;
510} /* _ht_put_string_ptr_trie(...) */
511
521int _ht_put_ptr_trie(HASH_TABLE* table, const char* key, void* ptr, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
522 __n_assert(table, return FALSE);
523 __n_assert(key, return FALSE);
524
525 HASH_NODE* node = table->root;
526
527 for (size_t it = 0; key[it] != '\0'; it++) {
528 size_t index = (size_t)key[it] - table->alphabet_offset;
529 if (index >= table->alphabet_length) {
530 n_log(LOG_ERR, "Invalid value %zu for character at position %zu of %s, set to 0", index, it, key);
531 index = 0;
532 }
533 if (node->children[index] == NULL) {
534 /* create a node */
535 node->children[index] = _ht_new_node_trie(table, key[it]);
536 __n_assert(node->children[index], return FALSE);
537 } else {
538 /* nothing to do since node is existing */
539 }
540 /* go down a level, to the child referenced by index */
541 node = node->children[index];
542 }
543 /* At the end of the key, mark this node as the leaf node */
544 int was_leaf = node->is_leaf;
545 if (was_leaf) {
546 FreeNoLog(node->key);
547 /* free old value if a destructor was set */
548 if (node->destroy_func && node->data.ptr) {
549 node->destroy_func(node->data.ptr);
550 }
551 }
552 node->is_leaf = 1;
553 /* Put the key */
554 node->key = strdup(key);
555 if (!node->key) {
556 n_log(LOG_ERR, "strdup failure for key [%s]", key);
557 table->nb_keys++; /* compensate for upcoming remove */
558 _ht_remove_trie(table, key);
559 return FALSE;
560 }
561 /* Put the value */
562 node->data.ptr = ptr;
563 node->destroy_func = destructor;
564 node->duplicate_func = duplicator;
565 node->type = HASH_PTR;
566
567 if (!was_leaf) {
568 table->nb_keys++;
569 }
570
571 return TRUE;
572} /* _ht_put_ptr_trie(...) */
573
581 __n_assert(table, return NULL);
582 __n_assert(key, return NULL);
583
584 HASH_NODE* node = NULL;
585
586 if (key[0] != '\0') {
587 node = table->root;
588 for (size_t it = 0; key[it] != '\0'; it++) {
589 size_t index = (size_t)key[it] - table->alphabet_offset;
590 if (index >= table->alphabet_length) {
591 n_log(LOG_DEBUG, "Invalid value %d for charater at index %d of %s, set to 0", index, it, key);
592 return NULL;
593 }
594 if (node->children[index] == NULL) {
595 /* not found */
596 return NULL;
597 }
598 node = node->children[index];
599 }
600 } else {
601 node = NULL;
602 }
603 return node;
604} /* _ht_get_node_trie(...) */
605
613int _ht_get_int_trie(HASH_TABLE* table, const char* key, HASH_INT_TYPE* val) {
614 __n_assert(table, return FALSE);
615 __n_assert(key, return FALSE);
616 if (strlen(key) == 0)
617 return FALSE;
618
619 HASH_NODE* node = _ht_get_node_trie(table, key);
620
621 if (!node || !node->is_leaf)
622 return FALSE;
623
624 if (node->type != HASH_INT) {
625 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_INT, key is type %s", key, ht_node_type(node));
626 return FALSE;
627 }
628
629 (*val) = node->data.ival;
630
631 return TRUE;
632} /* _ht_get_int_trie() */
633
641int _ht_get_double_trie(HASH_TABLE* table, const char* key, double* val) {
642 __n_assert(table, return FALSE);
643 __n_assert(key, return FALSE);
644 if (strlen(key) == 0)
645 return FALSE;
646
647 HASH_NODE* node = _ht_get_node_trie(table, key);
648
649 if (!node || !node->is_leaf)
650 return FALSE;
651
652 if (node->type != HASH_DOUBLE) {
653 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_DOUBLE, key is type %s", key, ht_node_type(node));
654 return FALSE;
655 }
656
657 (*val) = node->data.fval;
658
659 return TRUE;
660} /* _ht_get_double_trie() */
661
669int _ht_get_string_trie(HASH_TABLE* table, const char* key, char** val) {
670 __n_assert(table, return FALSE);
671 __n_assert(key, return FALSE);
672 if (strlen(key) == 0)
673 return FALSE;
674
675 HASH_NODE* node = _ht_get_node_trie(table, key);
676
677 if (!node || !node->is_leaf)
678 return FALSE;
679
680 if (node->type != HASH_STRING) {
681 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_STRING, key is type %s", key, ht_node_type(node));
682 return FALSE;
683 }
684
685 (*val) = node->data.string;
686
687 return TRUE;
688} /* _ht_get_string_trie() */
689
697int _ht_get_ptr_trie(HASH_TABLE* table, const char* key, void** val) {
698 __n_assert(table, return FALSE);
699 __n_assert(key, return FALSE);
700 if (strlen(key) == 0)
701 return FALSE;
702
703 HASH_NODE* node = _ht_get_node_trie(table, key);
704
705 if (!node || !node->is_leaf)
706 return FALSE;
707
708 if (node->type != HASH_PTR) {
709 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_PTR , key is type %s", key, ht_node_type(node));
710 return FALSE;
711 }
712
713 (*val) = node->data.ptr;
714
715 return TRUE;
716} /* _ht_get_ptr_trie() */
717
724 __n_assert(table, return FALSE);
725
726 _ht_node_destroy(table->root);
727
728 table->root = _ht_new_node_trie(table, '\0');
729
730 table->nb_keys = 0;
731 return TRUE;
732} /* _empty_ht_trie */
733
740 __n_assert(table && (*table), n_log(LOG_ERR, "Can't destroy table: already NULL"); return FALSE);
741
742 _ht_node_destroy((*table)->root);
743
744 Free((*table));
745
746 return TRUE;
747} /* _destroy_ht_trie */
748
755 if (!node)
756 return;
757
758 if (node->is_leaf) {
759 printf("key: %s, val: ", node->key);
760 switch (node->type) {
761 case HASH_INT:
762 printf("int: %ld", (long)node->data.ival);
763 break;
764 case HASH_DOUBLE:
765 printf("double: %f", node->data.fval);
766 break;
767 case HASH_PTR:
768 printf("ptr: %p", node->data.ptr);
769 break;
770 case HASH_STRING:
771 printf("%s", node->data.string);
772 break;
773 default:
774 printf("unknwow type %d", node->type);
775 break;
776 }
777 printf("\n");
778 }
779 for (size_t it = 0; it < table->alphabet_length; it++) {
780 _ht_print_trie_helper(table, node->children[it]);
781 }
782} /* _ht_print_trie_helper(...) */
783
789 __n_assert(table, return);
790 __n_assert(table->root, return);
791
792 HASH_NODE* node = table->root;
793
794 _ht_print_trie_helper(table, node);
795
796 return;
797} /* _ht_print_trie(...) */
798
805void _ht_search_trie_helper(LIST* results, HASH_NODE* node, int (*node_is_matching)(HASH_NODE* node)) {
806 if (!node)
807 return;
808
809 if (node->is_leaf) {
810 if (node_is_matching(node) == TRUE) {
811 list_push(results, strdup(node->key), &free);
812 }
813 }
814 for (size_t it = 0; it < node->alphabet_length; it++) {
815 _ht_search_trie_helper(results, node->children[it], node_is_matching);
816 }
817}
818
825LIST* _ht_search_trie(HASH_TABLE* table, int (*node_is_matching)(HASH_NODE* node)) {
826 __n_assert(table, return NULL);
827
829 __n_assert(results, return NULL);
830
831 _ht_search_trie_helper(results, table->root, node_is_matching);
832
833 if (results->nb_items < 1)
834 list_destroy(&results);
835
836 return results;
837} /* _ht_search_trie(...) */
838
846 __n_assert(results, return FALSE);
847
848 if (!node)
849 return FALSE;
850
851 for (size_t it = 0; it < node->alphabet_length; it++) {
852 _ht_depth_first_search(node->children[it], results);
853 }
854 if (node->is_leaf) {
855 if (results->nb_items < results->nb_max_items) {
856 return list_push(results, strdup(node->key), &free);
857 }
858 return TRUE;
859 }
860 return TRUE;
861} /* _ht_depth_first_search(...) */
862
863/* Classic hash table */
865#define ROTL64(x, r) (((x) << (r)) | ((x) >> (64 - (r))))
867#define ROTL32(x, r) (((x) << (r)) | ((x) >> (32 - (r))))
869#define BIG_CONSTANT(x) (x##LLU)
870
871/* NO-OP for little-endian platforms */
872#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
873#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
874#define BYTESWAP32(x) (x)
875#define BYTESWAP64(x) (x)
876#endif
877/* if __BYTE_ORDER__ is not predefined (like FreeBSD), use arch */
878#elif defined(__i386) || defined(__x86_64) || defined(__alpha) || defined(__vax)
879
880#define BYTESWAP32(x) (x)
881#define BYTESWAP64(x) (x)
882/* use __builtin_bswap32 if available */
883#elif defined(__GNUC__) || defined(__clang__)
884#ifdef __has_builtin
885#if __has_builtin(__builtin_bswap32)
886#define BYTESWAP32(x) __builtin_bswap32(x)
887#endif // __has_builtin(__builtin_bswap32)
888#if __has_builtin(__builtin_bswap64)
889#define BYTESWAP64(x) __builtin_bswap64(x)
890#endif // __has_builtin(__builtin_bswap64)
891#endif // __has_builtin
892#endif // defined(__GNUC__) || defined(__clang__)
893/* last resort (big-endian w/o __builtin_bswap) */
894#ifndef BYTESWAP32
896#define BYTESWAP32(x) ((((x) & 0xFF) << 24) | (((x) >> 24) & 0xFF) | (((x) & 0x0000FF00) << 8) | (((x) & 0x00FF0000) >> 8))
897#endif
898#ifndef BYTESWAP64
900#define BYTESWAP64(x) \
901 (((uint64_t)(x) << 56) | \
902 (((uint64_t)(x) << 40) & 0X00FF000000000000ULL) | \
903 (((uint64_t)(x) << 24) & 0X0000FF0000000000ULL) | \
904 (((uint64_t)(x) << 8) & 0X000000FF00000000ULL) | \
905 (((uint64_t)(x) >> 8) & 0X00000000FF000000ULL) | \
906 (((uint64_t)(x) >> 24) & 0X0000000000FF0000ULL) | \
907 (((uint64_t)(x) >> 40) & 0X000000000000FF00ULL) | \
908 ((uint64_t)(x) >> 56))
909#endif
910
917FORCE_INLINE uint32_t getblock32(const uint32_t* p, const size_t i) {
918 uint32_t result;
919 memcpy(&result, (const uint8_t*)p + i * 4, sizeof(result));
920 return BYTESWAP32(result);
921}
922
929FORCE_INLINE uint64_t getblock64(const uint64_t* p, const size_t i) {
930 uint64_t result;
931 memcpy(&result, (const uint8_t*)p + i * 8, sizeof(result));
932 return BYTESWAP64(result);
933}
934
940FORCE_INLINE uint32_t fmix32(uint32_t h) {
941 h ^= h >> 16;
942 h *= 0x85ebca6b;
943 h ^= h >> 13;
944 h *= 0xc2b2ae35;
945 h ^= h >> 16;
946
947 return h;
948} /* fmix32(...) */
949
955FORCE_INLINE uint64_t fmix64(uint64_t k) {
956 k ^= k >> 33;
957 k *= BIG_CONSTANT(0xff51afd7ed558ccd);
958 k ^= k >> 33;
959 k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
960 k ^= k >> 33;
961
962 return k;
963}
964
977// Safe forward-indexing version
978void MurmurHash3_x86_32(const void* key, const size_t len, const uint32_t seed, void* out) {
979 const uint8_t* data = (const uint8_t*)key;
980 const size_t nblocks = len / 4;
981
982 uint32_t h1 = seed;
983 const uint32_t c1 = 0xcc9e2d51;
984 const uint32_t c2 = 0x1b873593;
985
986 const uint32_t* blocks = (const uint32_t*)data;
987
988 for (size_t i = 0; i < nblocks; i++) {
989 uint32_t k1 = getblock32(blocks, i);
990 k1 *= c1;
991 k1 = ROTL32(k1, 15);
992 k1 *= c2;
993
994 h1 ^= k1;
995 h1 = ROTL32(h1, 13);
996 h1 = h1 * 5 + 0xe6546b64;
997 }
998
999 const uint8_t* tail = data + nblocks * 4;
1000 uint32_t k1 = 0;
1001 switch (len & 3) {
1002 case 3:
1003 k1 ^= (uint32_t)tail[2] << 16; /* fall through */
1005 case 2:
1006 k1 ^= (uint32_t)tail[1] << 8; /* fall through */
1008 case 1:
1009 k1 ^= (uint32_t)tail[0];
1010 k1 *= c1;
1011 k1 = ROTL32(k1, 15);
1012 k1 *= c2;
1013 h1 ^= k1;
1014 break;
1015 default:
1016 break;
1017 }
1018
1019 h1 ^= (uint32_t)len;
1020 h1 = fmix32(h1);
1021 *(uint32_t*)out = h1;
1022} /* MurmurHash3_x86_32 */
1023
1036void MurmurHash3_x86_128(const void* key, const size_t len, const uint32_t seed, void* out) {
1037 const uint8_t* data = (const uint8_t*)key;
1038 const size_t nblocks = len / 16;
1039
1040 uint32_t h1 = seed;
1041 uint32_t h2 = seed;
1042 uint32_t h3 = seed;
1043 uint32_t h4 = seed;
1044
1045 const uint32_t c1 = 0x239b961b;
1046 const uint32_t c2 = 0xab0e9789;
1047 const uint32_t c3 = 0x38b34ae5;
1048 const uint32_t c4 = 0xa1e38b93;
1049
1050 const uint32_t* blocks = (const uint32_t*)data;
1051
1052 for (size_t i = 0; i < nblocks; i++) {
1053 uint32_t k1 = getblock32(blocks, i * 4 + 0);
1054 uint32_t k2 = getblock32(blocks, i * 4 + 1);
1055 uint32_t k3 = getblock32(blocks, i * 4 + 2);
1056 uint32_t k4 = getblock32(blocks, i * 4 + 3);
1057
1058 k1 *= c1;
1059 k1 = ROTL32(k1, 15);
1060 k1 *= c2;
1061 h1 ^= k1;
1062 h1 = ROTL32(h1, 19);
1063 h1 += h2;
1064 h1 = h1 * 5 + 0x561ccd1b;
1065
1066 k2 *= c2;
1067 k2 = ROTL32(k2, 16);
1068 k2 *= c3;
1069 h2 ^= k2;
1070 h2 = ROTL32(h2, 17);
1071 h2 += h3;
1072 h2 = h2 * 5 + 0x0bcaa747;
1073
1074 k3 *= c3;
1075 k3 = ROTL32(k3, 17);
1076 k3 *= c4;
1077 h3 ^= k3;
1078 h3 = ROTL32(h3, 15);
1079 h3 += h4;
1080 h3 = h3 * 5 + 0x96cd1c35;
1081
1082 k4 *= c4;
1083 k4 = ROTL32(k4, 18);
1084 k4 *= c1;
1085 h4 ^= k4;
1086 h4 = ROTL32(h4, 13);
1087 h4 += h1;
1088 h4 = h4 * 5 + 0x32ac3b17;
1089 }
1090
1091 // tail
1092 const uint8_t* tail = data + nblocks * 16;
1093
1094 uint32_t k1 = 0, k2 = 0, k3 = 0, k4 = 0;
1095
1096 switch (len & 15) {
1097 case 15:
1098 k4 ^= (uint32_t)tail[14] << 16; /* fall through */
1100 case 14:
1101 k4 ^= (uint32_t)tail[13] << 8; /* fall through */
1103 case 13:
1104 k4 ^= (uint32_t)tail[12];
1105 k4 *= c4;
1106 k4 = ROTL32(k4, 18);
1107 k4 *= c1;
1108 h4 ^= k4;
1109 /* fall through */
1111 case 12:
1112 k3 ^= (uint32_t)tail[11] << 24; /* fall through */
1114 case 11:
1115 k3 ^= (uint32_t)tail[10] << 16; /* fall through */
1117 case 10:
1118 k3 ^= (uint32_t)tail[9] << 8; /* fall through */
1120 case 9:
1121 k3 ^= (uint32_t)tail[8];
1122 k3 *= c3;
1123 k3 = ROTL32(k3, 17);
1124 k3 *= c4;
1125 h3 ^= k3;
1126 /* fall through */
1128 case 8:
1129 k2 ^= (uint32_t)tail[7] << 24; /* fall through */
1131 case 7:
1132 k2 ^= (uint32_t)tail[6] << 16; /* fall through */
1134 case 6:
1135 k2 ^= (uint32_t)tail[5] << 8; /* fall through */
1137 case 5:
1138 k2 ^= (uint32_t)tail[4];
1139 k2 *= c2;
1140 k2 = ROTL32(k2, 16);
1141 k2 *= c3;
1142 h2 ^= k2;
1143 /* fall through */
1145 case 4:
1146 k1 ^= (uint32_t)tail[3] << 24; /* fall through */
1148 case 3:
1149 k1 ^= (uint32_t)tail[2] << 16; /* fall through */
1151 case 2:
1152 k1 ^= (uint32_t)tail[1] << 8; /* fall through */
1154 case 1:
1155 k1 ^= (uint32_t)tail[0];
1156 k1 *= c1;
1157 k1 = ROTL32(k1, 15);
1158 k1 *= c2;
1159 h1 ^= k1;
1160 break;
1161 default:
1162 break;
1163 }
1164
1165 // finalization
1166 h1 ^= (uint32_t)len;
1167 h2 ^= (uint32_t)len;
1168 h3 ^= (uint32_t)len;
1169 h4 ^= (uint32_t)len;
1170
1171 h1 += h2 + h3 + h4;
1172 h2 += h1;
1173 h3 += h1;
1174 h4 += h1;
1175
1176 h1 = fmix32(h1);
1177 h2 = fmix32(h2);
1178 h3 = fmix32(h3);
1179 h4 = fmix32(h4);
1180
1181 h1 += h2 + h3 + h4;
1182 h2 += h1;
1183 h3 += h1;
1184 h4 += h1;
1185
1186 ((uint32_t*)out)[0] = h1;
1187 ((uint32_t*)out)[1] = h2;
1188 ((uint32_t*)out)[2] = h3;
1189 ((uint32_t*)out)[3] = h4;
1190} /* MurmurHash3_x86_128(...) */
1191
1204void MurmurHash3_x64_128(const void* key, const size_t len, const uint64_t seed, void* out) {
1205 const uint8_t* data = (const uint8_t*)key;
1206 const size_t nblocks = len / 16;
1207
1208 uint64_t h1 = seed;
1209 uint64_t h2 = seed;
1210
1211 const uint64_t c1 = 0x87c37b91114253d5ULL;
1212 const uint64_t c2 = 0x4cf5ad432745937fULL;
1213
1214 // Body
1215 const uint64_t* blocks = (const uint64_t*)data;
1216 for (size_t i = 0; i < nblocks; i++) {
1217 uint64_t k1 = getblock64(blocks, i * 2 + 0);
1218 uint64_t k2 = getblock64(blocks, i * 2 + 1);
1219
1220 k1 *= c1;
1221 k1 = ROTL64(k1, 31);
1222 k1 *= c2;
1223 h1 ^= k1;
1224
1225 h1 = ROTL64(h1, 27);
1226 h1 += h2;
1227 h1 = h1 * 5 + 0x52dce729;
1228
1229 k2 *= c2;
1230 k2 = ROTL64(k2, 33);
1231 k2 *= c1;
1232 h2 ^= k2;
1233
1234 h2 = ROTL64(h2, 31);
1235 h2 += h1;
1236 h2 = h2 * 5 + 0x38495ab5;
1237 }
1238
1239 // Tail
1240 const uint8_t* tail = data + nblocks * 16;
1241
1242 uint64_t k1 = 0;
1243 uint64_t k2 = 0;
1244
1245 switch (len & 15) {
1246 case 15:
1247 k2 ^= ((uint64_t)tail[14]) << 48; /* fall through */
1249 case 14:
1250 k2 ^= ((uint64_t)tail[13]) << 40; /* fall through */
1252 case 13:
1253 k2 ^= ((uint64_t)tail[12]) << 32; /* fall through */
1255 case 12:
1256 k2 ^= ((uint64_t)tail[11]) << 24; /* fall through */
1258 case 11:
1259 k2 ^= ((uint64_t)tail[10]) << 16; /* fall through */
1261 case 10:
1262 k2 ^= ((uint64_t)tail[9]) << 8; /* fall through */
1264 case 9:
1265 k2 ^= ((uint64_t)tail[8]);
1266 k2 *= c2;
1267 k2 = ROTL64(k2, 33);
1268 k2 *= c1;
1269 h2 ^= k2;
1270 /* fall through */
1272 case 8:
1273 k1 ^= ((uint64_t)tail[7]) << 56; /* fall through */
1275 case 7:
1276 k1 ^= ((uint64_t)tail[6]) << 48; /* fall through */
1278 case 6:
1279 k1 ^= ((uint64_t)tail[5]) << 40; /* fall through */
1281 case 5:
1282 k1 ^= ((uint64_t)tail[4]) << 32; /* fall through */
1284 case 4:
1285 k1 ^= ((uint64_t)tail[3]) << 24; /* fall through */
1287 case 3:
1288 k1 ^= ((uint64_t)tail[2]) << 16; /* fall through */
1290 case 2:
1291 k1 ^= ((uint64_t)tail[1]) << 8; /* fall through */
1293 case 1:
1294 k1 ^= ((uint64_t)tail[0]);
1295 k1 *= c1;
1296 k1 = ROTL64(k1, 31);
1297 k1 *= c2;
1298 h1 ^= k1;
1299 break;
1300 default:
1301 break;
1302 }
1303
1304 // Finalization
1305 h1 ^= len;
1306 h2 ^= len;
1307
1308 h1 += h2;
1309 h2 += h1;
1310
1311 h1 = fmix64(h1);
1312 h2 = fmix64(h2);
1313
1314 h1 += h2;
1315 h2 += h1;
1316
1317 ((uint64_t*)out)[0] = h1;
1318 ((uint64_t*)out)[1] = h2;
1319} /* MurmurHash3_x64_128()*/
1320
1326char* ht_node_type(const HASH_NODE* node) {
1327 __n_assert(node, return "NULL_NODE");
1328
1329 switch (node->type) {
1330 case HASH_INT:
1331 return "HASH_INT";
1332 case HASH_DOUBLE:
1333 return "HASH_DOUBLE";
1334 case HASH_STRING:
1335 return "HASH_STRING";
1336 case HASH_PTR:
1337 return "HASH_PTR";
1338 default:
1339 return "HASH_UNKNOWN";
1340 }
1341} /* ht_node_type(...) */
1342
1349HASH_NODE* _ht_get_node(HASH_TABLE* table, const char* key) {
1350 HASH_VALUE hash_value[2] = {0, 0};
1351 size_t index = 0;
1352
1353 __n_assert(table, return NULL);
1354 __n_assert(key, return NULL);
1355
1356 if (key[0] == '\0')
1357 return NULL;
1358
1359 MurmurHash(key, strlen(key), table->seed, &hash_value);
1360 index = (hash_value[0]) % (table->size);
1361
1362 if (!table->hash_table[index]->start)
1363 return NULL;
1364
1365 list_foreach(list_node, table->hash_table[index]) {
1366 HASH_NODE* node_ptr = (HASH_NODE*)list_node->ptr;
1367 if (!strcmp(key, node_ptr->key)) {
1368 return node_ptr;
1369 }
1370 }
1371 return NULL;
1372} /* _ht_get_node() */
1373
1380HASH_NODE* _ht_new_node(const HASH_TABLE* table, const char* key) {
1381 __n_assert(table, return NULL);
1382 __n_assert(key, return NULL);
1383
1384 HASH_NODE* new_hash_node = NULL;
1385
1386 HASH_VALUE hash_value[2] = {0, 0};
1387
1388 if (strlen(key) == 0)
1389 return NULL;
1390
1391 MurmurHash(key, strlen(key), table->seed, &hash_value);
1392
1393 Malloc(new_hash_node, HASH_NODE, 1);
1394 __n_assert(new_hash_node, n_log(LOG_ERR, "Could not allocate new_hash_node"); return NULL);
1395 new_hash_node->key = strdup(key);
1396 new_hash_node->key_id = '\0';
1397 __n_assert(new_hash_node->key, n_log(LOG_ERR, "Could not allocate new_hash_node->key"); Free(new_hash_node); return NULL);
1398 new_hash_node->hash_value = hash_value[0];
1399 new_hash_node->data.ptr = NULL;
1400 new_hash_node->destroy_func = NULL;
1401 new_hash_node->children = NULL;
1402 new_hash_node->is_leaf = 0;
1403 new_hash_node->need_rehash = 0;
1404 new_hash_node->alphabet_length = 0;
1405
1406 return new_hash_node;
1407} /* _ht_new_node */
1408
1417 __n_assert(table, return NULL);
1418 __n_assert(key, return NULL);
1419
1420 HASH_NODE* new_hash_node = NULL;
1421 new_hash_node = _ht_new_node(table, key);
1422 if (new_hash_node) {
1423 new_hash_node->data.ival = value;
1424 new_hash_node->type = HASH_INT;
1425 } else {
1426 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1427 }
1428 return new_hash_node;
1429} /* _ht_new_int_node */
1430
1438HASH_NODE* _ht_new_double_node(HASH_TABLE* table, const char* key, double value) {
1439 __n_assert(table, return NULL);
1440 __n_assert(key, return NULL);
1441
1442 HASH_NODE* new_hash_node = NULL;
1443 new_hash_node = _ht_new_node(table, key);
1444 if (new_hash_node) {
1445 new_hash_node->data.fval = value;
1446 new_hash_node->type = HASH_DOUBLE;
1447 } else {
1448 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1449 }
1450 return new_hash_node;
1451} /* _ht_new_double_node */
1452
1460HASH_NODE* _ht_new_string_node(HASH_TABLE* table, const char* key, const char* value) {
1461 __n_assert(table, return NULL);
1462 __n_assert(key, return NULL);
1463
1464 HASH_NODE* new_hash_node = NULL;
1465 new_hash_node = _ht_new_node(table, key);
1466 if (new_hash_node) {
1467 if (value)
1468 new_hash_node->data.string = strdup(value);
1469 else
1470 new_hash_node->data.string = NULL;
1471 new_hash_node->type = HASH_STRING;
1472 } else {
1473 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1474 }
1475 return new_hash_node;
1476}
1477
1485HASH_NODE* _ht_new_string_ptr_node(HASH_TABLE* table, const char* key, char* value) {
1486 __n_assert(table, return NULL);
1487 __n_assert(key, return NULL);
1488
1489 HASH_NODE* new_hash_node = NULL;
1490 new_hash_node = _ht_new_node(table, key);
1491 if (new_hash_node) {
1492 new_hash_node->data.string = value;
1493 new_hash_node->type = HASH_STRING;
1494 } else {
1495 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1496 }
1497 return new_hash_node;
1498}
1499
1509HASH_NODE* _ht_new_ptr_node(HASH_TABLE* table, const char* key, void* value, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
1510 __n_assert(table, return NULL);
1511 __n_assert(key, return NULL);
1512
1513 HASH_NODE* new_hash_node = NULL;
1514 new_hash_node = _ht_new_node(table, key);
1515 if (new_hash_node) {
1516 new_hash_node->data.ptr = value;
1517 new_hash_node->destroy_func = destructor;
1518 new_hash_node->duplicate_func = duplicator;
1519 new_hash_node->type = HASH_PTR;
1520 } else {
1521 n_log(LOG_ERR, "Could not get a new node in table %p with key %s", table, key);
1522 }
1523 return new_hash_node;
1524}
1525
1533int _ht_put_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE value) {
1534 HASH_NODE* node_ptr = NULL;
1535
1536 __n_assert(table, return FALSE);
1537 __n_assert(key, return FALSE);
1538
1539 if ((node_ptr = _ht_get_node(table, key))) {
1540 if (node_ptr->type == HASH_INT) {
1541 node_ptr->data.ival = value;
1542 return TRUE;
1543 }
1544 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));
1545 return FALSE; /* key registered with another data type */
1546 }
1547
1548 int retcode = FALSE;
1549 node_ptr = _ht_new_int_node(table, key, value);
1550 if (node_ptr) {
1551 size_t index = (node_ptr->hash_value) % (table->size);
1552 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1553 if (retcode == TRUE) {
1554 table->nb_keys++;
1555 }
1556 }
1557 return retcode;
1558} /*_ht_put_int() */
1559
1567int _ht_put_double(HASH_TABLE* table, const char* key, double value) {
1568 HASH_NODE* node_ptr = NULL;
1569
1570 __n_assert(table, return FALSE);
1571 __n_assert(key, return FALSE);
1572
1573 if ((node_ptr = _ht_get_node(table, key))) {
1574 if (node_ptr->type == HASH_DOUBLE) {
1575 node_ptr->data.fval = value;
1576 return TRUE;
1577 }
1578 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));
1579 return FALSE; /* key registered with another data type */
1580 }
1581
1582 int retcode = FALSE;
1583 node_ptr = _ht_new_double_node(table, key, value);
1584 if (node_ptr) {
1585 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1586 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1587 if (retcode == TRUE) {
1588 table->nb_keys++;
1589 }
1590 }
1591 return retcode;
1592} /*_ht_put_double()*/
1593
1603int _ht_put_ptr(HASH_TABLE* table, const char* key, void* ptr, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
1604 HASH_NODE* node_ptr = NULL;
1605
1606 __n_assert(table, return FALSE);
1607 __n_assert(key, return FALSE);
1608
1609 if ((node_ptr = _ht_get_node(table, key))) {
1610 /* let's check the key isn't already assigned with another data type */
1611 if (node_ptr->type == HASH_PTR) {
1612 /* free the old value if a destructor is set */
1613 if (node_ptr->destroy_func && node_ptr->data.ptr) {
1614 node_ptr->destroy_func(node_ptr->data.ptr);
1615 }
1616 /* always update the pointer and function pointers */
1617 node_ptr->data.ptr = ptr;
1618 node_ptr->destroy_func = destructor;
1619 node_ptr->duplicate_func = duplicator;
1620 return TRUE;
1621 }
1622 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));
1623 return FALSE; /* key registered with another data type */
1624 }
1625
1626 int retcode = FALSE;
1627 node_ptr = _ht_new_ptr_node(table, key, ptr, destructor, duplicator);
1628 if (node_ptr) {
1629 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1630 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1631 if (retcode == TRUE) {
1632 table->nb_keys++;
1633 }
1634 }
1635 return retcode;
1636} /* _ht_put_ptr() */
1637
1645int _ht_put_string(HASH_TABLE* table, const char* key, char* string) {
1646 HASH_NODE* node_ptr = NULL;
1647
1648 __n_assert(table, return FALSE);
1649 __n_assert(key, return FALSE);
1650
1651 if ((node_ptr = _ht_get_node(table, key))) {
1652 /* let's check the key isn't already assigned with another data type */
1653 if (node_ptr->type == HASH_STRING) {
1654 char* new_str = NULL;
1655 if (string) {
1656 new_str = strdup(string);
1657 if (!new_str) {
1658 n_log(LOG_ERR, "could not strdup char *string at %p, didn't overwrite %s", string, key);
1659 return FALSE;
1660 }
1661 }
1662 Free(node_ptr->data.string);
1663 node_ptr->data.string = new_str;
1664 return TRUE;
1665 }
1666 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));
1667 return FALSE; /* key registered with another data type */
1668 }
1669
1670 int retcode = FALSE;
1671 node_ptr = _ht_new_string_node(table, key, string);
1672 if (node_ptr) {
1673 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1674 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1675 if (retcode == TRUE) {
1676 table->nb_keys++;
1677 }
1678 }
1679 return retcode;
1680} /*_ht_put_string */
1681
1689int _ht_put_string_ptr(HASH_TABLE* table, const char* key, char* string) {
1690 HASH_NODE* node_ptr = NULL;
1691
1692 __n_assert(table, return FALSE);
1693 __n_assert(key, return FALSE);
1694
1695 if ((node_ptr = _ht_get_node(table, key))) {
1696 /* let's check the key isn't already assigned with another data type */
1697 if (node_ptr->type == HASH_STRING) {
1698 Free(node_ptr->data.string);
1699 node_ptr->data.string = string;
1700 return TRUE;
1701 }
1702 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));
1703 return FALSE; /* key registered with another data type */
1704 }
1705
1706 int retcode = FALSE;
1707 node_ptr = _ht_new_string_ptr_node(table, key, string);
1708 if (node_ptr) {
1709 HASH_VALUE index = (node_ptr->hash_value) % (table->size);
1710 retcode = list_push(table->hash_table[index], node_ptr, &_ht_node_destroy);
1711 if (retcode == TRUE) {
1712 table->nb_keys++;
1713 }
1714 }
1715 return retcode;
1716} /*_ht_put_string_ptr */
1717
1725int _ht_get_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE* val) {
1726 __n_assert(table, return FALSE);
1727 __n_assert(key, return FALSE);
1728 if (strlen(key) == 0)
1729 return FALSE;
1730
1731 HASH_NODE* node = _ht_get_node(table, key);
1732
1733 if (!node)
1734 return FALSE;
1735
1736 if (node->type != HASH_INT) {
1737 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_INT, key is type %s", key, ht_node_type(node));
1738 return FALSE;
1739 }
1740
1741 (*val) = node->data.ival;
1742
1743 return TRUE;
1744} /* _ht_get_int() */
1745
1753int _ht_get_double(HASH_TABLE* table, const char* key, double* val) {
1754 __n_assert(table, return FALSE);
1755 __n_assert(key, return FALSE);
1756
1757 if (strlen(key) == 0)
1758 return FALSE;
1759
1760 HASH_NODE* node = _ht_get_node(table, key);
1761
1762 if (!node)
1763 return FALSE;
1764
1765 if (node->type != HASH_DOUBLE) {
1766 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_DOUBLE, key is type %s", key, ht_node_type(node));
1767 return FALSE;
1768 }
1769
1770 (*val) = node->data.fval;
1771
1772 return TRUE;
1773} /* _ht_get_double()*/
1774
1782int _ht_get_ptr(HASH_TABLE* table, const char* key, void** val) {
1783 __n_assert(table, return FALSE);
1784 __n_assert(key, return FALSE);
1785 if (strlen(key) == 0)
1786 return FALSE;
1787
1788 HASH_NODE* node = _ht_get_node(table, key);
1789 if (!node)
1790 return FALSE;
1791
1792 if (node->type != HASH_PTR) {
1793 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_PTR, key is type %s", key, ht_node_type(node));
1794 return FALSE;
1795 }
1796
1797 (*val) = node->data.ptr;
1798
1799 return TRUE;
1800} /* _ht_get_ptr() */
1801
1809int _ht_get_string(HASH_TABLE* table, const char* key, char** val) {
1810 __n_assert(table, return FALSE);
1811 __n_assert(key, return FALSE);
1812 if (strlen(key) == 0)
1813 return FALSE;
1814
1815 HASH_NODE* node = _ht_get_node(table, key);
1816 if (!node)
1817 return FALSE;
1818
1819 if (node->type != HASH_STRING) {
1820 n_log(LOG_ERR, "Can't get key[\"%s\"] of type HASH_STRING, key is type %s", key, ht_node_type(node));
1821 return FALSE;
1822 }
1823
1824 (*val) = node->data.string;
1825
1826 return TRUE;
1827} /* _ht_get_string() */
1828
1835int _ht_remove(HASH_TABLE* table, const char* key) {
1836 HASH_VALUE hash_value[2] = {0, 0};
1837 size_t index = 0;
1838
1839 HASH_NODE* node_ptr = NULL;
1840 LIST_NODE* node_to_kill = NULL;
1841
1842 __n_assert(table, return FALSE);
1843 __n_assert(key, return FALSE);
1844 if (strlen(key) == 0)
1845 return FALSE;
1846
1847 MurmurHash(key, strlen(key), table->seed, &hash_value);
1848 index = (hash_value[0]) % (table->size);
1849
1850 if (!table->hash_table[index]->start) {
1851 n_log(LOG_ERR, "Can't remove key[\"%s\"], table is empty", key);
1852 return FALSE;
1853 }
1854
1855 list_foreach(list_node, table->hash_table[index]) {
1856 node_ptr = (HASH_NODE*)list_node->ptr;
1857 /* if we found the same */
1858 if (!strcmp(key, node_ptr->key)) {
1859 node_to_kill = list_node;
1860 break;
1861 }
1862 }
1863 if (node_to_kill) {
1864 node_ptr = remove_list_node(table->hash_table[index], node_to_kill, HASH_NODE);
1865 _ht_node_destroy(node_ptr);
1866
1867 table->nb_keys--;
1868
1869 return TRUE;
1870 }
1871 n_log(LOG_ERR, "Can't delete key[\"%s\"]: inexisting key", key);
1872 return FALSE;
1873} /* ht_remove() */
1874
1881 __n_assert(table, return FALSE);
1882
1883 HASH_VALUE index = 0;
1884 for (index = 0; index < table->size; index++) {
1885 while (table->hash_table[index] && table->hash_table[index]->start) {
1886 HASH_NODE* hash_node = remove_list_node(table->hash_table[index], table->hash_table[index]->start, HASH_NODE);
1887 _ht_node_destroy(hash_node);
1888 }
1889 }
1890 table->nb_keys = 0;
1891 return TRUE;
1892} /* empty_ht */
1893
1900 __n_assert(table && (*table), n_log(LOG_ERR, "Can't destroy table: already NULL"); return FALSE);
1901
1902 if ((*table)->hash_table) {
1903 // empty_ht( (*table) );
1904
1905 HASH_VALUE it = 0;
1906 for (it = 0; it < (*table)->size; it++) {
1907 if ((*table)->hash_table[it])
1908 list_destroy(&(*table)->hash_table[it]);
1909 }
1910 Free((*table)->hash_table);
1911 }
1912 Free((*table));
1913 return TRUE;
1914} /* _destroy_ht */
1915
1920void _ht_print(HASH_TABLE* table) {
1921 __n_assert(table, return);
1922 __n_assert(table->hash_table, return);
1923 // cppcheck-suppress constVariablePointer ; node is generated by ht_foreach macro
1924 ht_foreach(node, table) {
1925 const HASH_NODE* ht_node = (const HASH_NODE*)node->ptr;
1926 printf("key:%s node:%s\n", ht_node->key, ht_node->key);
1927 }
1928
1929 return;
1930} /* _ht_print(...) */
1931
1938LIST* _ht_search(HASH_TABLE* table, int (*node_is_matching)(HASH_NODE* node)) {
1939 __n_assert(table, return NULL);
1940
1942 __n_assert(results, return NULL);
1943
1944 ht_foreach(node, table) {
1945 HASH_NODE* hnode = (HASH_NODE*)node->ptr;
1946 if (node_is_matching(hnode) == TRUE) {
1947 list_push(results, strdup(hnode->key), &free);
1948 }
1949 }
1950
1951 if (results->nb_items < 1)
1952 list_destroy(&results);
1953
1954 return results;
1955} /* _ht_search(...) */
1956
1957/* Hash tables function pointers and common table type functions */
1958
1965HASH_TABLE* new_ht_trie(size_t alphabet_length, size_t alphabet_offset) {
1966 HASH_TABLE* table = NULL;
1967
1968 Malloc(table, HASH_TABLE, 1);
1969 __n_assert(table, n_log(LOG_ERR, "Error allocating HASH_TABLE *table"); return NULL);
1970
1971 table->size = 0;
1972 table->seed = 0;
1973 table->nb_keys = 0;
1974 errno = 0;
1975 table->hash_table = NULL;
1976
1986 table->ht_remove = _ht_remove_trie;
1987 table->ht_search = _ht_search_trie;
1988 table->empty_ht = _empty_ht_trie;
1990 table->ht_print = _ht_print_trie;
1991
1992 table->alphabet_length = alphabet_length;
1993 table->alphabet_offset = alphabet_offset;
1994
1995 table->root = _ht_new_node_trie(table, '\0');
1996 if (!table->root) {
1997 n_log(LOG_ERR, "Couldn't allocate new_ht_trie with alphabet_length of %zu and alphabet offset of %zu", alphabet_length, alphabet_offset);
1998 Free(table);
1999 return NULL;
2000 }
2001 table->mode = HASH_TRIE;
2002
2003 return table;
2004} /* new_ht_trie */
2005
2011HASH_TABLE* new_ht(size_t size) {
2012 HASH_TABLE* table = NULL;
2013
2014 if (size < 1) {
2015 n_log(LOG_ERR, "Invalid size %zu for new_ht()", size);
2016 return NULL;
2017 }
2018 Malloc(table, HASH_TABLE, 1);
2019 __n_assert(table, n_log(LOG_ERR, "Error allocating HASH_TABLE *table"); return NULL);
2020
2021 table->size = size;
2022 table->seed = (uint32_t)rand() % 100000;
2023 table->nb_keys = 0;
2024 errno = 0;
2025 Malloc(table->hash_table, LIST*, size);
2026 // table -> hash_table = (LIST **)calloc( size, sizeof( LIST *) );
2027 __n_assert(table->hash_table, n_log(LOG_ERR, "Can't allocate table -> hash_table with size %zu !", size); Free(table); return NULL);
2028
2029 size_t it = 0;
2030 for (it = 0; it < size; it++) {
2032 // if no valid table then unroll previsouly created slots
2033 if (!table->hash_table[it]) {
2034 n_log(LOG_ERR, "Can't allocate table -> hash_table[ %d ] !", it);
2035 size_t it_delete = 0;
2036 for (it_delete = 0; it_delete < it; it_delete++) {
2037 list_destroy(&table->hash_table[it_delete]);
2038 }
2039 Free(table->hash_table);
2040 Free(table);
2041 return NULL;
2042 }
2043 }
2044 table->mode = HASH_CLASSIC;
2045
2046 table->ht_put_int = _ht_put_int;
2048 table->ht_put_ptr = _ht_put_ptr;
2051 table->ht_get_int = _ht_get_int;
2054 table->ht_get_ptr = _ht_get_ptr;
2055 table->ht_get_node = _ht_get_node;
2056 table->ht_remove = _ht_remove;
2057 table->ht_search = _ht_search;
2058 table->empty_ht = _empty_ht;
2059 table->destroy_ht = _destroy_ht;
2060 table->ht_print = _ht_print;
2061
2062 return table;
2063} /* new_ht(...) */
2064
2071HASH_NODE* ht_get_node(HASH_TABLE* table, const char* key) {
2072 __n_assert(table, return NULL);
2073 __n_assert(key, return NULL);
2074 return table->ht_get_node(table, key);
2075} /*ht_get_node(...) */
2076
2084int ht_get_double(HASH_TABLE* table, const char* key, double* val) {
2085 __n_assert(table, return FALSE);
2086 __n_assert(key, return FALSE);
2087 return table->ht_get_double(table, key, val);
2088} /* ht_get_double(...) */
2089
2097int ht_get_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE* val) {
2098 __n_assert(table, return FALSE);
2099 __n_assert(key, return FALSE);
2100 return table->ht_get_int(table, key, val);
2101} /* ht_get_int(...) */
2102
2110int ht_get_ptr(HASH_TABLE* table, const char* key, void** val) {
2111 __n_assert(table, return FALSE);
2112 __n_assert(key, return FALSE);
2113 return table->ht_get_ptr(table, key, val);
2114} /* ht_get_ptr(...) */
2115
2123int ht_get_string(HASH_TABLE* table, const char* key, char** val) {
2124 __n_assert(table, return FALSE);
2125 __n_assert(key, return FALSE);
2126 return table->ht_get_string(table, key, val);
2127} /* ht_get_string(...) */
2128
2136int ht_put_double(HASH_TABLE* table, const char* key, double value) {
2137 __n_assert(table, return FALSE);
2138 __n_assert(key, return FALSE);
2139 return table->ht_put_double(table, key, value);
2140} /* ht_put_double(...) */
2141
2149int ht_put_int(HASH_TABLE* table, const char* key, HASH_INT_TYPE value) {
2150 __n_assert(table, return FALSE);
2151 __n_assert(key, return FALSE);
2152 return table->ht_put_int(table, key, value);
2153} /* ht_put_int(...) */
2154
2164int ht_put_ptr(HASH_TABLE* table, const char* key, void* ptr, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
2165 __n_assert(table, return FALSE);
2166 __n_assert(key, return FALSE);
2167 return table->ht_put_ptr(table, key, ptr, destructor, duplicator);
2168} /* ht_put_ptr(...) */
2169
2177int ht_put_string(HASH_TABLE* table, const char* key, char* string) {
2178 __n_assert(table, return FALSE);
2179 __n_assert(key, return FALSE);
2180 return table->ht_put_string(table, key, string);
2181} /* ht_put_string(...) */
2182
2190int ht_put_string_ptr(HASH_TABLE* table, const char* key, char* string) {
2191 __n_assert(table, return FALSE);
2192 __n_assert(key, return FALSE);
2193 return table->ht_put_string_ptr(table, key, string);
2194} /* ht_put_string_ptr(...) */
2195
2202int ht_remove(HASH_TABLE* table, const char* key) {
2203 __n_assert(table, return FALSE);
2204 __n_assert(key, return FALSE);
2205 return table->ht_remove(table, key);
2206} /* ht_remove(...) */
2207
2212void ht_print(HASH_TABLE* table) {
2213 __n_assert(table, return);
2214 table->ht_print(table);
2215 return;
2216} /* ht_print(...) */
2217
2224LIST* ht_search(HASH_TABLE* table, int (*node_is_matching)(HASH_NODE* node)) {
2225 __n_assert(table, return NULL);
2226 return table->ht_search(table, node_is_matching);
2227} /* ht_search(...) */
2228
2235 __n_assert(table, return FALSE);
2236 return table->empty_ht(table);
2237} /* empty_ht(...) */
2238
2245 __n_assert((*table), return FALSE);
2246 return (*table)->destroy_ht(table);
2247} /* destroy_ht(...) */
2248
2256 __n_assert(table, return NULL);
2257 __n_assert(table->mode == HASH_CLASSIC, return NULL);
2258
2259 size_t index = (hash_value) % (table->size);
2260 if (!table->hash_table[index]->start) {
2261 return NULL;
2262 }
2263
2264 list_foreach(list_node, table->hash_table[index]) {
2265 HASH_NODE* node_ptr = (HASH_NODE*)list_node->ptr;
2266 if (hash_value == node_ptr->hash_value) {
2267 return node_ptr;
2268 }
2269 }
2270 return NULL;
2271} /* ht_get_node_ex() */
2272
2280int ht_get_ptr_ex(HASH_TABLE* table, HASH_VALUE hash_value, void** val) {
2281 __n_assert(table, return FALSE);
2282 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2283
2284 HASH_NODE* node = ht_get_node_ex(table, hash_value);
2285 if (!node)
2286 return FALSE;
2287
2288 if (node->type != HASH_PTR) {
2289 n_log(LOG_ERR, "Can't get key[\"%zu\"] of type HASH_PTR, key is type %s", hash_value, ht_node_type(node));
2290 return FALSE;
2291 }
2292
2293 (*val) = node->data.ptr;
2294
2295 return TRUE;
2296} /* ht_get_ptr_ex() */
2297
2307int ht_put_ptr_ex(HASH_TABLE* table, HASH_VALUE hash_value, void* val, void (*destructor)(void* ptr), void* (*duplicator)(void* ptr)) {
2308 __n_assert(table, return FALSE);
2309 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2310
2311 size_t index = 0;
2312 HASH_NODE* new_hash_node = NULL;
2313 HASH_NODE* node_ptr = NULL;
2314
2315 index = (hash_value) % (table->size);
2316
2317 /* we have some nodes here. Let's check if the key already exists */
2318 list_foreach(list_node, table->hash_table[index]) {
2319 node_ptr = (HASH_NODE*)list_node->ptr;
2320 /* if we found the same key we just replace the value and return */
2321 if (hash_value == node_ptr->hash_value) {
2322 /* let's check the key isn't already assigned with another data type */
2323 if (node_ptr->type == HASH_PTR) {
2324 if (node_ptr->destroy_func && node_ptr->data.ptr) {
2325 node_ptr->destroy_func(node_ptr->data.ptr);
2326 } else if (!node_ptr->destroy_func && node_ptr->data.ptr) {
2327 n_log(LOG_ERR, "Can't free previous key[\"%s\"] with type HASH_PTR , no hash node destroy func", node_ptr->key);
2328 }
2329 node_ptr->destroy_func = destructor;
2330 node_ptr->duplicate_func = duplicator;
2331 node_ptr->data.ptr = val;
2332 return TRUE;
2333 }
2334 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));
2335 return FALSE; /* key registered with another data type */
2336 }
2337 }
2338
2339 Malloc(new_hash_node, HASH_NODE, 1);
2340 __n_assert(new_hash_node, n_log(LOG_ERR, "Could not allocate new_hash_node"); return FALSE);
2341
2342 new_hash_node->key = NULL;
2343 new_hash_node->hash_value = hash_value;
2344 new_hash_node->data.ptr = val;
2345 new_hash_node->type = HASH_PTR;
2346 new_hash_node->destroy_func = destructor;
2347 new_hash_node->duplicate_func = duplicator;
2348
2349 table->nb_keys++;
2350
2351 return list_push(table->hash_table[index], new_hash_node, &_ht_node_destroy);
2352} /* ht_put_ptr_ex() */
2353
2360int ht_remove_ex(HASH_TABLE* table, HASH_VALUE hash_value) {
2361 __n_assert(table, return FALSE);
2362 __n_assert(table->mode == HASH_CLASSIC, return FALSE);
2363
2364 size_t index = 0;
2365 HASH_NODE* node_ptr = NULL;
2366 LIST_NODE* node_to_kill = NULL;
2367
2368 index = (hash_value) % (table->size);
2369 if (!table->hash_table[index]->start) {
2370 n_log(LOG_ERR, "Can't remove key[\"%zu\"], table is empty", hash_value);
2371 return FALSE;
2372 }
2373
2374 list_foreach(list_node, table->hash_table[index]) {
2375 node_ptr = (HASH_NODE*)list_node->ptr;
2376 /* if we found the same */
2377 if (hash_value == node_ptr->hash_value) {
2378 node_to_kill = list_node;
2379 break;
2380 }
2381 }
2382 if (node_to_kill) {
2383 node_ptr = remove_list_node(table->hash_table[index], node_to_kill, HASH_NODE);
2384 _ht_node_destroy(node_ptr);
2385
2386 table->nb_keys--;
2387
2388 return TRUE;
2389 }
2390 n_log(LOG_ERR, "Can't delete key[\"%zu\"]: inexisting key", hash_value);
2391 return FALSE;
2392} /* ht_remove_ex() */
2393
2401LIST* ht_get_completion_list(HASH_TABLE* table, const char* keybud, size_t max_results) {
2402 __n_assert(table, return NULL);
2403 __n_assert(keybud, return NULL);
2404
2405 LIST* results = new_generic_list(max_results);
2406 if (table->mode == HASH_TRIE) {
2407 HASH_NODE* node = _ht_get_node_trie(table, keybud);
2408 if (node) {
2409 if (list_push(results, strdup(keybud), &free) == TRUE) {
2410 _ht_depth_first_search(node, results);
2411 }
2412 } else {
2413 node = table->root;
2414 for (size_t it = 0; it < table->alphabet_length; it++) {
2415 if (node->children[it]) {
2416 char new_keybud[3] = "";
2417 new_keybud[0] = (char)(it + table->alphabet_offset);
2418 list_push(results, strdup(new_keybud), &free);
2419 }
2420 }
2421 }
2422 } else if (table->mode == HASH_CLASSIC) {
2423 ht_foreach(node, table) {
2424 HASH_NODE* hnode = (HASH_NODE*)node->ptr;
2425 if (strncasecmp(keybud, hnode->key, strlen(keybud)) == 0) {
2426 char* key = strdup(hnode->key);
2427 if (list_push(results, key, &free) == FALSE) {
2428 n_log(LOG_ERR, "not enough space in list or memory error, key %s not pushed !", key);
2429 Free(key);
2430 }
2431 }
2432 }
2433 } else {
2434 n_log(LOG_ERR, "unsupported mode %d", table->mode);
2435 list_destroy(&results);
2436 return NULL;
2437 }
2438 if (results && results->nb_items < 1)
2439 list_destroy(&results);
2440 return results;
2441} /* ht_get_completion_list(...) */
2442
2448int is_prime(size_t nb) {
2449 /* quick test for first primes */
2450 if (nb <= 1) return FALSE;
2451 if (nb <= 3) return TRUE;
2452
2453 /* skip middle five numbers in below loop */
2454 if ((nb % 2 == 0) || (nb % 3 == 0))
2455 return FALSE;
2456
2457 /* looping */
2458 for (size_t it = 5; it * it <= nb; it = it + 6) {
2459 if ((nb % it == 0) || (nb % (it + 2) == 0))
2460 return FALSE;
2461 }
2462 return TRUE;
2463} /* is_prime() */
2464
2470size_t next_prime(size_t nb) {
2471 if (nb <= 1)
2472 return 2;
2473
2474 size_t next_prime = nb;
2475 do {
2476 next_prime++;
2477 } while (is_prime(next_prime) == FALSE);
2478
2479 return next_prime;
2480} /* next_prime() */
2481
2488 __n_assert(table, return FALSE);
2489 if (table->mode != HASH_CLASSIC) {
2490 n_log(LOG_ERR, "unsupported table->mode (%d instead or %d)", table->mode, HASH_CLASSIC);
2491 return FALSE;
2492 }
2493 if (table->size == 0) return FALSE;
2494
2495 size_t nb_collisionned_lists = 0;
2496
2497 for (size_t hash_it = 0; hash_it < table->size; hash_it++) {
2498 if (table->hash_table[hash_it] && table->hash_table[hash_it]->nb_items > 1) {
2499 nb_collisionned_lists++;
2500 }
2501 }
2502 size_t collision_percentage = (100 * nb_collisionned_lists) / table->size;
2503 return (int)collision_percentage;
2504} /* ht_get_table_collision_percentage() */
2505
2512 __n_assert(table, return 0);
2513 if (table->mode != HASH_CLASSIC) {
2514 n_log(LOG_ERR, "unsupported table->mode (%d instead or %d)", table->mode, HASH_CLASSIC);
2515 return FALSE;
2516 }
2517
2518 size_t optimum_size = (size_t)((double)table->nb_keys * 1.3);
2519 if (is_prime(optimum_size) != TRUE)
2520 optimum_size = next_prime(optimum_size);
2521 return optimum_size;
2522} /* ht_get_optimal_size() */
2523
2530int ht_resize(HASH_TABLE** table, size_t size) {
2531 __n_assert((*table), return FALSE);
2532 if ((*table)->mode != HASH_CLASSIC) {
2533 n_log(LOG_ERR, "unsupported table->mode (%d instead or %d)", (*table)->mode, HASH_CLASSIC);
2534 return FALSE;
2535 }
2536 if (size < 1) {
2537 n_log(LOG_ERR, "invalid size %zu for hash table %p", size, (void*)(*table));
2538 return FALSE;
2539 }
2540 /* mark every existing entry for rehash before resizing.
2541 * Using ht_foreach (plain for-loop macro) instead of HT_FOREACH
2542 * because the body needs no break/continue, and HT_FOREACH's
2543 * GCC nested-function expansion is rejected by clang's parser. */
2544 ht_foreach(it_node, (*table)) {
2545 HASH_NODE* node = (HASH_NODE*)it_node->ptr;
2546 node->need_rehash = 1;
2547 }
2548
2549 if (size > (*table)->size) {
2550 if (Realloc((*table)->hash_table, LIST*, size) == FALSE) {
2551 return FALSE;
2552 }
2553 for (size_t it = (*table)->size; it < size; it++) {
2554 (*table)->hash_table[it] = new_generic_list(MAX_LIST_ITEMS);
2555 if (!(*table)->hash_table[it]) {
2556 n_log(LOG_ERR, "Can't allocate table -> hash_table[ %zu ] !", it);
2557 /* destroy newly added slots and shrink back */
2558 for (size_t it_delete = (*table)->size; it_delete < it; it_delete++) {
2559 list_destroy(&(*table)->hash_table[it_delete]);
2560 }
2561 /* best-effort rollback: shrink back to original size.
2562 Realloc preserves the pointer on failure, which is fine here. */
2563 Realloc((*table)->hash_table, LIST*, (*table)->size);
2564 return FALSE;
2565 }
2566 }
2567 /* rehash all marked nodes into their new positions */
2568 for (size_t it = 0; it < 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 } else {
2583 /* rehash nodes that need it into the smaller index space */
2584 for (size_t it = 0; it < (*table)->size; it++) {
2585 if ((*table)->hash_table[it]) {
2586 while ((*table)->hash_table[it]->start) {
2587 HASH_NODE* hash_node = (HASH_NODE*)(*table)->hash_table[it]->start->ptr;
2588 if (hash_node->need_rehash == 0)
2589 break;
2590 hash_node->need_rehash = 0;
2591 LIST_NODE* node = list_node_shift((*table)->hash_table[it]);
2592 node->next = node->prev = NULL;
2593 size_t index = (hash_node->hash_value) % (size);
2594 list_node_push((*table)->hash_table[index], node);
2595 }
2596 }
2597 }
2598 /* destroy trailing slots that are now unused */
2599 for (size_t it = size; it < (*table)->size; it++) {
2600 list_destroy(&(*table)->hash_table[it]);
2601 }
2602 /* shrink the backing array; Realloc preserves the pointer on failure.
2603 Trailing slots have already been list_destroy'd so they are NULL.
2604 (*table)->size is updated below regardless, keeping the table
2605 consistent even if the allocator cannot shrink in-place. */
2606 Realloc((*table)->hash_table, LIST*, size);
2607 }
2608 (*table)->size = size;
2609
2610 return TRUE;
2611} /* ht_resize() */
2612
2619 __n_assert((*table), return FALSE);
2620 if ((*table)->mode != HASH_CLASSIC) {
2621 n_log(LOG_ERR, "unsupported table->mode (%d instead or %d)", (*table)->mode, HASH_CLASSIC);
2622 return FALSE;
2623 }
2624
2625 size_t optimal_size = ht_get_optimal_size((*table));
2626 if (optimal_size == FALSE) {
2627 return FALSE;
2628 }
2629
2630 int collision_percentage = ht_get_table_collision_percentage((*table));
2631 if (collision_percentage == FALSE)
2632 return FALSE;
2633
2634 int resize_result = ht_resize(table, optimal_size);
2635 if (resize_result == FALSE) {
2636 return FALSE;
2637 }
2638
2639 collision_percentage = ht_get_table_collision_percentage((*table));
2640 if (collision_percentage == FALSE) {
2641 return FALSE;
2642 }
2643
2644 return TRUE;
2645} /* ht_optimize() */
2646
2653 __n_assert(table, return NULL);
2654 HASH_TABLE* duplicated_table = NULL;
2655
2656 if (table->mode != HASH_CLASSIC) {
2657 n_log(LOG_ERR, "unsupported mode %d for table %p", table->mode, table);
2658 return NULL;
2659 }
2660
2661 duplicated_table = new_ht(table->size);
2662 if (!duplicated_table) {
2663 n_log(LOG_ERR, "couldn't allocate duplicated table of %zu elements", table->size);
2664 return NULL;
2665 }
2666
2667 ht_foreach(node, table) {
2668 HASH_NODE* hash_node = (HASH_NODE*)node->ptr;
2669 int has_succeeded = TRUE;
2670 switch (hash_node->type) {
2671 case HASH_INT:
2672 has_succeeded = ht_put_int(duplicated_table, hash_node->key, hash_node->data.ival);
2673 break;
2674 case HASH_DOUBLE:
2675 has_succeeded = ht_put_double(duplicated_table, hash_node->key, hash_node->data.fval);
2676 break;
2677 case HASH_PTR: {
2678 if (hash_node->duplicate_func && hash_node->data.ptr) {
2679 /* deep copy: new entry takes ownership with the same funcs */
2680 void* duplicated_ptr = hash_node->duplicate_func(hash_node->data.ptr);
2681 if (!duplicated_ptr) {
2682 n_log(LOG_ERR, "duplicate_func returned NULL for key [%s]", hash_node->key);
2683 has_succeeded = FALSE;
2684 break;
2685 }
2686 has_succeeded = ht_put_ptr(duplicated_table, hash_node->key, duplicated_ptr, hash_node->destroy_func, hash_node->duplicate_func);
2687 } else {
2688 /* shallow copy: pass NULL destroy/duplicate so the duplicate table
2689 does not take ownership; only the source table will free the pointer */
2690 has_succeeded = ht_put_ptr(duplicated_table, hash_node->key, hash_node->data.ptr, NULL, NULL);
2691 }
2692 } break;
2693 case HASH_STRING:
2694 has_succeeded = ht_put_string(duplicated_table, hash_node->key, hash_node->data.string);
2695 break;
2696 default:
2697 n_log(LOG_ERR, "unknown node type %d for key [%s], skipping", hash_node->type, hash_node->key);
2698 break;
2699 }
2700
2701 if (has_succeeded == FALSE) {
2702 n_log(LOG_ERR, "problem when trying to duplicate value in %p, duplication cancelled", table);
2703 destroy_ht(&duplicated_table);
2704 return NULL;
2705 }
2706 }
2707
2708 return duplicated_table;
2709}
static size_t max_results
char * key
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:272
#define FALL_THROUGH
set windows if true
Definition n_common.h:72
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:204
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:279
#define FORCE_INLINE
FORCE_INLINE portable macro.
Definition n_common.h:164
#define Realloc(__ptr, __struct, __size)
Realloc Handler to get errors.
Definition n_common.h:231
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:263
int(* ht_put_int)(struct HASH_TABLE *table, const char *key, int64_t val)
put an integer
Definition n_hash.h:158
size_t alphabet_length
HASH_TRIE mode: size of alphabet and so size of children allocated array.
Definition n_hash.h:134
int need_rehash
flag to mark a node for rehash
Definition n_hash.h:130
HASH_NODE *(* ht_get_node)(struct HASH_TABLE *table, const char *key)
get HASH_NODE at 'key' from table
Definition n_hash.h:156
char key_id
key id of the node if any
Definition n_hash.h:116
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:174
int(* ht_put_string)(struct HASH_TABLE *table, const char *key, char *val)
put an char *string
Definition n_hash.h:164
char * key
string key of the node if any, else NULL
Definition n_hash.h:114
int64_t ival
integral type
Definition n_hash.h:102
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:162
int is_leaf
HASH_TRIE mode: does it have a value.
Definition n_hash.h:128
HASH_NODE * root
HASH_TRIE mode: Start of tree.
Definition n_hash.h:148
void * ptr
pointer type
Definition n_hash.h:106
union HASH_DATA data
data inside the node
Definition n_hash.h:122
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:172
int type
type of the node
Definition n_hash.h:120
int(* empty_ht)(struct HASH_TABLE *table)
empty a hash table.
Definition n_hash.h:180
LIST ** hash_table
HASH_CLASSIC mode: preallocated hash table.
Definition n_hash.h:146
size_t alphabet_offset
HASH_TRIE mode: offset to deduce to individual key digits.
Definition n_hash.h:152
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:170
size_t alphabet_length
HASH_TRIE mode: size of the alphabet.
Definition n_hash.h:150
void *(* duplicate_func)(void *ptr)
duplicator_func
Definition n_hash.h:126
unsigned int mode
hashing mode, murmurhash and classic HASH_MURMUR, or HASH_TRIE
Definition n_hash.h:154
size_t seed
table's seed
Definition n_hash.h:144
int(* destroy_ht)(struct HASH_TABLE **table)
destroy a hash table
Definition n_hash.h:182
int(* ht_put_string_ptr)(struct HASH_TABLE *table, const char *key, char *val)
put an char *string pointer
Definition n_hash.h:166
int(* ht_remove)(struct HASH_TABLE *table, const char *key)
remove given's key node from the table
Definition n_hash.h:176
void(* ht_print)(struct HASH_TABLE *table)
print table
Definition n_hash.h:184
char * string
char *type
Definition n_hash.h:108
int(* ht_put_double)(struct HASH_TABLE *table, const char *key, double val)
put a double
Definition n_hash.h:160
struct HASH_NODE ** children
HASH_TRIE mode: pointers to children.
Definition n_hash.h:132
HASH_VALUE hash_value
numeric key of the node if any, else < 0
Definition n_hash.h:118
double fval
double type
Definition n_hash.h:104
size_t size
size of the hash table
Definition n_hash.h:140
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:168
size_t nb_keys
total number of used keys in the table
Definition n_hash.h:142
LIST *(* ht_search)(struct HASH_TABLE *table, int(*node_is_matching)(HASH_NODE *node))
search elements given an expression
Definition n_hash.h:178
void(* destroy_func)(void *ptr)
destroy_func
Definition n_hash.h:124
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition n_hash.c:2110
#define ht_foreach(__ITEM_, __HASH_)
ForEach macro helper (classic / old)
Definition n_hash.h:192
LIST * ht_search(HASH_TABLE *table, int(*node_is_matching)(HASH_NODE *node))
seach table for matching nodes
Definition n_hash.c:2224
HASH_TABLE * ht_duplicate(HASH_TABLE *table)
duplicate a hash table (all pointers should have a duplicator func set)
Definition n_hash.c:2652
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition n_hash.c:2244
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:2307
int ht_remove(HASH_TABLE *table, const char *key)
remove and delete node at key in table
Definition n_hash.c:2202
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:2255
#define HASH_PTR
value of pointer type inside the hash node
Definition n_hash.h:76
HASH_TABLE * new_ht(size_t size)
Create a hash table with the given size.
Definition n_hash.c:2011
#define MurmurHash(__key, __len, __seed, __out)
Murmur hash macro helper 64 bits.
Definition n_hash.h:91
int ht_get_table_collision_percentage(HASH_TABLE *table)
get table collision percentage (HASH_CLASSIC mode only)
Definition n_hash.c:2487
int ht_get_double(HASH_TABLE *table, const char *key, double *val)
get double at 'key' from 'table'
Definition n_hash.c:2084
#define HASH_DOUBLE
value of double type inside the hash node
Definition n_hash.h:72
int empty_ht(HASH_TABLE *table)
empty a table
Definition n_hash.c:2234
#define HASH_STRING
value of char * type inside the hash node
Definition n_hash.h:74
void ht_print(HASH_TABLE *table)
print contents of table
Definition n_hash.c:2212
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:2401
size_t HASH_VALUE
type of a HASH_VALUE
Definition n_hash.h:97
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:2136
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:2511
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:2164
int ht_get_string(HASH_TABLE *table, const char *key, char **val)
get string at 'key' from 'table'
Definition n_hash.c:2123
int is_prime(size_t nb)
test if number is a prime number or not
Definition n_hash.c:2448
#define HASH_INT_TYPE
type of a HASH_INT in 64 bits
Definition n_hash.h:93
size_t next_prime(size_t nb)
compute next prime number after nb
Definition n_hash.c:2470
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:2177
int ht_resize(HASH_TABLE **table, size_t size)
rehash table according to size (HASH_CLASSIC mode only)
Definition n_hash.c:2530
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:1036
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:1204
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:2360
#define HASH_CLASSIC
Murmur hash using hash key string, hash key numeric value, index table with lists of elements.
Definition n_hash.h:80
int ht_get_int(HASH_TABLE *table, const char *key, int64_t *val)
get node at 'key' from 'table'
Definition n_hash.c:2097
HASH_NODE * ht_get_node(HASH_TABLE *table, const char *key)
get node at 'key' from 'table'
Definition n_hash.c:2071
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:1965
#define HASH_TRIE
TRIE tree using hash key string.
Definition n_hash.h:82
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:2149
int ht_optimize(HASH_TABLE **table)
try an automatic optimization of the table (HASH_CLASSIC mode only)
Definition n_hash.c:2618
char * ht_node_type(const HASH_NODE *node)
get the type of a node , text version
Definition n_hash.c:1326
#define HASH_INT
compatibility with existing rot func
Definition n_hash.h:70
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:978
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:2190
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:2280
structure of a hash table node
Definition n_hash.h:112
structure of a hash table
Definition n_hash.h:138
size_t nb_max_items
Maximum number of items in the list.
Definition n_list.h:63
struct LIST_NODE * prev
pointer to the previous node
Definition n_list.h:54
LIST_NODE * start
pointer to the start of the list
Definition n_list.h:66
size_t nb_items
number of item currently in the list
Definition n_list.h:61
struct LIST_NODE * next
pointer to the next node
Definition n_list.h:52
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:228
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper, safe for node removal during iteration.
Definition n_list.h:89
#define remove_list_node(__LIST_, __NODE_, __TYPE_)
Remove macro helper for void pointer casting.
Definition n_list.h:98
LIST_NODE * list_node_shift(LIST *list)
Get a LIST_NODE pointer from the start of the list.
Definition n_list.c:170
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:548
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:37
#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:75
int list_node_push(LIST *list, LIST_NODE *node)
Add a filled node to the end of the list.
Definition n_list.c:117
Structure of a generic LIST container.
Definition n_list.h:59
Structure of a generic list node.
Definition n_list.h:44
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_DEBUG
debug-level messages
Definition n_log.h:84
#define LOG_ERR
error conditions
Definition n_log.h:76
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:1380
void _ht_node_destroy(void *node)
destroy a HASH_NODE by first calling the HASH_NODE destructor
Definition n_hash.c:109
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:1603
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:1725
int _destroy_ht(HASH_TABLE **table)
Free and set the table to NULL.
Definition n_hash.c:1899
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:1753
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:613
HASH_NODE * _ht_new_double_node(HASH_TABLE *table, const char *key, double value)
node creation, HASH_CLASSIC mode
Definition n_hash.c:1438
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:1567
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:1485
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:397
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:917
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:1782
HASH_NODE * _ht_new_node_trie(HASH_TABLE *table, const char key)
node creation, HASH_CLASSIC mode
Definition n_hash.c:51
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:845
HASH_NODE * _ht_new_int_node(HASH_TABLE *table, const char *key, int64_t value)
node creation, HASH_CLASSIC mode
Definition n_hash.c:1416
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:940
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:1509
void _ht_print_trie(HASH_TABLE *table)
Generic print func call for trie trees.
Definition n_hash.c:788
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:669
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:287
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:521
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:754
HASH_NODE * _ht_get_node_trie(HASH_TABLE *table, const char *key)
retrieve a HASH_NODE at key from table
Definition n_hash.c:580
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:1645
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:1460
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:464
void _ht_print(HASH_TABLE *table)
Generic print func call for classic hash tables.
Definition n_hash.c:1920
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:188
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:697
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:1809
int _empty_ht(HASH_TABLE *table)
Empty a hash table (CLASSIC mode)
Definition n_hash.c:1880
#define BIG_CONSTANT(x)
max unsigned long long
Definition n_hash.c:869
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:85
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:1689
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:825
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:144
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:342
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:1349
#define BYTESWAP64(x)
32 bits bytes swap
Definition n_hash.c:900
#define BYTESWAP32(x)
32 bits bytes swap
Definition n_hash.c:896
int _destroy_ht_trie(HASH_TABLE **table)
Free and set the table to NULL (TRIE mode)
Definition n_hash.c:739
int _empty_ht_trie(HASH_TABLE *table)
Empty a TRIE hash table.
Definition n_hash.c:723
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:641
int _ht_remove(HASH_TABLE *table, const char *key)
Remove a key from a hash table.
Definition n_hash.c:1835
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:929
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:1533
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:220
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:1938
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:805
#define ROTL64(x, r)
64 bit rotate left
Definition n_hash.c:865
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:955
#define ROTL32(x, r)
32 bit rotate left
Definition n_hash.c:867
Hash functions and table.
Generic log system.
N_STR and string function declaration.