singleList

type-safe single linked list with less memory allocations
git clone https://noulin.net/git/singleList.git
Log | Files | Refs | README | LICENSE

isingleList.h (20043B)


      1 
      2 
      3 /**
      4  * \file
      5  *
      6  * Indexed Single linked list: isingleList
      7  *
      8  * head 1 <- 2 <- 3 last
      9  *
     10  * The single linked list can be used as a stack and is not efficient when used as a queue.
     11  *
     12  * The nodes in isingleList are linked with indexes in the internal dArray, in some cases it saves memory compare to using 64 bit pointers. (isingleList is not compatible with lForEach from libsheepy.h)
     13  *
     14  * NOTE: The macros in this file are for creating list functions wrapping the macros.
     15  *
     16  * The number of nodes is defined at list declaration with the index type definition in isingleListT, the nodes are dynamically allocated in segments.
     17  *
     18  * The element type handled by the list is defined with isingleListT
     19  *
     20  * The nodes have 2 members: .elem and .prev, .elem is the element data and .prev is the index of the previous node
     21  *
     22  * use push and pop to stack nodes
     23  *
     24  * The forEach macros loop on nodes or elements from last node to head node
     25  *
     26  * use unlinkPrev or unlinkBefore and unlinkLast to unlink nodes anywhere in the list
     27  *
     28  * use insertBefore, addBefore to insert anywhere in the list, before head and push, insertLast, addLast to insert after last
     29  *
     30  * use freeUnlinked to free unlinked nodes
     31  *
     32  * use isingleListDelPrev or isingleListDelBefore, isingleListDelLast or isingleListPop to delete nodes anywhere in the list
     33  *
     34  * To create a list in reverse order, add the first node with push and then add the nodes with addBefore head
     35  *
     36  * Example:
     37  *
     38  * // define list:
     39  * isingleListT(slt, u32, u32);
     40  *
     41  * // declare list:
     42  * slt sl;
     43  *
     44  * // initialize:
     45  * isingleListInit(&sl, -1);
     46  *
     47  * // push element:
     48  * isingleListPush(&sl);
     49  * isingleListLast(&sl) = 1;
     50  *
     51  * isingleListPush(&sl);
     52  * isingleListLast(&sl) = 2;
     53  *
     54  * // head element
     55  * isingleListHead(&sl) = 0;
     56  *
     57  * // previous node for last node
     58  * u32 prev  = isingleListNodePrev(isingleListLastNode(&sl));
     59  * u32 prev2 = isingleListLastNode(&sl).prev;
     60  * u32 prev3 = isingleListLastPrevIdx(&sl);
     61  * u32 prev4 = isingleListPrevIdx(&sl, isingleListLastIdx(&sl));
     62  * isingleListNode  (&sl, prev).elem    = 4;
     63  * isingleListPrevAt(&sl, sl.last).elem = 4;
     64  *
     65  * // pointer to node
     66  * isingleListNodeType(&sl) pointer = isingleListPtr(&sl, sl.head);
     67  *
     68  * // Pop/delLast element:
     69  * isingleListPop(&sl);
     70  *
     71  * // free list
     72  * isingleListFree(&sl);
     73  */
     74 
     75 #include "libsheepyObject.h"
     76 
     77 /**
     78  * list and node definition
     79  *
     80  * indexType is the type for storing the single node indexes (size_t, u32, ...)
     81  */
     82 #define isingleListT(typeName, indexType, elementType)\
     83   /* node type */\
     84   typ struct UNIQVAR(nodet) UNIQVAR(nodet);\
     85   struct UNIQVAR(nodet) {\
     86     elementType elem;\
     87     indexType prev;\
     88   };\
     89   /* dArray storing the nodes */\
     90   dArrayT(UNIQVAR(aNodet), UNIQVAR(nodet));\
     91   /* free node list */\
     92   dArrayT(UNIQVAR(freeaNodet), indexType);\
     93   typ struct {\
     94     indexType           head; /* first node */\
     95     indexType           last; /* last node */\
     96     indexType           null; /* null value for index */\
     97     UNIQVAR(aNodet)     list; /* node dArray */\
     98     UNIQVAR(freeaNodet) freeList; /* free node dArray */\
     99     size_t              count; /* node count */\
    100   } typeName
    101 
    102 /**
    103  * initialize list
    104  *
    105  * \param
    106  *   nullValue -1 or NULL value for indexType
    107  * \return
    108  *   true success, false failed
    109  */
    110 #define isingleListInit(name, nullValue) ({\
    111   (name)->head = nullValue;\
    112   (name)->last = nullValue;\
    113   (name)->null = nullValue;\
    114   dArrayInit(&(name)->list);\
    115   dArrayInit(&(name)->freeList);\
    116   (name)->count = 0;\
    117   true;\
    118   })
    119 
    120 /**
    121  * free list
    122  * free and reset internal structures
    123  */
    124 #define isingleListFree(name) do{\
    125   dArrayFree(&(name)->list);\
    126   dArrayFree(&(name)->freeList);\
    127   (name)->head = (name)->null;\
    128   (name)->last = (name)->null;\
    129   (name)->count = 0;\
    130   } while(0)
    131 
    132 /**
    133  * node type for declaring pointers to nodes
    134  * */
    135 #define isingleListNodeType(name) dArrayElemPtrType(&(name)->list)
    136 
    137 /**
    138  * is list empty
    139  */
    140 #define isingleListIsEmpty(name) (!(name)->count)
    141 
    142 /**
    143  * element count in list
    144  */
    145 #define isingleListCount(name) (name)->count
    146 
    147 /**
    148  * push element to list (only allocates node)
    149  * use isingleListLast to access the element
    150  *
    151  * \return
    152  *  true success, false failed
    153  */
    154 #define isingleListPush(name) ({\
    155   /* steps:
    156    * check if free node is empty
    157    *  free list is empty, add a new node
    158    *  create first node
    159    *  or link to previous node
    160    * reuse a free node
    161    *  create first node
    162    *  or link to previous node
    163    */\
    164   if (dArrayIsEmpty(&(name)->freeList)) {\
    165     /* free list is empty, add a new node */\
    166     dArrayPush(&(name)->list);\
    167     if (isingleListIsEmpty(name)) {\
    168       /* first node */\
    169       dArrayLast(&(name)->list).prev = (name)->null;\
    170       (name)->head = (name)->last    = dArrayLastIndex(&(name)->list);\
    171     }\
    172     else {\
    173       /* link to previous node */\
    174       dArrayLast(&(name)->list).prev = (name)->last;\
    175       (name)->last                   = dArrayLastIndex(&(name)->list);\
    176     }\
    177   }\
    178   else {\
    179     /* reuse a free node */\
    180     if (isingleListIsEmpty(name)) {\
    181       /* first node */\
    182       dArrayAt(&(name)->list, dArrayLast(&(name)->freeList)).prev = (name)->null;\
    183       (name)->head = (name)->last = dArrayLast(&(name)->freeList);\
    184     }\
    185     else {\
    186       /* link to previous node */\
    187       dArrayAt(&(name)->list, dArrayLast(&(name)->freeList)).prev = (name)->last;\
    188       (name)->last = dArrayLast(&(name)->freeList);\
    189     }\
    190     dArrayDelLast(&(name)->freeList);\
    191   }\
    192   (name)->count++;\
    193   true;\
    194   })
    195 
    196 /**
    197  * pop element from list (only free node)
    198  *
    199  * \return
    200  *   true success, false failed: the list is empty
    201  */
    202 #define isingleListPop(name) ({\
    203   bool UNIQVAR(res) = true;\
    204   if (isingleListIsEmpty(name)) {\
    205     /* the list is empty */\
    206     UNIQVAR(res) = false;\
    207     goto UNIQVAR(ret);\
    208   }\
    209   /* free last node */\
    210   dArrayAppend(&(name)->freeList, (name)->last);\
    211   /* previous node becomes last node */\
    212   (name)->last = dArrayAt(&(name)->list, (name)->last).prev;\
    213   if ((name)->count == 1) /* the list is empty, head is gone */ (name)->head = (name)->null;\
    214   (name)->count--;\
    215   UNIQVAR(ret):\
    216   UNIQVAR(res);\
    217   })
    218 
    219 #define isingleListDelLast isingleListPop
    220 
    221 /**
    222  * unlink previous node (use pop or unlinkLast to unlink the last node)
    223  *
    224  * nodeIndex must be of type indexType
    225  *
    226  * the node can be freed with isingleListFreeUnlinked or
    227  * inserted in the list with isingleListInsertBefore or isingleListInsertLast
    228  *
    229  * \return
    230  *   unlinked node index
    231  *   null index when the list is empty or when nodeIndex is head
    232  */
    233 #define isingleListUnlinkPrev(name, nodeIndex) ({\
    234   typeof((name)->null) UNIQVAR(nodeIdx) = nodeIndex;\
    235   var                  UNIQVAR(res)     = (name)->null;\
    236   if (isingleListIsEmpty(name)) /* list is empty*/ goto UNIQVAR(ret);\
    237   if (UNIQVAR(nodeIdx) == (name)->head) {\
    238     /* node is head, there is no previous node */\
    239     goto UNIQVAR(ret);\
    240   }\
    241   /* the unlinked node is prev */\
    242   UNIQVAR(res) = dArrayAt(&(name)->list, UNIQVAR(nodeIdx)).prev;\
    243   if (UNIQVAR(res) == (name)->head) {\
    244     /* prev node is head, so nodeIndex is now head and update head */\
    245     (name)->head = UNIQVAR(nodeIdx);\
    246     dArrayAt(&(name)->list, UNIQVAR(nodeIdx)).prev = (name)->null;\
    247   }\
    248   else {\
    249     /* link previous previous node to node at nodeIndex */\
    250     dArrayAt(&(name)->list, UNIQVAR(nodeIdx)).prev = dArrayAt(&(name)->list, UNIQVAR(res)).prev;\
    251   }\
    252   (name)->count--;\
    253   UNIQVAR(ret):\
    254   UNIQVAR(res);\
    255   })
    256 
    257 #define isingleListUnlinkBefore isingleListUnlinkPrev
    258 
    259 /**
    260  * unlink last node
    261  *
    262  * the node can be freed with isingleListFreeUnlinked or
    263  * inserted in the list with isingleListInsertBefore or isingleListInsertLast
    264  *
    265  * \return
    266  *   unlinked node index
    267  *   null index when the list is empty
    268  */
    269 #define isingleListUnlinkLast(name) ({\
    270   var UNIQVAR(res) = (name)->null;\
    271   if (isingleListIsEmpty(name)) /* list is empty*/ goto UNIQVAR(ret);\
    272   /* last is unlinked */\
    273   UNIQVAR(res) = (name)->last;\
    274   /* previous node is now last */\
    275   (name)->last = isingleListLastPrevIdx(name);\
    276   (name)->count--;\
    277   /* if the list is empty set head to null */\
    278   if (isingleListIsEmpty(name)) (name)->head = (name)->null;\
    279   UNIQVAR(ret):\
    280   UNIQVAR(res);\
    281   })
    282 
    283 /**
    284  * free unlinked node
    285  *
    286  * nodeIndex must be of type indexType
    287  */
    288 #define isingleListFreeUnlinked(name, nodeIndex) dArrayAppend(&(name)->freeList, nodeIndex)
    289 
    290 /**
    291  * delete node
    292  *
    293  * nodeIndex must be of type indexType
    294  *
    295  * unlink and free node
    296  */
    297 #define isingleListDelPrev(name, nodeIndex) ({\
    298   var UNIQVAR(prev) = isingleListUnlinkPrev(name, nodeIndex);\
    299   isingleListFreeUnlinked(name, UNIQVAR(prev));\
    300   true;\
    301   })
    302 
    303 #define isingleListDelBefore isingleListDelPrev
    304 
    305 
    306 
    307 
    308 
    309 /** first element */
    310 #define isingleListFirst(name) dArrayAt(&(name)->list, (name)->head).elem
    311 #define isingleListHead isingleListFirst
    312 
    313 /** first previous node index (always null) */
    314 #define isingleListFirstPrevIdx(name) dArrayAt(&(name)->list, (name)->head).prev
    315 #define isingleListHeadPrev isingleListFirstPrev
    316 
    317 /** first node */
    318 #define isingleListFirstNode(name) dArrayAt(&(name)->list, (name)->head)
    319 #define isingleListHeadNode isingleListFirstNode
    320 
    321 /** first index */
    322 #define isingleListFirstIdx(name) (name)->head
    323 #define isingleListHeadIdx isingleListFirstIdx
    324 
    325 /** first node pointer */
    326 #define isingleListFirstPtr(name) dArrayPtr(&(name)->list, (name)->head)
    327 #define isingleListHeadPtr isingleListFirstPtr
    328 
    329 /** last element */
    330 #define isingleListLast(name) dArrayAt(&(name)->list, (name)->last).elem
    331 
    332 /** last previous node index */
    333 #define isingleListLastPrevIdx(name) dArrayAt(&(name)->list, (name)->last).prev
    334 
    335 /** last node */
    336 #define isingleListLastNode(name) dArrayAt(&(name)->list, (name)->last)
    337 
    338 /** last index */
    339 #define isingleListLastIdx(name) (name)->last
    340 
    341 /** last node pointer */
    342 #define isingleListLastPtr(name) dArrayPtr(&(name)->list, (name)->last)
    343 
    344 /** elem at node index */
    345 #define isingleListElem(name, nodeIndex) dArrayAt(&(name)->list, nodeIndex).elem
    346 
    347 /** previous index */
    348 #define isingleListPrevIdx(name, nodeIndex) dArrayAt(&(name)->list, nodeIndex).prev
    349 
    350 /** node at index */
    351 #define isingleListNode(name, nodeIndex) dArrayAt(&(name)->list, nodeIndex)
    352 
    353 /** node pointer at index */
    354 #define isingleListPtr(name, nodeIndex) dArrayPtr(&(name)->list, nodeIndex)
    355 
    356 /** node element (or use node.elem) */
    357 #define isingleListNodeElem(node) (node).elem
    358 
    359 /** previous index in node */
    360 #define isingleListNodePrev(node) (node).prev
    361 
    362 /** node element (or use node.elem) */
    363 #define isingleListNodePtrElem(node) (node)->elem
    364 
    365 /** previous index in node */
    366 #define isingleListNodePtrPrev(node) (node)->prev
    367 
    368 /** previous node at index, index must not be equal to head */
    369 #define isingleListPrevAt(name, nodeIndex) dArrayAt(&(name)->list, isingleListPrevIdx(name, nodeIndex))
    370 
    371 /** previous node */
    372 #define isingleListPrev(name, node) dArrayAt(&(name)->list, (node).prev)
    373 
    374 /** previous node pointer */
    375 #define isingleListPrevPtr(name, nodePtr) ({\
    376   dArrayElemPtrType(&(name)->list) UNIQVAR(res) = NULL;\
    377   if ((nodePtr)->prev != (name)->null) {\
    378     UNIQVAR(res) = dArrayPtr(&(name)->list, (nodePtr)->prev);\
    379   }\
    380   UNIQVAR(res);\
    381   })
    382 
    383 
    384 
    385 
    386 
    387 
    388 
    389 /** loop on indexes from last to head, to access the element use isingleListElem */
    390 #define isingleListForEachDown(name, index)\
    391   for(var index = isingleListLastIdx(name); index != (name)->null ; index = isingleListPrevIdx(name, index))
    392 
    393 /** loop node pointers from last to head, to access the elment use isingleListNodePtrElem(node) or (node)->elem */
    394 #define isingleListForEachNodeDown(name, node)\
    395   for(var node = isingleListLastPtr(name); node != NULL ; node = isingleListPrevPtr(name, node))
    396 
    397 /** loop element from last to head (the element data is copied) */
    398 #define isingleListForEachElemDown(name, element)\
    399   var UNIQVAR(idx) = isingleListLastIdx(name);\
    400   for(var element = isingleListLast(name); UNIQVAR(idx) != (name)->null ; UNIQVAR(idx) = isingleListPrevIdx(name, UNIQVAR(idx)), element = (UNIQVAR(idx) != (name)->null) ? isingleListElem(name, UNIQVAR(idx)) : element)
    401 
    402 /** loop element pointers from last to head, use *elemPtr to access the element data */
    403 #define isingleListForEachElemPDown(name, elemPtr)\
    404   var UNIQVAR(idx) = isingleListLastIdx(name);\
    405   for(var elemPtr = &isingleListLast(name); UNIQVAR(idx) != (name)->null ; UNIQVAR(idx) = isingleListPrevIdx(name, UNIQVAR(idx)), elemPtr = (UNIQVAR(idx) != (name)->null) ? &isingleListElem(name, UNIQVAR(idx)) : elemPtr)
    406 
    407 /** loop on indexes from startIndex to head, to access the element use isingleListElem */
    408 #define isingleListForEachFromDown(name, index, startIndex)\
    409   for(typeof((name)->null) index = startIndex; index != (name)->null ; index = isingleListPrevIdx(name, index))
    410 
    411 /** loop node pointers from startNode to head, to access the elment use isingleListNodePtrElem(node) or (node)->elem */
    412 #define isingleListForEachNodeFromDown(name, node, startNode)\
    413   for(isingleListNodeType(name) node = startNode; node != NULL ; node = isingleListPrevPtr(name, node))
    414 
    415 /** loop element from startIndex to head (the element data is copied) */
    416 #define isingleListForEachElemFromDown(name, element, startIndex)\
    417   typeof((name)->null) UNIQVAR(idx) = startIndex;\
    418   for(var element = isingleListLast(name); UNIQVAR(idx) != (name)->null ; UNIQVAR(idx) = isingleListPrevIdx(name, UNIQVAR(idx)), element = (UNIQVAR(idx) != (name)->null) ? isingleListElem(name, UNIQVAR(idx)) : element)
    419 
    420 /** loop element pointers from startIndex to head, use *elemPtr to access the element data */
    421 #define isingleListForEachElemPFromDown(name, elemPtr, startIndex)\
    422   typeof((name)->null) UNIQVAR(idx) = startIndex;\
    423   for(var elemPtr = &isingleListLast(name); UNIQVAR(idx) != (name)->null ; UNIQVAR(idx) = isingleListPrevIdx(name, UNIQVAR(idx)), elemPtr = (UNIQVAR(idx) != (name)->null) ? &isingleListElem(name, UNIQVAR(idx)) : elemPtr)
    424 
    425 
    426 
    427 
    428 
    429 
    430 /**
    431  * insert nodeToInsert index before referenceNode index
    432  */
    433 #define isingleListInsertBefore(name, referenceNodeIndex, nodeToInsertIndex) do{\
    434   typeof((name)->null) UNIQVAR(referenceNodeIdx)      = referenceNodeIndex;\
    435   typeof((name)->null) UNIQVAR(nodeToInsertIdx)       = nodeToInsertIndex;\
    436   /* save previous node index */\
    437   var                  UNIQVAR(tmp)                   = isingleListPrevIdx(name, UNIQVAR(referenceNodeIdx));\
    438   /* previous node in now nodeToInsert */\
    439   isingleListPrevIdx(name, UNIQVAR(referenceNodeIdx)) = UNIQVAR(nodeToInsertIdx);\
    440   /* connect rest of the list to nodeToInsert */\
    441   isingleListPrevIdx(name, UNIQVAR(nodeToInsertIdx))  = UNIQVAR(tmp);\
    442   if (UNIQVAR(tmp) == (name)->null) /* referenceNode was head node */ (name)->head = UNIQVAR(nodeToInsertIdx);\
    443   (name)->count++;\
    444   } while(0)
    445 
    446 #define isingleListInsertPrev isingleListInsertBefore
    447 
    448 /**
    449  * insert nodeToInsert index last
    450  */
    451 #define isingleListInsertLast(name, nodeToInsertIndex) do{\
    452   typeof((name)->null) UNIQVAR(nodeToInsertIdx) = nodeToInsertIndex;\
    453   if (isingleListIsEmpty(name)) {\
    454     /* list is empty, previous node is null and set both head and last */\
    455     isingleListPrevIdx(name, UNIQVAR(nodeToInsertIdx)) = (name)->null;\
    456     (name)->head = (name)->last                        = UNIQVAR(nodeToInsertIdx);\
    457   }\
    458   else {\
    459     /* last node is previous node for nodeToInsert */\
    460     isingleListPrevIdx(name, UNIQVAR(nodeToInsertIdx)) = (name)->last;\
    461     /* now last is nodeToInsert */\
    462     (name)->last                                       = UNIQVAR(nodeToInsertIdx);\
    463   }\
    464   (name)->count++;\
    465   } while(0)
    466 
    467 // // NO - cant insert before and after last
    468 // #define isingleListInsert(name, referenceNodeIndex, nodeToInsertIndex) do{\
    469 //   typeof((name)->null) UNIQVAR(refNodeIdx) = referenceNodeIndex;\
    470 //   if (UNIQVAR(refNodeIdx) != (name)->last) isingleListInsertBefore(name, UNIQVAR(refNodeIdx), nodeToInsertIndex);\
    471 //   else isingleListInsertLast(name, nodeToInsertIndex);\
    472 //   } while(0)
    473 
    474 
    475 // Internal
    476 // allocate a node
    477 #define isingleListAddNode(name) ({\
    478   typeof((name)->null) UNIQVAR(res) = (name)->null;\
    479   if (dArrayIsEmpty(&(name)->freeList)) {\
    480     /* create new node */\
    481     dArrayPush(&(name)->list);\
    482     UNIQVAR(res) = dArrayLastIndex(&(name)->list);\
    483   }\
    484   else {\
    485     /* reuse a free node */\
    486     UNIQVAR(res) = dArrayLast(&(name)->freeList);\
    487     dArrayDelLast(&(name)->freeList);\
    488   }\
    489   UNIQVAR(res);\
    490   })
    491 
    492 /**
    493  * add new node before referenceNode index
    494  *
    495  * \return
    496  *   resultNode index: access element in node with isingleListElem(name, resultNode)
    497  */
    498 #define isingleListAddBefore(name, referenceNodeIndex) ({\
    499   typeof((name)->null) UNIQVAR(res) = isingleListAddNode(name);\
    500   isingleListInsertBefore(name, referenceNodeIndex, UNIQVAR(res));\
    501   UNIQVAR(res);\
    502   })
    503 
    504 #define isingleListAddPrev isingleListAddBefore
    505 
    506 /** add new node index after last
    507  *
    508  * \return
    509  *   resultNode new node index after last (new last node)
    510  */
    511 #define isingleListAddLast(name) ({\
    512   typeof((name)->null) UNIQVAR(res) = isingleListAddNode(name);\
    513   isingleListInsertLast(name, UNIQVAR(res));\
    514   UNIQVAR(res);\
    515   })
    516 
    517 // // NO - cant insert before and after last
    518 // #define isingleListAdd(name, referenceNodeIndex) ({\
    519 //   typeof((name)->null) UNIQVAR(res) = isingleListAddNode(name);\
    520 //   isingleListInsert(name, referenceNodeIndex, UNIQVAR(res));\
    521 //   UNIQVAR(res);\
    522 //   })
    523 
    524 
    525 
    526 
    527 
    528 /**
    529  * write the isingleList content to filename file
    530  * No NULL checks are done on the parameters
    531  *
    532  * \param
    533  *    filename file name string
    534  */
    535 #define isingleListWriteFilename(name, filename) do {\
    536   FILE *UNIQVAR(f) = fopen(filename, "w");\
    537   if (UNIQVAR(f)) {\
    538     isingleListForEachDown(name, UNIQVAR(i)) {\
    539       fwrite(&isingleListElem(name, UNIQVAR(i)), 1, sizeof(isingleListElem(name, 0)), UNIQVAR(f));\
    540     }\
    541     fclose(UNIQVAR(f));\
    542   }\
    543   } while(0)
    544 
    545 /**
    546  * write the isingleList content to disk
    547  * No NULL checks are done on the parameters
    548  *
    549  * \param
    550  *    file already opened file
    551  */
    552 #define isingleListWrite(name, file) do {\
    553   isingleListForEachDown(name, UNIQVAR(i)) {\
    554     fwrite(&isingleListElem(name, UNIQVAR(i)), 1, sizeof(isingleListElem(name, 0)), file);\
    555   }\
    556   } while(0)
    557 
    558 /**
    559  * read a isingleList from filename file
    560  * No NULL checks are done on the parameters
    561  *
    562  * \param
    563  * filename file name string
    564  */
    565 #define isingleListReadFilename(name, filename) do {\
    566   if (fileExists(filename)) {\
    567     size_t UNIQVAR(sz) = fileSize(filename);\
    568     const size_t UNIQVAR(elemSz) = sizeof(isingleListElem(name, 0));\
    569     if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\
    570     UNIQVAR(sz) /= UNIQVAR(elemSz);\
    571     if (!UNIQVAR(sz)) /* there is no element to load*/ break;\
    572     FILE *UNIQVAR(f) = fopen(filename, "r");\
    573     if (UNIQVAR(f)) {\
    574       isingleListPush(name);\
    575       fread(&isingleListLast(name), 1, UNIQVAR(elemSz), UNIQVAR(f));\
    576       typeof((name)->null) UNIQVAR(insertBefore) = (name)->last;\
    577       range(UNIQVAR(i), UNIQVAR(sz)-1) {\
    578         UNIQVAR(insertBefore) = isingleListAddBefore(name, UNIQVAR(insertBefore));\
    579         fread(&isingleListElem(name, UNIQVAR(insertBefore)), 1, UNIQVAR(elemSz), UNIQVAR(f));\
    580       }\
    581       fclose(UNIQVAR(f));\
    582     }\
    583   }\
    584   } while(0)
    585 
    586 /**
    587  * read a isingleList from disk
    588  * No NULL checks are done on the parameters
    589  *
    590  * \param
    591  *    file already opened file
    592  */
    593 #define isingleListRead(name, file) do {\
    594   fseek(file, 0 , SEEK_END);\
    595   size_t UNIQVAR(sz) = ftell(file);\
    596   fseek(file, 0 , SEEK_SET);\
    597   const size_t UNIQVAR(elemSz) = sizeof(isingleListElem(name, 0));\
    598   if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\
    599   UNIQVAR(sz) /= UNIQVAR(elemSz);\
    600   if (!UNIQVAR(sz)) /* there is no element to load*/ break;\
    601   isingleListPush(name);\
    602   fread(&isingleListLast(name), 1, UNIQVAR(elemSz), file);\
    603   typeof((name)->null) UNIQVAR(insertBefore) = (name)->last;\
    604   range(UNIQVAR(i), UNIQVAR(sz)-1) {\
    605     UNIQVAR(insertBefore) = isingleListAddBefore(name, UNIQVAR(insertBefore));\
    606     fread(&isingleListElem(name, UNIQVAR(insertBefore)), 1, UNIQVAR(elemSz), file);\
    607   }\
    608   } while(0)
    609 
    610 // vim: set expandtab ts=2 sw=2: