0024971: Incomplete interface of NCollection classes
[occt.git] / src / NCollection / NCollection_IndexedDataMap.hxx
CommitLineData
b311480e 1// Created on: 2002-04-24
2// Created by: Alexander KARTOMIN (akm)
973c2be1 3// Copyright (c) 2002-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
d5f74e42 7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 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.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
7fd59977 15
16#ifndef NCollection_IndexedDataMap_HeaderFile
17#define NCollection_IndexedDataMap_HeaderFile
18
7fd59977 19#include <NCollection_BaseMap.hxx>
20#include <NCollection_TListNode.hxx>
21#include <Standard_TypeMismatch.hxx>
22#include <Standard_NoSuchObject.hxx>
79a35943 23#include <NCollection_StlIterator.hxx>
9991c9c2 24#include <NCollection_DefaultHasher.hxx>
25
7fd59977 26#include <Standard_OutOfRange.hxx>
7fd59977 27
7fd59977 28/**
29 * Purpose: An indexed map is used to store keys and to bind
30 * an index to them. Each new key stored in the map
31 * gets an index. Index are incremented as keys are
32 * stored in the map. A key can be found by the index
33 * and an index by the key. No key but the last can
34 * be removed so the indices are in the range 1..
35 * Extent. An Item is stored with each key.
36 *
37 * This class is similar to IndexedMap from
38 * NCollection with the Item as a new feature. Note
39 * the important difference on the operator (). In
40 * the IndexedMap this operator returns the Key. In
41 * the IndexedDataMap this operator returns the Item.
42 *
43 * See the class Map from NCollection for a
44 * discussion about the number of buckets.
45 */
9991c9c2 46
47template < class TheKeyType,
48 class TheItemType,
49 class Hasher = NCollection_DefaultHasher<TheKeyType> >
ddf2fe8e 50class NCollection_IndexedDataMap : public NCollection_BaseMap
7fd59977 51{
52 //! Adaptation of the TListNode to the INDEXEDDatamap
53 private:
54 class IndexedDataMapNode : public NCollection_TListNode<TheItemType>
55 {
56 public:
57 //! Constructor with 'Next'
58 IndexedDataMapNode (const TheKeyType& theKey1,
59 const Standard_Integer theKey2,
60 const TheItemType& theItem,
61 NCollection_ListNode* theNext1,
62 NCollection_ListNode* theNext2) :
e3a6386d 63 NCollection_TListNode<TheItemType>(theItem,theNext1),
64 myKey1(theKey1),
65 myKey2(theKey2),
66 myNext2((IndexedDataMapNode*)theNext2)
7fd59977 67 {
7fd59977 68 }
69 //! Key1
70 TheKeyType& Key1 (void)
71 { return myKey1; }
72 //! Key2
73 const Standard_Integer& Key2 (void)
74 { return myKey2; }
75 //! Next2
76 IndexedDataMapNode*& Next2 (void)
77 { return myNext2; }
78
79 //! Static deleter to be passed to BaseList
80 static void delNode (NCollection_ListNode * theNode,
81 Handle(NCollection_BaseAllocator)& theAl)
82 {
83 ((IndexedDataMapNode *) theNode)->~IndexedDataMapNode();
84 theAl->Free(theNode);
85 }
86 private:
87 TheKeyType myKey1;
88 Standard_Integer myKey2;
89 IndexedDataMapNode * myNext2;
90 };
91
92 public:
93 //! Implementation of the Iterator interface.
ddf2fe8e 94 class Iterator
7fd59977 95 {
96 public:
97 //! Empty constructor
98 Iterator (void) :
99 myMap(NULL),
100 myIndex(0) {}
101 //! Constructor
ad3217cd 102 Iterator (const NCollection_IndexedDataMap& theMap)
103 : myMap ((NCollection_IndexedDataMap* )&theMap),
104 myNode (myMap->nodeFromIndex (1)),
105 myIndex (1) {}
7fd59977 106 //! Query if the end of collection is reached by iterator
ddf2fe8e 107 Standard_Boolean More(void) const
79a35943 108 { return (myMap != NULL) && (myIndex <= myMap->Extent()); }
7fd59977 109 //! Make a step along the collection
ddf2fe8e 110 void Next(void)
ad3217cd 111 {
112 myNode = myMap->nodeFromIndex (++myIndex);
113 }
7fd59977 114 //! Value access
ddf2fe8e 115 const TheItemType& Value(void) const
7fd59977 116 {
e3a6386d 117 Standard_NoSuchObject_Raise_if(!More(), "NCollection_IndexedDataMap::Iterator::Value");
ad3217cd 118 return myNode->Value();
7fd59977 119 }
120 //! ChangeValue access
ddf2fe8e 121 TheItemType& ChangeValue(void) const
7fd59977 122 {
e3a6386d 123 Standard_NoSuchObject_Raise_if(!More(), "NCollection_IndexedDataMap::Iterator::ChangeValue");
ad3217cd 124 return myNode->ChangeValue();
125 }
126 //! Key
127 const TheKeyType& Key() const
128 {
e3a6386d 129 Standard_NoSuchObject_Raise_if(!More(), "NCollection_IndexedDataMap::Iterator::Key");
ad3217cd 130 return myNode->Key1();
7fd59977 131 }
79a35943 132 //! Performs comparison of two iterators.
ddf2fe8e 133 Standard_Boolean IsEqual (const Iterator& theOther) const
79a35943 134 {
135 return myMap == theOther.myMap &&
136 myNode == theOther.myNode &&
137 myIndex == theOther.myIndex;
138 }
7fd59977 139 private:
ad3217cd 140 NCollection_IndexedDataMap* myMap; //!< Pointer to the map being iterated
141 IndexedDataMapNode* myNode; //!< Current node
142 Standard_Integer myIndex; //!< Current index
7fd59977 143 };
144
79a35943 145 //! Shorthand for a regular iterator type.
146 typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, false> iterator;
147
148 //! Shorthand for a constant iterator type.
149 typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheItemType, true> const_iterator;
150
151 //! Returns an iterator pointing to the first element in the map.
152 iterator begin() const { return Iterator (*this); }
153
154 //! Returns an iterator referring to the past-the-end element in the map.
155 iterator end() const { return Iterator(); }
156
157 //! Returns a const iterator pointing to the first element in the map.
158 const_iterator cbegin() const { return Iterator (*this); }
159
160 //! Returns a const iterator referring to the past-the-end element in the map.
161 const_iterator cend() const { return Iterator(); }
162
7fd59977 163 public:
164 // ---------- PUBLIC METHODS ------------
165
166 //! Constructor
167 NCollection_IndexedDataMap (const Standard_Integer NbBuckets=1,
168 const Handle(NCollection_BaseAllocator)& theAllocator = 0L)
ddf2fe8e 169 : NCollection_BaseMap (NbBuckets, Standard_False, theAllocator) {}
7fd59977 170
171 //! Copy constructor
172 NCollection_IndexedDataMap (const NCollection_IndexedDataMap& theOther)
ddf2fe8e 173 : NCollection_BaseMap (theOther.NbBuckets(), Standard_False, theOther.myAllocator)
7fd59977 174 { *this = theOther; }
175
ab2db9a5 176 //! Exchange the content of two maps without re-allocations.
177 //! Notice that allocators will be swapped as well!
178 void Exchange (NCollection_IndexedDataMap& theOther)
179 {
ddf2fe8e 180 this->exchangeMapsData (theOther);
ab2db9a5 181 }
182
ddf2fe8e 183 //! Assignment
184 NCollection_IndexedDataMap& Assign (const NCollection_IndexedDataMap& theOther)
7fd59977 185 {
186 if (this == &theOther)
187 return *this;
188
189 Clear(theOther.myAllocator);
190 ReSize (theOther.Extent()-1);
191 Standard_Integer i;
192 for (i=1; i<=theOther.Extent(); i++)
193 {
194 TheKeyType aKey1 = theOther.FindKey(i);
195 TheItemType anItem = theOther.FindFromIndex(i);
9991c9c2 196 Standard_Integer iK1 = Hasher::HashCode (aKey1, NbBuckets());
197 Standard_Integer iK2 = ::HashCode (i, NbBuckets());
7fd59977 198 IndexedDataMapNode * pNode =
199 new (this->myAllocator) IndexedDataMapNode (aKey1, i, anItem,
200 myData1[iK1], myData2[iK2]);
201 myData1[iK1] = pNode;
202 myData2[iK2] = pNode;
203 Increment();
204 }
205 return *this;
206 }
207
ddf2fe8e 208 //! Assignment operator
209 NCollection_IndexedDataMap& operator= (const NCollection_IndexedDataMap& theOther)
210 {
211 return Assign (theOther);
212 }
213
7fd59977 214 //! ReSize
215 void ReSize (const Standard_Integer N)
216 {
fd03ee4b 217 NCollection_ListNode** ppNewData1 = NULL;
218 NCollection_ListNode** ppNewData2 = NULL;
7fd59977 219 Standard_Integer newBuck;
ddf2fe8e 220 if (BeginResize (N, newBuck, ppNewData1, ppNewData2))
7fd59977 221 {
222 if (myData1)
223 {
224 IndexedDataMapNode *p, *q;
225 Standard_Integer i, iK1, iK2;
226 for (i = 0; i <= NbBuckets(); i++)
227 {
228 if (myData1[i])
229 {
230 p = (IndexedDataMapNode *) myData1[i];
231 while (p)
232 {
9991c9c2 233 iK1 = Hasher::HashCode (p->Key1(), newBuck);
234 iK2 = ::HashCode (p->Key2(), newBuck);
7fd59977 235 q = (IndexedDataMapNode*) p->Next();
236 p->Next() = ppNewData1[iK1];
fd03ee4b 237 p->Next2() = (IndexedDataMapNode*)ppNewData2[iK2];
7fd59977 238 ppNewData1[iK1] = p;
239 ppNewData2[iK2] = p;
240 p = q;
241 }
242 }
243 }
244 }
ddf2fe8e 245 EndResize (N, newBuck, ppNewData1, ppNewData2);
7fd59977 246 }
247 }
248
249 //! Add
250 Standard_Integer Add (const TheKeyType& theKey1, const TheItemType& theItem)
251 {
252 if (Resizable())
253 ReSize(Extent());
9991c9c2 254 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
7fd59977 255 IndexedDataMapNode * pNode;
256 pNode = (IndexedDataMapNode *) myData1[iK1];
257 while (pNode)
258 {
9991c9c2 259 if (Hasher::IsEqual (pNode->Key1(), theKey1))
7fd59977 260 return pNode->Key2();
261 pNode = (IndexedDataMapNode *) pNode->Next();
262 }
263 Increment();
9991c9c2 264 Standard_Integer iK2 = ::HashCode(Extent(),NbBuckets());
7fd59977 265 pNode = new (this->myAllocator) IndexedDataMapNode (theKey1, Extent(), theItem,
266 myData1[iK1], myData2[iK2]);
267 myData1[iK1] = pNode;
268 myData2[iK2] = pNode;
269 return Extent();
270 }
271
272 //! Contains
273 Standard_Boolean Contains (const TheKeyType& theKey1) const
274 {
275 if (IsEmpty())
276 return Standard_False;
9991c9c2 277 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
7fd59977 278 IndexedDataMapNode * pNode1;
279 pNode1 = (IndexedDataMapNode *) myData1[iK1];
280 while (pNode1)
281 {
9991c9c2 282 if (Hasher::IsEqual(pNode1->Key1(), theKey1))
7fd59977 283 return Standard_True;
284 pNode1 = (IndexedDataMapNode *) pNode1->Next();
285 }
286 return Standard_False;
287 }
288
289 //! Substitute
290 void Substitute (const Standard_Integer theIndex,
291 const TheKeyType& theKey1,
292 const TheItemType& theItem)
293 {
e3a6386d 294 Standard_OutOfRange_Raise_if (theIndex < 1 || theIndex > Extent(), "NCollection_IndexedDataMap::Substitute");
295
7fd59977 296 IndexedDataMapNode * p;
297 // check if theKey1 is not already in the map
9991c9c2 298 Standard_Integer iK1 = Hasher::HashCode (theKey1, NbBuckets());
7fd59977 299 p = (IndexedDataMapNode *) myData1[iK1];
300 while (p)
301 {
9991c9c2 302 if (Hasher::IsEqual (p->Key1(), theKey1))
7fd59977 303 Standard_DomainError::Raise("NCollection_IndexedDataMap::Substitute");
304 p = (IndexedDataMapNode *) p->Next();
305 }
306
307 // Find the node for the index I
9991c9c2 308 Standard_Integer iK2 = ::HashCode (theIndex, NbBuckets());
7fd59977 309 p = (IndexedDataMapNode *) myData2[iK2];
310 while (p)
311 {
312 if (p->Key2() == theIndex)
313 break;
314 p = (IndexedDataMapNode*) p->Next2();
315 }
316
317 // remove the old key
9991c9c2 318 Standard_Integer iK = Hasher::HashCode (p->Key1(), NbBuckets());
7fd59977 319 IndexedDataMapNode * q = (IndexedDataMapNode *) myData1[iK];
320 if (q == p)
321 myData1[iK] = (IndexedDataMapNode *) p->Next();
322 else
323 {
324 while (q->Next() != p)
325 q = (IndexedDataMapNode *) q->Next();
326 q->Next() = p->Next();
327 }
328
329 // update the node
330 p->Key1() = theKey1;
331 p->ChangeValue() = theItem;
332 p->Next() = myData1[iK1];
333 myData1[iK1] = p;
334 }
335
336 //! RemoveLast
337 void RemoveLast (void)
338 {
e3a6386d 339 Standard_OutOfRange_Raise_if (Extent() == 0, "NCollection_IndexedDataMap::RemoveLast");
340
7fd59977 341 IndexedDataMapNode * p, * q;
342 // Find the node for the last index and remove it
9991c9c2 343 Standard_Integer iK2 = ::HashCode (Extent(), NbBuckets());
7fd59977 344 p = (IndexedDataMapNode *) myData2[iK2];
345 q = NULL;
346 while (p)
347 {
348 if (p->Key2() == Extent())
349 break;
350 q = p;
351 p = (IndexedDataMapNode*) p->Next2();
352 }
353 if (q == NULL)
354 myData2[iK2] = (IndexedDataMapNode *) p->Next2();
355 else
356 q->Next2() = p->Next2();
357
358 // remove the key
9991c9c2 359 Standard_Integer iK1 = Hasher::HashCode (p->Key1(), NbBuckets());
7fd59977 360 q = (IndexedDataMapNode *) myData1[iK1];
361 if (q == p)
362 myData1[iK1] = (IndexedDataMapNode *) p->Next();
363 else
364 {
365 while (q->Next() != p)
366 q = (IndexedDataMapNode *) q->Next();
367 q->Next() = p->Next();
368 }
369 p->~IndexedDataMapNode();
370 this->myAllocator->Free(p);
371 Decrement();
372 }
373
374 //! FindKey
375 const TheKeyType& FindKey (const Standard_Integer theKey2) const
376 {
e3a6386d 377 Standard_OutOfRange_Raise_if (theKey2 < 1 || theKey2 > Extent(), "NCollection_IndexedDataMap::FindKey");
378
ad3217cd 379 IndexedDataMapNode* aNode = nodeFromIndex (theKey2);
380 if (aNode == NULL)
7fd59977 381 {
ad3217cd 382 Standard_NoSuchObject::Raise ("NCollection_IndexedDataMap::FindKey");
7fd59977 383 }
ad3217cd 384 return aNode->Key1();
7fd59977 385 }
386
387 //! FindFromIndex
388 const TheItemType& FindFromIndex (const Standard_Integer theKey2) const
389 {
e3a6386d 390 Standard_OutOfRange_Raise_if (theKey2 < 1 || theKey2 > Extent(), "NCollection_IndexedDataMap::FindFromIndex");
391
ad3217cd 392 IndexedDataMapNode* aNode = nodeFromIndex (theKey2);
393 if (aNode == NULL)
7fd59977 394 {
ad3217cd 395 Standard_NoSuchObject::Raise ("NCollection_IndexedDataMap::FindFromIndex");
7fd59977 396 }
ad3217cd 397 return aNode->Value();
7fd59977 398 }
399
400 //! operator ()
401 const TheItemType& operator() (const Standard_Integer theKey2) const
402 { return FindFromIndex (theKey2); }
403
404 //! ChangeFromIndex
405 TheItemType& ChangeFromIndex (const Standard_Integer theKey2)
406 {
e3a6386d 407 Standard_OutOfRange_Raise_if (theKey2 < 1 || theKey2 > Extent(), "NCollection_IndexedDataMap::ChangeFromIndex");
408
ad3217cd 409 IndexedDataMapNode* aNode = nodeFromIndex (theKey2);
410 if (aNode == NULL)
7fd59977 411 {
ad3217cd 412 Standard_NoSuchObject::Raise ("NCollection_IndexedDataMap::ChangeFromIndex");
7fd59977 413 }
ad3217cd 414 return aNode->ChangeValue();
7fd59977 415 }
416
417 //! operator ()
418 TheItemType& operator() (const Standard_Integer theKey2)
419 { return ChangeFromIndex (theKey2); }
420
421 //! FindIndex
422 Standard_Integer FindIndex(const TheKeyType& theKey1) const
423 {
424 if (IsEmpty()) return 0;
425 IndexedDataMapNode * pNode1 =
9991c9c2 426 (IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
7fd59977 427 while (pNode1)
428 {
9991c9c2 429 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
7fd59977 430 return pNode1->Key2();
431 pNode1 = (IndexedDataMapNode*) pNode1->Next();
432 }
433 return 0;
434 }
435
436 //! FindFromKey
437 const TheItemType& FindFromKey(const TheKeyType& theKey1) const
438 {
e3a6386d 439 Standard_NoSuchObject_Raise_if (IsEmpty(), "NCollection_IndexedDataMap::FindFromKey");
440
7fd59977 441 IndexedDataMapNode * pNode1 =
9991c9c2 442 (IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
7fd59977 443 while (pNode1)
444 {
9991c9c2 445 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
7fd59977 446 return pNode1->Value();
447 pNode1 = (IndexedDataMapNode*) pNode1->Next();
448 }
449 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::FindFromKey");
450 return pNode1->Value();
451 }
452
453 //! ChangeFromKey
454 TheItemType& ChangeFromKey (const TheKeyType& theKey1)
455 {
e3a6386d 456 Standard_NoSuchObject_Raise_if (IsEmpty(), "NCollection_IndexedDataMap::ChangeFromKey");
457
7fd59977 458 IndexedDataMapNode * pNode1 =
9991c9c2 459 (IndexedDataMapNode *) myData1[Hasher::HashCode(theKey1,NbBuckets())];
7fd59977 460 while (pNode1)
461 {
9991c9c2 462 if (Hasher::IsEqual (pNode1->Key1(), theKey1))
7fd59977 463 return pNode1->ChangeValue();
464 pNode1 = (IndexedDataMapNode*) pNode1->Next();
465 }
466 Standard_NoSuchObject::Raise("NCollection_IndexedDataMap::ChangeFromKey");
467 return pNode1->ChangeValue();
468 }
469
ad3217cd 470 //! Find value for key with copying.
471 //! @return true if key was found
472 Standard_Boolean FindFromKey (const TheKeyType& theKey1,
473 TheItemType& theValue) const
474 {
475 if (IsEmpty())
476 {
477 return Standard_False;
478 }
479 for (IndexedDataMapNode* aNode = (IndexedDataMapNode* )myData1[Hasher::HashCode (theKey1, NbBuckets())];
480 aNode != NULL; aNode = (IndexedDataMapNode* )aNode->Next())
481 {
482 if (Hasher::IsEqual (aNode->Key1(), theKey1))
483 {
484 theValue = aNode->Value();
485 return Standard_True;
486 }
487 }
488 return Standard_False;
489 }
490
7fd59977 491 //! Clear data. If doReleaseMemory is false then the table of
492 //! buckets is not released and will be reused.
493 void Clear(const Standard_Boolean doReleaseMemory = Standard_True)
ddf2fe8e 494 { Destroy (IndexedDataMapNode::delNode, doReleaseMemory); }
7fd59977 495
496 //! Clear data and reset allocator
497 void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
498 {
499 Clear();
500 this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
501 NCollection_BaseAllocator::CommonBaseAllocator() );
502 }
503
504 //! Destructor
505 ~NCollection_IndexedDataMap (void)
506 { Clear(); }
507
508 //! Size
ddf2fe8e 509 Standard_Integer Size(void) const
7fd59977 510 { return Extent(); }
511
512 private:
513 // ----------- PRIVATE METHODS -----------
514
ad3217cd 515 //! Find map node associated with specified index.
516 //! Return NULL if not found (exception-free internal implementation).
517 IndexedDataMapNode* nodeFromIndex (const Standard_Integer theKey2) const
518 {
519 if (Extent() == 0)
520 {
521 return NULL;
522 }
523 for (IndexedDataMapNode* aNode = (IndexedDataMapNode* )myData2[::HashCode (theKey2, NbBuckets())];
524 aNode != NULL; aNode = (IndexedDataMapNode* )aNode->Next2())
525 {
526 if (aNode->Key2() == theKey2)
527 {
528 return aNode;
529 }
530 }
531 return NULL;
532 }
533
7fd59977 534};
535
7fd59977 536#endif