Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/backend/nodes/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 30 kB image not shown  

Quelle  bitmapset.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * 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, 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.  Because an empty Bitmapset is represented as NULL, a non-NULL
 * Bitmapset always has at least 1 Bitmapword.  We can exploit this fact to
 * speed up 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 halves the
 * number of loop condition checks.
 *
 * Callers must ensure that the set returned by functions in this file which
 * adjust the members of an existing set is assigned to all pointers pointing
 * to that existing set.  No guarantees are made that we'll ever modify the
 * existing set in-place and return it.
 *
 * To help find bugs caused by callers failing to record the return value of
 * the function which manipulates an existing set, we support building with
 * REALLOCATE_BITMAPSETS.  This results in the set being reallocated each time
 * the set is altered and the existing being pfreed.  This is useful as if any
 * references still exist to the old set, we're more likely to notice as
 * any users of the old set will be accessing pfree'd memory.  This option is
 * only intended to be used for debugging.
 *
 * Copyright (c) 2003-2025, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *   src/backend/nodes/bitmapset.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "common/hashfn.h"
#include "nodes/bitmapset.h"
#include "nodes/pg_list.h"
#include "port/pg_bitutils.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))

#ifdef USE_ASSERT_CHECKING
/*
 * bms_is_valid_set - for cassert builds to check for valid sets
 */

static bool
bms_is_valid_set(const Bitmapset *a)
{
 /* NULL is the correct representation of an empty set */
 if (a == NULL)
  return true;

 /* check the node tag is set correctly.  pfree'd pointer, maybe? */
 if (!IsA(a, Bitmapset))
  return false;

 /* trailing zero words are not allowed */
 if (a->words[a->nwords - 1] == 0)
  return false;

 return true;
}
#endif

#ifdef REALLOCATE_BITMAPSETS
/*
 * bms_copy_and_free
 *  Only required in REALLOCATE_BITMAPSETS builds.  Provide a simple way
 *  to return a freshly allocated set and pfree the original.
 *
 * Note: callers which accept multiple sets must be careful when calling this
 * function to clone one parameter as other parameters may point to the same
 * set.  A good option is to call this just before returning the resulting
 * set.
 */

static Bitmapset *
bms_copy_and_free(Bitmapset *a)
{
 Bitmapset  *c = bms_copy(a);

 bms_free(a);
 return c;
}
#endif

/*
 * bms_copy - make a palloc'd copy of a bitmapset
 */

Bitmapset *
bms_copy(const Bitmapset *a)
{
 Bitmapset  *result;
 size_t  size;

 Assert(bms_is_valid_set(a));

 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? or both NULL?
 */

bool
bms_equal(const Bitmapset *a, const Bitmapset *b)
{
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL)
 {
  if (b == NULL)
   return true;
  return false;
 }
 else if (b == NULL)
  return false;

 /* can't be equal if the word counts don't match */
 if (a->nwords != b->nwords)
  return false;

 /* check each word matches */
 i = 0;
 do
 {
  if (a->words[i] != b->words[i])
   return false;
 } while (++i < a->nwords);

 return true;
}

/*
 * bms_compare - qsort-style comparator for bitmapsets
 *
 * This guarantees to report values as equal iff bms_equal would say they are
 * equal.  Otherwise, the highest-numbered bit that is set in one value but
 * not the other determines the result.  (This rule means that, for example,
 * {6} is greater than {5}, which seems plausible.)
 */

int
bms_compare(const Bitmapset *a, const Bitmapset *b)
{
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL)
  return (b == NULL) ? 0 : -1;
 else if (b == NULL)
  return +1;

 /* the set with the most words must be greater */
 if (a->nwords != b->nwords)
  return (a->nwords > b->nwords) ? +1 : -1;

 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;
}

/*
 * 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, "negative bitmapset member not allowed");
 wordnum = WORDNUM(x);
 bitnum = BITNUM(x);
 result = (Bitmapset *) palloc0(BITMAPSET_SIZE(wordnum + 1));
 result->type = T_Bitmapset;
 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);
}


/*
 * bms_union - create and return a new set containing all members from both
 * input sets.  Both inputs are left unmodified.
 */

Bitmapset *
bms_union(const Bitmapset *a, const Bitmapset *b)
{
 Bitmapset  *result;
 const Bitmapset *other;
 int   otherlen;
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* 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;
 i = 0;
 do
 {
  result->words[i] |= other->words[i];
 } while (++i < otherlen);
 return result;
}

/*
 * bms_intersect - create and return a new set containing members which both
 * input sets have in common.  Both inputs are left unmodified.
 */

Bitmapset *
bms_intersect(const Bitmapset *a, const Bitmapset *b)
{
 Bitmapset  *result;
 const Bitmapset *other;
 int   lastnonzero;
 int   resultlen;
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* 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;
 lastnonzero = -1;
 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)
 {
  pfree(result);
  return NULL;
 }

 /* get rid of trailing zero words */
 result->nwords = lastnonzero + 1;
 return result;
}

/*
 * bms_difference - create and return a new set containing all the members of
 * 'a' without the members of 'b'.
 */

Bitmapset *
bms_difference(const Bitmapset *a, const Bitmapset *b)
{
 Bitmapset  *result;
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL)
  return NULL;
 if (b == NULL)
  return bms_copy(a);

 /*
  * In Postgres' usage, an empty result is a very common case, so it's
  * worth optimizing for that by testing bms_nonempty_difference().  This
  * saves us a palloc/pfree cycle compared to checking after-the-fact.
 */

 if (!bms_nonempty_difference(a, b))
  return NULL;

 /* Copy the left input */
 result = bms_copy(a);

 /* And remove b's bits from result */
 if (result->nwords > b->nwords)
 {
  /*
   * We'll never need to remove trailing zero words when 'a' has more
   * words than 'b' as the additional words must be non-zero.
 */

  i = 0;
  do
  {
   result->words[i] &= ~b->words[i];
  } while (++i < b->nwords);
 }
 else
 {
  int   lastnonzero = -1;

  /* we may need to remove trailing zero words from the result. */
  i = 0;
  do
  {
   result->words[i] &= ~b->words[i];

   /* remember the last non-zero word */
   if (result->words[i] != 0)
    lastnonzero = i;
  } while (++i < result->nwords);

  /* trim off trailing zero words */
  result->nwords = lastnonzero + 1;
 }
 Assert(result->nwords != 0);

 /* Need not check for empty result, since we handled that case above */
 return result;
}

/*
 * bms_is_subset - is A a subset of B?
 */

bool
bms_is_subset(const Bitmapset *a, const Bitmapset *b)
{
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL)
  return true;   /* empty set is a subset of anything */
 if (b == NULL)
  return false;

 /* 'a' can't be a subset of 'b' if it contains more words */
 if (a->nwords > b->nwords)
  return false;

 /* Check all 'a' members are set in 'b' */
 i = 0;
 do
 {
  if ((a->words[i] & ~b->words[i]) != 0)
   return false;
 } while (++i < a->nwords);
 return true;
}

/*
 * bms_subset_compare - compare A and B for equality/subset relationships
 *
 * This is more efficient than testing bms_is_subset in both directions.
 */

BMS_Comparison
bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
{
 BMS_Comparison result;
 int   shortlen;
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL)
 {
  if (b == NULL)
   return BMS_EQUAL;
  return BMS_SUBSET1;
 }
 if (b == NULL)
  return BMS_SUBSET2;

 /* Check common words */
 result = BMS_EQUAL;   /* status so far */
 shortlen = Min(a->nwords, b->nwords);
 i = 0;
 do
 {
  bitmapword aword = a->words[i];
  bitmapword bword = b->words[i];

  if ((aword & ~bword) != 0)
  {
   /* a is not a subset of b */
   if (result == BMS_SUBSET1)
    return BMS_DIFFERENT;
   result = BMS_SUBSET2;
  }
  if ((bword & ~aword) != 0)
  {
   /* b is not a subset of a */
   if (result == BMS_SUBSET2)
    return BMS_DIFFERENT;
   result = BMS_SUBSET1;
  }
 } while (++i < shortlen);
 /* Check extra words */
 if (a->nwords > b->nwords)
 {
  /* if a has more words then a is not a subset of b */
  if (result == BMS_SUBSET1)
   return BMS_DIFFERENT;
  return BMS_SUBSET2;
 }
 else if (a->nwords < b->nwords)
 {
  /* if b has more words then b is not a subset of a */
  if (result == BMS_SUBSET2)
   return BMS_DIFFERENT;
  return BMS_SUBSET1;
 }
 return result;
}

/*
 * bms_is_member - is X a member of A?
 */

bool
bms_is_member(int x, const Bitmapset *a)
{
 int   wordnum,
    bitnum;

 Assert(bms_is_valid_set(a));

 /* XXX better to just return false for x<0 ? */
 if (x < 0)
  elog(ERROR, "negative bitmapset 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_member_index
 *  determine 0-based index of member x in the bitmap
 *
 * Returns (-1) when x is not a member.
 */

int
bms_member_index(Bitmapset *a, int x)
{
 int   i;
 int   bitnum;
 int   wordnum;
 int   result = 0;
 bitmapword mask;

 Assert(bms_is_valid_set(a));

 /* return -1 if not a member of the bitmap */
 if (!bms_is_member(x, a))
  return -1;

 wordnum = WORDNUM(x);
 bitnum = BITNUM(x);

 /* count bits in preceding words */
 for (i = 0; i < wordnum; i++)
 {
  bitmapword w = a->words[i];

  /* No need to count the bits in a zero word */
  if (w != 0)
   result += bmw_popcount(w);
 }

 /*
  * Now add bits of the last word, but only those before the item. We can
  * do that by applying a mask and then using popcount again. To get
  * 0-based index, we want to count only preceding bits, not the item
  * itself, so we subtract 1.
 */

 mask = ((bitmapword) 1 << bitnum) - 1;
 result += bmw_popcount(a->words[wordnum] & mask);

 return result;
}

/*
 * bms_overlap - do sets overlap (ie, have a nonempty intersection)?
 */

bool
bms_overlap(const Bitmapset *a, const Bitmapset *b)
{
 int   shortlen;
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL || b == NULL)
  return false;
 /* Check words in common */
 shortlen = Min(a->nwords, b->nwords);
 i = 0;
 do
 {
  if ((a->words[i] & b->words[i]) != 0)
   return true;
 } while (++i < shortlen);
 return false;
}

/*
 * bms_overlap_list - does a set overlap an integer list?
 */

bool
bms_overlap_list(const Bitmapset *a, const List *b)
{
 ListCell   *lc;
 int   wordnum,
    bitnum;

 Assert(bms_is_valid_set(a));

 if (a == NULL || b == NIL)
  return false;

 foreach(lc, b)
 {
  int   x = lfirst_int(lc);

  if (x < 0)
   elog(ERROR, "negative bitmapset member not allowed");
  wordnum = WORDNUM(x);
  bitnum = BITNUM(x);
  if (wordnum < a->nwords)
   if ((a->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0)
    return true;
 }

 return false;
}

/*
 * bms_nonempty_difference - do sets have a nonempty difference?
 *
 * i.e., are any members set in 'a' that are not also set in 'b'.
 */

bool
bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
{
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL)
  return false;
 if (b == NULL)
  return true;
 /* if 'a' has more words then it must contain additional members */
 if (a->nwords > b->nwords)
  return true;
 /* Check all 'a' members are set in 'b' */
 i = 0;
 do
 {
  if ((a->words[i] & ~b->words[i]) != 0)
   return true;
 } while (++i < a->nwords);
 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;

 Assert(bms_is_valid_set(a));

 if (a == NULL)
  elog(ERROR, "bitmapset is empty");

 nwords = a->nwords;
 wordnum = 0;
 do
 {
  bitmapword w = a->words[wordnum];

  if (w != 0)
  {
   if (result >= 0 || HAS_MULTIPLE_ONES(w))
    elog(ERROR, "bitmapset has multiple members");
   result = wordnum * BITS_PER_BITMAPWORD;
   result += bmw_rightmost_one_pos(w);
  }
 } while (++wordnum < nwords);

 /* we don't expect non-NULL sets to be empty */
 Assert(result >= 0);
 return result;
}

/*
 * bms_get_singleton_member
 *
 * Test whether the given set is a singleton.
 * If so, set *member to the value of its sole member, and return true.
 * If not, return false, without changing *member.
 *
 * This is more convenient and faster than calling bms_membership() and then
 * bms_singleton_member(), if we don't care about distinguishing empty sets
 * from multiple-member sets.
 */

bool
bms_get_singleton_member(const Bitmapset *a, int *member)
{
 int   result = -1;
 int   nwords;
 int   wordnum;

 Assert(bms_is_valid_set(a));

 if (a == NULL)
  return false;

 nwords = a->nwords;
 wordnum = 0;
 do
 {
  bitmapword w = a->words[wordnum];

  if (w != 0)
  {
   if (result >= 0 || HAS_MULTIPLE_ONES(w))
    return false;
   result = wordnum * BITS_PER_BITMAPWORD;
   result += bmw_rightmost_one_pos(w);
  }
 } while (++wordnum < nwords);

 /* we don't expect non-NULL sets to be empty */
 Assert(result >= 0);
 *member = result;
 return true;
}

/*
 * bms_num_members - count members of set
 */

int
bms_num_members(const Bitmapset *a)
{
 int   result = 0;
 int   nwords;
 int   wordnum;

 Assert(bms_is_valid_set(a));

 if (a == NULL)
  return 0;

 nwords = a->nwords;
 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;
}

/*
 * 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;

 Assert(bms_is_valid_set(a));

 if (a == NULL)
  return BMS_EMPTY_SET;

 nwords = a->nwords;
 wordnum = 0;
 do
 {
  bitmapword w = a->words[wordnum];

  if (w != 0)
  {
   if (result != BMS_EMPTY_SET || HAS_MULTIPLE_ONES(w))
    return BMS_MULTIPLE;
   result = BMS_SINGLETON;
  }
 } while (++wordnum < nwords);
 return result;
}


/*
 * bms_add_member - add a specified member to set
 *
 * 'a' is recycled when possible.
 */

Bitmapset *
bms_add_member(Bitmapset *a, int x)
{
 int   wordnum,
    bitnum;

 Assert(bms_is_valid_set(a));

 if (x < 0)
  elog(ERROR, "negative bitmapset member not allowed");
 if (a == NULL)
  return bms_make_singleton(x);

 wordnum = WORDNUM(x);
 bitnum = BITNUM(x);

 /* enlarge the set if necessary */
 if (wordnum >= a->nwords)
 {
  int   oldnwords = a->nwords;
  int   i;

  a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(wordnum + 1));
  a->nwords = wordnum + 1;
  /* zero out the enlarged portion */
  i = oldnwords;
  do
  {
   a->words[i] = 0;
  } while (++i < a->nwords);
 }

 a->words[wordnum] |= ((bitmapword) 1 << bitnum);

#ifdef REALLOCATE_BITMAPSETS

 /*
  * There's no guarantee that the repalloc returned a new pointer, so copy
  * and free unconditionally here.
 */

 a = bms_copy_and_free(a);
#endif

 return a;
}

/*
 * bms_del_member - remove a specified member from set
 *
 * No error if x is not currently a member of set
 *
 * 'a' is recycled when possible.
 */

Bitmapset *
bms_del_member(Bitmapset *a, int x)
{
 int   wordnum,
    bitnum;

 Assert(bms_is_valid_set(a));

 if (x < 0)
  elog(ERROR, "negative bitmapset member not allowed");
 if (a == NULL)
  return NULL;

 wordnum = WORDNUM(x);
 bitnum = BITNUM(x);

#ifdef REALLOCATE_BITMAPSETS
 a = bms_copy_and_free(a);
#endif

 /* member can't exist.  Return 'a' unmodified */
 if (unlikely(wordnum >= a->nwords))
  return a;

 a->words[wordnum] &= ~((bitmapword) 1 << bitnum);

 /* when last word becomes empty, trim off all trailing empty words */
 if (a->words[wordnum] == 0 && wordnum == a->nwords - 1)
 {
  /* find the last non-empty word and make that the new final word */
  for (int i = wordnum - 1; i >= 0; i--)
  {
   if (a->words[i] != 0)
   {
    a->nwords = i + 1;
    return a;
   }
  }

  /* the set is now empty */
  pfree(a);
  return NULL;
 }
 return a;
}

/*
 * bms_add_members - like bms_union, but left input is recycled when possible
 */

