💾 Archived View for gmi.noulin.net › gitRepositories › linkedList › file › linkedList.h.gmi captured on 2024-07-09 at 02:21:31. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

linkedList

Log

Files

Refs

README

LICENSE

linkedList.h (11521B)

     1 
     2 /**
     3  * \file
     4  *
     5  * double linked list: llist
     6  *
     7  * The nodes in llist are linked with pointers and dynamically allocated in segments
     8  *
     9  * The element type handled by the list is defined with llistT
    10  *
    11  *
    12  * Example:
    13  *
    14  * // define list:
    15  * llistT(llt, u32);
    16  *
    17  * // declare list:
    18  * llt ll;
    19  *
    20  * // initialize:
    21  * llistInit(&ll);
    22  *
    23  * // push element:
    24  * llistPush(&ll);
    25  * llistLast(&ll) = 1;
    26  *
    27  * // Pop/dellast element:
    28  * llistPop(&ll);
    29  *
    30  * // Free
    31  * llistFree(&ll);
    32  *
    33  * TODO create linkedList without head and last
    34  */
    35 
    36 #include "libsheepyObject.h"
    37 
    38 /**
    39  * list and node definition
    40  */
    41 #define llistT(typeName, elementType)\
    42   typ struct UNIQVAR(nodet) UNIQVAR(nodet);\
    43   struct UNIQVAR(nodet) {\
    44     elementType elem;\
    45     UNIQVAR(nodet) *prev;\
    46     UNIQVAR(nodet) *next;\
    47   };\
    48   dArrayT(UNIQVAR(aNodet), UNIQVAR(nodet));\
    49   dArrayT(UNIQVAR(freeaNodet), UNIQVAR(nodet)*);\
    50   typ struct {\
    51     UNIQVAR(nodet)      *head;\
    52     UNIQVAR(nodet)      *last;\
    53     UNIQVAR(aNodet)     list;\
    54     UNIQVAR(freeaNodet) freeList;\
    55   } typeName
    56 
    57 /**
    58  * initialize list
    59  */
    60 #define llistInit(name) do{\
    61     (name)->head = (name)->last = NULL;\
    62     dArrayInit(&(name)->list);\
    63     dArrayInit(&(name)->freeList);\
    64   } while(0)
    65 
    66 /**
    67  * free list
    68  */
    69 #define llistFree(name) do{\
    70     dArrayFree(&(name)->list);\
    71     dArrayFree(&(name)->freeList);\
    72     (name)->head = (name)->last = NULL;\
    73   } while(0)
    74 
    75 /**
    76  * node type for declaring pointers to nodes
    77  *
    78  * Example:
    79  * llistNodeType(name) node;
    80  * llistUnlink(name, node);
    81  * */
    82 #define llistNodeType(name) typeof((name)->head)
    83 
    84 /**
    85  * element count in list
    86  */
    87 #define llistCount(name) (dArrayCount(&(name)->list) - dArrayCount(&(name)->freeList))
    88 
    89 
    90 /**
    91  * is list empty
    92  */
    93 #define llistIsEmpty(name) ((name)->head == NULL)
    94 
    95 /**
    96  * push element to list (only allocates node)
    97  * use llistLast to access the element
    98  */
    99 #define llistPush(name) do{\
   100   if (dArrayIsEmpty(&(name)->freeList)) {\
   101     dArrayPush(&(name)->list);\
   102     if (!(name)->last) {\
   103       /* first node */\
   104       dArrayLast(&(name)->list).prev = NULL;\
   105       dArrayLast(&(name)->list).next = NULL;\
   106       (name)->head                   = &dArrayLast(&(name)->list);\
   107       (name)->last                   = &dArrayLast(&(name)->list);\
   108     }\
   109     else {\
   110       /* link to previous node */\
   111       dArrayLast(&(name)->list).prev = (name)->last;\
   112       (name)->last->next             = &dArrayLast(&(name)->list);\
   113       dArrayLast(&(name)->list).next = NULL;\
   114       (name)->last                   = &dArrayLast(&(name)->list);\
   115     }\
   116   }\
   117   else {\
   118     /* reuse a free node */\
   119     if (!(name)->last) {\
   120       dArrayLast(&(name)->freeList)->prev = NULL;\
   121       dArrayLast(&(name)->freeList)->next = NULL;\
   122       (name)->head                        = dArrayLast(&(name)->freeList);\
   123       (name)->last                        = dArrayLast(&(name)->freeList);\
   124     }\
   125     else {\
   126       dArrayLast(&(name)->freeList)->prev = (name)->last;\
   127       (name)->last->next                  = dArrayLast(&(name)->freeList);\
   128       dArrayLast(&(name)->freeList)->next = NULL;\
   129       (name)->last                        = dArrayLast(&(name)->freeList);\
   130     }\
   131     dArrayDelLast(&(name)->freeList);\
   132   }\
   133   } while(0)
   134 
   135 /**
   136  * pop element from list (only free node)
   137  *
   138  * \return
   139  *  true success, false failed: the list is empty
   140  */
   141 #define llistPop(name) ({\
   142   bool UNIQVAR(r) = true;\
   143   if (!(name)->last) {\
   144     /* the list is empty */\
   145     UNIQVAR(r) = false;\
   146     goto UNIQVAR(end);\
   147   }\
   148   dArrayPush(&(name)->freeList);\
   149   dArrayLast(&(name)->freeList) = (name)->last;\
   150   (name)->last                      = (name)->last->prev;\
   151   if ((name)->last) (name)->last->next = NULL;\
   152   if (!(name)->last) /* the list is empty */ (name)->head = NULL;\
   153   UNIQVAR(end):\
   154   UNIQVAR(r);\
   155   })
   156 
   157 #define llistDelLast llistPop
   158 
   159 /**
   160  * unlink node
   161  *
   162  * node must be of type llistNodeType(name)
   163  *
   164  * the node can be freed with llistFreeUnlinked or
   165  * inserted in the list with llistInsertAfter or llistInsertBefore
   166  */
   167 #define llistUnlink(name, node) do{\
   168   if (!(node)->prev) {\
   169     /* node is head */\
   170     (name)->head = (node)->next;\
   171   }\
   172   else {\
   173     (node)->prev->next = (node)->next;\
   174   }\
   175   if (!(node)->next) {\
   176     /* node is last */\
   177     (name)->last = (node)->prev;\
   178   }\
   179   else {\
   180     (node)->next->prev = (node)->prev;\
   181   }\
   182   } while(0)
   183 
   184 /**
   185  * free unlinked node
   186  *
   187  * node must be of type llistNodeType(name)
   188  */
   189 #define llistFreeUnlinked(name, node) do{\
   190   dArrayPush(&(name)->freeList);\
   191   dArrayLast(&(name)->freeList) = node;\
   192   } while(0)
   193 
   194 /**
   195  * delete node
   196  *
   197  * node must be of type llistNodeType(name)
   198  *
   199  * unlink and free node
   200  */
   201 #define llistDelNode(name, node) do{\
   202   llistUnlink(name, node);\
   203   llistFreeUnlinked(name, node);\
   204   } while(0)
   205 
   206 /** first element */
   207 #define llistFirst(name) (name)->head->elem
   208 
   209 /** first node pointer */
   210 #define llistFirstNode(name) (name)->head
   211 #define llistHeadNode llistFirstNode
   212 
   213 /** last element */
   214 #define llistLast(name) (name)->last->elem
   215 
   216 /** last node pointer */
   217 #define llistLastNode(name) (name)->last
   218 
   219 /** previous node */
   220 #define llistPrev(node) (node)->prev
   221 
   222 /** next node */
   223 #define llistNext(node) (node)->next
   224 
   225 /** node element (or use node->elem) */
   226 #define llistGetElem(node) (node)->elem
   227 
   228 /**
   229  * swap node1 with node2
   230  */
   231 #define llistSwap(name, node1, node2) do{\
   232   /* disable sanity checks to keep it simple - if (!node1 or !node2) {*/\
   233   /*  return value instead --- (name)->res = false;*/\
   234   /*  break;*/\
   235   /*}*/\
   236   if (node1 == node2) /* node1 and node2 are the same node, nothing to do */ break;\
   237   var UNIQVAR(tmp)    = (node1)->next;\
   238   (node1)->next       = (node2)->next;\
   239   (node2)->next       = UNIQVAR(tmp);\
   240   if (!(node1)->next) (name)->last = node1;\
   241   else (node1)->next->prev = node1;\
   242   if (!(node2)->next) (name)->last = node2;\
   243   else (node2)->next->prev = node2;\
   244   UNIQVAR(tmp)        = (node1)->prev;\
   245   (node1)->prev       = (node2)->prev;\
   246   (node2)->prev       = UNIQVAR(tmp);\
   247   if (!(node1)->prev) (name)->head = node1;\
   248   else (node1)->prev->next = node1;\
   249   if (!(node2)->prev) (name)->head = node2;\
   250   else (node2)->prev->next = node2;\
   251   } while(0)
   252 
   253 /** loop from head to last */
   254 #define llistForEach(name, node)\
   255   for(var node = (name)->head; node ; node = llistNext(node))
   256 
   257 /** loop from last to head */
   258 #define llistForEachDown(name, node)\
   259   for(var node = (name)->last; node ; node = llistPrev(node))
   260 
   261 /** loop from startNode to last */
   262 #define llistForEachFrom(node, startNode)\
   263   for(var node = startNode; node ; node = (node)->next)
   264 
   265 /** loop from startNode to head */
   266 #define llistForEachFromDown(node, startNode)\
   267   for(var node = startNode; node ; node = (node)->prev)
   268 
   269 /**
   270  * insert nodeToInsert after referenceNode
   271  *
   272  * nodeToInsert and referenceNode must be of type llistNodeType(name)
   273  */
   274 #define llistInsertAfter(name, referenceNode, nodeToInsert) do{\
   275   (nodeToInsert)->next  = referenceNode->next;\
   276   referenceNode->next   = nodeToInsert;\
   277   (nodeToInsert)->prev  = referenceNode;\
   278   if ((nodeToInsert)->next) {\
   279     (nodeToInsert)->next->prev = nodeToInsert;\
   280   }\
   281   else {\
   282     /* referenceNode was last node */\
   283     (name)->last = nodeToInsert;\
   284   }\
   285   } while(0)
   286 
   287 /**
   288  * insert nodeToInsert before referenceNode
   289  *
   290  * nodeToInsert and referenceNode must be of type llistNodeType(name)
   291  */
   292 #define llistInsertBefore(name, referenceNode, nodeToInsert) do{\
   293   (nodeToInsert)->prev  = referenceNode->prev;\
   294   referenceNode->prev   = nodeToInsert;\
   295   (nodeToInsert)->next  = referenceNode;\
   296   if ((nodeToInsert)->prev) {\
   297     (nodeToInsert)->prev->next = nodeToInsert;\
   298   }\
   299   else {\
   300     /* referenceNode was head node */\
   301     (name)->head = nodeToInsert;\
   302   }\
   303   } while(0)
   304 
   305 
   306 // Internal
   307 // allocate a node
   308 #define llistAddNode(name, resultNode) do{\
   309   if (dArrayIsEmpty(&(name)->freeList)) {\
   310     dArrayPush(&(name)->list);\
   311     resultNode = &dArrayLast(&(name)->list);\
   312   }\
   313   else {\
   314     /* reuse a free node */\
   315     resultNode = dArrayLast(&(name)->freeList);\
   316     dArrayPop(&(name)->freeList);\
   317   }\
   318   } while(0)
   319 
   320 /**
   321  * add new node after referenceNode
   322  *
   323  * resultNode and referenceNode must be of type llistNodeType(name)
   324  *
   325  * \return
   326  *   resultNode access element in node with resultNode->elem or llistGetElem(resultNode)
   327  */
   328 #define llistAddAfter(name, referenceNode, resultNode) do{\
   329   llistAddNode(name, resultNode);\
   330   (resultNode)->next  = referenceNode->next;\
   331   referenceNode->next = resultNode;\
   332   (resultNode)->prev  = referenceNode;\
   333   if ((resultNode)->next) {\
   334     (resultNode)->next->prev = resultNode;\
   335   }\
   336   else {\
   337     /* referenceNode was last node */\
   338     (name)->last = resultNode;\
   339   }\
   340   } while(0)
   341 
   342 /**
   343  * add new node before referenceNode
   344  *
   345  * resultNode and referenceNode must be of type llistNodeType(name)
   346  *
   347  * \return
   348  *   resultNode access element in node with resultNode->elem or llistGetElem(resultNode)
   349  */
   350 #define llistAddBefore(name, referenceNode, resultNode) do{\
   351   llistAddNode(name, resultNode);\
   352   (resultNode)->prev  = referenceNode->prev;\
   353   referenceNode->prev = resultNode;\
   354   (resultNode)->next  = referenceNode;\
   355   if ((resultNode)->prev) {\
   356     (resultNode)->prev->next = resultNode;\
   357   }\
   358   else {\
   359     /* referenceNode was head node */\
   360     (name)->head = resultNode;\
   361   }\
   362   } while(0)
   363 
   364 /**
   365  * write the llist content to filename file
   366  * No NULL checks are done on the parameters
   367  *
   368  * \param
   369  *    filename file name string
   370  */
   371 #define llistWriteFilename(name, filename) do {\
   372   FILE *UNIQVAR(f) = fopen(filename, "w");\
   373   if (UNIQVAR(f)) {\
   374     llistForEach(name, UNIQVAR(node)) {\
   375       fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), UNIQVAR(f));\
   376     }\
   377     fclose(UNIQVAR(f));\
   378   }\
   379   } while(0)
   380 
   381 /**
   382  * write the llist content to disk
   383  * No NULL checks are done on the parameters
   384  *
   385  * \param
   386  *    file already opened file
   387  */
   388 #define llistWrite(name, file) do {\
   389   llistForEach(name, UNIQVAR(node)) {\
   390     fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), file);\
   391   }\
   392   } while(0)
   393 
   394 /**
   395  * read a llist from filename file
   396  * No NULL checks are done on the parameters
   397  *
   398  * \param
   399  * filename file name string
   400  */
   401 #define llistReadFilename(name, filename) do {\
   402   if (fileExists(filename)) {\
   403     size_t UNIQVAR(sz) = fileSize(filename);\
   404     const size_t UNIQVAR(elemSz) = sizeof(dArrayLast(&(name)->list).elem);\
   405     if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\
   406     UNIQVAR(sz) /= UNIQVAR(elemSz);\
   407     if (UNIQVAR(sz) > (size_t)(name)->list.maxCount) /* file size exceeds capacity */ break;\
   408     FILE *UNIQVAR(f) = fopen(filename, "r");\
   409     if (UNIQVAR(f)) {\
   410       range(UNIQVAR(i), UNIQVAR(sz)) {\
   411         llistPush(name);\
   412         fread(&llistLast(name), 1, UNIQVAR(elemSz), UNIQVAR(f));\
   413       }\
   414       fclose(UNIQVAR(f));\
   415     }\
   416   }\
   417   } while(0)
   418 
   419 /**
   420  * read a llist from disk
   421  * No NULL checks are done on the parameters
   422  *
   423  * \param
   424  *    file already opened file
   425  */
   426 #define llistRead(name, file) do {\
   427   fseek(file, 0 , SEEK_END);\
   428   size_t UNIQVAR(sz) = ftell(file);\
   429   fseek(file, 0 , SEEK_SET);\
   430   const size_t UNIQVAR(elemSz) = sizeof(dArrayLast(&(name)->list).elem);\
   431   if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\
   432   UNIQVAR(sz) /= UNIQVAR(elemSz);\
   433   if (UNIQVAR(sz) > (size_t)(name)->list.maxCount) /* file size exceeds capacity */ break;\
   434   range(UNIQVAR(i), UNIQVAR(sz)) {\
   435     llistPush(name);\
   436     fread(&llistLast(name), 1, UNIQVAR(elemSz), file);\
   437   }\
   438   } while(0)
   439