1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +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

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

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

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

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

@ -14,9 +14,10 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <TCollection.hxx>
#include <Standard_OutOfRange.hxx>
// The array of prime numbers used as consequtive steps for
// size of array of buckets in the map.
// The prime numbers are used for array size with the hope that this will
@ -27,27 +28,47 @@
// 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 NB_PRIMES 12
static const Standard_Integer Primes[NB_PRIMES+1] = {
101,
1009,
2003,
5003,
10007,
20011,
37003,
57037,
65003,
100019,
209953, // The following are Pierpont primes taken from Wikipedia [List of prime numbers]
472393,
995329
};
#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)
{
Standard_Integer i;
for (i = 0; i < NB_PRIMES; i++)
if (Primes[i] > N) break;
return Primes[i];
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");
}