Bitmapset *
bms_add_members(Bitmapset *a, const Bitmapset *b)
{
 Bitmapset  *result;
 const Bitmapset *other;
 int   otherlen;
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL)
  return bms_copy(b);
 if (b == NULL)
 {
#ifdef REALLOCATE_BITMAPSETS
  a = bms_copy_and_free(a);
#endif

  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;
 i = 0;
 do
 {
  result->words[i] |= other->words[i];
 } while (++i < otherlen);
 if (result != a)
  pfree(a);
#ifdef REALLOCATE_BITMAPSETS
 else
  result = bms_copy_and_free(result);
#endif

 return result;
}

/*
 * bms_replace_members
 *  Remove all existing members from 'a' and repopulate the set with members
 *  from 'b', recycling 'a', when possible.
 */

Bitmapset *
bms_replace_members(Bitmapset *a, const Bitmapset *b)
{
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 if (a == NULL)
  return bms_copy(b);
 if (b == NULL)
 {
  pfree(a);
  return NULL;
 }

 if (a->nwords < b->nwords)
  a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(b->nwords));

 i = 0;
 do
 {
  a->words[i] = b->words[i];
 } while (++i < b->nwords);

 a->nwords = b->nwords;

#ifdef REALLOCATE_BITMAPSETS

 /*
  * There's no guarantee that the repalloc returned a new pointer, so copy
  * and free unconditionally here.
 */

 a = bms_copy_and_free(a);
#endif

 return a;
}

/*
 * bms_add_range
 *  Add members in the range of 'lower' to 'upper' to the set.
 *
 * Note this could also be done by calling bms_add_member in a loop, however,
 * using this function will be faster when the range is large as we work at
 * the bitmapword level rather than at bit level.
 */

Bitmapset *
bms_add_range(Bitmapset *a, int lower, int upper)
{
 int   lwordnum,
    lbitnum,
    uwordnum,
    ushiftbits,
    wordnum;

 Assert(bms_is_valid_set(a));

 /* do nothing if nothing is called for, without further checking */
 if (upper < lower)
 {
#ifdef REALLOCATE_BITMAPSETS
  a = bms_copy_and_free(a);
#endif

  return a;
 }

 if (lower < 0)
  elog(ERROR, "negative bitmapset member not allowed");
 uwordnum = WORDNUM(upper);

 if (a == NULL)
 {
  a = (Bitmapset *) palloc0(BITMAPSET_SIZE(uwordnum + 1));
  a->type = T_Bitmapset;
  a->nwords = uwordnum + 1;
 }
 else if (uwordnum >= a->nwords)
 {
  int   oldnwords = a->nwords;
  int   i;

  /* ensure we have enough words to store the upper bit */
  a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(uwordnum + 1));
  a->nwords = uwordnum + 1;
  /* zero out the enlarged portion */
  i = oldnwords;
  do
  {
   a->words[i] = 0;
  } while (++i < a->nwords);
 }

 wordnum = lwordnum = WORDNUM(lower);

 lbitnum = BITNUM(lower);
 ushiftbits = BITS_PER_BITMAPWORD - (BITNUM(upper) + 1);

 /*
  * Special case when lwordnum is the same as uwordnum we must perform the
  * upper and lower masking on the word.
 */

 if (lwordnum == uwordnum)
 {
  a->words[lwordnum] |= ~(bitmapword) (((bitmapword) 1 << lbitnum) - 1)
   & (~(bitmapword) 0) >> ushiftbits;
 }
 else
 {
  /* turn on lbitnum and all bits left of it */
  a->words[wordnum++] |= ~(bitmapword) (((bitmapword) 1 << lbitnum) - 1);

  /* turn on all bits for any intermediate words */
  while (wordnum < uwordnum)
   a->words[wordnum++] = ~(bitmapword) 0;

  /* turn on upper's bit and all bits right of it. */
  a->words[uwordnum] |= (~(bitmapword) 0) >> ushiftbits;
 }

