hashlist

type-safe random access double linked lists
git clone https://noulin.net/git/hashlist.git
Log | Files | Refs | README | LICENSE

hashlist.h (18790B)


      1 #pragma once
      2 
      3 #include "libsheepyObject.h"
      4 #include "shpPackages/hashtable/hashtable.h"
      5 
      6 /**
      7  * \file
      8  *
      9  * hashlist - random access double linked lists
     10  *
     11  * this data structure is a double linked list in a hashtable
     12  * each node in the list has a key, any node in the list is accessed using a key
     13  * multiple lists can be created in the hashtable
     14  *
     15  * the macros in this define and implement the hashlist types and functions
     16  * the hash function has to be provided by another package (hashfunctions)
     17  *
     18  * - hashlistDef defines the types and function prototype for the hashlist and hashtable
     19  * - hashlistFunctions implements the hashlist and hashtable functions
     20  *
     21  * the hashlist function names have the following pattern:
     22  *   hashlistFUNCTION_NAME##hashlistFuncSuffix
     23  *
     24  * the hashtable function names have the following pattern:
     25  *   FUNCTION_NAME##hashlistFuncSuffix
     26  *
     27  * the hashlist type is:      hashlistTypeName##t
     28  * the hashlist node type is: valueTypeName##t
     29  *
     30  * node.key is the key
     31  * node.prev is a pointer to previous node, NULL when node is head
     32  * node.next is a pointer to next node, NULL when node is last
     33  *
     34  * Use the regular hashtable functions to access the nodes using the keys: get####hashlistFuncSuffix, find##hashlistFuncSuffix...
     35  *
     36  * Push, Prepend, AppendAfter, AppendBefore       add new nodes and return a pointer to it
     37  * AddAfter, AddAfterKey, AddBefore, AddBeforeKey add new nodes and store the value in parameter in it
     38  *
     39  * Use Unlink to crop a node from the list and then use the FreeNode or Insert functions
     40  *
     41  * function descriptions:
     42  *
     43  * - Create:                             create a new list and store value in first node.
     44  *                                       Returns: node pointer or NULL when key already exists
     45  * - New:                                create a new list and a new node with given key.
     46  *                                       Returns: node pointer or NULL when key already exists
     47  * - Free:                               free all nodes in list (nodes before and after given node are freed, node doesn't need to be head or last)
     48  * - Release:                            free all nodes in list starting with node with given key
     49  *                                       (nodes before and after given key are freed, node doesn't need to be head or last)
     50  * - Push:                               add a new node with newKey after given node.
     51  *                                       Returns: new node pointer or NULL when node is NULL or when key already exists
     52  * - Prepend:                            add a new node with newKey before given node.
     53  *                                       Returns: new node pointer or NULL when node is NULL or when key already exists
     54  * - AppendAfter:                        add a new node with newKey after node given key.
     55  *                                       Returns: new node pointer or NULL when key doesn't exists or when key already exists
     56  * - AppendBefore:                       add a new node with newKey before node given key.
     57  *                                       Returns: new node pointer or NULL when key doesn't exists or when key already exists
     58  * - Unlink:                             crop node from the list.
     59  *                                       Returns node pointer or NULL when node is NULL
     60  * - UnlinkKey:                          crop node with given key from the list.
     61  *                                       Returns node pointer or NULL when key doesn't exists
     62  * - FreeNode (del##hashlistFuncSuffix): free an unlinked node.
     63  *                                       Returns: true or false when node is NULL
     64  * - DelNode:                            unlink and free node
     65  * - Del:                                unlink and free node with given key
     66  * - InsertAfter:                        insert unlinked node after given node. Returns node pointer or NULL when node or value are NULL
     67  * - InsertAfterKey:                     insert unlinked node after node with key. Returns node pointer or NULL when key doesn't exists or value is NULL
     68  * - InsertBefore:                       insert unlinked node before given node. Returns node pointer or NULL when node or value are NULL
     69  * - InsertBeforeKey:                    insert unlinked node before node with key. Returns node pointer or NULL when key doesn't exists or value is NULL
     70  * - AddAfter:                           add new node and store value in it after node.
     71  *                                       Returns: new node pointer or NULL when node is NULL or value.key already exists
     72  * - AddAfterKey:                        add new node and store value in it after node with given key.
     73  *                                       Returns: new node pointer or NULL when key doesn't exists or value.key already exists
     74  * - AddBefore:                          add new node and store value in it before node.
     75  *                                       Returns: new node pointer or NULL when node is NULL or value.key already exists
     76  * - AddBeforeKey:                       add new node and store value in it before node with given key.
     77  *                                       Returns: new node pointer or NULL when key doesn't exists or value.key already exists
     78  *
     79  * Example:
     80  * See main.c for more details
     81  *
     82  * // define node members:
     83  * #define listMembers char *v;
     84  *
     85  * // define hashlist
     86  *  hashlistDef(, lists, Lists, u64, list, u64, listMembers);
     87  *
     88  * // select hashtable functions
     89  * #define HASHFUNC u64Hash
     90  * #define CMPFUNC  cmpU64
     91  * #define FREEFUNC freeList
     92  *
     93  * // implement hashlist functions
     94  * hashlistFunctions(, lists, Lists, u64, list, u64, listMembers,
     95  * int cmpU64(u64 k1, u64 k2) {
     96  *   return k1 == k2;
     97  * }
     98  * void freeList(u64 *k, listt *v) {
     99  * });
    100  *
    101  * // undef functions
    102  * #undef HASHFUNC
    103  * #undef CMPFUNC
    104  * #undef FREEFUNC
    105  *
    106  * // declare hashlist
    107  * listst hlists;
    108  *
    109  * // initlialize hashlist
    110  * initLists(&hlists);
    111  *
    112  * // declare hashlist node
    113  * listt g;
    114  *
    115  * // create new list
    116  * g.key  = 0;
    117  * g.v    = "sdf";
    118  * listt *head = hashlistCreateLists(&hlists, g);
    119  *
    120  * // access node
    121  * listt *G = findLists(&hlists, 0);
    122  * logVarG(G->v);
    123  *
    124  * // push new node
    125  * G    = hashlistPushLists(&hlists, head, 1);
    126  * G->v = "22";
    127  *
    128  * // free list
    129  * hashlistFreeLists(&hlists, head);
    130  *
    131  * // free hashlist
    132  * freeLists(&hlists);
    133  *
    134  */
    135 
    136 #define hashlistDef(scope, hashlistTypeName, hashlistFuncSuffix, keyType, valueTypeName, hashType, valueMembers)\
    137   typ struct valueTypeName##t valueTypeName##t;\
    138   struct valueTypeName##t {\
    139     /* linked list */\
    140     keyType key;\
    141     valueTypeName##t *prev; /* prev list node */\
    142     valueTypeName##t *next; /* next list node */\
    143     valueMembers\
    144   };\
    145   \
    146   hashTbDef(scope, hashlistTypeName /* hashlistTypeNamet hashtable */, hashlistFuncSuffix /* functions: inithashlistFuncSuffix,... */, keyType /* key */, valueTypeName##t /* value */, hashType /* hash */);\
    147   scope valueTypeName##t* hashlistCreate##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t value);\
    148   scope valueTypeName##t* hashlistNew##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key);\
    149   scope void hashlistFree##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node);\
    150   scope void hashlistRelease##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key);\
    151   scope valueTypeName##t* hashlistPush##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node, keyType newKey);\
    152   scope valueTypeName##t* hashlistPrepend##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node, keyType newKey);\
    153   scope valueTypeName##t* hashlistAppendAfter##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, keyType newKey);\
    154   scope valueTypeName##t* hashlistAppendBefore##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, keyType newKey);\
    155   scope valueTypeName##t* hashlistUnlink##hashlistFuncSuffix(valueTypeName##t *node);\
    156   scope valueTypeName##t* hashlistUnlinkKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key);\
    157   scope bool hashlistFreeNode##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node);\
    158   scope bool hashlistDelNode##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node);\
    159   scope void hashlistDel##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key);\
    160   scope valueTypeName##t* hashlistInsertAfter##hashlistFuncSuffix(valueTypeName##t *node, valueTypeName##t *value);\
    161   scope valueTypeName##t* hashlistInsertAfterKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, valueTypeName##t *value);\
    162   scope valueTypeName##t* hashlistInsertBefore##hashlistFuncSuffix(valueTypeName##t *node, valueTypeName##t *value);\
    163   scope valueTypeName##t* hashlistInsertBeforeKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, valueTypeName##t *value);\
    164   scope valueTypeName##t* hashlistAddAfter##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node, valueTypeName##t value);\
    165   scope valueTypeName##t* hashlistAddAfterKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, valueTypeName##t value);\
    166   scope valueTypeName##t* hashlistAddBefore##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node, valueTypeName##t value);\
    167   scope valueTypeName##t* hashlistAddBeforeKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, valueTypeName##t value);
    168 
    169 #define hashlistFunctions(scope, hashlistTypeName, hashlistFuncSuffix, keyType, valueTypeName, hashType, valueMembers, functions /* declare the functions here */)\
    170   functions;\
    171   \
    172   hashTbFunctions(scope, hashlistTypeName, hashlistFuncSuffix, keyType /* key */, valueTypeName##t /* value */)\
    173   /* create head - first node in list */\
    174   scope valueTypeName##t* hashlistCreate##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t value) {\
    175     value.prev = value.next = NULL;\
    176     bool r;\
    177     valueTypeName##t* res = addOrFind##hashlistFuncSuffix(hashlist, value.key, &r);\
    178     if (!r) ret NULL;\
    179     *res = value;\
    180     ret res;\
    181   }\
    182   /* create new head with given key - first node in list */\
    183   scope valueTypeName##t* hashlistNew##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key) {\
    184     bool r;\
    185     valueTypeName##t* res = addOrFind##hashlistFuncSuffix(hashlist, key, &r);\
    186     if (!r) ret NULL;\
    187     res->prev = res->next = NULL;\
    188     res->key              = key;\
    189     ret res;\
    190   }\
    191   /* free list */\
    192   scope void hashlistFree##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node) {\
    193     if (!node) ret;\
    194     if (node->next) {\
    195       if (node->prev) {\
    196         /* there are nodes before and after */\
    197         var prev = node->prev;\
    198         /* delete node and next nodes */\
    199         var n   = node;\
    200         var tmp = n;\
    201         while (n) {\
    202           tmp = n->next;\
    203           del##hashlistFuncSuffix(hashlist, n->key);\
    204           n = tmp;\
    205         }\
    206         /* delete previous nodes */\
    207         n = prev;\
    208         while (n) {\
    209           tmp = n->prev;\
    210           del##hashlistFuncSuffix(hashlist, n->key);\
    211           n = tmp;\
    212         }\
    213       }\
    214       else {\
    215         /* node is head, there are only next nodes*/\
    216         var n   = node;\
    217         var tmp = n;\
    218         while (n) {\
    219           tmp = n->next;\
    220           del##hashlistFuncSuffix(hashlist, n->key);\
    221           n = tmp;\
    222         }\
    223       }\
    224     }\
    225     else {\
    226       /* node is last, there are only previous nodes */\
    227       var n   = node;\
    228       var tmp = n;\
    229       while (n) {\
    230         tmp = n->prev;\
    231         del##hashlistFuncSuffix(hashlist, n->key);\
    232         n = tmp;\
    233       }\
    234     }\
    235   }\
    236   /* free list using key */\
    237   scope void hashlistRelease##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key) {\
    238     valueTypeName##t *node = find##hashlistFuncSuffix(hashlist, key);\
    239     hashlistFree##hashlistFuncSuffix(hashlist, node);\
    240   }\
    241   /* push */\
    242   scope valueTypeName##t* hashlistPush##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node, keyType newKey) {\
    243     if (!node) ret NULL;\
    244     bool r;\
    245     valueTypeName##t *val = addOrFind##hashlistFuncSuffix(hashlist, newKey, &r);\
    246     if (!r) /* key already exists, failed to create new node */ ret NULL;\
    247     val->key   = newKey;\
    248     /*  connect new node to list */\
    249     val->next  = node->next;\
    250     if (val->next) {\
    251       val->next->prev = val;\
    252     }\
    253     node->next = val;\
    254     val->prev  = node;\
    255     ret val;\
    256   }\
    257   /* prepend */\
    258   scope valueTypeName##t* hashlistPrepend##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node, keyType newKey) {\
    259     if (!node) ret NULL;\
    260     bool r;\
    261     valueTypeName##t *val = addOrFind##hashlistFuncSuffix(hashlist, newKey, &r);\
    262     if (!r) /* key already exists, failed to create new node */ ret NULL;\
    263     val->key   = newKey;\
    264     /*  connect new node to list */\
    265     val->prev  = node->prev;\
    266     if (val->prev) {\
    267       val->prev->next = val;\
    268     }\
    269     node->prev = val;\
    270     val->next  = node;\
    271     ret val;\
    272   }\
    273   /* append new node after node with key */\
    274   scope valueTypeName##t* hashlistAppendAfter##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, keyType newKey) {\
    275     valueTypeName##t *node = find##hashlistFuncSuffix(hashlist, key);\
    276     ret hashlistPush##hashlistFuncSuffix(hashlist, node, newKey);\
    277   }\
    278   /* append new node before node with key */\
    279   scope valueTypeName##t* hashlistAppendBefore##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, keyType newKey) {\
    280     valueTypeName##t *node = find##hashlistFuncSuffix(hashlist, key);\
    281     ret hashlistPrepend##hashlistFuncSuffix(hashlist, node, newKey);\
    282   }\
    283   /* unlink */\
    284   scope valueTypeName##t* hashlistUnlink##hashlistFuncSuffix(valueTypeName##t *node) {\
    285     if (!node) ret NULL;\
    286     if (node->prev) {\
    287       node->prev->next = node->next;\
    288     }\
    289     if (node->next) {\
    290       node->next->prev = node->prev;\
    291     }\
    292     return node;\
    293   }\
    294   /* unlink with key */\
    295   scope valueTypeName##t* hashlistUnlinkKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key) {\
    296     valueTypeName##t *node = find##hashlistFuncSuffix(hashlist, key);\
    297     ret hashlistUnlink##hashlistFuncSuffix(node);\
    298   }\
    299   /* free unlinked node */\
    300   scope bool hashlistFreeNode##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node) {\
    301     if (!node) ret false;\
    302     del##hashlistFuncSuffix(hashlist, node->key);\
    303     ret true;\
    304   }\
    305   /* del node */\
    306   scope bool hashlistDelNode##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node) {\
    307     if (!node) ret false;\
    308     hashlistUnlink##hashlistFuncSuffix(node);\
    309     del##hashlistFuncSuffix(hashlist, node->key);\
    310     ret true;\
    311   }\
    312   /* del using key */\
    313   scope void hashlistDel##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key) {\
    314     hashlistTypeName##Nodet *node = unlink##hashlistFuncSuffix(hashlist, key);\
    315     if (!node) /* node not found */ ret;\
    316     hashlistUnlink##hashlistFuncSuffix(&node->value);\
    317     freeUnlinked##hashlistFuncSuffix(hashlist, node);\
    318   }\
    319   /* TODO swap 2 nodes */\
    320   /* insert an unlinked value after node */\
    321   scope valueTypeName##t* hashlistInsertAfter##hashlistFuncSuffix(valueTypeName##t *node, valueTypeName##t *value) {\
    322     if (!node or !value) ret NULL;\
    323     /*  connect value node to list */\
    324     value->next  = node->next;\
    325     if (value->next) {\
    326       value->next->prev = value;\
    327     }\
    328     node->next = value;\
    329     value->prev  = node;\
    330     ret value;\
    331   }\
    332   /* insert an unlinked value after node with key */\
    333   scope valueTypeName##t* hashlistInsertAfterKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, valueTypeName##t *value) {\
    334     valueTypeName##t *node = find##hashlistFuncSuffix(hashlist, key);\
    335     ret hashlistInsertAfter##hashlistFuncSuffix(node, value);\
    336   }\
    337   /* insert an unlinked value before node */\
    338   scope valueTypeName##t* hashlistInsertBefore##hashlistFuncSuffix(valueTypeName##t *node, valueTypeName##t *value) {\
    339     if (!node or !value) ret NULL;\
    340     /*  connect value node to list */\
    341     value->prev  = node->prev;\
    342     if (value->prev) {\
    343       value->prev->next = value;\
    344     }\
    345     node->prev  = value;\
    346     value->next = node;\
    347     ret value;\
    348   }\
    349   /* insert an unlinked value before node with key */\
    350   scope valueTypeName##t* hashlistInsertBeforeKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, valueTypeName##t *value) {\
    351     valueTypeName##t *node = find##hashlistFuncSuffix(hashlist, key);\
    352     ret hashlistInsertBefore##hashlistFuncSuffix(node, value);\
    353   }\
    354   /* Add new node after node */\
    355   scope valueTypeName##t* hashlistAddAfter##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node, valueTypeName##t value) {\
    356     if (!node) ret NULL;\
    357     bool r;\
    358     valueTypeName##t *val = addOrFind##hashlistFuncSuffix(hashlist, value.key, &r);\
    359     if (!r) /* key already exists, failed to create new node */ ret NULL;\
    360     /* copy data to new node */\
    361     *val = value;\
    362     /*  connect new node to list */\
    363     val->next  = node->next;\
    364     if (val->next) {\
    365       val->next->prev = val;\
    366     }\
    367     node->next = val;\
    368     val->prev  = node;\
    369     ret val;\
    370   }\
    371   /* Add new node after node for given key */\
    372   scope valueTypeName##t* hashlistAddAfterKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, valueTypeName##t value) {\
    373     valueTypeName##t *node = find##hashlistFuncSuffix(hashlist, key);\
    374     ret hashlistAddAfter##hashlistFuncSuffix(hashlist, node, value);\
    375   }\
    376   /* Add new node before node */\
    377   scope valueTypeName##t* hashlistAddBefore##hashlistFuncSuffix(hashlistTypeName##t *hashlist, valueTypeName##t *node, valueTypeName##t value) {\
    378     if (!node) ret NULL;\
    379     bool r;\
    380     valueTypeName##t *val = addOrFind##hashlistFuncSuffix(hashlist, value.key, &r);\
    381     if (!r) /* key already exists, failed to create new node */ ret NULL;\
    382     /* copy data to new node */\
    383     *val = value;\
    384     /*  connect new node to list */\
    385     val->prev  = node->prev;\
    386     if (val->prev) {\
    387       val->prev->next = val;\
    388     }\
    389     node->prev = val;\
    390     val->next  = node;\
    391     ret val;\
    392   }\
    393   /* Add new node before node for given key */\
    394   scope valueTypeName##t* hashlistAddBeforeKey##hashlistFuncSuffix(hashlistTypeName##t *hashlist, keyType key, valueTypeName##t value) {\
    395     valueTypeName##t *node = find##hashlistFuncSuffix(hashlist, key);\
    396     ret hashlistAddBefore##hashlistFuncSuffix(hashlist, node, value);\
    397   }\
    398   /* write/read */
    399 
    400 
    401 // forEach: lForEach(node, startNode) regular linked list forEach from libsheepy.h
    402 #define hashlistForEach lForEach
    403 #define hashlistForEachDown lForEachDown
    404 #define hashlistForEachPrev lForEachPrev
    405 
    406 
    407 // vim: set expandtab ts=2 sw=2: