linkedList

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

commit 1bf0d006195fcb9dc0dcb4f22222d48a0d30dc16
parent c2977d13051faf15b978b3d647e2141f2d5a5444
Author: Remy Noulin <loader2x@gmail.com>
Date:   Tue, 25 Dec 2018 14:55:43 +0100

add llist and lliste (external store) linked lists

.gitignore    |  11 ++
README.md     |  19 ++-
linkedList.h  | 440 +++++++++++++++++++++++++++++++++++++++++++++++++
linkedListe.h | 515 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main.c        |  84 ++++++++++
package.yml   |  31 ++++
6 files changed, 1099 insertions(+), 1 deletion(-)

Diffstat:
M.gitignore | 11+++++++++++
MREADME.md | 19++++++++++++++++++-
AlinkedList.h | 440+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AlinkedListe.h | 515+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amain.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apackage.yml | 31+++++++++++++++++++++++++++++++
6 files changed, 1099 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,14 @@ +# Vim +*.sw* + +# Debug +.gdb_history + +# Coverage +*.gcov +*.gcda +*.gcno + # Prerequisites *.d diff --git a/README.md b/README.md @@ -1,2 +1,19 @@ -# linkedList +# Sheepy +This is a sheepy package for [sheepy](https://github.com/RemyNoulin/sheepy) and using [libsheepy](https://github.com/RemyNoulin/libsheepy) + +# Linked list type-safe double linked lists + +The nodes in the list are stored in segments for efficiency. + +The data can be stored in the list directly nodes to reduce the frequency of memory allocations. + +# Usage + +Install with spm: `spm install linkedList` + +Include header file: +- `#include "shpPackages/linkedList/linkedList.h"` + +Usage examples are on the top of the headers and in `main.c`. + diff --git a/linkedList.h b/linkedList.h @@ -0,0 +1,440 @@ + +/** + * \file + * + * double linked list: llist + * + * The nodes in llist are linked with pointers and dynamically allocated in segments + * + * The element type handled by the list is defined with llistT + * + * + * Example: + * + * // define list: + * llistT(llt, u32); + * + * // declare list: + * llt ll; + * + * // initialize: + * llistInit(&ll); + * + * // push element: + * llistPush(&ll); + * llistLast(&ll) = 1; + * + * // Pop/dellast element: + * llistPop(&ll); + * + * // Free + * llistFree(&ll); + * + * TODO add node count like singlelist + * TODO create linkedList without head and last + */ + +#include "libsheepyObject.h" + +/** + * list and node definition + */ +#define llistT(typeName, elementType)\ + typ struct UNIQVAR(nodet) UNIQVAR(nodet);\ + struct UNIQVAR(nodet) {\ + elementType elem;\ + UNIQVAR(nodet) *prev;\ + UNIQVAR(nodet) *next;\ + };\ + dArrayT(UNIQVAR(aNodet), UNIQVAR(nodet));\ + dArrayT(UNIQVAR(freeaNodet), UNIQVAR(nodet)*);\ + typ struct {\ + UNIQVAR(nodet) *head;\ + UNIQVAR(nodet) *last;\ + UNIQVAR(aNodet) list;\ + UNIQVAR(freeaNodet) freeList;\ + } typeName + +/** + * initialize list + */ +#define llistInit(name) do{\ + (name)->head = (name)->last = NULL;\ + dArrayInit(&(name)->list);\ + dArrayInit(&(name)->freeList);\ + } while(0) + +/** + * free list + */ +#define llistFree(name) do{\ + dArrayFree(&(name)->list);\ + dArrayFree(&(name)->freeList);\ + (name)->head = (name)->last = NULL;\ + } while(0) + +/** + * node type for declaring pointers to nodes + * + * Example: + * llistNodeType(name) node; + * llistUnlink(name, node); + * */ +#define llistNodeType(name) typeof((name)->head) + +// /** TODO +// * element count in list +// */ +// #define llistCount(name) (name)->count + + +/** + * is list empty + */ +#define llistIsEmpty(name) dArrayIsEmpty(&(name)->list) + +/** + * push element to list (only allocates node) + * use llistLast to access the element + */ +#define llistPush(name) do{\ + if (dArrayIsEmpty(&(name)->freeList)) {\ + dArrayPush(&(name)->list);\ + if (!(name)->last) {\ + /* first node */\ + dArrayLast(&(name)->list).prev = NULL;\ + dArrayLast(&(name)->list).next = NULL;\ + (name)->head = &dArrayLast(&(name)->list);\ + (name)->last = &dArrayLast(&(name)->list);\ + }\ + else {\ + /* link to previous node */\ + dArrayLast(&(name)->list).prev = (name)->last;\ + (name)->last->next = &dArrayLast(&(name)->list);\ + dArrayLast(&(name)->list).next = NULL;\ + (name)->last = &dArrayLast(&(name)->list);\ + }\ + }\ + else {\ + /* reuse a free node */\ + if (!(name)->last) {\ + dArrayLast(&(name)->freeList)->prev = NULL;\ + dArrayLast(&(name)->freeList)->next = NULL;\ + (name)->head = dArrayLast(&(name)->freeList);\ + (name)->last = dArrayLast(&(name)->freeList);\ + }\ + else {\ + dArrayLast(&(name)->freeList)->prev = (name)->last;\ + (name)->last->next = dArrayLast(&(name)->freeList);\ + dArrayLast(&(name)->freeList)->next = NULL;\ + (name)->last = dArrayLast(&(name)->freeList);\ + }\ + dArrayPop(&(name)->freeList);\ + }\ + } while(0) + +/** + * pop element from list (only free node) + * + * \return + * true success, false failed: the list is empty + */ +#define llistPop(name) ({\ + bool UNIQVAR(r) = true;\ + if (!(name)->last) {\ + /* the list is empty */\ + UNIQVAR(r) = false;\ + goto UNIQVAR(end);\ + }\ + dArrayPush(&(name)->freeList);\ + dArrayLast(&(name)->freeList) = (name)->last;\ + (name)->last = (name)->last->prev;\ + if ((name)->last) (name)->last->next = NULL;\ + if (!(name)->last) /* the list is empty */ (name)->head = NULL;\ + UNIQVAR(end):\ + UNIQVAR(r);\ + }) + +#define llistDelLast llistPop + +/** + * unlink node + * + * node must be of type llistNodeType(name) + * + * the node can be freed with llistFreeUnlinked or + * inserted in the list with llistInsertAfter or llistInsertBefore + */ +#define llistUnlink(name, node) do{\ + if (!(node)->prev) {\ + /* node is head */\ + (name)->head = (node)->next;\ + }\ + else {\ + (node)->prev->next = (node)->next;\ + }\ + if (!(node)->next) {\ + /* node is last */\ + (name)->last = (node)->prev;\ + }\ + else {\ + (node)->next->prev = (node)->prev;\ + }\ + } while(0) + +/** + * free unlinked node + * + * node must be of type llistNodeType(name) + */ +#define llistFreeUnlinked(name, node) do{\ + dArrayPush(&(name)->freeList);\ + dArrayLast(&(name)->freeList) = node;\ + } while(0) + +/** + * delete node + * + * node must be of type llistNodeType(name) + * + * unlink and free node + */ +#define llistDelNode(name, node) do{\ + llistUnlink(name, node);\ + llistFreeUnlinked(name, node);\ + } while(0) + +/** first element */ +#define llistFirst(name) (name)->head->elem + +/** first node pointer */ +#define llistFirstNode(name) (name)->head +#define llistHeadNode llistFirstNode + +/** last element */ +#define llistLast(name) (name)->last->elem + +/** last node pointer */ +#define llistLasttNode(name) (name)->last + +/** previous node */ +#define llistPrev(node) (node)->prev + +/** next node */ +#define llistNext(node) (node)->next + +/** node element (or use node->elem) */ +#define llistGetElem(node) (node)->elem + +/** + * swap node1 with node2 + */ +#define llistSwap(name, node1, node2) do{\ + /* disable sanity checks to keep it simple - if (!node1 or !node2) {*/\ + /* return value instead --- (name)->res = false;*/\ + /* break;*/\ + /*}*/\ + if (node1 == node2) /* node1 and node2 are the same node, nothing to do */ break;\ + var UNIQVAR(tmp) = (node1)->next;\ + (node1)->next = (node2)->next;\ + (node2)->next = UNIQVAR(tmp);\ + if (!(node1)->next) (name)->last = node1;\ + else (node1)->next->prev = node1;\ + if (!(node2)->next) (name)->last = node2;\ + else (node2)->next->prev = node2;\ + UNIQVAR(tmp) = (node1)->prev;\ + (node1)->prev = (node2)->prev;\ + (node2)->prev = UNIQVAR(tmp);\ + if (!(node1)->prev) (name)->head = node1;\ + else (node1)->prev->next = node1;\ + if (!(node2)->prev) (name)->head = node2;\ + else (node2)->prev->next = node2;\ + } while(0) + +/** loop from head to last */ +#define llistForEach(name, node)\ + for(var node = (name)->head; node ; node = llistNext(node)) + +/** loop from last to head */ +#define llistForEachDown(name, node)\ + for(var node = (name)->last; node ; node = llistPrev(node)) + +/** loop from startNode to last */ +#define llistForEachFrom(node, startNode)\ + for(var node = startNode; node ; node = (node)->next) + +/** loop from startNode to head */ +#define llistForEachFromDown(node, startNode)\ + for(var node = startNode; node ; node = (node)->prev) + +/** + * insert nodeToInsert after referenceNode + * + * nodeToInsert and referenceNode must be of type llistNodeType(name) + */ +#define llistInsertAfter(name, referenceNode, nodeToInsert) do{\ + (nodeToInsert)->next = referenceNode->next;\ + referenceNode->next = nodeToInsert;\ + (nodeToInsert)->prev = referenceNode;\ + if ((nodeToInsert)->next) {\ + (nodeToInsert)->next->prev = nodeToInsert;\ + }\ + else {\ + /* referenceNode was last node */\ + (name)->last = nodeToInsert;\ + }\ + } while(0) + +/** + * insert nodeToInsert before referenceNode + * + * nodeToInsert and referenceNode must be of type llistNodeType(name) + */ +#define llistInsertBefore(name, referenceNode, nodeToInsert) do{\ + (nodeToInsert)->prev = referenceNode->prev;\ + referenceNode->prev = nodeToInsert;\ + (nodeToInsert)->next = referenceNode;\ + if ((nodeToInsert)->prev) {\ + (nodeToInsert)->prev->next = nodeToInsert;\ + }\ + else {\ + /* referenceNode was head node */\ + (name)->head = nodeToInsert;\ + }\ + } while(0) + + +// Internal +// allocate a node +#define llistAddNode(name, resultNode) do{\ + if (dArrayIsEmpty(&(name)->freeList)) {\ + dArrayPush(&(name)->list);\ + resultNode = &dArrayLast(&(name)->list);\ + }\ + else {\ + /* reuse a free node */\ + resultNode = dArrayLast(&(name)->freeList);\ + dArrayPop(&(name)->freeList);\ + }\ + } while(0) + +/** + * add new node after referenceNode + * + * resultNode and referenceNode must be of type llistNodeType(name) + * + * \return + * resultNode access element in node with resultNode->elem or llistGetElem(resultNode) + */ +#define llistAddAfter(name, referenceNode, resultNode) do{\ + llistAddNode(name, resultNode);\ + (resultNode)->next = referenceNode->next;\ + referenceNode->next = resultNode;\ + (resultNode)->prev = referenceNode;\ + if ((resultNode)->next) {\ + (resultNode)->next->prev = resultNode;\ + }\ + else {\ + /* referenceNode was last node */\ + (name)->last = resultNode;\ + }\ + } while(0) + +/** + * add new node before referenceNode + * + * resultNode and referenceNode must be of type llistNodeType(name) + * + * \return + * resultNode access element in node with resultNode->elem or llistGetElem(resultNode) + */ +#define llistAddBefore(name, referenceNode, resultNode) do{\ + llistAddNode(name, resultNode);\ + (resultNode)->prev = referenceNode->prev;\ + referenceNode->prev = resultNode;\ + (resultNode)->next = referenceNode;\ + if ((resultNode)->prev) {\ + (resultNode)->prev->next = resultNode;\ + }\ + else {\ + /* referenceNode was head node */\ + (name)->head = resultNode;\ + }\ + } while(0) + +/** + * write the llist content to filename file + * No NULL checks are done on the parameters + * + * \param + * filename file name string + */ +#define llistWriteFilename(name, filename) do {\ + FILE *UNIQVAR(f) = fopen(filename, "w");\ + if (UNIQVAR(f)) {\ + llistForEach(name, UNIQVAR(node)) {\ + fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), UNIQVAR(f));\ + }\ + fclose(UNIQVAR(f));\ + }\ + } while(0) + +/** + * write the llist content to disk + * No NULL checks are done on the parameters + * + * \param + * file already opened file + */ +#define llistWrite(name, file) do {\ + llistForEach(name, UNIQVAR(node)) {\ + fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), file);\ + }\ + } while(0) + +/** + * read a llist from filename file + * No NULL checks are done on the parameters + * + * \param + * filename file name string + */ +#define llistReadFilename(name, filename) do {\ + if (fileExists(filename)) {\ + size_t UNIQVAR(sz) = fileSize(filename);\ + const size_t UNIQVAR(elemSz) = sizeof(dArrayLast(&(name)->list).elem);\ + if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\ + UNIQVAR(sz) /= UNIQVAR(elemSz);\ + if (UNIQVAR(sz) > (size_t)(name)->list.maxCount) /* file size exceeds capacity */ break;\ + FILE *UNIQVAR(f) = fopen(filename, "r");\ + if (UNIQVAR(f)) {\ + range(UNIQVAR(i), UNIQVAR(sz)) {\ + llistPush(name);\ + fread(&llistLast(name), 1, UNIQVAR(elemSz), UNIQVAR(f));\ + }\ + fclose(UNIQVAR(f));\ + }\ + }\ + } while(0) + +/** + * read a llist from disk + * No NULL checks are done on the parameters + * + * \param + * file already opened file + */ +#define llistRead(name, file) do {\ + fseek(file, 0 , SEEK_END);\ + size_t UNIQVAR(sz) = ftell(file);\ + fseek(file, 0 , SEEK_SET);\ + const size_t UNIQVAR(elemSz) = sizeof(dArrayLast(&(name)->list).elem);\ + if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\ + UNIQVAR(sz) /= UNIQVAR(elemSz);\ + if (UNIQVAR(sz) > (size_t)(name)->list.maxCount) /* file size exceeds capacity */ break;\ + range(UNIQVAR(i), UNIQVAR(sz)) {\ + llistPush(name);\ + fread(&llistLast(name), 1, UNIQVAR(elemSz), file);\ + }\ + } while(0) + diff --git a/linkedListe.h b/linkedListe.h @@ -0,0 +1,515 @@ + +/** + * \file + * + * double linked list with external dArray: lliste + * + * the nodes in lliste are linked with pointers and dynamically allocated in segments in a shared dArray, + * so multiple lists can be stored in single dArray making free node reuse more efficient + * + * the element type handled by the list is defined with llisteT + * + * the external node and free node storage must be allocated after declaring the first list and before running llisteStoreIinit + * + * Example: + * + * // define list: + * llisteT(llt, u32); + * + * // declare list: + * llt ll; + * + * // initialize: + * llisteInit(&ll); + * + * // push element: + * llistePush(&ll); + * llisteLast(&ll) = 1; + * + * // Pop/dellast element: + * llistePop(&ll); + * + * // Free + * llisteFree(&ll); + * + * // define list: + * llisteT(llet, u32); + * + * // declare list: + * llet lle; + * + * // initialize node storage + * // local + * llisteNodesT(&lle) nodeStore; + * llisteFreeNodesT(&lle) freeNodeStore; + * llisteStoreInit(&nodeStore, &freeNodeStore); + * + * // or on heap + * llisteNodesPtrT(&lle) nodeStore; + * llisteFreeNodesPtrT(&lle) freeNodeStore; + * nodeStore = malloc(sizeof(llisteNodesT(&lle))); + * freeNodeStore = malloc(sizeof(llisteFreeNodesT(&lle))); + * + * // initialize: + * llisteInit(&lle, &nodeStore, &freeNodeStore); + * + * // push element: + * llistePush(&lle); + * llisteLast(&lle) = 1; + * + * // Pop/delleast element: + * llistePop(&lle); + * + * // Free + * llisteFree(&lle); + * + * // free node storage, after this all lists using this storage are invalid + * llisteStoreFree(&nodeStore, &freeNodeStore); + * + * + * TODO add node count like singlelist + * TODO create linkedList without head and last + * TODO create a free macro that takes a free function in parameter + */ + +#include "libsheepyObject.h" + +/** + * list and node definition + */ +#define llisteT(typeName, elementType)\ + typ struct UNIQVAR(nodet) UNIQVAR(nodet);\ + struct UNIQVAR(nodet) {\ + elementType elem;\ + UNIQVAR(nodet) *prev;\ + UNIQVAR(nodet) *next;\ + };\ + dArrayT(UNIQVAR(aNodet), UNIQVAR(nodet));\ + dArrayT(UNIQVAR(freeaNodet), UNIQVAR(nodet)*);\ + typ struct {\ + UNIQVAR(nodet) *head;\ + UNIQVAR(nodet) *last;\ + UNIQVAR(aNodet) *list;\ + UNIQVAR(freeaNodet) *freeList;\ + } typeName + +/** dArray type for storing the nodes */ +#define llisteNodesT(name) typeof(*(name)->list) + +/** pointer type to dArray storing the nodes */ +#define llisteNodesPtrT(name) typeof((name)->list) + +/** dArray type for storing the free nodes */ +#define llisteFreeNodesT(name) typeof(*(name)->freeList) + +/** pointer type to dArray storing the free nodes */ +#define llisteFreeNodesPtrT(name) typeof((name)->freeList) + +/** + * initialize the dArrays storing the nodes for all the lists + */ +#define llisteStoreInit(nodes, freeNodes) do{\ + dArrayInit(nodes);\ + dArrayInit(freeNodes);\ + } while(0) + +/** + * free node store for all lists + * after this, all the nodes in lists are freed + */ +#define llisteStoreFree(nodes, freeNodes) do{\ + dArrayFree(nodes);\ + dArrayFree(freeNodes);\ + } while(0) + +/** + * initialize list + * + * nodes and freeNodes must be initialized once before calling llisteInit + * + */ +#define llisteInit(name, nodes, freeNodes) do{\ + (name)->head = (name)->last = NULL;\ + (name)->list = nodes;\ + (name)->freeList = freeNodes;\ + } while(0) + +/** + * free list nodes + * free and reset internal structures + * + * the dArrays storing the nodes are kept, use llisteStoreFree to free them + */ +#define llisteFree(name) do{\ + llisteForEachDown(name, UNIQVAR(node)) {\ + dArrayAppend((name)->freeList, UNIQVAR(node));\ + }\ + (name)->head = NULL;\ + (name)->last = NULL;\ + } while(0) + +/** + * node type for declaring pointers to nodes + * + * Example: + * llisteNodeType(name) node; + * llisteUnlink(name, node); + * */ +#define llisteNodeType(name) typeof((name)->head) + +// /** TODO +// * element count in list +// */ +// #define llisteCount(name) (name)->count + + +/** + * is list empty + */ +#define llisteIsEmpty(name) dArrayIsEmpty((name)->list) + +/** + * push element to list (only allocates node) + * use llisteLast to access the element + */ +#define llistePush(name) do{\ + if (dArrayIsEmpty((name)->freeList)) {\ + dArrayPush((name)->list);\ + if (!(name)->last) {\ + /* first node */\ + dArrayLast((name)->list).prev = NULL;\ + dArrayLast((name)->list).next = NULL;\ + (name)->head = &dArrayLast((name)->list);\ + (name)->last = &dArrayLast((name)->list);\ + }\ + else {\ + /* link to previous node */\ + dArrayLast((name)->list).prev = (name)->last;\ + (name)->last->next = &dArrayLast((name)->list);\ + dArrayLast((name)->list).next = NULL;\ + (name)->last = &dArrayLast((name)->list);\ + }\ + }\ + else {\ + /* reuse a free node */\ + if (!(name)->last) {\ + dArrayLast((name)->freeList)->prev = NULL;\ + dArrayLast((name)->freeList)->next = NULL;\ + (name)->head = dArrayLast((name)->freeList);\ + (name)->last = dArrayLast((name)->freeList);\ + }\ + else {\ + dArrayLast((name)->freeList)->prev = (name)->last;\ + (name)->last->next = dArrayLast((name)->freeList);\ + dArrayLast((name)->freeList)->next = NULL;\ + (name)->last = dArrayLast((name)->freeList);\ + }\ + dArrayPop((name)->freeList);\ + }\ + } while(0) + +/** + * pop element from list (only free node) + * + * \return + * true success, false failed: the list is empty + */ +#define llistePop(name) ({\ + bool UNIQVAR(r) = true;\ + if (!(name)->last) {\ + /* the list is empty */\ + UNIQVAR(r) = false;\ + goto UNIQVAR(end);\ + }\ + dArrayPush((name)->freeList);\ + dArrayLast((name)->freeList) = (name)->last;\ + (name)->last = (name)->last->prev;\ + if ((name)->last) (name)->last->next = NULL;\ + if (!(name)->last) /* the list is empty */ (name)->head = NULL;\ + UNIQVAR(end):\ + UNIQVAR(r);\ + }) + +#define llisteDelLast llistePop + +/** + * unlink node + * + * node must be of type llisteNodeType(name) + * + * the node can be freed with llisteFreeUnlinked or + * inserted in the list with llisteInsertAfter or llisteInsertBefore + */ +#define llisteUnlink(name, node) do{\ + if (!(node)->prev) {\ + /* node is head */\ + (name)->head = (node)->next;\ + }\ + else {\ + (node)->prev->next = (node)->next;\ + }\ + if (!(node)->next) {\ + /* node is last */\ + (name)->last = (node)->prev;\ + }\ + else {\ + (node)->next->prev = (node)->prev;\ + }\ + } while(0) + +/** + * free unlinked node + * + * node must be of type llisteNodeType(name) + */ +#define llisteFreeUnlinked(name, node) do{\ + dArrayPush((name)->freeList);\ + dArrayLast((name)->freeList) = node;\ + } while(0) + +/** + * delete node + * + * node must be of type llisteNodeType(name) + * + * unlink and free node + */ +#define llisteDelNode(name, node) do{\ + llisteUnlink(name, node);\ + llisteFreeUnlinked(name, node);\ + } while(0) + +/** first element */ +#define llisteFirst(name) (name)->head->elem + +/** first node pointer */ +#define llisteFirstNode(name) (name)->head +#define llisteHeadNode llisteFirstNode + +/** last element */ +#define llisteLast(name) (name)->last->elem + +/** last node pointer */ +#define llisteLasttNode(name) (name)->last + +/** previous node */ +#define llistePrev(node) (node)->prev + +/** next node */ +#define llisteNext(node) (node)->next + +/** node element (or use node->elem) */ +#define llisteGetElem(node) (node)->elem + +/** + * swap node1 with node2 + */ +#define llisteSwap(name, node1, node2) do{\ + /* disable sanity checks to keep it simple - if (!node1 or !node2) {*/\ + /* return value instead --- (name)->res = false;*/\ + /* break;*/\ + /*}*/\ + if (node1 == node2) /* node1 and node2 are the same node, nothing to do */ break;\ + var UNIQVAR(tmp) = (node1)->next;\ + (node1)->next = (node2)->next;\ + (node2)->next = UNIQVAR(tmp);\ + if (!(node1)->next) (name)->last = node1;\ + else (node1)->next->prev = node1;\ + if (!(node2)->next) (name)->last = node2;\ + else (node2)->next->prev = node2;\ + UNIQVAR(tmp) = (node1)->prev;\ + (node1)->prev = (node2)->prev;\ + (node2)->prev = UNIQVAR(tmp);\ + if (!(node1)->prev) (name)->head = node1;\ + else (node1)->prev->next = node1;\ + if (!(node2)->prev) (name)->head = node2;\ + else (node2)->prev->next = node2;\ + } while(0) + +/** loop from head to last */ +#define llisteForEach(name, node)\ + for(var node = (name)->head; node ; node = llisteNext(node)) + +/** loop from last to head */ +#define llisteForEachDown(name, node)\ + for(var node = (name)->last; node ; node = llistePrev(node)) + +/** loop from startNode to last */ +#define llisteForEachFrom(node, startNode)\ + for(var node = startNode; node ; node = (node)->next) + +/** loop from startNode to head */ +#define llisteForEachFromDown(node, startNode)\ + for(var node = startNode; node ; node = (node)->prev) + +/** + * insert nodeToInsert after referenceNode + * + * nodeToInsert and referenceNode must be of type llisteNodeType(name) + */ +#define llisteInsertAfter(name, referenceNode, nodeToInsert) do{\ + (nodeToInsert)->next = referenceNode->next;\ + referenceNode->next = nodeToInsert;\ + (nodeToInsert)->prev = referenceNode;\ + if ((nodeToInsert)->next) {\ + (nodeToInsert)->next->prev = nodeToInsert;\ + }\ + else {\ + /* referenceNode was last node */\ + (name)->last = nodeToInsert;\ + }\ + } while(0) + +/** + * insert nodeToInsert before referenceNode + * + * nodeToInsert and referenceNode must be of type llisteNodeType(name) + */ +#define llisteInsertBefore(name, referenceNode, nodeToInsert) do{\ + (nodeToInsert)->prev = referenceNode->prev;\ + referenceNode->prev = nodeToInsert;\ + (nodeToInsert)->next = referenceNode;\ + if ((nodeToInsert)->prev) {\ + (nodeToInsert)->prev->next = nodeToInsert;\ + }\ + else {\ + /* referenceNode was head node */\ + (name)->head = nodeToInsert;\ + }\ + } while(0) + + +// Internal +// allocate a node +#define llisteAddNode(name, resultNode) do{\ + if (dArrayIsEmpty((name)->freeList)) {\ + dArrayPush((name)->list);\ + resultNode = &dArrayLast((name)->list);\ + }\ + else {\ + /* reuse a free node */\ + resultNode = dArrayLast((name)->freeList);\ + dArrayPop((name)->freeList);\ + }\ + } while(0) + +/** + * add new node after referenceNode + * + * resultNode and referenceNode must be of type llisteNodeType(name) + * + * \return + * resultNode access element in node with resultNode->elem or llisteGetElem(resultNode) + */ +#define llisteAddAfter(name, referenceNode, resultNode) do{\ + llisteAddNode(name, resultNode);\ + (resultNode)->next = referenceNode->next;\ + referenceNode->next = resultNode;\ + (resultNode)->prev = referenceNode;\ + if ((resultNode)->next) {\ + (resultNode)->next->prev = resultNode;\ + }\ + else {\ + /* referenceNode was last node */\ + (name)->last = resultNode;\ + }\ + } while(0) + +/** + * add new node before referenceNode + * + * resultNode and referenceNode must be of type llisteNodeType(name) + * + * \return + * resultNode access element in node with resultNode->elem or llisteGetElem(resultNode) + */ +#define llisteAddBefore(name, referenceNode, resultNode) do{\ + llisteAddNode(name, resultNode);\ + (resultNode)->prev = referenceNode->prev;\ + referenceNode->prev = resultNode;\ + (resultNode)->next = referenceNode;\ + if ((resultNode)->prev) {\ + (resultNode)->prev->next = resultNode;\ + }\ + else {\ + /* referenceNode was head node */\ + (name)->head = resultNode;\ + }\ + } while(0) + +/** + * write the lliste content to filename file + * No NULL checks are done on the parameters + * + * \param + * filename file name string + */ +#define llisteWriteFilename(name, filename) do {\ + FILE *UNIQVAR(f) = fopen(filename, "w");\ + if (UNIQVAR(f)) {\ + llisteForEach(name, UNIQVAR(node)) {\ + fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), UNIQVAR(f));\ + }\ + fclose(UNIQVAR(f));\ + }\ + } while(0) + +/** + * write the lliste content to disk + * No NULL checks are done on the parameters + * + * \param + * file already opened file + */ +#define llisteWrite(name, file) do {\ + llisteForEach(name, UNIQVAR(node)) {\ + fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), file);\ + }\ + } while(0) + +/** + * read a lliste from filename file + * No NULL checks are done on the parameters + * + * \param + * filename file name string + */ +#define llisteReadFilename(name, filename) do {\ + if (fileExists(filename)) {\ + size_t UNIQVAR(sz) = fileSize(filename);\ + const size_t UNIQVAR(elemSz) = sizeof(dArrayLast((name)->list).elem);\ + if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\ + UNIQVAR(sz) /= UNIQVAR(elemSz);\ + if (UNIQVAR(sz) > (size_t)(name)->list.maxCount) /* file size exceeds capacity */ break;\ + FILE *UNIQVAR(f) = fopen(filename, "r");\ + if (UNIQVAR(f)) {\ + range(UNIQVAR(i), UNIQVAR(sz)) {\ + llistePush(name);\ + fread(&llisteLast(name), 1, UNIQVAR(elemSz), UNIQVAR(f));\ + }\ + fclose(UNIQVAR(f));\ + }\ + }\ + } while(0) + +/** + * read a lliste from disk + * No NULL checks are done on the parameters + * + * \param + * file already opened file + */ +#define llisteRead(name, file) do {\ + fseek(file, 0 , SEEK_END);\ + size_t UNIQVAR(sz) = ftell(file);\ + fseek(file, 0 , SEEK_SET);\ + const size_t UNIQVAR(elemSz) = sizeof(dArrayLast((name)->list).elem);\ + if ((UNIQVAR(sz) % UNIQVAR(elemSz))) /* file size not a multiple of elem size, wrong*/ break;\ + UNIQVAR(sz) /= UNIQVAR(elemSz);\ + if (UNIQVAR(sz) > (size_t)(name)->list.maxCount) /* file size exceeds capacity */ break;\ + range(UNIQVAR(i), UNIQVAR(sz)) {\ + llistePush(name);\ + fread(&llisteLast(name), 1, UNIQVAR(elemSz), file);\ + }\ + } while(0) + diff --git a/main.c b/main.c @@ -0,0 +1,84 @@ +#! /usr/bin/env sheepy +/* or direct path to sheepy: #! /usr/local/bin/sheepy */ + +/* Libsheepy documentation: http://spartatek.se/libsheepy/ */ +#include "libsheepyObject.h" +#include "linkedList.h" +#include "linkedListe.h" +int argc; char **argv; + +/* enable/disable logging */ +/* #undef pLog */ +/* #define pLog(...) */ + +int main(int ARGC, char** ARGV) { + + argc = ARGC; argv = ARGV; + + initLibsheepy(ARGV[0]); + setLogMode(LOG_FUNC); + + + // llist linked list + + // define list: + llistT(llt, u32); + + // declare list: + llt ll; + + // initialize: + llistInit(&ll); + + // push element: + llistPush(&ll); + llistLast(&ll) = 1; + + // Pop/dellast element: + llistPop(&ll); + + // Free + llistFree(&ll); + + + + + + // lliste linked list with external storage + + // define list: + llisteT(llet, u32); + + // declare list: + llet lle; + + // initialize node storage + // local + llisteNodesT(&lle) nodeStore; + llisteFreeNodesT(&lle) freeNodeStore; + llisteStoreInit(&nodeStore, &freeNodeStore); + + /* // or on heap */ + /* llisteNodesPtrT(&lle) nodeStore; */ + /* llisteFreeNodesPtrT(&lle) freeNodeStore; */ + /* nodeStore = malloc(sizeof(llisteNodesT(&lle))); */ + /* freeNodeStore = malloc(sizeof(llisteFreeNodesT(&lle))); */ + + // initialize: + llisteInit(&lle, &nodeStore, &freeNodeStore); + + // push element: + llistePush(&lle); + llisteLast(&lle) = 1; + + // Pop/delleast element: + llistePop(&lle); + + // Free + llisteFree(&lle); + + // free node storage, after this all lists using this storage are invalid + llisteStoreFree(&nodeStore, &freeNodeStore); + +} +// vim: set expandtab ts=2 sw=2: diff --git a/package.yml b/package.yml @@ -0,0 +1,31 @@ +--- + name: linkedList + version: 0.0.1 + description: "double linked lists" + bin: ./linkedList.h + #cflags: -DA -ggdb -std=gnu11 -fPIC -pipe + #lflags: -lpcre + repository: + type: git + url: git+https://github.com/RemyNoulin/linkedList.git + keywords: + - data structure + author: Remy Noulin + license: MIT + bugs: + url: https://github.com/RemyNoulin/linkedList/issues + homepage: https://github.com/RemyNoulin/linkedList#readme + #compileHelp: # text displayed when there is a compilation error + #dependencies: + # md4c: + # Test configuration: + #testBin: ./testLinkedList.c + #testCflags: -ggdb -std=gnu11 -fPIC -pipe -fprofile-arcs -ftest-coverage -Wall -Wextra + #testLflags: -lcheck_pic -lrt -lm -lsubunit -fprofile-arcs -ftest-coverage -rdynamic + # Memcheck configuration: + #memcheckBin: ./memcheckLinkedList.c + #memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all + #memcheckCflags: -ggdb -std=gnu11 -fPIC -pipe + #memcheckLflags: -rdynamic + #documentationCmd: # command for generating the documentation with spm doc + private: false # true for private package