From b1270830d180bd5585f56e3dd55d0512c7648a5c Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Sat, 2 Nov 2024 19:02:02 +0000 Subject: [PATCH 1/7] Foundation Classes - Update Map to store insert order Changes to keep the insert order to improve iteration procedure. Making TCollection deprecated as a not clear definition. --- src/NCollection/FILES | 1 + src/NCollection/NCollection_BaseMap.cxx | 68 ++++-- src/NCollection/NCollection_BaseMap.hxx | 26 ++- .../NCollection_BasePointerVector.cxx | 1 - src/NCollection/NCollection_Map.hxx | 219 ++++++++++-------- src/NCollection/NCollection_Primes.hxx | 75 ++++++ src/TColStd/TColStd_PackedMapOfInteger.cxx | 4 +- src/TCollection/FILES | 1 - src/TCollection/TCollection.cxx | 74 ------ src/TCollection/TCollection.hxx | 9 +- 10 files changed, 271 insertions(+), 207 deletions(-) create mode 100644 src/NCollection/NCollection_Primes.hxx delete mode 100644 src/TCollection/TCollection.cxx diff --git a/src/NCollection/FILES b/src/NCollection/FILES index d93ebc08fb..d382c9ef60 100755 --- a/src/NCollection/FILES +++ b/src/NCollection/FILES @@ -49,6 +49,7 @@ NCollection_Map.hxx NCollection_Mat3.hxx NCollection_Mat4.hxx NCollection_OccAllocator.hxx +NCollection_Primes.hxx NCollection_Sequence.hxx NCollection_Shared.hxx NCollection_SparseArray.hxx diff --git a/src/NCollection/NCollection_BaseMap.cxx b/src/NCollection/NCollection_BaseMap.cxx index 7f32f332b3..7007d24d56 100644 --- a/src/NCollection/NCollection_BaseMap.cxx +++ b/src/NCollection/NCollection_BaseMap.cxx @@ -16,7 +16,7 @@ // Purpose: Implementation of the BaseMap class #include -#include +#include //======================================================================= //function : BeginResize @@ -30,7 +30,7 @@ Standard_Boolean NCollection_BaseMap::BeginResize NCollection_ListNode**& data2) const { // get next size for the buckets array - N = NextPrimeForMap(NbBuckets); + N = NCollection_Primes::NextPrimeForMap(NbBuckets); if (N <= myNbBuckets) { if (!myData1) @@ -46,7 +46,7 @@ Standard_Boolean NCollection_BaseMap::BeginResize Standard::Allocate((N+1)*sizeof(NCollection_ListNode *)); } else - data2 = NULL; + data2 = nullptr; return Standard_True; } @@ -71,14 +71,47 @@ void NCollection_BaseMap::EndResize myData2 = data2; } - //======================================================================= -//function : Destroy -//purpose : +//function : Reallocate +//purpose : //======================================================================= +Standard_Boolean NCollection_BaseMap::Reallocate(const Standard_Integer theNbBuckets) +{ + // get next size for the buckets array + Standard_Integer aNewBuckets = NCollection_Primes::NextPrimeForMap(theNbBuckets); + if (aNewBuckets <= myNbBuckets) + { + if (!myData1) + { + aNewBuckets = myNbBuckets; + } + else + { + return Standard_False; + } + } + myNbBuckets = aNewBuckets; + const size_t aSize = myNbBuckets + 1; + myData1 = (NCollection_ListNode**)Standard::Reallocate(myData1, aSize * sizeof(NCollection_ListNode*)); + memset(myData1, 0, aSize * sizeof(NCollection_ListNode*)); + if (isDouble) + { + myData2 = (NCollection_ListNode**)Standard::Reallocate(myData2, aSize * sizeof(NCollection_ListNode*)); + memset(myData2, 0, aSize * sizeof(NCollection_ListNode*)); + } + else + { + myData2 = nullptr; + } + return Standard_True; +} + + //======================================================================= + //function : Destroy + //purpose : + //======================================================================= -void NCollection_BaseMap::Destroy (NCollection_DelMapNode fDel, - Standard_Boolean doReleaseMemory) + void NCollection_BaseMap::Destroy(NCollection_DelMapNode fDel, Standard_Boolean doReleaseMemory) { if (!IsEmpty()) { @@ -94,23 +127,22 @@ void NCollection_BaseMap::Destroy (NCollection_DelMapNode fDel, fDel (aCur, myAllocator); aCur = aNext; } - myData1[anInd] = nullptr; + myData1[anInd] = nullptr; } } if (myData2) { memset(myData2, 0, (aNbBuckets + 1) * sizeof(NCollection_ListNode*)); } + mySize = 0; } - - mySize = 0; if (doReleaseMemory) { if (myData1) Standard::Free(myData1); if (myData2) Standard::Free(myData2); - myData1 = myData2 = NULL; + myData1 = myData2 = nullptr; } } @@ -166,15 +198,3 @@ void NCollection_BaseMap::Statistics(Standard_OStream& S) const delete [] sizes; } - -//======================================================================= -//function : NextPrimeForMap -//purpose : -//======================================================================= - -Standard_Integer NCollection_BaseMap::NextPrimeForMap - (const Standard_Integer N) const -{ - return TCollection::NextPrimeForMap ( N ); -} - diff --git a/src/NCollection/NCollection_BaseMap.hxx b/src/NCollection/NCollection_BaseMap.hxx index 07e530db08..41eac66863 100644 --- a/src/NCollection/NCollection_BaseMap.hxx +++ b/src/NCollection/NCollection_BaseMap.hxx @@ -49,16 +49,16 @@ public: //! Empty constructor Iterator (void) : myNbBuckets (0), - myBuckets (NULL), + myBuckets (nullptr), myBucket (0), - myNode (NULL) {} + myNode (nullptr) {} //! Constructor Iterator (const NCollection_BaseMap& theMap) : myNbBuckets (theMap.myNbBuckets), myBuckets (theMap.myData1), myBucket (-1), - myNode (NULL) + myNode (nullptr) { if (!myBuckets) myNbBuckets = -1; @@ -78,7 +78,7 @@ public: myNbBuckets = theMap.myNbBuckets; myBuckets = theMap.myData1; myBucket = -1; - myNode = NULL; + myNode = nullptr; if (!myBuckets) myNbBuckets = -1; PNext(); @@ -88,7 +88,7 @@ public: void Reset (void) { myBucket = -1; - myNode = NULL; + myNode = nullptr; PNext(); } @@ -101,7 +101,7 @@ public: protected: //! PMore Standard_Boolean PMore (void) const - { return (myNode != NULL); } + { return (myNode != nullptr); } //! PNext void PNext (void) @@ -161,8 +161,8 @@ public: const Standard_Boolean single, const Handle(NCollection_BaseAllocator)& theAllocator) : myAllocator(theAllocator.IsNull() ? NCollection_BaseAllocator::CommonBaseAllocator() : theAllocator), - myData1(NULL), - myData2(NULL), + myData1(nullptr), + myData2(nullptr), myNbBuckets(NbBuckets), mySize(0), isDouble(!single) @@ -200,6 +200,12 @@ public: NCollection_ListNode** data1, NCollection_ListNode** data2); + //! Reallocate the existed data containers. + //! Filling operation must to be done outside. + //! Reallocated memory will be cleared (all elements will be set to nullptr). + Standard_EXPORT Standard_Boolean Reallocate + (const Standard_Integer theNbBuckets); + //! Resizable Standard_Boolean Resizable() const { return IsEmpty() || (mySize > myNbBuckets); } @@ -214,10 +220,6 @@ public: Standard_EXPORT void Destroy(NCollection_DelMapNode fDel, Standard_Boolean doReleaseMemory = Standard_True); - //! NextPrimeForMap - Standard_EXPORT Standard_Integer NextPrimeForMap - (const Standard_Integer N) const; - //! Exchange content of two maps without data copying void exchangeMapsData (NCollection_BaseMap& theOther) { diff --git a/src/NCollection/NCollection_BasePointerVector.cxx b/src/NCollection/NCollection_BasePointerVector.cxx index 55a3439448..dce8200423 100644 --- a/src/NCollection/NCollection_BasePointerVector.cxx +++ b/src/NCollection/NCollection_BasePointerVector.cxx @@ -13,7 +13,6 @@ #include -#include #include //======================================================================= diff --git a/src/NCollection/NCollection_Map.hxx b/src/NCollection/NCollection_Map.hxx index ca7f0135b3..20ede2b981 100644 --- a/src/NCollection/NCollection_Map.hxx +++ b/src/NCollection/NCollection_Map.hxx @@ -68,48 +68,79 @@ public: public: //! Constructor with 'Next' MapNode (const TheKeyType& theKey, - NCollection_ListNode* theNext) : - NCollection_TListNode (theKey, theNext) {} + NCollection_ListNode* theNext, + MapNode* theNextSeq, + MapNode* thePrevSeq) + : NCollection_TListNode (theKey, theNext), + myNext(theNextSeq), + myPrevious(thePrevSeq) {} //! Constructor with 'Next' MapNode (TheKeyType&& theKey, - NCollection_ListNode* theNext) : - NCollection_TListNode (std::forward(theKey), theNext) {} - //! Key - const TheKeyType& Key (void) - { return this->Value(); } - + NCollection_ListNode* theNext, + MapNode* theNextSeq, + MapNode* thePrevSeq) + : NCollection_TListNode (std::forward(theKey), theNext), + myNext(theNextSeq), + myPrevious(thePrevSeq) {} + //! Duplicate the value interface for the set + const TheKeyType& Key (void) { return this->Value(); } + //! Sequence node access + MapNode* CurSeq () const { return this; } + MapNode* NextSeq () const { return myNext; } + MapNode* PrevSeq () const { return myPrevious; } + void SetNextSeq (MapNode* theNext) { myNext = theNext; } + void SetPrevSeq (MapNode* thePrev) { myPrevious = thePrev; } + private: + MapNode* myNext; + MapNode* myPrevious; }; public: //! Implementation of the Iterator interface. - class Iterator : public NCollection_BaseMap::Iterator + class Iterator { public: - //! Empty constructor - Iterator (void) : - NCollection_BaseMap::Iterator() {} //! Constructor Iterator (const NCollection_Map& theMap) : - NCollection_BaseMap::Iterator(theMap) {} + myFirst(theMap.myFirst), + myLast(theMap.myLast), + myNode(myFirst) {} + + Iterator() = default; + + void Initialize (const NCollection_Map& theMap) + { + myFirst = theMap.myFirst; + myLast = theMap.myLast; + myNode = myFirst; + } + //! Performs comparison of two iterators. + Standard_Boolean IsEqual (const Iterator& theOther) const + { + return myFirst == theOther.myFirst && myLast == theOther.myLast && myNode == theOther.myNode; + } //! Query if the end of collection is reached by iterator Standard_Boolean More(void) const - { return PMore(); } + { return myNode != nullptr && myNode != myLast; } //! Make a step along the collection void Next(void) - { PNext(); } + { myNode = myNode == nullptr? nullptr : myNode->NextSeq(); } //! Value inquiry const TheKeyType& Value(void) const { Standard_NoSuchObject_Raise_if (!More(), "NCollection_Map::Iterator::Value"); - return ((MapNode *) myNode)->Value(); + return myNode->Value(); } - //! Key const TheKeyType& Key (void) const { Standard_NoSuchObject_Raise_if (!More(), "NCollection_Map::Iterator::Key"); - return ((MapNode *) myNode)->Value(); + return myNode->Value(); } + private: + MapNode* myFirst = nullptr; + MapNode* myLast = nullptr; + MapNode* myNode = nullptr; }; //! Shorthand for a constant iterator type. @@ -191,34 +222,22 @@ public: } //! ReSize - void ReSize (const Standard_Integer N) + void ReSize (const Standard_Integer theLength) { - NCollection_ListNode** newdata = 0L; - NCollection_ListNode** dummy = 0L; - Standard_Integer newBuck; - if (BeginResize (N, newBuck, newdata, dummy)) + if (Reallocate(theLength)) { - if (myData1) + MapNode* aNode = myFirst; + while (aNode) { - MapNode** olddata = (MapNode**) myData1; - MapNode *p, *q; - for (int i = 0; i <= NbBuckets(); i++) + const size_t aHashCode = HashCode(((MapNode*)aNode)->Key(), NbBuckets()); + NCollection_ListNode* aNodePlacement = myData1[aHashCode]; + myData1[aHashCode] = aNode; + if (aNodePlacement) { - if (olddata[i]) - { - p = olddata[i]; - while (p) - { - const size_t k = HashCode(p->Key(),newBuck); - q = (MapNode*) p->Next(); - p->Next() = newdata[k]; - newdata[k] = p; - p = q; - } - } + aNode->Next() = aNodePlacement; } + aNode = aNode->NextSeq(); } - EndResize (N, newBuck, newdata, dummy); } } @@ -227,15 +246,15 @@ public: { if (Resizable()) ReSize(Extent()); - MapNode* aNode; + MapNode* aTempNode; size_t aHash; - if (lookup(theKey, aNode, aHash)) + if (lookup(theKey, aTempNode, aHash)) { return Standard_False; } - MapNode** data = (MapNode**)myData1; - data[aHash] = new (this->myAllocator) MapNode(theKey,data[aHash]); - Increment(); + MapNode*& aNode = (MapNode*&)myData1[aHash]; + aNode = new (this->myAllocator) MapNode(theKey, aNode, myLast, nullptr); + Increment(aNode); return Standard_True; } @@ -244,15 +263,15 @@ public: { if (Resizable()) ReSize(Extent()); - MapNode* aNode; + MapNode* aTempNode; size_t aHash; - if (lookup(theKey, aNode, aHash)) + if (lookup(theKey, aTempNode, aHash)) { return Standard_False; } - MapNode** data = (MapNode**)myData1; - data[aHash] = new (this->myAllocator) MapNode(std::forward(theKey),data[aHash]); - Increment(); + MapNode*& aNode = (MapNode*&)myData1[aHash]; + aNode = new (this->myAllocator) MapNode(std::forward(theKey), aNode, myLast, nullptr); + Increment(aNode); return Standard_True; } @@ -262,16 +281,16 @@ public: { if (Resizable()) ReSize(Extent()); - MapNode* aNode; + MapNode* aTempNode; size_t aHash; - if (lookup(theKey, aNode, aHash)) + if (lookup(theKey, aTempNode, aHash)) { - return aNode->Key(); + return aTempNode->Key(); } - MapNode** data = (MapNode**)myData1; - data[aHash] = new (this->myAllocator) MapNode(theKey,data[aHash]); - Increment(); - return data[aHash]->Key(); + MapNode*& aNode = (MapNode*&)myData1[aHash]; + aNode = new (this->myAllocator) MapNode(theKey, aNode, myLast, nullptr); + Increment(aNode); + return aNode->Key(); } //! Added: add a new key if not yet in the map, and return @@ -280,16 +299,16 @@ public: { if (Resizable()) ReSize(Extent()); - MapNode* aNode; + MapNode* aTempNode; size_t aHash; - if (lookup(theKey, aNode, aHash)) + if (lookup(theKey, aTempNode, aHash)) { - return aNode->Key(); + return aTempNode->Key(); } - MapNode** data = (MapNode**)myData1; - data[aHash] = new (this->myAllocator) MapNode(std::forward(theKey),data[aHash]); - Increment(); - return data[aHash]->Key(); + MapNode*& aNode = (MapNode*&)myData1[aHash]; + aNode = new (this->myAllocator) MapNode(std::forward(theKey), aNode, myLast, nullptr); + Increment(aNode); + return aNode->Key(); } //! Contains @@ -300,29 +319,41 @@ public: } //! Remove - Standard_Boolean Remove(const TheKeyType& K) + Standard_Boolean Remove(const TheKeyType& theKey) { if (IsEmpty()) return Standard_False; - MapNode** data = (MapNode**) myData1; - const size_t k = HashCode(K,NbBuckets()); - MapNode* p = data[k]; - MapNode* q = NULL; - while (p) + const size_t aHashCode = HashCode(theKey, NbBuckets()); + MapNode* aCurNode = (MapNode*)myData1[aHashCode]; + MapNode* aPrevNode = nullptr; + while (aCurNode) { - if (IsEqual(p->Key(),K)) + if (IsEqual(aCurNode->Key(), theKey)) { Decrement(); - if (q) - q->Next() = p->Next(); + if (aPrevNode) + { + aPrevNode->Next() = aCurNode->Next(); + aPrevNode->SetNextSeq(aCurNode->NextSeq()); + } else - data[k] = (MapNode*) p->Next(); - p->~MapNode(); - this->myAllocator->Free(p); + { + myData1[aHashCode] = aCurNode->Next(); + } + if (aCurNode == myFirst) + { + myFirst = aCurNode->NextSeq(); + } + if (aCurNode == myLast) + { + myLast = aCurNode->PrevSeq(); + } + aCurNode->~MapNode(); + this->myAllocator->Free(aCurNode); return Standard_True; } - q = p; - p = (MapNode*) p->Next(); + aPrevNode = aCurNode; + aCurNode = (MapNode*)aCurNode->Next(); } return Standard_False; } @@ -330,7 +361,7 @@ public: //! Clear data. If doReleaseMemory is false then the table of //! buckets is not released and will be reused. void Clear(const Standard_Boolean doReleaseMemory = Standard_False) - { Destroy (MapNode::delNode, doReleaseMemory); } + { Destroy (MapNode::delNode, doReleaseMemory); myFirst = myLast = nullptr; } //! Clear data and reset allocator void Clear (const Handle(NCollection_BaseAllocator)& theAllocator) @@ -665,17 +696,8 @@ protected: //! @return true if key is found Standard_Boolean lookup(const TheKeyType& theKey, MapNode*& theNode) const { - if (IsEmpty()) - return Standard_False; // Not found - for (theNode = (MapNode*)myData1[HashCode(theKey, NbBuckets())]; - theNode; theNode = (MapNode*)theNode->Next()) - { - if (IsEqual(theNode->Key(), theKey)) - { - return Standard_True; - } - } - return Standard_False; // Not found + size_t aHash; + return lookup(theKey, theNode, aHash); } bool IsEqual(const TheKeyType& theKey1, @@ -689,9 +711,24 @@ protected: { return myHasher(theKey) % theUpperBound + 1; } -protected: + void Increment (MapNode* theNode) + { + if (myLast) + { + myLast->SetNextSeq(theNode); + } + if (!myFirst) + { + myFirst = theNode; + } + NCollection_BaseMap::Increment(); + } + +protected: Hasher myHasher; + MapNode* myFirst = nullptr; + MapNode* myLast = nullptr; }; #endif diff --git a/src/NCollection/NCollection_Primes.hxx b/src/NCollection/NCollection_Primes.hxx new file mode 100644 index 0000000000..5b7ce8a52b --- /dev/null +++ b/src/NCollection/NCollection_Primes.hxx @@ -0,0 +1,75 @@ +// Copyright (c) 2024 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _NCollection_Primes_HeaderFile +#define _NCollection_Primes_HeaderFile + +#include +#include + +//! Namespace provides a collection of prime numbers. +//! +//! This class is used to store a collection of prime numbers that are used as +//! consecutive steps for the size of an array of buckets in a map. The prime +//! numbers are chosen to minimize the probability of having the same hash codes +//! for different map items. The class also provides a method to find the next +//! prime number greater than or equal to a given number. +namespace NCollection_Primes +{ + //! The array of prime numbers used as consecutive steps for + //! size of array of buckets in the map. + //! The prime numbers are used for array size with the hope that this will + //! lead to less probability of having the same hash codes for + //! different map items (note that all hash codes are modulo that size). + //! The value of each next step is chosen to be ~2 times greater than previous. + //! Though this could be thought as too much, actually the amount of + //! memory overhead in that case is only ~15% as compared with total size of + //! all auxiliary data structures (each map node takes ~24 bytes), + //! and this proves to pay off in performance (see OCC13189). + //! + //! The following are Pierpont primes, prime numbers of the form 2^u * 3^v + 1 + static constexpr Standard_Integer PrimeVector[] = {101, 1009, 2003, 5003, 10007, 20011, + 37003, 57037, 65003, 100019, 209953, 472393, + 995329, 2359297, 4478977, 9437185, 17915905, 35831809, + 71663617, 150994945, 301989889, 573308929, 1019215873, 2038431745}; + + //! The number of prime numbers in the array. + static constexpr Standard_Integer NbPrimes = sizeof(PrimeVector) / sizeof(Standard_Integer); + + //! Returns the next prime number greater than or equal to theN. + static Standard_Integer NextPrimeForMap(const Standard_Integer theN) + { + const Standard_Integer* aLow = PrimeVector; + const Standard_Integer* aHigh = PrimeVector + NbPrimes - 1; + + while (aLow <= aHigh) + { + const Standard_Integer* aMid = aLow + (aHigh - aLow) / 2; + if (*aMid > theN) + { + if (aMid == PrimeVector || *(aMid - 1) <= theN) + { + return *aMid; + } + aHigh = aMid - 1; + } + else + { + aLow = aMid + 1; + } + } + throw Standard_OutOfRange("NCollection_Primes::NextPrimeForMap() - requested too big size"); + } +}; + +#endif // _NCollection_Primes_HeaderFile diff --git a/src/TColStd/TColStd_PackedMapOfInteger.cxx b/src/TColStd/TColStd_PackedMapOfInteger.cxx index 55fa98ad8a..5d9cb4264c 100644 --- a/src/TColStd/TColStd_PackedMapOfInteger.cxx +++ b/src/TColStd/TColStd_PackedMapOfInteger.cxx @@ -16,7 +16,7 @@ #include #include -#include +#include namespace { @@ -153,7 +153,7 @@ TColStd_PackedMapOfInteger& TColStd_PackedMapOfInteger::Assign void TColStd_PackedMapOfInteger::ReSize (const Standard_Integer theNbBuckets) { - Standard_Integer aNewBuck = TCollection::NextPrimeForMap (theNbBuckets); + Standard_Integer aNewBuck = NCollection_Primes::NextPrimeForMap (theNbBuckets); if (aNewBuck <= myNbBuckets) { if (!IsEmpty()) diff --git a/src/TCollection/FILES b/src/TCollection/FILES index e9d85856a8..e25280fb4f 100755 --- a/src/TCollection/FILES +++ b/src/TCollection/FILES @@ -1,4 +1,3 @@ -TCollection.cxx TCollection.hxx TCollection_AsciiString.cxx TCollection_AsciiString.hxx diff --git a/src/TCollection/TCollection.cxx b/src/TCollection/TCollection.cxx deleted file mode 100644 index e41ec3565f..0000000000 --- a/src/TCollection/TCollection.cxx +++ /dev/null @@ -1,74 +0,0 @@ -// Created on: 1993-01-14 -// Created by: Remi LEQUETTE -// Copyright (c) 1993-1999 Matra Datavision -// Copyright (c) 1999-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 - -#include - -// The array of prime numbers used as consecutive steps for -// size of array of buckets in the map. -// The prime numbers are used for array size with the hope that this will -// lead to less probability of having the same hash codes for -// different map items (note that all hash codes are modulo that size). -// The value of each next step is chosen to be ~2 times greater than previous. -// Though this could be thought as too much, actually the amount of -// memory overhead in that case is only ~15% as compared with total size of -// all auxiliary data structures (each map node takes ~24 bytes), -// and this proves to pay off in performance (see OCC13189). -#define THE_NB_PRIMES 24 -static const Standard_Integer THE_TCollection_Primes[THE_NB_PRIMES] = -{ - 101, - 1009, - 2003, - 5003, - 10007, - 20011, - 37003, - 57037, - 65003, - 100019, - 209953, // The following are Pierpont primes [List of prime numbers] - 472393, - 995329, - 2359297, - 4478977, - 9437185, - 17915905, - 35831809, - 71663617, - 150994945, - 301989889, - 573308929, - 1019215873, - 2038431745 -}; - -// ======================================================================= -// function : NextPrimeForMap -// purpose : -// ======================================================================= -Standard_Integer TCollection::NextPrimeForMap(const Standard_Integer N) -{ - for (Standard_Integer aPrimeIter = 0; aPrimeIter < THE_NB_PRIMES; ++aPrimeIter) - { - if (THE_TCollection_Primes[aPrimeIter] > N) - { - return THE_TCollection_Primes[aPrimeIter]; - } - } - throw Standard_OutOfRange ("TCollection::NextPrimeForMap() - requested too big size"); -} diff --git a/src/TCollection/TCollection.hxx b/src/TCollection/TCollection.hxx index 9867b943b9..4e0903ba2e 100644 --- a/src/TCollection/TCollection.hxx +++ b/src/TCollection/TCollection.hxx @@ -17,13 +17,15 @@ #ifndef _TCollection_HeaderFile #define _TCollection_HeaderFile +#include + #include #include #include //! The package provides the services for the //! transient basic data structures. -class TCollection +class Standard_DEPRECATED("Deprecated since OCCT 7.9, NCollection_Primes should be used instead of TCollection") TCollection { public: @@ -35,7 +37,10 @@ public: //! around 1 000 000). This is not a limit of the number of //! items but a limit in the number of buckets. i.e. //! there will be more collisions in the map. - Standard_EXPORT static Standard_Integer NextPrimeForMap (const Standard_Integer I); + static Standard_Integer NextPrimeForMap (const Standard_Integer I) + { + return NCollection_Primes::NextPrimeForMap(I); + } }; From 2c6a4fed6e008f795397bf036315c196b79da7d4 Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Sat, 2 Nov 2024 22:14:24 +0000 Subject: [PATCH 2/7] Foundation Classes - Fix linked list management in NCollection_Map --- src/NCollection/NCollection_Map.hxx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/NCollection/NCollection_Map.hxx b/src/NCollection/NCollection_Map.hxx index 20ede2b981..fe35525ed8 100644 --- a/src/NCollection/NCollection_Map.hxx +++ b/src/NCollection/NCollection_Map.hxx @@ -334,19 +334,28 @@ public: if (aPrevNode) { aPrevNode->Next() = aCurNode->Next(); - aPrevNode->SetNextSeq(aCurNode->NextSeq()); } else { myData1[aHashCode] = aCurNode->Next(); } - if (aCurNode == myFirst) + if (aCurNode->PrevSeq()) + { + aCurNode->PrevSeq()->SetNextSeq(aCurNode->NextSeq()); + } + else { myFirst = aCurNode->NextSeq(); + myFirst->SetPrevSeq(nullptr); } - if (aCurNode == myLast) + if (aCurNode->NextSeq()) + { + aCurNode->NextSeq()->SetPrevSeq(aCurNode->PrevSeq()); + } + else { myLast = aCurNode->PrevSeq(); + myLast->SetNextSeq(nullptr); } aCurNode->~MapNode(); this->myAllocator->Free(aCurNode); @@ -717,10 +726,13 @@ protected: if (myLast) { myLast->SetNextSeq(theNode); + myLast = theNode; + theNode->SetPrevSeq(myLast); } - if (!myFirst) + else { myFirst = theNode; + myLast = theNode; } NCollection_BaseMap::Increment(); } From af59c71af4dca17ccece9ee1b32d0a001cfea8e1 Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Sat, 2 Nov 2024 23:20:16 +0000 Subject: [PATCH 3/7] Foundation Classes - Fix MapNode constructor parameter order and improve null checks --- src/NCollection/NCollection_Map.hxx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/NCollection/NCollection_Map.hxx b/src/NCollection/NCollection_Map.hxx index fe35525ed8..107ede75b9 100644 --- a/src/NCollection/NCollection_Map.hxx +++ b/src/NCollection/NCollection_Map.hxx @@ -69,19 +69,19 @@ public: //! Constructor with 'Next' MapNode (const TheKeyType& theKey, NCollection_ListNode* theNext, - MapNode* theNextSeq, - MapNode* thePrevSeq) + MapNode* thePrevSeq, + MapNode* theNextSeq) : NCollection_TListNode (theKey, theNext), - myNext(theNextSeq), - myPrevious(thePrevSeq) {} + myPrevious(thePrevSeq), + myNext(theNextSeq) {} //! Constructor with 'Next' MapNode (TheKeyType&& theKey, NCollection_ListNode* theNext, - MapNode* theNextSeq, - MapNode* thePrevSeq) + MapNode* thePrevSeq, + MapNode* theNextSeq) : NCollection_TListNode (std::forward(theKey), theNext), - myNext(theNextSeq), - myPrevious(thePrevSeq) {} + myPrevious(thePrevSeq), + myNext(theNextSeq) {} //! Duplicate the value interface for the set const TheKeyType& Key (void) { return this->Value(); } //! Sequence node access @@ -91,8 +91,8 @@ public: void SetNextSeq (MapNode* theNext) { myNext = theNext; } void SetPrevSeq (MapNode* thePrev) { myPrevious = thePrev; } private: - MapNode* myNext; MapNode* myPrevious; + MapNode* myNext; }; public: @@ -346,7 +346,8 @@ public: else { myFirst = aCurNode->NextSeq(); - myFirst->SetPrevSeq(nullptr); + if (myFirst) + myFirst->SetPrevSeq(nullptr); } if (aCurNode->NextSeq()) { @@ -355,7 +356,8 @@ public: else { myLast = aCurNode->PrevSeq(); - myLast->SetNextSeq(nullptr); + if (myLast) + myLast->SetNextSeq(nullptr); } aCurNode->~MapNode(); this->myAllocator->Free(aCurNode); @@ -726,8 +728,8 @@ protected: if (myLast) { myLast->SetNextSeq(theNode); - myLast = theNode; theNode->SetPrevSeq(myLast); + myLast = theNode; } else { From a0e3cdb6e07b99edd448d07e4fc514677bf0231b Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Sat, 2 Nov 2024 23:38:29 +0000 Subject: [PATCH 4/7] Foundation Classes - Ensure Next pointer is set to nullptr when no placement is provided in NCollection_Map TODO: destroying rework for indexed and normal maps. --- src/NCollection/NCollection_Map.hxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/NCollection/NCollection_Map.hxx b/src/NCollection/NCollection_Map.hxx index 107ede75b9..ce6a0f4c92 100644 --- a/src/NCollection/NCollection_Map.hxx +++ b/src/NCollection/NCollection_Map.hxx @@ -236,6 +236,10 @@ public: { aNode->Next() = aNodePlacement; } + else + { + aNode->Next() = nullptr; + } aNode = aNode->NextSeq(); } } From d12e566290b252b1a7cb8c1b296aebc5c132f42b Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Sun, 3 Nov 2024 08:44:48 +0000 Subject: [PATCH 5/7] Foundation Classes - Simplify More() method in NCollection_Map to only check for nullptr --- src/NCollection/NCollection_Map.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NCollection/NCollection_Map.hxx b/src/NCollection/NCollection_Map.hxx index ce6a0f4c92..68d77f153a 100644 --- a/src/NCollection/NCollection_Map.hxx +++ b/src/NCollection/NCollection_Map.hxx @@ -121,7 +121,7 @@ public: } //! Query if the end of collection is reached by iterator Standard_Boolean More(void) const - { return myNode != nullptr && myNode != myLast; } + { return myNode != nullptr; } //! Make a step along the collection void Next(void) { myNode = myNode == nullptr? nullptr : myNode->NextSeq(); } From dc6f4e325f8ee221ac94e3ecd3b5b18567be0461 Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Sun, 3 Nov 2024 10:11:15 +0000 Subject: [PATCH 6/7] Foundation Classes - Optimize Exchange method in NCollection_Map to swap first and last pointers --- src/NCollection/NCollection_Map.hxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NCollection/NCollection_Map.hxx b/src/NCollection/NCollection_Map.hxx index 68d77f153a..1dd40bd46c 100644 --- a/src/NCollection/NCollection_Map.hxx +++ b/src/NCollection/NCollection_Map.hxx @@ -185,6 +185,8 @@ public: void Exchange (NCollection_Map& theOther) { this->exchangeMapsData (theOther); + std::swap(myLast, theOther.myLast); + std::swap(myFirst, theOther.myFirst); } //! Assign. @@ -217,7 +219,7 @@ public: { if (this == &theOther) return *this; - exchangeMapsData(theOther); + Exchange(theOther); return *this; } From c0569467cbd9d5022d5979a2090e70857ddc9649 Mon Sep 17 00:00:00 2001 From: dpasukhi Date: Sun, 3 Nov 2024 11:17:53 +0000 Subject: [PATCH 7/7] Foundation Classes - Add resetSize method and enhance Destroy method in NCollection_Map for better memory management --- src/NCollection/NCollection_BaseMap.hxx | 2 ++ src/NCollection/NCollection_Map.hxx | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/NCollection/NCollection_BaseMap.hxx b/src/NCollection/NCollection_BaseMap.hxx index 41eac66863..ff6d5c81f7 100644 --- a/src/NCollection/NCollection_BaseMap.hxx +++ b/src/NCollection/NCollection_BaseMap.hxx @@ -245,6 +245,8 @@ public: NCollection_ListNode ** myData1; NCollection_ListNode ** myData2; + void resetSize() { mySize = 0; } + private: // ---------- PRIVATE FIELDS ------------ Standard_Integer myNbBuckets; diff --git a/src/NCollection/NCollection_Map.hxx b/src/NCollection/NCollection_Map.hxx index 1dd40bd46c..ac16df31fe 100644 --- a/src/NCollection/NCollection_Map.hxx +++ b/src/NCollection/NCollection_Map.hxx @@ -378,7 +378,7 @@ public: //! Clear data. If doReleaseMemory is false then the table of //! buckets is not released and will be reused. void Clear(const Standard_Boolean doReleaseMemory = Standard_False) - { Destroy (MapNode::delNode, doReleaseMemory); myFirst = myLast = nullptr; } + { Destroy (MapNode::delNode, doReleaseMemory); } //! Clear data and reset allocator void Clear (const Handle(NCollection_BaseAllocator)& theAllocator) @@ -388,6 +388,29 @@ public: NCollection_BaseAllocator::CommonBaseAllocator() ); } + //! Deallocate all node elements + void Destroy(NCollection_DelMapNode fDel, Standard_Boolean doReleaseMemory) + { + if (!IsEmpty()) + { + MapNode* aNode = myFirst; + while (aNode) + { + MapNode* aCurNode = aNode; + aNode = aNode->NextSeq(); + fDel (aCurNode, myAllocator); + } + myFirst = myLast = nullptr; + memset(myData1, 0, (NbBuckets() + 1) * sizeof(NCollection_ListNode*)); + resetSize(); + } + if (doReleaseMemory) + { + Standard::Free(myData1); + myData1 = myData2 = nullptr; + } + } + //! Destructor virtual ~NCollection_Map (void) { Clear(true); }