staticList

macros of double linked list with defined maximum length supporting any type, this list doesnt use malloc
git clone https://noulin.net/git/staticList.git
Log | Files | Refs | LICENSE

commit 21834cd8b2ed0b1c07a8253c7fe2385555dbbbe8
parent 3ba24c6bb59c02032f00bb5e63ece07b4b917cba
Author: Remy Noulin <loader2x@gmail.com>
Date:   Sun, 20 May 2018 10:49:27 +0200

staticList library

main.c       | 195 +++++++++++++++++++++++++
package.yml  |  17 +++
staticList.h | 465 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 677 insertions(+)

Diffstat:
Amain.c | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apackage.yml | 17+++++++++++++++++
AstaticList.h | 465+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 677 insertions(+), 0 deletions(-)

diff --git a/main.c b/main.c @@ -0,0 +1,195 @@ +#! /usr/bin/env sheepy +/* or direct path to sheepy: #! /usr/local/bin/sheepy */ + +#include "libsheepyObject.h" +#include "staticList.h" + +int argc; char **argv; + +int main(int ARGC, char** ARGV) { + + argc = ARGC; argv = ARGV; + + initLibsheepy(argv[0]); + setLogMode(LOG_FUNC); + + puts("C template"); + + staticListT(slt, u32, 3); + slt sl; + + staticListInit(sl); + + logPtr(sl.head); + logPtr(sl.last); + staticListPush(sl); + staticListLast(sl) = 1; + logPtr(sl.head); + logPtr(sl.last); + staticListPush(sl); + staticListLast(sl) = 10; + logPtr(sl.head); + logPtr(sl.last); + staticListPop(sl); + logPtr(sl.head); + logPtr(sl.last); + staticListPop(sl); + logPtr(sl.head); + logPtr(sl.last); + staticListPop(sl); + + + logPtr(sl.head); + logPtr(sl.last); + staticListPush(sl); + staticListLast(sl) = 1; + logPtr(sl.head); + logPtr(sl.head->next); + logPtr(sl.head->prev); + logPtr(sl.last); + logPtr(sl.last->next); + logPtr(sl.last->prev); + staticListPush(sl); + staticListLast(sl) = 10; + logPtr(sl.head); + logPtr(sl.head->next); + logPtr(sl.head->prev); + logPtr(sl.last); + logPtr(sl.last->next); + logPtr(sl.last->prev); + staticListPush(sl); + staticListLast(sl) = 100; + logPtr(sl.head); + logPtr(sl.head->next); + logPtr(sl.head->prev); + logPtr(sl.last); + logPtr(sl.last->next); + logPtr(sl.last->prev); + logPtr(sl.last->prev->prev); + logPtr(sl.last->prev->next); + var idx = sl.head->next; + staticListDelNode(sl, idx); + logPtr(sl.head); + logPtr(sl.head->next); + logPtr(sl.head->prev); + logPtr(sl.last); + logPtr(sl.last->next); + logPtr(sl.last->prev); + idx = sl.head; + staticListDelNode(sl, idx); + logPtr(sl.head); + logPtr(sl.head->next); + logPtr(sl.head->prev); + logPtr(sl.last); + logPtr(sl.last->next); + logPtr(sl.last->prev); + idx = sl.head; + staticListDelNode(sl, idx); + logPtr(sl.head); + logPtr(sl.last); + + + logPtr(sl.head); + logPtr(sl.last); + staticListPush(sl); + staticListLast(sl) = 1; + logPtr(sl.head); + logPtr(sl.last); + staticListPush(sl); + staticListLast(sl) = 10; + logPtr(sl.head); + logPtr(sl.last); + staticListPush(sl); + staticListLast(sl) = 100; + logPtr(sl.head); + logPtr(sl.last); + + staticListForEach(sl, e) { + logVarG(e->elem); + } + + logPtr(sl.head); + logPtr(sl.head->next); + logPtr(sl.head->prev); + logPtr(sl.last); + logPtr(sl.last->next); + logPtr(sl.last->prev); + logPtr(sl.last->prev->prev); + logPtr(sl.last->prev->next); + var e1 = sl.head; + var e2 = sl.last; + logI("\nswap"); + staticListSwap(sl, e1, e2); + logPtr(sl.head); + logPtr(sl.head->next); + logPtr(sl.head->prev); + logPtr(sl.last); + logPtr(sl.last->next); + logPtr(sl.last->prev); + logPtr(sl.last->prev->prev); + logPtr(sl.last->prev->next); + staticListForEach(sl, e) { + logVarG(e->elem); + } + + e1 = sl.head; + e2 = sl.head->next; + logI("\nswap"); + staticListSwap(sl, e1, e2); + staticListForEach(sl, e) { + logVarG(e->elem); + } + + e1 = sl.last; + e2 = sl.last->prev; + logI("\nswap"); + staticListSwap(sl, e1, e2); + staticListForEach(sl, e) { + logVarG(e->elem); + } + + staticListPop(sl); + logI("pop"); + staticListForEach(sl, e) { + logVarG(e->elem); + } + + e1 = sl.head; + e2 = sl.last; + logI("\nswap"); + staticListSwap(sl, e1, e2); + staticListForEach(sl, e) { + logVarG(e->elem); + } + + put + logI("unlink head"); + staticListPush(sl); + staticListLast(sl) = 100; + put + staticListForEach(sl, e) { + logVarG(e->elem); + } + e1 = sl.head; + staticListUnlink(sl, e1); + e2 = sl.last; + staticListInsertAfter(sl, e2, e1); + put + staticListForEach(sl, e) { + logVarG(e->elem); + } + + put + logI("unlink last"); + e1 = sl.last; + staticListUnlink(sl, e1); + e2 = sl.head; + staticListInsertAfter(sl, e2, e1); + put + staticListForEach(sl, e) { + logVarG(e->elem); + } + + /* staticListWriteFilename(sl, "linked.bin"); */ + /* staticListReadFilename(sl, "linked.bin"); */ +} diff --git a/package.yml b/package.yml @@ -0,0 +1,17 @@ +--- + name: staticList + version: 0.0.11 + description: "macros of double linked list with defined maximum length supporting any type, this list doesnt use malloc" + bin: ./staticList.h + #cflags: -DA -ggdb -std=gnu11 -fPIC -pipe + #lflags: -rdynamic # debug + repository: + type: git + url: git+https://github.com/RemyNoulin/staticList.git + keywords: + - data structure + author: Remy + license: MIT + bugs: + url: https://github.com/RemyNoulin/staticList/issues + homepage: https://github.com/RemyNoulin/staticList#readme diff --git a/staticList.h b/staticList.h @@ -0,0 +1,465 @@ + +/** + * \file + * + * Static double linked list + * + * NOTE: The macros in this file are for creating list functions wrapping the macros. + * The parameters to these macros should be variables to avoid wrong computation + * and infinite loops. + * Example: + * staticListDelNode(list, list.head) fails because list.head changes value during the + * macro execution. + * + * The number of nodes is defined at list declaration, all the nodes are preallocated. + * The heap is not used, there is no malloc, realloc or free. + * + * The status of the macros is saved (list).res and is set to true when the operation is success and + * false when the operation is failure. + * + * The element type handled by the list is defined with staticListT + * + * Example: + * + * define list: + * staticListT(slt, u32, 3); + * + * declare list: + * slt sl; + * + * initialize: + * staticListInit(sl); + * + * push element: + * staticListPush(sl); + * staticListLast(sl) = 1; + * + * Pop/dellast element: + * staticListPop(sl); + */ + +#include "libsheepyObject.h" + +/** + * list and node definition + * + * MAXCOUNT is the list capacity + */ +#define staticListT(typeName, elementType, MAXCOUNT)\ + typ struct UNIQVAR(nodet) UNIQVAR(nodet);\ + struct UNIQVAR(nodet) {\ + elementType elem;\ + UNIQVAR(nodet) *prev;\ + UNIQVAR(nodet) *next;\ + };\ + staticArrayT(UNIQVAR(aNodet), UNIQVAR(nodet), MAXCOUNT);\ + staticArrayT(UNIQVAR(freeaNodet), UNIQVAR(nodet)*, MAXCOUNT);\ + typ struct {\ + UNIQVAR(nodet) *head;\ + UNIQVAR(nodet) *last;\ + UNIQVAR(aNodet) list;\ + UNIQVAR(freeaNodet) freeList;\ + bool res;\ + } typeName + +/** + * initialize list + * + * \return + * (name).res true success, false failed + */ +#define staticListInit(name) do{\ + (name).head = (name).last = NULL;\ + staticArrayInit((name).list)\ + staticArrayInit((name).freeList);\ + (name).res = true;\ + } while(0) + +/** + * node type for declaring pointers to nodes + * + * Example: + * staticListNodeType(name) node; + * staticListUnlink(name, node); + * */ +#define staticListNodeType(name) typeof((name).head) + +/** + * is list empty + */ +#define staticListIsEmpty(name) (staticArrayIsEmpty((name).list) || staticArrayIsFull((name).freeList)) + +/** + * is list full + */ +#define staticListIsFull(name) (staticArrayIsFull((name).list) && staticArrayIsEmpty((name).freeList)) + +/** + * push element to list (only allocates node) + * use staticListLast to access the element + * + * \return + * (name).res true success, false failed + */ +#define staticListPush(name) do{\ + if (staticArrayIsEmpty((name).freeList)) {\ + if (staticArrayIsFull((name).list)) {\ + /* the list is full */\ + (name).res = false;\ + break;\ + }\ + staticArrayPush((name).list);\ + if (!(name).last) {\ + /* first node */\ + staticArrayLast((name).list).prev = NULL;\ + staticArrayLast((name).list).next = NULL;\ + (name).head = &staticArrayLast((name).list);\ + (name).last = &staticArrayLast((name).list);\ + }\ + else {\ + /* link to previous node */\ + staticArrayLast((name).list).prev = (name).last;\ + (name).last->next = &staticArrayLast((name).list);\ + staticArrayLast((name).list).next = NULL;\ + (name).last = &staticArrayLast((name).list);\ + }\ + }\ + else {\ + /* reuse a free node */\ + if (!(name).last) {\ + staticArrayLast((name).freeList)->prev = NULL;\ + staticArrayLast((name).freeList)->next = NULL;\ + (name).head = staticArrayLast((name).freeList);\ + (name).last = staticArrayLast((name).freeList);\ + }\ + else {\ + staticArrayLast((name).freeList)->prev = (name).last;\ + (name).last->next = staticArrayLast((name).freeList);\ + staticArrayLast((name).freeList)->next = NULL;\ + (name).last = staticArrayLast((name).freeList);\ + }\ + staticArrayPop((name).freeList);\ + }\ + (name).res = true;\ + } while(0) + +/** + * pop element from list (only free node) + * + * \return + * (name).res true success, false failed: the list is empty + */ +#define staticListPop(name) do{\ + if (!(name).last) {\ + /* the list is empty */\ + (name).res = false;\ + break;\ + }\ + staticArrayPush((name).freeList);\ + staticArrayLast((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;\ + (name).res = true;\ + } while(0) + +#define staticListDelLast staticListPop + +/** + * unlink node + * + * node must be of type staticListNodeType(name) + * + * the node can be freed with staticListFreeUnlinked or + * inserted in the list with staticListInsertAfter or staticListInsertBefore + */ +#define staticListUnlink(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 staticListNodeType(name) + */ +#define staticListFreeUnlinked(name, node) do{\ + staticArrayPush((name).freeList);\ + staticArrayLast((name).freeList) = node;\ + } while(0) + +/** + * delete node + * + * node must be of type staticListNodeType(name) + * + * unlink and free node + */ +#define staticListDelNode(name, node) do{\ + staticListUnlink(name, node);\ + staticListFreeUnlinked(name, node);\ + (name).res = true;\ + } while(0) + +/** first element */ +#define staticListFirst(name) (name).head->elem + +/** first node pointer */ +#define staticListFirstNode(name) (name).head +#define staticListHeadNode staticListFirstNode + +/** last element */ +#define staticListLast(name) (name).last->elem + +/** last node pointer */ +#define staticListLasttNode(name) (name).last + +/** previous node */ +#define staticListPrev(node) (node)->prev + +/** next node */ +#define staticListNext(node) (node)->next + +/** node element (or use node->elem) */ +#define staticListGetElem(node) (node)->elem + +/** + * swap node1 with node2 + * + * \return + * (name).res true success, false failed + */ +#define staticListSwap(name, node1, node2) do{\ + /* disable sanity checks to keep it simple - if (!node1 or !node2) {*/\ + /* (name).res = false;*/\ + /* break;*/\ + /*}*/\ + (name).res = true;\ + 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 staticListForEach(name, node)\ + for(var node = (name).head; node ; node = staticListNext(node)) + +/** loop from last to head */ +#define staticListForEachDown(name, node)\ + for(var node = (name).last; node ; node = staticListPrev(node)) + +/** loop from startNode to last */ +#define staticListForEachFrom(node, startNode)\ + for(var node = startNode; node ; node = (node)->next) + +/** loop from startNode to head */ +#define staticListForEachFromDown(node, startNode)\ + for(var node = startNode; node ; node = (node)->prev) + +/** + * insert nodeToInsert after referenceNode + * + * nodeToInsert and referenceNode must be of type staticListNodeType(name) + */ +#define staticListInsertAfter(name, referenceNode, nodeToInsert) do{\ + var UNIQVAR(tmp) = referenceNode->next;\ + referenceNode->next = nodeToInsert;\ + (nodeToInsert)->prev = referenceNode;\ + (nodeToInsert)->next = UNIQVAR(tmp);\ + if (UNIQVAR(tmp)) {\ + UNIQVAR(tmp)->prev = nodeToInsert;\ + }\ + else {\ + /* referenceNode was last node */\ + (name).last = nodeToInsert;\ + }\ + } while(0) + +/** + * insert nodeToInsert before referenceNode + * + * nodeToInsert and referenceNode must be of type staticListNodeType(name) + */ +#define staticListInsertBefore(name, referenceNode, nodeToInsert) do{\ + var UNIQVAR(tmp) = referenceNode->prev;\ + referenceNode->prev = nodeToInsert;\ + (nodeToInsert)->next = referenceNode;\ + (nodeToInsert)->prev = UNIQVAR(tmp);\ + if (UNIQVAR(tmp)) {\ + UNIQVAR(tmp)->next = nodeToInsert;\ + }\ + else {\ + /* referenceNode was head node */\ + (name).head = nodeToInsert;\ + }\ + } while(0) + + +// Internal +// allocate a node +// true success, false failed: list is full +#define staticListAddNode(name, resultNode) do{\ + if (staticArrayIsEmpty((name).freeList)) {\ + if (staticArrayIsFull((name).list)) {\ + /* the list is full */\ + (name).res = false;\ + break;\ + }\ + staticArrayPush((name).list);\ + resultNode = &staticArrayLast((name).list);\ + }\ + else {\ + /* reuse a free node */\ + resultNode = staticArrayLast((name).freeList);\ + staticArrayPop((name).freeList);\ + }\ + (name).res = true;\ + } while(0) + +/** + * add new node after referenceNode + * + * resultNode and referenceNode must be of type staticListNodeType(name) + * + * \return + * resultNode access element in node with resultNode->elem or staticListGetElem(resultNode) + */ +#define staticListAddAfter(name, referenceNode, resultNode) do{\ + staticListAddNode(name, resultNode);\ + if (!(name).res) /* list is full, return false */ break;\ + var UNIQVAR(tmp) = referenceNode->next;\ + referenceNode->next = resultNode;\ + (resultNode)->prev = referenceNode;\ + (resultNode)->next = UNIQVAR(tmp);\ + if (UNIQVAR(tmp)) {\ + UNIQVAR(tmp)->prev = resultNode;\ + }\ + else {\ + /* referenceNode was last node */\ + (name).last = resultNode;\ + }\ + } while(0) + +/** + * add new node before referenceNode + * + * resultNode and referenceNode must be of type staticListNodeType(name) + * + * \return + * resultNode access element in node with resultNode->elem or staticListGetElem(resultNode) + */ +#define staticListAddBefore(name, referenceNode, resultNode) do{\ + staticListAddNode(name, resultNode);\ + if (!(name).res) /* list is full, return false */ break;\ + var UNIQVAR(tmp) = referenceNode->prev;\ + referenceNode->prev = resultNode;\ + (resultNode)->next = referenceNode;\ + (resultNode)->prev = UNIQVAR(tmp);\ + if (UNIQVAR(tmp)) {\ + UNIQVAR(tmp)->next = resultNode;\ + }\ + else {\ + /* referenceNode was head node */\ + (name).head = resultNode;\ + }\ + } while(0) + +/** + * write the staticList content to filename file + * No NULL checks are done on the parameters + * + * \param + * filename file name string + */ +#define staticListWriteFilename(name, filename) do {\ + FILE *UNIQVAR(f) = fopen(filename, "w");\ + if (UNIQVAR(f)) {\ + staticListForEach(name, UNIQVAR(node)) {\ + fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), UNIQVAR(f));\ + }\ + fclose(UNIQVAR(f));\ + }\ + } while(0) + +/** + * write the staticList content to disk + * No NULL checks are done on the parameters + * + * \param + * file already opened file + */ +#define staticListWrite(name, file) do {\ + staticListForEach(name, UNIQVAR(node)) {\ + fwrite(&UNIQVAR(node)->elem, 1, sizeof(UNIQVAR(node)->elem), file);\ + }\ + } while(0) + +/** + * read a staticList from filename file + * No NULL checks are done on the parameters + * + * \param + * filename file name string + */ +#define staticListReadFilename(name, filename) do {\ + if (fileExists(filename)) {\ + size_t UNIQVAR(sz) = fileSize(filename);\ + const size_t UNIQVAR(elemSz) = sizeof(staticArrayLast((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)) {\ + staticListPush(name);\ + fread(&staticListLast(name), 1, UNIQVAR(elemSz), UNIQVAR(f));\ + }\ + fclose(UNIQVAR(f));\ + }\ + }\ + } while(0) + +/** + * read a staticList from disk + * No NULL checks are done on the parameters + * + * \param + * file already opened file + */ +#define staticListRead(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(staticArrayLast((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)) {\ + staticListPush(name);\ + fread(&staticListLast(name), 1, UNIQVAR(elemSz), file);\ + }\ + } while(0)