1 
2 /*
3  * File DHMap.hpp.
4  *
5  * This file is part of the source code of the software program
6  * Vampire. It is protected by applicable
7  * copyright laws.
8  *
9  * This source code is distributed under the licence found here
10  * https://vprover.github.io/license.html
11  * and in the source directory
12  *
13  * In summary, you are allowed to use Vampire for non-commercial
14  * purposes but not allowed to distribute, modify, copy, create derivatives,
15  * or use in competitions.
16  * For other uses of Vampire please contact developers for a different
17  * licence, which we will make an effort to provide.
18  */
19 /**
20  * @file DHMap.hpp
21  * Defines class DHMap<Key,Val,Hash1,Hash2> of maps, implemented as
22  * double hashed hashtables.
23  */
24 
25 #ifndef __DHMap__
26 #define __DHMap__
27 
28 #include <cstdlib>
29 #include <utility>
30 
31 #if VDEBUG
32 #include <typeinfo>
33 #endif
34 
35 #include "Debug/Assertion.hpp"
36 #include "Allocator.hpp"
37 #include "Exception.hpp"
38 #include "Hash.hpp"
39 #include "VirtualIterator.hpp"
40 
41 namespace Lib {
42 
43 #define DHMAP_MAX_CAPACITY_INDEX 29
44 
45 
46 /**
47  * Traits class for hash classes, which should be specialized
48  * for classes whose hash functions have second parameter for
49  * hashtable capacity.
50  */
51 template<typename Hash>
52 struct HashTraits
53 {
54   enum {SINGLE_PARAM_HASH=1};
55 };
56 
57 /**
58  * Auxiliary class for computing of hash values which depends on
59  * specializations of HashTraits class.
60  */
61 template<int I, class Hash, typename Key>
62 class HashCompClass {
63 };
64 
65 /**
66  * Auxiliary class for computing of hash values which depends on
67  * specializations of HashTraits class.
68  */
69 template<class Hash, typename Key>
70 struct HashCompClass<1,Hash,Key> {
computeLib::HashCompClass71   static inline unsigned compute(Key& key, int capacity)
72   {
73     return Hash::hash(key);
74   }
75 };
76 
77 /**
78  * Auxiliary class for computing of hash values which depends on
79  * specializations of HashTraits class.
80  */
81 template<class Hash, typename Key>
82 struct HashCompClass<0,Hash,Key> {
computeLib::HashCompClass83   static inline unsigned compute(Key& key, int capacity)
84   {
85     return Hash::hash(key, capacity);
86   }
87 };
88 
89 /** Computes hash value of given key for hashtable with specified capacity */
90 template<class Hash, typename Key>
91 inline
computeHash(Key & key,int capacity)92 unsigned computeHash(Key& key, int capacity)
93 {
94   return HashCompClass<HashTraits<Hash>::SINGLE_PARAM_HASH,Hash,Key>::compute(key, capacity);
95 };
96 
97 extern const unsigned DHMapTableCapacities[];
98 extern const unsigned DHMapTableNextExpansions[];
99 
100 /**
101  * Class DHMap implements generic maps with keys of a class Key
102  * and values of a class Value. If you implement a map with
103  * a new class Key, Hash1 and Hash2 are classes containing a function
104  * hash() mapping keys to unsigned integer values.
105  *
106  * @param Key a pointer or integral value (e.g., integer or long):
107  *        anything that can be hashed to an unsigned integer
108  *        and compared using ==
109  * @param Val values, can be anything
110  * @param Hash1 class containig the hash function for keys which
111  *	  determines position of entry in hashtable when no collision
112  *	  occurs. This function can also take second int parameter,
113  * 	  which will contain current capacity of the hashtable. In
114  * 	  this case, HashTraits struct has to be specialized for this
115  * 	  class, so that enum member SINGLE_PARAM_HASH is equal to 0.
116  * @param Hash2 class containig the hash function for keys which
117  *	  will be used when collision occurs. Otherwise it will not be
118  *	  enumerated.
119  */
120 template <typename Key, typename Val, class Hash1, class Hash2>
121 class DHMap
122 {
123 public:
124   CLASS_NAME(DHMap);
125   USE_ALLOCATOR(DHMap);
126 
127   /** Create a new DHMap */
DHMap()128   DHMap()
129   : _timestamp(1), _size(0), _deleted(0), _capacityIndex(0), _capacity(0),
130   _nextExpansionOccupancy(0), _entries(0), _afterLast(0)
131   {
132     ensureExpanded();
133   }
134 
DHMap(const DHMap & obj)135   DHMap(const DHMap& obj)
136   : _timestamp(1), _size(0), _deleted(0), _capacityIndex(0), _capacity(0),
137   _nextExpansionOccupancy(0), _entries(0), _afterLast(0)
138   {
139     ensureExpanded();
140 
141     typename DHMap::Iterator iit(obj);
142     while(iit.hasNext()) {
143       Key k;
144       Val v;
145       iit.next(k, v);
146       ALWAYS(insert(k,v));
147     }
148   }
149 
150   /** Deallocate the DHMap */
~DHMap()151   ~DHMap()
152   {
153     if(_entries) {
154       ASS_EQ(_afterLast-_entries,_capacity);
155       array_delete(_entries, _capacity);
156       DEALLOC_KNOWN(_entries,_capacity*sizeof(Entry),"DHMap::Entry");
157 //      DEALLOC_KNOWN(_entries,_capacity*sizeof(Entry),typeid(Entry).name());
158     }
159   }
160 
161   /** Empty the DHMap */
reset()162   void reset()
163   {
164     CALL("DHMap::reset");
165     unsigned oldTS=_timestamp;
166     _timestamp++;
167     _size=0;
168     _deleted=0;
169 
170     if(oldTS>(_timestamp&0x3FFFFFFF)) {
171       //We store timestamp only in 30 bits in entries,
172       //and they've just overflowed.
173       _timestamp=1;
174       Entry* pe=_afterLast;
175       while(pe--!=_entries) {
176 	pe->_info.timestamp=0;
177       }
178     }
179   }
180 
181   /**
182    *  Find value by the @b key. The result is true if a pair
183    *  with this key is in the map. If such a pair is found,
184    *  then its value is returned in @b val. Otherwise, the
185    *  value of @b val remains unchanged.
186    */
187   inline
find(Key key,Val & val) const188   bool find(Key key, Val& val) const
189   {
190     CALL("DHMap::find/2");
191     const Entry* e=findEntry(key);
192     if(!e) {
193       return false;
194     }
195     val=e->_val;
196     return true;
197   }
198 
199   /**
200    * Return a pointer to Val inside the map
201    * if entry corresponding to Key exists.
202    * Otherwise return nullptr.
203    */
findPtr(Key key)204   Val* findPtr(Key key)
205   {
206     CALL("DHMap::findPtr");
207     Entry* e=findEntry(key);
208     if(!e) {
209       return nullptr;
210     }
211     return &e->_val;
212   }
213 
214   /**
215    *  Return true iff a pair with @b key as a key is in the map.
216    */
217   inline
find(Key key) const218   bool find(Key key) const
219   {
220     CALL("DHMap::find/1");
221     return findEntry(key);
222   }
223 
224   /**
225    *  Return value associated with given key. A pair with
226    *  this key has to be present.
227    */
228   inline
get(Key key) const229   const Val& get(Key key) const
230   {
231     const Entry* e=findEntry(key);
232     ASS(e);
233     return e->_val;
234   }
235 
236   /**
237    *  Return value associated with given key. A pair with
238    *  this key has to be present.
239    */
240   inline
get(Key key)241   Val& get(Key key)
242   {
243     Entry* e=findEntry(key);
244     ASS(e);
245     return e->_val;
246   }
247 
248   /**
249    *  If @b key is present in the map, return value associated
250    *  with it; otherwise return @b def
251    */
252   inline
get(Key key,Val def) const253   Val get(Key key, Val def) const
254   {
255     const Entry* e=findEntry(key);
256     if(!e) {
257       return def;
258     }
259     return e->_val;
260   }
261 
262 
263   /** Load key-value pairs from a DHMap. The current map must not contain any elements from @c map. */
loadFromMap(const DHMap & map)264   void loadFromMap(const DHMap& map)
265   {
266     Iterator iit(map);
267     while(iit.hasNext()) {
268       Key k;
269       Val v;
270       iit.next(k, v);
271       ALWAYS(insert(k,v));
272     }
273   }
274 
275   /** Load key-value pairs from an inverted DHMap. The @b inverted map must be one-to-one. */
276   template<class HashX1, class HashX2>
loadFromInverted(const DHMap<Val,Key,HashX1,HashX2> & inverted)277   void loadFromInverted(const DHMap<Val, Key, HashX1, HashX2>& inverted)
278   {
279     typename DHMap<Val, Key, HashX1, HashX2>::Iterator iit(inverted);
280     while(iit.hasNext()) {
281       Key k;
282       Val v;
283       iit.next(v, k);
284       ALWAYS(insert(k,v));
285     }
286   }
287 
288   /**
289    * If there is no value stored under @b key in the map,
290    * insert pair (key,value) and return true. Otherwise,
291    * return false.
292    */
insert(Key key,const Val & val)293   bool insert(Key key, const Val& val)
294   {
295     CALL("DHMap::insert");
296     ensureExpanded();
297     Entry* e=findEntryToInsert(key);
298     bool exists = e->_info.timestamp==_timestamp && !e->_info.deleted;
299     if(!exists) {
300       if(e->_info.timestamp!=_timestamp) {
301 	e->_info.timestamp=_timestamp;
302 	//no collision has occured on this entry while this _timestamp is set
303 	e->_info.collision=0;
304       } else {
305 	ASS(e->_info.deleted);
306 	_deleted--;
307       }
308       e->_info.deleted=0;
309       e->_key=key;
310       e->_val=val;
311       _size++;
312     }
313     return !exists;
314   }
315 
316   /**
317    * If there is no value stored under @b key in the map,
318    * insert pair (key,value). Return value stored under @b key.
319    */
findOrInsert(Key key,const Val & val)320   Val findOrInsert(Key key, const Val& val)
321   {
322     CALL("DHMap::insert");
323     ensureExpanded();
324     Entry* e=findEntryToInsert(key);
325     bool exists = e->_info.timestamp==_timestamp && !e->_info.deleted;
326     if(!exists) {
327       if(e->_info.timestamp!=_timestamp) {
328 	e->_info.timestamp=_timestamp;
329 	//no collision has occured on this entry while this _timestamp is set
330 	e->_info.collision=0;
331       } else {
332 	ASS(e->_info.deleted);
333 	_deleted--;
334       }
335       e->_info.deleted=0;
336       e->_key=key;
337       e->_val=val;
338       _size++;
339     }
340     return e->_val;
341   }
342 
343   /**
344    * If there is no value stored under @b key in the map,
345    * insert pair (key,initial). Assign value stored under
346    * @b key into @b val. Return true iff the new value was
347    * inserted.
348    */
findOrInsert(Key key,Val & val,const Val & initial)349   bool findOrInsert(Key key, Val& val, const Val& initial)
350   {
351     CALL("DHMap::insert");
352     ensureExpanded();
353     Entry* e=findEntryToInsert(key);
354     bool exists = e->_info.timestamp==_timestamp && !e->_info.deleted;
355     if(!exists) {
356       if(e->_info.timestamp!=_timestamp) {
357 	e->_info.timestamp=_timestamp;
358 	//no collision has occured on this entry while this _timestamp is set
359 	e->_info.collision=0;
360       } else {
361 	ASS(e->_info.deleted);
362 	_deleted--;
363       }
364       e->_info.deleted=0;
365       e->_key=key;
366       e->_val=initial;
367       _size++;
368     }
369     val=e->_val;
370     return !exists;
371   }
372 
373   /**
374    * Assign pointer to value stored under @b key into @b pval.
375    * If nothing was previously stored under @b key, initialize
376    * the value with @b initial, and return true. Otherwise,
377    * return false.
378    */
getValuePtr(Key key,Val * & pval,const Val & initial)379   bool getValuePtr(Key key, Val*& pval, const Val& initial)
380   {
381     CALL("DHMap::getValuePtr/3");
382     ensureExpanded();
383     Entry* e=findEntryToInsert(key);
384     bool exists = e->_info.timestamp==_timestamp && !e->_info.deleted;
385     if(!exists) {
386       if(e->_info.timestamp!=_timestamp) {
387 	e->_info.timestamp=_timestamp;
388 	//no collision has occured on this entry while this _timestamp is set
389 	e->_info.collision=0;
390       } else {
391 	ASS(e->_info.deleted);
392 	_deleted--;
393       }
394       e->_info.deleted=0;
395       e->_key=key;
396       e->_val=initial;
397       _size++;
398     }
399     pval=&e->_val;
400     return !exists;
401   }
402 
403   /**
404    * Assign pointer to value stored under @b key into @b pval.
405    * If nothing was previously stored under @b key, return true
406    * and recreate the value object default constructor.
407    * Otherwise, return false.
408    */
getValuePtr(Key key,Val * & pval)409   bool getValuePtr(Key key, Val*& pval)
410   {
411     CALL("DHMap::getValuePtr/2");
412     ensureExpanded();
413     Entry* e=findEntryToInsert(key);
414     bool exists = e->_info.timestamp==_timestamp && !e->_info.deleted;
415     if(!exists) {
416       if(e->_info.timestamp!=_timestamp) {
417 	e->_info.timestamp=_timestamp;
418 	//no collision has occured on this entry while this _timestamp is set
419 	e->_info.collision=0;
420       } else {
421 	ASS(e->_info.deleted);
422 	_deleted--;
423       }
424       e->_info.deleted=0;
425       e->_key=key;
426       e->_val.~Val();
427       new(&e->_val) Val();
428       _size++;
429     }
430     pval=&e->_val;
431     return !exists;
432   }
433 
434   /**
435    * Store @b value under @b key. Return true if nothing was
436    * previously stored under @b key. Otherwise,
437    * return false.
438    */
set(Key key,const Val & val)439   bool set(Key key, const Val& val)
440   {
441     CALL("DHMap::set");
442     ensureExpanded();
443     Entry* e=findEntryToInsert(key);
444     bool exists = e->_info.timestamp==_timestamp && !e->_info.deleted;
445     if(!exists) {
446       if(e->_info.timestamp!=_timestamp) {
447 	e->_info.timestamp=_timestamp;
448 	//no collision has occured on this entry while this _timestamp is set
449 	e->_info.collision=0;
450       } else {
451 	ASS(e->_info.deleted);
452 	_deleted--;
453       }
454       e->_info.deleted=0;
455       e->_key=key;
456       _size++;
457     }
458     e->_val=val;
459     return !exists;
460   }
461 
462 
463   /**
464    *  Find value by the @b key. The result is true iff a pair
465    *  with this key is in the map. If such a pair is found,
466    *  then its value is returned in @b val, and the pair is
467    *  removed. Otherwise, the value of @b val remains unchanged.
468    */
469   inline
pop(Key key,Val & val)470   bool pop(Key key, Val& val)
471   {
472     CALL("DHMap::pop");
473     Entry* e=findEntry(key);
474     if(!e) {
475       return false;
476     }
477     val=e->_val;
478     e->_info.deleted=1;
479     _size--;
480     _deleted++;
481     return true;
482   }
483 
484 
485   /**
486    * If there is a value stored under the @b key, remove
487    * it and return true. Otherwise, return false.
488    */
remove(Key key)489   bool remove(Key key)
490   {
491     CALL("DHMap::remove");
492     Entry* e=findEntry(key);
493     if(!e) {
494       return false;
495     }
496     e->_info.deleted=1;
497     _size--;
498     _deleted++;
499     return true;
500   }
501 
502 
503   /** Return mumber of entries stored in this DHMap */
504   inline
size() const505   unsigned size() const
506   {
507     ASS(_size>=0);
508     return _size;
509   }
510 
511   /** Return true iff there are any entries stored in this DHMap */
512   inline
isEmpty() const513   bool isEmpty() const
514   {
515     ASS(_size>=0);
516     return _size==0;
517   }
518 
519   /** Return one arbitrary key, that is present in the map */
getOneKey()520   Key getOneKey()
521   {
522     Iterator it(*this);
523     ALWAYS(it.hasNext());
524     return it.nextKey();
525   }
526 
527 private:
528   struct Entry
529   {
530     /** Create a new Entry */
EntryLib::DHMap::Entry531     Entry() : _infoData(0) {}
532     union {
533       struct {
534 	unsigned deleted : 1;
535 	/** 1 if first collision occured on this entry during some insertion */
536 	unsigned collision : 1;
537 	unsigned timestamp : 30;
538       } _info;
539       int _infoData;
540     };
541     Key _key;
542     Val _val;
543   };
544 
545   /** operator= is private and without a body, because we don't want any. */
546   DHMap& operator=(const DHMap& obj);
547 
548 
549   /** Check whether an expansion is needed and if so, expand */
550   inline
ensureExpanded()551   void ensureExpanded()
552   {
553     if(_size+_deleted>=_nextExpansionOccupancy) {
554       //cout << this << ", " << _size << ", " << _deleted << ", " << _nextExpansionOccupancy << endl;
555       expand();
556     }
557   }
558 
559   /** Expand DHMap to about double of its current size */
expand()560   void expand()
561   {
562     CALL("DHMap::expand");
563 
564     if(_capacityIndex>=DHMAP_MAX_CAPACITY_INDEX) {
565       throw Exception("Lib::DHMap::expand: MaxCapacityIndex reached.");
566     }
567 
568     int newCapacity=DHMapTableCapacities[_capacityIndex+1];
569     void* mem = ALLOC_KNOWN(newCapacity*sizeof(Entry),"DHMap::Entry");
570 //    void* mem = ALLOC_KNOWN(newCapacity*sizeof(Entry),typeid(Entry).name());
571 
572     //std::cout << (_size+_deleted) << std::endl;
573 
574     Entry* oldEntries=_entries;
575     Entry* oldAfterLast=_afterLast;
576     unsigned oldTimestamp=_timestamp;
577     int oldCapacity=_capacity;
578 
579     _timestamp=1;
580     _size=0;
581     _deleted=0;
582     _capacityIndex++;
583     _capacity = newCapacity;
584     _nextExpansionOccupancy = DHMapTableNextExpansions[_capacityIndex];
585 
586     _entries = array_new<Entry>(mem, _capacity);
587     _afterLast = _entries + _capacity;
588 
589     Entry* ep=oldEntries;
590     while(ep!=oldAfterLast) {
591       ASS(ep);
592       if(ep->_info.timestamp==oldTimestamp && !ep->_info.deleted) {
593 	insert(ep->_key, ep->_val);
594       }
595       (ep++)->~Entry();
596     }
597     //std::cout << "copied" << std::endl;
598     if(oldCapacity) {
599       DEALLOC_KNOWN(oldEntries,oldCapacity*sizeof(Entry),"DHMap::Entry");
600 //      DEALLOC_KNOWN(oldEntries,oldCapacity*sizeof(Entry),typeid(Entry).name());
601     }
602   }
603 
604   /** Return pointer to an Entry object which contains specified key,
605    * or 0, if there is no such */
606   inline
findEntry(Key key)607   Entry* findEntry(Key key)
608   {
609     return const_cast<Entry*>(static_cast<const DHMap*>(this)->findEntry(key));
610   }
611 
612   /** Return pointer to an Entry object which contains specified key,
613    * or 0, if there is no such */
findEntry(Key key) const614   const Entry* findEntry(Key key) const
615   {
616     CALL("DHMap::findEntry");
617     ASS(_capacity>_size+_deleted);
618 
619     unsigned h1=computeHash<Hash1>(key, _capacity);
620     int pos=h1%_capacity;
621     Entry* res=&_entries[pos];
622     if(res->_info.timestamp != _timestamp ) {
623       return 0;
624     }
625     if(res->_key==key) {
626       return res->_info.deleted ? 0 : res;
627     }
628 
629     //We have a collision...
630 
631     if(!res->_info.collision) {
632       //There were no collisions on this position during inserting,
633       //so the key we're searching for isn't here anyway
634       return 0;
635     }
636 
637     unsigned h2=Hash2::hash(key)%_capacity;
638     if(h2==0) {
639       h2=1;
640     }
641     do {
642       pos=(pos+h2)%_capacity;
643       res=&_entries[pos];
644     } while (res->_info.timestamp == _timestamp && res->_key!=key);
645 
646     if(res->_info.timestamp != _timestamp ) {
647       return 0;
648     }
649 
650     ASS(res->_key==key);
651     return res->_info.deleted ? 0 : res;
652   }
653 
654   /** Return pointer to an Entry object which contains, or could contain
655    * specified key */
findEntryToInsert(Key key)656   Entry* findEntryToInsert(Key key)
657   {
658     CALL("DHMap::findEntryToInsert");
659     ASS(_capacity>_size+_deleted);
660 
661     unsigned h1=computeHash<Hash1>(key, _capacity);
662     int pos=h1%_capacity;
663     Entry* res=&_entries[pos];
664     if(res->_info.timestamp != _timestamp || res->_key==key) {
665       return res;
666     }
667 
668     //We have a collision...
669 
670     //mark the entry where the collision occured
671     res->_info.collision=1;
672 
673     unsigned h2=Hash2::hash(key)%_capacity;
674     if(h2==0) {
675       h2=1;
676     }
677     do {
678       pos=(pos+h2)%_capacity;
679       res=&_entries[pos];
680     } while (res->_info.timestamp == _timestamp && res->_key!=key);
681     return res;
682   }
683 
684   /** Entries with _timestamp different from this are considered empty */
685   unsigned _timestamp;
686   /** Number of entries stored in this DHMap */
687   int _size;
688   /** Number of entries marked as deleted */
689   int _deleted;
690   /** Index of current _capacity in the TableCapacities array */
691   int _capacityIndex;
692   /** Size of the _entries array */
693   int _capacity;
694   /** When _size+_deleted reaches this, expansion will occur */
695   int _nextExpansionOccupancy;
696 
697   /** Array containing hashtable storing content of this map */
698   Entry* _entries;
699   /** Pointer to element after the last element of _entries array */
700   Entry* _afterLast;
701 
702 private:
703   class IteratorBase {
704   public:
705     /** Create a new IteratorBase */
IteratorBase(const DHMap & map)706     inline IteratorBase(const DHMap& map)
707     : _next(map._entries), _last(map._afterLast),
708     _timestamp(map._timestamp) {}
709 
710     /**
711      * True if there exists next element
712      */
hasNext()713     bool hasNext()
714     {
715       CALL("DHMap::DomainIteratorCore::hasNext");
716       while (_next != _last) {
717 	if (_next->_info.timestamp==_timestamp && !_next->_info.deleted) {
718 	  return true;
719 	}
720 	_next++;
721       }
722       return false;
723     }
724 
725     /**
726      * Return the next entry
727      * @warning hasNext() must have been called before
728      */
729     inline
next()730     Entry* next()
731     {
732       CALL("DHMap::DomainIteratorCore::next");
733       ASS(_next != _last);
734       ASS(_next->_info.timestamp==_timestamp && !_next->_info.deleted);
735       return _next++;
736     }
737 
738   private:
739     /** iterator will look for the next occupied cell starting with this one */
740     Entry* _next;
741     /** iterator will stop looking for the next cell after reaching this one */
742     Entry* _last;
743     /** only cells with _timestamp equal to this are considered occupied */
744     unsigned _timestamp;
745   }; // class DHMap::IteratorBase
746 
747   class DomainIteratorCore
748   : public IteratorCore<Key> {
749   public:
750     /** Create a new iterator */
DomainIteratorCore(const DHMap & map)751     inline DomainIteratorCore(const DHMap& map) : _base(map) {}
752     /** True if there exists next element */
hasNext()753     inline bool hasNext() { return _base.hasNext(); }
754 
755     /**
756      * Return the next key
757      * @warning hasNext() must have been called before
758      */
next()759     inline Key next() { return _base.next()->_key; }
760   private:
761     IteratorBase _base;
762   }; // class DHMap::DomainIteratorCore
763 
764     class RangeIteratorCore
765     : public IteratorCore<Val> {
766     public:
767         /** Create a new iterator */
RangeIteratorCore(const DHMap & map)768         inline RangeIteratorCore(const DHMap& map) : _base(map) {}
769         /** True if there exists next element */
hasNext()770         inline bool hasNext() { return _base.hasNext(); }
771 
772         /**
773          * Return the next key
774          * @warning hasNext() must have been called before
775          */
next()776         inline Val next() { return _base.next()->_val; }
777     private:
778         IteratorBase _base;
779     }; // class DHMap::RangeIteratorCore
780 
781 public:
domain() const782   VirtualIterator<Key> domain() const
783   {
784     return VirtualIterator<Key>(new DomainIteratorCore(*this));
785   }
range() const786   VirtualIterator<Val> range() const
787   {
788     return VirtualIterator<Val>(new RangeIteratorCore(*this));
789   }
790 
791   typedef std::pair<Key,Val> Item;
792 
793 private:
794   class ItemIteratorCore
795   : public IteratorCore<Item> {
796   public:
797     /** Create a new iterator */
ItemIteratorCore(const DHMap & map)798     inline ItemIteratorCore(const DHMap& map) : _base(map) {}
799     /** True if there exists next element */
hasNext()800     inline bool hasNext() { return _base.hasNext(); }
801 
802     /**
803      * Return the next key
804      * @warning hasNext() must have been called before
805      */
next()806     inline Item next()
807     {
808       Entry* e=_base.next();
809       return Item(e->_key, e->_val);
810     }
811   private:
812     IteratorBase _base;
813   }; // class DHMap::DomainIteratorCore
814 public:
815 
items() const816   VirtualIterator<Item> items() const
817   {
818     return VirtualIterator<Item>(new ItemIteratorCore(*this));
819   }
820 
821 
822   /**
823    * Class to allow iteration over keys and values stored in the map.
824    */
825   class Iterator {
826   public:
827     /** Create a new iterator */
Iterator(const DHMap & map)828     inline Iterator(const DHMap& map) : _base(map) {}
829 
830     /** True if there exists next element */
hasNext()831     bool hasNext() { return _base.hasNext(); }
832 
833     /**
834      * Assign key and value of the next entry to respective parameters
835      * @warning hasNext() must have been called before
836      */
837     inline
next(Key & key,Val & val)838     void next(Key& key, Val& val)
839     {
840       Entry* e=_base.next();
841       key=e->_key;
842       val=e->_val;
843     }
844 
845     /**
846      * Return next value via reference and pass corresponding key via argument.
847      * @warning hasNext() must have been called before
848      */
849     inline
nextRef(Key & key)850     Val& nextRef(Key& key)
851     {
852       Entry* e= _base.next();
853       key= e->_key;
854       return e->_val;
855     }
856 
857     /**
858      * Return the next value
859      * @warning hasNext() must have been called before
860      */
next()861     inline Val next() { return _base.next()->_val; }
862 
863     /**
864      * Return the key of next entry
865      * @warning hasNext() must have been called before
866      */
nextKey()867     inline Key nextKey() { return _base.next()->_key; }
868 
869   private:
870     IteratorBase _base;
871   }; // class DHMap::Iterator
872 
873   /**
874    * Class to allow iteration over keys and values stored in the map,
875    * modification of the value and deleteion of the entry.
876    */
877   class DelIterator {
878   public:
879     /** Create a new iterator */
DelIterator(DHMap & map)880     inline DelIterator(DHMap& map) : _base(map), _map(map) {}
881 
882     /** True if there exists next element */
hasNext()883     bool hasNext() { return _base.hasNext(); }
884 
885     /**
886      * Assign key and value of the next entry to respective parameters
887      * @warning hasNext() must have been called before
888      */
889     inline
next(Key & key,Val & val)890     void next(Key& key, Val& val)
891     {
892       Entry* e=getNextEntry();
893       key=e->_key;
894       val=e->_val;
895     }
896 
897     /**
898      * Return the next value
899      * @warning hasNext() must have been called before
900      */
next()901     inline Val next() { return getNextEntry()->_val; }
902 
903     /**
904      * Return the key of next entry
905      * @warning hasNext() must have been called before
906      */
nextKey()907     inline Key nextKey() { return getNextEntry()->_key; }
908 
del()909     void del() {
910       CALL("DHMap::DelIterator::del");
911       _curr->_info.deleted=1;
912       _map._size--;
913       _map._deleted++;
914     }
915 
setValue(Val val)916     void setValue(Val val) {
917       CALL("DHMap::DelIterator::setValue");
918       _curr->_val = val;
919     }
920 
921   private:
getNextEntry()922     Entry* getNextEntry() {
923       _curr = _base.next();
924       return _curr;
925     }
926 
927     IteratorBase _base;
928     DHMap& _map;
929     Entry* _curr;
930   }; // class DHMap::Iterator
931 
932 
933 
934 }; // class DHMap
935 
936 }
937 
938 #endif // __DHMap__
939 
940