/* * 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 . */ #include "llist.h" #include // va_args #include // uintmax_t #include // 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); }