From 6b8e8a4762e01e3c50ac2d1232bd518a60d29979 Mon Sep 17 00:00:00 2001 From: fef Date: Sun, 18 Jul 2021 21:10:43 +0200 Subject: [PATCH] list: add "simple" linked list --- include/neo/list.h | 151 +++++++++++++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 2 +- src/list.c | 72 +++++++++++++++++++++ 3 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 include/neo/list.h create mode 100644 src/list.c diff --git a/include/neo/list.h b/include/neo/list.h new file mode 100644 index 0000000..700ca45 --- /dev/null +++ b/include/neo/list.h @@ -0,0 +1,151 @@ +/** See the end of this file for copyright and license terms. */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "neo/_stddef.h" +#include "neo/_types.h" + +struct _neo_listnode { + struct _neo_listnode *_next; + struct _neo_listnode *_prev; + struct _neo_list *_list; +}; +/** + * List node anchor for embedding into your own structure. + */ +typedef struct _neo_listnode listnode_t; + +struct _neo_list { + struct _neo_listnode _root; + NLEN_FIELD(_len); +}; +typedef struct _neo_list list_t; + +/** + * Initialize a list. + * + * @param list: The list + */ +void list_init(list_t *list); + +/** + * When casting out from a `listnode_t` to its supposed containing structure + * (in a loop), it is possible that it was in fact the `list_t` that contained + * the `listnode_t`. This macro checks whether that is the case. + * + * @param casted: `struct *` that the `listnode_t *` was casted out to + * @param list: `list_t *` storing the root `listnode_t` + * @param member: Name of the `listnode_t` member embedded within the `struct *` + */ +#define _neo_list_is_root(casted, list, member) \ + ( &(casted)->member == &(list)->_root ) + +#define _neo_list_first(list, type, member) ({ \ + void *__ptr = (list)->_root._next; \ + (type)( __ptr - offsetof(type, member) ); \ +}) + +#define _neo_list_last(list, type, member) ({ \ + void *__ptr = (list)->_root._prev; \ + (type)( __ptr - offsetof(type, member) ); \ +}) + +#define _neo_list_next(current, member) ({ \ + void *__next = (current)->member._next; \ + (typeof(current))( __next - offsetof(typeof(current), member) ); \ +}) + +#define _neo_list_prev(current, member) ({ \ + void *__prev = (current)->member._prev; \ + (typeof(current))( __prev - offsetof(typeof(current), member) ); \ +}) + +/** + * Append a new node to the end of a list. + * + * @param list: List to append to + * @param new: New node to append + */ +void list_add(list_t *list, listnode_t *new); + +/** + * Remove a node from a list. + * + * @param node: Node to remove + */ +void list_del(listnode_t *node); + +/** + * Insert a new node to the beginning of a list. + * + * @param list: List to insert the node into + * @param new: New node to insert + */ +void list_add_first(list_t *list, listnode_t *new); + +/** + * Insert a new node after the specified list node. + * + * @param pos: List node to insert the new node after + * @param new: Node to insert after the specified position + */ +void list_insert(listnode_t *pos, listnode_t *new); + +/** + * Insert a new node before the specified list node. + * + * @param pos: List node to insert the new node before + * @param new: Node to insert before the specified position + */ +void list_insert_before(listnode_t *pos, listnode_t *new); + +/** + * Iterate over each item in a list. + * + * The current entry can be safely removed from the list. + * + * @param cursor: `type *` to use as a cursor; may be a declaration + * @param list: `list_t *` to iterate over + * @param member: Name of the `listnode_t` member embedded within `cursor` + */ +#define list_foreach(cursor, list, member) \ + for (cursor = _neo_list_first(list, typeof(cursor), member)), \ + typeof(cursor) __tmp = _neo_list_next(cursor, member); \ + !_neo_list_is_root(cursor, list, member); \ + cursor = __tmp, __tmp = _neo_list_next(__tmp, member)) + +/** + * Iterate over each item in a list in reverse order. + * + * The current entry can be safely removed from the list. + * + * @param cursor: `type *` to use as a cursor; may be a declaration + * @param list: `list_t *` to iterate over + * @param member: Name of the `listnode_t` member embedded within `cursor` + */ +#define list_foreach_reverse(cursor, list, member) \ + for (cursor = _neo_list_last(list, typeof(cursor), member)), \ + typeof(cursor) __tmp = _neo_list_prev(cursor, member); \ + !_neo_list_is_root(cursor, list, member); \ + cursor = __tmp, __tmp = _neo_list_prev(__tmp, member)) + +#ifdef __cplusplus +}; /* extern "C" */ +#endif + +/* + * This file is part of libneo. + * Copyright (c) 2021 Fefie . + * + * libneo is non-violent software: you may only use, redistribute, + * and/or modify it under the terms of the CNPLv6+ as found in + * the LICENSE file in the source code root directory or at + * . + * + * libneo comes with ABSOLUTELY NO WARRANTY, to the extent + * permitted by applicable law. See the CNPLv6+ for details. + */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6709102..1be6673 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,7 @@ add_library(neo STATIC) -target_link_options(neo INTERFACE -T${CMAKE_SOURCE_DIR}/src/neo.ld) +target_link_options(neo INTERFACE -T${CMAKE_CURRENT_SOURCE_DIR}/src/neo.ld) execute_process(COMMAND uname -m OUTPUT_VARIABLE HOST_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) string(TOLOWER "${HOST_ARCH}" HOST_ARCH) diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..01c9676 --- /dev/null +++ b/src/list.c @@ -0,0 +1,72 @@ +/** See the end of this file for copyright and license terms. */ + +#include "neo/list.h" + +void list_init(list_t *list) +{ + list->_root._next = &list->_root; + list->_root._prev = &list->_root; + list->_root._list = list; + list->_len = 0; +} + +void list_add(list_t *list, listnode_t *new) +{ + list_insert_before(&list->_root, new); + new->_list = list; + list->_len++; +} + +void list_add_first(list_t *list, listnode_t *new) +{ + list_insert(&list->_root, new); + new->_list = list; + list->_len++; +} + +void list_del(listnode_t *node) +{ + node->_prev->_next = node->_next; + node->_next->_prev = node->_prev; + + node->_list->_len++; + + /* TODO: find a way to nil the pointers in node w/out breaking list_foreach */ +} + +void list_insert(listnode_t *pos, listnode_t *new) +{ + new->_next = pos->_next; + pos->_next->_prev = new; + + new->_prev = pos; + pos->_next = new; + + new->_list = pos->_list; + pos->_list->_len++; +} + +void list_insert_before(listnode_t *pos, listnode_t *new) +{ + pos->_prev->_next = new; + new->_prev = pos->_prev; + + new->_next = pos; + pos->_prev = new; + + new->_list = pos->_list; + pos->_list->_len++; +} + +/* + * This file is part of libneo. + * Copyright (c) 2021 Fefie . + * + * libneo is non-violent software: you may only use, redistribute, + * and/or modify it under the terms of the CNPLv6+ as found in + * the LICENSE file in the source code root directory or at + * . + * + * libneo comes with ABSOLUTELY NO WARRANTY, to the extent + * permitted by applicable law. See the CNPLv6+ for details. + */