diff options
| author | Tom Lane | 2020-09-29 00:32:53 +0000 |
|---|---|---|
| committer | Tom Lane | 2020-09-29 00:33:13 +0000 |
| commit | 56fe008996bc1a547ce60c8dddd2ca821cac163e (patch) | |
| tree | 5226bf659104f86d5489332f005e6060f8a97199 /src/include | |
| parent | fe0a1dc52c7332a65b44db8e8408a5fd1d8fc8fb (diff) | |
Add for_each_from, to simplify loops starting from non-first list cells.
We have a dozen or so places that need to iterate over all but the
first cell of a List. Prior to v13 this was typically written as
for_each_cell(lc, lnext(list_head(list)))
Commit 1cff1b95a changed these to
for_each_cell(lc, list, list_second_cell(list))
This patch introduces a new macro for_each_from() which expresses
the start point as a list index, allowing these to be written as
for_each_from(lc, list, 1)
This is marginally more efficient, since ForEachState.i can be
initialized directly instead of backing into it from a ListCell
address. It also seems clearer and less typo-prone.
Some of the remaining uses of for_each_cell() look like they could
profitably be changed to for_each_from(), but here I confined myself
to changing uses of list_second_cell().
Also, fix for_each_cell_setup() and for_both_cell_setup() to
const-ify their arguments; that's a simple oversight in 1cff1b95a.
Back-patch into v13, on the grounds that (1) the const-ification
is a minor bug fix, and (2) it's better for back-patching purposes
if we only have two ways to write these loops rather than three.
In HEAD, also remove list_third_cell() and list_fourth_cell(),
which were also introduced in 1cff1b95a, and are unused as of
cc99baa43. It seems unlikely that any third-party code would
have started to use them already; anyone who has can be directed
to list_nth_cell instead.
Discussion: https://postgr.es/m/CAApHDvpo1zj9KhEpU2cCRZfSM3Q6XGdhzuAS2v79PH7WJBkYVA@mail.gmail.com
Diffstat (limited to 'src/include')
| -rw-r--r-- | src/include/nodes/pg_list.h | 52 |
1 files changed, 29 insertions, 23 deletions
diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index 104df4174ab..ec231010ce4 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -144,26 +144,6 @@ list_second_cell(const List *l) return NULL; } -/* Fetch address of list's third cell, if it has one, else NULL */ -static inline ListCell * -list_third_cell(const List *l) -{ - if (l && l->length >= 3) - return &l->elements[2]; - else - return NULL; -} - -/* Fetch address of list's fourth cell, if it has one, else NULL */ -static inline ListCell * -list_fourth_cell(const List *l) -{ - if (l && l->length >= 4) - return &l->elements[3]; - else - return NULL; -} - /* Fetch list's length */ static inline int list_length(const List *l) @@ -390,6 +370,32 @@ lnext(const List *l, const ListCell *c) #define foreach_current_index(cell) (cell##__state.i) /* + * for_each_from - + * Like foreach(), but start from the N'th (zero-based) list element, + * not necessarily the first one. + * + * It's okay for N to exceed the list length, but not for it to be negative. + * + * The caveats for foreach() apply equally here. + */ +#define for_each_from(cell, lst, N) \ + for (ForEachState cell##__state = for_each_from_setup(lst, N); \ + (cell##__state.l != NIL && \ + cell##__state.i < cell##__state.l->length) ? \ + (cell = &cell##__state.l->elements[cell##__state.i], true) : \ + (cell = NULL, false); \ + cell##__state.i++) + +static inline ForEachState +for_each_from_setup(const List *lst, int N) +{ + ForEachState r = {lst, N}; + + Assert(N >= 0); + return r; +} + +/* * for_each_cell - * a convenience macro which loops through a list starting from a * specified cell @@ -405,7 +411,7 @@ lnext(const List *l, const ListCell *c) cell##__state.i++) static inline ForEachState -for_each_cell_setup(List *lst, ListCell *initcell) +for_each_cell_setup(const List *lst, const ListCell *initcell) { ForEachState r = {lst, initcell ? list_cell_number(lst, initcell) : list_length(lst)}; @@ -456,8 +462,8 @@ for_each_cell_setup(List *lst, ListCell *initcell) cell1##__state.i1++, cell1##__state.i2++) static inline ForBothCellState -for_both_cell_setup(List *list1, ListCell *initcell1, - List *list2, ListCell *initcell2) +for_both_cell_setup(const List *list1, const ListCell *initcell1, + const List *list2, const ListCell *initcell2) { ForBothCellState r = {list1, list2, initcell1 ? list_cell_number(list1, initcell1) : list_length(list1), |
