Skip to content

Commit 5c06752

Browse files
committed
Add bms_prev_member function
This works very much like the existing bms_last_member function, only it traverses through the Bitmapset in the opposite direction from the most significant bit down to the least significant bit. A special prevbit value of -1 may be used to have the function determine the most significant bit. This is useful for starting a loop. When there are no members less than prevbit, the function returns -2 to indicate there are no more members. Author: David Rowley Discussion: https://postgr.es/m/CAKJS1f-K=3d5MDASNYFJpUpc20xcBnAwNC1-AOeunhn0OtkWbQ@mail.gmail.com
1 parent f16241b commit 5c06752

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

src/backend/nodes/bitmapset.c

+95
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@
5858
* rightmost_one_pos[x] gives the bit number (0-7) of the rightmost one bit
5959
* in a nonzero byte value x. The entry for x=0 is never used.
6060
*
61+
* leftmost_one_pos[x] gives the bit number (0-7) of the leftmost one bit in a
62+
* nonzero byte value x. The entry for x=0 is never used.
63+
*
6164
* number_of_ones[x] gives the number of one-bits (0-8) in a byte value x.
6265
*
6366
* We could make these tables larger and reduce the number of iterations
@@ -84,6 +87,25 @@ static const uint8 rightmost_one_pos[256] = {
8487
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
8588
};
8689

90+
static const uint8 leftmost_one_pos[256] = {
91+
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
92+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
93+
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
94+
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
95+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
96+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
97+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
98+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
99+
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
100+
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
101+
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
102+
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
103+
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
104+
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
105+
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
106+
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
107+
};
108+
87109
static const uint8 number_of_ones[256] = {
88110
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
89111
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
@@ -1088,6 +1110,79 @@ bms_next_member(const Bitmapset *a, int prevbit)
10881110
return -2;
10891111
}
10901112

1113+
/*
1114+
* bms_prev_member - find prev member of a set
1115+
*
1116+
* Returns largest member less than "prevbit", or -2 if there is none.
1117+
* "prevbit" must NOT be more than one above the highest possible bit that can
1118+
* be set at the Bitmapset at its current size.
1119+
*
1120+
* To ease finding the highest set bit for the initial loop, the special
1121+
* prevbit value of -1 can be passed to have the function find the highest
1122+
* valued member in the set.
1123+
*
1124+
* This is intended as support for iterating through the members of a set in
1125+
* reverse. The typical pattern is
1126+
*
1127+
* x = -1;
1128+
* while ((x = bms_prev_member(inputset, x)) >= 0)
1129+
* process member x;
1130+
*
1131+
* Notice that when there are no more members, we return -2, not -1 as you
1132+
* might expect. The rationale for that is to allow distinguishing the
1133+
* loop-not-started state (x == -1) from the loop-completed state (x == -2).
1134+
* It makes no difference in simple loop usage, but complex iteration logic
1135+
* might need such an ability.
1136+
*/
1137+
1138+
int
1139+
bms_prev_member(const Bitmapset *a, int prevbit)
1140+
{
1141+
int wordnum;
1142+
int ushiftbits;
1143+
bitmapword mask;
1144+
1145+
/*
1146+
* If set is NULL or if there are no more bits to the right then we've
1147+
* nothing to do.
1148+
*/
1149+
if (a == NULL || prevbit == 0)
1150+
return -2;
1151+
1152+
/* transform -1 to the highest possible bit we could have set */
1153+
if (prevbit == -1)
1154+
prevbit = a->nwords * BITS_PER_BITMAPWORD - 1;
1155+
else
1156+
prevbit--;
1157+
1158+
ushiftbits = BITS_PER_BITMAPWORD - (BITNUM(prevbit) + 1);
1159+
mask = (~(bitmapword) 0) >> ushiftbits;
1160+
for (wordnum = WORDNUM(prevbit); wordnum >= 0; wordnum--)
1161+
{
1162+
bitmapword w = a->words[wordnum];
1163+
1164+
/* mask out bits left of prevbit */
1165+
w &= mask;
1166+
1167+
if (w != 0)
1168+
{
1169+
int result;
1170+
int shift = 24;
1171+
result = wordnum * BITS_PER_BITMAPWORD;
1172+
1173+
while ((w >> shift) == 0)
1174+
shift -= 8;
1175+
1176+
result += shift + leftmost_one_pos[(w >> shift) & 255];
1177+
return result;
1178+
}
1179+
1180+
/* in subsequent words, consider all bits */
1181+
mask = (~(bitmapword) 0);
1182+
}
1183+
return -2;
1184+
}
1185+
10911186
/*
10921187
* bms_hash_value - compute a hash key for a Bitmapset
10931188
*

src/include/nodes/bitmapset.h

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ extern Bitmapset *bms_join(Bitmapset *a, Bitmapset *b);
9999
/* support for iterating through the integer elements of a set: */
100100
extern int bms_first_member(Bitmapset *a);
101101
extern int bms_next_member(const Bitmapset *a, int prevbit);
102+
extern int bms_prev_member(const Bitmapset *a, int prevbit);
102103

103104
/* support for hashtables using Bitmapsets as keys: */
104105
extern uint32 bms_hash_value(const Bitmapset *a);

0 commit comments

Comments
 (0)