#ifdef REALLOCATE_BITMAPSETS

 /*
  * There's no guarantee that the repalloc returned a new pointer, so copy
  * and free unconditionally here.
 */

 a = bms_copy_and_free(a);
#endif

 return a;
}

/*
 * bms_int_members - like bms_intersect, but left input is recycled when
 * possible
 */

Bitmapset *
bms_int_members(Bitmapset *a, const Bitmapset *b)
{
 int   lastnonzero;
 int   shortlen;
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* 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);
 lastnonzero = -1;
 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)
 {
  pfree(a);
  return NULL;
 }

 /* get rid of trailing zero words */
 a->nwords = lastnonzero + 1;

#ifdef REALLOCATE_BITMAPSETS
 a = bms_copy_and_free(a);
#endif

 return a;
}

/*
 * bms_del_members - delete members in 'a' that are set in 'b'.  'a' is
 * recycled when possible.
 */

Bitmapset *
bms_del_members(Bitmapset *a, const Bitmapset *b)
{
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL)
  return NULL;
 if (b == NULL)
 {
#ifdef REALLOCATE_BITMAPSETS
  a = bms_copy_and_free(a);
#endif

  return a;
 }

 /* Remove b's bits from a; we need never copy */
 if (a->nwords > b->nwords)
 {
  /*
   * We'll never need to remove trailing zero words when 'a' has more
   * words than 'b'.
 */

  i = 0;
  do
  {
   a->words[i] &= ~b->words[i];
  } while (++i < b->nwords);
 }
 else
 {
  int   lastnonzero = -1;

  /* we may need to remove trailing zero words from the result. */
  i = 0;
  do
  {
   a->words[i] &= ~b->words[i];

   /* remember the last non-zero word */
   if (a->words[i] != 0)
    lastnonzero = i;
  } while (++i < a->nwords);

  /* check if 'a' has become empty */
  if (lastnonzero == -1)
  {
   pfree(a);
   return NULL;
  }

  /* trim off any trailing zero words */
  a->nwords = lastnonzero + 1;
 }

#ifdef REALLOCATE_BITMAPSETS
 a = bms_copy_and_free(a);
#endif

 return a;
}

/*
 * bms_join - like bms_union, but *either* input *may* be recycled
 */

