blob: 04f3aa82b846aedf2c92e1f9ef006254c8832fe6 [file] [log] [blame]
//*********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
//*********************************************************************
//*********************************************************************
//
// File: ClusteredBitmap.cpp
// Description: This implements the ClusteredBitmap class that
// allows for a sparse bitmap with values clustered
// around smaller ranges of numbers. Its primary purpose
// is to save memory when storing large ValueIds.
//
// Created: 1/20/2008
// Language: C++
//
//*********************************************************************
#include <stdlib.h>
#include <string.h>
#include "Platform.h"
#include "BaseTypes.h"
#include "NAMemory.h"
#include "ClusteredBitmap.h"
#ifdef WIN32
// The firstSetBit() function produces a warning on Windows.
// Turn it off temporarily.
#pragma warning( disable : 4146 ) // disable "unsigned" warnings
#endif // WIN32
// Isolate the first set bit in the integer value.
inline ClusteredBitmap::cb_int_t
ClusteredBitmap::firstSetBit(cb_int_t value)
{
return value & (-value);
}
#ifdef WIN32
#pragma warning( default : 4146 ) // allow "unsigned" warnings
#endif // WIN32
// Return the significant bits for a particular value. The
// significant bits are bits 9-31 and are used as a lookup
// value in the bitmapMap_ array.
inline UInt32
ClusteredBitmap::significantBits(UInt32 value)
{
return value & SIGNIFICANT_BITS_MASK;
}
// Determine which word in the bitmap stores this value.
inline UInt32
ClusteredBitmap::word(UInt32 value)
{
return (value >> WORD_BITS_SHIFT) & WORD_BITS_MASK;
}
// Return the shifted bit value for the passed in value. The
// returned bit value may be used to perform operations that
// set or clear the bit.
inline ClusteredBitmap::cb_int_t
ClusteredBitmap::shiftedBit(UInt32 value)
{
return (cb_int_t)1 << (value & BITS_MASK);
}
// Count the number of set bits in an integer
inline UInt32
ClusteredBitmap::popCnt(cb_int_t value)
{
// This is a well known algorithm for counting the number of set
// bits in a 32-bit integer. There are no branches, so this is
// pretty quick.
value -= ((value >> 1) & 0x55555555);
value = (((value >> 2) & 0x33333333) + (value & 0x33333333));
value = (((value >> 4) + value) & 0x0f0f0f0f);
value += (value >> 8);
value += (value >> 16);
return (value & 0x0000003f);
}
// Set the 64-byte bitmap array to zero.
inline void
ClusteredBitmap::initializeBitmap(cb_int_t *bits)
{
// Set bits to zero without branches (for slight performance improvement)
*bits++ = 0; *bits++ = 0; *bits++ = 0; *bits++ = 0;
*bits++ = 0; *bits++ = 0; *bits++ = 0; *bits = 0;
#if (CB_BITS_PER_WORD == 32)
*++bits = 0; *++bits = 0; *++bits = 0; *++bits = 0;
*++bits = 0; *++bits = 0; *++bits = 0; *++bits = 0;
#endif
}
// Count the number of set bits in a 64-byte bitmap.
// NOTE: On Yosemite, this is done 64-bits at a time, while on other
// platforms, it is done 32-bits at a time.
inline Int32
ClusteredBitmap::countBits(cb_int_t *bits)
{
Int32 numBits = 0;
numBits += popCnt(*bits++); numBits += popCnt(*bits++);
numBits += popCnt(*bits++); numBits += popCnt(*bits++);
numBits += popCnt(*bits++); numBits += popCnt(*bits++);
numBits += popCnt(*bits++); numBits += popCnt(*bits);
#if (CB_BITS_PER_WORD == 32)
numBits += popCnt(*++bits); numBits += popCnt(*++bits);
numBits += popCnt(*++bits); numBits += popCnt(*++bits);
numBits += popCnt(*++bits); numBits += popCnt(*++bits);
numBits += popCnt(*++bits); numBits += popCnt(*++bits);
#endif
return numBits;
}
// Copy a 64-byte bitmap to another 64-byte bitmap.
inline void
ClusteredBitmap::copyBits(cb_int_t *tobits, cb_int_t *frombits)
{
*tobits++ = *frombits++; *tobits++ = *frombits++;
*tobits++ = *frombits++; *tobits++ = *frombits++;
*tobits++ = *frombits++; *tobits++ = *frombits++;
*tobits++ = *frombits++; *tobits = *frombits;
#if (CB_BITS_PER_WORD == 32)
*++tobits = *++frombits; *++tobits = *++frombits;
*++tobits = *++frombits; *++tobits = *++frombits;
*++tobits = *++frombits; *++tobits = *++frombits;
*++tobits = *++frombits; *++tobits = *++frombits;
#endif
}
// Copy each of the words in the bitmap and return the number of
// bits that were set in the copy.
inline Int32
ClusteredBitmap::copyCountBits(cb_int_t *tobits, cb_int_t *frombits)
{
Int32 numBits = 0;
// Copy to the other bitmap and call popCnt() to see how many bits
// are set in the copied word.
for (UInt32 wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
{
cb_int_t fromWord = *frombits++;
*tobits++ = fromWord;
numBits += popCnt(fromWord);
}
return numBits;
}
// Logical OR two bit arrays storing the results in the first array.
// The number of bits in the result array is returned.
inline Int32
ClusteredBitmap::orBits(cb_int_t *tobits, cb_int_t *frombits)
{
Int32 setBits = 0;
// Perform logical-OR on each bit set (when the bits are not equal)
// and store the result in the tobits array.
for (UInt32 wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
{
cb_int_t result = *frombits++ | *tobits;
*tobits++ = result;
setBits += popCnt(result);
}
return setBits;
}
// Logically-AND two bit arrays storing the results in the first array
// The number of set bits in the result array is returned.
inline Int32
ClusteredBitmap::andBits(cb_int_t *tobits, cb_int_t *otherbits)
{
Int32 numSetBits = 0;
for (UInt32 wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
{
cb_int_t andVal = *tobits & *otherbits++;
*tobits++ = andVal;
numSetBits += popCnt(andVal);
}
return numSetBits;
}
// Clear bits in the first array that are set in the second array.
inline Int32
ClusteredBitmap::clearBits(cb_int_t *tobits, cb_int_t *removebits)
{
Int32 numSetBits = 0;
for (UInt32 wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
{
cb_int_t result = *tobits & ~(*removebits++);
*tobits++ = result;
numSetBits += popCnt(result);
}
return numSetBits;
}
// Increase the size of the bitmap array to hold at least the size
// needed. The maximum number of elements in the array will be
// increased to the next multiple of 8 boundary.
inline void
ClusteredBitmap::increaseBitmapMapSize(UInt32 numNeeded)
{
if (numNeeded > maxBitmaps_)
{
// Increase size to next multiple of 8 boundary.
maxBitmaps_ = (numNeeded & ~0x7) + 8;
// Create a new bitsToBitmap to array and copy old values to new
// array.
bitsToBitmap *newMap = new (heap_) bitsToBitmap[maxBitmaps_];
for (UInt32 thisIdx = 0; thisIdx < numBitmaps_; thisIdx++)
{
// LCOV_EXCL_START :cnu
newMap[thisIdx].significantBits_ = bitmapMap_[thisIdx].significantBits_;
newMap[thisIdx].bitmap_ = bitmapMap_[thisIdx].bitmap_;
// LCOV_EXCL_STOP
}
// Delete old array and set current bitmapMap to the new one
if (bitmapMap_)
NADELETEBASIC(bitmapMap_, heap_);
bitmapMap_ = newMap;
}
}
// Allocate and insert a new bitmap based on the significant bits.
// The caller should ensure that this function is not called when
// an entry already exists that matches the significant bits.
ClusteredBitmap::cb_int_t*
ClusteredBitmap::insertMap(UInt32 significantBits)
{
UInt32 thisIdx;
// Allocate a new bitmap and initialize it to zero.
cb_int_t *bitmap = new (heap_) cb_int_t[WORDS_PER_BITMAP];
initializeBitmap(bitmap);
// Make sure there are enough bitmap entries
if (numBitmaps_ == maxBitmaps_)
{
// Increase size to next multiple of 8 boundary.
maxBitmaps_ = (maxBitmaps_ & ~0x7) + 8;
// Create a new bitsToBitmap array
bitsToBitmap *newMap = new (heap_) bitsToBitmap[maxBitmaps_];
// Copy to the new bitmap map while looking for the proper
// insertion point.
for (thisIdx = 0; thisIdx < numBitmaps_; thisIdx++)
{
if (significantBits < bitmapMap_[thisIdx].significantBits_)
break;
newMap[thisIdx].bitmap_ = bitmapMap_[thisIdx].bitmap_;
newMap[thisIdx].significantBits_ =
bitmapMap_[thisIdx].significantBits_;
}
// Insert the new bitmap into the array of bitmap maps.
newMap[thisIdx].bitmap_ = bitmap;
newMap[thisIdx].significantBits_ = significantBits;
numBitmaps_++;
// Copy the rest of the bitmaps to the bitmap array;
for (thisIdx++; thisIdx < numBitmaps_; thisIdx++)
{
newMap[thisIdx].bitmap_ = bitmapMap_[thisIdx - 1].bitmap_;
newMap[thisIdx].significantBits_ =
bitmapMap_[thisIdx - 1].significantBits_;
}
// Free the old bitmap map and set the pointer to the new one
if (bitmapMap_)
NADELETEBASIC(bitmapMap_, heap_);
bitmapMap_ = newMap;
}
else
{
// Start from the last bitmap map and move entries forward
// until the proper insertion point is found.
for (thisIdx = numBitmaps_; thisIdx > 0; thisIdx--)
{
if (significantBits > bitmapMap_[thisIdx - 1].significantBits_)
break;
bitmapMap_[thisIdx].bitmap_ = bitmapMap_[thisIdx - 1].bitmap_;
bitmapMap_[thisIdx].significantBits_ =
bitmapMap_[thisIdx - 1].significantBits_;
}
// Insert the new bitmap map;
bitmapMap_[thisIdx].bitmap_ = bitmap;
bitmapMap_[thisIdx].significantBits_ = significantBits;
numBitmaps_++;
}
return bitmap;
}
// ClusteredBitmap constructor
ClusteredBitmap::ClusteredBitmap(CollHeap *heap) :
heap_(heap),
bitmapMap_(0),
numBitmaps_(0),
maxBitmaps_(0),
entries_(0)
{
}
// ClusteredBitmap constructor
ClusteredBitmap::ClusteredBitmap(const ClusteredBitmap &other,
CollHeap *heap)
: heap_(heap),
bitmapMap_(0),
numBitmaps_(0), // Reset to new value later
maxBitmaps_(0),
entries_(other.entries_)
{
if (other.numBitmaps_)
{
increaseBitmapMapSize(other.numBitmaps_);
numBitmaps_ = other.numBitmaps_;
for (UInt32 thisIdx = 0; thisIdx < numBitmaps_; thisIdx++)
{
bitmapMap_[thisIdx].significantBits_ =
other.bitmapMap_[thisIdx].significantBits_;
bitmapMap_[thisIdx].bitmap_ = new (heap_) cb_int_t[WORDS_PER_BITMAP];
copyBits(bitmapMap_[thisIdx].bitmap_, other.bitmapMap_[thisIdx].bitmap_);
}
}
}
// LCOV_EXCL_START :cnu
// ClusteredBitmap constructor
ClusteredBitmap::ClusteredBitmap(const ClusteredBitmap &other)
: heap_(other.heap_),
bitmapMap_(0),
numBitmaps_(0), // Reset to new value later
maxBitmaps_(0),
entries_(other.entries_)
{
increaseBitmapMapSize(other.numBitmaps_);
numBitmaps_ = other.numBitmaps_;
for (UInt32 thisIdx = 0; thisIdx < numBitmaps_; thisIdx++)
{
bitmapMap_[thisIdx].significantBits_ =
other.bitmapMap_[thisIdx].significantBits_;
bitmapMap_[thisIdx].bitmap_ = new (heap_) cb_int_t[WORDS_PER_BITMAP];
copyBits(bitmapMap_[thisIdx].bitmap_, other.bitmapMap_[thisIdx].bitmap_);
}
}
// LCOV_EXCL_STOP
// ClusteredBitmap destructor
ClusteredBitmap::~ClusteredBitmap()
{
if (bitmapMap_)
{
for (UInt32 i = 0; i < numBitmaps_; i++)
NADELETEBASIC(bitmapMap_[i].bitmap_, heap_);
NADELETEBASIC(bitmapMap_, heap_);
}
}
// Clear this ClusteredBitmap object.
void ClusteredBitmap::clear()
{
if (bitmapMap_)
{
for (UInt32 thisIdx = 0; thisIdx < numBitmaps_; thisIdx++)
NADELETEBASIC(bitmapMap_[thisIdx].bitmap_, heap_);
NADELETEBASIC(bitmapMap_, heap_);
bitmapMap_ = NULL;
}
numBitmaps_ = 0;
maxBitmaps_ = 0;
entries_ = 0;
}
// This returns either the bitmap map that matches the significant bits,
// or returns the first bitmap map that is greater than the significant
// bits. This uses a binary search to find the matching bitmap.
inline ClusteredBitmap::bitsToBitmap*
ClusteredBitmap::findEqualOrGreaterBitmapMap(UInt32 sigBits) const
{
if (numBitmaps_ == 0)
return NULL;
Int32 low = 0;
Int32 high = numBitmaps_ - 1;
Int32 middle;
bitsToBitmap *map;
while (low <= high)
{
middle = (low + high) >> 1;
map = &bitmapMap_[middle];
if (map->significantBits_ > sigBits)
high = middle - 1;
else if (map->significantBits_ < sigBits)
low = middle + 1;
else
return map; // Found an equal match
}
if (map->significantBits_ < sigBits)
map++;
if (map == &bitmapMap_[numBitmaps_])
return NULL;
// This is the map with the next greater significant bits
return map;
}
// findBitmap() uses a binary search to find a matching bitmap.
inline ClusteredBitmap::cb_int_t*
ClusteredBitmap::findBitmap(UInt32 significantBits) const
{
Int32 low = 0;
Int32 high = (Int32)numBitmaps_ - 1;
while (low <= high)
{
Int32 middle = (low + high) >> 1;
bitsToBitmap *map = &bitmapMap_[middle];
if (map->significantBits_ > significantBits)
high = middle - 1;
else if (map->significantBits_ < significantBits)
low = middle + 1;
else
return map->bitmap_;
}
return NULL;
}
// Add a value to this bitmap.
ClusteredBitmap &
ClusteredBitmap::addElement(UInt32 value)
{
UInt32 sigBits = significantBits(value);
cb_int_t *bitmap = findBitmap(sigBits);
if (bitmap == NULL)
bitmap = insertMap(sigBits);
cb_int_t *wordPtr = &bitmap[word(value)];
cb_int_t bit = shiftedBit(value);
if ((*wordPtr & bit) == 0)
{
*wordPtr |= bit;
entries_++;
}
return *this;
}
// Remove a value from this bitmap.
ClusteredBitmap &
ClusteredBitmap::subtractElement(UInt32 value)
{
UInt32 sigBits = significantBits(value);
cb_int_t *bitmap = findBitmap(sigBits);
if (bitmap == NULL)
return *this;
cb_int_t *wordPtr = &bitmap[word(value)];
cb_int_t bit = shiftedBit(value);
if ((*wordPtr & bit) != 0)
{
*wordPtr &= ~bit;
entries_--;
}
return *this;
}
// Add the elements from another bitmap to this one.
// This function first determines how many bitmaps are needed and allocates
// a new buffer for the map of bitmaps. Then as the two bitmaps are combined,
// the new buffer is filled in with the new bitmaps.
ClusteredBitmap &
ClusteredBitmap::addSet(const ClusteredBitmap &other)
{
UInt32 thisIdx = 0;
UInt32 otherIdx = 0;
UInt32 neededBitmaps = 0;
UInt32 numNewBits = 0;
// First determine how many bitmaps are needed so we only have
// to allocate memory once for the final bitmap maps.
while (thisIdx < numBitmaps_ && otherIdx < other.numBitmaps_)
{
neededBitmaps++;
if (bitmapMap_[thisIdx].significantBits_ ==
other.bitmapMap_[otherIdx].significantBits_)
{
thisIdx++;
otherIdx++;
}
else if (bitmapMap_[thisIdx].significantBits_ <
other.bitmapMap_[otherIdx].significantBits_)
{
thisIdx++;
}
else
{
otherIdx++;
}
}
// Add additional bitmaps that weren't taken into account in previous
// loop.
neededBitmaps += numBitmaps_ - thisIdx + other.numBitmaps_ - otherIdx;
// Increase to next multiple of 8.
neededBitmaps = (neededBitmaps & ~0x7) + 8;
maxBitmaps_ = neededBitmaps;
// Allocate a new buffer to hold the bitmap map.
bitsToBitmap *newMap = new (heap_) bitsToBitmap[neededBitmaps];
thisIdx = 0;
otherIdx = 0;
UInt32 newMapIdx = 0;
// Create the new bitmap array that logically OR all of the bitmaps.
while (thisIdx < numBitmaps_ && otherIdx < other.numBitmaps_)
{
if (bitmapMap_[thisIdx].significantBits_ ==
other.bitmapMap_[otherIdx].significantBits_)
{
numNewBits += orBits(bitmapMap_[thisIdx].bitmap_,
other.bitmapMap_[otherIdx].bitmap_);
newMap[newMapIdx].significantBits_ =
bitmapMap_[thisIdx].significantBits_;
newMap[newMapIdx].bitmap_ = bitmapMap_[thisIdx].bitmap_;
thisIdx++;
otherIdx++;
}
else if (bitmapMap_[thisIdx].significantBits_ <
other.bitmapMap_[otherIdx].significantBits_)
{
newMap[newMapIdx].significantBits_ =
bitmapMap_[thisIdx].significantBits_;
newMap[newMapIdx].bitmap_ = bitmapMap_[thisIdx].bitmap_;
numNewBits += countBits(bitmapMap_[thisIdx].bitmap_);
thisIdx++;
}
else
{
newMap[newMapIdx].significantBits_ =
other.bitmapMap_[otherIdx].significantBits_;
newMap[newMapIdx].bitmap_ = new (heap_) cb_int_t[WORDS_PER_BITMAP];
numNewBits += copyCountBits(newMap[newMapIdx].bitmap_,
other.bitmapMap_[otherIdx].bitmap_);
otherIdx++;
}
newMapIdx++;
}
// Set any remaining bitmaps in this object in the new buffer.
while (thisIdx < numBitmaps_)
{
newMap[newMapIdx].significantBits_ =
bitmapMap_[thisIdx].significantBits_;
newMap[newMapIdx].bitmap_ = bitmapMap_[thisIdx].bitmap_;
numNewBits += countBits(bitmapMap_[thisIdx].bitmap_);
thisIdx++;
newMapIdx++;
}
// Copy any remaining bitmaps in the other object and store pointers
// to the bitmaps in the new bitmap map.
while (otherIdx < other.numBitmaps_)
{
newMap[newMapIdx].significantBits_ =
other.bitmapMap_[otherIdx].significantBits_;
newMap[newMapIdx].bitmap_ = new (heap_) cb_int_t[WORDS_PER_BITMAP];
numNewBits += copyCountBits(newMap[newMapIdx].bitmap_,
other.bitmapMap_[otherIdx].bitmap_);
otherIdx++;
newMapIdx++;
}
// Destroy the old bitmap map array and assign the new one.
if (bitmapMap_)
NADELETEBASIC(bitmapMap_, heap_);
bitmapMap_ = newMap;
numBitmaps_ = newMapIdx;
entries_ = numNewBits;
return *this;
}
// Remove the bits that are in the other bitmap from this one.
ClusteredBitmap &
ClusteredBitmap::subtractSet(const ClusteredBitmap &other)
{
UInt32 thisIdx = 0;
UInt32 otherIdx = 0;
UInt32 newMapIdx = 0;
Int32 numSetBits = 0;
// Examine each bitmap array
while (thisIdx < numBitmaps_ && otherIdx < other.numBitmaps_)
{
if (bitmapMap_[thisIdx].significantBits_ ==
other.bitmapMap_[otherIdx].significantBits_)
{
Int32 numBits = clearBits(bitmapMap_[thisIdx].bitmap_,
other.bitmapMap_[otherIdx].bitmap_);
if (numBits == 0)
{
NADELETEBASIC(bitmapMap_[thisIdx].bitmap_, heap_);
bitmapMap_[thisIdx].bitmap_ = 0;
bitmapMap_[thisIdx].significantBits_ = 0;
}
else
{
numSetBits += numBits;
bitmapMap_[newMapIdx].significantBits_ =
bitmapMap_[thisIdx].significantBits_;
bitmapMap_[newMapIdx].bitmap_ = bitmapMap_[thisIdx].bitmap_;
newMapIdx++;
}
thisIdx++;
otherIdx++;
}
else if (bitmapMap_[thisIdx].significantBits_ <
other.bitmapMap_[otherIdx].significantBits_)
{
numSetBits += countBits(bitmapMap_[thisIdx].bitmap_);
bitmapMap_[newMapIdx].bitmap_ = bitmapMap_[thisIdx].bitmap_;
bitmapMap_[newMapIdx].significantBits_ =
bitmapMap_[thisIdx].significantBits_;
thisIdx++;
newMapIdx++;
}
else
{
otherIdx++;
}
}
// Move any remaining ones bitmaps forward in the array
while (thisIdx < numBitmaps_)
{
numSetBits += countBits(bitmapMap_[thisIdx].bitmap_);
bitmapMap_[newMapIdx].bitmap_ = bitmapMap_[thisIdx].bitmap_;
bitmapMap_[newMapIdx].significantBits_ =
bitmapMap_[thisIdx].significantBits_;
thisIdx++;
newMapIdx++;
}
// Set remaining ones to NULL. These ones have already been moved
// forward so they should not be deleted. Also, this loop isn't really
// necessary, but may help with debugging.
for (UInt32 j = newMapIdx; j < numBitmaps_; j++)
{
bitmapMap_[j].bitmap_ = 0;
bitmapMap_[j].significantBits_ = 0;
}
numBitmaps_ = newMapIdx;
entries_ = numSetBits;
return *this;
}
// Find the next set bit in the bitmap starting with the passed in value.
// True is returned if a value was successfully found, and false is returned
// if there is not another bit set.
NABoolean
ClusteredBitmap::nextUsed(CollIndex &start) const
{
cb_int_t *bitmap;
UInt32 sigBits = significantBits(start);
bitsToBitmap * map = findEqualOrGreaterBitmapMap(sigBits);
if (!map)
return false;
// If an exact bitmap match was found, search the rest of it for another
// set bit.
if (map->significantBits_ == sigBits)
{
bitmap = map->bitmap_;
UInt32 wordIdx = word(start);
cb_int_t bit = shiftedBit(start);
// Set all bits to the left of the bit including the shifted bit.
cb_int_t bitMask = ~(bit - 1);
// Determine if any bits are set above this one in this word.
cb_int_t setBits = bitmap[wordIdx] & bitMask;
// If any bits are set, then determine the next set bit and return
// it in the "start" parameter.
if (setBits)
{
// Isolate the least significant bit set in this word.
cb_int_t leastBit = firstSetBit(setBits);
// Determine the index of this bit using population count.
UInt32 bitIdx = popCnt(--leastBit);
start = map->significantBits_ + (wordIdx << WORD_BITS_SHIFT) +
bitIdx;
return true;
}
// Check the rest of the words in this bitmap.
for (wordIdx++; wordIdx < WORDS_PER_BITMAP; wordIdx++)
{
// Store the word in a local variable
cb_int_t wordVal = bitmap[wordIdx];
// If any bits are set, then determine the first set bit and
// return it in the "start" parameter.
if (wordVal != 0)
{
// Isolate the least significant bit set in this word.
cb_int_t leastBit = firstSetBit(wordVal);
// Determine the index of this bit using population count.
UInt32 bitIdx = popCnt(--leastBit);
start = map->significantBits_ + (wordIdx << WORD_BITS_SHIFT) +
bitIdx;
return true;
}
}
// Increment map pointer to point to next bitmap map.
map++;
}
// Get a pointer to one past the final bitmap.
bitsToBitmap *endPtr = &bitmapMap_[numBitmaps_];
// Search the rest of the bitmaps for a set bit.
while (map < endPtr)
{
cb_int_t *wordPtr = map->bitmap_;
for (UInt32 wordIdx = 0; wordIdx != WORDS_PER_BITMAP; wordIdx++)
{
cb_int_t wordVal = *wordPtr++;
if (wordVal != 0)
{
// Isolate the least significant bit set in this word.
cb_int_t leastBit = firstSetBit(wordVal);
// Determine the index of this bit using population count.
UInt32 bitIdx = popCnt(--leastBit);
start = map->significantBits_ + (wordIdx << WORD_BITS_SHIFT) +
bitIdx;
return true;
}
}
// Increment map pointer to point to next bitmap map.
map++;
}
// There were no more set bits. Return false.
return false;
}
// Perform a logical AND of this bitmap with another.
// This operation always results in either the same number of
// bitmaps or less bitmaps than this object started with.
// The only bitmaps that remain must be in common between
// the two objects. This function removes any bitmaps that
// do not have any bits set.
ClusteredBitmap &
ClusteredBitmap::intersectSet(const ClusteredBitmap &other)
{
UInt32 thisIdx = 0;
UInt32 otherIdx = 0;
UInt32 numBitmaps = 0;
UInt32 newNumBits = 0;
UInt32 numSetBits;
// Examine each bitmap array
while (thisIdx < numBitmaps_ && otherIdx < other.numBitmaps_)
{
if (bitmapMap_[thisIdx].significantBits_ ==
other.bitmapMap_[otherIdx].significantBits_)
{
// Perform a logical AND of the two bitmaps.
numSetBits = andBits(bitmapMap_[thisIdx].bitmap_,
other.bitmapMap_[otherIdx].bitmap_);
// If there were no bits in common between the two bitmaps
// then delete this bitmap. Otherwise adjust the significant
// bits and bitmap pointer in the array to account for any
// other bitmaps that may have been deleted during other times
// through the "while" loop.
if (numSetBits == 0)
{
NADELETEBASIC(bitmapMap_[thisIdx].bitmap_, heap_);
bitmapMap_[thisIdx].bitmap_ = 0;
bitmapMap_[thisIdx].significantBits_ = 0;
}
else
{
newNumBits += numSetBits;
bitmapMap_[numBitmaps].significantBits_ =
bitmapMap_[thisIdx].significantBits_;
bitmapMap_[numBitmaps].bitmap_ = bitmapMap_[thisIdx].bitmap_;
numBitmaps++;
}
thisIdx++;
otherIdx++;
}
else if (bitmapMap_[thisIdx].significantBits_ <
other.bitmapMap_[otherIdx].significantBits_)
{
// This bitmap does not have a match in the other. It must be
// deleted.
NADELETEBASIC(bitmapMap_[thisIdx].bitmap_, heap_);
bitmapMap_[thisIdx].bitmap_ = 0;
bitmapMap_[thisIdx].significantBits_ = 0;
thisIdx++;
}
else
{
// This other bitmap does not have a match in this one. Simply
// increment the other index.
otherIdx++;
}
}
// Remove any that weren't already handled in previous loop.
while (thisIdx < numBitmaps_)
{
NADELETEBASIC(bitmapMap_[thisIdx].bitmap_, heap_);
// It isn't necessary to set these to 0, but it may help with debugging.
bitmapMap_[thisIdx].bitmap_ = 0;
bitmapMap_[thisIdx].significantBits_ = 0;
thisIdx++;
}
// Set the number of bitmaps to the number that were handled in the first
// while loop.
entries_ = newNumBits;
numBitmaps_ = numBitmaps;
return *this;
} // ClusteredBitmap::intersectSet(const ClusteredBitmap &other)
// Return whether all bits in the other set are set within this set.
NABoolean
ClusteredBitmap::contains(const ClusteredBitmap & other) const
{
UInt32 thisIdx = 0;
UInt32 otherIdx = 0;
UInt32 wordIdx;
cb_int_t *otherWordPtr;
cb_int_t *thisWordPtr;
// Search through the the bitmaps of both objects for bits that
// are set only in the other ClusteredBitmap
while (thisIdx < numBitmaps_ && otherIdx < other.numBitmaps_)
{
if (bitmapMap_[thisIdx].significantBits_ ==
other.bitmapMap_[otherIdx].significantBits_)
{
// Set the bitmap pointers and also increment each map index
otherWordPtr = other.bitmapMap_[otherIdx++].bitmap_;
thisWordPtr = bitmapMap_[thisIdx++].bitmap_;
for (wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
{
// for a word present in both, "other" mustn't have bits on that
// are off in this word (in other words, when ORing the two words,
// other must not cause any changes by having additional bits set)
cb_int_t word = *thisWordPtr++;
if (word != (word | *otherWordPtr++))
return false;
}
}
else if (bitmapMap_[thisIdx].significantBits_ <
other.bitmapMap_[otherIdx].significantBits_)
{
// If the other contains bits and this is missing a bitmap
// for this range, then return false;
// If there isn't a bitmap in the other, then just skip
// the bitmap in this by incrementing the map index.
thisIdx++;
}
else
{
// Set the bitmap pointer and increment the other map index
otherWordPtr = other.bitmapMap_[otherIdx++].bitmap_;
// If the other contains bits and this is missing a bitmap
// for this range, then return false;
for (wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
if (*otherWordPtr++ != 0)
return false;
}
}
// Search any remaining in other for set bits. If there are
// any, then return false.
while (otherIdx < other.numBitmaps_)
{
otherWordPtr = other.bitmapMap_[otherIdx++].bitmap_;
for (wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
if (*otherWordPtr++ != 0)
return false;
}
// No bits were found that are only set in "other", so return true.
return true;
} // ClusteredBitmap::contains(const ClusteredBitmap & other) const
// Return whether the passed in value is set within this bitmap.
NABoolean
ClusteredBitmap::contains(const UInt32 value) const
{
cb_int_t *bitmap = findBitmap(significantBits(value));
return (bitmap && (bitmap[word(value)] & shiftedBit(value)) != 0);
}
// Assign this ClusteredBitmap to another one.
ClusteredBitmap &
ClusteredBitmap::operator= (const ClusteredBitmap &other)
{
if (this != &other)
{
// Delete all of the previous bitmaps
for (UInt32 thisIdx = 0; thisIdx < numBitmaps_; thisIdx++)
NADELETEBASIC(bitmapMap_[thisIdx].bitmap_, heap_);
// Set numBitmaps_ to zero and call increaseBitmapMapSize() to
// allocation additional memory if necessary. NOTE: numBitmaps_
// is set to zero before calling increaseBitmapMapSize() because
// there is no need to copy the old bitmap information.
numBitmaps_ = 0;
if (other.numBitmaps_ > maxBitmaps_)
increaseBitmapMapSize(other.numBitmaps_);
numBitmaps_ = other.numBitmaps_;
entries_ = other.entries_;
// Copy each of the other's bitmaps
for (UInt32 thisIdx = 0; thisIdx < numBitmaps_; thisIdx++)
{
bitmapMap_[thisIdx].significantBits_ =
other.bitmapMap_[thisIdx].significantBits_;
bitmapMap_[thisIdx].bitmap_ = new (heap_) cb_int_t[WORDS_PER_BITMAP];
copyBits(bitmapMap_[thisIdx].bitmap_, other.bitmapMap_[thisIdx].bitmap_);
}
}
return *this;
}
// Compare two ClusteredBitmap objects to see whether they
// contain the same set bits.
NABoolean
ClusteredBitmap::operator== (const ClusteredBitmap &other) const
{
if (entries_ != other.entries_)
return false;
if (entries_ == 0 && other.entries_ == 0)
return true;
UInt32 thisIdx = 0;
UInt32 otherIdx = 0;
UInt32 wordIdx;
cb_int_t *thisWordPtr;
cb_int_t *otherWordPtr;
// Compare each bitmap to the other. This code must take into
// account the possibility of an empty bitmap in either of the
// ClusteredBitmap objects.
while (thisIdx < numBitmaps_ && otherIdx < other.numBitmaps_)
{
if (bitmapMap_[thisIdx].significantBits_ ==
other.bitmapMap_[otherIdx].significantBits_)
{
thisWordPtr = bitmapMap_[thisIdx++].bitmap_;
otherWordPtr = other.bitmapMap_[otherIdx++].bitmap_;
for (wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
if (*thisWordPtr++ != *otherWordPtr++)
return false;
}
else if (bitmapMap_[thisIdx].significantBits_ <
other.bitmapMap_[otherIdx].significantBits_)
{
// if this contains any set bits, then the two are not
// equal.
thisWordPtr = bitmapMap_[thisIdx++].bitmap_;
for (wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
if (*thisWordPtr++ != 0)
return false;
}
else
{
// if the other contains any set bits, then the two are not
// equal.
otherWordPtr = other.bitmapMap_[otherIdx++].bitmap_;
for (wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
if (*otherWordPtr++ != 0)
return false;
}
}
// Check any remaining bitmaps in this object
while (thisIdx < numBitmaps_)
{
thisWordPtr = bitmapMap_[thisIdx++].bitmap_;
for (wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
if (*thisWordPtr++ != 0)
return false;
}
// Check any remaining bitmaps in the other object
while (otherIdx < other.numBitmaps_)
{
otherWordPtr = other.bitmapMap_[otherIdx++].bitmap_;
for (wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
if (*otherWordPtr++ != 0)
return false;
}
return true;
}
// Provide a hash value based on bits that are set in the bitmaps
ULng32
ClusteredBitmap::hash() const
{
cb_int_t hashVal = 0;
for (UInt32 thisIdx = 0; thisIdx < numBitmaps_; thisIdx++)
{
cb_int_t *wordPtr = bitmapMap_[thisIdx].bitmap_;
for (UInt32 wordIdx = WORDS_PER_BITMAP; wordIdx != 0; wordIdx--)
hashVal ^= *wordPtr++;
}
#if (CB_BITS_PER_WORD == 32)
return hashVal;
#else
return (ULng32)(hashVal & 0xFFFFFFFF) ^ (ULng32)(hashVal >> 32);
#endif
}