From 0effd91ab9ee3b3c678f1d128e487b9a728c8588 Mon Sep 17 00:00:00 2001 From: Jelte Fennema-Nio Date: Tue, 24 Oct 2023 16:46:08 +0200 Subject: [PATCH v1 1/2] Add macros for looping through a list without needing a ListCell Many usages of the foreach macro only use the ListCell variable to get its contents. This adds macros that simplify iteration code for that common use case. --- src/include/nodes/pg_list.h | 92 ++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index 529a382d284..af1ecc5e394 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -383,13 +383,15 @@ lnext(const List *l, const ListCell *c) * delete the current list element from the List associated with a * surrounding foreach() loop, returning the new List pointer. * - * This is equivalent to list_delete_cell(), but it also adjusts the foreach - * loop's state so that no list elements will be missed. Do not delete - * elements from an active foreach loop's list in any other way! + * This is similar to list_delete_cell(), but it also works when using + * for_each_xyz macros that don't require passing in a "ListCell *". + * Furthermore it adjusts the foreach loop's state so that no list elements + * will be missed. Do not delete elements from an active foreach loop's list in + * any other way! */ -#define foreach_delete_current(lst, cell) \ - (cell##__state.i--, \ - (List *) (cell##__state.l = list_delete_cell(lst, cell))) +#define foreach_delete_current(lst, var) \ + (var##__state.i--, \ + (List *) (var##__state.l = list_delete_cell(lst, &var##__state.l->elements[var##__state.i]))) /* * foreach_current_index - @@ -452,6 +454,84 @@ for_each_cell_setup(const List *lst, const ListCell *initcell) return r; } +/* + * for_each_ptr - + * a convenience macro which loops through a list of pointers without + * needing a "ListCell *", just a declared pointer variable to store the + * current pointer int; + * + * The caveats for foreach() apply equally here. + */ +#define for_each_ptr(var, lst) \ + for (ForEachState var##__state = {(lst), 0}; \ + (var##__state.l != NIL && \ + var##__state.i < var##__state.l->length) ? \ + (var = lfirst(&var##__state.l->elements[var##__state.i]), true) : \ + (var = NULL, false); \ + var##__state.i++) + +/* + * for_each_int - + * a convenience macro which loops through a list of ints without needing a + * "ListCell *", just a declared int variable to store the current int in. + * + * The caveats for foreach() apply equally here. + */ +#define for_each_int(var, lst) \ + for (ForEachState var##__state = {(lst), 0}; \ + (var##__state.l != NIL && \ + var##__state.i < var##__state.l->length) ? \ + (var = lfirst_int(&var##__state.l->elements[var##__state.i]), true) : \ + (var = 0, false); \ + var##__state.i++) + +/* + * foreach_oid - + * a convenience macro which loops through an oid list without needing a + * "ListCell *", just a declared Oid variable to store the current oid in. + * + * The caveats for foreach() apply equally here. + */ +#define for_each_oid(var, lst) \ + for (ForEachState var##__state = {(lst), 0}; \ + (var##__state.l != NIL && \ + var##__state.i < var##__state.l->length) ? \ + (var = lfirst_oid(&var##__state.l->elements[var##__state.i]), true) : \ + (var = 0, false); \ + var##__state.i++) + +/* + * foreach_xid - + * a convenience macro which loops through an xid list without needing a + * "ListCell *", just a declared TransactionId variable to store the current + * xid in. + * + * The caveats for foreach() apply equally here. + */ +#define for_each_xid(var, lst) \ + for (ForEachState var##__state = {(lst), 0}; \ + (var##__state.l != NIL && \ + var##__state.i < var##__state.l->length) ? \ + (var = lfirst_xid(&var##__state.l->elements[var##__state.i]), true) : \ + (var = 0, false); \ + var##__state.i++) + +/* + * for_each_node - + * a convenience macro which loops through a node list without needing a + * "ListCell *", just a declared pointer variable to store the pointer of + * the current node in. + * + * The caveats for foreach() apply equally here. + */ +#define for_each_node(type, var, lst) \ + for (ForEachState var##__state = {(lst), 0}; \ + (var##__state.l != NIL && \ + var##__state.i < var##__state.l->length) ? \ + (var = lfirst_node(type, &var##__state.l->elements[var##__state.i]), true) : \ + (var = 0, false); \ + var##__state.i++) + /* * forboth - * a convenience macro for advancing through two linked lists base-commit: 00d7fb5e2e39198387ae00af8dd18b787b6a4d63 -- 2.34.1