From b1fdf930965460eedf8cf9c25ebb6087530fa5da Mon Sep 17 00:00:00 2001 From: David Rowley Date: Tue, 7 Mar 2023 12:43:26 +1300 Subject: [PATCH v2 2/4] Use do while loops instead of for loops --- src/backend/nodes/bitmapset.c | 118 +++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 51 deletions(-) diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c index 14fb100087..aec7392cff 100644 --- a/src/backend/nodes/bitmapset.c +++ b/src/backend/nodes/bitmapset.c @@ -8,7 +8,13 @@ * say at most a few hundred. By convention, we always represent a set with * the minimum possible number of words, i.e, there are never any trailing * zero words. Enforcing this requires that an empty set is represented as - * NULL. + * NULL. Because an empty Bitmapset is represented as NULL, a non-NULL + * Bitmapset always has at least 1 Bitmapword. We can exploit this fact to + * speedup various loops over the Bitmapset's words array by using "do while" + * loops instead of "for" loops. This means the code does not waste time + * checking the loop condition before the first iteration. For Bitmapsets + * containing only a single word (likely the majority of them) this reduces + * the loop condition tests by half. * * * Copyright (c) 2003-2023, PostgreSQL Global Development Group @@ -109,11 +115,11 @@ bms_equal(const Bitmapset *a, const Bitmapset *b) return false; /* check each word matches */ - for (i = 0; i < a->nwords; i++) - { + i = 0; + do { if (a->words[i] != b->words[i]) return false; - } + } while (++i < a->nwords); return true; } @@ -140,14 +146,14 @@ bms_compare(const Bitmapset *a, const Bitmapset *b) if (a->nwords != b->nwords) return (a->nwords > b->nwords) ? +1 : -1; - for (i = a->nwords - 1; i >= 0; i--) - { + i = a->nwords - 1; + do { bitmapword aw = a->words[i]; bitmapword bw = b->words[i]; if (aw != bw) return (aw > bw) ? +1 : -1; - } + } while (--i >= 0); return 0; } @@ -220,8 +226,10 @@ bms_union(const Bitmapset *a, const Bitmapset *b) } /* And union the shorter input into the result */ otherlen = other->nwords; - for (i = 0; i < otherlen; i++) + i = 0; + do { result->words[i] |= other->words[i]; + } while (++i < otherlen); return result; } @@ -254,13 +262,13 @@ bms_intersect(const Bitmapset *a, const Bitmapset *b) /* And intersect the longer input with the result */ resultlen = result->nwords; lastnonzero = -1; - for (i = 0; i < resultlen; i++) - { + i = 0; + do { result->words[i] &= other->words[i]; if (result->words[i] != 0) lastnonzero = i; - } + } while (++i < resultlen); /* If we computed an empty result, we must return NULL */ if (lastnonzero == -1) { @@ -303,13 +311,13 @@ bms_difference(const Bitmapset *a, const Bitmapset *b) /* And remove b's bits from result */ shortlen = Min(a->nwords, b->nwords); lastnonzero = -1; - for (i = 0; i < shortlen; i++) - { + i = 0; + do { result->words[i] &= ~b->words[i]; if (result->words[i] != 0) lastnonzero = i; - } + } while (++i < shortlen); /* get rid of trailing zero words */ result->nwords = lastnonzero + 1; @@ -337,11 +345,11 @@ bms_is_subset(const Bitmapset *a, const Bitmapset *b) return false; /* Check all 'a' members are set in 'b' */ - for (i = 0; i < a->nwords; i++) - { + i = 0; + do { if ((a->words[i] & ~b->words[i]) != 0) return false; - } + } while (++i < a->nwords); return true; } @@ -369,8 +377,8 @@ bms_subset_compare(const Bitmapset *a, const Bitmapset *b) /* Check common words */ result = BMS_EQUAL; /* status so far */ shortlen = Min(a->nwords, b->nwords); - for (i = 0; i < shortlen; i++) - { + i = 0; + do { bitmapword aword = a->words[i]; bitmapword bword = b->words[i]; @@ -388,7 +396,7 @@ bms_subset_compare(const Bitmapset *a, const Bitmapset *b) return BMS_DIFFERENT; result = BMS_SUBSET1; } - } + } while (++i < shortlen); /* Check extra words */ if (a->nwords > b->nwords) { @@ -488,11 +496,11 @@ bms_overlap(const Bitmapset *a, const Bitmapset *b) return false; /* Check words in common */ shortlen = Min(a->nwords, b->nwords); - for (i = 0; i < shortlen; i++) - { + i = 0; + do { if ((a->words[i] & b->words[i]) != 0) return true; - } + } while (++i < shortlen); return false; } @@ -543,11 +551,11 @@ bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b) if (a->nwords > b->nwords) return true; /* Check all 'a' members are set in 'b' */ - for (i = 0; i < a->nwords; i++) - { + i = 0; + do { if ((a->words[i] & ~b->words[i]) != 0) return true; - } + } while (++i < a->nwords); return false; } @@ -566,8 +574,8 @@ bms_singleton_member(const Bitmapset *a) if (a == NULL) elog(ERROR, "bitmapset is empty"); nwords = a->nwords; - for (wordnum = 0; wordnum < nwords; wordnum++) - { + wordnum = 0; + do { bitmapword w = a->words[wordnum]; if (w != 0) @@ -577,7 +585,7 @@ bms_singleton_member(const Bitmapset *a) result = wordnum * BITS_PER_BITMAPWORD; result += bmw_rightmost_one_pos(w); } - } + } while (++wordnum < nwords); if (result < 0) elog(ERROR, "bitmapset is empty"); return result; @@ -604,8 +612,8 @@ bms_get_singleton_member(const Bitmapset *a, int *member) if (a == NULL) return false; nwords = a->nwords; - for (wordnum = 0; wordnum < nwords; wordnum++) - { + wordnum = 0; + do { bitmapword w = a->words[wordnum]; if (w != 0) @@ -615,7 +623,7 @@ bms_get_singleton_member(const Bitmapset *a, int *member) result = wordnum * BITS_PER_BITMAPWORD; result += bmw_rightmost_one_pos(w); } - } + } while (++wordnum < nwords); if (result < 0) return false; *member = result; @@ -635,14 +643,14 @@ bms_num_members(const Bitmapset *a) if (a == NULL) return 0; nwords = a->nwords; - for (wordnum = 0; wordnum < nwords; wordnum++) - { + wordnum = 0; + do { bitmapword w = a->words[wordnum]; /* No need to count the bits in a zero word */ if (w != 0) result += bmw_popcount(w); - } + } while (++wordnum < nwords); return result; } @@ -661,8 +669,8 @@ bms_membership(const Bitmapset *a) if (a == NULL) return BMS_EMPTY_SET; nwords = a->nwords; - for (wordnum = 0; wordnum < nwords; wordnum++) - { + wordnum = 0; + do { bitmapword w = a->words[wordnum]; if (w != 0) @@ -671,7 +679,7 @@ bms_membership(const Bitmapset *a) return BMS_MULTIPLE; result = BMS_SINGLETON; } - } + } while (++wordnum < nwords); return result; } @@ -689,13 +697,13 @@ bms_is_empty_internal(const Bitmapset *a) int wordnum; nwords = a->nwords; - for (wordnum = 0; wordnum < nwords; wordnum++) - { + wordnum = 0; + do { bitmapword w = a->words[wordnum]; if (w != 0) return false; - } + } while (++wordnum < nwords); return true; } @@ -737,8 +745,10 @@ bms_add_member(Bitmapset *a, int x) a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(wordnum + 1)); a->nwords = wordnum + 1; /* zero out the enlarged portion */ - for (i = oldnwords; i < a->nwords; i++) + i = oldnwords; + do { a->words[i] = 0; + } while (++i < a->nwords); } a->words[wordnum] |= ((bitmapword) 1 << bitnum); @@ -804,8 +814,10 @@ bms_add_members(Bitmapset *a, const Bitmapset *b) } /* And union the shorter input into the result */ otherlen = other->nwords; - for (i = 0; i < otherlen; i++) + i = 0; + do { result->words[i] |= other->words[i]; + } while (++i < otherlen); if (result != a) pfree(a); return result; @@ -851,8 +863,10 @@ bms_add_range(Bitmapset *a, int lower, int upper) a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(uwordnum + 1)); a->nwords = uwordnum + 1; /* zero out the enlarged portion */ - for (i = oldnwords; i < a->nwords; i++) + i = oldnwords; + do { a->words[i] = 0; + } while (++i < a->nwords); } wordnum = lwordnum = WORDNUM(lower); @@ -906,13 +920,13 @@ bms_int_members(Bitmapset *a, const Bitmapset *b) /* Intersect b into a; we need never copy */ shortlen = Min(a->nwords, b->nwords); lastnonzero = -1; - for (i = 0; i < shortlen; i++) - { + i = 0; + do { a->words[i] &= b->words[i]; if (a->words[i] != 0) lastnonzero = i; - } + } while (++i < shortlen); /* If we computed an empty result, we must return NULL */ if (lastnonzero == -1) @@ -944,13 +958,13 @@ bms_del_members(Bitmapset *a, const Bitmapset *b) /* Remove b's bits from a; we need never copy */ shortlen = Min(a->nwords, b->nwords); lastnonzero = -1; - for (i = 0; i < shortlen; i++) - { + i = 0; + do { a->words[i] &= ~b->words[i]; if (a->words[i] != 0) lastnonzero = i; - } + } while (++i < shortlen); /* If we computed an empty result, we must return NULL */ if (lastnonzero == -1) @@ -994,8 +1008,10 @@ bms_join(Bitmapset *a, Bitmapset *b) } /* And union the shorter input into the result */ otherlen = other->nwords; - for (i = 0; i < otherlen; i++) + i = 0; + do { result->words[i] |= other->words[i]; + } while (++i < otherlen); if (other != result) /* pure paranoia */ pfree(other); return result; -- 2.41.0.windows.1