Bitmapset *
bms_join(Bitmapset *a, Bitmapset *b)
{
 Bitmapset  *result;
 Bitmapset  *other;
 int   otherlen;
 int   i;

 Assert(bms_is_valid_set(a));
 Assert(bms_is_valid_set(b));

 /* Handle cases where either input is NULL */
 if (a == NULL)
 {
#ifdef REALLOCATE_BITMAPSETS
  b = bms_copy_and_free(b);
#endif

  return b;
 }
 if (b == NULL)
 {
#ifdef REALLOCATE_BITMAPSETS
  a = bms_copy_and_free(a);
#endif

  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;
 i = 0;
 do
 {
  result->words[i] |= other->words[i];
 } while (++i < otherlen);
 if (other != result)  /* pure paranoia */
  pfree(other);

#ifdef REALLOCATE_BITMAPSETS
 result = bms_copy_and_free(result);
#endif

 return result;
}

/*
 * bms_next_member - find next member of a set
 *
 * Returns smallest member greater than "prevbit", or -2 if there is none.
 * "prevbit" must NOT be less than -1, or the behavior is unpredictable.
 *
 * This is intended as support for iterating through the members of a set.
 * The typical pattern is
 *
 *   x = -1;
 *   while ((x = bms_next_member(inputset, x)) >= 0)
 *    process member x;
 *
 * Notice that when there are no more members, we return -2, not -1 as you
 * might expect.  The rationale for that is to allow distinguishing the
 * loop-not-started state (x == -1) from the loop-completed state (x == -2).
 * It makes no difference in simple loop usage, but complex iteration logic
 * might need such an ability.
 */

int
bms_next_member(const Bitmapset *a, int prevbit)
{
 int   nwords;
 int   wordnum;
 bitmapword mask;

 Assert(bms_is_valid_set(a));

 if (a == NULL)
  return -2;
 nwords = a->nwords;
 prevbit++;
 mask = (~(bitmapword) 0) << BITNUM(prevbit);
 for (wordnum = WORDNUM(prevbit); wordnum < nwords; wordnum++)
 {
  bitmapword w = a->words[wordnum];

  /* ignore bits before prevbit */
  w &= mask;

  if (w != 0)
  {
   int   result;

   result = wordnum * BITS_PER_BITMAPWORD;
   result += bmw_rightmost_one_pos(w);
   return result;
  }

  /* in subsequent words, consider all bits */
  mask = (~(bitmapword) 0);
 }
 return -2;
}

/*
 * bms_prev_member - find prev member of a set
 *
 * Returns largest member less than "prevbit", or -2 if there is none.
 * "prevbit" must NOT be more than one above the highest possible bit that can
 * be set at the Bitmapset at its current size.
 *
 * To ease finding the highest set bit for the initial loop, the special
 * prevbit value of -1 can be passed to have the function find the highest
 * valued member in the set.
 *
 * This is intended as support for iterating through the members of a set in
 * reverse.  The typical pattern is
 *
 *   x = -1;
 *   while ((x = bms_prev_member(inputset, x)) >= 0)
 *    process member x;
 *
 * Notice that when there are no more members, we return -2, not -1 as you
 * might expect.  The rationale for that is to allow distinguishing the
 * loop-not-started state (x == -1) from the loop-completed state (x == -2).
 * It makes no difference in simple loop usage, but complex iteration logic
 * might need such an ability.
 */


int
bms_prev_member(const Bitmapset *a, int prevbit)
{
 int   wordnum;
 int   ushiftbits;
 bitmapword mask;

 Assert(bms_is_valid_set(a));

 /*
  * If set is NULL or if there are no more bits to the right then we've
  * nothing to do.
 */

 if (a == NULL || prevbit == 0)
  return -2;

 /* transform -1 to the highest possible bit we could have set */
 if (prevbit == -1)
  prevbit = a->nwords * BITS_PER_BITMAPWORD - 1;
 else
  prevbit--;

 ushiftbits = BITS_PER_BITMAPWORD - (BITNUM(prevbit) + 1);
 mask = (~(bitmapword) 0) >> ushiftbits;
 for (wordnum = WORDNUM(prevbit); wordnum >= 0; wordnum--)
 {
  bitmapword w = a->words[wordnum];

  /* mask out bits left of prevbit */
  w &= mask;

  if (w != 0)
  {
   int   result;

   result = wordnum * BITS_PER_BITMAPWORD;
   result += bmw_leftmost_one_pos(w);
   return result;
  }

  /* in subsequent words, consider all bits */
  mask = (~(bitmapword) 0);
 }
 return -2;
}

/*
 * bms_hash_value - compute a hash key for a Bitmapset
 */

uint32
bms_hash_value(const Bitmapset *a)
{
 Assert(bms_is_valid_set(a));

 if (a == NULL)
  return 0;    /* All empty sets hash to 0 */
 return DatumGetUInt32(hash_any((const unsigned char *) a->words,
           a->nwords * sizeof(bitmapword)));
}

/*
 * bitmap_hash - hash function for keys that are (pointers to) Bitmapsets
 *
 * Note: don't forget to specify bitmap_match as the match function!
 */

uint32
bitmap_hash(const void *key, Size keysize)
{
 Assert(keysize == sizeof(Bitmapset *));
 return bms_hash_value(*((const Bitmapset *const *) key));
}

/*
 * bitmap_match - match function to use with bitmap_hash
 */

int
bitmap_match(const void *key1, const void *key2, Size keysize)
{
 Assert(keysize == sizeof(Bitmapset *));
 return !bms_equal(*((const Bitmapset *const *) key1),
       *((const Bitmapset *const *) key2));
}

Messung V0.5 in Prozent
C=90 H=94 G=91

¤ Dauer der Verarbeitung: 0.257 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.