tuyau

Client/server for transfering files (like cp)
git clone https://noulin.net/git/tuyau.git
Log | Files | Refs | README

hashtable.h (49706B)


      1 #pragma once
      2 
      3 /**
      4  * \file
      5  *
      6  * Chained hash table
      7  *
      8  * NOTE: The macros in this file are for creating hash table functions wrapping the macros.
      9  *       I don't advise using these directly because of the risk of memory leaks and
     10  *       wrong computations.
     11  *       The leaks and wrong computations happen because the parameters to the macros
     12  *       are evaluated multiple times.
     13  *       Example:
     14  *       hashTbAdd(ahashtable, strdup("akey"), value) causes a leak because strdup is
     15  *       evaluted twice.
     16  *
     17  * NOTE: This package doesn't provide the hash functions, install the hashfunctions package to
     18  *       get some hash functions.
     19  *
     20  * This hash table has 2 single linked lists in each bucket,
     21  * the performance is still good with a load factor of 2.
     22  *
     23  * The maximum number of buckets is 2^32 and and the maximum number (key, value) nodes 2^32 ( > 40 GB RAM)
     24  *
     25  * The size (bucket count) increases in power of 2.
     26  *
     27  * The status of the macros is saved (hashtableVar).res and is set to true when the operation is success and
     28  * false when the operation is failure.
     29  *
     30  * Use hashmap when there are more than 50 elements in the dictionary
     31  *
     32  * Hash table memory usage (for key type char* and value type u32):
     33  * Empty hashmap size: 2744 bytes
     34  * Size depending on element count (with load factor 2): 184 + 42 * count
     35  *
     36  * It takes in average 4 times more memory than smallDict
     37  * hashmap = 4 * smallDict RAM
     38  *
     39  * Lookup time:
     40  * fnv hash get: 440ns (300 000 000 keys in hash table - kaby lake CPU)
     41  *
     42  * This hash table has better performance than smallDict with 50 elements
     43  *
     44  *
     45  * The types handled by the hash table (key, value and hash types)
     46  * are defined with hashTbT or hashNodeT and hashtableT.
     47  *
     48  * The hashTb* are short and convenient macros for the hashtable* macros.
     49  * With hashTb* macros there is no need to specify the hash, cmp and free functions.
     50  *
     51  * Before using the hashTb* macros, define HASHFUNC CMPFUNC and FREEFUNC.
     52  *
     53  * *Node Macros:
     54  * The *Node macros handle the nodes in hash table and save time by not running the hash function.
     55  * These macros are useful when the hash function is expensive (like siphash).
     56  *
     57  * The hash table has to be defined with hashNodeT and hashtableT to be able to use the *Node macros.
     58  * The *Node macros use the context type defined by hashNodeT, the context type is named:
     59  *
     60  *  context_typeName
     61  *
     62  * The key and value in the node is accessed with:
     63  * node.key
     64  * node.value
     65  *
     66  * HASHFUNC is a function with prototype:
     67  * hashType hashFunc(keyType key);
     68  *
     69  * CMPFUNC compares keys and is a function with prototype:
     70  * int compare(keyType k1, keyType k2);
     71  * Return 0 when the keys are equal, 1 otherwise
     72  *
     73  * FREEFUNC frees key and value is a function with prototype:
     74  * void freeKV(keyType* key, valueType* value);
     75  * NOTE: the free function gets a pointer to the key and value which is useful when iterating on the nodes
     76  *       (for example, when keyType is int, set key to -1, iterate on the aHashnode dArray and ignore the node
     77  *        when the key is -1)
     78  *
     79  * See the 'node macros' section below for details on usage scenarios of the *Node macros.
     80  *
     81  * Example:
     82  * hashTbT(hasht, char*, u32, u32);
     83  *
     84  * #define HASHFUNC strHashFNV1A
     85  * #define CMPFUNC  strcmp
     86  * #define FREEFUNC freeNode
     87  *
     88  * void freeNode(char **key, u32* UNUSED value) {
     89  *  //logI("free key %x\n", key);
     90  *  free(key);
     91  * }
     92  *
     93  * hasht h;
     94  * hashtableInit(h, 128, 2, 1);
     95  *
     96  * hashTbAdd(h, "a key", 12);
     97  *
     98  * u32 result = 0;
     99  * hashTbGet(h, "a key", result);
    100  *
    101  * hashTbDel(h, "a key");
    102  *
    103  * hashTbFree(h);
    104  */
    105 
    106 
    107 #include "libsheepyObject.h"
    108 
    109 /**
    110  * function declarations for tailored hash table
    111  *
    112  * - define hash table types
    113  * - declare prototypes
    114  *
    115  * this macro is placed most of the time in a header file
    116  *
    117  * the Hash table type is defined as:
    118  * 'typeName't
    119  *
    120  * the node in the hash table is defined as:
    121  * 'typeName'Nodet
    122  *
    123  * the node context is defined as:
    124  * context_'typeName'Nodet
    125  *
    126  * the function names are:
    127  * function'suffix'
    128  *
    129  * the scope parameter is the function scope and can be 'empty' for global functions, 'static' for local functions, ...
    130  *
    131  * the declared functions are:
    132  * init, empty, free, add, addOrFind, find, get, getKey, del, seed, addOrFindNode
    133  * setKeyNode, getNode, updateNodeContext, unlink, freeUnlinked, delNode
    134  *
    135  *
    136  * RETURN VALUES:
    137  * add, setKeyNode, updateNodeContext: true success, false failure
    138  * addOrFind, addOrFindNode:           non NULL success, NULL failure.
    139  *                                     *isnew is set to true when the returned value pointer is in a new node.
    140  * find, getNode, unlink:              non NULL success, NULL failure
    141  *
    142  * the ctx pointer parameters must be allocated before the function calls
    143  * the isnew pointer must point to an existing bool variable
    144  *
    145  *
    146  * Example:
    147  * hashTbDef(, m3232, M32, u32, u32, u32); // declare hash table type m3232t with u32 keys, u32 values and u32 hash
    148  *
    149  * m3232Nodet *node;
    150  * context_m3232Nodet ctx;
    151  * bool isnew;
    152  *
    153  * m3232t h; // declares a hash table
    154  *
    155  */
    156 #define hashTbDef(scope, typeName, suffix, keyType, valueType, hashType) \
    157   hashNodeT(typeName##Nodet, keyType, valueType, hashType);\
    158   hashtableT(typeName##t, typeName##Nodet);\
    159   scope void init##suffix(typeName##t *map);\
    160   scope void empty##suffix(typeName##t *map);\
    161   scope void free##suffix(typeName##t *map);\
    162   scope bool add##suffix(typeName##t *map, keyType key, valueType value);\
    163   scope valueType* addOrFind##suffix(typeName##t *map, keyType key, bool *isnew);\
    164   scope valueType* find##suffix(typeName##t *map, keyType key);\
    165   scope valueType get##suffix(typeName##t *map, keyType key);\
    166   scope keyType getKey##suffix(typeName##t *map, keyType key);\
    167   scope void del##suffix(typeName##t *map, keyType key);\
    168   scope u8* seed##suffix(typeName##t *map);\
    169   scope typeName##Nodet* addOrFindNode##suffix(typeName##t *map, keyType key, bool *isnew, context_##typeName##Nodet *ctx);\
    170   scope bool setKeyNode##suffix(typeName##t *map, context_##typeName##Nodet *ctx);\
    171   scope typeName##Nodet *getNode##suffix(typeName##t *map, keyType key, context_##typeName##Nodet *ctx);\
    172   scope bool updateNodeContext##suffix(typeName##t *map, context_##typeName##Nodet *ctx);\
    173   scope typeName##Nodet* unlink##suffix(typeName##t *map, keyType key);\
    174   scope void freeUnlinked##suffix(typeName##t *map, typeName##Nodet *node);\
    175   scope void delNode##suffix(typeName##t *map, context_##typeName##Nodet *ctx)
    176 
    177 /**
    178  * function implementations
    179  *
    180  * this macros implements the hash table functions:
    181  * init, empty, free, add, addOrFind, find, get, getKey, del, seed, addOrFindNode
    182  * setKeyNode, getNode, updateNodeContext, unlink, freeUnlinked, delNode
    183  *
    184  * this macro is placed most of the time in a source file
    185  *
    186  * the hash function, compare function and free function must be implemented before this macro
    187  * HASHFUNC, CMPFUNC and FREEFUNC must be defined  before this macro
    188  *
    189  * Example:
    190  * hashTbDef(, m3232, M32, u32, u32, u32); // declare hash table type m3232t with u32 keys, u32 values and u32 hash
    191  *
    192  * int cmp(u32 k1, u32 k2) {
    193  *   return k1 == k2 ? 0 : 1;
    194  * }
    195  *
    196  * void freeM(u32* k, u32* v) {
    197  * }
    198  *
    199  * #define HASHFUNC u32Hash // hash function from the hashfunctions spm package
    200  * #define CMPFUNC  cmp
    201  * #define FREEFUNC freeM
    202  *
    203  * hashTbFunctions(, m3232, M32, u32, u32); // implements global scope m3232t functions: *M32()
    204  *
    205  * #undef HASHFUNC
    206  * #undef CMPFUNC
    207  * #undef FREEFUNC
    208  *
    209  * m3232t h; // declares a hash table
    210  *
    211  * initM32(&h);
    212  * addM32(&h, 1, 1);
    213  *
    214  */
    215 #define hashTbFunctions(scope, typeName, suffix, keyType, valueType)\
    216   scope void init##suffix(typeName##t *map) {\
    217     hashTbInit(*map, 64, 2, 1);\
    218   }\
    219   scope void empty##suffix(typeName##t *map) {\
    220     hashTbEmpty(*map);\
    221   }\
    222   scope void free##suffix(typeName##t *map) {\
    223     hashTbFree(*map);\
    224   }\
    225   scope bool add##suffix(typeName##t *map, keyType key, valueType value) {\
    226     hashTbAdd(*map, key, value);\
    227     return map->res;\
    228   }\
    229   scope valueType* addOrFind##suffix(typeName##t *map, keyType key, bool *isnew) {\
    230     valueType* r = NULL;\
    231     hashTbAddOrFind(*map, key, r, *isnew);\
    232     return r;\
    233   }\
    234   scope valueType* find##suffix(typeName##t *map, keyType key) {\
    235     valueType *r = NULL;\
    236     hashTbFind(*map, key, r);\
    237     return r;\
    238   }\
    239   scope valueType get##suffix(typeName##t *map, keyType key) {\
    240     valueType r;\
    241     hashTbGet(*map, key, r);\
    242     return r;\
    243   }\
    244   scope keyType getKey##suffix(typeName##t *map, keyType key) {\
    245     keyType r;\
    246     hashTbGetKey(*map, key, r);\
    247     return r;\
    248   }\
    249   scope void del##suffix(typeName##t *map, keyType key) {\
    250     hashTbDel(*map, key);\
    251   }\
    252   scope u8* seed##suffix(typeName##t *map) {\
    253     u8 *r = hashTbSeed(*map);\
    254     return r;\
    255   }\
    256   scope typeName##Nodet* addOrFindNode##suffix(typeName##t *map, keyType key, bool *isnew, context_##typeName##Nodet *ctx) {\
    257     typeName##Nodet* r;\
    258     hashTbAddOrFindNode(*map, key, r, *ctx, *isnew);\
    259     return r;\
    260   }\
    261   scope bool setKeyNode##suffix(typeName##t *map, context_##typeName##Nodet *ctx) {\
    262     hashTbSetKeyNode(*map, *ctx);\
    263     return map->res;\
    264   }\
    265   scope typeName##Nodet *getNode##suffix(typeName##t *map, keyType key, context_##typeName##Nodet *ctx) {\
    266     typeName##Nodet *r = NULL;\
    267     hashTbGetNode(*map , key, r, *ctx);\
    268     return r;\
    269   }\
    270   scope bool updateNodeContext##suffix(typeName##t *map, context_##typeName##Nodet *ctx) {\
    271     hashTbUpdateNodeContext(*map, *ctx);\
    272     return map->res;\
    273   }\
    274   scope typeName##Nodet* unlink##suffix(typeName##t *map, keyType key) {\
    275     typeName##Nodet *r = NULL;\
    276     hashTbUnlinkNode(*map, key, r);\
    277     return r;\
    278   }\
    279   scope void freeUnlinked##suffix(typeName##t *map, typeName##Nodet *node) {\
    280     hashTbFreeUnlinkedNode(*map, node);\
    281   }\
    282   scope void delNode##suffix(typeName##t *map, context_##typeName##Nodet *ctx) {\
    283     hashTbDelNode(*map, *ctx);\
    284   }
    285 
    286 
    287 /** initialize hash table */
    288 #define hashTbInit(HT, SIZE, NUMERATOR, DENOMINATOR) hashtableInit(HT, SIZE, NUMERATOR, DENOMINATOR)
    289 
    290 /** remove all key,value pairs in hash table */
    291 #define hashTbEmpty(HT) hashtableEmpty(HT, FREEFUNC)
    292 
    293 /** free hash table */
    294 #define hashTbFree(HT) hashtableFree(HT, FREEFUNC)
    295 
    296 /** insert new (key,value), fail when the key already exists */
    297 #define hashTbAdd(HT, K, V) hashtableAdd(HT, K, V, HASHFUNC, CMPFUNC)
    298 
    299 /** insert/find key, return value address in VPOINTER and ISNEW */
    300 #define hashTbAddOrFind(HT, K, VPOINTER, ISNEW) hashtableAddOrFind(HT, K, VPOINTER, ISNEW, HASHFUNC, CMPFUNC)
    301 
    302 /** find key, return value address in VPOINTER */
    303 #define hashTbFind(HT, K, VPOINTER) hashtableFind(HT, K, VPOINTER, HASHFUNC, CMPFUNC)
    304 
    305 /** get value */
    306 #define hashTbGet(HT, K, R) hashtableGet(HT, K, R, HASHFUNC, CMPFUNC)
    307 
    308 /** get key */
    309 #define hashTbGetKey(HT, K, R) hashtableGetKey(HT, K, R, HASHFUNC, CMPFUNC)
    310 
    311 /** remove key, value */
    312 #define hashTbDel(HT, K) hashtableDel(HT, K, HASHFUNC, CMPFUNC, FREEFUNC)
    313 
    314 /** get random seed address */
    315 #define hashTbSeed(HT) hashtableSeed(HT)
    316 
    317 /** create or reuse an exists node, return NODEPOINTER, NODECONTEXT and ISNEW */
    318 #define hashTbAddOrFindNode(HT, K, NODEPOINTER, NODECONTEXT, ISNEW) hashtableAddOrFindNode(HT, K, NODEPOINTER, NODECONTEXT, ISNEW, HASHFUNC, CMPFUNC)
    319 
    320 /** change the key in a node */
    321 #define hashTbSetKeyNode(HT, NODECONTEXT) hashtableSetKeyNode(HT, NODECONTEXT, HASHFUNC, CMPFUNC)
    322 
    323 /** get a node, return NODE and NODECONTEXT */
    324 #define hashTbGetNode(HT, K, NODE, NODECONTEXT) hashtableGetNode(HT, K, NODE, NODECONTEXT, HASHFUNC, CMPFUNC)
    325 
    326 /** key in node */
    327 #define hashTbNodeKey(NODE) (NODE).key
    328 
    329 /** value in node */
    330 #define hashTbNodeValue(NODE) (NODE).value
    331 
    332 /** update node context after a rehash, return NODECONTEXT */
    333 #define hashTbUpdateNodeContext(HT, NODECONTEXT) hashtableUpdateNodeContext(HT, NODECONTEXT, HASHFUNC, CMPFUNC)
    334 
    335 /** return a node and remove it from the hashtable, return NODE */
    336 #define hashTbUnlinkNode(HT, K, NODE) hashtableUnlinkNode(HT, K, NODE, HASHFUNC, CMPFUNC)
    337 
    338 /** free an unlinked node */
    339 #define hashTbFreeUnlinkedNode(HT, NODE) hashtableFreeUnlinkedNode(HT, NODE, FREEFUNC)
    340 
    341 /** delete a node */
    342 #define hashTbDelNode(HT, NODECONTEXT) hashtableDelNode(HT, NODECONTEXT, FREEFUNC)
    343 
    344 /**
    345  * node definition for bucket single linked lists
    346  *
    347  * keyType, valueType and hashType can any valid type.
    348  *
    349  * context_typeName is defined and is needed for *Node macros
    350  *
    351  * In general, hashType is an uint between 32bits and 256bits
    352  */
    353 #define hashNodeT(typeName, keyType, valueType, hashType)\
    354   typedef struct typeName typeName;\
    355   struct typeName {\
    356     keyType   key;\
    357     typeName  *next;\
    358     hashType  hash;\
    359     u32       index;\
    360     valueType value;\
    361   };\
    362   typedef struct {\
    363     typeName *node;\
    364     typeName *prev;\
    365     u32      mhash;\
    366     u8       moreOrLess;\
    367     u32      size;\
    368   } TOKENPASTE(context_, typeName) /* concatenate strings with preprocessor */
    369 
    370 /**
    371  * hash table definition
    372  * typeName is the type of hash table defined.
    373  *
    374  * hashNodeT(nodeType) has to defined before this macro.
    375  *
    376  * Example:
    377  * hashNodeT(hashSipNodet, char*, u32, u64);
    378  * hashtableT(hashsipt, hashSipNodet);
    379  *
    380  * context_hashSipNodet is the node context type.
    381  */
    382 #define hashtableT(typeName,  nodeType)\
    383   dArrayT(UNIQVAR(aHashnodet), nodeType);\
    384   dArrayT(UNIQVAR(HNFreet), u32);\
    385   typedef struct {\
    386     nodeType*           (*list)[][2]; /* buckets, 2 single linked lists */\
    387     nodeType            node;\
    388     size_t              count;        /* node count */\
    389     u32                 size;         /* bucket count */\
    390     u32                 szMask;       /* mask for bucket indexing */\
    391     UNIQVAR(aHashnodet) aHashnode;    /* node dynamic array */\
    392     UNIQVAR(HNFreet)    HNFree;       /* list of free nodes in aHashnode */\
    393     u8                  hashseed[16]; /* random seed for siphash */\
    394     u32                 loadfactor_numerator;\
    395     u32                 loadfactor_denominator;\
    396     bool                res;          /* return value for macros */\
    397     bool                newNodeInDArray; /* add, addOrFind and addOrFindNode set this flag: true an new node is pushed in aHashnode, false an existing array element is recycled */\
    398   } typeName
    399 
    400 /**
    401  * hash table and hash node definition
    402  * typeName is the type of hash table defined.
    403  *
    404  * keyType, valueType and hashType can any valid type.
    405  *
    406  * In general, hashType is an uint between 32bits and 256bits
    407  */
    408 #define hashTbT(typeName,  keyType, valueType, hashType)\
    409   hashNodeT(UNIQVAR(hashnodet), keyType, valueType, hashType);\
    410   hashtableT(typeName, UNIQVAR(hashnodet))
    411 
    412 /**
    413  * fast log2 function for computing the bucket list size and mask
    414  */
    415 u32 ilog2Hashtable(u32 value);
    416 
    417 /**
    418  * initialize the hash table 'name'
    419  *
    420  * sz is the initial size
    421  * numerator and denominator are the load factor
    422  *
    423  * the random hash seed is generated
    424  *
    425  * this macro must be called before using the hash table
    426  *
    427  * \return
    428  *  (name).res true success, false failed
    429  */
    430 #define hashtableInit(name, sz, numerator, denominator) do{\
    431     (name).size = sz;\
    432     if (sz <= 0) { (name).res = false; break;}\
    433     (name).loadfactor_numerator   = numerator;\
    434     (name).loadfactor_denominator = denominator;\
    435     dArrayInit(&(name).aHashnode);\
    436     dArrayInit(&(name).HNFree);\
    437     setSoftwareRandom();\
    438     range(UNIQVAR(i),16) {\
    439       (name).hashseed[UNIQVAR(i)] = randomChoice(256);\
    440     }\
    441     (name).size   = (1<<ilog2Hashtable(sz));\
    442     (name).szMask = (name).size - 1;\
    443     (name).list   = malloc((name).size * 2 * sizeof(typeof((name).node)*));\
    444     if (!(name).list) /* alloc failed */ { (name).size = 0;  (name).res = false; break;}\
    445     memset((name).list, 0, (name).size * 2 * sizeof(typeof((name).node)*));\
    446     (name).count = 0;\
    447     (name).res   = true;\
    448   } while(0)
    449 
    450 /** Internal - for testing the hash table
    451  * show the content of the buckets
    452  */
    453 #define hashtableTest(name) do{\
    454     range(UNIQVAR(i), (name).size) {\
    455       /* free first linked list */\
    456       typeof((name).node) *UNIQVAR(node) = (*(name).list)[UNIQVAR(i)][0];\
    457       while (UNIQVAR(node)) {\
    458         logI("bucket %3d list 0 key %s", UNIQVAR(i), UNIQVAR(node)->key);\
    459         typeof((name).node) *UNIQVAR(next) = UNIQVAR(node)->next;\
    460         UNIQVAR(node) = UNIQVAR(next);\
    461       }\
    462       /* free second linked list */\
    463       UNIQVAR(node) = (*(name).list)[UNIQVAR(i)][1];\
    464       while (UNIQVAR(node)) {\
    465         logI("bucket %3d list 1 key %s", UNIQVAR(i), UNIQVAR(node)->key);\
    466         typeof((name).node) *UNIQVAR(next) = UNIQVAR(node)->next;\
    467         UNIQVAR(node) = UNIQVAR(next);\
    468       }\
    469     }\
    470   } while(0);
    471 
    472 /**
    473  * remove all key,value pairs in hash table
    474  */
    475 #define hashtableEmpty(name, freeNodeFunc) do{\
    476     range(UNIQVAR(i), (name).size) {\
    477       /* free first linked list */\
    478       typeof((name).node) *UNIQVAR(node) = (*(name).list)[UNIQVAR(i)][0];\
    479       while (UNIQVAR(node)) {\
    480         typeof((name).node) *UNIQVAR(next) = UNIQVAR(node)->next;\
    481         freeNodeFunc(&UNIQVAR(node)->key, &UNIQVAR(node)->value);\
    482         UNIQVAR(node) = UNIQVAR(next);\
    483       }\
    484       /* free second linked list */\
    485       UNIQVAR(node) = (*(name).list)[UNIQVAR(i)][1];\
    486       while (UNIQVAR(node)) {\
    487         typeof((name).node) *UNIQVAR(next) = UNIQVAR(node)->next;\
    488         freeNodeFunc(&UNIQVAR(node)->key, &UNIQVAR(node)->value);\
    489         UNIQVAR(node) = UNIQVAR(next);\
    490       }\
    491       (*(name).list)[UNIQVAR(i)][0] = NULL;\
    492       (*(name).list)[UNIQVAR(i)][1] = NULL;\
    493     }\
    494     (name).count = 0;\
    495   } while(0);
    496 
    497 /**
    498  * empty hash table and free all buffers
    499  *
    500  * \return
    501  *  (name).res true success, false failed
    502  */
    503 #define hashtableFree(name, freeNodeFunc) do{\
    504     (name).res = false;\
    505     if (!(name).size) /* size=0 invalid */ break;\
    506     hashtableEmpty(name, freeNodeFunc);\
    507     free((name).list);\
    508     dArrayFree(&(name).aHashnode);\
    509     dArrayFree(&(name).HNFree);\
    510     (name).list  = NULL;\
    511     (name).count = 0;\
    512     (name).size  = 0;\
    513     (name).res = true;\
    514   } while(0)
    515 
    516 /**
    517  * resize the hash table
    518  *
    519  * \return
    520  *  (name).res true success, false failed
    521  */
    522 #define hashtableResize(name, sz) do{\
    523     u32 UNIQVAR(new_size)  = (1<<ilog2Hashtable(sz));\
    524     (name).szMask          = (name).size - 1;\
    525     if ((name).size == UNIQVAR(new_size)) goto UNIQVAR(msuccess);\
    526     typeof((name).node) *(*UNIQVAR(list))[][2] = malloc(UNIQVAR(new_size) * 2 * sizeof(typeof((name).node)*));\
    527     if (!UNIQVAR(list)) {(name).res = false; break;}\
    528     memset(UNIQVAR(list), 0, UNIQVAR(new_size) * 2 * sizeof(typeof((name).node)*));\
    529     range(UNIQVAR(i), (name).size) {\
    530       range(UNIQVAR(moreLessIdx), 2) {\
    531         for (typeof((name).node) *UNIQVAR(node) = (*(name).list)[UNIQVAR(i)][UNIQVAR(moreLessIdx)]; UNIQVAR(node);) {\
    532           typeof((name).node) *UNIQVAR(next)   = UNIQVAR(node)->next;\
    533           u32 UNIQVAR(mhash)                   = UNIQVAR(node)->hash & (name).szMask;\
    534           typeof((name).node) *UNIQVAR(search) = (*UNIQVAR(list))[UNIQVAR(mhash)][0];\
    535           typeof((name).node) *UNIQVAR(prev)   = NULL;\
    536           u8 UNIQVAR(moreOrLess) = 0;\
    537           if (UNIQVAR(search)) {\
    538             if (UNIQVAR(node)->hash >= UNIQVAR(search)->hash) {\
    539               UNIQVAR(moreOrLess) = 0;\
    540               while (UNIQVAR(search) && UNIQVAR(node)->hash >= UNIQVAR(search)->hash) {\
    541                 UNIQVAR(prev) = UNIQVAR(search);\
    542                 UNIQVAR(search) = UNIQVAR(search)->next;\
    543               }\
    544             }\
    545             else {\
    546               UNIQVAR(moreOrLess) = 1;\
    547               UNIQVAR(search)       = (*UNIQVAR(list))[UNIQVAR(mhash)][1];\
    548               while (UNIQVAR(search) && UNIQVAR(node)->hash <= UNIQVAR(search)->hash) {\
    549                 UNIQVAR(prev)   = UNIQVAR(search);\
    550                 UNIQVAR(search) = UNIQVAR(search)->next;\
    551               }\
    552             }\
    553           }\
    554           UNIQVAR(node)->next = UNIQVAR(search);\
    555           if (UNIQVAR(prev)) {\
    556             UNIQVAR(prev)->next = UNIQVAR(node);\
    557           }\
    558           else {\
    559             (*UNIQVAR(list))[UNIQVAR(mhash)][UNIQVAR(moreOrLess)] = UNIQVAR(node);\
    560           }\
    561           UNIQVAR(node) = UNIQVAR(next);\
    562         }\
    563       }\
    564     }\
    565     free((name).list);\
    566     (name).list = UNIQVAR(list);\
    567     (name).size = UNIQVAR(new_size);\
    568     UNIQVAR(msuccess):\
    569     (name).res = true;\
    570   } while(0)
    571 
    572 /**
    573  * insert key, value
    574  *
    575  * fails when the key already exists
    576  *
    577  * \return
    578  *  (name).res true success, false failed
    579  */
    580 #define hashtableAdd(name, k, v, hashFunc, cmpFunc) do{\
    581     if ((name).loadfactor_denominator * (name).count >= (name).loadfactor_numerator * (name).size) {\
    582       /* load factor too high */\
    583       hashtableResize(name, (name).count*2);\
    584       /*if (!(name).res) break; else (name).res = false;*/\
    585     }\
    586     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc(k);\
    587     const u32 UNIQVAR(mhash)                     = UNIQVAR(hash) & (name).szMask;\
    588     typeof((name).node) *UNIQVAR(node)           = (*(name).list)[UNIQVAR(mhash)][0];\
    589     typeof((name).node) *UNIQVAR(prev)           = NULL;\
    590     typeof((name).node) *UNIQVAR(add);\
    591     u8 UNIQVAR(moreOrLess)                       = 0;\
    592     if (UNIQVAR(node)) {\
    593       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    594         UNIQVAR(moreOrLess) = 0;\
    595         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    596           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    597             (name).newNodeInDArray = false;\
    598             (name).res = false; goto UNIQVAR(mreturn);\
    599           }\
    600           UNIQVAR(prev) = UNIQVAR(node);\
    601           UNIQVAR(node) = UNIQVAR(node)->next;\
    602         }\
    603       }\
    604       else {\
    605         UNIQVAR(moreOrLess) = 1;\
    606         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
    607         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
    608           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    609             (name).newNodeInDArray = false;\
    610             (name).res = false; goto UNIQVAR(mreturn);\
    611           }\
    612           UNIQVAR(prev) = UNIQVAR(node);\
    613           UNIQVAR(node) = UNIQVAR(node)->next;\
    614         }\
    615       }\
    616     }\
    617     if (dArrayIsEmpty(&(name).HNFree)) {\
    618       dArrayPush(&(name).aHashnode);\
    619       UNIQVAR(add)           = dArrayLastPtr(&(name).aHashnode);\
    620       UNIQVAR(add)->index    = dArrayLastIndex(&(name).aHashnode);\
    621       (name).newNodeInDArray = true;\
    622     }\
    623     else {\
    624       u32 UNIQVAR(idx)       = dArrayLast(&(name).HNFree);\
    625       dArrayDelLast(&(name).HNFree);\
    626       UNIQVAR(add)           = dArrayPtr(&(name).aHashnode, UNIQVAR(idx));\
    627       (name).newNodeInDArray = false;\
    628     }\
    629     UNIQVAR(add)->key   = k;\
    630     UNIQVAR(add)->value = v;\
    631     UNIQVAR(add)->hash  = UNIQVAR(hash);\
    632     if (UNIQVAR(prev)) UNIQVAR(prev)->next = UNIQVAR(add);\
    633     else (*(name).list)[UNIQVAR(mhash)][UNIQVAR(moreOrLess)] = UNIQVAR(add);\
    634     UNIQVAR(add)->next  = UNIQVAR(node);\
    635     (name).count++;\
    636     (name).res = true;\
    637     UNIQVAR(mreturn):;\
    638   } while(0)
    639 
    640 /**
    641  * add or find key, get value pointer
    642  *
    643  * vPointer must be of type:
    644  * valueType *
    645  *
    646  * isNew must be of type:
    647  * bool
    648  *
    649  * \return
    650  *   vPointer  address to value associated the key k
    651  *   isNew     true when the node is new, false when the node already existed
    652  *  (name).res true success, false failed
    653  */
    654 #define hashtableAddOrFind(name, k, vPointer, isNew, hashFunc, cmpFunc) do{\
    655     if ((name).loadfactor_denominator * (name).count >= (name).loadfactor_numerator * (name).size) {\
    656       /* load factor too high */\
    657       hashtableResize(name, (name).count*2);\
    658       /*if (!(name).res) break; else (name).res = false;*/\
    659     }\
    660     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc(k);\
    661     const u32 UNIQVAR(mhash)                     = UNIQVAR(hash) & (name).szMask;\
    662     typeof((name).node) *UNIQVAR(node)           = (*(name).list)[UNIQVAR(mhash)][0];\
    663     typeof((name).node) *UNIQVAR(prev)           = NULL;\
    664     typeof((name).node) *UNIQVAR(add);\
    665     u8 UNIQVAR(moreOrLess)                       = 0;\
    666     if (UNIQVAR(node)) {\
    667       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    668         UNIQVAR(moreOrLess) = 0;\
    669         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    670           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    671             vPointer               = &(UNIQVAR(node)->value);\
    672             isNew                  = false;\
    673             (name).newNodeInDArray = false;\
    674             (name).res = true; goto UNIQVAR(mreturn);\
    675           }\
    676           UNIQVAR(prev) = UNIQVAR(node);\
    677           UNIQVAR(node) = UNIQVAR(node)->next;\
    678         }\
    679       }\
    680       else {\
    681         UNIQVAR(moreOrLess) = 1;\
    682         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
    683         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
    684           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    685             vPointer               = &(UNIQVAR(node)->value);\
    686             isNew                  = false;\
    687             (name).newNodeInDArray = false;\
    688             (name).res = true; goto UNIQVAR(mreturn);\
    689           }\
    690           UNIQVAR(prev) = UNIQVAR(node);\
    691           UNIQVAR(node) = UNIQVAR(node)->next;\
    692         }\
    693       }\
    694     }\
    695     isNew = true;\
    696     if (dArrayIsEmpty(&(name).HNFree)) {\
    697       dArrayPush(&(name).aHashnode);\
    698       UNIQVAR(add)           = dArrayLastPtr(&(name).aHashnode);\
    699       UNIQVAR(add)->index    = dArrayLastIndex(&(name).aHashnode);\
    700       (name).newNodeInDArray = true;\
    701     }\
    702     else {\
    703       u32 UNIQVAR(idx)       = dArrayLast(&(name).HNFree);\
    704       dArrayDelLast(&(name).HNFree);\
    705       UNIQVAR(add)           = dArrayPtr(&(name).aHashnode, UNIQVAR(idx));\
    706       (name).newNodeInDArray = false;\
    707     }\
    708     UNIQVAR(add)->key   = k;\
    709     vPointer            = &(UNIQVAR(add)->value);\
    710     UNIQVAR(add)->hash  = UNIQVAR(hash);\
    711     if (UNIQVAR(prev)) UNIQVAR(prev)->next = UNIQVAR(add);\
    712     else (*(name).list)[UNIQVAR(mhash)][UNIQVAR(moreOrLess)] = UNIQVAR(add);\
    713     UNIQVAR(add)->next  = UNIQVAR(node);\
    714     (name).count++;\
    715     (name).res = true;\
    716     UNIQVAR(mreturn):;\
    717   } while(0)
    718 
    719 /**
    720  * find key, get value pointer
    721  *
    722  * vPointer must be of type:
    723  * valueType *
    724  *
    725  * \return
    726  *   vPointer  address to value associated the key k
    727  *  (name).res true success, false failed
    728  */
    729 #define hashtableFind(name, k, vPointer, hashFunc, cmpFunc) do{\
    730     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc(k);\
    731     const u32 UNIQVAR(mhash)                     = UNIQVAR(hash) & (name).szMask;\
    732     typeof((name).node) *UNIQVAR(node)           = (*(name).list)[UNIQVAR(hash) & (name).szMask][0];\
    733     if (UNIQVAR(node)) {\
    734       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    735         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    736           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    737             vPointer     = &UNIQVAR(node)->value;\
    738             (name).res = true;\
    739             goto UNIQVAR(mreturn);\
    740           }\
    741           UNIQVAR(node) = UNIQVAR(node)->next;\
    742         }\
    743       }\
    744       else {\
    745         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
    746         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
    747           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    748             vPointer     = &UNIQVAR(node)->value;\
    749             (name).res = true;\
    750             goto UNIQVAR(mreturn);\
    751           }\
    752           UNIQVAR(node) = UNIQVAR(node)->next;\
    753         }\
    754       }\
    755     }\
    756     (name).res = false;\
    757     UNIQVAR(mreturn):;\
    758   } while(0)
    759 
    760 /**
    761  * get value
    762  *
    763  * \return
    764  *  (name).res true success, false failed
    765  */
    766 #define hashtableGet(name, k, result, hashFunc, cmpFunc) do{\
    767     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc(k);\
    768     const u32 UNIQVAR(mhash)                     = UNIQVAR(hash) & (name).szMask;\
    769     typeof((name).node) *UNIQVAR(node)           = (*(name).list)[UNIQVAR(hash) & (name).szMask][0];\
    770     if (UNIQVAR(node)) {\
    771       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    772         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    773           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    774             result     = UNIQVAR(node)->value;\
    775             (name).res = true;\
    776             goto UNIQVAR(mreturn);\
    777           }\
    778           UNIQVAR(node) = UNIQVAR(node)->next;\
    779         }\
    780       }\
    781       else {\
    782         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
    783         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
    784           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    785             result     = UNIQVAR(node)->value;\
    786             (name).res = true;\
    787             goto UNIQVAR(mreturn);\
    788           }\
    789           UNIQVAR(node) = UNIQVAR(node)->next;\
    790         }\
    791       }\
    792     }\
    793     (name).res = false;\
    794     UNIQVAR(mreturn):;\
    795   } while(0)
    796 
    797 /**
    798  * get key
    799  *
    800  * \return
    801  *  (name).res true success, false failed
    802  */
    803 #define hashtableGetKey(name, k, result, hashFunc, cmpFunc) do{\
    804     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc(k);\
    805     const u32 UNIQVAR(mhash)                     = UNIQVAR(hash) & (name).szMask;\
    806     typeof((name).node) *UNIQVAR(node)           = (*(name).list)[UNIQVAR(hash) & (name).szMask][0];\
    807     if (UNIQVAR(node)) {\
    808       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    809         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    810           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    811             result     = UNIQVAR(node)->key;\
    812             (name).res = true;\
    813             goto UNIQVAR(mreturn);\
    814           }\
    815           UNIQVAR(node) = UNIQVAR(node)->next;\
    816         }\
    817       }\
    818       else {\
    819         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
    820         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
    821           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    822             result     = UNIQVAR(node)->key;\
    823             (name).res = true;\
    824             goto UNIQVAR(mreturn);\
    825           }\
    826           UNIQVAR(node) = UNIQVAR(node)->next;\
    827         }\
    828       }\
    829     }\
    830     (name).res = false;\
    831     UNIQVAR(mreturn):;\
    832   } while(0)
    833 
    834 /**
    835  * remove key, value
    836  *
    837  * \return
    838  *  (name).res true success, false failed
    839  */
    840 #define hashtableDel(name, k, hashFunc, cmpFunc, freeNodeFunc) do{\
    841     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc(k);\
    842     u32 UNIQVAR(mhash)                           = UNIQVAR(hash) & (name).szMask;\
    843     typeof((name).node) *UNIQVAR(node) = (*(name).list)[UNIQVAR(mhash)][0];\
    844     typeof((name).node) *UNIQVAR(prev) = NULL;\
    845     if (UNIQVAR(node)) {\
    846       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    847         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    848           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    849             freeNodeFunc(&UNIQVAR(node)->key, &UNIQVAR(node)->value);\
    850             hashtableInternalDelNode(name, UNIQVAR(node), UNIQVAR(mhash), UNIQVAR(prev), 0);\
    851             (name).res = true;\
    852             goto UNIQVAR(mreturn);\
    853           }\
    854           UNIQVAR(prev) = UNIQVAR(node);\
    855           UNIQVAR(node) = UNIQVAR(node)->next;\
    856         }\
    857       }\
    858       else {\
    859         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
    860         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
    861           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    862             freeNodeFunc(&UNIQVAR(node)->key, &UNIQVAR(node)->value);\
    863             hashtableInternalDelNode(name, UNIQVAR(node), UNIQVAR(mhash), UNIQVAR(prev), 1);\
    864             (name).res = true;\
    865             goto UNIQVAR(mreturn);\
    866           }\
    867           UNIQVAR(prev) = UNIQVAR(node);\
    868           UNIQVAR(node) = UNIQVAR(node)->next;\
    869         }\
    870       }\
    871     }\
    872     (name).res = false;\
    873     UNIQVAR(mreturn):;\
    874   } while(0)
    875 
    876 // Internal macro
    877 #define hashtableInternalDelNode(name, node, mhash, prev, moreOrLess) do{\
    878     hashtableInternalUnlink(name, node, mhash, prev, moreOrLess);\
    879     dArrayAppend(&(name).HNFree, node->index);\
    880     (name).count--;\
    881   } while(0)
    882 
    883 /**
    884  * get hash seed address for siphash
    885  */
    886 #define hashtableSeed(name) ((name).hashseed)
    887 
    888 
    889 
    890 /***************************************
    891  * node macros
    892  *
    893  * Usage scenarios:
    894  *
    895  * The getNode allow processing node data before reinsert or delete and running the hash function
    896  * only once.
    897  *
    898  * Example:
    899  * getNode
    900  * use node data, change key
    901  * setKeyNode
    902  *
    903  * same as
    904  * get
    905  * use node data, change key
    906  * del original key
    907  * add new key, value
    908  *
    909  * The unlink macro allow using data in a node before deleting it.
    910  * The same operation can be done with Get and Del, using unlink runs the hash function only once.
    911  *
    912  * Example:
    913  * unlinkNode
    914  * use node data
    915  * freeUnlinkedNode
    916  *
    917  * same as
    918  * get
    919  * use value
    920  * del
    921  *
    922  ***************************************/
    923 
    924 /**
    925  * add or find node
    926  *
    927  * nodePointer must be a pointer to hash node type
    928  * hashNode *result;
    929  *
    930  * nodeContext must be a struct of type
    931  * context_hashNode ctx;
    932  *
    933  * \return
    934  *  (name).res true success, false failed
    935  */
    936 #define hashtableAddOrFindNode(name, k, nodePointer, nodeContext, isNew, hashFunc, cmpFunc) do{\
    937     if ((name).loadfactor_denominator * (name).count >= (name).loadfactor_numerator * (name).size) {\
    938       /* load factor too high */\
    939       hashtableResize(name, (name).count*2);\
    940       /*if (!(name).res) break; else (name).res = false;*/\
    941     }\
    942     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc(k);\
    943     const u32 UNIQVAR(mhash)                     = UNIQVAR(hash) & (name).szMask;\
    944     (nodeContext).node->hash                     = UNIQVAR(hash);\
    945     typeof((name).node) *UNIQVAR(node)           = (*(name).list)[UNIQVAR(mhash)][0];\
    946     typeof((name).node) *UNIQVAR(prev)           = NULL;\
    947     u8 UNIQVAR(moreOrLess)                       = 0;\
    948     if (UNIQVAR(node)) {\
    949       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    950         UNIQVAR(moreOrLess) = 0;\
    951         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
    952           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    953             nodePointer              = UNIQVAR(node);\
    954             (nodeContext).node       = nodePointer;\
    955             (nodeContext).prev       = UNIQVAR(prev);\
    956             (nodeContext).mhash      = UNIQVAR(mhash);\
    957             (nodeContext).moreOrLess = UNIQVAR(moreOrLess);\
    958             (nodeContext).size       = (name).size;\
    959             isNew                    = false;\
    960             (name).newNodeInDArray   = false;\
    961             (name).res = true; goto UNIQVAR(mreturn);\
    962           }\
    963           UNIQVAR(prev) = UNIQVAR(node);\
    964           UNIQVAR(node) = UNIQVAR(node)->next;\
    965         }\
    966       }\
    967       else {\
    968         UNIQVAR(moreOrLess) = 1;\
    969         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
    970         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
    971           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
    972             nodePointer              = UNIQVAR(node);\
    973             (nodeContext).node       = nodePointer;\
    974             (nodeContext).prev       = UNIQVAR(prev);\
    975             (nodeContext).mhash      = UNIQVAR(mhash);\
    976             (nodeContext).moreOrLess = UNIQVAR(moreOrLess);\
    977             (nodeContext).size       = (name).size;\
    978             isNew                    = false;\
    979             (name).newNodeInDArray   = false;\
    980             (name).res = true; goto UNIQVAR(mreturn);\
    981           }\
    982           UNIQVAR(prev) = UNIQVAR(node);\
    983           UNIQVAR(node) = UNIQVAR(node)->next;\
    984         }\
    985       }\
    986     }\
    987     isNew = true;\
    988     if (dArrayIsEmpty(&(name).HNFree)) {\
    989       dArrayPush(&(name).aHashnode);\
    990       nodePointer            = dArrayLastPtr(&(name).aHashnode);\
    991       nodePointer->index     = dArrayLastIndex(&(name).aHashnode);\
    992       (name).newNodeInDArray = true;\
    993     }\
    994     else {\
    995       u32 UNIQVAR(idx)       = dArrayLast(&(name).HNFree);\
    996       dArrayDelLast(&(name).HNFree);\
    997       nodePointer            = dArrayPtr(&(name).aHashnode, UNIQVAR(idx));\
    998       (name).newNodeInDArray = false;\
    999     }\
   1000     nodePointer->key   = k;\
   1001     if (UNIQVAR(prev)) UNIQVAR(prev)->next = nodePointer;\
   1002     else (*(name).list)[UNIQVAR(mhash)][UNIQVAR(moreOrLess)] = nodePointer;\
   1003     nodePointer->next  = UNIQVAR(node);\
   1004     (name).count++;\
   1005     /* set context */\
   1006     (nodeContext).node        = nodePointer;\
   1007     (nodeContext).prev        = UNIQVAR(prev);\
   1008     (nodeContext).mhash       = UNIQVAR(mhash);\
   1009     (nodeContext).moreOrLess  = UNIQVAR(moreOrLess);\
   1010     (nodeContext).size        = (name).size;\
   1011     (name).res = true;\
   1012     UNIQVAR(mreturn):;\
   1013   } while(0)
   1014 
   1015 /**
   1016  * set node to be used when the key is updated
   1017  * unlink the node then
   1018  * insert it in another bucket
   1019  *
   1020  * nodeContext must be a struct of type
   1021  * context_hashNode ctx;
   1022  *
   1023  * The node context is updated and remains valid after this macro (no need to run updateNodeContext)
   1024  *
   1025  * When key,value pairs are added after getNode and the table is rehashed (the size changed), the node context should be updated with getNode before calling this macro
   1026  *
   1027  * The node is unlinked, so in case of failure, the node should be added with AddOrFindNode or the node should be freed with freeUnlinkedNode
   1028  *
   1029  * \return
   1030  *  (name).res true success, false failed
   1031  */
   1032 #define hashtableSetKeyNode(name, nodeContext, hashFunc, cmpFunc) do{\
   1033     /* no need to resize because the node is unlinked and the key is rehashed */\
   1034     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc((nodeContext).node->key);\
   1035     if (UNIQVAR(hash) == (nodeContext).node->hash) /* the hash is identical to the previous one, we are done */{\
   1036       (name).res = true; goto UNIQVAR(mreturn);\
   1037     }\
   1038     hashtableInternalUnlinkNode(name, nodeContext);\
   1039     if (!(name).res) /* the table has been rehashed, the context is invalid */ goto UNIQVAR(mreturn);\
   1040     const u32 UNIQVAR(mhash)           = UNIQVAR(hash) & (name).szMask;\
   1041     (nodeContext).node->hash           = UNIQVAR(hash);\
   1042     typeof((name).node) *UNIQVAR(node) = (*(name).list)[UNIQVAR(mhash)][0];\
   1043     typeof((name).node) *UNIQVAR(prev) = NULL;\
   1044     u8 UNIQVAR(moreOrLess)             = 0;\
   1045     if (UNIQVAR(node)) {\
   1046       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
   1047         UNIQVAR(moreOrLess) = 0;\
   1048         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
   1049           if (UNIQVAR(hash) == UNIQVAR(node)->hash && (((nodeContext).node->key == UNIQVAR(node)->key) || (cmpFunc((nodeContext).node->key, UNIQVAR(node)->key) == 0))) {\
   1050             (name).res = false; goto UNIQVAR(mreturn);\
   1051           }\
   1052           UNIQVAR(prev) = UNIQVAR(node);\
   1053           UNIQVAR(node) = UNIQVAR(node)->next;\
   1054         }\
   1055       }\
   1056       else {\
   1057         UNIQVAR(moreOrLess) = 1;\
   1058         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
   1059         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
   1060           if (UNIQVAR(hash) == UNIQVAR(node)->hash && (((nodeContext).node->key == UNIQVAR(node)->key) || (cmpFunc((nodeContext).node->key, UNIQVAR(node)->key) == 0))) {\
   1061             (name).res = false; goto UNIQVAR(mreturn);\
   1062           }\
   1063           UNIQVAR(prev) = UNIQVAR(node);\
   1064           UNIQVAR(node) = UNIQVAR(node)->next;\
   1065         }\
   1066       }\
   1067     }\
   1068     if (UNIQVAR(prev)) UNIQVAR(prev)->next = (nodeContext).node;\
   1069     else (*(name).list)[UNIQVAR(mhash)][UNIQVAR(moreOrLess)] = (nodeContext).node;\
   1070     (nodeContext).node->next  = UNIQVAR(node);\
   1071     /* update context */\
   1072     (nodeContext).prev        = UNIQVAR(prev);\
   1073     (nodeContext).mhash       = UNIQVAR(mhash);\
   1074     (nodeContext).moreOrLess  = UNIQVAR(moreOrLess);\
   1075     (nodeContext).size        = (name).size;\
   1076     (name).res = true;\
   1077     UNIQVAR(mreturn):;\
   1078   } while(0)
   1079 
   1080 // Internal macro, like Internal DelNode without free the node
   1081 // the node is removed from the bucket
   1082 #define hashtableInternalUnlinkNode(name, nodeContext) do{\
   1083     if ((nodeContext).size != (name).size) {\
   1084       /* the table has been rehashed since the nodeContext was filled in */\
   1085       /* update the context, run updateNodeContext with the original key */\
   1086       /* the original is not available in the context, since the key is probably updated */\
   1087       (name).res = false;\
   1088       break;\
   1089     }\
   1090     if ((nodeContext).prev) (nodeContext).prev->next = (nodeContext).node->next;\
   1091     else (*(name).list)[(nodeContext).mhash][(nodeContext).moreOrLess] = (nodeContext).node->next;\
   1092     if (((nodeContext).moreOrLess == 0) && !(*(name).list)[(nodeContext).mhash][0] && (*(name).list)[(nodeContext).mhash][1]) {\
   1093       /* the first linked list is empty, take the first element from the second linked list */\
   1094       (*(name).list)[(nodeContext).mhash][0]       = (*(name).list)[(nodeContext).mhash][1];\
   1095       (*(name).list)[(nodeContext).mhash][1]       = (*(name).list)[(nodeContext).mhash][1]->next;\
   1096       (*(name).list)[(nodeContext).mhash][0]->next = NULL;\
   1097     }\
   1098     (name).res = true;\
   1099   } while(0)
   1100 
   1101 
   1102 /**
   1103  * get node
   1104  *
   1105  * result must be a pointer to hash node type
   1106  * hashNode *result;
   1107  *
   1108  * nodeContext must be a struct of type
   1109  * context_hashNode ctx;
   1110  *
   1111  * \return
   1112  *  (name).res true success, false failed
   1113  */
   1114 #define hashtableGetNode(name, k, result, nodeContext, hashFunc, cmpFunc) do{\
   1115     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc(k);\
   1116     const u32 UNIQVAR(mhash)                     = UNIQVAR(hash) & (name).szMask;\
   1117     typeof((name).node) *UNIQVAR(node)           = (*(name).list)[UNIQVAR(hash) & (name).szMask][0];\
   1118     typeof((name).node) *UNIQVAR(prev)           = NULL;\
   1119     if (UNIQVAR(node)) {\
   1120       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
   1121         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
   1122           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
   1123             result                   = UNIQVAR(node);\
   1124             (nodeContext).node       = UNIQVAR(node);\
   1125             (nodeContext).prev       = UNIQVAR(prev);\
   1126             (nodeContext).mhash      = UNIQVAR(mhash);\
   1127             (nodeContext).moreOrLess = 0;\
   1128             (nodeContext).size       = (name).size;\
   1129             (name).res               = true;\
   1130             goto UNIQVAR(mreturn);\
   1131           }\
   1132           UNIQVAR(prev) = UNIQVAR(node);\
   1133           UNIQVAR(node) = UNIQVAR(node)->next;\
   1134         }\
   1135       }\
   1136       else {\
   1137         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
   1138         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
   1139           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
   1140             result                   = UNIQVAR(node);\
   1141             (nodeContext).node       = UNIQVAR(node);\
   1142             (nodeContext).prev       = UNIQVAR(prev);\
   1143             (nodeContext).mhash      = UNIQVAR(mhash);\
   1144             (nodeContext).moreOrLess = 1;\
   1145             (nodeContext).size       = (name).size;\
   1146             (name).res               = true;\
   1147             goto UNIQVAR(mreturn);\
   1148           }\
   1149           UNIQVAR(prev) = UNIQVAR(node);\
   1150           UNIQVAR(node) = UNIQVAR(node)->next;\
   1151         }\
   1152       }\
   1153     }\
   1154     (name).res = false;\
   1155     UNIQVAR(mreturn):;\
   1156   } while(0)
   1157 
   1158 /**
   1159  * update node context
   1160  *
   1161  * the node context must have been initialized with getNode or setKeyNode
   1162  *
   1163  * call this macro when the table has been rehashed after getNode or setKeyNode
   1164  *
   1165  * nodeContext must be a struct of type
   1166  * context_hashNode ctx;
   1167  *
   1168  * \return
   1169  *  (name).res true success, false failed
   1170  */
   1171 #define hashtableUpdateNodeContext(name, nodeContext, hashFunc, cmpFunc) do{\
   1172     const typeof((name).node.hash) UNIQVAR(hash) = (nodeContext).node->hash;\
   1173     const u32 UNIQVAR(mhash)                     = UNIQVAR(hash) & (name).szMask;\
   1174     typeof((name).node) *UNIQVAR(node)           = (*(name).list)[UNIQVAR(hash) & (name).szMask][0];\
   1175     typeof((name).node) *UNIQVAR(prev)           = NULL;\
   1176     if (UNIQVAR(node)) {\
   1177       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
   1178         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
   1179           if (UNIQVAR(hash) == UNIQVAR(node)->hash && (((nodeContext).node->key == UNIQVAR(node)->key) || (cmpFunc((nodeContext).node->key, UNIQVAR(node)->key) == 0))) {\
   1180             (nodeContext).prev       = UNIQVAR(prev);\
   1181             (nodeContext).mhash      = UNIQVAR(mhash);\
   1182             (nodeContext).moreOrLess = 0;\
   1183             (nodeContext).size       = (name).size;\
   1184             (name).res               = true;\
   1185             goto UNIQVAR(mreturn);\
   1186           }\
   1187           UNIQVAR(prev) = UNIQVAR(node);\
   1188           UNIQVAR(node) = UNIQVAR(node)->next;\
   1189         }\
   1190       }\
   1191       else {\
   1192         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
   1193         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
   1194           if (UNIQVAR(hash) == UNIQVAR(node)->hash && (((nodeContext).node->key == UNIQVAR(node)->key) || (cmpFunc((nodeContext).node->key, UNIQVAR(node)->key) == 0))) {\
   1195             (nodeContext).prev       = UNIQVAR(prev);\
   1196             (nodeContext).mhash      = UNIQVAR(mhash);\
   1197             (nodeContext).moreOrLess = 1;\
   1198             (nodeContext).size       = (name).size;\
   1199             (name).res               = true;\
   1200             goto UNIQVAR(mreturn);\
   1201           }\
   1202           UNIQVAR(prev) = UNIQVAR(node);\
   1203           UNIQVAR(node) = UNIQVAR(node)->next;\
   1204         }\
   1205       }\
   1206     }\
   1207     (name).res = false;\
   1208     UNIQVAR(mreturn):;\
   1209   } while(0)
   1210 
   1211 /**
   1212  * unlink node
   1213  *
   1214  * result must be a pointer to hash node type
   1215  * hashNode *result;
   1216  *
   1217  * result must be freed with freeUnlinkNode
   1218  *
   1219  * This macro allow using data in a node before deleting it.
   1220  * The same operation can be done with Get and Del, using unlink runs the hash function only once.
   1221  *
   1222  * Example:
   1223  * unlinkNode
   1224  * use node data
   1225  * freeUnlinkedNode
   1226  *
   1227  * same as
   1228  * get
   1229  * use value
   1230  * del
   1231  *
   1232  * \return
   1233  * result unlinked node
   1234  *  (name).res true success, false failed
   1235  */
   1236 #define hashtableUnlinkNode(name, k, result, hashFunc, cmpFunc) do{\
   1237     const typeof((name).node.hash) UNIQVAR(hash) = hashFunc(k);\
   1238     const u32 UNIQVAR(mhash)                     = UNIQVAR(hash) & (name).szMask;\
   1239     typeof((name).node) *UNIQVAR(node)           = (*(name).list)[UNIQVAR(hash) & (name).szMask][0];\
   1240     typeof((name).node) *UNIQVAR(prev)           = NULL;\
   1241     if (UNIQVAR(node)) {\
   1242       if (UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
   1243         while (UNIQVAR(node) && UNIQVAR(hash) >= UNIQVAR(node)->hash) {\
   1244           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
   1245             hashtableInternalUnlink(name, UNIQVAR(node), UNIQVAR(mhash), UNIQVAR(prev), 0);\
   1246             result     = UNIQVAR(node);\
   1247             (name).res = true;\
   1248             goto UNIQVAR(mreturn);\
   1249           }\
   1250           UNIQVAR(prev) = UNIQVAR(node);\
   1251           UNIQVAR(node) = UNIQVAR(node)->next;\
   1252         }\
   1253       }\
   1254       else {\
   1255         UNIQVAR(node)       = (*(name).list)[UNIQVAR(mhash)][1];\
   1256         while (UNIQVAR(node) && UNIQVAR(hash) <= UNIQVAR(node)->hash) {\
   1257           if (UNIQVAR(hash) == UNIQVAR(node)->hash && ((k == UNIQVAR(node)->key) || (cmpFunc(k, UNIQVAR(node)->key) == 0))) {\
   1258             hashtableInternalUnlink(name, UNIQVAR(node), UNIQVAR(mhash), UNIQVAR(prev), 1);\
   1259             result     = UNIQVAR(node);\
   1260             (name).res = true;\
   1261             goto UNIQVAR(mreturn);\
   1262           }\
   1263           UNIQVAR(prev) = UNIQVAR(node);\
   1264           UNIQVAR(node) = UNIQVAR(node)->next;\
   1265         }\
   1266       }\
   1267     }\
   1268     (name).res = false;\
   1269     UNIQVAR(mreturn):;\
   1270   } while(0)
   1271 
   1272 // Internal macro
   1273 #define hashtableInternalUnlink(name, node, mhash, prev, moreOrLess) do{\
   1274     if (prev) prev->next = node->next;\
   1275     else (*(name).list)[mhash][moreOrLess] = node->next;\
   1276     if ((moreOrLess == 0) && !(*(name).list)[mhash][0] && (*(name).list)[mhash][1]) {\
   1277       /* the first linked list is empty, take the first element from the second linked list */\
   1278       (*(name).list)[mhash][0]       = (*(name).list)[mhash][1];\
   1279       (*(name).list)[mhash][1]       = (*(name).list)[mhash][1]->next;\
   1280       (*(name).list)[mhash][0]->next = NULL;\
   1281     }\
   1282   } while(0)
   1283 
   1284 /**
   1285  * free an unlinked node
   1286  *
   1287  * node must be a pointer to hash node type
   1288  * hashNode *node;
   1289  *
   1290  * the node has to be first unlinked with the unlinkNode macro
   1291  */
   1292 #define hashtableFreeUnlinkedNode(name, node, freeNodeFunc) do{\
   1293     freeNodeFunc(&(node)->key, &(node)->value);\
   1294     dArrayAppend(&(name).HNFree, (node)->index);\
   1295     (name).count--;\
   1296   } while(0)
   1297 
   1298 /**
   1299  * delete/remove node
   1300  *
   1301  * the node context must be already initialized with the other *Node macros
   1302  *
   1303  * if the node context is changed due to rehash, updateNodeContext has to be called before this macro
   1304  */
   1305 // no status
   1306 #define hashtableDelNode(name, nodeContext, freeNodeFunc) do{\
   1307     freeNodeFunc(&(nodeContext).node->key, &(nodeContext).node->value);\
   1308     hashtableInternalDelNode(name, (nodeContext).node, (nodeContext).mhash, (nodeContext).prev, (nodeContext).moreOrLess);\
   1309   } while(0)
   1310