From 0effd91ab9ee3b3c678f1d128e487b9a728c8588 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
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

