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_ImmutableObject.hxx>
26 #include <Standard_NoSuchObject.hxx>
29 * Purpose: Single hashed Map. This Map is used to store and
30 * retrieve keys in linear time.
32 * The ::Iterator class can be used to explore the
33 * content of the map. It is not wise to iterate and
34 * modify a map in parallel.
36 * To compute the hashcode of the key the function
37 * ::HashCode must be defined in the global namespace
39 * To compare two keys the function ::IsEqual must be
40 * defined in the global namespace.
42 * The performance of a Map is conditionned by its
43 * number of buckets that should be kept greater to
44 * the number of keys. This map has an automatic
45 * management of the number of buckets. It is resized
46 * when the number of Keys becomes greater than the
49 * If you have a fair idea of the number of objects
50 * you can save on automatic resizing by giving a
51 * number of buckets at creation or using the ReSize
52 * method. This should be consider only for crucial
53 * optimisation issues.
56 template < class TheKeyType,
57 class Hasher = NCollection_DefaultHasher<TheKeyType> >
58 class NCollection_Map : public NCollection_BaseMap
60 //! Adaptation of the TListNode to the map notations
63 class MapNode : public NCollection_TListNode<TheKeyType>
66 //! Constructor with 'Next'
67 MapNode (const TheKeyType& theKey,
68 NCollection_ListNode* theNext) :
69 NCollection_TListNode<TheKeyType> (theKey, theNext) {}
71 const TheKeyType& Key (void)
72 { return this->Value(); }
77 //! Implementation of the Iterator interface.
78 class Iterator : public NCollection_BaseMap::Iterator
83 NCollection_BaseMap::Iterator() {}
85 Iterator (const NCollection_Map& theMap) :
86 NCollection_BaseMap::Iterator(theMap) {}
87 //! Query if the end of collection is reached by iterator
88 Standard_Boolean More(void) const
90 //! Make a step along the collection
94 const TheKeyType& Value(void) const
96 Standard_NoSuchObject_Raise_if (!More(), "NCollection_Map::Iterator::Value");
97 return ((MapNode *) myNode)->Value();
99 //! Value change access - denied
100 TheKeyType& ChangeValue(void) const
102 Standard_ImmutableObject::Raise("NCollection_Map::Iterator::ChangeValue");
103 return * (TheKeyType *) NULL; // For compiler
106 const TheKeyType& Key (void) const
108 Standard_NoSuchObject_Raise_if (!More(), "NCollection_Map::Iterator::Key");
109 return ((MapNode *) myNode)->Value();
113 //! Shorthand for a constant iterator type.
114 typedef NCollection_StlIterator<std::forward_iterator_tag, Iterator, TheKeyType, true> const_iterator;
116 //! Returns a const iterator pointing to the first element in the map.
117 const_iterator cbegin() const { return Iterator (*this); }
119 //! Returns a const iterator referring to the past-the-end element in the map.
120 const_iterator cend() const { return Iterator(); }
123 // ---------- PUBLIC METHODS ------------
126 NCollection_Map (const Standard_Integer NbBuckets = 1,
127 const Handle(NCollection_BaseAllocator)& theAllocator = 0L) :
128 NCollection_BaseMap (NbBuckets, Standard_True, theAllocator) {}
131 NCollection_Map (const NCollection_Map& theOther) :
132 NCollection_BaseMap (theOther.NbBuckets(), Standard_True, theOther.myAllocator)
133 { *this = theOther; }
135 //! Exchange the content of two maps without re-allocations.
136 //! Notice that allocators will be swapped as well!
137 void Exchange (NCollection_Map& theOther)
139 this->exchangeMapsData (theOther);
143 NCollection_Map& Assign (const NCollection_Map& theOther)
145 if (this == &theOther)
148 Clear(theOther.myAllocator);
149 ReSize (theOther.Extent()-1);
150 Iterator anIter(theOther);
151 for (; anIter.More(); anIter.Next())
157 NCollection_Map& operator= (const NCollection_Map& theOther)
159 return Assign(theOther);
163 void ReSize (const Standard_Integer N)
165 NCollection_ListNode** newdata = 0L;
166 NCollection_ListNode** dummy = 0L;
167 Standard_Integer newBuck;
168 if (BeginResize (N, newBuck, newdata, dummy))
172 MapNode** olddata = (MapNode**) myData1;
174 Standard_Integer i,k;
175 for (i = 0; i <= NbBuckets(); i++)
182 k = Hasher::HashCode(p->Key(),newBuck);
183 q = (MapNode*) p->Next();
184 p->Next() = newdata[k];
191 EndResize (N, newBuck, newdata, dummy);
196 Standard_Boolean Add(const TheKeyType& K)
200 MapNode** data = (MapNode**)myData1;
201 Standard_Integer k = Hasher::HashCode(K,NbBuckets());
202 MapNode* p = data[k];
205 if (Hasher::IsEqual(p->Key(),K))
206 return Standard_False;
207 p = (MapNode *) p->Next();
209 data[k] = new (this->myAllocator) MapNode(K,data[k]);
211 return Standard_True;
214 //! Added: add a new key if not yet in the map, and return
215 //! reference to either newly added or previously existing object
216 const TheKeyType& Added(const TheKeyType& K)
220 MapNode** data = (MapNode**)myData1;
221 Standard_Integer k = Hasher::HashCode(K,NbBuckets());
222 MapNode* p = data[k];
225 if (Hasher::IsEqual(p->Key(),K))
227 p = (MapNode *) p->Next();
229 data[k] = new (this->myAllocator) MapNode(K,data[k]);
231 return data[k]->Key();
235 Standard_Boolean Contains(const TheKeyType& K) const
238 return Standard_False;
239 MapNode** data = (MapNode**) myData1;
240 MapNode* p = data[Hasher::HashCode(K,NbBuckets())];
243 if (Hasher::IsEqual(p->Key(),K))
244 return Standard_True;
245 p = (MapNode *) p->Next();
247 return Standard_False;
251 Standard_Boolean Remove(const TheKeyType& K)
254 return Standard_False;
255 MapNode** data = (MapNode**) myData1;
256 Standard_Integer k = Hasher::HashCode(K,NbBuckets());
257 MapNode* p = data[k];
261 if (Hasher::IsEqual(p->Key(),K))
265 q->Next() = p->Next();
267 data[k] = (MapNode*) p->Next();
269 this->myAllocator->Free(p);
270 return Standard_True;
273 p = (MapNode*) p->Next();
275 return Standard_False;
278 //! Clear data. If doReleaseMemory is false then the table of
279 //! buckets is not released and will be reused.
280 void Clear(const Standard_Boolean doReleaseMemory = Standard_True)
281 { Destroy (MapNode::delNode, doReleaseMemory); }
283 //! Clear data and reset allocator
284 void Clear (const Handle(NCollection_BaseAllocator)& theAllocator)
287 this->myAllocator = ( ! theAllocator.IsNull() ? theAllocator :
288 NCollection_BaseAllocator::CommonBaseAllocator() );
292 ~NCollection_Map (void)
296 Standard_Integer Size(void) const
300 //!@name Boolean operations with maps as sets of keys
303 //! @return true if two maps contains exactly the same keys
304 Standard_Boolean IsEqual (const NCollection_Map& theOther) const
306 return Extent() == theOther.Extent()
307 && Contains (theOther);
310 //! @return true if this map contains ALL keys of another map.
311 Standard_Boolean Contains (const NCollection_Map& theOther) const
313 if (this == &theOther
314 || theOther.IsEmpty())
316 return Standard_True;
318 else if (Extent() < theOther.Extent())
320 return Standard_False;
323 for (Iterator anIter (theOther); anIter.More(); anIter.Next())
325 if (!Contains (anIter.Key()))
327 return Standard_False;
331 return Standard_True;
334 //! Sets this Map to be the result of union (aka addition, fuse, merge, boolean OR) operation between two given Maps
335 //! The new Map contains the values that are contained either in the first map or in the second map or in both.
336 //! All previous content of this Map is cleared.
337 //! This map (result of the boolean operation) can also be passed as one of operands.
338 void Union (const NCollection_Map& theLeft,
339 const NCollection_Map& theRight)
341 if (&theLeft == &theRight)
348 && this != &theRight)
353 if (this != &theLeft)
355 for (Iterator anIter (theLeft); anIter.More(); anIter.Next())
360 if (this != &theRight)
362 for (Iterator anIter (theRight); anIter.More(); anIter.Next())
369 //! Apply to this Map the boolean operation union (aka addition, fuse, merge, boolean OR) with another (given) Map.
370 //! The result contains the values that were previously contained in this map or contained in the given (operand) map.
371 //! This algorithm is similar to method Union().
372 //! Returns True if contents of this map is changed.
373 Standard_Boolean Unite (const NCollection_Map& theOther)
375 if (this == &theOther)
377 return Standard_False;
380 const Standard_Integer anOldExtent = Extent();
381 Union (*this, theOther);
382 return anOldExtent != Extent();
385 //! Sets this Map to be the result of intersection (aka multiplication, common, boolean AND) operation between two given Maps.
386 //! The new Map contains only the values that are contained in both map operands.
387 //! All previous content of this Map is cleared.
388 //! This same map (result of the boolean operation) can also be used as one of operands.
389 void Intersection (const NCollection_Map& theLeft,
390 const NCollection_Map& theRight)
392 if (&theLeft == &theRight)
398 if (this == &theLeft)
400 NCollection_Map aCopy (1, this->myAllocator);
402 Intersection (aCopy, theRight);
405 else if (this == &theRight)
407 NCollection_Map aCopy (1, this->myAllocator);
409 Intersection (theLeft, aCopy);
414 if (theLeft.Extent() < theRight.Extent())
416 for (Iterator anIter (theLeft); anIter.More(); anIter.Next())
418 if (theRight.Contains (anIter.Key()))
426 for (Iterator anIter (theRight); anIter.More(); anIter.Next())
428 if (theLeft.Contains (anIter.Key()))
436 //! Apply to this Map the intersection operation (aka multiplication, common, boolean AND) with another (given) Map.
437 //! The result contains only the values that are contained in both this and the given maps.
438 //! This algorithm is similar to method Intersection().
439 //! Returns True if contents of this map is changed.
440 Standard_Boolean Intersect (const NCollection_Map& theOther)
442 if (this == &theOther
445 return Standard_False;
448 const Standard_Integer anOldExtent = Extent();
449 Intersection (*this, theOther);
450 return anOldExtent != Extent();
453 //! Sets this Map to be the result of subtraction (aka set-theoretic difference, relative complement,
454 //! exclude, cut, boolean NOT) operation between two given Maps.
455 //! The new Map contains only the values that are contained in the first map operands and not contained in the second one.
456 //! All previous content of this Map is cleared.
457 void Subtraction (const NCollection_Map& theLeft,
458 const NCollection_Map& theRight)
460 if (this == &theLeft)
465 else if (this == &theRight)
467 NCollection_Map aCopy (1, this->myAllocator);
469 Subtraction (theLeft, aCopy);
477 //! Apply to this Map the subtraction (aka set-theoretic difference, relative complement,
478 //! exclude, cut, boolean NOT) operation with another (given) Map.
479 //! The result contains only the values that were previously contained in this map and not contained in this map.
480 //! This algorithm is similar to method Subtract() with two operands.
481 //! Returns True if contents of this map is changed.
482 Standard_Boolean Subtract (const NCollection_Map& theOther)
484 if (this == &theOther)
488 return Standard_False;
492 return Standard_True;
495 const Standard_Integer anOldExtent = Extent();
496 for (Iterator anIter (theOther); anIter.More(); anIter.Next())
498 Remove (anIter.Key());
500 return anOldExtent != Extent();
503 //! Sets this Map to be the result of symmetric difference (aka exclusive disjunction, boolean XOR) operation between two given Maps.
504 //! The new Map contains the values that are contained only in the first or the second operand maps but not in both.
505 //! All previous content of this Map is cleared. This map (result of the boolean operation) can also be used as one of operands.
506 void Difference (const NCollection_Map& theLeft,
507 const NCollection_Map& theRight)
509 if (&theLeft == &theRight)
514 else if (this == &theLeft)
516 NCollection_Map aCopy (1, this->myAllocator);
518 Difference (aCopy, theRight);
521 else if (this == &theRight)
523 NCollection_Map aCopy (1, this->myAllocator);
525 Difference (theLeft, aCopy);
530 for (Iterator anIter (theLeft); anIter.More(); anIter.Next())
532 if (!theRight.Contains (anIter.Key()))
537 for (Iterator anIter (theRight); anIter.More(); anIter.Next())
539 if (!theLeft.Contains (anIter.Key()))
546 //! Apply to this Map the symmetric difference (aka exclusive disjunction, boolean XOR) operation with another (given) Map.
547 //! The result contains the values that are contained only in this or the operand map, but not in both.
548 //! This algorithm is similar to method Difference().
549 //! Returns True if contents of this map is changed.
550 Standard_Boolean Differ (const NCollection_Map& theOther)
552 if (this == &theOther)
556 return Standard_False;
559 return Standard_True;
562 const Standard_Integer anOldExtent = Extent();
563 Difference (*this, theOther);
564 return anOldExtent != Extent();