1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-04 18:06:22 +03:00
occt/src/TColStd/TColStd_PackedMapOfInteger.cxx

1278 lines
45 KiB
C++

// Created on: 2005-11-05
// Created by: Alexander GRIGORIEV
// Copyright (c) 2005-2014 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.
#include <TColStd_PackedMapOfInteger.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#include <TCollection_MapNode.hxx>
#include <Standard_DefineHandle.hxx>
// 5 lower bits
#define MASK_LOW 0x001f
// 27 upper bits
#define MASK_HIGH (~MASK_LOW)
/**
* Class implementing a block of 32 consecutive integer values as a node of
* a Map collection. The data are stored in 64 bits as:
* - bits 0 - 4 : (number of integers stored in the block) - 1;
* - bits 5 - 31: base address of the block of integers (low bits assumed 0)
* - bits 32 - 63: 32-bit field where each bit indicates the presence of the
* corresponding integer in the block. Number of non-zero bits
* must be equal to the number expressed in bits 0-4.
*/
class TColStd_intMapNode : public TCollection_MapNode
{
public:
inline TColStd_intMapNode (TCollection_MapNode * ptr = 0L)
: TCollection_MapNode (ptr),
myMask (0),
myData (0) {}
inline TColStd_intMapNode (const Standard_Integer theValue,
TCollection_MapNode *& ptr)
: TCollection_MapNode (ptr),
myMask ((unsigned int) (theValue & MASK_HIGH)),
myData (1 << (theValue & MASK_LOW)) {}
inline TColStd_intMapNode (unsigned int theMask,
unsigned int theData,
TCollection_MapNode * ptr)
: TCollection_MapNode (ptr),
myMask (theMask),
myData (theData) {}
inline unsigned int Mask () const
{ return myMask; }
inline unsigned int Data () const
{ return myData; }
inline unsigned int& ChangeMask ()
{ return myMask; }
inline unsigned int& ChangeData ()
{ return myData; }
inline Standard_Integer Key () const
{ return Standard_Integer (myMask & MASK_HIGH); }
inline size_t NbValues () const
{ return size_t(myMask & MASK_LOW) + 1; }
inline Standard_Boolean HasValues () const
{ return (myData != 0); }
Standard_Integer HasValue (const Standard_Integer theValue) const
{ return (myData & (1 << (theValue & MASK_LOW))); }
Standard_Boolean AddValue (const Standard_Integer theValue);
Standard_Boolean DelValue (const Standard_Integer theValue);
/**
* Find the smallest non-zero bit under the given mask. Outputs the new mask
* that does not contain the detected bit.
*/
Standard_Integer FindNext (unsigned int& theMask) const;
/**
* Support of Map interface.
*/
inline Standard_Integer HashCode (const Standard_Integer theUpper) const
{
return ::HashCode (Standard_Integer(myMask >> 5), theUpper);
}
/**
* Support of Map interface.
*/
inline Standard_Boolean IsEqual (const Standard_Integer theOther) const
{
return ((myMask >> 5) == (unsigned)theOther);
}
/**
* Local friend function, used in TColStd_MapIteratorOfPackedMapOfInteger.
*/
friend Standard_Integer TColStd_intMapNode_findNext(const TColStd_intMapNode*,
unsigned int& );
/**
* Local friend function.
*/
friend Standard_Integer TColStd_intMapNode_findPrev(const TColStd_intMapNode*,
unsigned int& );
private:
unsigned int myMask;
unsigned int myData;
};
//=======================================================================
//function : TColStd_intMapNode::AddValue
//purpose :
//=======================================================================
Standard_Boolean TColStd_intMapNode::AddValue (const Standard_Integer theValue)
{
Standard_Boolean aResult (Standard_False);
const Standard_Integer aValInt = (1 << (theValue & MASK_LOW));
if ((myData & aValInt) == 0) {
myData ^= aValInt;
myMask++;
aResult = Standard_True;
}
return aResult;
}
//=======================================================================
//function : TColStd_intMapNode::DelValue
//purpose :
//=======================================================================
Standard_Boolean TColStd_intMapNode::DelValue (const Standard_Integer theValue)
{
Standard_Boolean aResult (Standard_False);
const Standard_Integer aValInt = (1 << (theValue & MASK_LOW));
if ((myData & aValInt) != 0) {
myData ^= aValInt;
myMask--;
aResult = Standard_True;
}
return aResult;
}
//=======================================================================
//function : TColStd_Population
//purpose : Compute the population (i.e., the number of non-zero bits) of
// the 32-bit word theData. The population is stored decremented
// as it is defined in TColStd_intMapNode.
//source : H.S.Warren, Hacker''s Delight, Addison-Wesley Inc. 2002, Ch.5.1
//=======================================================================
inline size_t TColStd_Population (unsigned int& theMask,
const unsigned int theData)
{
unsigned int aRes = theData - ((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);
}
//=======================================================================
//function : TColStd_intMapNode_findNext
//purpose : Find the smallest non-zero bit under the given mask. Outputs
// the new mask that does not contain the detected bit.
//=======================================================================
Standard_Integer TColStd_intMapNode_findNext (const TColStd_intMapNode* theNode,
unsigned int& theMask)
{
unsigned int val = theNode->myData & theMask;
int nZeros (0);
if (val == 0)
theMask = ~0U; // void, nothing to do
else{
unsigned int aMask = ~0U;
if ((val & 0x0000ffff) == 0) {
aMask = 0xffff0000;
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 nZeros + theNode->Key();
}
//=======================================================================
//function : TColStd_intMapNode_findPrev
//purpose : Find the highest non-zero bit under the given mask. Outputs
// the new mask that does not contain the detected bit.
//=======================================================================
Standard_Integer TColStd_intMapNode_findPrev (const TColStd_intMapNode* theNode,
unsigned int& theMask)
{
unsigned int val = theNode->myData & theMask;
int nZeros (0);
if (val == 0)
theMask = ~0U; // void, nothing to do
else {
unsigned int aMask = ~0U;
if ((val & 0xffff0000) == 0) {
aMask = 0x0000ffff;
nZeros = 16;
val <<= 16;
}
if ((val & 0xff000000) == 0) {
aMask >>= 8;
nZeros += 8;
val <<= 8;
}
if ((val & 0xf0000000) == 0) {
aMask >>= 4;
nZeros += 4;
val <<= 4;
}
if ((val & 0xc0000000) == 0) {
aMask >>= 2;
nZeros += 2;
val <<= 2;
}
if ((val & 0x80000000) == 0) {
aMask >>= 1;
nZeros ++;
}
theMask = (aMask >> 1);
}
return (31 - nZeros) + theNode->Key();
}
//=======================================================================
//function : Assign
//purpose :
//=======================================================================
TColStd_PackedMapOfInteger& TColStd_PackedMapOfInteger::Assign
(const TColStd_PackedMapOfInteger& theOther)
{
if (this != &theOther) {
Clear();
if (!theOther.IsEmpty()) {
ReSize (theOther.InternalExtent());
const Standard_Integer nBucketsSrc = theOther.NbBuckets();
const Standard_Integer nBuckets = NbBuckets();
const TColStd_intMapNode** aDataSrc =
(const TColStd_intMapNode**) theOther.myData1;
TColStd_intMapNode** aData = (TColStd_intMapNode**) myData1;
for (Standard_Integer i = 0; i <= nBucketsSrc; i++) {
const TColStd_intMapNode * p = aDataSrc[i];
while (p) {
const Standard_Integer aHashCode = p->HashCode(nBuckets);
aData[aHashCode] =
new TColStd_intMapNode (p->Mask(), p->Data(), aData[aHashCode]);
Increment();
p = reinterpret_cast <const TColStd_intMapNode*> (p->Next());
}
}
// TColStd_MapIteratorOfPackedMapOfInteger anIt (theOther);
// for (; anIt.More(); anIt.Next())
// Add (anIt.Key());
}
}
myExtent = theOther.myExtent;
return * this;
}
//=======================================================================
//function : ReSize
//purpose :
//=======================================================================
void TColStd_PackedMapOfInteger::ReSize (const Standard_Integer nbBuckets)
{
Standard_Integer newBuck;
Standard_Address newData1=NULL, dummy=NULL;
if (BeginResize (nbBuckets, newBuck, newData1, dummy))
{
if (myData1) {
TColStd_intMapNode** newdata =
reinterpret_cast <TColStd_intMapNode**> (newData1);
TColStd_intMapNode** olddata =
reinterpret_cast <TColStd_intMapNode**> (myData1);
TColStd_intMapNode * p;
Standard_Integer i,k;
for (i = 0; i <= NbBuckets(); i++) {
if (olddata[i]) {
p = olddata[i];
while (p) {
k = p->HashCode(newBuck);
TCollection_MapNode * q = p->Next();
p->Next() = newdata[k];
newdata[k] = p;
p = static_cast <TColStd_intMapNode*> (q);
}
}
}
}
EndResize (nbBuckets, newBuck, newData1, dummy);
}
}
//=======================================================================
//function : Clear
//purpose :
//=======================================================================
void TColStd_PackedMapOfInteger::Clear ()
{
if (!IsEmpty()) {
Standard_Integer i;
TColStd_intMapNode** data =
reinterpret_cast <TColStd_intMapNode**> (myData1);
TColStd_intMapNode * p;
for (i = 0; i <= NbBuckets(); i++) {
if (data[i]) {
p = data[i];
while (p) {
TCollection_MapNode * q = p->Next();
delete p;
p = static_cast <TColStd_intMapNode*> (q);
}
}
}
}
TCollection_BasicMap::Destroy();
myExtent = 0;
}
//=======================================================================
//function : Add
//purpose :
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::Add (const Standard_Integer aKey)
{
if (Resizable())
ReSize(InternalExtent());
Standard_Boolean aResult (Standard_False);
TColStd_intMapNode ** data =
reinterpret_cast <TColStd_intMapNode**> (myData1);
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
const Standard_Integer aHashCode = HashCode (aKeyInt, NbBuckets());
TCollection_MapNodePtr aBucketHead = data[aHashCode];
TColStd_intMapNode * p = static_cast<TColStd_intMapNode*> (aBucketHead);
while (p) {
if (p->IsEqual(aKeyInt)) {
aResult = p->AddValue (aKey);
// break;
goto finish; // goto saves us 4 CPU clocks or 4% performance
}
p = reinterpret_cast <TColStd_intMapNode*> (p->Next());
}
// if (!p) { // not needed, as long as we exit the loop by goto
data[aHashCode] = new TColStd_intMapNode(aKey, aBucketHead);
Increment();
aResult = Standard_True;
// }
finish:
if (aResult)
myExtent++;
return aResult;
}
//=======================================================================
//function : Contains
//purpose :
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::Contains
(const Standard_Integer aKey) const
{
Standard_Boolean aResult (Standard_False);
if (!IsEmpty()) {
TColStd_intMapNode** data = (TColStd_intMapNode**) myData1;
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
TColStd_intMapNode * p = data[HashCode (aKeyInt, NbBuckets())];
while (p) {
if (p->IsEqual(aKeyInt)) {
aResult = (p->HasValue (aKey) != 0);
break;
}
p = reinterpret_cast <TColStd_intMapNode*> (p->Next());
}
}
return aResult;
}
//=======================================================================
//function : Remove
//purpose :
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::Remove(const Standard_Integer aKey)
{
Standard_Boolean aResult (Standard_False);
if (!IsEmpty()) {
TColStd_intMapNode** data =
reinterpret_cast <TColStd_intMapNode**> (myData1);
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
TColStd_intMapNode*& aBucketHead = data[HashCode(aKeyInt, NbBuckets())];
TColStd_intMapNode* p = aBucketHead;
TColStd_intMapNode* q = 0L;
while (p) {
if (p->IsEqual(aKeyInt)) {
aResult = p->DelValue (aKey);
if (aResult) {
myExtent--;
if (p->HasValues() == Standard_False) {
Decrement();
if (q) q->Next() = p->Next();
else aBucketHead = reinterpret_cast<TColStd_intMapNode*>(p->Next());
delete p;
}
}
break;
}
q = p;
p = reinterpret_cast <TColStd_intMapNode*> (p->Next());
}
}
return aResult;
}
//=======================================================================
//function : GetMinimalMapped
//purpose : Query the minimal contained key value.
//=======================================================================
Standard_Integer TColStd_PackedMapOfInteger::GetMinimalMapped () const
{
Standard_Integer aResult (IntegerLast());
if (!IsEmpty()) {
const TCollection_MapNode** aData = (const TCollection_MapNode**) myData1;
const TColStd_intMapNode * pFoundNode = 0L;
for (Standard_Integer i = 0; i <= NbBuckets(); i++) {
for (const TCollection_MapNode * p = aData[i]; p != 0L; p = p->Next()) {
const Standard_Integer aKey =
reinterpret_cast <const TColStd_intMapNode *>(p)->Key();
if (aResult > aKey) {
aResult = aKey;
pFoundNode = reinterpret_cast<const TColStd_intMapNode *>(p);
}
}
}
if (pFoundNode) {
unsigned int aFullMask (0xffffffff);
aResult = TColStd_intMapNode_findNext (pFoundNode, aFullMask);
}
}
return aResult;
}
//=======================================================================
//function : GetMaximalMapped
//purpose : Query the maximal contained key value.
//=======================================================================
Standard_Integer TColStd_PackedMapOfInteger::GetMaximalMapped () const
{
Standard_Integer aResult (IntegerFirst());
if (!IsEmpty()) {
const TCollection_MapNode** aData = (const TCollection_MapNode**) myData1;
const TColStd_intMapNode * pFoundNode = 0L;
for (Standard_Integer i = 0; i <= NbBuckets(); i++) {
for (const TCollection_MapNode * p = aData[i]; p != 0L; p = p->Next()) {
const Standard_Integer aKey =
reinterpret_cast <const TColStd_intMapNode *>(p)->Key();
if (aResult < aKey) {
aResult = aKey;
pFoundNode = reinterpret_cast<const TColStd_intMapNode *>(p);
}
}
}
if (pFoundNode) {
unsigned int aFullMask (0xffffffff);
aResult = TColStd_intMapNode_findPrev (pFoundNode, aFullMask);
}
}
return aResult;
}
//=======================================================================
//function : Union
//purpose : Boolean operation OR between 2 maps
//=======================================================================
void TColStd_PackedMapOfInteger::Union (const TColStd_PackedMapOfInteger& theMap1,
const TColStd_PackedMapOfInteger& theMap2)
{
if (theMap1.IsEmpty()) // 0 | B == B
Assign (theMap2);
else if (theMap2.IsEmpty()) // A | 0 == A
Assign (theMap1);
else if (myData1 == theMap1.myData1)
Unite (theMap2);
else if (myData1 == theMap2.myData1)
Unite (theMap1);
else {
Standard_Integer i;
const TColStd_intMapNode** aData1 =
(const TColStd_intMapNode**) theMap1.myData1;
const TColStd_intMapNode** aData2 =
(const TColStd_intMapNode**) theMap2.myData1;
const Standard_Integer nBuckets1 = theMap1.NbBuckets();
const Standard_Integer nBuckets2 = theMap2.NbBuckets();
Clear();
TColStd_intMapNode** aData = (TColStd_intMapNode**) myData1;
// Iteration of the 1st map.
for (i = 0; i <= nBuckets1; i++) {
const TColStd_intMapNode * p1 = aData1[i];
while (p1 != 0L) {
// Find aKey - the base address of currently iterated block
const Standard_Integer aKey = p1->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
unsigned int aNewMask = p1->Mask();
unsigned int aNewData = p1->Data();
size_t nValues (p1->NbValues());
// Find the corresponding block in the 2nd map
const TColStd_intMapNode * p2 =
aData2 [HashCode (aKeyInt, nBuckets2)];
while (p2) {
if (p2->IsEqual(aKeyInt)) {
aNewData |= p2->Data();
nValues = TColStd_Population (aNewMask, aNewData);
break;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
// Store the block - result of operation
if (Resizable()) {
ReSize(InternalExtent());
aData = (TColStd_intMapNode**) myData1;
}
const Standard_Integer aHashCode = HashCode (aKeyInt, NbBuckets());
aData[aHashCode] = new TColStd_intMapNode (aNewMask, aNewData,
aData[aHashCode]);
Increment();
myExtent += nValues;
p1 = reinterpret_cast <const TColStd_intMapNode*> (p1->Next());
}
}
// Iteration of the 2nd map.
for (i = 0; i <= nBuckets2; i++) {
const TColStd_intMapNode * p2 = aData2[i];
while (p2 != 0L) {
// Find aKey - the base address of currently iterated block
const Standard_Integer aKey = p2->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
// Find the corresponding block in the 1st map
const TColStd_intMapNode * p1 =
aData1 [HashCode (aKeyInt, nBuckets1)];
while (p1) {
if (p1->IsEqual(aKeyInt))
break;
p1 = reinterpret_cast <const TColStd_intMapNode*> (p1->Next());
}
// Add the block from the 2nd map only in the case when the similar
// block has not been found in the 1st map
if (p1 == 0L) {
if (Resizable()) {
ReSize(InternalExtent());
aData = (TColStd_intMapNode**) myData1;
}
const Standard_Integer aHashCode = HashCode (aKeyInt, NbBuckets());
aData[aHashCode]= new TColStd_intMapNode (p2->Mask(), p2->Data(),
aData[aHashCode]);
Increment();
myExtent += p2->NbValues();
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
}
}
}
//=======================================================================
//function : Unite
//purpose : Boolean operation OR with the given map
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::Unite(const TColStd_PackedMapOfInteger& theMap)
{
if (theMap.IsEmpty() || myData1 == theMap.myData1) // A | 0 == A | A == A
return Standard_False;
else if ( IsEmpty() ) { // 0 | B == B
Assign ( theMap );
return Standard_True;
}
else {
size_t aNewExtent (myExtent);
TColStd_intMapNode** aData = (TColStd_intMapNode**) myData1;
const TColStd_intMapNode** aData2 =
(const TColStd_intMapNode**) theMap.myData1;
const Standard_Integer nBuckets2 = theMap.NbBuckets();
// Iteration of the 2nd map.
for (Standard_Integer i = 0; i <= nBuckets2; i++) {
const TColStd_intMapNode * p2 = aData2[i];
while (p2 != 0L) {
// Find aKey - the base address of currently iterated block of integers
const Standard_Integer aKey = p2->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
// Find the corresponding block in the 1st (this) map
Standard_Integer aHashCode = HashCode (aKeyInt, NbBuckets());
TColStd_intMapNode * p1 = aData[aHashCode];
while (p1) {
if (p1->IsEqual(aKeyInt)) {
const size_t anOldPop = p1->NbValues();
unsigned int newData = p1->Data() | p2->Data();
if ( newData != p1->Data() ) {
p1->ChangeData() = newData;
aNewExtent = aNewExtent - anOldPop +
TColStd_Population (p1->ChangeMask(), newData);
}
break;
}
p1 = reinterpret_cast <TColStd_intMapNode*> (p1->Next());
}
// If the block is not found in the 1st map, add it to the 1st map
if (p1 == 0L) {
if (Resizable()) {
ReSize(InternalExtent());
aData = (TColStd_intMapNode**) myData1;
aHashCode = HashCode (aKeyInt, NbBuckets());
}
aData[aHashCode] = new TColStd_intMapNode (p2->Mask(), p2->Data(),
aData[aHashCode]);
Increment();
aNewExtent += p2->NbValues();
}
p2 = reinterpret_cast <TColStd_intMapNode*> (p2->Next());
}
}
Standard_Boolean isChanged = ( myExtent != aNewExtent );
myExtent = aNewExtent;
return isChanged;
}
}
//=======================================================================
//function : Intersection
//purpose : Boolean operation AND between 2 maps
//=======================================================================
void TColStd_PackedMapOfInteger::Intersection
(const TColStd_PackedMapOfInteger& theMap1,
const TColStd_PackedMapOfInteger& theMap2)
{
if (theMap1.IsEmpty() || theMap2.IsEmpty()) // A & 0 == 0 & B == 0
Clear();
else if (myData1 == theMap1.myData1)
Intersect (theMap2);
else if (myData1 == theMap2.myData1)
Intersect (theMap1);
else {
const TColStd_intMapNode** aData1, ** aData2;
Standard_Integer nBuckets1, nBuckets2;
if (theMap1.Extent() < theMap2.Extent()) {
aData1 = (const TColStd_intMapNode**) theMap1.myData1;
aData2 = (const TColStd_intMapNode**) theMap2.myData1;
nBuckets1 = theMap1.NbBuckets();
nBuckets2 = theMap2.NbBuckets();
}
else {
aData1 = (const TColStd_intMapNode**) theMap2.myData1;
aData2 = (const TColStd_intMapNode**) theMap1.myData1;
nBuckets1 = theMap2.NbBuckets();
nBuckets2 = theMap1.NbBuckets();
}
Clear();
TColStd_intMapNode** aData = (TColStd_intMapNode**) myData1;
// Iteration of the 1st map.
for (Standard_Integer i = 0; i <= nBuckets1; i++) {
const TColStd_intMapNode * p1 = aData1[i];
while (p1 != 0L) {
// Find aKey - the base address of currently iterated block
const Standard_Integer aKey = p1->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
// Find the corresponding block in the 2nd map
const TColStd_intMapNode * p2 =
aData2 [HashCode (aKeyInt, nBuckets2)];
while (p2) {
if (p2->IsEqual(aKeyInt)) {
const unsigned int aNewData = p1->Data() & p2->Data();
// Store the block - result of operation
if (aNewData) {
if (Resizable()) {
ReSize(InternalExtent());
aData = (TColStd_intMapNode**) myData1;
}
const Standard_Integer aHashCode = HashCode (aKeyInt,
NbBuckets());
unsigned int aNewMask = p1->Mask();
myExtent += TColStd_Population (aNewMask, aNewData);
aData[aHashCode]= new TColStd_intMapNode(aNewMask, aNewData,
aData[aHashCode]);
Increment();
}
break;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
p1 = reinterpret_cast <const TColStd_intMapNode*> (p1->Next());
}
}
}
}
//=======================================================================
//function : Intersect
//purpose : Boolean operation AND with the given map
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::Intersect
(const TColStd_PackedMapOfInteger& theMap)
{
if ( IsEmpty() ) // 0 & B == 0
return Standard_False;
else if (theMap.IsEmpty()) { // A & 0 == 0
Clear();
return Standard_True;
}
else if (myData1 == theMap.myData1) // A & A == A
return Standard_False;
else {
size_t aNewExtent (0);
TColStd_intMapNode** aData = (TColStd_intMapNode**) myData1;
const TColStd_intMapNode** aData2 =
(const TColStd_intMapNode**) theMap.myData1;
const Standard_Integer nBuckets2 = theMap.NbBuckets();
// Iteration of this map.
for (Standard_Integer i = 0; i <= NbBuckets(); i++) {
TColStd_intMapNode * q = 0L;
TColStd_intMapNode * p1 = aData[i];
while (p1 != 0L) {
// Find aKey - the base address of currently iterated block of integers
const Standard_Integer aKey = p1->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
// Find the corresponding block in the 2nd map
const TColStd_intMapNode * p2 =
aData2 [HashCode (aKeyInt, nBuckets2)];
while (p2) {
if (p2->IsEqual(aKeyInt)) {
const unsigned int aNewData = p1->Data() & p2->Data();
// Store the block - result of operation
if (aNewData == 0)
p2 = 0L; // no match - the block has to be removed
else
{
if ( aNewData != p1->Data() )
p1->ChangeData() = aNewData;
aNewExtent += TColStd_Population (p1->ChangeMask(), aNewData);
}
break;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
TColStd_intMapNode* pNext =
reinterpret_cast <TColStd_intMapNode*> (p1->Next());
// If p2!=NULL, then the map node is kept and we move to the next one
// Otherwise we should remove the current node
if (p2)
q = p1;
else {
Decrement();
if (q) q->Next() = pNext;
else aData[i] = pNext;
delete p1;
}
p1 = pNext;
}
}
Standard_Boolean isChanged = ( myExtent != aNewExtent );
myExtent = aNewExtent;
return isChanged;
}
}
//=======================================================================
//function : Subtraction
//purpose : Boolean operation SUBTRACT between two maps
//=======================================================================
void TColStd_PackedMapOfInteger::Subtraction
(const TColStd_PackedMapOfInteger& theMap1,
const TColStd_PackedMapOfInteger& theMap2)
{
if (theMap1.IsEmpty() || theMap2.myData1 == theMap1.myData1) // 0 \ A == A \ A == 0
Clear();
else if (theMap2.IsEmpty()) // A \ 0 == A
Assign (theMap1);
else if (myData1 == theMap1.myData1)
Subtract (theMap2);
else if (myData1 == theMap2.myData1) {
TColStd_PackedMapOfInteger aMap;
aMap.Subtraction ( theMap1, theMap2 );
Assign ( aMap );
}
else {
const TColStd_intMapNode** aData1 =
(const TColStd_intMapNode**) theMap1.myData1;
const TColStd_intMapNode** aData2 =
(const TColStd_intMapNode**) theMap2.myData1;
const Standard_Integer nBuckets1 = theMap1.NbBuckets();
const Standard_Integer nBuckets2 = theMap2.NbBuckets();
Clear();
TColStd_intMapNode** aData = (TColStd_intMapNode**) myData1;
// Iteration of the 1st map.
for (Standard_Integer i = 0; i <= nBuckets1; i++) {
const TColStd_intMapNode * p1 = aData1[i];
while (p1 != 0L) {
// Find aKey - the base address of currently iterated block of integers
const Standard_Integer aKey = p1->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
unsigned int aNewMask = p1->Mask();
unsigned int aNewData = p1->Data();
size_t nValues (p1->NbValues());
// Find the corresponding block in the 2nd map
const TColStd_intMapNode * p2 =
aData2 [HashCode (aKeyInt, nBuckets2)];
while (p2) {
if (p2->IsEqual(aKeyInt)) {
aNewData &= ~p2->Data();
nValues = TColStd_Population (aNewMask, aNewData);
break;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
// Store the block - result of operation
if (aNewData) {
if (Resizable()) {
ReSize(InternalExtent());
aData = (TColStd_intMapNode**) myData1;
}
const Standard_Integer aHashCode = HashCode (aKeyInt, NbBuckets());
aData[aHashCode]= new TColStd_intMapNode (aNewMask, aNewData,
aData[aHashCode]);
Increment();
myExtent += nValues;
}
p1 = reinterpret_cast <const TColStd_intMapNode*> (p1->Next());
}
}
}
}
//=======================================================================
//function : Subtract
//purpose : Boolean operation SUBTRACT with the given map
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::Subtract
(const TColStd_PackedMapOfInteger& theMap)
{
if ( IsEmpty() || theMap.IsEmpty() ) // 0 \ B == 0; A \ 0 == A
return Standard_False;
else if (myData1 == theMap.myData1) { // A \ A == 0
Clear();
return Standard_True;
}
else {
size_t aNewExtent (0);
TColStd_intMapNode** aData = (TColStd_intMapNode**) myData1;
const TColStd_intMapNode** aData2 =
(const TColStd_intMapNode**) theMap.myData1;
const Standard_Integer nBuckets2 = theMap.NbBuckets();
// Iteration of this map.
for (Standard_Integer i = 0; i <= NbBuckets(); i++) {
TColStd_intMapNode * q = 0L;
TColStd_intMapNode * p1 = aData[i];
while (p1 != 0L) {
// Find aKey - the base address of currently iterated block of integers
const Standard_Integer aKey = p1->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
TColStd_intMapNode* pNext =
reinterpret_cast <TColStd_intMapNode*> (p1->Next());
// Find the corresponding block in the 2nd map
const TColStd_intMapNode * p2 =
aData2 [HashCode (aKeyInt, nBuckets2)];
while (p2) {
if (p2->IsEqual(aKeyInt)) {
const unsigned int aNewData = p1->Data() & ~p2->Data();
// Store the block - result of operation
if (aNewData == 0) {
// no match - the block has to be removed
Decrement();
if (q) q->Next() = pNext;
else aData[i] = pNext;
delete p1;
}
else if ( aNewData != p1->Data() ) {
p1->ChangeData() = aNewData;
aNewExtent += TColStd_Population (p1->ChangeMask(), aNewData);
q = p1;
}
else {
aNewExtent += p1->NbValues();
q = p1;
}
break;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
if (p2 == 0L) {
aNewExtent += p1->NbValues();
q = p1;
}
p1 = pNext;
}
}
Standard_Boolean isChanged = ( myExtent != aNewExtent );
myExtent = aNewExtent;
return isChanged;
}
}
//=======================================================================
//function : Difference
//purpose : Boolean operation XOR
//=======================================================================
void TColStd_PackedMapOfInteger::Difference (const TColStd_PackedMapOfInteger& theMap1,
const TColStd_PackedMapOfInteger& theMap2)
{
if (theMap1.IsEmpty()) // 0 ^ B == B
Assign (theMap2);
else if (theMap2.IsEmpty()) // A ^ 0 == A
Assign (theMap1);
else if (myData1 == theMap1.myData1)
Differ(theMap2);
else if (myData1 == theMap2.myData1)
Differ(theMap1);
else {
Standard_Integer i;
const TColStd_intMapNode** aData1 =
(const TColStd_intMapNode**) theMap1.myData1;
const TColStd_intMapNode** aData2 =
(const TColStd_intMapNode**) theMap2.myData1;
const Standard_Integer nBuckets1 = theMap1.NbBuckets();
const Standard_Integer nBuckets2 = theMap2.NbBuckets();
Clear();
TColStd_intMapNode** aData = (TColStd_intMapNode**) myData1;
// Iteration of the 1st map.
for (i = 0; i <= nBuckets1; i++) {
const TColStd_intMapNode * p1 = aData1[i];
while (p1 != 0L) {
// Find aKey - the base address of currently iterated block of integers
const Standard_Integer aKey = p1->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
unsigned int aNewMask = p1->Mask();
unsigned int aNewData = p1->Data();
size_t nValues (p1->NbValues());
// Find the corresponding block in the 2nd map
const TColStd_intMapNode * p2 =
aData2 [HashCode (aKeyInt, nBuckets2)];
while (p2) {
if (p2->IsEqual(aKeyInt)) {
aNewData ^= p2->Data();
nValues = TColStd_Population (aNewMask, aNewData);
break;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
// Store the block - result of operation
if (aNewData) {
if (Resizable()) {
ReSize(InternalExtent());
aData = (TColStd_intMapNode**) myData1;
}
const Standard_Integer aHashCode = HashCode (aKeyInt, NbBuckets());
aData[aHashCode]= new TColStd_intMapNode (aNewMask, aNewData,
aData[aHashCode]);
Increment();
myExtent += nValues;
}
p1 = reinterpret_cast <const TColStd_intMapNode*> (p1->Next());
}
}
// Iteration of the 2nd map.
for (i = 0; i <= nBuckets2; i++) {
const TColStd_intMapNode * p2 = aData2[i];
while (p2 != 0L) {
// Find aKey - the base address of currently iterated block
const Standard_Integer aKey = p2->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
// Find the corresponding block in the 1st map
const TColStd_intMapNode * p1 =
aData1 [HashCode (aKeyInt, nBuckets1)];
while (p1) {
if (p1->IsEqual(aKeyInt))
break;
p1 = reinterpret_cast <const TColStd_intMapNode*> (p1->Next());
}
// Add the block from the 2nd map only in the case when the similar
// block has not been found in the 1st map
if (p1 == 0L) {
if (Resizable()) {
ReSize(InternalExtent());
aData = (TColStd_intMapNode**) myData1;
}
const Standard_Integer aHashCode = HashCode (aKeyInt, NbBuckets());
aData[aHashCode]= new TColStd_intMapNode (p2->Mask(), p2->Data(),
aData[aHashCode]);
Increment();
myExtent += p2->NbValues();
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
}
}
}
//=======================================================================
//function : Differ
//purpose : Boolean operation XOR
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::Differ(const TColStd_PackedMapOfInteger& theMap)
{
if (theMap.IsEmpty()) // A ^ 0 = A
return Standard_False;
else if (IsEmpty()) { // 0 ^ B = B
Assign ( theMap );
return Standard_True;
}
else if( myData1 == theMap.myData1) { // A ^ A == 0
Clear();
return Standard_True;
}
else {
size_t aNewExtent (0);
TColStd_intMapNode** aData1 = (TColStd_intMapNode**) myData1;
const TColStd_intMapNode** aData2 =
(const TColStd_intMapNode**) theMap.myData1;
const Standard_Integer nBuckets2 = theMap.NbBuckets();
Standard_Boolean isChanged = Standard_False;
Standard_Integer i = 0;
// Iteration by other map
for ( ; i <= nBuckets2; i++) {
TColStd_intMapNode * q = 0L;
const TColStd_intMapNode * p2 = aData2[i];
while (p2 != 0L) {
// Find aKey - the base address of currently iterated block
const Standard_Integer aKey = p2->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
// Find the corresponding block in the 1st map
TColStd_intMapNode * p1 =
aData1[HashCode (aKeyInt, NbBuckets())];
TColStd_intMapNode* pNext =
reinterpret_cast <TColStd_intMapNode*> (p1->Next());
while (p1) {
if (p1->IsEqual(aKeyInt)) {
const unsigned int aNewData = p1->Data() ^ p2->Data();
// Store the block - result of operation
if (aNewData == 0) {
// no match - the block has to be removed
Decrement();
if (q) q->Next() = pNext;
else aData1[i] = pNext;
delete p1;
}
else if ( aNewData != p1->Data() ) {
p1->ChangeData() = aNewData;
isChanged = Standard_True;
aNewExtent += TColStd_Population (p1->ChangeMask(), aNewData);
q = p1;
}
break;
}
p1 = pNext;
}
// Add the block from the 2nd map only in the case when the similar
// block has not been found in the 1st map
TColStd_intMapNode** aData = NULL;
if (p1 == 0L) {
if (Resizable()) {
ReSize(InternalExtent());
aData = (TColStd_intMapNode**) myData1;
}
const Standard_Integer aHashCode = HashCode (aKeyInt, NbBuckets());
aData[aHashCode]= new TColStd_intMapNode (p2->Mask(), p2->Data(),
aData[aHashCode]);
Increment();
aNewExtent += p2->NbValues();
isChanged = Standard_True;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
}
myExtent = aNewExtent;
return isChanged;
}
}
//=======================================================================
//function : IsEqual
//purpose : Boolean operation returns true if this map is equal to the other map
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::IsEqual(const TColStd_PackedMapOfInteger& theMap) const
{
if (IsEmpty() && theMap.IsEmpty())
return Standard_True;
else if ( Extent() != theMap.Extent() )
return Standard_False;
else {
const TColStd_intMapNode** aData1 = (const TColStd_intMapNode**) myData1;
const TColStd_intMapNode** aData2 = (const TColStd_intMapNode**) theMap.myData1;
const Standard_Integer nBuckets2 = theMap.NbBuckets();
if(aData1 == aData2)
return Standard_True;
Standard_Integer i = 0;
// Iteration of this map.
for (; i <= NbBuckets(); i++) {
const TColStd_intMapNode * p1 = aData1[i];
while (p1 != 0L) {
// Find aKey - the base address of currently iterated block of integers
const Standard_Integer aKey = p1->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
TColStd_intMapNode* pNext =
reinterpret_cast <TColStd_intMapNode*> (p1->Next());
// Find the corresponding block in the 2nd map
const TColStd_intMapNode * p2 =
aData2 [HashCode (aKeyInt, nBuckets2)];
while (p2) {
if ( p2->IsEqual(aKeyInt) ) {
if ( p1->Data() != p2->Data() )
return Standard_False;
break;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
// if the same block not found, maps are different
if (p2 == 0L)
return Standard_False;
p1 = pNext;
}
}
return Standard_True;
}
}
//=======================================================================
//function : IsSubset
//purpose : Boolean operation returns true if this map if subset of other map
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::IsSubset (const TColStd_PackedMapOfInteger& theMap) const
{
if ( IsEmpty() ) // 0 <= A
return Standard_True;
else if ( theMap.IsEmpty() ) // ! ( A <= 0 )
return Standard_False;
else if ( Extent() > theMap.Extent() )
return Standard_False;
else {
const TColStd_intMapNode** aData1 = (const TColStd_intMapNode**) myData1;
const TColStd_intMapNode** aData2 = (const TColStd_intMapNode**) theMap.myData1;
if(aData1 == aData2)
return Standard_True;
const Standard_Integer nBuckets2 = theMap.NbBuckets();
Standard_Integer i = 0;
// Iteration of this map.
for (; i <= NbBuckets(); i++) {
const TColStd_intMapNode * p1 = aData1[i];
while (p1 != 0L) {
// Find aKey - the base address of currently iterated block of integers
const Standard_Integer aKey = p1->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
TColStd_intMapNode* pNext =
reinterpret_cast <TColStd_intMapNode*> (p1->Next());
// Find the corresponding block in the 2nd map
const TColStd_intMapNode * p2 =
aData2 [HashCode (aKeyInt, nBuckets2)];
if (!p2)
return Standard_False;
while (p2) {
if ( p2->IsEqual(aKeyInt) ) {
if ( p1->Data() & ~p2->Data() ) // at least one bit set in p1 is not set in p2
return Standard_False;
break;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
p1 = pNext;
}
}
return Standard_True;
}
}
//=======================================================================
//function : HasIntersection
//purpose : Boolean operation returns true if this map intersects with other map
//=======================================================================
Standard_Boolean TColStd_PackedMapOfInteger::HasIntersection (const TColStd_PackedMapOfInteger& theMap) const
{
if (IsEmpty() || theMap.IsEmpty()) // A * 0 == 0 * B == 0
return Standard_False;
else {
const TColStd_intMapNode** aData1 = (const TColStd_intMapNode**) myData1;
const TColStd_intMapNode** aData2 = (const TColStd_intMapNode**) theMap.myData1;
const Standard_Integer nBuckets2 = theMap.NbBuckets();
if(aData1 == aData2)
return Standard_True;
Standard_Integer i = 0;
// Iteration of this map.
for (; i <= NbBuckets(); i++) {
const TColStd_intMapNode * p1 = aData1[i];
while (p1 != 0L) {
// Find aKey - the base address of currently iterated block of integers
const Standard_Integer aKey = p1->Key();
const Standard_Integer aKeyInt = (unsigned)aKey >> 5;
TColStd_intMapNode* pNext =
reinterpret_cast <TColStd_intMapNode*> (p1->Next());
// Find the corresponding block in the 2nd map
const TColStd_intMapNode * p2 =
aData2 [HashCode (aKeyInt, nBuckets2)];
while (p2) {
if (p2->IsEqual(aKeyInt)) {
if ( p1->Data() & p2->Data() )
return Standard_True;
break;
}
p2 = reinterpret_cast <const TColStd_intMapNode*> (p2->Next());
}
p1 = pNext;
}
}
return Standard_False;
}
}