From 6b21a0da96967bf94a7569e0a1c89bf13cf38868 Mon Sep 17 00:00:00 2001 From: Jelte Fennema-Nio Date: Wed, 25 Oct 2023 14:20:07 +0200 Subject: [PATCH v5 3/3] Introduce for_each_object Add new for_each_object helper that does not require var argument to be declared before hand. --- src/backend/replication/logical/tablesync.c | 3 +-- src/include/nodes/pg_list.h | 23 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index c82d05a642e..ed27181c2a9 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -416,7 +416,6 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn) TimestampTz last_start_time; }; static HTAB *last_start_times = NULL; - SubscriptionRelState *rstate; bool started_tx = false; bool should_exit = false; @@ -453,7 +452,7 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn) /* * Process all tables that are being synchronized. */ - for_each_ptr(rstate, table_states_not_ready) + for_each_object(SubscriptionRelState, rstate, table_states_not_ready) { if (rstate->state == SUBREL_STATE_SYNCDONE) { diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index e09116e8fdb..0748d36536b 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -473,6 +473,29 @@ for_each_cell_setup(const List *lst, const ListCell *initcell) (var = lfirst(&var##__state.l->elements[var##__state.i]), true));\ var##__state.i++) +/* + * for_each_object - + * a convenience macro which loops through a list of pointers without + * needing a "ListCell *" only a type and variable name. It automatically + * declares a loop variable with the given name and type; + * + * Unlike with foreach() it's not possible to detect if an early "break" + * occured by checking the value of the loop variable at the end of the loop. + * If you need this, it's recommended to use foreach() instead or manually keep + * track of a break occured using a boolean flag variable called e.g. "found". + * + * The caveats for foreach() apply equally here. + */ +#define for_each_object(type, var, lst) \ + for (type * var = NULL, *var##__outerloop = (type *) 1; \ + var##__outerloop; \ + var##__outerloop = NULL) \ + 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##__state.i++) + /* * for_each_int - * a convenience macro which loops through a list of ints without needing a -- 2.34.1