1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-21 10:13:43 +03:00

0029302: Foundation Classes, NCollection - optimize iteration of indexed maps

NCollection_IndexedMap and NCollection_IndexedDataMap
now access Key by Index number without computing Hash code.
IndexedMapNode::myNext2 and IndexedDataMapNode::myNext2 fields
have been removed, so that indexed map now may utilize less memory.

TCollection::NextPrimeForMap() has been extended upto 2038431745
(almost full signed 32-bit integer range),
and NCollection_BaseMap::mySaturated property has been removed.

NCollection_IndexedDataMap::RemoveFromIndex(), FindKey(), FindFromIndex(),
ChangeFromIndex() - removed duplicating checks for out of range input.
This commit is contained in:
kgv 2017-11-08 15:25:51 +03:00 committed by bugmaster
parent f88457e638
commit 510cb85241
5 changed files with 225 additions and 379 deletions

View File

@ -29,7 +29,6 @@ Standard_Boolean NCollection_BaseMap::BeginResize
NCollection_ListNode**& data1, NCollection_ListNode**& data1,
NCollection_ListNode**& data2) const NCollection_ListNode**& data2) const
{ {
if (mySaturated) return Standard_False;
N = NextPrimeForMap(NbBuckets); N = NextPrimeForMap(NbBuckets);
if (N <= myNbBuckets) { if (N <= myNbBuckets) {
if (!myData1) if (!myData1)
@ -57,17 +56,17 @@ Standard_Boolean NCollection_BaseMap::BeginResize
//======================================================================= //=======================================================================
void NCollection_BaseMap::EndResize void NCollection_BaseMap::EndResize
(const Standard_Integer NbBuckets, (const Standard_Integer theNbBuckets,
const Standard_Integer N, const Standard_Integer N,
NCollection_ListNode** data1, NCollection_ListNode** data1,
NCollection_ListNode** data2) NCollection_ListNode** data2)
{ {
(void )theNbBuckets; // obsolete parameter
if (myData1) if (myData1)
myAllocator->Free(myData1); myAllocator->Free(myData1);
if (myData2) if (myData2)
myAllocator->Free(myData2); myAllocator->Free(myData2);
myNbBuckets = N; myNbBuckets = N;
mySaturated = (myNbBuckets <= NbBuckets);
myData1 = data1; myData1 = data1;
myData2 = data2; myData2 = data2;
} }
@ -105,7 +104,6 @@ void NCollection_BaseMap::Destroy (NCollection_DelMapNode fDel,
mySize = 0; mySize = 0;
if (doReleaseMemory) if (doReleaseMemory)
{ {
mySaturated = Standard_False;
if (myData1) if (myData1)
myAllocator->Free(myData1); myAllocator->Free(myData1);
if (isDouble && myData2) if (isDouble && myData2)
@ -124,7 +122,6 @@ void NCollection_BaseMap::Statistics(Standard_OStream& S) const
{ {
S <<"\nMap Statistics\n---------------\n\n"; S <<"\nMap Statistics\n---------------\n\n";
S <<"This Map has "<<myNbBuckets<<" Buckets and "<<mySize<<" Keys\n\n"; S <<"This Map has "<<myNbBuckets<<" Buckets and "<<mySize<<" Keys\n\n";
if (mySaturated) S<<"The maximum number of Buckets is reached\n";
if (mySize == 0) return; if (mySize == 0) return;

View File

@ -162,10 +162,9 @@ public:
const Handle(NCollection_BaseAllocator)& theAllocator) const Handle(NCollection_BaseAllocator)& theAllocator)
: myData1(NULL), : myData1(NULL),
myData2(NULL), myData2(NULL),
isDouble(!single),
mySaturated(Standard_False),
myNbBuckets(NbBuckets), myNbBuckets(NbBuckets),
mySize(0) mySize(0),
isDouble(!single)
{ {
myAllocator = (theAllocator.IsNull() ? NCollection_BaseAllocator::CommonBaseAllocator() : theAllocator); myAllocator = (theAllocator.IsNull() ? NCollection_BaseAllocator::CommonBaseAllocator() : theAllocator);
} }
@ -189,15 +188,13 @@ public:
//! Resizable //! Resizable
Standard_Boolean Resizable() const Standard_Boolean Resizable() const
{ return IsEmpty() || (!mySaturated && (mySize > myNbBuckets)); } { return IsEmpty() || (mySize > myNbBuckets); }
//! Increment //! Increment
void Increment() Standard_Integer Increment() { return ++mySize; }
{ mySize++; }
//! Decrement //! Decrement
void Decrement() Standard_Integer Decrement() { return --mySize; }
{ mySize--; }
//! Destroy //! Destroy
Standard_EXPORT void Destroy(NCollection_DelMapNode fDel, Standard_EXPORT void Destroy(NCollection_DelMapNode fDel,
@ -213,10 +210,9 @@ public:
std::swap (myAllocator, theOther.myAllocator); std::swap (myAllocator, theOther.myAllocator);
std::swap (myData1, theOther.myData1); std::swap (myData1, theOther.myData1);
std::swap (myData2, theOther.myData2); std::swap (myData2, theOther.myData2);
//std::swap (isDouble, theOther.isDouble);
std::swap (mySaturated, theOther.mySaturated);
std::swap (myNbBuckets, theOther.myNbBuckets); std::swap (myNbBuckets, theOther.myNbBuckets);
std::swap (mySize, theOther.mySize); std::swap (mySize, theOther.mySize);
//std::swap (isDouble, theOther.isDouble);
} }
protected: protected:
@ -227,10 +223,9 @@ public:
private: private:
// ---------- PRIVATE FIELDS ------------ // ---------- PRIVATE FIELDS ------------
Standard_Boolean isDouble;
Standard_Boolean mySaturated;
Standard_Integer myNbBuckets; Standard_Integer myNbBuckets;
Standard_Integer mySize; Standard_Integer mySize;
Standard_Boolean isDouble;
// ---------- FRIEND CLASSES ------------ // ---------- FRIEND CLASSES ------------
friend class Iterator; friend class Iterator;

View File

@ -62,25 +62,18 @@ private:
public: public:
//! Constructor with 'Next' //! Constructor with 'Next'
IndexedDataMapNode (const TheKeyType& theKey1, IndexedDataMapNode (const TheKeyType& theKey1,
const Standard_Integer theKey2, const Standard_Integer theIndex,
const TheItemType& theItem, const TheItemType& theItem,
NCollection_ListNode* theNext1, NCollection_ListNode* theNext1)
NCollection_ListNode* theNext2) : : NCollection_TListNode<TheItemType>(theItem,theNext1),
NCollection_TListNode<TheItemType>(theItem,theNext1),
myKey1 (theKey1), myKey1 (theKey1),
myKey2(theKey2), myIndex (theIndex)
myNext2((IndexedDataMapNode*)theNext2)
{ {
} }
//! Key1 //! Key1
TheKeyType& Key1 (void) TheKeyType& Key1() { return myKey1; }
{ return myKey1; } //! Index
//! Key2 Standard_Integer& Index() { return myIndex; }
Standard_Integer& Key2 (void)
{ return myKey2; }
//! Next2
IndexedDataMapNode*& Next2 (void)
{ return myNext2; }
//! Static deleter to be passed to BaseList //! Static deleter to be passed to BaseList
static void delNode (NCollection_ListNode * theNode, static void delNode (NCollection_ListNode * theNode,
@ -91,8 +84,7 @@ private:
} }
private: private:
TheKeyType myKey1; TheKeyType myKey1;
Standard_Integer myKey2; Standard_Integer myIndex;
IndexedDataMapNode * myNext2;
}; };
public: public:
@ -101,13 +93,14 @@ private:
{ {
public: public:
//! Empty constructor //! Empty constructor
Iterator (void) : Iterator()
myMap(NULL), : myMap (NULL),
myNode (NULL),
myIndex (0) {} myIndex (0) {}
//! Constructor //! Constructor
Iterator (const NCollection_IndexedDataMap& theMap) Iterator (const NCollection_IndexedDataMap& theMap)
: myMap ((NCollection_IndexedDataMap* )&theMap), : myMap ((NCollection_IndexedDataMap* )&theMap),
myNode (myMap->nodeFromIndex (1)), myNode (!theMap.IsEmpty() ? (IndexedDataMapNode* )myMap->myData2[0] : NULL),
myIndex (1) {} myIndex (1) {}
//! Query if the end of collection is reached by iterator //! Query if the end of collection is reached by iterator
Standard_Boolean More(void) const Standard_Boolean More(void) const
@ -115,7 +108,7 @@ private:
//! Make a step along the collection //! Make a step along the collection
void Next(void) void Next(void)
{ {
myNode = myMap->nodeFromIndex (++myIndex); myNode = (IndexedDataMapNode* )myMap->myData2[++myIndex - 1];
} }
//! Value access //! Value access
const TheItemType& Value(void) const const TheItemType& Value(void) const
@ -195,18 +188,14 @@ private:
Clear(); Clear();
ReSize (theOther.Extent()-1); ReSize (theOther.Extent()-1);
Standard_Integer i; for (Standard_Integer anIndexIter = 1; anIndexIter <= theOther.Extent(); ++anIndexIter)
for (i=1; i<=theOther.Extent(); i++)
{ {
TheKeyType aKey1 = theOther.FindKey(i); const TheKeyType& aKey1 = theOther.FindKey (anIndexIter);
TheItemType anItem = theOther.FindFromIndex(i); const TheItemType& anItem = theOther.FindFromIndex(anIndexIter);
Standard_Integer iK1 = Hasher::HashCode (aKey1, NbBuckets()); const Standard_Integer iK1 = Hasher::HashCode (aKey1, NbBuckets());
Standard_Integer iK2 = ::HashCode (i, NbBuckets()); IndexedDataMapNode* pNode = new (this->myAllocator) IndexedDataMapNode (aKey1, anIndexIter, anItem, myData1[iK1]);
IndexedDataMapNode * pNode =
new (this->myAllocator) IndexedDataMapNode (aKey1, i, anItem,
myData1[iK1], myData2[iK2]);
myData1[iK1] = pNode; myData1[iK1] = pNode;
myData2[iK2] = pNode; myData2[anIndexIter - 1] = pNode;
Increment(); Increment();
} }
return *this; return *this;
@ -228,22 +217,18 @@ private:
{ {
if (myData1) if (myData1)
{ {
IndexedDataMapNode *p, *q; memcpy (ppNewData2, myData2, sizeof(IndexedDataMapNode*) * Extent());
Standard_Integer i, iK1, iK2; for (Standard_Integer aBucketIter = 0; aBucketIter <= NbBuckets(); ++aBucketIter)
for (i = 0; i <= NbBuckets(); i++)
{ {
if (myData1[i]) if (myData1[aBucketIter])
{ {
p = (IndexedDataMapNode *) myData1[i]; IndexedDataMapNode* p = (IndexedDataMapNode *) myData1[aBucketIter];
while (p) while (p)
{ {
iK1 = Hasher::HashCode (p->Key1(), newBuck); const Standard_Integer iK1 = Hasher::HashCode (p->Key1(), newBuck);
iK2 = ::HashCode (p->Key2(), newBuck); IndexedDataMapNode* q = (IndexedDataMapNode* )p->Next();
q = (IndexedDataMapNode*) p->Next();
p->Next() = ppNewData1[iK1]; p->Next() = ppNewData1[iK1];
p->Next2() = (IndexedDataMapNode*)ppNewData2[iK2];
ppNewData1[iK1] = p; ppNewData1[iK1] = p;
ppNewData2[iK2] = p;
p = q; p = q;
} }
} }
@ -257,23 +242,26 @@ private:
Standard_Integer Add (const TheKeyType& theKey1, const TheItemType& theItem) Standard_Integer Add (const TheKeyType& theKey1, const TheItemType& theItem)
{ {
if (Resizable()) if (Resizable())
{
ReSize(Extent()); ReSize(Extent());
Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets()); }
IndexedDataMapNode * pNode;
pNode = (IndexedDataMapNode *) myData1[iK1]; const Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
IndexedDataMapNode* pNode = (IndexedDataMapNode* )myData1[iK1];
while (pNode) while (pNode)
{ {
if (Hasher::IsEqual (pNode->Key1(), theKey1)) if (Hasher::IsEqual (pNode->Key1(), theKey1))
return pNode->Key2(); {
return pNode->Index();
}
pNode = (IndexedDataMapNode *) pNode->Next(); pNode = (IndexedDataMapNode *) pNode->Next();
} }
Increment();
Standard_Integer iK2 = ::HashCode(Extent(),NbBuckets()); const Standard_Integer aNewIndex = Increment();
pNode = new (this->myAllocator) IndexedDataMapNode (theKey1, Extent(), theItem, pNode = new (this->myAllocator) IndexedDataMapNode (theKey1, aNewIndex, theItem, myData1[iK1]);
myData1[iK1], myData2[iK2]);
myData1[iK1] = pNode; myData1[iK1] = pNode;
myData2[iK2] = pNode; myData2[aNewIndex - 1] = pNode;
return Extent(); return aNewIndex;
} }
//! Contains //! Contains
@ -302,15 +290,14 @@ private:
"NCollection_IndexedDataMap::Substitute : " "NCollection_IndexedDataMap::Substitute : "
"Index is out of range"); "Index is out of range");
IndexedDataMapNode * p;
// check if theKey1 is not already in the map // check if theKey1 is not already in the map
Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets()); const Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
p = (IndexedDataMapNode *) myData1[iK1]; IndexedDataMapNode* p = (IndexedDataMapNode *) myData1[iK1];
while (p) while (p)
{ {
if (Hasher::IsEqual (p->Key1(), theKey1)) if (Hasher::IsEqual (p->Key1(), theKey1))
{ {
if (p->Key2() != theIndex) if (p->Index() != theIndex)
{ {
throw Standard_DomainError ("NCollection_IndexedDataMap::Substitute : " throw Standard_DomainError ("NCollection_IndexedDataMap::Substitute : "
"Attempt to substitute existing key"); "Attempt to substitute existing key");
@ -323,17 +310,10 @@ private:
} }
// Find the node for the index I // Find the node for the index I
Standard_Integer iK2 = ::HashCode (theIndex, NbBuckets()); p = (IndexedDataMapNode* )myData2[theIndex - 1];
p = (IndexedDataMapNode *) myData2[iK2];
while (p)
{
if (p->Key2() == theIndex)
break;
p = (IndexedDataMapNode*) p->Next2();
}
// remove the old key // remove the old key
Standard_Integer iK = Hasher::HashCode (p->Key1(), NbBuckets()); const Standard_Integer iK = Hasher::HashCode (p->Key1(), NbBuckets());
IndexedDataMapNode * q = (IndexedDataMapNode *) myData1[iK]; IndexedDataMapNode * q = (IndexedDataMapNode *) myData1[iK];
if (q == p) if (q == p)
myData1[iK] = (IndexedDataMapNode *) p->Next(); myData1[iK] = (IndexedDataMapNode *) p->Next();
@ -363,71 +343,26 @@ private:
return; return;
} }
const Standard_Integer aK1 = ::HashCode (theIndex1, NbBuckets()); IndexedDataMapNode* aP1 = (IndexedDataMapNode* )myData2[theIndex1 - 1];
const Standard_Integer aK2 = ::HashCode (theIndex2, NbBuckets()); IndexedDataMapNode* aP2 = (IndexedDataMapNode* )myData2[theIndex2 - 1];
std::swap (aP1->Index(), aP2->Index());
IndexedDataMapNode* aP1 = (IndexedDataMapNode*) myData2[aK1]; myData2[theIndex2 - 1] = aP1;
IndexedDataMapNode* aP2 = (IndexedDataMapNode*) myData2[aK2]; myData2[theIndex1 - 1] = aP2;
if (aP1->Key2() == theIndex1)
{
myData2[aK1] = (IndexedDataMapNode *) aP1->Next2();
}
else
{
IndexedDataMapNode* aQ = aP1;
for (aP1 = aQ->Next2(); aP1->Key2() != theIndex1; aQ = aP1, aP1 = aQ->Next2()) { }
aQ->Next2() = aP1->Next2();
}
if (aP2->Key2() == theIndex2)
{
myData2[aK2] = (IndexedDataMapNode *) aP2->Next2();
}
else
{
IndexedDataMapNode* aQ = aP2;
for (aP2 = aQ->Next2(); aP2->Key2() != theIndex2; aQ = aP2, aP2 = aQ->Next2()) { }
aQ->Next2() = aP2->Next2();
}
std::swap (aP1->Key2(),
aP2->Key2());
aP1->Next2() = (IndexedDataMapNode*) myData2[aK2];
myData2[aK2] = aP1;
aP2->Next2() = (IndexedDataMapNode*) myData2[aK1];
myData2[aK1] = aP2;
} }
//! RemoveLast //! RemoveLast
void RemoveLast (void) void RemoveLast (void)
{ {
Standard_OutOfRange_Raise_if (Extent() == 0, "NCollection_IndexedDataMap::RemoveLast"); const Standard_Integer aLastIndex = Extent();
Standard_OutOfRange_Raise_if (aLastIndex == 0, "NCollection_IndexedDataMap::RemoveLast");
IndexedDataMapNode * p, * q;
// Find the node for the last index and remove it // Find the node for the last index and remove it
Standard_Integer iK2 = ::HashCode (Extent(), NbBuckets()); IndexedDataMapNode* p = (IndexedDataMapNode* )myData2[aLastIndex - 1];
p = (IndexedDataMapNode *) myData2[iK2]; myData2[aLastIndex - 1] = NULL;
q = NULL;
while (p)
{
if (p->Key2() == Extent())
break;
q = p;
p = (IndexedDataMapNode*) p->Next2();
}
if (q == NULL)
myData2[iK2] = (IndexedDataMapNode *) p->Next2();
else
q->Next2() = p->Next2();
// remove the key // remove the key
Standard_Integer iK1 = Hasher::HashCode (p->Key1(), NbBuckets()); const Standard_Integer iK1 = Hasher::HashCode (p->Key1(), NbBuckets());
q = (IndexedDataMapNode *) myData1[iK1]; IndexedDataMapNode* q = (IndexedDataMapNode *) myData1[iK1];
if (q == p) if (q == p)
myData1[iK1] = (IndexedDataMapNode *) p->Next(); myData1[iK1] = (IndexedDataMapNode *) p->Next();
else else
@ -443,12 +378,14 @@ private:
//! Remove the key of the given index. //! Remove the key of the given index.
//! Caution! The index of the last key can be changed. //! Caution! The index of the last key can be changed.
void RemoveFromIndex(const Standard_Integer theKey2) void RemoveFromIndex(const Standard_Integer theIndex)
{ {
Standard_OutOfRange_Raise_if(theKey2 < 1 || theKey2 > Extent(), "NCollection_IndexedDataMap::Remove"); const Standard_Integer aLastInd = Extent();
Standard_Integer aLastInd = Extent(); Standard_OutOfRange_Raise_if(theIndex < 1 || theIndex > aLastInd, "NCollection_IndexedDataMap::Remove");
if (theKey2 != aLastInd) if (theIndex != aLastInd)
Swap(theKey2, aLastInd); {
Swap (theIndex, aLastInd);
}
RemoveLast(); RemoveLast();
} }
@ -463,62 +400,46 @@ private:
} }
//! FindKey //! FindKey
const TheKeyType& FindKey (const Standard_Integer theKey2) const const TheKeyType& FindKey (const Standard_Integer theIndex) const
{ {
Standard_OutOfRange_Raise_if (theKey2 < 1 || theKey2 > Extent(), "NCollection_IndexedDataMap::FindKey"); Standard_OutOfRange_Raise_if (theIndex < 1 || theIndex > Extent(), "NCollection_IndexedDataMap::FindKey");
IndexedDataMapNode* aNode = (IndexedDataMapNode* )myData2[theIndex - 1];
IndexedDataMapNode* aNode = nodeFromIndex (theKey2);
if (aNode == NULL)
{
throw Standard_NoSuchObject("NCollection_IndexedDataMap::FindKey");
}
return aNode->Key1(); return aNode->Key1();
} }
//! FindFromIndex //! FindFromIndex
const TheItemType& FindFromIndex (const Standard_Integer theKey2) const const TheItemType& FindFromIndex (const Standard_Integer theIndex) const
{ {
Standard_OutOfRange_Raise_if (theKey2 < 1 || theKey2 > Extent(), "NCollection_IndexedDataMap::FindFromIndex"); Standard_OutOfRange_Raise_if (theIndex < 1 || theIndex > Extent(), "NCollection_IndexedDataMap::FindFromIndex");
IndexedDataMapNode* aNode = (IndexedDataMapNode* )myData2[theIndex - 1];
IndexedDataMapNode* aNode = nodeFromIndex (theKey2);
if (aNode == NULL)
{
throw Standard_NoSuchObject("NCollection_IndexedDataMap::FindFromIndex");
}
return aNode->Value(); return aNode->Value();
} }
//! operator () //! operator ()
const TheItemType& operator() (const Standard_Integer theKey2) const const TheItemType& operator() (const Standard_Integer theIndex) const { return FindFromIndex (theIndex); }
{ return FindFromIndex (theKey2); }
//! ChangeFromIndex //! ChangeFromIndex
TheItemType& ChangeFromIndex (const Standard_Integer theKey2) TheItemType& ChangeFromIndex (const Standard_Integer theIndex)
{ {
Standard_OutOfRange_Raise_if (theKey2 < 1 || theKey2 > Extent(), "NCollection_IndexedDataMap::ChangeFromIndex"); Standard_OutOfRange_Raise_if (theIndex < 1 || theIndex > Extent(), "NCollection_IndexedDataMap::ChangeFromIndex");
IndexedDataMapNode* aNode = (IndexedDataMapNode* )myData2[theIndex - 1];
IndexedDataMapNode* aNode = nodeFromIndex (theKey2);
if (aNode == NULL)
{
throw Standard_NoSuchObject("NCollection_IndexedDataMap::ChangeFromIndex");
}
return aNode->ChangeValue(); return aNode->ChangeValue();
} }
//! operator () //! operator ()
TheItemType& operator() (const Standard_Integer theKey2) TheItemType& operator() (const Standard_Integer theIndex) { return ChangeFromIndex (theIndex); }
{ return ChangeFromIndex (theKey2); }
//! FindIndex //! FindIndex
Standard_Integer FindIndex(const TheKeyType& theKey1) const Standard_Integer FindIndex(const TheKeyType& theKey1) const
{ {
if (IsEmpty()) return 0; if (IsEmpty()) return 0;
IndexedDataMapNode * pNode1 = IndexedDataMapNode* pNode1 = (IndexedDataMapNode* )myData1[Hasher::HashCode(theKey1,NbBuckets())];
(IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
while (pNode1) while (pNode1)
{ {
if (Hasher::IsEqual (pNode1->Key1(), theKey1)) if (Hasher::IsEqual (pNode1->Key1(), theKey1))
return pNode1->Key2(); {
return pNode1->Index();
}
pNode1 = (IndexedDataMapNode*) pNode1->Next(); pNode1 = (IndexedDataMapNode*) pNode1->Next();
} }
return 0; return 0;
@ -529,12 +450,13 @@ private:
{ {
Standard_NoSuchObject_Raise_if (IsEmpty(), "NCollection_IndexedDataMap::FindFromKey"); Standard_NoSuchObject_Raise_if (IsEmpty(), "NCollection_IndexedDataMap::FindFromKey");
IndexedDataMapNode * pNode1 = IndexedDataMapNode* pNode1 = (IndexedDataMapNode* )myData1[Hasher::HashCode(theKey1,NbBuckets())];
(IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
while (pNode1) while (pNode1)
{ {
if (Hasher::IsEqual (pNode1->Key1(), theKey1)) if (Hasher::IsEqual (pNode1->Key1(), theKey1))
{
return pNode1->Value(); return pNode1->Value();
}
pNode1 = (IndexedDataMapNode*) pNode1->Next(); pNode1 = (IndexedDataMapNode*) pNode1->Next();
} }
throw Standard_NoSuchObject("NCollection_IndexedDataMap::FindFromKey"); throw Standard_NoSuchObject("NCollection_IndexedDataMap::FindFromKey");
@ -545,12 +467,13 @@ private:
{ {
Standard_NoSuchObject_Raise_if (IsEmpty(), "NCollection_IndexedDataMap::ChangeFromKey"); Standard_NoSuchObject_Raise_if (IsEmpty(), "NCollection_IndexedDataMap::ChangeFromKey");
IndexedDataMapNode * pNode1 = IndexedDataMapNode* pNode1 = (IndexedDataMapNode* )myData1[Hasher::HashCode(theKey1,NbBuckets())];
(IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
while (pNode1) while (pNode1)
{ {
if (Hasher::IsEqual (pNode1->Key1(), theKey1)) if (Hasher::IsEqual (pNode1->Key1(), theKey1))
{
return pNode1->ChangeValue(); return pNode1->ChangeValue();
}
pNode1 = (IndexedDataMapNode*) pNode1->Next(); pNode1 = (IndexedDataMapNode*) pNode1->Next();
} }
throw Standard_NoSuchObject("NCollection_IndexedDataMap::ChangeFromKey"); throw Standard_NoSuchObject("NCollection_IndexedDataMap::ChangeFromKey");
@ -571,12 +494,13 @@ private:
{ {
if (!IsEmpty()) if (!IsEmpty())
{ {
IndexedDataMapNode * pNode1 = IndexedDataMapNode* pNode1 = (IndexedDataMapNode* )myData1[Hasher::HashCode(theKey1,NbBuckets())];
(IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
while (pNode1) while (pNode1)
{ {
if (Hasher::IsEqual (pNode1->Key1(), theKey1)) if (Hasher::IsEqual (pNode1->Key1(), theKey1))
{
return &pNode1->ChangeValue(); return &pNode1->ChangeValue();
}
pNode1 = (IndexedDataMapNode*) pNode1->Next(); pNode1 = (IndexedDataMapNode*) pNode1->Next();
} }
} }
@ -628,25 +552,6 @@ private:
private: private:
// ----------- PRIVATE METHODS ----------- // ----------- PRIVATE METHODS -----------
//! Find map node associated with specified index.
//! Return NULL if not found (exception-free internal implementation).
IndexedDataMapNode* nodeFromIndex (const Standard_Integer theKey2) const
{
if (Extent() == 0)
{
return NULL;
}
for (IndexedDataMapNode* aNode = (IndexedDataMapNode* )myData2[::HashCode (theKey2, NbBuckets())];
aNode != NULL; aNode = (IndexedDataMapNode* )aNode->Next2())
{
if (aNode->Key2() == theKey2)
{
return aNode;
}
}
return NULL;
}
}; };
#endif #endif

View File

@ -45,29 +45,23 @@ public:
typedef TheKeyType key_type; typedef TheKeyType key_type;
private: private:
// **************** Adaptation of the TListNode to the INDEXEDmap //! Adaptation of the TListNode to the INDEXEDmap
class IndexedMapNode : public NCollection_TListNode<TheKeyType> class IndexedMapNode : public NCollection_TListNode<TheKeyType>
{ {
public: public:
//! Constructor with 'Next' //! Constructor with 'Next'
IndexedMapNode (const TheKeyType& theKey1, IndexedMapNode (const TheKeyType& theKey1,
const Standard_Integer theKey2, const Standard_Integer theIndex,
NCollection_ListNode* theNext1, NCollection_ListNode* theNext1)
NCollection_ListNode* theNext2) : : NCollection_TListNode<TheKeyType> (theKey1, theNext1),
NCollection_TListNode<TheKeyType> (theKey1, theNext1), myIndex (theIndex)
myKey2(theKey2),
myNext2((IndexedMapNode*)theNext2)
{ {
} }
//! Key1 //! Key1
TheKeyType& Key1 (void) TheKeyType& Key1() { return this->ChangeValue(); }
{ return this->ChangeValue(); }
//! Key2 //! Index
Standard_Integer& Key2 (void) Standard_Integer& Index() { return myIndex; }
{ return myKey2; }
//! Next2
IndexedMapNode*& Next2 (void)
{ return myNext2; }
//! Static deleter to be passed to BaseList //! Static deleter to be passed to BaseList
static void delNode (NCollection_ListNode * theNode, static void delNode (NCollection_ListNode * theNode,
@ -78,8 +72,7 @@ public:
} }
private: private:
Standard_Integer myKey2; Standard_Integer myIndex;
IndexedMapNode * myNext2;
}; };
public: public:
@ -157,17 +150,14 @@ public:
Clear(); Clear();
ReSize (theOther.Extent()-1); ReSize (theOther.Extent()-1);
Standard_Integer i, iLength=theOther.Extent(); const Standard_Integer iLength = theOther.Extent();
for (i=1; i<=iLength; i++) for (Standard_Integer anIndexIter = 1; anIndexIter <= iLength; ++anIndexIter)
{ {
TheKeyType aKey1 = theOther(i); const TheKeyType& aKey1 = theOther.FindKey (anIndexIter);
Standard_Integer iK1 = Hasher::HashCode (aKey1, NbBuckets()); const Standard_Integer iK1 = Hasher::HashCode (aKey1, NbBuckets());
Standard_Integer iK2 = ::HashCode (i, NbBuckets()); IndexedMapNode* pNode = new (this->myAllocator) IndexedMapNode (aKey1, anIndexIter, myData1[iK1]);
IndexedMapNode * pNode = new (this->myAllocator) IndexedMapNode (aKey1, i,
myData1[iK1],
myData2[iK2]);
myData1[iK1] = pNode; myData1[iK1] = pNode;
myData2[iK2] = pNode; myData2[anIndexIter - 1] = pNode;
Increment(); Increment();
} }
return *this; return *this;
@ -180,40 +170,33 @@ public:
} }
//! ReSize //! ReSize
void ReSize (const Standard_Integer N) void ReSize (const Standard_Integer theExtent)
{ {
NCollection_ListNode** ppNewData1 = NULL; NCollection_ListNode** ppNewData1 = NULL;
NCollection_ListNode** ppNewData2 = NULL; NCollection_ListNode** ppNewData2 = NULL;
Standard_Integer newBuck; Standard_Integer newBuck;
if (BeginResize (N, newBuck, ppNewData1, ppNewData2)) if (BeginResize (theExtent, newBuck, ppNewData1, ppNewData2))
{ {
if (myData1) if (myData1)
{ {
IndexedMapNode *p, *q; memcpy (ppNewData2, myData2, sizeof(IndexedMapNode*) * Extent());
Standard_Integer i, iK1, iK2; for (Standard_Integer aBucketIter = 0; aBucketIter <= NbBuckets(); ++aBucketIter)
for (i = 0; i <= NbBuckets(); i++)
{ {
if (myData1[i]) if (myData1[aBucketIter])
{ {
p = (IndexedMapNode *) myData1[i]; IndexedMapNode* p = (IndexedMapNode* )myData1[aBucketIter];
while (p) while (p)
{ {
iK1 =Hasher::HashCode(p->Key1(), newBuck); const Standard_Integer iK1 = Hasher::HashCode (p->Key1(), newBuck);
q = (IndexedMapNode*) p->Next(); IndexedMapNode* q = (IndexedMapNode* )p->Next();
p->Next() = ppNewData1[iK1]; p->Next() = ppNewData1[iK1];
ppNewData1[iK1] = p; ppNewData1[iK1] = p;
if (p->Key2() > 0)
{
iK2 = ::HashCode (p->Key2(), newBuck);
p->Next2() = (IndexedMapNode*)ppNewData2[iK2];
ppNewData2[iK2] = p;
}
p = q; p = q;
} }
} }
} }
} }
EndResize (N, newBuck, ppNewData1, ppNewData2); EndResize (theExtent, newBuck, ppNewData1, ppNewData2);
} }
} }
@ -221,23 +204,26 @@ public:
Standard_Integer Add (const TheKeyType& theKey1) Standard_Integer Add (const TheKeyType& theKey1)
{ {
if (Resizable()) if (Resizable())
{
ReSize (Extent()); ReSize (Extent());
}
Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets()); Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
IndexedMapNode * pNode; IndexedMapNode* pNode = (IndexedMapNode* )myData1[iK1];
pNode = (IndexedMapNode *) myData1[iK1];
while (pNode) while (pNode)
{ {
if (Hasher::IsEqual (pNode->Key1(), theKey1)) if (Hasher::IsEqual (pNode->Key1(), theKey1))
return pNode->Key2(); {
return pNode->Index();
}
pNode = (IndexedMapNode *) pNode->Next(); pNode = (IndexedMapNode *) pNode->Next();
} }
Increment();
Standard_Integer iK2 = ::HashCode(Extent(),NbBuckets()); const Standard_Integer aNewIndex = Increment();
pNode = new (this->myAllocator) IndexedMapNode (theKey1, Extent(), pNode = new (this->myAllocator) IndexedMapNode (theKey1, aNewIndex, myData1[iK1]);
myData1[iK1], myData2[iK2]);
myData1[iK1] = pNode; myData1[iK1] = pNode;
myData2[iK2] = pNode; myData2[aNewIndex - 1] = pNode;
return Extent(); return aNewIndex;
} }
//! Contains //! Contains
@ -265,15 +251,14 @@ public:
"NCollection_IndexedMap::Substitute : " "NCollection_IndexedMap::Substitute : "
"Index is out of range"); "Index is out of range");
IndexedMapNode * p;
// check if theKey1 is not already in the map // check if theKey1 is not already in the map
Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets()); Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
p = (IndexedMapNode *) myData1[iK1]; IndexedMapNode* p = (IndexedMapNode *) myData1[iK1];
while (p) while (p)
{ {
if (Hasher::IsEqual (p->Key1(), theKey1)) if (Hasher::IsEqual (p->Key1(), theKey1))
{ {
if (p->Key2() != theIndex) if (p->Index() != theIndex)
{ {
throw Standard_DomainError ("NCollection_IndexedMap::Substitute : " throw Standard_DomainError ("NCollection_IndexedMap::Substitute : "
"Attempt to substitute existing key"); "Attempt to substitute existing key");
@ -285,14 +270,7 @@ public:
} }
// Find the node for the index I // Find the node for the index I
Standard_Integer iK2 = ::HashCode (theIndex, NbBuckets()); p = (IndexedMapNode* )myData2[theIndex - 1];
p = (IndexedMapNode *) myData2[iK2];
while (p)
{
if (p->Key2() == theIndex)
break;
p = (IndexedMapNode*) p->Next2();
}
// remove the old key // remove the old key
Standard_Integer iK = Hasher::HashCode (p->Key1(), NbBuckets()); Standard_Integer iK = Hasher::HashCode (p->Key1(), NbBuckets());
@ -324,71 +302,26 @@ public:
return; return;
} }
const Standard_Integer aK1 = ::HashCode (theIndex1, NbBuckets()); IndexedMapNode* aP1 = (IndexedMapNode* )myData2[theIndex1 - 1];
const Standard_Integer aK2 = ::HashCode (theIndex2, NbBuckets()); IndexedMapNode* aP2 = (IndexedMapNode* )myData2[theIndex2 - 1];
std::swap (aP1->Index(), aP2->Index());
IndexedMapNode* aP1 = (IndexedMapNode*) myData2[aK1]; myData2[theIndex2 - 1] = aP1;
IndexedMapNode* aP2 = (IndexedMapNode*) myData2[aK2]; myData2[theIndex1 - 1] = aP2;
if (aP1->Key2() == theIndex1)
{
myData2[aK1] = (IndexedMapNode *) aP1->Next2();
}
else
{
IndexedMapNode* aQ = aP1;
for (aP1 = aQ->Next2(); aP1->Key2() != theIndex1; aQ = aP1, aP1 = aQ->Next2()) { }
aQ->Next2() = aP1->Next2();
}
if (aP2->Key2() == theIndex2)
{
myData2[aK2] = (IndexedMapNode *) aP2->Next2();
}
else
{
IndexedMapNode* aQ = aP2;
for (aP2 = aQ->Next2(); aP2->Key2() != theIndex2; aQ = aP2, aP2 = aQ->Next2()) { }
aQ->Next2() = aP2->Next2();
}
std::swap (aP1->Key2(),
aP2->Key2());
aP1->Next2() = (IndexedMapNode*) myData2[aK2];
myData2[aK2] = aP1;
aP2->Next2() = (IndexedMapNode*) myData2[aK1];
myData2[aK1] = aP2;
} }
//! RemoveLast //! RemoveLast
void RemoveLast (void) void RemoveLast (void)
{ {
Standard_OutOfRange_Raise_if (Extent() == 0, "NCollection_IndexedMap::RemoveLast"); const Standard_Integer aLastIndex = Extent();
Standard_OutOfRange_Raise_if (aLastIndex == 0, "NCollection_IndexedMap::RemoveLast");
IndexedMapNode * p, * q;
// Find the node for the last index and remove it // Find the node for the last index and remove it
Standard_Integer iK2 = ::HashCode (Extent(), NbBuckets()); IndexedMapNode* p = (IndexedMapNode* )myData2[aLastIndex - 1];
p = (IndexedMapNode *) myData2[iK2]; myData2[aLastIndex - 1] = NULL;
q = NULL;
while (p)
{
if (p->Key2() == Extent())
break;
q = p;
p = (IndexedMapNode*) p->Next2();
}
if (q == NULL)
myData2[iK2] = (IndexedMapNode *) p->Next2();
else
q->Next2() = p->Next2();
// remove the key // remove the key
Standard_Integer iK1 = Hasher::HashCode (p->Key1(), NbBuckets()); Standard_Integer iK1 = Hasher::HashCode (p->Key1(), NbBuckets());
q = (IndexedMapNode *) myData1[iK1]; IndexedMapNode* q = (IndexedMapNode *) myData1[iK1];
if (q == p) if (q == p)
myData1[iK1] = (IndexedMapNode *) p->Next(); myData1[iK1] = (IndexedMapNode *) p->Next();
else else
@ -404,12 +337,14 @@ public:
//! Remove the key of the given index. //! Remove the key of the given index.
//! Caution! The index of the last key can be changed. //! Caution! The index of the last key can be changed.
void RemoveFromIndex(const Standard_Integer theKey2) void RemoveFromIndex(const Standard_Integer theIndex)
{ {
Standard_OutOfRange_Raise_if(theKey2 < 1 || theKey2 > Extent(), "NCollection_IndexedMap::Remove"); Standard_OutOfRange_Raise_if(theIndex < 1 || theIndex > Extent(), "NCollection_IndexedMap::RemoveFromIndex");
Standard_Integer aLastInd = Extent(); const Standard_Integer aLastInd = Extent();
if (theKey2 != aLastInd) if (theIndex != aLastInd)
Swap(theKey2, aLastInd); {
Swap(theIndex, aLastInd);
}
RemoveLast(); RemoveLast();
} }
@ -428,35 +363,28 @@ public:
} }
//! FindKey //! FindKey
const TheKeyType& FindKey (const Standard_Integer theKey2) const const TheKeyType& FindKey (const Standard_Integer theIndex) const
{ {
Standard_OutOfRange_Raise_if (theKey2 < 1 || theKey2 > Extent(), "NCollection_IndexedMap::FindKey"); Standard_OutOfRange_Raise_if (theIndex < 1 || theIndex > Extent(), "NCollection_IndexedMap::FindKey");
IndexedMapNode* pNode2 = (IndexedMapNode* )myData2[theIndex - 1];
IndexedMapNode * pNode2 =
(IndexedMapNode *) myData2[::HashCode(theKey2,NbBuckets())];
while (pNode2)
{
if (pNode2->Key2() == theKey2)
return pNode2->Key1(); return pNode2->Key1();
pNode2 = (IndexedMapNode*) pNode2->Next2();
}
throw Standard_NoSuchObject("NCollection_IndexedMap::FindKey");
} }
//! operator () //! operator ()
const TheKeyType& operator() (const Standard_Integer theKey2) const const TheKeyType& operator() (const Standard_Integer theIndex) const
{ return FindKey (theKey2); } { return FindKey (theIndex); }
//! FindIndex //! FindIndex
Standard_Integer FindIndex(const TheKeyType& theKey1) const Standard_Integer FindIndex(const TheKeyType& theKey1) const
{ {
if (IsEmpty()) return 0; if (IsEmpty()) return 0;
IndexedMapNode * pNode1 = IndexedMapNode* pNode1 = (IndexedMapNode* )myData1[Hasher::HashCode(theKey1,NbBuckets())];
(IndexedMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
while (pNode1) while (pNode1)
{ {
if (Hasher::IsEqual (pNode1->Key1(), theKey1)) if (Hasher::IsEqual (pNode1->Key1(), theKey1))
return pNode1->Key2(); {
return pNode1->Index();
}
pNode1 = (IndexedMapNode*) pNode1->Next(); pNode1 = (IndexedMapNode*) pNode1->Next();
} }
return 0; return 0;

View File

@ -14,9 +14,10 @@
// Alternatively, this file may be used under the terms of Open CASCADE // Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement. // commercial license or contractual agreement.
#include <TCollection.hxx> #include <TCollection.hxx>
#include <Standard_OutOfRange.hxx>
// The array of prime numbers used as consequtive steps for // The array of prime numbers used as consequtive steps for
// size of array of buckets in the map. // size of array of buckets in the map.
// The prime numbers are used for array size with the hope that this will // The prime numbers are used for array size with the hope that this will
@ -27,8 +28,9 @@
// memory overhead in that case is only ~15% as compared with total size 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), // all auxiliary data structures (each map node takes ~24 bytes),
// and this proves to pay off in performance (see OCC13189). // and this proves to pay off in performance (see OCC13189).
#define NB_PRIMES 12 #define THE_NB_PRIMES 24
static const Standard_Integer Primes[NB_PRIMES+1] = { static const Standard_Integer THE_TCollection_Primes[THE_NB_PRIMES] =
{
101, 101,
1009, 1009,
2003, 2003,
@ -39,15 +41,34 @@ static const Standard_Integer Primes[NB_PRIMES+1] = {
57037, 57037,
65003, 65003,
100019, 100019,
209953, // The following are Pierpont primes taken from Wikipedia [List of prime numbers] 209953, // The following are Pierpont primes [List of prime numbers]
472393, 472393,
995329 995329,
2359297,
4478977,
9437185,
17915905,
35831809,
71663617,
150994945,
301989889,
573308929,
1019215873,
2038431745
}; };
// =======================================================================
// function : NextPrimeForMap
// purpose :
// =======================================================================
Standard_Integer TCollection::NextPrimeForMap(const Standard_Integer N) Standard_Integer TCollection::NextPrimeForMap(const Standard_Integer N)
{ {
Standard_Integer i; for (Standard_Integer aPrimeIter = 0; aPrimeIter < THE_NB_PRIMES; ++aPrimeIter)
for (i = 0; i < NB_PRIMES; i++) {
if (Primes[i] > N) break; if (THE_TCollection_Primes[aPrimeIter] > N)
return Primes[i]; {
return THE_TCollection_Primes[aPrimeIter];
}
}
throw Standard_OutOfRange ("TCollection::NextPrimeForMap() - requested too big size");
} }