From 6dc59ccbf8d15202a970ce645a936832620c744b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sat, 30 Nov 2013 13:40:05 +0100 Subject: [PATCH] Add macros for iterating the containing entry --- include/ucore/tailq.h | 74 ++++++++++++++++++++++++++++++++++++++----- test/tailq_example.c | 36 +++++++++++++-------- 2 files changed, 88 insertions(+), 22 deletions(-) diff --git a/include/ucore/tailq.h b/include/ucore/tailq.h index 3e4ce17..761259a 100644 --- a/include/ucore/tailq.h +++ b/include/ucore/tailq.h @@ -155,16 +155,44 @@ static UC_INLINE void uc_tailq_move_tail(struct TailQ *entry, struct TailQ *head * @param head the struct TailQ* head of the tailq */ #define UC_TAILQ_FOREACH(entry, head)\ - for ((entry) = (head)->next; (entry) != (head); (entry) = (entry)->next) + for ((entry) = UC_TAILQ_FIRST(head); \ + (entry) != (head); \ + (entry) = UC_TAILQ_NEXT(entry)) -/** Iterate over a tailq in reverse order. The tailq cannot be altered while - * iterating. +/** Iterate over the containing element in a tailq. + * The tailq cannot be altered while iterating. + * + * @param ptr a pointer to the struct which the tailq nodes are member of + * @param member the member of ptr that is the tailq node + * @param head the struct TailQ* head of the tailq + */ +#define UC_TAILQ_FOREACH_CONTAINER(ptr, member, head)\ + for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_FIRST(head), typeof(*ptr), member);\ + &(ptr)->member != (head);\ + (ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member)) + +/** Iterate over a tailq in reverse order. + * The tailq cannot be altered while iterating. * * @param entry a struct TailQ* to which each element is assigned. * @param head the struct TailQ* head of the tailq */ #define UC_TAILQ_FOREACH_REVERSE(entry, head)\ - for ((entry) = (head)->prev; (entry) != (head); (entry) = (entry)->prev) + for ((entry) = UC_TAILQ_LAST(entry); \ + (entry) != (head); \ + (entry) = UC_TAILQ_PREV(entry) + +/** Iterate over the containing element in a tailq in reverse. + * The tailq cannot be altered while iterating. + * + * @param ptr a pointer to the struct which the tailq nodes are member of + * @param member the member of ptr that is the tailq node + * @param head the struct TailQ* head of the tailq + */ +#define UC_TAILQ_FOREACH_REVERSE_CONTAINER(ptr, member, head)\ + for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_LAST(head), typeof(*ptr), member);\ + &(ptr)->member != (head);\ + (ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_PREV(&(ptr)->member), typeof(*ptr), member)) /** Iterate over a tailq. safe to remove the entry when iterating. * @@ -173,9 +201,24 @@ static UC_INLINE void uc_tailq_move_tail(struct TailQ *entry, struct TailQ *head * @param head the struct TailQ* head of the tailq */ #define UC_TAILQ_FOREACH_SAFE(entry, nxt, head)\ - for ((entry) = (head)->next, nxt = (entry)->next; \ + for ((entry) = UC_TAILQ_FIRST(head), (nxt) = UC_TAILQ_NEXT(entry); \ (entry) != (head); \ - (entry) = (nxt), (nxt) = (entry)->next) + (entry) = (nxt), (nxt) = UC_TAILQ_NEXT(entry))\ + +/** Iterate over the containing element in a tailq, safe to remove + * the entry when iterating + * + * @param ptr a pointer to the struct which the tailq nodes are member of + * @param nxt same type as ptr needed for temporary storage. + * @param member the member of ptr that is the tailq node + * @param head the struct TailQ* head of the tailq + */ +#define UC_TAILQ_FOREACH_CONTAINER_SAFE(ptr, nxt, member, head)\ + for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_FIRST(head), typeof(*ptr), member),\ + (nxt) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member);\ + &(ptr)->member != (head);\ + (ptr) = (nxt),\ + (nxt) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member)) /** Iterate over a tailq in reverse order. safe to remove the entry when * iterating. @@ -185,9 +228,24 @@ static UC_INLINE void uc_tailq_move_tail(struct TailQ *entry, struct TailQ *head * @param head the struct TailQ* head of the tailq */ #define UC_TAILQ_FOREACH_REVERSE_SAFE(entry, prv, head)\ - for ((entry) = (head)->prev, prev = (entry)->prev; \ + for ((entry) = UC_TAILQ_LAST(head), (prv) = UC_TAILQ_PREV(entry); \ (entry) != (head); \ - (entry) = (prv), (prv) = (entry)->prev) + (entry) = (prv), (prv) = UC_TAILQ_PREV(entry))\ + +/** Iterate over the containing element in a tailq in reverse order, safe + * to remove the entry when iterating + * + * @param ptr a pointer to the struct which the tailq nodes are member of + * @param prv same type as ptr needed for temporary storage. + * @param member the member of ptr that is the tailq node + * @param head the struct TailQ* head of the tailq + */ +#define UC_TAILQ_FOREACH_REVERSE_CONTAINER_SAFE(ptr, prv, member, head)\ + for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_LAST(head), typeof(*ptr), member),\ + (prv) = UC_TAILQ_CONTAINER(UC_TAILQ_PREV(&(ptr)->member), typeof(*ptr), member);\ + &(ptr)->member != (head);\ + (ptr) = (prv),\ + (prv) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member)) #undef UC_INLINE diff --git a/test/tailq_example.c b/test/tailq_example.c index 11419b6..e91609f 100644 --- a/test/tailq_example.c +++ b/test/tailq_example.c @@ -23,32 +23,38 @@ void add_block(struct File *f, const char *txt) void print_file(struct File *f) { - struct TailQ *entry; + struct Block *entry; printf("File: %s\n", f->name); - UC_TAILQ_FOREACH(entry, &f->head) { - struct Block *b = UC_CONTAINER_OF(entry, struct Block, blocks); - printf("Block: %s\n", b->text); + UC_TAILQ_FOREACH_CONTAINER(entry, blocks, &f->head) { + printf("Block: %s\n", entry->text); + } +} + +void print_file_reverse(struct File *f) +{ + struct Block *entry; + printf("File: %s\n", f->name); + UC_TAILQ_FOREACH_REVERSE_CONTAINER(entry, blocks, &f->head) { + printf("Block: %s\n", entry->text); } } void delete_block(struct File *f, const char *txt) { - struct TailQ *entry, *next; - UC_TAILQ_FOREACH_SAFE(entry, next, &f->head) { - struct Block *b = UC_CONTAINER_OF(entry, struct Block, blocks); - if (strcmp(txt, b->text) == 0) { - uc_tailq_remove(entry); - free(b); + struct Block *entry, *next; + UC_TAILQ_FOREACH_CONTAINER_SAFE(entry, next, blocks, &f->head) { + if (strcmp(txt, entry->text) == 0) { + uc_tailq_remove(&entry->blocks); + free(entry); } } } void delete_all_blocks(struct File *f) { - struct TailQ *entry, *next; - UC_TAILQ_FOREACH_SAFE(entry, next, &f->head) { - struct Block *b = UC_CONTAINER_OF(entry, struct Block, blocks); - free(b); + struct Block *entry, *next; + UC_TAILQ_FOREACH_CONTAINER_SAFE(entry, next, blocks, &f->head) { + free(entry); } uc_tailq_init(&f->head); } @@ -74,6 +80,8 @@ int main(void) add_block(&f,"three"); add_block(&f,"three"); print_file(&f); + puts("\nReverse order:"); + print_file_reverse(&f); puts("\nDeleting three"); delete_block(&f, "three");