1 // Created on: 2002-04-24
2 // Created by: Alexander KARTOMIN (akm)
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and / or modify it
8 // under the terms of the GNU Lesser General Public version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #ifndef NCollection_IndexedDataMap_HeaderFile
17 #define NCollection_IndexedDataMap_HeaderFile
19 #include <NCollection_BaseCollection.hxx>
20 #include <NCollection_BaseMap.hxx>
21 #include <NCollection_TListNode.hxx>
22 #include <Standard_TypeMismatch.hxx>
23 #include <Standard_NoSuchObject.hxx>
25 #include <NCollection_DefaultHasher.hxx>
27 #if !defined No_Exception && !defined No_Standard_OutOfRange
28 #include <Standard_OutOfRange.hxx>
32 * Purpose: An indexed map is used to store keys and to bind
33 * an index to them. Each new key stored in the map
34 * gets an index. Index are incremented as keys are
35 * stored in the map. A key can be found by the index
36 * and an index by the key. No key but the last can
37 * be removed so the indices are in the range 1..
38 * Extent. An Item is stored with each key.
40 * This class is similar to IndexedMap from
41 * NCollection with the Item as a new feature. Note
42 * the important difference on the operator (). In
43 * the IndexedMap this operator returns the Key. In
44 * the IndexedDataMap this operator returns the Item.
46 * See the class Map from NCollection for a
47 * discussion about the number of buckets.
50 template < class TheKeyType,
52 class Hasher = NCollection_DefaultHasher<TheKeyType> >
53 class NCollection_IndexedDataMap
54 : public NCollection_BaseCollection<TheItemType>,
55 public NCollection_BaseMap
57 //! Adaptation of the TListNode to the INDEXEDDatamap
59 class IndexedDataMapNode : public NCollection_TListNode<TheItemType>
62 //! Constructor with 'Next'
63 IndexedDataMapNode (const TheKeyType& theKey1,
64 const Standard_Integer theKey2,
65 const TheItemType& theItem,
66 NCollection_ListNode* theNext1,
67 NCollection_ListNode* theNext2) :
68 NCollection_TListNode<TheItemType>(theItem,theNext1)
72 myNext2 = (IndexedDataMapNode *) theNext2;
75 TheKeyType& Key1 (void)
78 const Standard_Integer& Key2 (void)
81 IndexedDataMapNode*& Next2 (void)
84 //! Static deleter to be passed to BaseList
85 static void delNode (NCollection_ListNode * theNode,
86 Handle(NCollection_BaseAllocator)& theAl)
88 ((IndexedDataMapNode *) theNode)->~IndexedDataMapNode();
93 Standard_Integer myKey2;
94 IndexedDataMapNode * myNext2;
98 //! Implementation of the Iterator interface.
99 class Iterator : public NCollection_BaseCollection<TheItemType>::Iterator
102 //! Empty constructor
107 Iterator (const NCollection_IndexedDataMap& theMap) :
108 myMap((NCollection_IndexedDataMap *) &theMap),
110 //! Query if the end of collection is reached by iterator
111 virtual Standard_Boolean More(void) const
112 { return (myIndex <= myMap->Extent()); }
113 //! Make a step along the collection
114 virtual void Next(void)
117 virtual const TheItemType& Value(void) const
119 #if !defined No_Exception && !defined No_Standard_NoSuchObject
121 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::Iterator::Value");
123 return myMap->FindFromIndex(myIndex);
125 //! ChangeValue access
126 virtual TheItemType& ChangeValue(void) const
128 #if !defined No_Exception && !defined No_Standard_NoSuchObject
130 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::Iterator::ChangeValue");
132 return myMap->ChangeFromIndex(myIndex);
136 NCollection_IndexedDataMap * myMap; //!< Pointer to the map being iterated
137 Standard_Integer myIndex; //!< Current index
141 // ---------- PUBLIC METHODS ------------
144 NCollection_IndexedDataMap (const Standard_Integer NbBuckets=1,
145 const Handle(NCollection_BaseAllocator)& theAllocator = 0L)
146 : NCollection_BaseCollection<TheItemType>(theAllocator),
147 NCollection_BaseMap (NbBuckets, Standard_False) {}
150 NCollection_IndexedDataMap (const NCollection_IndexedDataMap& theOther)
151 : NCollection_BaseCollection<TheItemType>(theOther.myAllocator),
152 NCollection_BaseMap (theOther.NbBuckets(), Standard_False)
153 { *this = theOther; }
155 //! Assign another collection
156 virtual void Assign(const NCollection_BaseCollection<TheItemType>& theOther)
158 if (this == &theOther)
160 Standard_TypeMismatch::Raise("NCollection_IndexedDataMap::Assign");
163 //! Exchange the content of two maps without re-allocations.
164 //! Notice that allocators will be swapped as well!
165 void Exchange (NCollection_IndexedDataMap& theOther)
167 this->exchangeAllocators (theOther);
168 this->exchangeMapsData (theOther);
172 NCollection_IndexedDataMap& operator=
173 (const NCollection_IndexedDataMap& theOther)
175 if (this == &theOther)
178 Clear(theOther.myAllocator);
179 ReSize (theOther.Extent()-1);
181 for (i=1; i<=theOther.Extent(); i++)
183 TheKeyType aKey1 = theOther.FindKey(i);
184 TheItemType anItem = theOther.FindFromIndex(i);
185 Standard_Integer iK1 = Hasher::HashCode (aKey1, NbBuckets());
186 Standard_Integer iK2 = ::HashCode (i, NbBuckets());
187 IndexedDataMapNode * pNode =
188 new (this->myAllocator) IndexedDataMapNode (aKey1, i, anItem,
189 myData1[iK1], myData2[iK2]);
190 myData1[iK1] = pNode;
191 myData2[iK2] = pNode;
198 void ReSize (const Standard_Integer N)
200 NCollection_ListNode** ppNewData1 = NULL;
201 NCollection_ListNode** ppNewData2 = NULL;
202 Standard_Integer newBuck;
203 if (BeginResize (N, newBuck, ppNewData1, ppNewData2, this->myAllocator))
207 IndexedDataMapNode *p, *q;
208 Standard_Integer i, iK1, iK2;
209 for (i = 0; i <= NbBuckets(); i++)
213 p = (IndexedDataMapNode *) myData1[i];
216 iK1 = Hasher::HashCode (p->Key1(), newBuck);
217 iK2 = ::HashCode (p->Key2(), newBuck);
218 q = (IndexedDataMapNode*) p->Next();
219 p->Next() = ppNewData1[iK1];
220 p->Next2() = (IndexedDataMapNode*)ppNewData2[iK2];
228 EndResize (N, newBuck, ppNewData1, ppNewData2, this->myAllocator);
233 Standard_Integer Add (const TheKeyType& theKey1, const TheItemType& theItem)
237 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
238 IndexedDataMapNode * pNode;
239 pNode = (IndexedDataMapNode *) myData1[iK1];
242 if (Hasher::IsEqual (pNode->Key1(), theKey1))
243 return pNode->Key2();
244 pNode = (IndexedDataMapNode *) pNode->Next();
247 Standard_Integer iK2 = ::HashCode(Extent(),NbBuckets());
248 pNode = new (this->myAllocator) IndexedDataMapNode (theKey1, Extent(), theItem,
249 myData1[iK1], myData2[iK2]);
250 myData1[iK1] = pNode;
251 myData2[iK2] = pNode;
256 Standard_Boolean Contains (const TheKeyType& theKey1) const
259 return Standard_False;
260 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
261 IndexedDataMapNode * pNode1;
262 pNode1 = (IndexedDataMapNode *) myData1[iK1];
265 if (Hasher::IsEqual(pNode1->Key1(), theKey1))
266 return Standard_True;
267 pNode1 = (IndexedDataMapNode *) pNode1->Next();
269 return Standard_False;
273 void Substitute (const Standard_Integer theIndex,
274 const TheKeyType& theKey1,
275 const TheItemType& theItem)
277 #if !defined No_Exception && !defined No_Standard_OutOfRange
278 if (theIndex < 1 || theIndex > Extent())
279 Standard_OutOfRange::Raise ("NCollection_IndexedDataMap::Substitute");
281 IndexedDataMapNode * p;
282 // check if theKey1 is not already in the map
283 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
284 p = (IndexedDataMapNode *) myData1[iK1];
287 if (Hasher::IsEqual (p->Key1(), theKey1))
288 Standard_DomainError::Raise("NCollection_IndexedDataMap::Substitute");
289 p = (IndexedDataMapNode *) p->Next();
292 // Find the node for the index I
293 Standard_Integer iK2 = ::HashCode (theIndex, NbBuckets());
294 p = (IndexedDataMapNode *) myData2[iK2];
297 if (p->Key2() == theIndex)
299 p = (IndexedDataMapNode*) p->Next2();
302 // remove the old key
303 Standard_Integer iK = Hasher::HashCode (p->Key1(), NbBuckets());
304 IndexedDataMapNode * q = (IndexedDataMapNode *) myData1[iK];
306 myData1[iK] = (IndexedDataMapNode *) p->Next();
309 while (q->Next() != p)
310 q = (IndexedDataMapNode *) q->Next();
311 q->Next() = p->Next();
316 p->ChangeValue() = theItem;
317 p->Next() = myData1[iK1];
322 void RemoveLast (void)
324 #if !defined No_Exception && !defined No_Standard_OutOfRange
326 Standard_OutOfRange::Raise ("NCollection_IndexedDataMap::RemoveLast");
328 IndexedDataMapNode * p, * q;
329 // Find the node for the last index and remove it
330 Standard_Integer iK2 = ::HashCode (Extent(), NbBuckets());
331 p = (IndexedDataMapNode *) myData2[iK2];
335 if (p->Key2() == Extent())
338 p = (IndexedDataMapNode*) p->Next2();
341 myData2[iK2] = (IndexedDataMapNode *) p->Next2();
343 q->Next2() = p->Next2();
346 Standard_Integer iK1 = Hasher::HashCode (p->Key1(), NbBuckets());
347 q = (IndexedDataMapNode *) myData1[iK1];
349 myData1[iK1] = (IndexedDataMapNode *) p->Next();
352 while (q->Next() != p)
353 q = (IndexedDataMapNode *) q->Next();
354 q->Next() = p->Next();
356 p->~IndexedDataMapNode();
357 this->myAllocator->Free(p);
362 const TheKeyType& FindKey (const Standard_Integer theKey2) const
364 #if !defined No_Exception && !defined No_Standard_OutOfRange
365 if (theKey2 < 1 || theKey2 > Extent())
366 Standard_OutOfRange::Raise ("NCollection_IndexedDataMap::FindKey");
368 IndexedDataMapNode * pNode2 =
369 (IndexedDataMapNode *) myData2[::HashCode(theKey2,NbBuckets())];
372 if (pNode2->Key2() == theKey2)
373 return pNode2->Key1();
374 pNode2 = (IndexedDataMapNode*) pNode2->Next2();
376 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::FindKey");
377 return pNode2->Key1(); // This for compiler
381 const TheItemType& FindFromIndex (const Standard_Integer theKey2) const
383 #if !defined No_Exception && !defined No_Standard_OutOfRange
384 if (theKey2 < 1 || theKey2 > Extent())
385 Standard_OutOfRange::Raise ("NCollection_IndexedDataMap::FindFromIndex");
387 IndexedDataMapNode * pNode2 =
388 (IndexedDataMapNode *) myData2[::HashCode(theKey2,NbBuckets())];
391 if (pNode2->Key2() == theKey2)
392 return pNode2->Value();
393 pNode2 = (IndexedDataMapNode*) pNode2->Next2();
395 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::FindFromIndex");
396 return pNode2->Value(); // This for compiler
400 const TheItemType& operator() (const Standard_Integer theKey2) const
401 { return FindFromIndex (theKey2); }
404 TheItemType& ChangeFromIndex (const Standard_Integer theKey2)
406 #if !defined No_Exception && !defined No_Standard_OutOfRange
407 if (theKey2 < 1 || theKey2 > Extent())
408 Standard_OutOfRange::Raise("NCollection_IndexedDataMap::ChangeFromIndex");
410 IndexedDataMapNode * pNode2 =
411 (IndexedDataMapNode *) myData2[::HashCode(theKey2,NbBuckets())];
414 if (pNode2->Key2() == theKey2)
415 return pNode2->ChangeValue();
416 pNode2 = (IndexedDataMapNode*) pNode2->Next2();
418 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::FindFromIndex");
419 return pNode2->ChangeValue(); // This for compiler
423 TheItemType& operator() (const Standard_Integer theKey2)
424 { return ChangeFromIndex (theKey2); }
427 Standard_Integer FindIndex(const TheKeyType& theKey1) const
429 if (IsEmpty()) return 0;
430 IndexedDataMapNode * pNode1 =
431 (IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
434 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
435 return pNode1->Key2();
436 pNode1 = (IndexedDataMapNode*) pNode1->Next();
442 const TheItemType& FindFromKey(const TheKeyType& theKey1) const
444 #if !defined No_Exception && !defined No_Standard_NoSuchObject
446 Standard_NoSuchObject::Raise ("NCollection_IndexedDataMap::FindFromKey");
448 IndexedDataMapNode * pNode1 =
449 (IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
452 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
453 return pNode1->Value();
454 pNode1 = (IndexedDataMapNode*) pNode1->Next();
456 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::FindFromKey");
457 return pNode1->Value();
461 TheItemType& ChangeFromKey (const TheKeyType& theKey1)
463 #if !defined No_Exception && !defined No_Standard_NoSuchObject
465 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::ChangeFromKey");
467 IndexedDataMapNode * pNode1 =
468 (IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
471 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
472 return pNode1->ChangeValue();
473 pNode1 = (IndexedDataMapNode*) pNode1->Next();
475 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::ChangeFromKey");
476 return pNode1->ChangeValue();
479 //! Clear data. If doReleaseMemory is false then the table of
480 //! buckets is not released and will be reused.
481 void Clear(const Standard_Boolean doReleaseMemory = Standard_True)
482 { Destroy (IndexedDataMapNode::delNode, this->myAllocator, doReleaseMemory); }
484 //! Clear data and reset allocator
485 void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
488 this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
489 NCollection_BaseAllocator::CommonBaseAllocator() );
493 ~NCollection_IndexedDataMap (void)
497 virtual Standard_Integer Size(void) const
501 // ----------- PRIVATE METHODS -----------
503 //! Creates Iterator for use on BaseCollection
504 virtual TYPENAME NCollection_BaseCollection<TheItemType>::Iterator&
505 CreateIterator(void) const
506 { return *(new (this->IterAllocator()) Iterator(*this)); }