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