Compare commits
4 Commits
Author | SHA1 | Date |
---|---|---|
Alex D. | fe14ba00b7 | |
Alex D. | 2d89d5f40c | |
Alex D. | 525d0140de | |
Alex D. | 9855146f8b |
|
@ -1,41 +1,61 @@
|
||||||
---
|
---
|
||||||
BasedOnStyle: LLVM
|
Standard: Auto
|
||||||
AlignConsecutiveMacros: 'true'
|
|
||||||
AlignConsecutiveAssignments: 'true'
|
|
||||||
AlignConsecutiveDeclarations: 'true'
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
AllowShortBlocksOnASingleLine: 'true'
|
|
||||||
AllowShortCaseLabelsOnASingleLine: 'true'
|
|
||||||
AllowShortFunctionsOnASingleLine: All
|
|
||||||
AllowShortIfStatementsOnASingleLine: Always
|
|
||||||
AllowShortLoopsOnASingleLine: 'true'
|
|
||||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
|
||||||
AlwaysBreakAfterReturnType: AllDefinitions
|
|
||||||
AlwaysBreakBeforeMultilineStrings: 'false'
|
|
||||||
BinPackArguments: 'false'
|
|
||||||
BinPackParameters: 'false'
|
|
||||||
BreakBeforeBinaryOperators: NonAssignment
|
|
||||||
BreakBeforeBraces: Linux
|
|
||||||
BreakStringLiterals: 'false'
|
|
||||||
ColumnLimit: '150'
|
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
|
||||||
Cpp11BracedListStyle: 'false'
|
|
||||||
IncludeBlocks: Regroup
|
|
||||||
IndentCaseLabels: 'true'
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentWidth: '8'
|
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
PointerAlignment: Left
|
BasedOnStyle: LLVM
|
||||||
ReflowComments: 'true'
|
ColumnLimit: 0
|
||||||
SortIncludes: 'true'
|
IndentWidth: 8
|
||||||
SpaceAfterCStyleCast: 'true'
|
TabWidth: 8
|
||||||
SpaceAfterLogicalNot: 'false'
|
|
||||||
SpaceBeforeAssignmentOperators: 'true'
|
|
||||||
SpaceBeforeCpp11BracedList: 'true'
|
|
||||||
SpaceBeforeParens: ControlStatements
|
|
||||||
SpacesInCStyleCastParentheses: 'false'
|
|
||||||
Standard: Cpp11
|
|
||||||
TabWidth: '8'
|
|
||||||
UseTab: ForIndentation
|
UseTab: ForIndentation
|
||||||
|
|
||||||
|
AlignConsecutiveAssignments: true
|
||||||
|
AlignConsecutiveBitFields: true
|
||||||
|
AlignConsecutiveDeclarations: true
|
||||||
|
AlignConsecutiveMacros: true
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: AlignAfterOperator
|
||||||
|
AlignTrailingComments: true
|
||||||
|
|
||||||
|
AllowShortBlocksOnASingleLine: Always
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Always
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
|
||||||
|
BreakBeforeBinaryOperators: All
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
|
||||||
|
BreakStringLiterals: false
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentGotoLabels: true
|
||||||
|
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
ContinuationIndentWidth: 2
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
InsertTrailingCommas: Wrapped
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: true
|
||||||
|
SpaceBeforeParens: Always
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
63
Makefile
63
Makefile
|
@ -1,65 +1,18 @@
|
||||||
include config.mk
|
include config.mk
|
||||||
include sources.mk
|
|
||||||
|
|
||||||
ifeq (${CC},clang)
|
|
||||||
|
|
||||||
CFLAGS =\
|
|
||||||
-std=c99\
|
|
||||||
-Weverything\
|
|
||||||
-Wno-padded\
|
|
||||||
-Wno-disabled-macro-expansion\
|
|
||||||
-pedantic
|
|
||||||
|
|
||||||
ifeq (${DEBUG},1)
|
|
||||||
CFLAGS += -g
|
|
||||||
else
|
|
||||||
CFLAGS += -O2 -Werror
|
|
||||||
endif
|
|
||||||
|
|
||||||
else ifeq (${CC},gcc)
|
|
||||||
|
|
||||||
CFLAGS =\
|
|
||||||
-std=c99\
|
|
||||||
-Wall\
|
|
||||||
-Wextra\
|
|
||||||
-Wformat-overflow=2\
|
|
||||||
-Wformat-security\
|
|
||||||
-Winit-self\
|
|
||||||
-Wstrict-overflow=2\
|
|
||||||
-Wstringop-overflow=2\
|
|
||||||
-Walloc-zero\
|
|
||||||
-Wduplicated-branches\
|
|
||||||
-Wduplicated-cond\
|
|
||||||
-Wtrampolines\
|
|
||||||
-Wfloat-equal\
|
|
||||||
-Wshadow\
|
|
||||||
-Wunsafe-loop-optimizations\
|
|
||||||
-Wparentheses\
|
|
||||||
-pedantic
|
|
||||||
|
|
||||||
ifeq (${DEBUG},1)
|
|
||||||
CFLAGS += -g
|
|
||||||
else
|
|
||||||
CFLAGS += -O2 -Werror
|
|
||||||
endif
|
|
||||||
|
|
||||||
endif
|
|
||||||
CFLAGS += ${EXTRA_CFLAGS}
|
|
||||||
|
|
||||||
OBJ = ${SRC:.c=.o}
|
OBJ = ${SRC:.c=.o}
|
||||||
|
|
||||||
all: ${OBJ}
|
all: ${OBJ} ${BIN}
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
${CC} -c ${CFLAGS} -o $@ $<
|
${CC} -o $@ -c ${CFLAGS} $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f ${OBJ}
|
rm -f ${OBJ} ${BIN}
|
||||||
|
|
||||||
install: all
|
ifneq (${BIN},)
|
||||||
mkdir -p "${DESTDIR}${PREFIX}/lib/corelibs"
|
${BIN}: ${OBJ}
|
||||||
cp -f ${OBJ} "${DESTDIR}${PREFIX}/lib/corelibs"
|
${CC} -o "$@" ${LDFLAGS} $^
|
||||||
mkdir -p "${DESTDIR}${PREFIX}/include/corelibs"
|
endif
|
||||||
cp -f ${HDR} "${DESTDIR}${PREFIX}/include/corelibs"
|
|
||||||
|
|
||||||
.PHONY: all clean install
|
.PHONY: all clean
|
||||||
|
|
19
config.mk
19
config.mk
|
@ -1,3 +1,20 @@
|
||||||
PREFIX = /usr/local
|
SRC = src/llist.c
|
||||||
|
BIN =
|
||||||
|
|
||||||
CC = clang
|
CC = clang
|
||||||
DEBUG = 1
|
DEBUG = 1
|
||||||
|
|
||||||
|
LDFLAGS =\
|
||||||
|
-static
|
||||||
|
|
||||||
|
CFLAGS =\
|
||||||
|
-std=c99\
|
||||||
|
-Weverything\
|
||||||
|
-Wno-padded\
|
||||||
|
-Wno-disabled-macro-expansion\
|
||||||
|
-pedantic
|
||||||
|
ifeq (${DEBUG},1)
|
||||||
|
CFLAGS += -g
|
||||||
|
else
|
||||||
|
CFLAGS += -O2 -Werror
|
||||||
|
endif
|
||||||
|
|
293
llist.c
293
llist.c
|
@ -1,293 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of corelibs. (https://git.redxen.eu/corelibs)
|
|
||||||
* Copyright (c) 2021 Alex-David Denes
|
|
||||||
*
|
|
||||||
* corelibs is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* corelibs is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with corelibs. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "llist.h"
|
|
||||||
|
|
||||||
#include <stdarg.h> // va_args
|
|
||||||
#include <stdint.h> // uintmax_t
|
|
||||||
#include <stdlib.h> // malloc() free()
|
|
||||||
|
|
||||||
static cl_llist_err corelibs_llist_create(void*, void (*)(void*), cl_llist_t**);
|
|
||||||
|
|
||||||
static cl_llist_err corelibs_llist_link(uintmax_t, ...);
|
|
||||||
static cl_llist_err corelibs_llist_rep(cl_llist_t*, cl_llist_t*);
|
|
||||||
|
|
||||||
static cl_llist_err corelibs_llist_free_list(cl_llist_t*);
|
|
||||||
static cl_llist_err corelibs_llist_free_elem(cl_llist_t*);
|
|
||||||
|
|
||||||
static cl_llist_err corelibs_llist_set_cont(cl_llist_t*, void*);
|
|
||||||
static cl_llist_err corelibs_llist_set_free(cl_llist_t*, void (*)(void*));
|
|
||||||
|
|
||||||
static cl_llist_err corelibs_llist_get_next(const cl_llist_t*, cl_llist_t**);
|
|
||||||
static cl_llist_err corelibs_llist_get_prev(const cl_llist_t*, cl_llist_t**);
|
|
||||||
static cl_llist_err corelibs_llist_get_cont(const cl_llist_t*, void**);
|
|
||||||
|
|
||||||
static void corelibs_llist_remove(cl_llist_t*);
|
|
||||||
|
|
||||||
struct cl_llist_t {
|
|
||||||
struct cl_llist_t *next, *prev;
|
|
||||||
void* cont;
|
|
||||||
void (*free)(void*);
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { // Avoid collision in error numbers
|
|
||||||
CORELIBS_LLIST_ERR_ARGS_MIS = -4,
|
|
||||||
CORELIBS_LLIST_ERR_UNDEF,
|
|
||||||
CORELIBS_LLIST_ERR_MEM_NULL,
|
|
||||||
CORELIBS_LLIST_ERR_MEM_ALLOC,
|
|
||||||
CORELIBS_LLIST_ERR_UNK = 0,
|
|
||||||
CORELIBS_LLIST_ERR_OK = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct corelibs_llist_interface const cl_llist = {
|
|
||||||
.create = corelibs_llist_create,
|
|
||||||
.link = corelibs_llist_link,
|
|
||||||
.rep = corelibs_llist_rep,
|
|
||||||
.free = {
|
|
||||||
.list = corelibs_llist_free_list,
|
|
||||||
.elem = corelibs_llist_free_elem,
|
|
||||||
},
|
|
||||||
.set = {
|
|
||||||
.cont = corelibs_llist_set_cont,
|
|
||||||
.free = corelibs_llist_set_free,
|
|
||||||
},
|
|
||||||
.get = {
|
|
||||||
.prev = corelibs_llist_get_prev,
|
|
||||||
.cont = corelibs_llist_get_cont,
|
|
||||||
.next = corelibs_llist_get_next,
|
|
||||||
},
|
|
||||||
.err = {
|
|
||||||
.ok = CORELIBS_LLIST_ERR_OK,
|
|
||||||
.unknown = CORELIBS_LLIST_ERR_UNK,
|
|
||||||
.undef = CORELIBS_LLIST_ERR_UNDEF,
|
|
||||||
.mem = {
|
|
||||||
.null = CORELIBS_LLIST_ERR_MEM_NULL,
|
|
||||||
.alloc = CORELIBS_LLIST_ERR_MEM_ALLOC,
|
|
||||||
},
|
|
||||||
.args = {
|
|
||||||
.mis = CORELIBS_LLIST_ERR_ARGS_MIS,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_create(void* c, void (*const f)(void*), cl_llist_t** s)
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
cl_llist_t* cur = malloc(sizeof(*cur));
|
|
||||||
if (cur == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_MEM_ALLOC;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur->prev = NULL;
|
|
||||||
cur->next = NULL;
|
|
||||||
cur->cont = c;
|
|
||||||
cur->free = f;
|
|
||||||
|
|
||||||
*s = cur;
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_free_list(cl_llist_t* l)
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
if (l == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_MEM_NULL;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free previous elements if we have any
|
|
||||||
if (l->prev != NULL) {
|
|
||||||
for (cl_llist_t* p = l->prev; p != NULL;) {
|
|
||||||
cl_llist_t* c = p;
|
|
||||||
p = p->prev;
|
|
||||||
corelibs_llist_remove(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free current and next elements
|
|
||||||
for (cl_llist_t* p = l; p != NULL;) {
|
|
||||||
cl_llist_t* c = p;
|
|
||||||
p = p->next;
|
|
||||||
corelibs_llist_remove(c);
|
|
||||||
}
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_free_elem(cl_llist_t* l)
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
if (l == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_MEM_NULL;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
corelibs_llist_remove(l);
|
|
||||||
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_link(uintmax_t cnt, ...)
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
if (cnt <= 1) {
|
|
||||||
err = CORELIBS_LLIST_ERR_ARGS_MIS;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, cnt);
|
|
||||||
|
|
||||||
uintmax_t ccnt = 0;
|
|
||||||
cl_llist_t *a = NULL, *b = NULL;
|
|
||||||
while (ccnt < cnt) {
|
|
||||||
a = b;
|
|
||||||
b = va_arg(ap, cl_llist_t*);
|
|
||||||
if (ccnt < 1) continue; // Fill at least first 2 slots
|
|
||||||
|
|
||||||
if (a != NULL) a->next = b;
|
|
||||||
if (b != NULL) b->prev = a;
|
|
||||||
|
|
||||||
ccnt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(ap);
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_rep(cl_llist_t* dest, cl_llist_t* src)
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
if (src == NULL || dest == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_MEM_NULL;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dest->prev != NULL) dest->prev->next = src;
|
|
||||||
if (dest->next != NULL) dest->next->prev = src;
|
|
||||||
|
|
||||||
corelibs_llist_free_elem(dest);
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_get_next(const cl_llist_t* e, cl_llist_t** save)
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
if (e == NULL || save == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_MEM_NULL;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->next == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_UNDEF;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
*save = e->next;
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_get_prev(const cl_llist_t* e, cl_llist_t** save)
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
if (e == NULL || save == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_MEM_NULL;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->prev == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_UNDEF;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
*save = e->prev;
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_get_cont(const cl_llist_t* e, void** save)
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
if (e == NULL || save == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_MEM_NULL;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
*save = e->cont;
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_set_cont(cl_llist_t* e, void* i)
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
if (e == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_MEM_NULL;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
e->cont = i;
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cl_llist_err
|
|
||||||
corelibs_llist_set_free(cl_llist_t* e, void (*const f)(void*))
|
|
||||||
{
|
|
||||||
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
|
||||||
|
|
||||||
if (e == NULL) {
|
|
||||||
err = CORELIBS_LLIST_ERR_MEM_NULL;
|
|
||||||
goto ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
e->free = f;
|
|
||||||
ret:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private function
|
|
||||||
static void
|
|
||||||
corelibs_llist_remove(cl_llist_t* e)
|
|
||||||
{
|
|
||||||
corelibs_llist_link(2, e->prev, e->next);
|
|
||||||
if (e->free != NULL) e->free(e->cont);
|
|
||||||
free(e);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
SRC = llist.c
|
|
||||||
HDR = llist.h
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* This file is part of corelibs. (https://git.redxen.eu/corelibs)
|
||||||
|
* Copyright (c) 2021 Alex-David Denes
|
||||||
|
*
|
||||||
|
* corelibs is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* corelibs is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with corelibs. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "llist.h"
|
||||||
|
|
||||||
|
#include <stdarg.h> // va_args
|
||||||
|
#include <stdint.h> // uintmax_t
|
||||||
|
#include <stdlib.h> // malloc() free()
|
||||||
|
|
||||||
|
static cl_llist_err corelibs_llist_create (void *, void (*) (void *), cl_llist_t **);
|
||||||
|
|
||||||
|
static cl_llist_err corelibs_llist_link (uintmax_t, ...);
|
||||||
|
static cl_llist_err corelibs_llist_rep (cl_llist_t *, cl_llist_t *);
|
||||||
|
|
||||||
|
static cl_llist_err corelibs_llist_free_list (cl_llist_t *);
|
||||||
|
static cl_llist_err corelibs_llist_free_elem (cl_llist_t *);
|
||||||
|
|
||||||
|
static cl_llist_err corelibs_llist_set_cont (cl_llist_t *, void *);
|
||||||
|
static cl_llist_err corelibs_llist_set_free (cl_llist_t *, void (*) (void *));
|
||||||
|
|
||||||
|
static cl_llist_err corelibs_llist_get_next (const cl_llist_t *, cl_llist_t **);
|
||||||
|
static cl_llist_err corelibs_llist_get_prev (const cl_llist_t *, cl_llist_t **);
|
||||||
|
static cl_llist_err corelibs_llist_get_cont (const cl_llist_t *, void **);
|
||||||
|
|
||||||
|
static void corelibs_llist_remove (cl_llist_t *);
|
||||||
|
|
||||||
|
struct cl_llist_t {
|
||||||
|
struct cl_llist_t *next, *prev;
|
||||||
|
void * cont;
|
||||||
|
void (*free) (void *);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { // Avoid collision in error numbers
|
||||||
|
CORELIBS_LLIST_ERR_ARGS_MIS = -4,
|
||||||
|
CORELIBS_LLIST_ERR_UNDEF,
|
||||||
|
CORELIBS_LLIST_ERR_MEM_NULL,
|
||||||
|
CORELIBS_LLIST_ERR_MEM_ALLOC,
|
||||||
|
CORELIBS_LLIST_ERR_UNK = 0,
|
||||||
|
CORELIBS_LLIST_ERR_OK = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct corelibs_llist_interface const cl_llist = {
|
||||||
|
.create = corelibs_llist_create,
|
||||||
|
.link = corelibs_llist_link,
|
||||||
|
.rep = corelibs_llist_rep,
|
||||||
|
.free = {
|
||||||
|
.list = corelibs_llist_free_list,
|
||||||
|
.elem = corelibs_llist_free_elem,
|
||||||
|
},
|
||||||
|
.set = {
|
||||||
|
.cont = corelibs_llist_set_cont,
|
||||||
|
.free = corelibs_llist_set_free,
|
||||||
|
},
|
||||||
|
.get = {
|
||||||
|
.prev = corelibs_llist_get_prev,
|
||||||
|
.cont = corelibs_llist_get_cont,
|
||||||
|
.next = corelibs_llist_get_next,
|
||||||
|
},
|
||||||
|
.err = {
|
||||||
|
.ok = CORELIBS_LLIST_ERR_OK,
|
||||||
|
.unknown = CORELIBS_LLIST_ERR_UNK,
|
||||||
|
.undef = CORELIBS_LLIST_ERR_UNDEF,
|
||||||
|
.mem = {
|
||||||
|
.null = CORELIBS_LLIST_ERR_MEM_NULL,
|
||||||
|
.alloc = CORELIBS_LLIST_ERR_MEM_ALLOC,
|
||||||
|
},
|
||||||
|
.args = {
|
||||||
|
.mis = CORELIBS_LLIST_ERR_ARGS_MIS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_create (void *c, void (*const f) (void *), cl_llist_t **s) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (s == NULL) err = CORELIBS_LLIST_ERR_MEM_NULL;
|
||||||
|
if (!err) {
|
||||||
|
cl_llist_t *cur = malloc (sizeof (*cur));
|
||||||
|
if (cur != NULL) {
|
||||||
|
cur->prev = NULL;
|
||||||
|
cur->next = NULL;
|
||||||
|
cur->cont = c;
|
||||||
|
cur->free = f;
|
||||||
|
*s = cur;
|
||||||
|
} else {
|
||||||
|
err = CORELIBS_LLIST_ERR_MEM_ALLOC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_free_list (cl_llist_t *l) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (l == NULL) err = CORELIBS_LLIST_ERR_MEM_NULL;
|
||||||
|
if (!err) {
|
||||||
|
// Free previous elements if we have any
|
||||||
|
if (l->prev != NULL) {
|
||||||
|
for (cl_llist_t *p = l->prev; p != NULL;) {
|
||||||
|
cl_llist_t *c = p;
|
||||||
|
p = p->prev;
|
||||||
|
corelibs_llist_remove (c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free current and next elements
|
||||||
|
for (cl_llist_t *p = l; p != NULL;) {
|
||||||
|
cl_llist_t *c = p;
|
||||||
|
p = p->next;
|
||||||
|
corelibs_llist_remove (c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_free_elem (cl_llist_t *l) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (l == NULL) err = CORELIBS_LLIST_ERR_MEM_NULL;
|
||||||
|
if (!err) {
|
||||||
|
corelibs_llist_remove (l);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_link (uintmax_t cnt, ...) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (cnt <= 1) err = CORELIBS_LLIST_ERR_ARGS_MIS;
|
||||||
|
if (!err) {
|
||||||
|
va_list ap;
|
||||||
|
va_start (ap, cnt);
|
||||||
|
|
||||||
|
uintmax_t ccnt = 0;
|
||||||
|
cl_llist_t *a = NULL, *b = NULL;
|
||||||
|
while (ccnt < cnt) {
|
||||||
|
a = b;
|
||||||
|
b = va_arg (ap, cl_llist_t *);
|
||||||
|
if (ccnt < 1) continue; // Fill at least first 2 slots
|
||||||
|
|
||||||
|
if (a != NULL) a->next = b;
|
||||||
|
if (b != NULL) b->prev = a;
|
||||||
|
|
||||||
|
ccnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end (ap);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_rep (cl_llist_t *dest, cl_llist_t *src) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (src == NULL || dest == NULL) err = CORELIBS_LLIST_ERR_MEM_NULL;
|
||||||
|
if (!err) {
|
||||||
|
if (dest->prev != NULL) dest->prev->next = src;
|
||||||
|
if (dest->next != NULL) dest->next->prev = src;
|
||||||
|
corelibs_llist_free_elem (dest);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_get_next (const cl_llist_t *e, cl_llist_t **save) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (e == NULL || save == NULL) err = CORELIBS_LLIST_ERR_MEM_NULL;
|
||||||
|
if (e->next == NULL) err = CORELIBS_LLIST_ERR_UNDEF;
|
||||||
|
if (!err) {
|
||||||
|
*save = e->next;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_get_prev (const cl_llist_t *e, cl_llist_t **save) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (e == NULL || save == NULL) err = CORELIBS_LLIST_ERR_MEM_NULL;
|
||||||
|
if (e->prev == NULL) err = CORELIBS_LLIST_ERR_UNDEF;
|
||||||
|
if (!err) {
|
||||||
|
*save = e->prev;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_get_cont (const cl_llist_t *e, void **save) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (e == NULL || save == NULL) err = CORELIBS_LLIST_ERR_MEM_NULL;
|
||||||
|
if (!err) {
|
||||||
|
*save = e->cont;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_set_cont (cl_llist_t *e, void *i) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (e == NULL) err = CORELIBS_LLIST_ERR_MEM_NULL;
|
||||||
|
if (!err) {
|
||||||
|
e->cont = i;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cl_llist_err
|
||||||
|
corelibs_llist_set_free (cl_llist_t *e, void (*const f) (void *)) {
|
||||||
|
cl_llist_err err = CORELIBS_LLIST_ERR_OK;
|
||||||
|
if (e == NULL) err = CORELIBS_LLIST_ERR_MEM_NULL;
|
||||||
|
if (!err) {
|
||||||
|
e->free = f;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private function
|
||||||
|
static void
|
||||||
|
corelibs_llist_remove (cl_llist_t *e) {
|
||||||
|
corelibs_llist_link (2, e->prev, e->next);
|
||||||
|
if (e->free != NULL) e->free (e->cont);
|
||||||
|
free (e);
|
||||||
|
}
|
Reference in New Issue