💾 Archived View for gmi.noulin.net › gitRepositories › staticList › file › staticList.h.gmi captured on 2023-07-10 at 15:56:16. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

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

staticList

Log

Files

Refs

LICENSE

staticList.h (13028B)

     1 
     2 /**
     3  * \file
     4  *
     5  * Static double linked list
     6  *
     7  * NOTE: The macros in this file are for creating list functions wrapping the macros.
     8  *    The parameters to these macros should be variables to avoid wrong computation
     9  *    and infinite loops.
    10  *    Example:
    11  *    staticListDelNode(list, list.head) fails because list.head changes value during the
    12  *    macro execution.
    13  *
    14  * The number of nodes is defined at list declaration, all the nodes are preallocated.
    15  * The heap is not used, there is no malloc, realloc or free.
    16  *
    17  * The status of the macros is saved (list).res and is set to true when the operation is success and
    18  * false when the operation is failure.
    19  *
    20  * The element type handled by the list is defined with staticListT
    21  *
    22  * Example:
    23  *
    24  * define list:
    25  * staticListT(slt, u32, 3);
    26  *
    27  * declare list:
    28  * slt sl;
    29  *
    30  * initialize:
    31  * staticListInit(sl);
    32  *
    33  * push element:
    34  * staticListPush(sl);
    35  * staticListLast(sl) = 1;
    36  *
    37  * Pop/dellast element:
    38  * staticListPop(sl);
    39  */
    40 
    41 #include "libsheepyObject.h"
    42 
    43 /**
    44  * list and node definition
    45  *
    46  * MAXCOUNT is the list capacity
    47  */
    48 #define staticListT(typeName, elementType, MAXCOUNT)\
    49   typ struct UNIQVAR(nodet) UNIQVAR(nodet);\
    50   struct UNIQVAR(nodet) {\
    51     elementType elem;\
    52     UNIQVAR(nodet) *prev;\
    53     UNIQVAR(nodet) *next;\
    54   };\
    55   staticArrayT(UNIQVAR(aNodet), UNIQVAR(nodet), MAXCOUNT);\
    56   staticArrayT(UNIQVAR(freeaNodet), UNIQVAR(nodet)*, MAXCOUNT);\
    57   typ struct {\
    58     UNIQVAR(nodet)      *head;\
    59     UNIQVAR(nodet)      *last;\
    60     UNIQVAR(aNodet)     list;\
    61     UNIQVAR(freeaNodet) freeList;\
    62     bool                res;\
    63   } typeName
    64 
    65 /**
    66  * initialize list
    67  *
    68  * \return
    69  *  (name).res true success, false failed
    70  */
    71 #define staticListInit(name) do{\
    72     (name).head = (name).last = NULL;\
    73     staticArrayInit((name).list)\
    74     staticArrayInit((name).freeList);\
    75     (name).res  = true;\
    76   } while(0)
    77 
    78 /**
    79  * node type for declaring pointers to nodes
    80  *
    81  * Example:
    82  * staticListNodeType(name) node;
    83  * staticListUnlink(name, node);
    84  * */
    85 #define staticListNodeType(name) typeof((name).head)
    86 
    87 /**
    88  * is list empty
    89  */
    90 #define staticListIsEmpty(name) (staticArrayIsEmpty((name).list) || staticArrayIsFull((name).freeList))
    91 
    92 /**
    93  * is list full
    94  */
    95 #define staticListIsFull(name) (staticArrayIsFull((name).list) && staticArrayIsEmpty((name).freeList))
    96 
    97 /**
    98  * push element to list (only allocates node)
    99  * use staticListLast to access the element
   100  *
   101  * \return
   102  *  (name).res true success, false failed
   103  */
   104 #define staticListPush(name) do{\
   105   if (staticArrayIsEmpty((name).freeList)) {\
   106     if (staticArrayIsFull((name).list)) {\
   107       /* the list is full */\
   108       (name).res = false;\
   109       break;\
   110     }\
   111     staticArrayPush((name).list);\
   112     if (!(name).last) {\
   113       /* first node */\
   114       staticArrayLast((name).list).prev = NULL;\
   115       staticArrayLast((name).list).next = NULL;\
   116       (name).head                = &staticArrayLast((name).list);\
   117       (name).last                = &staticArrayLast((name).list);\
   118     }\
   119     else {\
   120       /* link to previous node */\
   121       staticArrayLast((name).list).prev = (name).last;\
   122       (name).last->next                 = &staticArrayLast((name).list);\
   123       staticArrayLast((name).list).next = NULL;\
   124       (name).last                       = &staticArrayLast((name).list);\
   125     }\
   126   }\
   127   else {\
   128     /* reuse a free node */\
   129     if (!(name).last) {\
   130       staticArrayLast((name).freeList)->prev = NULL;\
   131       staticArrayLast((name).freeList)->next = NULL;\
   132       (name).head                = staticArrayLast((name).freeList);\
   133       (name).last                = staticArrayLast((name).freeList);\
   134     }\
   135     else {\
   136       staticArrayLast((name).freeList)->prev = (name).last;\
   137       (name).last->next                                                  = staticArrayLast((name).freeList);\
   138       staticArrayLast((name).freeList)->next = NULL;\
   139       (name).last                                                        = staticArrayLast((name).freeList);\
   140     }\
   141     staticArrayPop((name).freeList);\
   142   }\
   143   (name).res = true;\
   144   } while(0)
   145 
   146 /**
   147  * pop element from list (only free node)
   148  *
   149  * \return
   150  *  (name).res true success, false failed: the list is empty
   151  */
   152 #define staticListPop(name) do{\
   153   if (!(name).last) {\
   154     /* the list is empty */\
   155     (name).res = false;\
   156     break;\
   157   }\
   158   staticArrayPush((name).freeList);\
   159   staticArrayLast((name).freeList) = (name).last;\
   160   (name).last                      = (name).last->prev;\
   161   if ((name).last) (name).last->next = NULL;\
   162   if (!(name).last) /* the list is empty */ (name).head = NULL;\
   163   (name).res = true;\
   164   } while(0)
   165 
   166 #define staticListDelLast staticListPop
   167 
   168 /**
   169  * unlink node
   170  *
   171  * node must be of type staticListNodeType(name)
   172  *
   173  * the node can be freed with staticListFreeUnlinked or
   174  * inserted in the list with staticListInsertAfter or staticListInsertBefore
   175  */
   176 #define staticListUnlink(name, node) do{\
   177   if (!(node)->prev) {\
   178     /* node is head */\
   179     (name).head = (node)->next;\
   180   }\
   181   else {\
   182     (node)->prev->next = (node)->next;\
   183   }\
   184   if (!(node)->next) {\
   185     /* node is last */\
   186     (name).last = (node)->prev;\
   187   }\
   188   else {\
   189     (node)->next->prev = (node)->prev;\
   190   }\
   191   } while(0)
   192 
   193 /**
   194  * free unlinked node
   195  *
   196  * node must be of type staticListNodeType(name)
   197  */
   198 #define staticListFreeUnlinked(name, node) do{\
   199   staticArrayPush((name).freeList);\
   200   staticArrayLast((name).freeList) = node;\
   201   } while(0)
   202 
   203 /**
   204  * delete node
   205  *
   206  * node must be of type staticListNodeType(name)
   207  *
   208  * unlink and free node
   209  */
   210 #define staticListDelNode(name, node) do{\
   211   staticListUnlink(name, node);\
   212   staticListFreeUnlinked(name, node);\
   213   (name).res = true;\
   214   } while(0)
   215 
   216 /** first element */
   217 #define staticListFirst(name) (name).head->elem
   218 
   219 /** first node pointer */
   220 #define staticListFirstNode(name) (name).head
   221 #define staticListHeadNode staticListFirstNode
   222 
   223 /** last element */
   224 #define staticListLast(name) (name).last->elem
   225 
   226 /** last node pointer */
   227 #define staticListLasttNode(name) (name).last
   228 
   229 /** previous node */
   230 #define staticListPrev(node) (node)->prev
   231 
   232 /** next node */
   233 #define staticListNext(node) (node)->next
   234 
   235 /** node element (or use node->elem) */
   236 #define staticListGetElem(node) (node)->elem
   237 
   238 /**
   239  * swap node1 with node2
   240  *
   241  * \return
   242  *  (name).res true success, false failed
   243  */
   244 #define staticListSwap(name, node1, node2) do{\
   245   /* disable sanity checks to keep it simple - if (!node1 or !node2) {*/\
   246   /*  (name).res = false;*/\
   247   /*  break;*/\
   248   /*}*/\
   249   (name).res = true;\
   250   if (node1 == node2) /* node1 and node2 are the same node, nothing to do */ break;\
   251   var UNIQVAR(tmp)    = (node1)->next;\
   252   (node1)->next       = (node2)->next;\
   253   (node2)->next       = UNIQVAR(tmp);\
   254   if (!(node1)->next) (name).last = node1;\
   255   else (node1)->next->prev = node1;\
   256   if (!(node2)->next) (name).last = node2;\
   257   else (node2)->next->prev = node2;\
   258   UNIQVAR(tmp)        = (node1)->prev;\
   259   (node1)->prev       = (node2)->prev;\
   260   (node2)->prev       = UNIQVAR(tmp);\
   261   if (!(node1)->prev) (name).head = node1;\
   262   else (node1)->prev->next = node1;\
   263   if (!(node2)->prev) (name).head = node2;\
   264   else (node2)->prev->next = node2;\
   265   } while(0)
   266 
   267 /** loop from head to last */
   268 #define staticListForEach(name, node)\
   269   for(var node = (name).head; node ; node = staticListNext(node))
   270 
   271 /** loop from last to head */
   272 #define staticListForEachDown(name, node)\
   273   for(var node = (name).last; node ; node = staticListPrev(node))
   274 
   275 /** loop from startNode to last */
   276 #define staticListForEachFrom(node, startNode)\
   277   for(var node = startNode; node ; node = (node)->next)
   278 
   279 /** loop from startNode to head */
   280 #define staticListForEachFromDown(node, startNode)\
   281   for(var node = startNode; node ; node = (node)->prev)
   282 
   283 /**
   284  * insert nodeToInsert after referenceNode
   285  *
   286  * nodeToInsert and referenceNode must be of type staticListNodeType(name)
   287  */
   288 #define staticListInsertAfter(name, referenceNode, nodeToInsert) do{\
   289   (nodeToInsert)->next  = referenceNode->next;\
   290   referenceNode->next   = nodeToInsert;\
   291   (nodeToInsert)->prev  = referenceNode;\
   292   if ((nodeToInsert)->next) {\
   293     (nodeToInsert)->next->prev = nodeToInsert;\
   294   }\
   295   else {\
   296     /* referenceNode was last node */\
   297     (name).last = nodeToInsert;\
   298   }\
   299   } while(0)
   300 
   301 /**
   302  * insert nodeToInsert before referenceNode
   303  *
   304  * nodeToInsert and referenceNode must be of type staticListNodeType(name)
   305  */
   306 #define staticListInsertBefore(name, referenceNode, nodeToInsert) do{\
   307   (nodeToInsert)->prev  = referenceNode->prev;\
   308   referenceNode->prev   = nodeToInsert;\
   309   (nodeToInsert)->next  = referenceNode;\
   310   if ((nodeToInsert)->prev) {\
   311     (nodeToInsert)->prev->next = nodeToInsert;\
   312   }\
   313   else {\
   314     /* referenceNode was head node */\
   315     (name).head = nodeToInsert;\
   316   }\
   317   } while(0)
   318 
   319 
   320 // Internal
   321 // allocate a node
   322 // true success, false failed: list is full
   323 #define staticListAddNode(name, resultNode) do{\
   324   if (staticArrayIsEmpty((name).freeList)) {\
   325     if (staticArrayIsFull((name).list)) {\
   326       /* the list is full */\
   327       (name).res = false;\
   328       break;\
   329     }\
   330     staticArrayPush((name).list);\
   331     resultNode = &staticArrayLast((name).list);\
   332   }\
   333   else {\
   334     /* reuse a free node */\
   335     resultNode = staticArrayLast((name).freeList);\
   336     staticArrayPop((name).freeList);\
   337   }\
   338   (name).res = true;\
   339   } while(0)
   340 
   341 /**
   342  * add new node after referenceNode
   343  *
   344  * resultNode and referenceNode must be of type staticListNodeType(name)
   345  *
   346  * \return
   347  *   resultNode access element in node with resultNode->elem or staticListGetElem(resultNode)
   348  */
   349 #define staticListAddAfter(name, referenceNode, resultNode) do{\
   350   staticListAddNode(name, resultNode);\
   351   if (!(name).res) /* list is full, return false */ break;\
   352   (resultNode)->next  = referenceNode->next;\
   353   referenceNode->next = resultNode;\
   354   (resultNode)->prev  = referenceNode;\
   355   if ((resultNode)->next) {\
   356     (resultNode)->next->prev = resultNode;\
   357   }\
   358   else {\
   359     /* referenceNode was last node */\
   360     (name).last = resultNode;\
   361   }\
   362   } while(0)
   363 
   364 /**
   365  * add new node before referenceNode
   366  *
   367  * resultNode and referenceNode must be of type staticListNodeType(name)
   368  *
   369  * \return
   370  *   resultNode access element in node with resultNode->elem or staticListGetElem(resultNode)
   371  */
   372 #define staticListAddBefore(name, referenceNode, resultNode) do{\
   373   staticListAddNode(name, resultNode);\
   374   if (!(name).res) /* list is full, return false */ break;\
   375   (resultNode)->prev  = referenceNode->prev;\
   376   referenceNode->prev = resultNode;\
   377   (resultNode)->next  = referenceNode;\
   378   if ((resultNode)->prev) {\
   379     (resultNode)->prev->next = resultNode;\
   380   }\
   381   else {\
   382     /* referenceNode was head node */\
   383     (name).head = resultNode;\
   384   }\
   385   } while(0)
   386 
   387 /**
   388  * write the staticList content to filename file
   389  * No NULL checks are done on the parameters
   390  *
   391  * \param
   392  *    filename file name string
   393  */
   394 #define staticListWriteFilename(name, filename) do {\
   395   FILE *UNIQVAR(f) = fopen(filename, "w");\
   396   if (UNIQVAR(f)) {\
   397     staticListForEach(name, UNIQVAR(node)) {\
   398       fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), UNIQVAR(f));\
   399     }\
   400     fclose(UNIQVAR(f));\
   401   }\
   402   } while(0)
   403 
   404 /**
   405  * write the staticList content to disk
   406  * No NULL checks are done on the parameters
   407  *
   408  * \param
   409  *    file already opened file
   410  */
   411 #define staticListWrite(name, file) do {\
   412   staticListForEach(name, UNIQVAR(node)) {\
   413     fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), file);\
   414   }\
   415   } while(0)
   416 
   417 /**
   418  * read a staticList from filename file
   419  * No NULL checks are done on the parameters
   420  *
   421  * \param
   422  * filename file name string
   423  */
   424 #define staticListReadFilename(name, filename) do {\
   425   if (fileExists(filename)) {\
   426     size_t UNIQVAR(sz) = fileSize(filename);\
   427     const size_t UNIQVAR(elemSz) = sizeof(staticArrayLast((name).list).elem);\
   428     if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\
   429     UNIQVAR(sz) /= UNIQVAR(elemSz);\
   430     if (UNIQVAR(sz) > (size_t)(name).list.maxCount) /* file size exceeds capacity */ break;\
   431     FILE *UNIQVAR(f) = fopen(filename, "r");\
   432     if (UNIQVAR(f)) {\
   433       range(UNIQVAR(i), UNIQVAR(sz)) {\
   434         staticListPush(name);\
   435         fread(&staticListLast(name), 1, UNIQVAR(elemSz), UNIQVAR(f));\
   436       }\
   437       fclose(UNIQVAR(f));\
   438     }\
   439   }\
   440   } while(0)
   441 
   442 /**
   443  * read a staticList from disk
   444  * No NULL checks are done on the parameters
   445  *
   446  * \param
   447  *    file already opened file
   448  */
   449 #define staticListRead(name, file) do {\
   450   fseek(file, 0 , SEEK_END);\
   451   size_t UNIQVAR(sz) = ftell(file);\
   452   fseek(file, 0 , SEEK_SET);\
   453   const size_t UNIQVAR(elemSz) = sizeof(staticArrayLast((name).list).elem);\
   454   if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\
   455   UNIQVAR(sz) /= UNIQVAR(elemSz);\
   456   if (UNIQVAR(sz) > (size_t)(name).list.maxCount) /* file size exceeds capacity */ break;\
   457   range(UNIQVAR(i), UNIQVAR(sz)) {\
   458     staticListPush(name);\
   459     fread(&staticListLast(name), 1, UNIQVAR(elemSz), file);\
   460   }\
   461   } while(0)