1 // Created on: 2002-04-23
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 under
8 // the terms of the GNU Lesser General Public License 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_Map_HeaderFile
17 #define NCollection_Map_HeaderFile
19 #include <NCollection_BaseMap.hxx>
20 #include <NCollection_DataMap.hxx>
21 #include <NCollection_TListNode.hxx>
22 #include <NCollection_StlIterator.hxx>
23 #include <NCollection_DefaultHasher.hxx>
25 #include <Standard_NoSuchObject.hxx>
28 * Purpose: Single hashed Map. This Map is used to store and
29 * retrieve keys in linear time.
31 * The ::Iterator class can be used to explore the
32 * content of the map. It is not wise to iterate and
33 * modify a map in parallel.
35 * To compute the hashcode of the key the function
36 * ::HashCode must be defined in the global namespace
38 * To compare two keys the function ::IsEqual must be
39 * defined in the global namespace.
41 * The performance of a Map is conditionned by its
42 * number of buckets that should be kept greater to
43 * the number of keys. This map has an automatic
44 * management of the number of buckets. It is resized
45 * when the number of Keys becomes greater than the
48 * If you have a fair idea of the number of objects
49 * you can save on automatic resizing by giving a
50 * number of buckets at creation or using the ReSize
51 * method. This should be consider only for crucial
52 * optimisation issues.
55 template < class TheKeyType,
56 class Hasher = NCollection_DefaultHasher<TheKeyType> >
57 class NCollection_Map : public NCollection_BaseMap
59 //! Adaptation of the TListNode to the map notations
62 class MapNode : public NCollection_TListNode<TheKeyType>
65 //! Constructor with 'Next'
66 MapNode (const TheKeyType& theKey,
67 NCollection_ListNode* theNext) :
68 NCollection_TListNode<TheKeyType> (theKey, theNext) {}
70 const TheKeyType& Key (void)
71 { return this->Value(); }
76 //! Implementation of the Iterator interface.
77 class Iterator : public NCollection_BaseMap::Iterator
82 NCollection_BaseMap::Iterator() {}
84 Iterator (const NCollection_Map& theMap) :
85 NCollection_BaseMap::Iterator(theMap) {}
86 //! Query if the end of collection is reached by iterator
87 Standard_Boolean More(void) const
89 //! Make a step along the collection
93 const TheKeyType& Value(void) const
95 Standard_NoSuchObject_Raise_if (!More(), "NCollection_Map::Iterator::Value");
96 return ((MapNode *) myNode)->Value();
100 const TheKeyType& Key (void) const
102 Standard_NoSuchObject_Raise_if (!More(), "NCollection_Map::Iterator::Key");
103 return ((MapNode *) myNode)->Value();
107 //! Shorthand for a constant iterator type.
108 typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheKeyType, true> const_iterator;
110 //! Returns a const iterator pointing to the first element in the map.
111 const_iterator cbegin() const { return Iterator (*this); }
113 //! Returns a const iterator referring to the past-the-end element in the map.
114 const_iterator cend() const { return Iterator(); }
117 // ---------- PUBLIC METHODS ------------
120 NCollection_Map (const Standard_Integer NbBuckets = 1,
121 const Handle(NCollection_BaseAllocator)& theAllocator = 0L) :
122 NCollection_BaseMap (NbBuckets, Standard_True, theAllocator) {}
125 NCollection_Map (const NCollection_Map& theOther) :
126 NCollection_BaseMap (theOther.NbBuckets(), Standard_True, theOther.myAllocator)
127 { *this = theOther; }
129 //! Exchange the content of two maps without re-allocations.
130 //! Notice that allocators will be swapped as well!
131 void Exchange (NCollection_Map& theOther)
133 this->exchangeMapsData (theOther);
137 //! This method does not change the internal allocator.
138 NCollection_Map& Assign (const NCollection_Map& theOther)
140 if (this == &theOther)
144 ReSize (theOther.Extent()-1);
145 Iterator anIter(theOther);
146 for (; anIter.More(); anIter.Next())
152 NCollection_Map& operator= (const NCollection_Map& theOther)
154 return Assign(theOther);
158 void ReSize (const Standard_Integer N)
160 NCollection_ListNode** newdata = 0L;
161 NCollection_ListNode** dummy = 0L;
162 Standard_Integer newBuck;
163 if (BeginResize (N, newBuck, newdata, dummy))
167 MapNode** olddata = (MapNode**) myData1;
169 Standard_Integer i,k;
170 for (i = 0; i <= NbBuckets(); i++)
177 k = Hasher::HashCode(p->Key(),newBuck);
178 q = (MapNode*) p->Next();
179 p->Next() = newdata[k];
186 EndResize (N, newBuck, newdata, dummy);
191 Standard_Boolean Add(const TheKeyType& K)
195 MapNode** data = (MapNode**)myData1;
196 Standard_Integer k = Hasher::HashCode(K,NbBuckets());
197 MapNode* p = data[k];
200 if (Hasher::IsEqual(p->Key(),K))
201 return Standard_False;
202 p = (MapNode *) p->Next();
204 data[k] = new (this->myAllocator) MapNode(K,data[k]);
206 return Standard_True;
209 //! Added: add a new key if not yet in the map, and return
210 //! reference to either newly added or previously existing object
211 const TheKeyType& Added(const TheKeyType& K)
215 MapNode** data = (MapNode**)myData1;
216 Standard_Integer k = Hasher::HashCode(K,NbBuckets());
217 MapNode* p = data[k];
220 if (Hasher::IsEqual(p->Key(),K))
222 p = (MapNode *) p->Next();
224 data[k] = new (this->myAllocator) MapNode(K,data[k]);
226 return data[k]->Key();
230 Standard_Boolean Contains(const TheKeyType& K) const
233 return Standard_False;
234 MapNode** data = (MapNode**) myData1;
235 MapNode* p = data[Hasher::HashCode(K,NbBuckets())];
238 if (Hasher::IsEqual(p->Key(),K))
239 return Standard_True;
240 p = (MapNode *) p->Next();
242 return Standard_False;
246 Standard_Boolean Remove(const TheKeyType& K)
249 return Standard_False;
250 MapNode** data = (MapNode**) myData1;
251 Standard_Integer k = Hasher::HashCode(K,NbBuckets());
252 MapNode* p = data[k];
256 if (Hasher::IsEqual(p->Key(),K))
260 q->Next() = p->Next();
262 data[k] = (MapNode*) p->Next();
264 this->myAllocator->Free(p);
265 return Standard_True;
268 p = (MapNode*) p->Next();
270 return Standard_False;
273 //! Clear data. If doReleaseMemory is false then the table of
274 //! buckets is not released and will be reused.
275 void Clear(const Standard_Boolean doReleaseMemory = Standard_True)
276 { Destroy (MapNode::delNode, doReleaseMemory); }
278 //! Clear data and reset allocator
279 void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
282 this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
283 NCollection_BaseAllocator::CommonBaseAllocator() );
287 virtual ~NCollection_Map (void)
291 Standard_Integer Size(void) const
295 //!@name Boolean operations with maps as sets of keys
298 //! @return true if two maps contains exactly the same keys
299 Standard_Boolean IsEqual (const NCollection_Map& theOther) const
301 return Extent() == theOther.Extent()
302 && Contains (theOther);
305 //! @return true if this map contains ALL keys of another map.
306 Standard_Boolean Contains (const NCollection_Map& theOther) const
308 if (this == &theOther
309 || theOther.IsEmpty())
311 return Standard_True;
313 else if (Extent() < theOther.Extent())
315 return Standard_False;
318 for (Iterator anIter (theOther); anIter.More(); anIter.Next())
320 if (!Contains (anIter.Key()))
322 return Standard_False;
326 return Standard_True;
329 //! Sets this Map to be the result of union (aka addition, fuse, merge, boolean OR) operation between two given Maps
330 //! The new Map contains the values that are contained either in the first map or in the second map or in both.
331 //! All previous content of this Map is cleared.
332 //! This map (result of the boolean operation) can also be passed as one of operands.
333 void Union (const NCollection_Map& theLeft,
334 const NCollection_Map& theRight)
336 if (&theLeft == &theRight)
343 && this != &theRight)
348 if (this != &theLeft)
350 for (Iterator anIter (theLeft); anIter.More(); anIter.Next())
355 if (this != &theRight)
357 for (Iterator anIter (theRight); anIter.More(); anIter.Next())
364 //! Apply to this Map the boolean operation union (aka addition, fuse, merge, boolean OR) with another (given) Map.
365 //! The result contains the values that were previously contained in this map or contained in the given (operand) map.
366 //! This algorithm is similar to method Union().
367 //! Returns True if contents of this map is changed.
368 Standard_Boolean Unite (const NCollection_Map& theOther)
370 if (this == &theOther)
372 return Standard_False;
375 const Standard_Integer anOldExtent = Extent();
376 Union (*this, theOther);
377 return anOldExtent != Extent();
380 //! Returns true if this and theMap have common elements.
381 Standard_Boolean HasIntersection (const NCollection_Map& theMap) const
383 const NCollection_Map* aMap1 = this;
384 const NCollection_Map* aMap2 = &theMap;
385 if (theMap.Size() < Size())
391 for (NCollection_Map::Iterator aIt(*aMap1); aIt.More(); aIt.Next())
393 if (aMap2->Contains(aIt.Value()))
395 return Standard_True;
399 return Standard_False;
402 //! Sets this Map to be the result of intersection (aka multiplication, common, boolean AND) operation between two given Maps.
403 //! The new Map contains only the values that are contained in both map operands.
404 //! All previous content of this Map is cleared.
405 //! This same map (result of the boolean operation) can also be used as one of operands.
406 void Intersection (const NCollection_Map& theLeft,
407 const NCollection_Map& theRight)
409 if (&theLeft == &theRight)
415 if (this == &theLeft)
417 NCollection_Map aCopy (1, this->myAllocator);
419 Intersection (aCopy, theRight);
422 else if (this == &theRight)
424 NCollection_Map aCopy (1, this->myAllocator);
426 Intersection (theLeft, aCopy);
431 if (theLeft.Extent() < theRight.Extent())
433 for (Iterator anIter (theLeft); anIter.More(); anIter.Next())
435 if (theRight.Contains (anIter.Key()))
443 for (Iterator anIter (theRight); anIter.More(); anIter.Next())
445 if (theLeft.Contains (anIter.Key()))
453 //! Apply to this Map the intersection operation (aka multiplication, common, boolean AND) with another (given) Map.
454 //! The result contains only the values that are contained in both this and the given maps.
455 //! This algorithm is similar to method Intersection().
456 //! Returns True if contents of this map is changed.
457 Standard_Boolean Intersect (const NCollection_Map& theOther)
459 if (this == &theOther
462 return Standard_False;
465 const Standard_Integer anOldExtent = Extent();
466 Intersection (*this, theOther);
467 return anOldExtent != Extent();
470 //! Sets this Map to be the result of subtraction (aka set-theoretic difference, relative complement,
471 //! exclude, cut, boolean NOT) operation between two given Maps.
472 //! The new Map contains only the values that are contained in the first map operands and not contained in the second one.
473 //! All previous content of this Map is cleared.
474 void Subtraction (const NCollection_Map& theLeft,
475 const NCollection_Map& theRight)
477 if (this == &theLeft)
482 else if (this == &theRight)
484 NCollection_Map aCopy (1, this->myAllocator);
486 Subtraction (theLeft, aCopy);
494 //! Apply to this Map the subtraction (aka set-theoretic difference, relative complement,
495 //! exclude, cut, boolean NOT) operation with another (given) Map.
496 //! The result contains only the values that were previously contained in this map and not contained in this map.
497 //! This algorithm is similar to method Subtract() with two operands.
498 //! Returns True if contents of this map is changed.
499 Standard_Boolean Subtract (const NCollection_Map& theOther)
501 if (this == &theOther)
505 return Standard_False;
509 return Standard_True;
512 const Standard_Integer anOldExtent = Extent();
513 for (Iterator anIter (theOther); anIter.More(); anIter.Next())
515 Remove (anIter.Key());
517 return anOldExtent != Extent();
520 //! Sets this Map to be the result of symmetric difference (aka exclusive disjunction, boolean XOR) operation between two given Maps.
521 //! The new Map contains the values that are contained only in the first or the second operand maps but not in both.
522 //! All previous content of this Map is cleared. This map (result of the boolean operation) can also be used as one of operands.
523 void Difference (const NCollection_Map& theLeft,
524 const NCollection_Map& theRight)
526 if (&theLeft == &theRight)
531 else if (this == &theLeft)
533 NCollection_Map aCopy (1, this->myAllocator);
535 Difference (aCopy, theRight);
538 else if (this == &theRight)
540 NCollection_Map aCopy (1, this->myAllocator);
542 Difference (theLeft, aCopy);
547 for (Iterator anIter (theLeft); anIter.More(); anIter.Next())
549 if (!theRight.Contains (anIter.Key()))
554 for (Iterator anIter (theRight); anIter.More(); anIter.Next())
556 if (!theLeft.Contains (anIter.Key()))
563 //! Apply to this Map the symmetric difference (aka exclusive disjunction, boolean XOR) operation with another (given) Map.
564 //! The result contains the values that are contained only in this or the operand map, but not in both.
565 //! This algorithm is similar to method Difference().
566 //! Returns True if contents of this map is changed.
567 Standard_Boolean Differ (const NCollection_Map& theOther)
569 if (this == &theOther)
573 return Standard_False;
576 return Standard_True;
579 const Standard_Integer anOldExtent = Extent();
580 Difference (*this, theOther);
581 return anOldExtent != Extent();