From 9a55aaca32df321dbf2954ed96069a644473e7c5 Mon Sep 17 00:00:00 2001 From: Ronan Dalton Date: Wed, 20 Nov 2024 11:16:11 +1300 Subject: [PATCH] c-list: add reverse iterators Add reverse versions of each for_each macro, allowing for reverse iteration of lists. --- src/c-list.h | 132 ++++++++++++++++++++++++++++++++++++------------- src/test-api.c | 34 +++++++++++++ 2 files changed, 132 insertions(+), 34 deletions(-) diff --git a/src/c-list.h b/src/c-list.h index 711b54d..c05a219 100644 --- a/src/c-list.h +++ b/src/c-list.h @@ -362,72 +362,136 @@ static inline CList *c_list_last(CList *list) { * it assumes the entire list will be unlinked. You must not * break out of the loop, or the list will be in an inconsistent * state. + * + * - "reverse": The list is iterated in reverse order. + * + * Note: macros starting with "__" are not meant to be used directly. */ /* direct/raw iterators */ -#define c_list_for_each(_iter, _list) \ - for (_iter = (_list)->next; \ +#define __c_list_for_each(_iter, _list, _dir) \ + for (_iter = (_list)->_dir; \ (_iter) != (_list); \ - _iter = (_iter)->next) + _iter = (_iter)->_dir) -#define c_list_for_each_safe(_iter, _safe, _list) \ - for (_iter = (_list)->next, _safe = (_iter)->next; \ +#define __c_list_for_each_safe(_iter, _safe, _list, _dir) \ + for (_iter = (_list)->_dir, _safe = (_iter)->_dir; \ (_iter) != (_list); \ - _iter = (_safe), _safe = (_safe)->next) + _iter = (_safe), _safe = (_safe)->_dir) -#define c_list_for_each_continue(_iter, _list) \ - for (_iter = (_iter) ? (_iter)->next : (_list)->next; \ +#define __c_list_for_each_continue(_iter, _list, _dir) \ + for (_iter = (_iter) ? (_iter)->_dir : (_list)->_dir; \ (_iter) != (_list); \ - _iter = (_iter)->next) + _iter = (_iter)->_dir) -#define c_list_for_each_safe_continue(_iter, _safe, _list) \ - for (_iter = (_iter) ? (_iter)->next : (_list)->next, \ - _safe = (_iter)->next; \ +#define __c_list_for_each_safe_continue(_iter, _safe, _list, _dir) \ + for (_iter = (_iter) ? (_iter)->_dir : (_list)->_dir, \ + _safe = (_iter)->_dir; \ (_iter) != (_list); \ - _iter = (_safe), _safe = (_safe)->next) + _iter = (_safe), _safe = (_safe)->_dir) -#define c_list_for_each_safe_unlink(_iter, _safe, _list) \ - for (_iter = (_list)->next, _safe = (_iter)->next; \ +#define __c_list_for_each_safe_unlink(_iter, _safe, _list, _dir) \ + for (_iter = (_list)->_dir, _safe = (_iter)->_dir; \ c_list_init(_iter) != (_list); \ - _iter = (_safe), _safe = (_safe)->next) + _iter = (_safe), _safe = (_safe)->_dir) + +#define c_list_for_each(_iter, _list) \ + __c_list_for_each(_iter, _list, next) + +#define c_list_for_each_reverse(_iter, _list) \ + __c_list_for_each(_iter, _list, prev) + +#define c_list_for_each_safe(_iter, _safe, _list) \ + __c_list_for_each_safe(_iter, _safe, _list, next) + +#define c_list_for_each_safe_reverse(_iter, _safe, _list) \ + __c_list_for_each_safe(_iter, _safe, _list, prev) + +#define c_list_for_each_continue(_iter, _list) \ + __c_list_for_each_continue(_iter, _list, next) + +#define c_list_for_each_continue_reverse(_iter, _list) \ + __c_list_for_each_continue(_iter, _list, prev) + +#define c_list_for_each_safe_continue(_iter, _safe, _list) \ + __c_list_for_each_safe_continue(_iter, _safe, _list, next) + +#define c_list_for_each_safe_continue_reverse(_iter, _safe, _list) \ + __c_list_for_each_safe_continue(_iter, _safe, _list, prev) + +#define c_list_for_each_safe_unlink(_iter, _safe, _list) \ + __c_list_for_each_safe_unlink(_iter, _safe, _list, next) + +#define c_list_for_each_safe_unlink_reverse(_iter, _safe, _list) \ + __c_list_for_each_safe_unlink(_iter, _safe, _list, prev) /* c_list_entry() based iterators */ -#define c_list_for_each_entry(_iter, _list, _m) \ - for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m); \ +#define __c_list_for_each_entry(_iter, _list, _m, _dir) \ + for (_iter = c_list_entry((_list)->_dir, __typeof__(*_iter), _m); \ &(_iter)->_m != (_list); \ - _iter = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m)) + _iter = c_list_entry((_iter)->_m._dir, __typeof__(*_iter), _m)) -#define c_list_for_each_entry_safe(_iter, _safe, _list, _m) \ - for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m), \ - _safe = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m); \ +#define __c_list_for_each_entry_safe(_iter, _safe, _list, _m, _dir) \ + for (_iter = c_list_entry((_list)->_dir, __typeof__(*_iter), _m), \ + _safe = c_list_entry((_iter)->_m._dir, __typeof__(*_iter), _m); \ &(_iter)->_m != (_list); \ _iter = (_safe), \ - _safe = c_list_entry((_safe)->_m.next, __typeof__(*_iter), _m)) + _safe = c_list_entry((_safe)->_m._dir, __typeof__(*_iter), _m)) -#define c_list_for_each_entry_continue(_iter, _list, _m) \ - for (_iter = c_list_entry((_iter) ? (_iter)->_m.next : (_list)->next, \ +#define __c_list_for_each_entry_continue(_iter, _list, _m, _dir) \ + for (_iter = c_list_entry((_iter) ? (_iter)->_m._dir : (_list)->_dir, \ __typeof__(*_iter), \ _m); \ &(_iter)->_m != (_list); \ - _iter = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m)) + _iter = c_list_entry((_iter)->_m._dir, __typeof__(*_iter), _m)) -#define c_list_for_each_entry_safe_continue(_iter, _safe, _list, _m) \ - for (_iter = c_list_entry((_iter) ? (_iter)->_m.next : (_list)->next, \ +#define __c_list_for_each_entry_safe_continue(_iter, _safe, _list, _m, _dir) \ + for (_iter = c_list_entry((_iter) ? (_iter)->_m._dir : (_list)->_dir, \ __typeof__(*_iter), \ _m), \ - _safe = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m); \ + _safe = c_list_entry((_iter)->_m._dir, __typeof__(*_iter), _m); \ &(_iter)->_m != (_list); \ _iter = (_safe), \ - _safe = c_list_entry((_safe)->_m.next, __typeof__(*_iter), _m)) + _safe = c_list_entry((_safe)->_m._dir, __typeof__(*_iter), _m)) -#define c_list_for_each_entry_safe_unlink(_iter, _safe, _list, _m) \ - for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m), \ - _safe = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m); \ +#define __c_list_for_each_entry_safe_unlink(_iter, _safe, _list, _m, _dir) \ + for (_iter = c_list_entry((_list)->_dir, __typeof__(*_iter), _m), \ + _safe = c_list_entry((_iter)->_m._dir, __typeof__(*_iter), _m); \ c_list_init(&(_iter)->_m) != (_list); \ _iter = (_safe), \ - _safe = c_list_entry((_safe)->_m.next, __typeof__(*_iter), _m)) + _safe = c_list_entry((_safe)->_m._dir, __typeof__(*_iter), _m)) + +#define c_list_for_each_entry(_iter, _list, _m) \ + __c_list_for_each_entry(_iter, _list, _m, next) + +#define c_list_for_each_entry_reverse(_iter, _list, _m) \ + __c_list_for_each_entry(_iter, _list, _m, prev) + +#define c_list_for_each_entry_safe(_iter, _safe, _list, _m) \ + __c_list_for_each_entry_safe(_iter, _safe, _list, _m, next) + +#define c_list_for_each_entry_safe_reverse(_iter, _safe, _list, _m) \ + __c_list_for_each_entry_safe(_iter, _safe, _list, _m, prev) + +#define c_list_for_each_entry_continue(_iter, _list, _m) \ + __c_list_for_each_entry_continue(_iter, _list, _m, next) + +#define c_list_for_each_entry_continue_reverse(_iter, _list, _m) \ + __c_list_for_each_entry_continue(_iter, _list, _m, prev) + +#define c_list_for_each_entry_safe_continue(_iter, _safe, _list, _m) \ + __c_list_for_each_entry_safe_continue(_iter, _safe, _list, _m, next) + +#define c_list_for_each_entry_safe_continue_reverse(_iter, _safe, _list, _m) \ + __c_list_for_each_entry_safe_continue(_iter, _safe, _list, _m, prev) + +#define c_list_for_each_entry_safe_unlink(_iter, _safe, _list, _m) \ + __c_list_for_each_entry_safe_unlink(_iter, _safe, _list, _m, next) + +#define c_list_for_each_entry_safe_unlink_reverse(_iter, _safe, _list, _m) \ + __c_list_for_each_entry_safe_unlink(_iter, _safe, _list, _m, prev) /** * c_list_flush() - flush all entries from a list diff --git a/src/test-api.c b/src/test-api.c index 864d198..c8af9a1 100644 --- a/src/test-api.c +++ b/src/test-api.c @@ -86,20 +86,37 @@ static void test_api(void) { c_list_for_each(list_iter, &list) assert(list_iter != &list); + c_list_for_each_reverse(list_iter, &list) + assert(list_iter != &list); + c_list_for_each_safe(list_iter, list_safe, &list) assert(list_iter != &list); + c_list_for_each_safe_reverse(list_iter, list_safe, &list) + assert(list_iter != &list); + list_iter = NULL; c_list_for_each_continue(list_iter, &list) assert(list_iter != &list); + list_iter = NULL; + c_list_for_each_continue_reverse(list_iter, &list) + assert(list_iter != &list); + list_iter = NULL; c_list_for_each_safe_continue(list_iter, list_safe, &list) assert(list_iter != &list); + list_iter = NULL; + c_list_for_each_safe_continue_reverse(list_iter, list_safe, &list) + assert(list_iter != &list); + c_list_for_each_safe_unlink(list_iter, list_safe, &list) assert(list_iter != &list); + c_list_for_each_safe_unlink_reverse(list_iter, list_safe, &list) + assert(list_iter != &list); + /* list accessors */ assert(!c_list_first(&list)); @@ -118,19 +135,36 @@ static void test_api_gnu(void) { c_list_for_each_entry(node_iter, &list, link) assert(&node_iter->link != &list); + c_list_for_each_entry_reverse(node_iter, &list, link) + assert(&node_iter->link != &list); + c_list_for_each_entry_safe(node_iter, node_safe, &list, link) assert(&node_iter->link != &list); + c_list_for_each_entry_safe_reverse(node_iter, node_safe, &list, link) + assert(&node_iter->link != &list); + node_iter = NULL; c_list_for_each_entry_continue(node_iter, &list, link) assert(&node_iter->link != &list); + node_iter = NULL; + c_list_for_each_entry_continue_reverse(node_iter, &list, link) + assert(&node_iter->link != &list); + node_iter = NULL; c_list_for_each_entry_safe_continue(node_iter, node_safe, &list, link) assert(&node_iter->link != &list); + node_iter = NULL; + c_list_for_each_entry_safe_continue_reverse(node_iter, node_safe, &list, link) + assert(&node_iter->link != &list); + c_list_for_each_entry_safe_unlink(node_iter, node_safe, &list, link) assert(&node_iter->link != &list); + + c_list_for_each_entry_safe_unlink_reverse(node_iter, node_safe, &list, link) + assert(&node_iter->link != &list); } #else static void test_api_gnu(void) {