Loading files
// Copyright (c) 2005-2026 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef NCollection_PackedMap_HeaderFile
#define NCollection_PackedMap_HeaderFile
#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
#include <Standard_NoSuchObject.hxx>
#include <Standard_OStream.hxx>
#include <NCollection_Array1.hxx>
#include <NCollection_Primes.hxx>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iterator>
#include <limits>
#include <type_traits>
//! @brief Optimized Map for integer values of various integral types.
//!
//! This template class provides a memory-efficient storage for sets of integers.
//! Each block of BitsPerBlock (32 or 64) consecutive integers is stored compactly
//! using bit manipulation. The block size is automatically selected based on
//! the integer type: 32 bits for int/unsigned, 64 bits for size_t-sized types.
//!
//! @tparam IntType The integral type to store (int, unsigned int, size_t, etc.)
template <typename IntType>
class NCollection_PackedMap
{
static_assert(std::is_integral<IntType>::value,
"NCollection_PackedMap requires an integral type");
public:
DEFINE_STANDARD_ALLOC
//! True if the integer type is larger than 32 bits
static constexpr bool Is64Bit = sizeof(IntType) > 4;
//! The block type for storing packed bits
using BlockType = typename std::conditional<Is64Bit, uint64_t, uint32_t>::type;
//! The type for addressing packed key blocks.
using IndexType = typename std::conditional<sizeof(IntType) <= 4, uint32_t, uint64_t>::type;
using value_type = IntType;
using size_type = size_t;
using difference_type = std::ptrdiff_t;
using reference = const IntType&;
using const_reference = const IntType&;
using pointer = const IntType*;
using const_pointer = const IntType*;
//! Number of bits per block
static constexpr int BitsPerBlock = Is64Bit ? 64 : 32;
private:
//! Number of low bits used for position within a block
static constexpr int MaskLowBits = Is64Bit ? 6 : 5;
//! Mask for low bits (position within block)
static constexpr IndexType MASK_LOW = (IndexType(1) << MaskLowBits) - 1;
//! Mask for high bits (block base address)
static constexpr IndexType MASK_HIGH = ~MASK_LOW;
//! @brief Class implementing a block of consecutive integer values as a node.
//!
//! For 32-bit types: stores 32 consecutive values
//! For 64-bit types: stores 64 consecutive values
//!
//! The data are stored as:
//! - myMask: contains the count-1 in low bits and block base address in high bits
//! - myData: bit field where each bit indicates presence of corresponding integer
class PackedMapNode
{
public:
PackedMapNode(PackedMapNode* thePtr = nullptr)
: myNext(thePtr),
myMask(0),
myData(0)
{
}
PackedMapNode(IntType theValue, PackedMapNode*& thePtr)
: myNext(thePtr),
myMask(static_cast<IndexType>(theValue) & MASK_HIGH),
myData(BlockType(1) << (static_cast<IndexType>(theValue) & MASK_LOW))
{
}
PackedMapNode(IndexType theMask, BlockType theData, PackedMapNode* thePtr)
: myNext(thePtr),
myMask(theMask),
myData(theData)
{
}
IndexType Mask() const { return myMask; }
BlockType Data() const { return myData; }
IndexType& ChangeMask() { return myMask; }
BlockType& ChangeData() { return myData; }
//! Compute the sequential index of this packed node in the map.
IntType Key() const { return static_cast<IntType>(myMask & MASK_HIGH); }
//! Return the number of set integer keys.
size_t NbValues() const { return size_t(myMask & MASK_LOW) + 1; }
//! Return TRUE if this packed node is not empty.
bool HasValues() const { return (myData != 0); }
//! Return TRUE if the given integer key is set within this packed node.
bool HasValue(IntType theValue) const
{
return (myData & (BlockType(1) << (static_cast<IndexType>(theValue) & MASK_LOW))) != 0;
}
//! Add integer key to this packed node.
//! @return TRUE if key has been added
bool AddValue(IntType theValue)
{
const BlockType aValBit = BlockType(1) << (static_cast<IndexType>(theValue) & MASK_LOW);
if ((myData & aValBit) == 0)
{
myData ^= aValBit;
++myMask;
return true;
}
return false;
}
//! Delete integer key from this packed node.
//! @return TRUE if key has been deleted
bool DelValue(IntType theValue)
{
const BlockType aValBit = BlockType(1) << (static_cast<IndexType>(theValue) & MASK_LOW);
if ((myData & aValBit) != 0)
{
myData ^= aValBit;
myMask--;
return true;
}
return false;
}
//! Return the next node having the same hash code.
PackedMapNode* Next() const { return myNext; }
//! Set the next node having the same hash code.
void SetNext(PackedMapNode* theNext) { myNext = theNext; }
public:
//! Support of Map interface.
size_t HashCode(size_t theUpper) const
{
return static_cast<size_t>(myMask >> MaskLowBits) % theUpper + 1;
}
//! Support of Map interface.
bool IsEqual(IndexType theOther) const
{
return (myMask >> MaskLowBits) == (static_cast<IndexType>(theOther));
}
private:
PackedMapNode* myNext;
IndexType myMask;
BlockType myData;
};
//! Iterator implementation over packed bit fields.
template <bool IsConstant>
class BasicIterator
{
public:
using iterator_category = std::input_iterator_tag;
using value_type = IntType;
using difference_type = std::ptrdiff_t;
using pointer = const IntType*;
using reference = const IntType&;
BasicIterator() noexcept
: myBuckets(nullptr),
myNode(nullptr),
myNbBuckets(0),
myBucket(0),
myIntMask(~BlockType(0)),
myKey(0)
{
}
explicit BasicIterator(const NCollection_PackedMap& theMap) noexcept
: myBuckets(theMap.myData1),
myNode(nullptr),
myNbBuckets(theMap.myData1 == nullptr ? 0 : theMap.myNbBuckets),
myBucket(0),
myIntMask(~BlockType(0)),
myKey(0)
{
findFirst();
if (myNode != nullptr)
{
myKey = NCollection_PackedMap::findNext(myNode, myIntMask);
}
}
template <bool B = IsConstant, typename std::enable_if<B, int>::type = 0>
BasicIterator(const BasicIterator<false>& theOther) noexcept
: myBuckets(theOther.myBuckets),
myNode(theOther.myNode),
myNbBuckets(theOther.myNbBuckets),
myBucket(theOther.myBucket),
myIntMask(theOther.myIntMask),
myKey(theOther.myKey)
{
}
template <bool B = IsConstant, typename std::enable_if<B, int>::type = 0>
BasicIterator& operator=(const BasicIterator<false>& theOther) noexcept
{
myBuckets = theOther.myBuckets;
myNode = theOther.myNode;
myNbBuckets = theOther.myNbBuckets;
myBucket = theOther.myBucket;
myIntMask = theOther.myIntMask;
myKey = theOther.myKey;
return *this;
}
reference operator*() const noexcept { return myKey; }
pointer operator->() const noexcept { return &myKey; }
const IntType& Key() const noexcept { return myKey; }
const IntType& Value() const noexcept { return myKey; }
bool More() const noexcept { return myNode != nullptr; }
BasicIterator& operator++()
{
while (myNode != nullptr)
{
myKey = NCollection_PackedMap::findNext(myNode, myIntMask);
if (myIntMask != ~BlockType(0))
{
return *this;
}
nextNode();
}
return *this;
}
BasicIterator operator++(int)
{
BasicIterator anOld(*this);
++(*this);
return anOld;
}
void Reset() noexcept
{
myBucket = 0;
myNode = nullptr;
myIntMask = ~BlockType(0);
myKey = 0;
findFirst();
if (myNode != nullptr)
{
myKey = NCollection_PackedMap::findNext(myNode, myIntMask);
}
}
template <bool theOtherIsConstant>
bool operator==(const BasicIterator<theOtherIsConstant>& theOther) const noexcept
{
if (!More() || !theOther.More())
{
return More() == theOther.More();
}
return myBuckets == theOther.myBuckets && myNode == theOther.myNode
&& myBucket == theOther.myBucket && myIntMask == theOther.myIntMask
&& myKey == theOther.myKey;
}
template <bool theOtherIsConstant>
bool operator!=(const BasicIterator<theOtherIsConstant>& theOther) const noexcept
{
return !(*this == theOther);
}
private:
template <bool>
friend class BasicIterator;
void findFirst() noexcept
{
if (myBuckets == nullptr)
{
return;
}
for (; myBucket <= myNbBuckets; ++myBucket)
{
myNode = myBuckets[myBucket];
if (myNode != nullptr)
{
return;
}
}
}
void nextNode() noexcept
{
if (myNode != nullptr)
{
myNode = myNode->Next();
if (myNode != nullptr)
{
return;
}
}
++myBucket;
while (myBuckets != nullptr && myBucket <= myNbBuckets)
{
myNode = myBuckets[myBucket];
if (myNode != nullptr)
{
return;
}
++myBucket;
}
}
PackedMapNode* const* myBuckets;
PackedMapNode* myNode;
size_t myNbBuckets;
size_t myBucket;
BlockType myIntMask;
IntType myKey;
};
public:
using iterator = BasicIterator<false>;
using const_iterator = BasicIterator<true>;
public:
//! Legacy OCCT cursor backed by the standard iterator state.
class Iterator : public const_iterator
{
public:
Iterator() noexcept = default;
explicit Iterator(const NCollection_PackedMap& theMap) noexcept
: const_iterator(theMap)
{
}
void Initialize(const NCollection_PackedMap& theMap) noexcept { *this = Iterator(theMap); }
void Reset() noexcept { const_iterator::Reset(); }
const IntType& Key() const
{
Standard_NoSuchObject_Raise_if(!More(), "NCollection_PackedMap::Iterator::Key");
return const_iterator::Key();
}
const IntType& Value() const { return Key(); }
bool More() const noexcept { return const_iterator::More(); }
bool IsEqual(const Iterator& theOther) const noexcept
{
return const_iterator::operator==(static_cast<const const_iterator&>(theOther));
}
void Next() noexcept { ++(*this); }
};
public:
//! Returns an iterator pointing to the first element in the map.
iterator begin() noexcept { return iterator(*this); }
//! Returns a const iterator pointing to the first element in the map.
const_iterator begin() const noexcept { return const_iterator(*this); }
//! Returns an iterator referring to the past-the-end element in the map.
iterator end() noexcept { return iterator(); }
//! Returns a const iterator referring to the past-the-end element in the map.
const_iterator end() const noexcept { return const_iterator(); }
//! Returns a const iterator pointing to the first element in the map.
const_iterator cbegin() const noexcept { return const_iterator(*this); }
//! Returns a const iterator referring to the past-the-end element in the map.
const_iterator cend() const noexcept { return const_iterator(); }
public:
//! Constructor
NCollection_PackedMap(const size_t theNbBuckets = 1)
: myData1(nullptr),
myNbBuckets(theNbBuckets == 0 ? 1 : theNbBuckets),
myNbPackedMapNodes(0),
myExtent(0)
{
}
//! Constructor (legacy int-taking).
NCollection_PackedMap(const int theNbBuckets)
: myData1(nullptr),
myNbBuckets(theNbBuckets < 1 ? 1 : static_cast<size_t>(theNbBuckets)),
myNbPackedMapNodes(0),
myExtent(0)
{
}
//! Copy constructor
NCollection_PackedMap(const NCollection_PackedMap& theOther)
: myData1(nullptr),
myNbBuckets(1),
myNbPackedMapNodes(0),
myExtent(0)
{
Assign(theOther);
}
NCollection_PackedMap& operator=(const NCollection_PackedMap& theOther)
{
return Assign(theOther);
}
//! Move constructor
NCollection_PackedMap(NCollection_PackedMap&& theOther) noexcept
: myData1(theOther.myData1),
myNbBuckets(theOther.myNbBuckets),
myNbPackedMapNodes(theOther.myNbPackedMapNodes),
myExtent(theOther.myExtent)
{
theOther.myData1 = nullptr;
theOther.myNbBuckets = 1;
theOther.myNbPackedMapNodes = 0;
theOther.myExtent = 0;
}
//! Move assignment operator
NCollection_PackedMap& operator=(NCollection_PackedMap&& theOther) noexcept
{
if (this != &theOther)
{
Clear();
myData1 = theOther.myData1;
myNbBuckets = theOther.myNbBuckets;
myNbPackedMapNodes = theOther.myNbPackedMapNodes;
myExtent = theOther.myExtent;
theOther.myData1 = nullptr;
theOther.myNbBuckets = 1;
theOther.myNbPackedMapNodes = 0;
theOther.myExtent = 0;
}
return *this;
}
//! Assignment operator
NCollection_PackedMap& Assign(const NCollection_PackedMap& theOther)
{
if (this != &theOther)
{
Clear();
if (!theOther.IsEmpty())
{
ReSize(theOther.myNbPackedMapNodes);
const size_t nBucketsSrc = theOther.myNbBuckets;
const size_t nBuckets = myNbBuckets;
for (size_t i = 0; i <= nBucketsSrc; ++i)
{
for (const PackedMapNode* p = theOther.myData1[i]; p != nullptr;)
{
const size_t aHashCode = p->HashCode(nBuckets);
myData1[aHashCode] = new PackedMapNode(p->Mask(), p->Data(), myData1[aHashCode]);
++myNbPackedMapNodes;
p = p->Next();
}
}
}
myExtent = theOther.myExtent;
}
return *this;
}
//! Resize the map
void ReSize(const size_t theNbBuckets)
{
size_t aNewBuck = NCollection_Primes::NextPrimeForMap(theNbBuckets);
if (aNewBuck <= myNbBuckets)
{
if (!IsEmpty())
{
return;
}
aNewBuck = myNbBuckets;
}
const size_t aBucketCount = aNewBuck + 1;
const size_t aBucketBytes = aBucketCount * sizeof(PackedMapNode*);
PackedMapNode** aNewData =
reinterpret_cast<PackedMapNode**>(Standard::AllocateOptimal(aBucketBytes));
memset(aNewData, 0, aBucketBytes);
if (myData1 != nullptr)
{
PackedMapNode** anOldData = myData1;
for (size_t i = 0; i <= myNbBuckets; ++i)
{
for (PackedMapNode* p = anOldData[i]; p != nullptr;)
{
size_t k = p->HashCode(aNewBuck);
PackedMapNode* q = p->Next();
p->SetNext(aNewData[k]);
aNewData[k] = p;
p = q;
}
}
}
Standard::Free(myData1);
myNbBuckets = aNewBuck;
myData1 = aNewData;
}
//! Resize the map (legacy int-taking).
void ReSize(const int theNbBuckets)
{
ReSize(static_cast<size_t>(theNbBuckets < 0 ? 0 : theNbBuckets));
}
//! Clear the map
void Clear()
{
if (!IsEmpty())
{
for (size_t aBucketIter = 0; aBucketIter <= myNbBuckets; ++aBucketIter)
{
if (myData1[aBucketIter])
{
for (PackedMapNode* aSubNodeIter = myData1[aBucketIter]; aSubNodeIter != nullptr;)
{
PackedMapNode* q = aSubNodeIter->Next();
delete aSubNodeIter;
aSubNodeIter = q;
}
}
}
}
myNbPackedMapNodes = 0;
Standard::Free(myData1);
myData1 = nullptr;
myExtent = 0;
}
~NCollection_PackedMap() { Clear(); }
//! Add a key to the map
//! @param[in] theKey the key to add
//! @return true if the key was added, false if it already existed
bool Add(const IntType theKey)
{
if (resizable())
{
ReSize(myNbPackedMapNodes);
}
const IndexType aKeyInt = packedKeyIndex(theKey);
const size_t aHashCode = hashCode(aKeyInt, myNbBuckets);
PackedMapNode* aBucketHead = myData1[aHashCode];
for (PackedMapNode* p = aBucketHead; p != nullptr; p = p->Next())
{
if (p->IsEqual(aKeyInt))
{
if (p->AddValue(theKey))
{
++myExtent;
return true;
}
return false;
}
}
myData1[aHashCode] = new PackedMapNode(theKey, aBucketHead);
++myNbPackedMapNodes;
++myExtent;
return true;
}
//! Check if the map contains a key
//! @param[in] theKey the key to check
//! @return true if the key is in the map
bool Contains(const IntType theKey) const
{
if (IsEmpty())
{
return false;
}
const IndexType aKeyInt = packedKeyIndex(theKey);
for (PackedMapNode* p = myData1[hashCode(aKeyInt, myNbBuckets)]; p != nullptr;)
{
if (p->IsEqual(aKeyInt))
{
return p->HasValue(theKey);
}
p = p->Next();
}
return false;
}
//! Remove a key from the map
//! @param[in] theKey the key to remove
//! @return true if the key was removed, false if it was not present
bool Remove(const IntType theKey)
{
if (IsEmpty())
{
return false;
}
const IndexType aKeyInt = packedKeyIndex(theKey);
PackedMapNode*& aBucketHead = myData1[hashCode(aKeyInt, myNbBuckets)];
PackedMapNode* p = aBucketHead;
PackedMapNode* q = nullptr;
while (p)
{
if (p->IsEqual(aKeyInt))
{
bool aResult = p->DelValue(theKey);
if (aResult)
{
--myExtent;
if (!p->HasValues())
{
--myNbPackedMapNodes;
if (q != nullptr)
{
q->SetNext(p->Next());
}
else
{
aBucketHead = p->Next();
}
delete p;
}
}
return aResult;
}
q = p;
p = p->Next();
}
return false;
}
//! Returns the number of map buckets.
size_t NbBuckets() const { return myNbBuckets; }
//! Returns map extent (legacy int-returning API).
int Extent() const { return static_cast<int>(myExtent); }
//! Returns map extent (legacy int-returning API, synonym of Extent()).
int Length() const { return static_cast<int>(myExtent); }
//! Returns map extent.
size_t Size() const { return myExtent; }
//! Returns TRUE if map is empty.
bool IsEmpty() const { return myNbPackedMapNodes == 0; }
//! Query the minimal contained key value.
IntType GetMinimalMapped() const
{
if (IsEmpty())
{
return std::numeric_limits<IntType>::max();
}
IntType aResult = std::numeric_limits<IntType>::max();
const PackedMapNode* pFoundNode = nullptr;
for (size_t i = 0; i <= myNbBuckets; ++i)
{
for (const PackedMapNode* p = myData1[i]; p != nullptr; p = p->Next())
{
const IntType aKey = p->Key();
if (aResult > aKey)
{
aResult = aKey;
pFoundNode = p;
}
}
}
if (pFoundNode)
{
BlockType aFullMask = ~BlockType(0);
aResult = findNext(pFoundNode, aFullMask);
}
return aResult;
}
//! Query the maximal contained key value.
IntType GetMaximalMapped() const
{
if (IsEmpty())
{
return std::numeric_limits<IntType>::lowest();
}
IntType aResult = std::numeric_limits<IntType>::lowest();
const PackedMapNode* pFoundNode = nullptr;
for (size_t i = 0; i <= myNbBuckets; ++i)
{
for (const PackedMapNode* p = myData1[i]; p != nullptr; p = p->Next())
{
const IntType aKey = p->Key();
if (aResult < aKey)
{
aResult = aKey;
pFoundNode = p;
}
}
}
if (pFoundNode)
{
BlockType aFullMask = ~BlockType(0);
aResult = findPrev(pFoundNode, aFullMask);
}
return aResult;
}
public:
//! @name Deprecated boolean operations (use NCollection_PackedMapAlgo instead)
//! @deprecated Use NCollection_PackedMapAlgo::Union() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
void Union(const NCollection_PackedMap& theLeft, const NCollection_PackedMap& theRight);
//! @deprecated Use NCollection_PackedMapAlgo::Unite() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
bool Unite(const NCollection_PackedMap& theOther);
//! @deprecated Use NCollection_PackedMapAlgo::Intersection() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
void Intersection(const NCollection_PackedMap& theLeft, const NCollection_PackedMap& theRight);
//! @deprecated Use NCollection_PackedMapAlgo::Intersect() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
bool Intersect(const NCollection_PackedMap& theOther);
//! @deprecated Use NCollection_PackedMapAlgo::Subtraction() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
void Subtraction(const NCollection_PackedMap& theLeft, const NCollection_PackedMap& theRight);
//! @deprecated Use NCollection_PackedMapAlgo::Subtract() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
bool Subtract(const NCollection_PackedMap& theOther);
//! @deprecated Use NCollection_PackedMapAlgo::Difference() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
void Difference(const NCollection_PackedMap& theLeft, const NCollection_PackedMap& theRight);
//! @deprecated Use NCollection_PackedMapAlgo::Differ() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
bool Differ(const NCollection_PackedMap& theOther);
//! @deprecated Use NCollection_PackedMapAlgo::IsEqual() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
bool IsEqual(const NCollection_PackedMap& theOther) const;
//! @deprecated Use NCollection_PackedMapAlgo::IsSubset() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
bool IsSubset(const NCollection_PackedMap& theOther) const;
//! @deprecated Use NCollection_PackedMapAlgo::HasIntersection() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
bool HasIntersection(const NCollection_PackedMap& theOther) const;
//! @deprecated Use NCollection_PackedMapAlgo::Contains() instead
Standard_DEPRECATED("This method will be removed after OCCT 7.9 release. Use methods from "
"NCollection_PackedMapAlgo.hxx instead.")
bool Contains(const NCollection_PackedMap& theOther) const;
protected:
//! Returns TRUE if resizing the map should be considered.
bool resizable() const { return IsEmpty() || (myNbPackedMapNodes > myNbBuckets); }
//! Return an integer index for specified key.
static IndexType packedKeyIndex(IntType theKey)
{
return static_cast<IndexType>(theKey) >> MaskLowBits;
}
//! Compute hash code for a key index.
static size_t hashCode(IndexType theKeyIndex, size_t theNbBuckets)
{
return static_cast<size_t>(theKeyIndex) % theNbBuckets + 1;
}
//! Compute the population (i.e., the number of non-zero bits) of the block.
//! The population is stored decremented as it is defined in PackedMapNode.
static size_t population(IndexType& theMask, BlockType theData)
{
if constexpr (Is64Bit)
{
// 64-bit population count
uint64_t aRes = theData - ((theData >> 1) & 0x5555555555555555ULL);
aRes = (aRes & 0x3333333333333333ULL) + ((aRes >> 2) & 0x3333333333333333ULL);
aRes = (aRes + (aRes >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
aRes = aRes + (aRes >> 8);
aRes = aRes + (aRes >> 16);
aRes = aRes + (aRes >> 32);
theMask = (theMask & MASK_HIGH) | ((static_cast<IndexType>(aRes) - 1) & MASK_LOW);
return size_t(aRes & 0x7f);
}
else
{
// 32-bit population count
uint32_t aRes =
static_cast<uint32_t>(theData) - ((static_cast<uint32_t>(theData) >> 1) & 0x55555555);
aRes = (aRes & 0x33333333) + ((aRes >> 2) & 0x33333333);
aRes = (aRes + (aRes >> 4)) & 0x0f0f0f0f;
aRes = aRes + (aRes >> 8);
aRes = aRes + (aRes >> 16);
theMask = (theMask & MASK_HIGH) | ((aRes - 1) & MASK_LOW);
return size_t(aRes & 0x3f);
}
}
//! Find the smallest non-zero bit under the given mask.
//! Outputs the new mask that does not contain the detected bit.
static IntType findNext(const PackedMapNode* theNode, BlockType& theMask)
{
BlockType val = theNode->Data() & theMask;
int nZeros = 0;
if (val == 0)
{
theMask = ~BlockType(0); // void, nothing to do
}
else
{
BlockType aMask = ~BlockType(0);
if constexpr (Is64Bit)
{
if ((val & 0x00000000ffffffffULL) == 0)
{
aMask = 0xffffffff00000000ULL;
nZeros = 32;
val >>= 32;
}
}
if ((val & 0x0000ffff) == 0)
{
aMask <<= 16;
nZeros += 16;
val >>= 16;
}
if ((val & 0x000000ff) == 0)
{
aMask <<= 8;
nZeros += 8;
val >>= 8;
}
if ((val & 0x0000000f) == 0)
{
aMask <<= 4;
nZeros += 4;
val >>= 4;
}
if ((val & 0x00000003) == 0)
{
aMask <<= 2;
nZeros += 2;
val >>= 2;
}
if ((val & 0x00000001) == 0)
{
aMask <<= 1;
nZeros++;
}
theMask = (aMask << 1);
}
return static_cast<IntType>(nZeros) + theNode->Key();
}
//! Find the highest non-zero bit under the given mask.
//! Outputs the new mask that does not contain the detected bit.
static IntType findPrev(const PackedMapNode* theNode, BlockType& theMask)
{
BlockType val = theNode->Data() & theMask;
int nZeros = 0;
if (val == 0)
{
theMask = ~BlockType(0); // void, nothing to do
}
else
{
BlockType aMask = ~BlockType(0);
if constexpr (Is64Bit)
{
if ((val & 0xffffffff00000000ULL) == 0)
{
aMask = 0x00000000ffffffffULL;
nZeros = 32;
val <<= 32;
}
}
if ((val & BlockType(0xffff0000) << (Is64Bit ? 32 : 0)) == 0)
{
aMask >>= 16;
nZeros += 16;
val <<= 16;
}
if ((val & BlockType(0xff000000) << (Is64Bit ? 32 : 0)) == 0)
{
aMask >>= 8;
nZeros += 8;
val <<= 8;
}
if ((val & BlockType(0xf0000000) << (Is64Bit ? 32 : 0)) == 0)
{
aMask >>= 4;
nZeros += 4;
val <<= 4;
}
if ((val & BlockType(0xc0000000) << (Is64Bit ? 32 : 0)) == 0)
{
aMask >>= 2;
nZeros += 2;
val <<= 2;
}
if ((val & BlockType(0x80000000) << (Is64Bit ? 32 : 0)) == 0)
{
aMask >>= 1;
nZeros++;
}
theMask = (aMask >> 1);
}
return static_cast<IntType>((BitsPerBlock - 1) - nZeros) + theNode->Key();
}
private:
PackedMapNode** myData1; //!< data array
size_t myNbBuckets; //!< number of buckets (size of data array)
size_t myNbPackedMapNodes; //!< amount of packed map nodes
size_t myExtent; //!< extent of this map (number of unpacked integer keys)
};
// Include algorithm header after class definition to avoid circular dependency
#include <NCollection_PackedMapAlgo.hxx>
// Implementation of deprecated methods
template <typename IntType>
void NCollection_PackedMap<IntType>::Union(const NCollection_PackedMap& theLeft,
const NCollection_PackedMap& theRight)
{
NCollection_PackedMapAlgo::Union(*this, theLeft, theRight);
}
template <typename IntType>
bool NCollection_PackedMap<IntType>::Unite(const NCollection_PackedMap& theOther)
{
return NCollection_PackedMapAlgo::Unite(*this, theOther);
}
template <typename IntType>
void NCollection_PackedMap<IntType>::Intersection(const NCollection_PackedMap& theLeft,
const NCollection_PackedMap& theRight)
{
NCollection_PackedMapAlgo::Intersection(*this, theLeft, theRight);
}
template <typename IntType>
bool NCollection_PackedMap<IntType>::Intersect(const NCollection_PackedMap& theOther)
{
return NCollection_PackedMapAlgo::Intersect(*this, theOther);
}
template <typename IntType>
void NCollection_PackedMap<IntType>::Subtraction(const NCollection_PackedMap& theLeft,
const NCollection_PackedMap& theRight)
{
NCollection_PackedMapAlgo::Subtraction(*this, theLeft, theRight);
}
template <typename IntType>
bool NCollection_PackedMap<IntType>::Subtract(const NCollection_PackedMap& theOther)
{
return NCollection_PackedMapAlgo::Subtract(*this, theOther);
}
template <typename IntType>
void NCollection_PackedMap<IntType>::Difference(const NCollection_PackedMap& theLeft,
const NCollection_PackedMap& theRight)
{
NCollection_PackedMapAlgo::Difference(*this, theLeft, theRight);
}
template <typename IntType>
bool NCollection_PackedMap<IntType>::Differ(const NCollection_PackedMap& theOther)
{
return NCollection_PackedMapAlgo::Differ(*this, theOther);
}
template <typename IntType>
bool NCollection_PackedMap<IntType>::IsEqual(const NCollection_PackedMap& theOther) const
{
return NCollection_PackedMapAlgo::IsEqual(*this, theOther);
}
template <typename IntType>
bool NCollection_PackedMap<IntType>::IsSubset(const NCollection_PackedMap& theOther) const
{
return NCollection_PackedMapAlgo::IsSubset(*this, theOther);
}
template <typename IntType>
bool NCollection_PackedMap<IntType>::HasIntersection(const NCollection_PackedMap& theOther) const
{
return NCollection_PackedMapAlgo::HasIntersection(*this, theOther);
}
template <typename IntType>
bool NCollection_PackedMap<IntType>::Contains(const NCollection_PackedMap& theOther) const
{
return NCollection_PackedMapAlgo::Contains(*this, theOther);
}
#endif // NCollection_PackedMap_HeaderFile
c09a95501This file is pinned to the selected release. Download the original to open it in your design tool.