Skip to content

Commit

Permalink
c-list: add reverse iterators
Browse files Browse the repository at this point in the history
Add reverse versions of each for_each macro, allowing for reverse
iteration of lists.
  • Loading branch information
ronand-atl committed Nov 19, 2024
1 parent 9aa81d8 commit 9a55aac
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 34 deletions.
132 changes: 98 additions & 34 deletions src/c-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions src/test-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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) {
Expand Down

0 comments on commit 9a55aac

Please sign in to comment.