mirror of https://github.com/postgres/postgres
Instead of Lists of integers, we now store variable-length bitmap sets. This should be faster as well as less error-prone.WIN32_DEV
parent
893678eda7
commit
c15a4c2aef
@ -0,0 +1,759 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* bitmapset.c |
||||
* PostgreSQL generic bitmap set package |
||||
* |
||||
* A bitmap set can represent any set of nonnegative integers, although |
||||
* it is mainly intended for sets where the maximum value is not large, |
||||
* say at most a few hundred. By convention, a NULL pointer is always |
||||
* accepted by all operations to represent the empty set. (But beware |
||||
* that this is not the only representation of the empty set. Use |
||||
* bms_is_empty() in preference to testing for NULL.) |
||||
* |
||||
* |
||||
* Copyright (c) 2003, PostgreSQL Global Development Group |
||||
* |
||||
* IDENTIFICATION |
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/bitmapset.c,v 1.1 2003/02/08 20:20:53 tgl Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "nodes/bitmapset.h" |
||||
|
||||
|
||||
#define WORDNUM(x) ((x) / BITS_PER_BITMAPWORD) |
||||
#define BITNUM(x) ((x) % BITS_PER_BITMAPWORD) |
||||
|
||||
#define BITMAPSET_SIZE(nwords) \ |
||||
(offsetof(Bitmapset, words) + (nwords) * sizeof(bitmapword)) |
||||
|
||||
/*----------
|
||||
* This is a well-known cute trick for isolating the rightmost one-bit |
||||
* in a word. It assumes two's complement arithmetic. Consider any |
||||
* nonzero value, and focus attention on the rightmost one. The value is |
||||
* then something like |
||||
* xxxxxx10000 |
||||
* where x's are unspecified bits. The two's complement negative is formed |
||||
* by inverting all the bits and adding one. Inversion gives |
||||
* yyyyyy01111 |
||||
* where each y is the inverse of the corresponding x. Incrementing gives |
||||
* yyyyyy10000 |
||||
* and then ANDing with the original value gives |
||||
* 00000010000 |
||||
* This works for all cases except original value = zero, where of course |
||||
* we get zero. |
||||
*---------- |
||||
*/ |
||||
#define RIGHTMOST_ONE(x) ((signedbitmapword) (x) & -((signedbitmapword) (x))) |
||||
|
||||
#define HAS_MULTIPLE_ONES(x) ((bitmapword) RIGHTMOST_ONE(x) != (x)) |
||||
|
||||
|
||||
/*
|
||||
* Lookup tables to avoid need for bit-by-bit groveling |
||||
* |
||||
* rightmost_one_pos[x] gives the bit number (0-7) of the rightmost one bit |
||||
* in a nonzero byte value x. The entry for x=0 is never used. |
||||
* |
||||
* number_of_ones[x] gives the number of one-bits (0-8) in a byte value x. |
||||
* |
||||
* We could make these tables larger and reduce the number of iterations |
||||
* in the functions that use them, but bytewise shifts and masks are |
||||
* especially fast on many machines, so working a byte at a time seems best. |
||||
*/ |
||||
|
||||
static const uint8 rightmost_one_pos[256] = { |
||||
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 |
||||
}; |
||||
|
||||
static const uint8 number_of_ones[256] = { |
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, |
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 |
||||
}; |
||||
|
||||
|
||||
/*
|
||||
* bms_copy - make a palloc'd copy of a bitmapset |
||||
*/ |
||||
Bitmapset * |
||||
bms_copy(const Bitmapset *a) |
||||
{ |
||||
Bitmapset *result; |
||||
size_t size; |
||||
|
||||
if (a == NULL) |
||||
return NULL; |
||||
size = BITMAPSET_SIZE(a->nwords); |
||||
result = (Bitmapset *) palloc(size); |
||||
memcpy(result, a, size); |
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* bms_equal - are two bitmapsets equal? |
||||
* |
||||
* This is logical not physical equality; in particular, a NULL pointer will |
||||
* be reported as equal to a palloc'd value containing no members. |
||||
*/ |
||||
bool |
||||
bms_equal(const Bitmapset *a, const Bitmapset *b) |
||||
{ |
||||
const Bitmapset *shorter; |
||||
const Bitmapset *longer; |
||||
int shortlen; |
||||
int longlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL) |
||||
{ |
||||
if (b == NULL) |
||||
return true; |
||||
return bms_is_empty(b); |
||||
} |
||||
else if (b == NULL) |
||||
{ |
||||
return bms_is_empty(a); |
||||
} |
||||
/* Identify shorter and longer input */ |
||||
if (a->nwords <= b->nwords) |
||||
{ |
||||
shorter = a; |
||||
longer = b; |
||||
} |
||||
else |
||||
{ |
||||
shorter = b; |
||||
longer = a; |
||||
} |
||||
/* And process */ |
||||
shortlen = shorter->nwords; |
||||
for (i = 0; i < shortlen; i++) |
||||
{ |
||||
if (shorter->words[i] != longer->words[i]) |
||||
return false; |
||||
} |
||||
longlen = longer->nwords; |
||||
for (; i < longlen; i++) |
||||
{ |
||||
if (longer->words[i] != 0) |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/*
|
||||
* bms_make_singleton - build a bitmapset containing a single member |
||||
*/ |
||||
Bitmapset * |
||||
bms_make_singleton(int x) |
||||
{ |
||||
Bitmapset *result; |
||||
int wordnum, |
||||
bitnum; |
||||
|
||||
if (x < 0) |
||||
elog(ERROR, "bms_make_singleton: negative set member not allowed"); |
||||
wordnum = WORDNUM(x); |
||||
bitnum = BITNUM(x); |
||||
result = (Bitmapset *) palloc0(BITMAPSET_SIZE(wordnum + 1)); |
||||
result->nwords = wordnum + 1; |
||||
result->words[wordnum] = ((bitmapword) 1 << bitnum); |
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* bms_free - free a bitmapset |
||||
* |
||||
* Same as pfree except for allowing NULL input |
||||
*/ |
||||
void |
||||
bms_free(Bitmapset *a) |
||||
{ |
||||
if (a) |
||||
pfree(a); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* These operations all make a freshly palloc'd result, |
||||
* leaving their inputs untouched |
||||
*/ |
||||
|
||||
|
||||
/*
|
||||
* bms_union - set union |
||||
*/ |
||||
Bitmapset * |
||||
bms_union(const Bitmapset *a, const Bitmapset *b) |
||||
{ |
||||
Bitmapset *result; |
||||
const Bitmapset *other; |
||||
int otherlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL) |
||||
return bms_copy(b); |
||||
if (b == NULL) |
||||
return bms_copy(a); |
||||
/* Identify shorter and longer input; copy the longer one */ |
||||
if (a->nwords <= b->nwords) |
||||
{ |
||||
result = bms_copy(b); |
||||
other = a; |
||||
} |
||||
else |
||||
{ |
||||
result = bms_copy(a); |
||||
other = b; |
||||
} |
||||
/* And union the shorter input into the result */ |
||||
otherlen = other->nwords; |
||||
for (i = 0; i < otherlen; i++) |
||||
{ |
||||
result->words[i] |= other->words[i]; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* bms_intersect - set intersection |
||||
*/ |
||||
Bitmapset * |
||||
bms_intersect(const Bitmapset *a, const Bitmapset *b) |
||||
{ |
||||
Bitmapset *result; |
||||
const Bitmapset *other; |
||||
int resultlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL || b == NULL) |
||||
return NULL; |
||||
/* Identify shorter and longer input; copy the shorter one */ |
||||
if (a->nwords <= b->nwords) |
||||
{ |
||||
result = bms_copy(a); |
||||
other = b; |
||||
} |
||||
else |
||||
{ |
||||
result = bms_copy(b); |
||||
other = a; |
||||
} |
||||
/* And intersect the longer input with the result */ |
||||
resultlen = result->nwords; |
||||
for (i = 0; i < resultlen; i++) |
||||
{ |
||||
result->words[i] &= other->words[i]; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* bms_difference - set difference (ie, A without members of B) |
||||
*/ |
||||
Bitmapset * |
||||
bms_difference(const Bitmapset *a, const Bitmapset *b) |
||||
{ |
||||
Bitmapset *result; |
||||
int shortlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL) |
||||
return NULL; |
||||
if (b == NULL) |
||||
return bms_copy(a); |
||||
/* Copy the left input */ |
||||
result = bms_copy(a); |
||||
/* And remove b's bits from result */ |
||||
shortlen = Min(a->nwords, b->nwords); |
||||
for (i = 0; i < shortlen; i++) |
||||
{ |
||||
result->words[i] &= ~ b->words[i]; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* bms_is_subset - is A a subset of B? |
||||
*/ |
||||
bool |
||||
bms_is_subset(const Bitmapset *a, const Bitmapset *b) |
||||
{ |
||||
int shortlen; |
||||
int longlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL) |
||||
return true; /* empty set is a subset of anything */ |
||||
if (b == NULL) |
||||
return bms_is_empty(a); |
||||
/* Check common words */ |
||||
shortlen = Min(a->nwords, b->nwords); |
||||
for (i = 0; i < shortlen; i++) |
||||
{ |
||||
if ((a->words[i] & ~ b->words[i]) != 0) |
||||
return false; |
||||
} |
||||
/* Check extra words */ |
||||
if (a->nwords > b->nwords) |
||||
{ |
||||
longlen = a->nwords; |
||||
for (; i < longlen; i++) |
||||
{ |
||||
if (a->words[i] != 0) |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/*
|
||||
* bms_is_member - is X a member of A? |
||||
*/ |
||||
bool |
||||
bms_is_member(int x, const Bitmapset *a) |
||||
{ |
||||
int wordnum, |
||||
bitnum; |
||||
|
||||
/* XXX better to just return false for x<0 ? */ |
||||
if (x < 0) |
||||
elog(ERROR, "bms_is_member: negative set member not allowed"); |
||||
if (a == NULL) |
||||
return false; |
||||
wordnum = WORDNUM(x); |
||||
bitnum = BITNUM(x); |
||||
if (wordnum >= a->nwords) |
||||
return false; |
||||
if ((a->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0) |
||||
return true; |
||||
return false; |
||||
} |
||||
|
||||
/*
|
||||
* bms_overlap - do sets overlap (ie, have a nonempty intersection)? |
||||
*/ |
||||
bool |
||||
bms_overlap(const Bitmapset *a, const Bitmapset *b) |
||||
{ |
||||
int shortlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL || b == NULL) |
||||
return false; |
||||
/* Check words in common */ |
||||
shortlen = Min(a->nwords, b->nwords); |
||||
for (i = 0; i < shortlen; i++) |
||||
{ |
||||
if ((a->words[i] & b->words[i]) != 0) |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/*
|
||||
* bms_singleton_member - return the sole integer member of set |
||||
* |
||||
* Raises error if |a| is not 1. |
||||
*/ |
||||
int |
||||
bms_singleton_member(const Bitmapset *a) |
||||
{ |
||||
int result = -1; |
||||
int nwords; |
||||
int wordnum; |
||||
|
||||
if (a == NULL) |
||||
elog(ERROR, "bms_singleton_member: set is empty"); |
||||
nwords = a->nwords; |
||||
for (wordnum = 0; wordnum < nwords; wordnum++) |
||||
{ |
||||
bitmapword w = a->words[wordnum]; |
||||
|
||||
if (w != 0) |
||||
{ |
||||
if (result >= 0 || HAS_MULTIPLE_ONES(w)) |
||||
elog(ERROR, "bms_singleton_member: set has multiple members"); |
||||
result = wordnum * BITS_PER_BITMAPWORD; |
||||
while ((w & 255) == 0) |
||||
{ |
||||
w >>= 8; |
||||
result += 8; |
||||
} |
||||
result += rightmost_one_pos[w & 255]; |
||||
} |
||||
} |
||||
if (result < 0) |
||||
elog(ERROR, "bms_singleton_member: set is empty"); |
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* bms_num_members - count members of set |
||||
*/ |
||||
int |
||||
bms_num_members(const Bitmapset *a) |
||||
{ |
||||
int result = 0; |
||||
int nwords; |
||||
int wordnum; |
||||
|
||||
if (a == NULL) |
||||
return 0; |
||||
nwords = a->nwords; |
||||
for (wordnum = 0; wordnum < nwords; wordnum++) |
||||
{ |
||||
bitmapword w = a->words[wordnum]; |
||||
|
||||
/* we assume here that bitmapword is an unsigned type */ |
||||
while (w != 0) |
||||
{ |
||||
result += number_of_ones[w & 255]; |
||||
w >>= 8; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* bms_membership - does a set have zero, one, or multiple members? |
||||
* |
||||
* This is faster than making an exact count with bms_num_members(). |
||||
*/ |
||||
BMS_Membership |
||||
bms_membership(const Bitmapset *a) |
||||
{ |
||||
BMS_Membership result = BMS_EMPTY_SET; |
||||
int nwords; |
||||
int wordnum; |
||||
|
||||
if (a == NULL) |
||||
return BMS_EMPTY_SET; |
||||
nwords = a->nwords; |
||||
for (wordnum = 0; wordnum < nwords; wordnum++) |
||||
{ |
||||
bitmapword w = a->words[wordnum]; |
||||
|
||||
if (w != 0) |
||||
{ |
||||
if (result != BMS_EMPTY_SET || HAS_MULTIPLE_ONES(w)) |
||||
return BMS_MULTIPLE; |
||||
result = BMS_SINGLETON; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* bms_is_empty - is a set empty? |
||||
* |
||||
* This is even faster than bms_membership(). |
||||
*/ |
||||
bool |
||||
bms_is_empty(const Bitmapset *a) |
||||
{ |
||||
int nwords; |
||||
int wordnum; |
||||
|
||||
if (a == NULL) |
||||
return true; |
||||
nwords = a->nwords; |
||||
for (wordnum = 0; wordnum < nwords; wordnum++) |
||||
{ |
||||
bitmapword w = a->words[wordnum]; |
||||
|
||||
if (w != 0) |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* These operations all "recycle" their non-const inputs, ie, either |
||||
* return the modified input or pfree it if it can't hold the result. |
||||
* |
||||
* These should generally be used in the style |
||||
* |
||||
* foo = bms_add_member(foo, x); |
||||
*/ |
||||
|
||||
|
||||
/*
|
||||
* bms_add_member - add a specified member to set |
||||
* |
||||
* Input set is modified or recycled! |
||||
*/ |
||||
Bitmapset * |
||||
bms_add_member(Bitmapset *a, int x) |
||||
{ |
||||
int wordnum, |
||||
bitnum; |
||||
|
||||
if (x < 0) |
||||
elog(ERROR, "bms_add_member: negative set member not allowed"); |
||||
if (a == NULL) |
||||
return bms_make_singleton(x); |
||||
wordnum = WORDNUM(x); |
||||
bitnum = BITNUM(x); |
||||
if (wordnum >= a->nwords) |
||||
{ |
||||
/* Slow path: make a larger set and union the input set into it */ |
||||
Bitmapset *result; |
||||
int nwords; |
||||
int i; |
||||
|
||||
result = bms_make_singleton(x); |
||||
nwords = a->nwords; |
||||
for (i = 0; i < nwords; i++) |
||||
{ |
||||
result->words[i] |= a->words[i]; |
||||
} |
||||
pfree(a); |
||||
return result; |
||||
} |
||||
/* Fast path: x fits in existing set */ |
||||
a->words[wordnum] |= ((bitmapword) 1 << bitnum); |
||||
return a; |
||||
} |
||||
|
||||
/*
|
||||
* bms_del_member - remove a specified member from set |
||||
* |
||||
* No error if x is not currently a member of set |
||||
* |
||||
* Input set is modified in-place! |
||||
*/ |
||||
Bitmapset * |
||||
bms_del_member(Bitmapset *a, int x) |
||||
{ |
||||
int wordnum, |
||||
bitnum; |
||||
|
||||
if (x < 0) |
||||
elog(ERROR, "bms_del_member: negative set member not allowed"); |
||||
if (a == NULL) |
||||
return NULL; |
||||
wordnum = WORDNUM(x); |
||||
bitnum = BITNUM(x); |
||||
if (wordnum < a->nwords) |
||||
{ |
||||
a->words[wordnum] &= ~ ((bitmapword) 1 << bitnum); |
||||
} |
||||
return a; |
||||
} |
||||
|
||||
/*
|
||||
* bms_add_members - like bms_union, but left input is recycled |
||||
*/ |
||||
Bitmapset * |
||||
bms_add_members(Bitmapset *a, const Bitmapset *b) |
||||
{ |
||||
Bitmapset *result; |
||||
const Bitmapset *other; |
||||
int otherlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL) |
||||
return bms_copy(b); |
||||
if (b == NULL) |
||||
return a; |
||||
/* Identify shorter and longer input; copy the longer one if needed */ |
||||
if (a->nwords < b->nwords) |
||||
{ |
||||
result = bms_copy(b); |
||||
other = a; |
||||
} |
||||
else |
||||
{ |
||||
result = a; |
||||
other = b; |
||||
} |
||||
/* And union the shorter input into the result */ |
||||
otherlen = other->nwords; |
||||
for (i = 0; i < otherlen; i++) |
||||
{ |
||||
result->words[i] |= other->words[i]; |
||||
} |
||||
if (result != a) |
||||
pfree(a); |
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* bms_int_members - like bms_intersect, but left input is recycled |
||||
*/ |
||||
Bitmapset * |
||||
bms_int_members(Bitmapset *a, const Bitmapset *b) |
||||
{ |
||||
int shortlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL) |
||||
return NULL; |
||||
if (b == NULL) |
||||
{ |
||||
pfree(a); |
||||
return NULL; |
||||
} |
||||
/* Intersect b into a; we need never copy */ |
||||
shortlen = Min(a->nwords, b->nwords); |
||||
for (i = 0; i < shortlen; i++) |
||||
{ |
||||
a->words[i] &= b->words[i]; |
||||
} |
||||
for (; i < a->nwords; i++) |
||||
{ |
||||
a->words[i] = 0; |
||||
} |
||||
return a; |
||||
} |
||||
|
||||
/*
|
||||
* bms_del_members - like bms_difference, but left input is recycled |
||||
*/ |
||||
Bitmapset * |
||||
bms_del_members(Bitmapset *a, const Bitmapset *b) |
||||
{ |
||||
int shortlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL) |
||||
return NULL; |
||||
if (b == NULL) |
||||
return a; |
||||
/* Remove b's bits from a; we need never copy */ |
||||
shortlen = Min(a->nwords, b->nwords); |
||||
for (i = 0; i < shortlen; i++) |
||||
{ |
||||
a->words[i] &= ~ b->words[i]; |
||||
} |
||||
return a; |
||||
} |
||||
|
||||
/*
|
||||
* bms_join - like bms_union, but *both* inputs are recycled |
||||
*/ |
||||
Bitmapset * |
||||
bms_join(Bitmapset *a, Bitmapset *b) |
||||
{ |
||||
Bitmapset *result; |
||||
Bitmapset *other; |
||||
int otherlen; |
||||
int i; |
||||
|
||||
/* Handle cases where either input is NULL */ |
||||
if (a == NULL) |
||||
return b; |
||||
if (b == NULL) |
||||
return a; |
||||
/* Identify shorter and longer input; use longer one as result */ |
||||
if (a->nwords < b->nwords) |
||||
{ |
||||
result = b; |
||||
other = a; |
||||
} |
||||
else |
||||
{ |
||||
result = a; |
||||
other = b; |
||||
} |
||||
/* And union the shorter input into the result */ |
||||
otherlen = other->nwords; |
||||
for (i = 0; i < otherlen; i++) |
||||
{ |
||||
result->words[i] |= other->words[i]; |
||||
} |
||||
if (other != result) /* pure paranoia */ |
||||
pfree(other); |
||||
return result; |
||||
} |
||||
|
||||
/*----------
|
||||
* bms_first_member - find and remove first member of a set |
||||
* |
||||
* Returns -1 if set is empty. NB: set is destructively modified! |
||||
* |
||||
* This is intended as support for iterating through the members of a set. |
||||
* The typical pattern is |
||||
* |
||||
* tmpset = bms_copy(inputset); |
||||
* while ((x = bms_first_member(tmpset)) >= 0) |
||||
* { |
||||
* process member x; |
||||
* } |
||||
* bms_free(tmpset); |
||||
*---------- |
||||
*/ |
||||
int |
||||
bms_first_member(Bitmapset *a) |
||||
{ |
||||
int nwords; |
||||
int wordnum; |
||||
|
||||
if (a == NULL) |
||||
return -1; |
||||
nwords = a->nwords; |
||||
for (wordnum = 0; wordnum < nwords; wordnum++) |
||||
{ |
||||
bitmapword w = a->words[wordnum]; |
||||
|
||||
if (w != 0) |
||||
{ |
||||
int result; |
||||
|
||||
w = RIGHTMOST_ONE(w); |
||||
a->words[wordnum] &= ~ w; |
||||
|
||||
result = wordnum * BITS_PER_BITMAPWORD; |
||||
while ((w & 255) == 0) |
||||
{ |
||||
w >>= 8; |
||||
result += 8; |
||||
} |
||||
result += rightmost_one_pos[w & 255]; |
||||
return result; |
||||
} |
||||
} |
||||
return -1; |
||||
} |
||||
@ -0,0 +1,80 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* bitmapset.h |
||||
* PostgreSQL generic bitmap set package |
||||
* |
||||
* A bitmap set can represent any set of nonnegative integers, although |
||||
* it is mainly intended for sets where the maximum value is not large, |
||||
* say at most a few hundred. By convention, a NULL pointer is always |
||||
* accepted by all operations to represent the empty set. (But beware |
||||
* that this is not the only representation of the empty set. Use |
||||
* bms_is_empty() in preference to testing for NULL.) |
||||
* |
||||
* |
||||
* Copyright (c) 2003, PostgreSQL Global Development Group |
||||
* |
||||
* $Id: bitmapset.h,v 1.1 2003/02/08 20:20:55 tgl Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef BITMAPSET_H |
||||
#define BITMAPSET_H |
||||
|
||||
/*
|
||||
* Data representation |
||||
*/ |
||||
|
||||
/* The unit size can be adjusted by changing these three declarations: */ |
||||
#define BITS_PER_BITMAPWORD 32 |
||||
typedef uint32 bitmapword; /* must be an unsigned type */ |
||||
typedef int32 signedbitmapword; /* must be the matching signed type */ |
||||
|
||||
typedef struct Bitmapset { |
||||
int nwords; /* number of words in array */ |
||||
bitmapword words[1]; /* really [nwords] */ |
||||
} Bitmapset; /* VARIABLE LENGTH STRUCT */ |
||||
|
||||
|
||||
/* result of bms_membership */ |
||||
typedef enum |
||||
{ |
||||
BMS_EMPTY_SET, /* 0 members */ |
||||
BMS_SINGLETON, /* 1 member */ |
||||
BMS_MULTIPLE /* >1 member */ |
||||
} BMS_Membership; |
||||
|
||||
|
||||
/*
|
||||
* function prototypes in nodes/bitmapset.c |
||||
*/ |
||||
|
||||
extern Bitmapset *bms_copy(const Bitmapset *a); |
||||
extern bool bms_equal(const Bitmapset *a, const Bitmapset *b); |
||||
extern Bitmapset *bms_make_singleton(int x); |
||||
extern void bms_free(Bitmapset *a); |
||||
|
||||
extern Bitmapset *bms_union(const Bitmapset *a, const Bitmapset *b); |
||||
extern Bitmapset *bms_intersect(const Bitmapset *a, const Bitmapset *b); |
||||
extern Bitmapset *bms_difference(const Bitmapset *a, const Bitmapset *b); |
||||
extern bool bms_is_subset(const Bitmapset *a, const Bitmapset *b); |
||||
extern bool bms_is_member(int x, const Bitmapset *a); |
||||
extern bool bms_overlap(const Bitmapset *a, const Bitmapset *b); |
||||
extern int bms_singleton_member(const Bitmapset *a); |
||||
extern int bms_num_members(const Bitmapset *a); |
||||
/* optimized tests when we don't need to know exact membership count: */ |
||||
extern BMS_Membership bms_membership(const Bitmapset *a); |
||||
extern bool bms_is_empty(const Bitmapset *a); |
||||
|
||||
/* these routines recycle (modify or free) their non-const inputs: */ |
||||
|
||||
extern Bitmapset *bms_add_member(Bitmapset *a, int x); |
||||
extern Bitmapset *bms_del_member(Bitmapset *a, int x); |
||||
extern Bitmapset *bms_add_members(Bitmapset *a, const Bitmapset *b); |
||||
extern Bitmapset *bms_int_members(Bitmapset *a, const Bitmapset *b); |
||||
extern Bitmapset *bms_del_members(Bitmapset *a, const Bitmapset *b); |
||||
extern Bitmapset *bms_join(Bitmapset *a, Bitmapset *b); |
||||
|
||||
/* support for iterating through the integer elements of a set: */ |
||||
extern int bms_first_member(Bitmapset *a); |
||||
|
||||
#endif /* BITMAPSET_H */ |
||||
Loading…
Reference in new issue