From 979f4e631ce1c8c8f7a3bfc057028dc284c98a76 Mon Sep 17 00:00:00 2001 From: kgv Date: Wed, 26 Sep 2018 22:11:59 +0300 Subject: [PATCH 2/2] TColStd_PackedMapOfInteger::SparseAllocation() - added new flag managing memory allocation scheme between map style and array style. --- src/TColStd/TColStd_PackedMapOfInteger.cxx | 335 +++++++++++---------- src/TColStd/TColStd_PackedMapOfInteger.hxx | 158 ++++++++-- 2 files changed, 312 insertions(+), 181 deletions(-) diff --git a/src/TColStd/TColStd_PackedMapOfInteger.cxx b/src/TColStd/TColStd_PackedMapOfInteger.cxx index 85a515ee75..5c0d4ff783 100644 --- a/src/TColStd/TColStd_PackedMapOfInteger.cxx +++ b/src/TColStd/TColStd_PackedMapOfInteger.cxx @@ -17,6 +17,7 @@ #include #include +#include //======================================================================= //function : TColStd_intMapNode_findNext @@ -112,29 +113,33 @@ Standard_Integer TColStd_PackedMapOfInteger::TColStd_intMapNode_findPrev (const 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()); + if (this == &theOther) + { + return *this; + } + + Clear(); + if (theOther.IsEmpty()) + { + return *this; + } + + const Standard_Integer aNbBuckets = myIsSparseAlloc || !theOther.myIsSparseAlloc + ? theOther.myNbPackedMapNodes + : Max (0, theOther.GetMaximalMapped()); + ReSize (aNbBuckets); + for (Standard_Integer i = 0; i <= theOther.myNbBuckets; i++) + { + for (const TColStd_intMapNode* p = theOther.myData1[i]; p != NULL; p = p->Next()) + { + const Standard_Integer aHashCode = p->HashCode (myNbBuckets); + allocateNode (aHashCode, p->Mask(), p->Data()); } } - myExtent = theOther.myExtent; - return * this; +// Simple alternative +// for (TColStd_MapIteratorOfPackedMapOfInteger anIt (theOther); anIt.More(); anIt.Next()) { Add (anIt.Key()); } + myExtent = theOther.myExtent; + return *this; } //======================================================================= @@ -147,79 +152,128 @@ void TColStd_PackedMapOfInteger::ReSize (const Standard_Integer theNbBuckets) Standard_Integer aNewBuck = TCollection::NextPrimeForMap (theNbBuckets); if (aNewBuck <= myNbBuckets) { - if (!IsEmpty()) + if (myData1 != NULL) { 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** anOldData1 = myData1; + TColStd_intMapNode* anOldData2 = myData2; + const Standard_Integer anOldNbBuckets = myNbBuckets; + + myData1 = new TColStd_intMapNode*[aNewBuck + 1]; + memset (myData1, 0, (aNewBuck + 1) * sizeof(TColStd_intMapNode*)); + if (myIsSparseAlloc) + { + myData2 = NULL; + } + else + { + myData2 = new TColStd_intMapNode[aNewBuck + 1]; + } + myNbBuckets = aNewBuck; + + if (anOldData1 != NULL) { - TColStd_intMapNode** anOldData = myData1; - for (Standard_Integer i = 0; i <= myNbBuckets; ++i) + if (myData2 == NULL + && anOldData2 == NULL) { - for (TColStd_intMapNode* p = anOldData[i]; p != NULL; ) + // move old packed nodes to the new array + for (Standard_Integer i = 0; i <= anOldNbBuckets; ++i) { - Standard_Integer k = p->HashCode (aNewBuck); - TColStd_intMapNode* q = p->Next(); - p->SetNext (aNewData[k]); - aNewData[k] = p; - p = q; + for (TColStd_intMapNode* p = anOldData1[i]; p != NULL; ) + { + const Standard_Integer aHashCode = p->HashCode (aNewBuck); + TColStd_intMapNode* q = p->Next(); + p->SetNext (myData1[aHashCode]); + myData1[aHashCode] = p; + p = q; + } + } + } + else + { + // copy packed nodes + for (Standard_Integer i = 0; i <= anOldNbBuckets; ++i) + { + for (TColStd_intMapNode* p = anOldData1[i]; p != NULL; p = p->Next()) + { + const Standard_Integer aHashCode = p->HashCode (aNewBuck); + allocateNode (aHashCode, p->Mask(), p->Data()); + } + } + + // release old data + if (anOldData2 == NULL) + { + for (Standard_Integer i = 0; i <= anOldNbBuckets; i++) + { + for (TColStd_intMapNode* p = myData1[i]; p != NULL; ) + { + TColStd_intMapNode* q = p->Next(); + delete p; + p = q; + } + } } } } - Standard::Free (myData1); - myNbBuckets = aNewBuck; - myData1 = aNewData; + delete[] anOldData1; + delete[] anOldData2; } //======================================================================= -//function : Clear -//purpose : +//function : clear +//purpose : //======================================================================= -void TColStd_PackedMapOfInteger::Clear () +void TColStd_PackedMapOfInteger::clear (Standard_Boolean theToReleaseMemory) { - /*if (!IsEmpty()) /// TODO + if (!theToReleaseMemory) { - for (Standard_Integer aBucketIter = 0; aBucketIter <= myNbBuckets; ++aBucketIter) + if (!IsEmpty()) { - if (myData1[aBucketIter]) + if (myData2 != NULL) + { + memset (myData1, 0, (myNbBuckets + 1) * sizeof(TColStd_intMapNode*)); + } + else { - for (TColStd_intMapNode* aSubNodeIter = myData1[aBucketIter]; aSubNodeIter != NULL; ) + for (Standard_Integer aBucketIter = 0; aBucketIter <= myNbBuckets; ++aBucketIter) { - aSubNodeIter->ChangeData() = 0; - aSubNodeIter = static_cast (aSubNodeIter->Next()); + for (TColStd_intMapNode* aSubNodeIter = myData1[aBucketIter]; aSubNodeIter != NULL; aSubNodeIter = aSubNodeIter->Next()) + { + aSubNodeIter->ClearValues(); + } } } } + myNbPackedMapNodes = 0; + myExtent = 0; + return; } - myNbPackedMapNodes = 0; - myExtent = 0;*/ - if (!IsEmpty()) + if (myNbPackedMapNodes > 0 && myData2 == NULL) { for (Standard_Integer i = 0; i <= myNbBuckets; i++) { - if (myData1[i]) + for (TColStd_intMapNode* p = myData1[i]; p != NULL; ) { - for (TColStd_intMapNode* p = myData1[i]; p != NULL; ) - { - TColStd_intMapNode* q = p->Next(); - delete p; - p = q; - } + TColStd_intMapNode* q = p->Next(); + deleteNode (i, p); + p = q; } } } myNbPackedMapNodes = 0; - Standard::Free (myData1); + delete[] myData1; + delete[] myData2; myData1 = NULL; + myData2 = NULL; myExtent = 0; } @@ -230,18 +284,27 @@ void TColStd_PackedMapOfInteger::Clear () Standard_Boolean TColStd_PackedMapOfInteger::Add (const Standard_Integer aKey) { - if (Resizable()) + const Standard_Integer aKeyInt = packedKeyIndex (aKey); + autoReSize (aKeyInt); + if (myData2 != NULL) { - ReSize (myNbPackedMapNodes); + Standard_OutOfRange_Raise_if (aKey < 0, "TColStd_PackedMapOfInteger::Add() - negative key is not allowed"); + if (myData1[aKeyInt] != NULL + && myData1[aKeyInt]->AddValue (aKey)) + { + ++myExtent; + return Standard_True; + } + allocateNode (aKeyInt, aKey); + ++myExtent; + return Standard_True; } Standard_Boolean aResult (Standard_False); - 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()) + for (TColStd_intMapNode* p = myData1[aHashCode]; p != NULL; p = p->Next()) { - if (p->IsEqual(aKeyInt)) + if (myData2 != NULL || p->IsEqual(aKeyInt)) { aResult = p->AddValue (aKey); // break; @@ -249,8 +312,7 @@ Standard_Boolean TColStd_PackedMapOfInteger::Add (const Standard_Integer aKey) } } // if (!p) { // not needed, as long as we exit the loop by goto - myData1[aHashCode] = new TColStd_intMapNode(aKey, aBucketHead); - ++myNbPackedMapNodes; + allocateNode (aHashCode, aKey); aResult = Standard_True; // } finish: @@ -276,7 +338,7 @@ Standard_Boolean TColStd_PackedMapOfInteger::Contains const Standard_Integer aKeyInt = packedKeyIndex (aKey); for (TColStd_intMapNode* p = myData1[HashCode (aKeyInt, myNbBuckets)]; p != NULL; ) { - if (p->IsEqual(aKeyInt)) + if (myData2 != NULL || p->IsEqual(aKeyInt)) { aResult = (p->HasValue (aKey) != 0); break; @@ -298,39 +360,36 @@ Standard_Boolean TColStd_PackedMapOfInteger::Remove(const Standard_Integer aKey) 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; + const Standard_Integer aHashCode = HashCode(aKeyInt, myNbBuckets); + TColStd_intMapNode* q = 0L; - while (p) + for (TColStd_intMapNode* p = myData1[aHashCode]; p != NULL; p = p->Next()) { - if (p->IsEqual(aKeyInt)) + if (myData2 != NULL || p->IsEqual(aKeyInt)) { - aResult = p->DelValue (aKey); - if (aResult) + if (p->DelValue (aKey)) { --myExtent; if (!p->HasValues()) { - --myNbPackedMapNodes; if (q != NULL) { q->SetNext (p->Next()); } else { - aBucketHead = p->Next(); + myData1[aHashCode] = p->Next(); } - delete p; + deleteNode (aHashCode, p); } + return Standard_True; } - break; + return Standard_False; } q = p; - p = p->Next(); } - return aResult; + return Standard_False; } //======================================================================= @@ -442,13 +501,9 @@ void TColStd_PackedMapOfInteger::Union (const TColStd_PackedMapOfInteger& theMap p2 = p2->Next(); } // Store the block - result of operation - if (Resizable()) { - ReSize (myNbPackedMapNodes); - } + autoReSize (aKeyInt); const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets); - myData1[aHashCode] = new TColStd_intMapNode (aNewMask, aNewData, - myData1[aHashCode]); - ++myNbPackedMapNodes; + allocateNode (aHashCode, aNewMask, aNewData); myExtent += nValues; p1 = p1->Next(); } @@ -474,14 +529,9 @@ void TColStd_PackedMapOfInteger::Union (const TColStd_PackedMapOfInteger& theMap // block has not been found in the 1st map if (p1 == 0L) { - if (Resizable()) - { - ReSize (myNbPackedMapNodes); - } + autoReSize (aKeyInt); const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets); - myData1[aHashCode]= new TColStd_intMapNode (p2->Mask(), p2->Data(), - myData1[aHashCode]); - ++myNbPackedMapNodes; + allocateNode (aHashCode, p2->Mask(), p2->Data()); myExtent += p2->NbValues(); } p2 = p2->Next(); @@ -537,14 +587,11 @@ Standard_Boolean TColStd_PackedMapOfInteger::Unite(const TColStd_PackedMapOfInte // If the block is not found in the 1st map, add it to the 1st map if (p1 == 0L) { - if (Resizable()) + if (autoReSize (aKeyInt)) { - ReSize (myNbPackedMapNodes); aHashCode = HashCode (aKeyInt, myNbBuckets); } - myData1[aHashCode] = new TColStd_intMapNode (p2->Mask(), p2->Data(), - myData1[aHashCode]); - ++myNbPackedMapNodes; + allocateNode (aHashCode, p2->Mask(), p2->Data()); aNewExtent += p2->NbValues(); } p2 = p2->Next(); @@ -609,16 +656,11 @@ void TColStd_PackedMapOfInteger::Intersection // Store the block - result of operation if (aNewData) { - if (Resizable()) - { - ReSize (myNbPackedMapNodes); - } + autoReSize (aKeyInt); 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; + allocateNode (aHashCode, aNewMask, aNewData); } break; } @@ -654,15 +696,15 @@ Standard_Boolean TColStd_PackedMapOfInteger::Intersect for (Standard_Integer i = 0; i <= myNbBuckets; i++) { TColStd_intMapNode* q = 0L; - TColStd_intMapNode* p1 = myData1[i]; - while (p1 != 0L) + for (TColStd_intMapNode* p1 = myData1[i]; p1 != NULL; ) { // Find aKey - the base address of currently iterated block of integers const Standard_Integer aKey = p1->Key(); const Standard_Integer aKeyInt = packedKeyIndex (aKey); + const Standard_Integer aHashCode2 = HashCode (aKeyInt, nBuckets2); // Find the corresponding block in the 2nd map - const TColStd_intMapNode* p2 = theMap.myData1[HashCode (aKeyInt, nBuckets2)]; - while (p2) + const TColStd_intMapNode* p2 = theMap.myData1[aHashCode2]; + for (; p2 != NULL; p2 = p2->Next()) { if (p2->IsEqual(aKeyInt)) { @@ -678,8 +720,8 @@ Standard_Boolean TColStd_PackedMapOfInteger::Intersect } 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 @@ -689,10 +731,10 @@ Standard_Boolean TColStd_PackedMapOfInteger::Intersect } else { - --myNbPackedMapNodes; if (q) q->SetNext (pNext); else myData1[i] = pNext; - delete p1; + + deleteNode (i, p1); } p1 = pNext; } @@ -754,14 +796,9 @@ void TColStd_PackedMapOfInteger::Subtraction // Store the block - result of operation if (aNewData) { - if (Resizable()) - { - ReSize (myNbPackedMapNodes); - } + autoReSize (aKeyInt); const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets); - myData1[aHashCode]= new TColStd_intMapNode (aNewMask, aNewData, - myData1[aHashCode]); - ++myNbPackedMapNodes; + allocateNode (aHashCode, aNewMask, aNewData); myExtent += nValues; } p1 = p1->Next(); @@ -786,21 +823,19 @@ Standard_Boolean TColStd_PackedMapOfInteger::Subtract } 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) + TColStd_intMapNode* q = NULL; + for (TColStd_intMapNode* p1 = myData1[i]; p1 != NULL; ) { // 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) + const TColStd_intMapNode* p2 = theMap.myData1[HashCode (aKeyInt, theMap.myNbBuckets)]; + for (; p2 != NULL; p2 = p2->Next()) { if (p2->IsEqual(aKeyInt)) { @@ -809,10 +844,9 @@ Standard_Boolean TColStd_PackedMapOfInteger::Subtract if (aNewData == 0) { // no match - the block has to be removed - --myNbPackedMapNodes; if (q) q->SetNext (pNext); else myData1[i] = pNext; - delete p1; + deleteNode (i, p1); } else if ( aNewData != p1->Data() ) { @@ -827,7 +861,6 @@ Standard_Boolean TColStd_PackedMapOfInteger::Subtract } break; } - p2 = p2->Next(); } if (p2 == 0L) { @@ -892,14 +925,9 @@ void TColStd_PackedMapOfInteger::Difference (const TColStd_PackedMapOfInteger& // Store the block - result of operation if (aNewData) { - if (Resizable()) - { - ReSize (myNbPackedMapNodes); - } + autoReSize (aKeyInt); const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets); - myData1[aHashCode]= new TColStd_intMapNode (aNewMask, aNewData, - myData1[aHashCode]); - ++myNbPackedMapNodes; + allocateNode (aHashCode, aNewMask, aNewData); myExtent += nValues; } p1 = p1->Next(); @@ -927,14 +955,9 @@ void TColStd_PackedMapOfInteger::Difference (const TColStd_PackedMapOfInteger& // block has not been found in the 1st map if (p1 == 0L) { - if (Resizable()) - { - ReSize (myNbPackedMapNodes); - } + autoReSize (aKeyInt); const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets); - myData1[aHashCode]= new TColStd_intMapNode (p2->Mask(), p2->Data(), - myData1[aHashCode]); - ++myNbPackedMapNodes; + allocateNode (aHashCode, p2->Mask(), p2->Data()); myExtent += p2->NbValues(); } p2 = p2->Next(); @@ -962,24 +985,23 @@ Standard_Boolean TColStd_PackedMapOfInteger::Differ(const TColStd_PackedMapOfInt } 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++) + for (Standard_Integer i = 0; i <= theMap.myNbBuckets; i++) { - TColStd_intMapNode * q = 0L; - const TColStd_intMapNode* p2 = theMap.myData1[i]; - while (p2 != 0L) + TColStd_intMapNode* q = NULL; + for (const TColStd_intMapNode* p2 = theMap.myData1[i]; p2 != NULL; p2 = p2->Next()) { // Find aKey - the base address of currently iterated block const Standard_Integer aKey = p2->Key(); const Standard_Integer aKeyInt = packedKeyIndex (aKey); + const Standard_Integer aHashCode = HashCode (aKeyInt, myNbBuckets); // Find the corresponding block in the 1st map - TColStd_intMapNode* p1 = myData1[HashCode (aKeyInt, myNbBuckets)]; - TColStd_intMapNode* pNext = p1->Next(); - while (p1) + TColStd_intMapNode* p1 = myData1[aHashCode]; + for (; p1 != NULL;) { + TColStd_intMapNode* pNext = p1->Next(); if (p1->IsEqual(aKeyInt)) { const unsigned int aNewData = p1->Data() ^ p2->Data(); @@ -987,10 +1009,9 @@ Standard_Boolean TColStd_PackedMapOfInteger::Differ(const TColStd_PackedMapOfInt if (aNewData == 0) { // no match - the block has to be removed - --myNbPackedMapNodes; if (q) q->SetNext (pNext); - else myData1[i] = pNext; - delete p1; + else myData1[aHashCode] = pNext; + deleteNode (aHashCode, p1); } else if ( aNewData != p1->Data() ) { @@ -1007,18 +1028,12 @@ Standard_Boolean TColStd_PackedMapOfInteger::Differ(const TColStd_PackedMapOfInt // 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; + autoReSize (aKeyInt); + const Standard_Integer aHashCodeNew = HashCode (aKeyInt, myNbBuckets); + allocateNode (aHashCodeNew, p2->Mask(), p2->Data()); aNewExtent += p2->NbValues(); isChanged = Standard_True; } - p2 = p2->Next(); } } myExtent = aNewExtent; diff --git a/src/TColStd/TColStd_PackedMapOfInteger.hxx b/src/TColStd/TColStd_PackedMapOfInteger.hxx index 6bcfa1b70d..6ab83ff174 100644 --- a/src/TColStd/TColStd_PackedMapOfInteger.hxx +++ b/src/TColStd/TColStd_PackedMapOfInteger.hxx @@ -46,8 +46,8 @@ private: class TColStd_intMapNode { public: - TColStd_intMapNode (TColStd_intMapNode* thePtr = NULL) - : myNext (thePtr), myMask (0), myData (0) {} + TColStd_intMapNode() + : myNext (NULL), myMask (0), myData (0) {} TColStd_intMapNode (Standard_Integer theValue, TColStd_intMapNode*& thePtr) : myNext (thePtr), @@ -107,6 +107,13 @@ private: return Standard_False; } + //! Delete all integer keys from this packed node but without invalidating the mask. + void ClearValues() + { + myMask -= (Standard_Integer )NbValues(); + myData = 0; + } + //! 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; @@ -218,20 +225,29 @@ public: { return; } - - if (myNode != NULL) + else if (myNode != NULL) { myNode = myNode->Next(); } - while (myNode == NULL) + for (;;) { - ++myBucket; - if (myBucket > myNbBuckets) + if (myNode == NULL) + { + if (++myBucket > myNbBuckets) + { + return; + } + myNode = myBuckets[myBucket]; + } + + for (; myNode != NULL; myNode = myNode->Next()) { - return; + if (myNode->HasValues()) + { + return; + } } - myNode = myBuckets[myBucket]; } } @@ -250,16 +266,20 @@ public: //! Constructor TColStd_PackedMapOfInteger (const Standard_Integer theNbBuckets = 1) : myData1 (NULL), + myData2 (NULL), + myExtent (0), myNbBuckets (theNbBuckets), myNbPackedMapNodes (0), - myExtent (0) {} + myIsSparseAlloc (Standard_True) {} //! Copy constructor TColStd_PackedMapOfInteger (const TColStd_PackedMapOfInteger& theOther) : myData1 (NULL), + myData2 (NULL), + myExtent (0), myNbBuckets (1), myNbPackedMapNodes (0), - myExtent (0) + myIsSparseAlloc (Standard_True) { Assign (theOther); } @@ -271,8 +291,20 @@ public: Standard_EXPORT TColStd_PackedMapOfInteger& Assign (const TColStd_PackedMapOfInteger&); Standard_EXPORT void ReSize (const Standard_Integer NbBuckets); - Standard_EXPORT void Clear (); - ~TColStd_PackedMapOfInteger() { Clear(); } + + //! Clear map and release memory. + void Clear() + { + clear (myIsSparseAlloc); + } + + //! Clear map and optionally release memory. + void Clear (Standard_Boolean theToReleaseMemory) + { + clear (theToReleaseMemory); + } + + ~TColStd_PackedMapOfInteger() { clear (Standard_True); } Standard_EXPORT Standard_Boolean Add (const Standard_Integer aKey); Standard_EXPORT Standard_Boolean @@ -299,6 +331,32 @@ public: */ Standard_EXPORT Standard_Integer GetMaximalMapped () const; + //! Returns TRUE if sparse memory allocation is active; TRUE by default. + //! + //! Sparse memory allocation would keep memory usage low for a small amount of values, + //! but woulds require regular memory reallocations on adding/removing key operations. + //! + //! Opposite to sparse memory allocation will be allocation of map as array of (packed) Boolean flags, + //! so that map containing only small amount of keys would still occupy memory + //! enough for storing an array [0, GetMaximalMapped()], + //! but adding/removing key will be done with lesser amount of memory reallocations. + //! + //! WARNING! Only positive keys are allowed when sparse allocation is disabled! + Standard_Boolean SparseAllocation() const { return myIsSparseAlloc; } + + //! Set flag for sparse memory allocation. + //! Should be called BEFORE map usage. + void SetSparseAllocation (Standard_Boolean theIsSparse) + { + if (myIsSparseAlloc != theIsSparse) + { + const TColStd_PackedMapOfInteger aCopy (*this); + clear (Standard_True); + myIsSparseAlloc = theIsSparse; + Assign (aCopy); + } + } + public: //!@name Boolean operations with maps as sets of integers //!@{ @@ -427,15 +485,25 @@ public: //!@} - protected: +private: - //! Returns TRUE if resizing the map should be considered. - Standard_Boolean Resizable() const { return IsEmpty() || (myNbPackedMapNodes > myNbBuckets); } + //! Clear map and release memory. + Standard_EXPORT void clear (Standard_Boolean theToReleaseMemory); - //! Return an integer index for specified key. - static Standard_Integer packedKeyIndex (Standard_Integer theKey) { return (unsigned)theKey >> 5; } + //! Resize map to fit at least one more element. + Standard_Boolean autoReSize (Standard_Integer theNewMax) + { + const Standard_Integer aNbBuckets = myIsSparseAlloc ? myNbPackedMapNodes : theNewMax; + if (IsEmpty() || (aNbBuckets > myNbBuckets)) + { + ReSize (aNbBuckets); + return Standard_True; + } + return Standard_False; + } -private: + //! Return an integer index for specified key. + static Standard_Integer packedKeyIndex (Standard_Integer theKey) { return (unsigned)theKey >> 5; } //! Find the smallest non-zero bit under the given mask. //! Outputs the new mask that does not contain the detected bit. @@ -461,12 +529,60 @@ private: return size_t(aRes & 0x3f); } + //! Allocate a new packed node within the map. + void allocateNode (Standard_Integer theHashCode, Standard_Integer theValue) + { + if (myData2 != NULL) + { + myData1[theHashCode] = &myData2[theHashCode]; + myData1[theHashCode]->ChangeMask() = (unsigned int) (theValue & MASK_HIGH); + myData1[theHashCode]->ChangeData() = 1 << (theValue & MASK_LOW); + } + else + { + myData1[theHashCode] = new TColStd_intMapNode (theValue, myData1[theHashCode]); + } + ++myNbPackedMapNodes; + } + + //! Allocate a new packed node within the map. + void allocateNode (Standard_Integer theHashCode, unsigned int theMask, unsigned int theData) + { + if (myData2 != NULL) + { + myData1[theHashCode] = &myData2[theHashCode]; + myData1[theHashCode]->ChangeMask() = theMask; + myData1[theHashCode]->ChangeData() = theData; + } + else + { + myData1[theHashCode] = new TColStd_intMapNode (theMask, theData, myData1[theHashCode]); + } + ++myNbPackedMapNodes; + } + + //! Release a packed node from the map. + void deleteNode (Standard_Integer theHashCode, TColStd_intMapNode* theNode) + { + if (myData2 != NULL) + { + myData1[theHashCode] = NULL; + } + else + { + delete theNode; + } + --myNbPackedMapNodes; + } + private: - TColStd_intMapNode** myData1; //!< data array + TColStd_intMapNode** myData1; //!< data array of buckets + TColStd_intMapNode* myData2; //!< data array of pre-allocated buckets + Standard_Size myExtent; //!< extent of this map (number of unpacked integer keys) Standard_Integer myNbBuckets; //!< number of buckets (size of data array) Standard_Integer myNbPackedMapNodes; //!< amount of packed map nodes - Standard_Size myExtent; //!< extent of this map (number of unpacked integer keys) + Standard_Boolean myIsSparseAlloc; //!< use sparse memory allocation - the number of }; #endif -- 2.31.1.windows.1