mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-09 18:50:54 +03:00
1193 lines
37 KiB
C++
1193 lines
37 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 <NCollection_Array1.hxx>
|
|
#include <TCollection.hxx>
|
|
#include <Standard_Type.hxx>
|
|
|
|
//=======================================================================
|
|
//function : TColStd_intMapNode_findNext
|
|
//purpose :
|
|
//=======================================================================
|
|
Standard_Integer TColStd_PackedMapOfInteger::TColStd_intMapNode_findNext (const TColStd_intMapNode* theNode,
|
|
unsigned int& theMask)
|
|
{
|
|
const TColStd_intMapNode* aNode = reinterpret_cast<const TColStd_intMapNode*> (theNode);
|
|
unsigned int val = aNode->Data() & 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 + aNode->Key();
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : TColStd_intMapNode_findPrev
|
|
//purpose :
|
|
//=======================================================================
|
|
Standard_Integer TColStd_PackedMapOfInteger::TColStd_intMapNode_findPrev (const TColStd_intMapNode* theNode,
|
|
unsigned int& theMask)
|
|
{
|
|
const TColStd_intMapNode* aNode = reinterpret_cast<const TColStd_intMapNode*> (theNode);
|
|
unsigned int val = aNode->Data() & 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) + aNode->Key();
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Assign
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
TColStd_PackedMapOfInteger& TColStd_PackedMapOfInteger::Assign
|
|
(const TColStd_PackedMapOfInteger& theOther)
|
|
{
|
|
if (this != &theOther) {
|
|
Clear();
|
|
if (!theOther.IsEmpty()) {
|
|
ReSize (theOther.myNbPackedMapNodes);
|
|
const Standard_Integer nBucketsSrc = theOther.myNbBuckets;
|
|
const Standard_Integer nBuckets = myNbBuckets;
|
|
for (Standard_Integer i = 0; i <= nBucketsSrc; i++)
|
|
{
|
|
for (const TColStd_intMapNode* p = theOther.myData1[i]; p != NULL; )
|
|
{
|
|
const Standard_Integer aHashCode = p->HashCode(nBuckets);
|
|
myData1[aHashCode] = new TColStd_intMapNode (p->Mask(), p->Data(), myData1[aHashCode]);
|
|
++myNbPackedMapNodes;
|
|
p = 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 theNbBuckets)
|
|
{
|
|
Standard_Integer aNewBuck = TCollection::NextPrimeForMap (theNbBuckets);
|
|
if (aNewBuck <= myNbBuckets)
|
|
{
|
|
if (!IsEmpty())
|
|
{
|
|
return;
|
|
}
|
|
aNewBuck = myNbBuckets;
|
|
}
|
|
|
|
TColStd_intMapNode** aNewData = (TColStd_intMapNode** )Standard::Allocate ((aNewBuck + 1) * sizeof(TColStd_intMapNode*));
|
|
memset (aNewData, 0, (aNewBuck + 1) * sizeof(TColStd_intMapNode*));
|
|
if (myData1 != NULL)
|
|
{
|
|
TColStd_intMapNode** anOldData = myData1;
|
|
for (Standard_Integer i = 0; i <= myNbBuckets; ++i)
|
|
{
|
|
for (TColStd_intMapNode* p = anOldData[i]; p != NULL; )
|
|
{
|
|
Standard_Integer k = p->HashCode (aNewBuck);
|
|
TColStd_intMapNode* q = p->Next();
|
|
p->SetNext (aNewData[k]);
|
|
aNewData[k] = p;
|
|
p = q;
|
|
}
|
|
}
|
|
}
|
|
|
|
Standard::Free (myData1);
|
|
myNbBuckets = aNewBuck;
|
|
myData1 = aNewData;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Clear
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void TColStd_PackedMapOfInteger::Clear ()
|
|
{
|
|
if (!IsEmpty())
|
|
{
|
|
for (Standard_Integer aBucketIter = 0; aBucketIter <= myNbBuckets; ++aBucketIter)
|
|
{
|
|
if (myData1[aBucketIter])
|
|
{
|
|
for (TColStd_intMapNode* aSubNodeIter = myData1[aBucketIter]; aSubNodeIter != NULL; )
|
|
{
|
|
TColStd_intMapNode* q = aSubNodeIter->Next();
|
|
delete aSubNodeIter;
|
|
aSubNodeIter = q;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
myNbPackedMapNodes = 0;
|
|
Standard::Free (myData1);
|
|
myData1 = NULL;
|
|
myExtent = 0;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Add
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
Standard_Boolean TColStd_PackedMapOfInteger::Add (const Standard_Integer aKey)
|
|
{
|
|
if (Resizable())
|
|
{
|
|
ReSize (myNbPackedMapNodes);
|
|
}
|
|
|
|
const Standard_Integer aKeyInt = packedKeyIndex (aKey);
|
|
const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
TColStd_intMapNode* aBucketHead = myData1[aHashCode];
|
|
for (TColStd_intMapNode* p = aBucketHead; p != NULL; p = p->Next())
|
|
{
|
|
if (p->IsEqual(aKeyInt))
|
|
{
|
|
if (p->AddValue (aKey))
|
|
{
|
|
++myExtent;
|
|
return Standard_True;
|
|
}
|
|
return Standard_False;
|
|
}
|
|
}
|
|
|
|
myData1[aHashCode] = new TColStd_intMapNode (aKey, aBucketHead);
|
|
++myNbPackedMapNodes;
|
|
++myExtent;
|
|
return Standard_True;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Contains
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
Standard_Boolean TColStd_PackedMapOfInteger::Contains
|
|
(const Standard_Integer aKey) const
|
|
{
|
|
if (IsEmpty())
|
|
{
|
|
return Standard_False;
|
|
}
|
|
|
|
Standard_Boolean aResult = Standard_False;
|
|
const Standard_Integer aKeyInt = packedKeyIndex (aKey);
|
|
for (TColStd_intMapNode* p = myData1[HashCode (aKeyInt, myNbBuckets)]; p != NULL; )
|
|
{
|
|
if (p->IsEqual(aKeyInt))
|
|
{
|
|
aResult = (p->HasValue (aKey) != 0);
|
|
break;
|
|
}
|
|
p = p->Next();
|
|
}
|
|
return aResult;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Remove
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
Standard_Boolean TColStd_PackedMapOfInteger::Remove(const Standard_Integer aKey)
|
|
{
|
|
if (IsEmpty())
|
|
{
|
|
return Standard_False;
|
|
}
|
|
|
|
Standard_Boolean aResult (Standard_False);
|
|
const Standard_Integer aKeyInt = packedKeyIndex (aKey);
|
|
TColStd_intMapNode*& aBucketHead = myData1[HashCode(aKeyInt, myNbBuckets)];
|
|
TColStd_intMapNode* p = aBucketHead;
|
|
TColStd_intMapNode* q = 0L;
|
|
while (p)
|
|
{
|
|
if (p->IsEqual(aKeyInt))
|
|
{
|
|
aResult = p->DelValue (aKey);
|
|
if (aResult)
|
|
{
|
|
--myExtent;
|
|
if (!p->HasValues())
|
|
{
|
|
--myNbPackedMapNodes;
|
|
if (q != NULL)
|
|
{
|
|
q->SetNext (p->Next());
|
|
}
|
|
else
|
|
{
|
|
aBucketHead = p->Next();
|
|
}
|
|
delete p;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
q = p;
|
|
p = p->Next();
|
|
}
|
|
return aResult;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetMinimalMapped
|
|
//purpose : Query the minimal contained key value.
|
|
//=======================================================================
|
|
|
|
Standard_Integer TColStd_PackedMapOfInteger::GetMinimalMapped () const
|
|
{
|
|
if (IsEmpty())
|
|
{
|
|
return IntegerLast();
|
|
}
|
|
|
|
Standard_Integer aResult (IntegerLast());
|
|
const TColStd_intMapNode* pFoundNode = 0L;
|
|
for (Standard_Integer i = 0; i <= myNbBuckets; i++)
|
|
{
|
|
for (const TColStd_intMapNode* p = myData1[i]; p != 0L; p = p->Next())
|
|
{
|
|
const Standard_Integer aKey = p->Key();
|
|
if (aResult > aKey)
|
|
{
|
|
aResult = aKey;
|
|
pFoundNode = 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
|
|
{
|
|
if (IsEmpty())
|
|
{
|
|
return IntegerFirst();
|
|
}
|
|
|
|
Standard_Integer aResult (IntegerFirst());
|
|
const TColStd_intMapNode* pFoundNode = 0L;
|
|
for (Standard_Integer i = 0; i <= myNbBuckets; i++)
|
|
{
|
|
for (const TColStd_intMapNode* p = myData1[i]; p != 0L; p = p->Next())
|
|
{
|
|
const Standard_Integer aKey = p->Key();
|
|
if (aResult < aKey)
|
|
{
|
|
aResult = aKey;
|
|
pFoundNode = 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 {
|
|
const Standard_Integer nBuckets1 = theMap1.myNbBuckets;
|
|
const Standard_Integer nBuckets2 = theMap2.myNbBuckets;
|
|
Clear();
|
|
// Iteration of the 1st map.
|
|
for (Standard_Integer i = 0; i <= nBuckets1; i++) {
|
|
const TColStd_intMapNode* p1 = theMap1.myData1[i];
|
|
while (p1 != 0L) {
|
|
// Find aKey - the base address of currently iterated block
|
|
const Standard_Integer aKey = p1->Key();
|
|
const Standard_Integer aKeyInt = packedKeyIndex (aKey);
|
|
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 = theMap2.myData1[HashCode (aKeyInt, nBuckets2)];
|
|
while (p2) {
|
|
if (p2->IsEqual(aKeyInt)) {
|
|
aNewData |= p2->Data();
|
|
nValues = TColStd_Population (aNewMask, aNewData);
|
|
break;
|
|
}
|
|
p2 = p2->Next();
|
|
}
|
|
// Store the block - result of operation
|
|
if (Resizable()) {
|
|
ReSize (myNbPackedMapNodes);
|
|
}
|
|
const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
myData1[aHashCode] = new TColStd_intMapNode (aNewMask, aNewData,
|
|
myData1[aHashCode]);
|
|
++myNbPackedMapNodes;
|
|
myExtent += nValues;
|
|
p1 = p1->Next();
|
|
}
|
|
}
|
|
// Iteration of the 2nd map.
|
|
for (Standard_Integer i = 0; i <= nBuckets2; i++)
|
|
{
|
|
const TColStd_intMapNode* p2 = theMap2.myData1[i];
|
|
while (p2 != 0L)
|
|
{
|
|
// Find aKey - the base address of currently iterated block
|
|
const Standard_Integer aKey = p2->Key();
|
|
const Standard_Integer aKeyInt = packedKeyIndex (aKey);
|
|
// Find the corresponding block in the 1st map
|
|
const TColStd_intMapNode* p1 = theMap1.myData1[HashCode (aKeyInt, nBuckets1)];
|
|
while (p1)
|
|
{
|
|
if (p1->IsEqual(aKeyInt))
|
|
break;
|
|
p1 = 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 (myNbPackedMapNodes);
|
|
}
|
|
const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
myData1[aHashCode]= new TColStd_intMapNode (p2->Mask(), p2->Data(),
|
|
myData1[aHashCode]);
|
|
++myNbPackedMapNodes;
|
|
myExtent += p2->NbValues();
|
|
}
|
|
p2 = 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;
|
|
}
|
|
|
|
size_t aNewExtent (myExtent);
|
|
const Standard_Integer nBuckets2 = theMap.myNbBuckets;
|
|
|
|
// Iteration of the 2nd map.
|
|
for (Standard_Integer i = 0; i <= nBuckets2; i++)
|
|
{
|
|
const TColStd_intMapNode* p2 = theMap.myData1[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 = packedKeyIndex (aKey);
|
|
// Find the corresponding block in the 1st (this) map
|
|
Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
TColStd_intMapNode* p1 = myData1[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 = p1->Next();
|
|
}
|
|
// If the block is not found in the 1st map, add it to the 1st map
|
|
if (p1 == 0L)
|
|
{
|
|
if (Resizable())
|
|
{
|
|
ReSize (myNbPackedMapNodes);
|
|
aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
}
|
|
myData1[aHashCode] = new TColStd_intMapNode (p2->Mask(), p2->Data(),
|
|
myData1[aHashCode]);
|
|
++myNbPackedMapNodes;
|
|
aNewExtent += p2->NbValues();
|
|
}
|
|
p2 = 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* const* aData1;
|
|
const TColStd_intMapNode* const* aData2;
|
|
Standard_Integer nBuckets1, nBuckets2;
|
|
if (theMap1.Extent() < theMap2.Extent())
|
|
{
|
|
aData1 = theMap1.myData1;
|
|
aData2 = theMap2.myData1;
|
|
nBuckets1 = theMap1.myNbBuckets;
|
|
nBuckets2 = theMap2.myNbBuckets;
|
|
}
|
|
else
|
|
{
|
|
aData1 = theMap2.myData1;
|
|
aData2 = theMap1.myData1;
|
|
nBuckets1 = theMap2.myNbBuckets;
|
|
nBuckets2 = theMap1.myNbBuckets;
|
|
}
|
|
Clear();
|
|
|
|
// 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 = packedKeyIndex (aKey);
|
|
// 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 (myNbPackedMapNodes);
|
|
}
|
|
const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
unsigned int aNewMask = p1->Mask();
|
|
myExtent += TColStd_Population (aNewMask, aNewData);
|
|
myData1[aHashCode]= new TColStd_intMapNode(aNewMask, aNewData,
|
|
myData1[aHashCode]);
|
|
++myNbPackedMapNodes;
|
|
}
|
|
break;
|
|
}
|
|
p2 = p2->Next();
|
|
}
|
|
p1 = 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;
|
|
|
|
size_t aNewExtent (0);
|
|
const Standard_Integer nBuckets2 = theMap.myNbBuckets;
|
|
|
|
// Iteration of this map.
|
|
for (Standard_Integer i = 0; i <= myNbBuckets; i++)
|
|
{
|
|
TColStd_intMapNode* q = 0L;
|
|
TColStd_intMapNode* p1 = myData1[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 = packedKeyIndex (aKey);
|
|
// Find the corresponding block in the 2nd map
|
|
const TColStd_intMapNode* p2 = theMap.myData1[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 = p2->Next();
|
|
}
|
|
TColStd_intMapNode* pNext = 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
|
|
{
|
|
--myNbPackedMapNodes;
|
|
if (q) q->SetNext (pNext);
|
|
else myData1[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 Standard_Integer nBuckets1 = theMap1.myNbBuckets;
|
|
const Standard_Integer nBuckets2 = theMap2.myNbBuckets;
|
|
Clear();
|
|
|
|
// Iteration of the 1st map.
|
|
for (Standard_Integer i = 0; i <= nBuckets1; i++)
|
|
{
|
|
const TColStd_intMapNode * p1 = theMap1.myData1[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 = packedKeyIndex (aKey);
|
|
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 = theMap2.myData1[HashCode (aKeyInt, nBuckets2)];
|
|
while (p2)
|
|
{
|
|
if (p2->IsEqual(aKeyInt))
|
|
{
|
|
aNewData &= ~p2->Data();
|
|
nValues = TColStd_Population (aNewMask, aNewData);
|
|
break;
|
|
}
|
|
p2 = p2->Next();
|
|
}
|
|
// Store the block - result of operation
|
|
if (aNewData)
|
|
{
|
|
if (Resizable())
|
|
{
|
|
ReSize (myNbPackedMapNodes);
|
|
}
|
|
const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
myData1[aHashCode]= new TColStd_intMapNode (aNewMask, aNewData,
|
|
myData1[aHashCode]);
|
|
++myNbPackedMapNodes;
|
|
myExtent += nValues;
|
|
}
|
|
p1 = 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);
|
|
const Standard_Integer nBuckets2 = theMap.myNbBuckets;
|
|
// Iteration of this map.
|
|
for (Standard_Integer i = 0; i <= myNbBuckets; i++)
|
|
{
|
|
TColStd_intMapNode* q = 0L;
|
|
TColStd_intMapNode* p1 = myData1[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 = packedKeyIndex (aKey);
|
|
TColStd_intMapNode* pNext = p1->Next();
|
|
// Find the corresponding block in the 2nd map
|
|
const TColStd_intMapNode* p2 = theMap.myData1[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
|
|
--myNbPackedMapNodes;
|
|
if (q) q->SetNext (pNext);
|
|
else myData1[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 = 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 Standard_Integer nBuckets1 = theMap1.myNbBuckets;
|
|
const Standard_Integer nBuckets2 = theMap2.myNbBuckets;
|
|
Clear();
|
|
|
|
// Iteration of the 1st map.
|
|
for (i = 0; i <= nBuckets1; i++)
|
|
{
|
|
const TColStd_intMapNode* p1 = theMap1.myData1[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 = packedKeyIndex (aKey);
|
|
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 = theMap2.myData1[HashCode (aKeyInt, nBuckets2)];
|
|
while (p2)
|
|
{
|
|
if (p2->IsEqual(aKeyInt))
|
|
{
|
|
aNewData ^= p2->Data();
|
|
nValues = TColStd_Population (aNewMask, aNewData);
|
|
break;
|
|
}
|
|
p2 = p2->Next();
|
|
}
|
|
// Store the block - result of operation
|
|
if (aNewData)
|
|
{
|
|
if (Resizable())
|
|
{
|
|
ReSize (myNbPackedMapNodes);
|
|
}
|
|
const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
myData1[aHashCode]= new TColStd_intMapNode (aNewMask, aNewData,
|
|
myData1[aHashCode]);
|
|
++myNbPackedMapNodes;
|
|
myExtent += nValues;
|
|
}
|
|
p1 = p1->Next();
|
|
}
|
|
}
|
|
|
|
// Iteration of the 2nd map.
|
|
for (i = 0; i <= nBuckets2; i++)
|
|
{
|
|
const TColStd_intMapNode* p2 = theMap2.myData1[i];
|
|
while (p2 != 0L)
|
|
{
|
|
// Find aKey - the base address of currently iterated block
|
|
const Standard_Integer aKey = p2->Key();
|
|
const Standard_Integer aKeyInt = packedKeyIndex (aKey);
|
|
// Find the corresponding block in the 1st map
|
|
const TColStd_intMapNode* p1 = theMap1.myData1[HashCode (aKeyInt, nBuckets1)];
|
|
while (p1)
|
|
{
|
|
if (p1->IsEqual(aKeyInt))
|
|
break;
|
|
p1 = 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 (myNbPackedMapNodes);
|
|
}
|
|
const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
myData1[aHashCode]= new TColStd_intMapNode (p2->Mask(), p2->Data(),
|
|
myData1[aHashCode]);
|
|
++myNbPackedMapNodes;
|
|
myExtent += p2->NbValues();
|
|
}
|
|
p2 = 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;
|
|
}
|
|
|
|
size_t aNewExtent (0);
|
|
const Standard_Integer nBuckets2 = theMap.myNbBuckets;
|
|
Standard_Boolean isChanged = Standard_False;
|
|
// Iteration by other map
|
|
for (Standard_Integer i = 0; i <= nBuckets2; i++)
|
|
{
|
|
TColStd_intMapNode * q = 0L;
|
|
const TColStd_intMapNode* p2 = theMap.myData1[i];
|
|
while (p2 != 0L)
|
|
{
|
|
// Find aKey - the base address of currently iterated block
|
|
const Standard_Integer aKey = p2->Key();
|
|
const Standard_Integer aKeyInt = packedKeyIndex (aKey);
|
|
|
|
// Find the corresponding block in the 1st map
|
|
TColStd_intMapNode* p1 = myData1[HashCode (aKeyInt, myNbBuckets)];
|
|
TColStd_intMapNode* pNext = 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
|
|
--myNbPackedMapNodes;
|
|
if (q) q->SetNext (pNext);
|
|
else myData1[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
|
|
if (p1 == 0L)
|
|
{
|
|
if (Resizable())
|
|
{
|
|
ReSize (myNbPackedMapNodes);
|
|
}
|
|
const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets);
|
|
myData1[aHashCode] = new TColStd_intMapNode (p2->Mask(), p2->Data(),
|
|
myData1[aHashCode]);
|
|
++myNbPackedMapNodes;
|
|
aNewExtent += p2->NbValues();
|
|
isChanged = Standard_True;
|
|
}
|
|
p2 = 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 if(myData1 == theMap.myData1)
|
|
return Standard_True;
|
|
|
|
const Standard_Integer nBuckets2 = theMap.myNbBuckets;
|
|
// Iteration of this map.
|
|
for (Standard_Integer i = 0; i <= myNbBuckets; i++)
|
|
{
|
|
const TColStd_intMapNode* p1 = myData1[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 = packedKeyIndex (aKey);
|
|
TColStd_intMapNode* pNext = p1->Next();
|
|
// Find the corresponding block in the 2nd map
|
|
const TColStd_intMapNode* p2 = theMap.myData1[HashCode (aKeyInt, nBuckets2)];
|
|
while (p2)
|
|
{
|
|
if ( p2->IsEqual(aKeyInt) )
|
|
{
|
|
if ( p1->Data() != p2->Data() )
|
|
return Standard_False;
|
|
break;
|
|
}
|
|
p2 = 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 if(myData1 == theMap.myData1)
|
|
return Standard_True;
|
|
|
|
const Standard_Integer nBuckets2 = theMap.myNbBuckets;
|
|
// Iteration of this map.
|
|
for (Standard_Integer i = 0; i <= myNbBuckets; i++)
|
|
{
|
|
const TColStd_intMapNode* p1 = myData1[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 = packedKeyIndex (aKey);
|
|
TColStd_intMapNode* pNext = p1->Next();
|
|
// Find the corresponding block in the 2nd map
|
|
const TColStd_intMapNode* p2 = theMap.myData1[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 = 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;
|
|
|
|
if(myData1 == theMap.myData1)
|
|
return Standard_True;
|
|
|
|
const Standard_Integer nBuckets2 = theMap.myNbBuckets;
|
|
// Iteration of this map.
|
|
for (Standard_Integer i = 0; i <= myNbBuckets; i++)
|
|
{
|
|
const TColStd_intMapNode* p1 = myData1[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 = packedKeyIndex (aKey);
|
|
TColStd_intMapNode* pNext = p1->Next();
|
|
// Find the corresponding block in the 2nd map
|
|
const TColStd_intMapNode* p2 = theMap.myData1[HashCode (aKeyInt, nBuckets2)];
|
|
while (p2)
|
|
{
|
|
if (p2->IsEqual(aKeyInt))
|
|
{
|
|
if (p1->Data() & p2->Data())
|
|
return Standard_True;
|
|
break;
|
|
}
|
|
p2 = p2->Next();
|
|
}
|
|
p1 = pNext;
|
|
}
|
|
}
|
|
return Standard_False;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Statistics
|
|
//purpose :
|
|
//=======================================================================
|
|
void TColStd_PackedMapOfInteger::Statistics (Standard_OStream& theStream) const
|
|
{
|
|
theStream << "\nMap Statistics\n---------------\n\n";
|
|
theStream << "This Map has " << myNbBuckets << " Buckets and " << myNbPackedMapNodes << " Keys\n\n";
|
|
if (myNbPackedMapNodes == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NCollection_Array1<Standard_Integer> aSizes (0, myNbPackedMapNodes);
|
|
aSizes.Init (0);
|
|
|
|
theStream << "\nStatistics for the first Key\n";
|
|
Standard_Integer aNbNonEmpty = 0;
|
|
for (Standard_Integer aBucketIter = 0; aBucketIter <= myNbBuckets; ++aBucketIter)
|
|
{
|
|
TColStd_intMapNode* aSubNodeIter = myData1[aBucketIter];
|
|
if (aSubNodeIter != NULL)
|
|
{
|
|
++aNbNonEmpty;
|
|
}
|
|
|
|
Standard_Integer aNbMapSubNodes = 0;
|
|
for (; aSubNodeIter != NULL; aSubNodeIter = aSubNodeIter->Next())
|
|
{
|
|
++aNbMapSubNodes;
|
|
}
|
|
++aSizes[aNbMapSubNodes];
|
|
}
|
|
|
|
// display results
|
|
Standard_Integer aNbMapSubNodesTotal = 0;
|
|
for (Standard_Integer aNbMapSubNodes = 0; aNbMapSubNodes <= myNbPackedMapNodes; ++aNbMapSubNodes)
|
|
{
|
|
if (aSizes[aNbMapSubNodes] > 0)
|
|
{
|
|
aNbMapSubNodesTotal += aSizes[aNbMapSubNodes] * aNbMapSubNodes;
|
|
theStream << std::setw(5) << aSizes[aNbMapSubNodes] << " buckets of size " << aNbMapSubNodes << "\n";
|
|
}
|
|
}
|
|
|
|
const Standard_Real aMean = ((Standard_Real) aNbMapSubNodesTotal) / ((Standard_Real) aNbNonEmpty);
|
|
theStream << "\n\nMean of length: " << aMean << "\n";
|
|
}
|