aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
hashTable_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40#pragma once
41
42
49#include <iostream>
50#include <sstream>
51#include <string>
52
53// to help IDE parser
55
56namespace gum {
57
58
59 // ===========================================================================
60 // === IMPLEMENTATION OF THE CHAINED LISTS USED IN THE HASH TABLES ===
61 // ===========================================================================
62
63 template < typename Key, typename Val >
64 void HashTableList< Key, Val >::_copy_(const HashTableList< Key, Val >& from) {
65 Bucket *ptr, *old_ptr{nullptr}, *new_elt{nullptr};
66 // set the defaults
67 _deb_list_ = nullptr;
68
69 // copy from's list
70 try {
71 for (ptr = from._deb_list_; ptr != nullptr; ptr = ptr->next) {
72 // copy the current from's bucket (may throw an exception either because
73 // new cannot allocate the bucket or because the copy constructor of Val
74 // throws an exception)
75 new_elt = new Bucket(*ptr);
76
77 // rechain properly the new list
78 new_elt->prev = old_ptr;
79
80 if (old_ptr != nullptr) old_ptr->next = new_elt;
81 else _deb_list_ = new_elt;
82
83 old_ptr = new_elt;
84 }
85
86 if (old_ptr != nullptr) old_ptr->next = nullptr;
87
88 // update the number of elements stored into the list and the end of the
89 // list
90 _nb_elements_ = from._nb_elements_;
91 _end_list_ = new_elt;
92 } catch (...) {
93 // problem: we could not allocate an element in the list => we delete
94 // the elements created so far and we throw an exception
95 for (; _deb_list_ != nullptr; _deb_list_ = new_elt) {
96 new_elt = _deb_list_->next;
97 delete _deb_list_;
98 }
99
100 _nb_elements_ = 0;
101 _end_list_ = nullptr;
102
103 throw;
104 }
105 }
106
107 template < typename Key, typename Val >
109 for (Bucket* ptr = _deb_list_; ptr != nullptr; ptr = ptr->next)
110 if (ptr->key() == key) return ptr;
111
112 return nullptr;
113 }
114
115 template < typename Key, typename Val >
117 // check that the pointer is not nullptr
118 if (ptr == nullptr) { GUM_ERROR(NullElement, "trying to erase a nullptr bucket") }
119
120 // relink properly the doubly chained list
121 if (ptr->prev != nullptr) ptr->prev->next = ptr->next;
122 else _deb_list_ = ptr->next;
123
124 if (ptr->next != nullptr) ptr->next->prev = ptr->prev;
125 else _end_list_ = ptr->prev;
126
127 // remove the current element from the list
128 delete ptr;
129
131 }
132
133 template < typename Key, typename Val >
135
136 template < typename Key, typename Val >
137 INLINE HashTableList< Key, Val >::HashTableList(const HashTableList< Key, Val >& from) {
138 _copy_(from);
139 }
140
141 template < typename Key, typename Val >
142 INLINE HashTableList< Key, Val >::HashTableList(HashTableList< Key, Val >&& from) noexcept :
143 _deb_list_{from._deb_list_}, _end_list_{from._end_list_}, _nb_elements_{from._nb_elements_} {
144 from._deb_list_ = nullptr;
145 }
146
147 template < typename Key, typename Val >
149 for (Bucket *next_ptr, *ptr = _deb_list_; ptr != nullptr; ptr = next_ptr) {
150 next_ptr = ptr->next;
151 delete ptr;
152 }
153 }
154
155 template < typename Key, typename Val >
157 for (Bucket *next_ptr, *ptr = _deb_list_; ptr != nullptr; ptr = next_ptr) {
158 next_ptr = ptr->next;
159 delete ptr;
160 }
161
162 _nb_elements_ = Size(0);
163 _deb_list_ = nullptr;
164 _end_list_ = nullptr;
165 }
166
167 template < typename Key, typename Val >
168 INLINE HashTableList< Key, Val >&
169 HashTableList< Key, Val >::operator=(const HashTableList< Key, Val >& from) {
170 // avoid self assignment
171 if (this != &from) {
172 clear();
173 _copy_(from);
174 }
175
176 return *this;
177 }
178
179 template < typename Key, typename Val >
180 INLINE HashTableList< Key, Val >&
181 HashTableList< Key, Val >::operator=(HashTableList< Key, Val >&& from) noexcept {
182 // avoid self assignment
183 if (this != &from) {
184 _deb_list_ = from._deb_list_;
185 _end_list_ = from._end_list_;
186 _nb_elements_ = from._nb_elements_;
187 from._deb_list_ = nullptr;
188 }
189
190 return *this;
191 }
192
193 template < typename Key, typename Val >
195 if (i >= _nb_elements_) { GUM_ERROR(NotFound, "not enough elements in the chained list") }
196
197 Bucket* ptr;
198
199 for (ptr = _deb_list_; i; --i, ptr = ptr->next) {}
200
201 return ptr->elt();
202 }
203
204 template < typename Key, typename Val >
205 INLINE const typename HashTableList< Key, Val >::value_type&
207 if (i >= _nb_elements_) { GUM_ERROR(NotFound, "not enough elements in the chained list") }
208
209 Bucket* ptr;
210
211 for (ptr = _deb_list_; i; --i, ptr = ptr->next) {}
212
213 return ptr->elt();
214 }
215
216 template < typename Key, typename Val >
217 INLINE const typename HashTableList< Key, Val >::mapped_type&
219 for (Bucket* ptr = _deb_list_; ptr != nullptr; ptr = ptr->next)
220 if (ptr->key() == key) return ptr->val();
221
222 GUM_ERROR(NotFound, "No element with the key <" << key << ">")
223 }
224
225 template < typename Key, typename Val >
228 for (Bucket* ptr = _deb_list_; ptr != nullptr; ptr = ptr->next)
229 if (ptr->key() == key) return ptr->val();
230
231 GUM_ERROR(NotFound, "No element with the key <" << key << ">")
232 }
233
234 template < typename Key, typename Val >
235 INLINE bool HashTableList< Key, Val >::exists(const Key& key) const {
236 for (Bucket* ptr = _deb_list_; ptr != nullptr; ptr = ptr->next) {
237 if (ptr->key() == key) { return true; }
238 }
239
240 return false;
241 }
242
243 template < typename Key, typename Val >
244 INLINE bool HashTableList< Key, Val >::empty() const noexcept {
245 return (_nb_elements_ == Size(0));
246 }
247
248 template < typename Key, typename Val >
250 // place the bucket at the beginning of the list
251 new_elt->prev = nullptr;
252 new_elt->next = _deb_list_;
253
254 if (_deb_list_ != nullptr) _deb_list_->prev = new_elt;
255 else _end_list_ = new_elt;
256
257 _deb_list_ = new_elt;
258
260 }
261
262 // ===========================================================================
263 // === GENERIC HASH TABLE IMPLEMENTATION ===
264 // ===========================================================================
265
266 template < typename Key, typename Val >
268 // in debug mode, check that this and table have ' __nodes' arrays of the
269 // same size
270 GUM_ASSERT(table._size_ == _size_);
271
272 // try to fill the array of chained lists
273 for (Size i = 0; i < table._size_; ++i) {
274 try {
275 _nodes_[i] = table._nodes_[i];
276 } catch (...) {
277 // here we could allocate the _nodes_[j], j=0..i-1, so we should
278 // deallocate them
279 for (Size j = 0; j < _size_; ++j)
280 _nodes_[j].clear();
281
282 _nb_elements_ = Size(0);
283
284 // propagate the exception
285 throw;
286 }
287 }
288
290 }
291
292 template < typename Key, typename Val >
294 // setup the _nodes_ vector (contains only empty lists)
295 _nodes_.resize(size);
296
297 // set up properly the hash function
298 _hash_func_.resize(size);
299 }
300
301 template < typename Key, typename Val >
302 HashTable< Key, Val >::HashTable(Size size_param, bool resize_pol, bool key_uniqueness_pol) :
303 // size must be >= 2 else we lose all the bits of the hash function
304 _size_{Size(1) << _hashTableLog2_(std::max(Size(2), size_param))},
305 _resize_policy_{resize_pol}, _key_uniqueness_policy_{key_uniqueness_pol} {
306 // for debugging purposes
307 GUM_CONSTRUCTOR(HashTable);
308
309 // finalize the creation
311 }
312
313 template < typename Key, typename Val >
314 HashTable< Key, Val >::HashTable(std::initializer_list< std::pair< Key, Val > > list) :
315 // size must be >= 2 else we lose all the bits of the hash function
316 _size_{Size(1) << _hashTableLog2_(std::max< Size >(Size(2), Size(list.size()) / 2))} {
317 // for debugging purposes
318 GUM_CONSTRUCTOR(HashTable);
319
320 // setup the _nodes_ vector (contains only empty lists)
322
323 // insert all the elements
324 for (const auto& elt: list) {
325 insert(elt);
326 }
327 }
328
329 template < typename Key, typename Val >
333 // for debugging purposes
334 GUM_CONS_CPY(HashTable);
335
336 // setup the _nodes_ vector (contains only empty lists)
338
339 // fill with the content of table
340 _copy_(table);
341 }
343 template < typename Key, typename Val >
345 _nodes_(std::move(table._nodes_)), _size_{table._size_}, _nb_elements_{table._nb_elements_},
349 // for debugging purposes
350 table._size_ = 0;
351 GUM_CONS_MOV(HashTable);
352 }
353
354 template < typename Key, typename Val >
356 const Size len = _safe_iterators_.size();
357 for (Size i = Size(0); i < len; ++i)
359 }
360
361 template < typename Key, typename Val >
363 // update all the registered iterators: they should now point to nullptr
364 // and they are positioned to the end of the hashtable.
365 _clearIterators_();
366
367 // remove the buckets
368 for (Size i = Size(0); i < _size_; ++i)
369 _nodes_[i].clear();
370
371 _nb_elements_ = Size(0);
372 _begin_index_ = std::numeric_limits< Size >::max();
373 }
374
375 template < typename Key, typename Val >
377 // for debugging purposes
378 GUM_DESTRUCTOR(HashTable);
379
380 // update all the registered iterators: they should now point to nullptr
381 // and their hashtable should be set to nullptr
383 }
384
385 template < typename Key, typename Val >
387 // avoid self assignment
388 if (this != &from) {
389 // for debugging purposes
390 GUM_OP_CPY(HashTable);
391
392 // first remove the current content of the hashtable and make
393 // the iterators point to end
394 clear();
395
396 // if sizes of from's and this' _nodes_ vectors are not the same,
397 // we need to remove the current _nodes_' array and to create a
398 // new array with the correct size
399 if (_size_ != from._size_) {
400 _nodes_.resize(from._size_);
401 _size_ = from._size_;
402
403 // update the hash function : this is important as the computation of
404 // the hash values heavily depends on the size of the hash table
405 _hash_func_.resize(_size_);
406 }
407
408 _resize_policy_ = from._resize_policy_;
409 _key_uniqueness_policy_ = from._key_uniqueness_policy_;
410 _begin_index_ = from._begin_index_;
411
412 // perform the copy
413 _copy_(from);
414 }
415
416 return *this;
417 }
418
419 template < typename Key, typename Val >
421 // avoid self assignment
422 if (this != &table) {
423 // for debugging purposes
424 GUM_OP_MOV(HashTable);
425
426 // first remove the current content of the hashtable and make
427 // the iterators point to end
428 clear();
429
430 _nodes_ = std::move(table._nodes_);
431 _safe_iterators_ = std::move(table._safe_iterators_);
432 _size_ = table._size_;
433 _nb_elements_ = table._nb_elements_;
434 _hash_func_ = table._hash_func_;
435 _resize_policy_ = table._resize_policy_;
436 _key_uniqueness_policy_ = table._key_uniqueness_policy_;
437 _begin_index_ = table._begin_index_;
438
439 table._size_ = 0; // necessary if we wish to perform moves iteratively,
440 // i.e. x = std::move ( y ); y = std::move ( z ); ...
441 }
442
443 return *this;
444 }
445
446 template < typename Key, typename Val >
448 return *(reinterpret_cast< const iterator* >(_HashTable_end_));
449 }
450
451 template < typename Key, typename Val >
452 INLINE const typename HashTable< Key, Val >::const_iterator&
453 HashTable< Key, Val >::end() const noexcept {
454 return *(reinterpret_cast< const const_iterator* >(_HashTable_cend_));
456
457 template < typename Key, typename Val >
458 INLINE const typename HashTable< Key, Val >::const_iterator&
460 return *(reinterpret_cast< const const_iterator* >(_HashTable_cend_));
462
463 template < typename Key, typename Val >
465 // if the table is empty, make the begin and end point to the same element
466 if (_nb_elements_ == Size(0)) return iterator{end()};
467 else return iterator{*this};
468 }
469
470 template < typename Key, typename Val >
472 // if the table is empty, make the begin and end point to the same element
473 if (_nb_elements_ == Size(0)) return const_iterator{end()};
474 else return const_iterator{*this};
475 }
476
477 template < typename Key, typename Val >
479 // if the table is empty, make the begin and end point to the same element
480 if (_nb_elements_ == Size(0)) return const_iterator{cend()};
481 else return const_iterator{*this};
482 }
483
484 template < typename Key, typename Val >
485 INLINE const typename HashTable< Key, Val >::iterator_safe&
487 return *(reinterpret_cast< const iterator_safe* >(_HashTable_end_safe_));
488 }
489
490 template < typename Key, typename Val >
491 INLINE const typename HashTable< Key, Val >::const_iterator_safe&
493 return *(reinterpret_cast< const const_iterator_safe* >(_HashTable_cend_safe_));
494 }
495
496 template < typename Key, typename Val >
497 INLINE const typename HashTable< Key, Val >::const_iterator_safe&
499 return *(reinterpret_cast< const const_iterator_safe* >(_HashTable_cend_safe_));
500 }
501
502 template < typename Key, typename Val >
504 // if the table is empty, make the begin and end point to the same element
505 if (_nb_elements_ == Size(0)) return iterator_safe{endSafe()};
506 else return iterator_safe{*this};
507 }
508
509 template < typename Key, typename Val >
512 // if the table is empty, make the begin and end point to the same element
513 if (_nb_elements_ == Size(0)) return const_iterator_safe{endSafe()};
514 else return const_iterator_safe{*this};
515 }
516
517 template < typename Key, typename Val >
520 // if the table is empty, make the begin and end point to the same element
521 if (_nb_elements_ == Size(0)) return const_iterator_safe{cendSafe()};
522 else return const_iterator_safe{*this};
523 }
524
525 template < typename Key, typename Val >
526 INLINE Val& HashTable< Key, Val >::operator[](const Key& key) {
527 return _nodes_[_hash_func_(key)][key];
528 }
529
530 template < typename Key, typename Val >
531 INLINE const Val& HashTable< Key, Val >::operator[](const Key& key) const {
532 return _nodes_[_hash_func_(key)][key];
533 }
534
535 template < typename Key, typename Val >
536 INLINE Size HashTable< Key, Val >::size() const noexcept {
537 return _nb_elements_;
538 }
539
540 template < typename Key, typename Val >
541 INLINE Size HashTable< Key, Val >::capacity() const noexcept {
542 return _size_;
543 }
544
545 template < typename Key, typename Val >
546 INLINE bool HashTable< Key, Val >::exists(const Key& key) const {
547 return _nodes_[_hash_func_(key)].exists(key);
548 }
549
550 template < typename Key, typename Val >
551 INLINE void HashTable< Key, Val >::setResizePolicy(const bool new_policy) noexcept {
552 _resize_policy_ = new_policy;
553 }
554
555 template < typename Key, typename Val >
556 INLINE bool HashTable< Key, Val >::resizePolicy() const noexcept {
557 return _resize_policy_;
558 }
559
560 template < typename Key, typename Val >
561 INLINE void HashTable< Key, Val >::setKeyUniquenessPolicy(const bool new_policy) noexcept {
562 _key_uniqueness_policy_ = new_policy;
563 }
564
565 template < typename Key, typename Val >
566 INLINE bool HashTable< Key, Val >::keyUniquenessPolicy() const noexcept {
568 }
569
570 template < typename Key, typename Val >
572 // new_size must be >= 2 else all the bits of the hash function are lost
573 new_size = std::max(Size(2), new_size);
574
575 // find the real size for allocation (the smallest power of 2 greater
576 // than or equal to new_size) and get its base-2 logarithm
577 int log_size = _hashTableLog2_(new_size);
578 new_size = Size(1) << log_size;
579
580 // check if the new size is different from the actual size
581 // if not, nothing else need be done
582
583 if (new_size != _size_) {
584 // under automatic resize policy, check if the new size leaves
585 // enough space for storing all the current elements
586 if (!_resize_policy_
588 // create a new array of _nodes_ to store the elements
589 std::vector< HashTableList< Key, Val > > new_nodes(new_size);
590
591 // set the new hash function
592 _hash_func_.resize(new_size);
593
594 // put all the elements of the current _nodes_ array into the new one
595 Bucket* bucket;
596 Size new_hashed_key;
597
598 for (Size i = Size(0); i < _size_; ++i) {
599 while ((bucket = _nodes_[i]._deb_list_) != nullptr) {
600 // compute the new hashed key
601 new_hashed_key = _hash_func_(bucket->key());
602
603 // remove the bucket from the list of buckets of the current
604 // node vector
605 _nodes_[i]._deb_list_ = bucket->next;
606
607 // put the bucket into the new _nodes_ vector
608 new_nodes[new_hashed_key].insert(bucket);
609 }
610 }
611
612 // update the size of the hash table
613 _size_ = new_size;
614 _begin_index_ = std::numeric_limits< Size >::max();
615
616 // substitute the current _nodes_ array by the new one
617 std::swap(_nodes_, new_nodes);
618
619 // update the iterators
620 for (auto iter: _safe_iterators_) {
621 if (iter->_bucket_) iter->_index_ = _hash_func_(iter->_bucket_->key());
622 else {
623 iter->_next_bucket_ = nullptr;
624 iter->_index_ = 0;
625 }
626 }
627 }
628 }
629 }
630
631 template < typename Key, typename Val >
633 Size hash_key = _hash_func_(bucket->key());
634
635 // check that there does not already exist an element with the same key
636 if (_key_uniqueness_policy_ && _nodes_[hash_key].exists(bucket->key())) {
637 // remove the bucket from memory
638 Key k = bucket->key();
639 delete bucket;
641 "the hashtable contains an element with the same key (" << k << ")");
642 }
643
644 // check whether there is sufficient space to insert the new pair
645 // if not, resize the current hashtable
647 resize(_size_ << 1);
648 hash_key = _hash_func_(bucket->key());
649 }
650
651 // add the new pair
652 _nodes_[hash_key].insert(bucket);
654
655 // recompute the index of the beginning of the hashtable if possible
656 // WARNING: if _begin_index_ = std::numeric_limits<Size>::max (), we CANNOT
657 // recompute the index because we cannot know whether the current index is
658 // equal to max because there was no element in the hashtable or whether a
659 // previous _erase_() has set the index to max.
660 if (_begin_index_ < hash_key) { _begin_index_ = hash_key; }
661 }
662
663 template < typename Key, typename Val >
664 INLINE typename HashTable< Key, Val >::value_type&
665 HashTable< Key, Val >::insert(const Key& thekey, const Val& theval) {
666 auto bucket = new Bucket(thekey, theval);
667 _insert_(bucket);
668 return bucket->elt();
669 }
670
671 template < typename Key, typename Val >
673 Val&& theval) {
674 auto bucket = new Bucket(std::move(thekey), std::move(theval));
675 _insert_(bucket);
676 return bucket->elt();
677 }
678
679 template < typename Key, typename Val >
680 INLINE typename HashTable< Key, Val >::value_type&
681 HashTable< Key, Val >::insert(const std::pair< Key, Val >& elt) {
682 auto bucket = new Bucket(reinterpret_cast< const value_type& >(elt));
683 _insert_(bucket);
684 return bucket->elt();
685 }
686
687 template < typename Key, typename Val >
688 INLINE typename HashTable< Key, Val >::value_type&
689 HashTable< Key, Val >::insert(std::pair< Key, Val >&& elt) {
690 auto bucket = new Bucket(std::move(reinterpret_cast< value_type& >(elt)));
691 _insert_(bucket);
692 return bucket->elt();
693 }
694
695 template < typename Key, typename Val >
696 template < typename... Args >
697 INLINE typename HashTable< Key, Val >::value_type&
699 auto bucket
700 = new Bucket(HashTableBucket< Key, Val >::Emplace::EMPLACE, std::forward< Args >(args)...);
701 _insert_(bucket);
702 return bucket->elt();
703 }
704
705 template < typename Key, typename Val >
707 HashTable< Key, Val >::getWithDefault(const Key& key, const Val& default_value) {
708 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
709
710 if (bucket == nullptr) return insert(key, default_value).second;
711 else return bucket->val();
712 }
713
714 template < typename Key, typename Val >
716 HashTable< Key, Val >::getWithDefault(Key&& key, Val&& default_value) {
717 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
718
719 if (bucket == nullptr) return insert(std::move(key), std::move(default_value)).second;
720 else return bucket->val();
721 }
722
723 template < typename Key, typename Val >
724 INLINE void HashTable< Key, Val >::set(const Key& key, const Val& value) {
725 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
726
727 if (bucket == nullptr) insert(key, value);
728 else bucket->val() = value;
729 }
730
731 template < typename Key, typename Val >
733 if (bucket == nullptr) return;
734
735 // update the registered iterators pointing to this bucket
736 for (auto iter: _safe_iterators_) {
737 if (iter->_bucket_ == bucket) {
738 iter->operator++();
739 iter->_next_bucket_ = iter->_bucket_;
740 iter->_bucket_ = nullptr;
741 } else if (iter->_next_bucket_ == bucket) {
742 iter->_bucket_ = bucket;
743 iter->operator++();
744 iter->_next_bucket_ = iter->_bucket_;
745 iter->_bucket_ = nullptr;
746 }
747 }
748
749 // remove the element from the _nodes_ vector
750 _nodes_[index].erase(bucket);
751
753
754 if ((index == _begin_index_) && _nodes_[index].empty()) {
755 _begin_index_ = std::numeric_limits< Size >::max();
756 }
757 }
758
759 template < typename Key, typename Val >
760 INLINE void HashTable< Key, Val >::erase(const Key& key) {
761 // get the hashed key
762 Size hash = _hash_func_(key);
763
764 // get the bucket containing the element to erase
765 HashTableBucket< Key, Val >* bucket = _nodes_[hash].bucket(key);
766
767 _erase_(bucket, hash);
768 }
769
770 template < typename Key, typename Val >
772 _erase_(iter._getBucket_(), iter._getIndex_());
773 }
775 template < typename Key, typename Val >
777 _erase_(iter._getBucket_(), iter._getIndex_());
778 }
779
780 template < typename Key, typename Val >
781 INLINE void HashTable< Key, Val >::eraseByVal(const Val& val) {
782 for (auto iter = cbegin(); iter != cend(); ++iter)
783 if (iter._bucket_->val() == val) {
784 _erase_(iter._getBucket_(), iter._getIndex_());
785 return;
786 }
787 }
788
789 template < typename Key, typename Val >
790 INLINE void HashTable< Key, Val >::reset(const Key& key) {
791 erase(key);
792 }
793
794 template < typename Key, typename Val >
795 INLINE const Key& HashTable< Key, Val >::keyByVal(const Val& val) const {
796 for (auto iter = begin(); iter != end(); ++iter)
797 if (iter._bucket_->val() == val) return iter.key();
798
799 GUM_ERROR(NotFound, "not enough elements in the chained list")
800 }
801
802 template < typename Key, typename Val >
803 INLINE const Key& HashTable< Key, Val >::key(const Key& key) const {
804 // get the bucket corresponding to the key
805 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
806
807 if (bucket == nullptr) { GUM_ERROR(NotFound, "key does not belong to the hashtable") }
808
809 return bucket->key();
810 }
811
812 template < typename Key, typename Val >
814 for (auto iterAll = cbeginSafe(); iterAll != cendSafe(); ++iterAll) {
815 if (iterAll._bucket_->val() == val) { _erase_(iterAll._bucket_, iterAll._index_); }
816 }
817 }
818
819 template < typename Key, typename Val >
820 INLINE bool HashTable< Key, Val >::empty() const noexcept {
821 return (_nb_elements_ == Size(0));
822 }
823
824 template < typename Key, typename Val >
825 template < typename Mount >
827 Size size,
828 bool resize_pol,
829 bool key_uniqueness_pol) const {
830 // determine the proper size of the hashtable
831 // by default, the size of the table is set so that the table does not take
832 // too much space while allowing to add a few elements without needing to
833 // resize in autmatic resizing mode
834 if (size == 0) size = std::max(Size(2), _nb_elements_ / 2);
835
836 // create a new table
837 HashTable< Key, Mount > table(size, resize_pol, key_uniqueness_pol);
838
839 // fill the new hash table
840 for (auto iter = begin(); iter != end(); ++iter) {
841 table.insert(iter.key(), f(iter.val()));
842 }
843
844 return table;
845 }
846
847 template < typename Key, typename Val >
848 template < typename Mount >
850 Size size,
851 bool resize_pol,
852 bool key_uniqueness_pol) const {
853 // determine the proper size of the hashtable
854 // by default, the size of the table is set so that the table does not take
855 // too much space while allowing to add a few elements without needing to
856 // resize in autmatic resizing mode
857 if (size == Size(0)) size = std::max(Size(2), _nb_elements_ / 2);
858
859 // create a new table
860 HashTable< Key, Mount > table(size, resize_pol, key_uniqueness_pol);
861
862 // fill the new hash table
863 for (auto iter = begin(); iter != end(); ++iter) {
864 table.insert(iter.key(), f(const_cast< Val& >(iter.val())));
865 }
866
867 return table;
868 }
869
870 template < typename Key, typename Val >
871 template < typename Mount >
873 Size size,
874 bool resize_pol,
875 bool key_uniqueness_pol) const {
876 // determine the proper size of the hashtable
877 // by default, the size of the table is set so that the table does not take
878 // too much space while allowing to add a few elements without needing to
879 // resize in autmatic resizing mode
880 if (size == Size(0)) size = std::max(Size(2), _nb_elements_ / 2);
881
882 // create a new table
883 HashTable< Key, Mount > table(size, resize_pol, key_uniqueness_pol);
884
885 // fill the new hash table
886 for (auto iter = begin(); iter != end(); ++iter) {
887 table.insert(iter.key(), f(iter.val()));
888 }
889
890 return table;
891 }
892
893 template < typename Key, typename Val >
894 template < typename Mount >
896 Size size,
897 bool resize_pol,
898 bool key_uniqueness_pol) const {
899 // determine the proper size of the hashtable
900 // by default, the size of the table is set so that the table does not take
901 // too much space while allowing to add a few elements without needing to
902 // resize in autmatic resizing mode
903 if (size == Size(0)) size = std::max(Size(2), _nb_elements_ / 2);
904
905 // create a new table
906 HashTable< Key, Mount > table(size, resize_pol, key_uniqueness_pol);
907
908 // fill the new hash table
909 for (auto iter = begin(); iter != end(); ++iter) {
910 table.insert(iter.key(), val);
911 }
912
913 return table;
914 }
915
916 template < typename Key, typename Val >
918 // checks whether the two hashtables contain the same number of elements
919 if (from._nb_elements_ != _nb_elements_) return false;
920
921 // parse this and check that each element also belongs to from
922 for (auto iter = begin(); iter != end(); ++iter) {
923 try {
924 if (iter.val() != from[iter.key()]) return false;
925 } catch (NotFound const&) { return false; }
926 }
927
928 return true;
929 }
930
931 template < typename Key, typename Val >
933 return !operator==(from);
934 }
935
936 template < typename Key, typename Val >
937 std::ostream& operator<<(std::ostream& stream, const HashTableList< Key, Val >& list) {
938 bool deja = false;
939 stream << "[";
940
941 for (HashTableBucket< Key, Val >* ptr = list._deb_list_; ptr;
942 ptr = ptr->list.next, deja = true) {
943 if (deja) stream << " , ";
944
945 stream << ptr->key() << "=>" << ptr->val();
946 }
947
948 stream << "]";
949
950 return stream;
951 }
953 template < typename Key, typename Val >
954 std::ostream& operator<<(std::ostream& stream, const HashTableList< Key*, Val >& list) {
955 bool deja = false;
956 stream << "[";
957
958 for (HashTableBucket< Key, Val >* ptr = list._deb_list_; ptr;
959 ptr = ptr->list.next, deja = true) {
960 if (deja) stream << " , ";
961
962 stream << ptr->key() << "=>" << ptr->val();
963 }
964
965 stream << "]";
966
967 return stream;
968 }
970 template < typename Key, typename Val >
971 std::ostream& operator<<(std::ostream& stream, const HashTable< Key, Val >& table) {
972 bool deja = false;
973 stream << "{";
974
975 for (Size i = Size(0); i < table._size_; ++i)
976 for (auto ptr = table._nodes_[i]._deb_list_; ptr; ptr = ptr->next) {
977 if (deja) stream << " , ";
978
979 stream << ptr->key() << "=>" << ptr->val();
980
981 deja = true;
982 }
983
984 stream << "}";
985
986 return stream;
987 }
988
989 template < typename Key, typename Val >
990 std::ostream& operator<<(std::ostream& stream, const HashTable< Key*, Val >& table) {
991 bool deja = false;
992 stream << "{";
993
994 for (Size i = Size(0); i < table._size_; ++i)
995 for (auto ptr = table._nodes_[i]._deb_list_; ptr; ptr = ptr->next) {
996 if (deja) stream << " , ";
997
998 stream << ptr->key() << "=>" << ptr->val();
999
1000 deja = true;
1001 }
1002
1003 stream << "}";
1004
1005 return stream;
1006 }
1007
1008 // ===========================================================================
1009 // === SAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1010 // ===========================================================================
1011
1012 template < typename Key, typename Val >
1014 _table_->_safe_iterators_.push_back(
1015 const_cast< HashTableConstIteratorSafe< Key, Val >* >(this));
1016 }
1017
1018 template < typename Key, typename Val >
1020 if (_table_ == nullptr) return;
1021
1022 // find where the iterator is
1023 std::vector< HashTableConstIteratorSafe< Key, Val >* >& iter_vect = _table_->_safe_iterators_;
1024
1025 auto len = iter_vect.size();
1026 for (Size i = Size(0); i < len; ++i) {
1027 if (iter_vect[i] == this) {
1028 iter_vect.erase(iter_vect.begin() + i);
1029 break;
1030 }
1032 }
1033
1034 template < typename Key, typename Val >
1036 // for debugging purposes
1038 }
1039
1040 template < typename Key, typename Val >
1042 const HashTable< Key, Val >& tab) :
1043 _table_{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1044 // for debugging purposes
1045 GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1046
1047 // make the hashtable keep track of this iterator
1049
1050 if (_table_->_nb_elements_) {
1051 if (_table_->_begin_index_ != std::numeric_limits< Size >::max()) {
1052 _index_ = _table_->_begin_index_;
1053 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1054 } else {
1055 // find the element we shall point to from the start of the hashtable
1056 for (Size i = _table_->_size_ - Size(1);; --i) { // no test on i since
1057 // _nb_elements_ != 0
1058 if (_table_->_nodes_[i]._nb_elements_) {
1059 _index_ = i;
1060 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1061 _table_->_begin_index_ = _index_;
1062 break;
1063 }
1065 }
1066 }
1067 }
1068
1069 template < typename Key, typename Val >
1071 const HashTable< Key, Val >& tab,
1072 Size ind_elt) : _table_{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1073 Size i;
1074
1075 // check if we are looking for a begin() and we know for sure its index
1076 if ((ind_elt == Size(0)) && (_table_->_begin_index_ != std::numeric_limits< Size >::max())) {
1077 _index_ = _table_->_begin_index_;
1078 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1079 } else {
1080 // check if it is faster to find the ind_eltth element from the start or
1081 // from the end of the hashtable
1082 if (ind_elt < (_table_->_nb_elements_ >> 1)) {
1083 // find the element we shall point to from the start of the hashtable
1084 for (i = _table_->_size_ - 1;; --i) { // no test on i since
1085 // ind_elt < table_-> _nb_elements_
1086 if (_table_->_nodes_[i]._nb_elements_) {
1087 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1088 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1089 else {
1090 for (_bucket_ = _table_->_nodes_[i]._end_list_; ind_elt;
1091 --ind_elt, _bucket_ = _bucket_->prev) {}
1092
1093 _index_ = i;
1094 break;
1095 }
1096 }
1097 }
1098 } else {
1099 // ind_elt = the index of the element we should point to
1100 // check if the index passed as parameter is valid
1101 if (ind_elt >= _table_->_nb_elements_) {
1102 GUM_ERROR(UndefinedIteratorValue, "Not enough elements in the hashtable")
1103 }
1104
1105 // find the element we shall point to from the end of the hashtable
1106 for (i = 0, ind_elt = _table_->_nb_elements_ - ind_elt - 1;; ++i) {
1107 if (_table_->_nodes_[i]._nb_elements_) {
1108 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1109 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1110 else {
1111 for (_bucket_ = _table_->_nodes_[i]._deb_list_; ind_elt;
1112 --ind_elt, _bucket_ = _bucket_->next) {}
1113
1114 _index_ = i;
1115 break;
1116 }
1117 }
1118 }
1119 }
1120 }
1121
1122 // for debugging purposes
1123 GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1124
1125 // make the hashtable keep track of this iterator
1126 _insertIntoSafeList_();
1127 }
1128
1129 template < typename Key, typename Val >
1132 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_},
1134 // make the hashtable keep track of this iterator
1135 if (_table_ != nullptr) { _insertIntoSafeList_(); }
1136
1137 // for debugging purposes
1138 GUM_CONS_CPY(HashTableConstIteratorSafe);
1139 }
1140
1141 template < typename Key, typename Val >
1144 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_} {
1145 // make the hashtable keep track of this iterator
1146 if (_table_ != nullptr) { _insertIntoSafeList_(); }
1147
1148 // for debugging purposes
1149 GUM_CONS_CPY(HashTableConstIteratorSafe);
1150 }
1151
1152 template < typename Key, typename Val >
1155 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_},
1157 GUM_CONS_MOV(HashTableConstIteratorSafe);
1158
1159 // find "from" in the hashtable's list of safe iterators and substitute
1160 // it by this
1161 if (_table_ != nullptr) {
1162 std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect = _table_->_safe_iterators_;
1163
1164 for (auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1165 if (*ptr == &from) {
1166 *ptr = this;
1167 from._table_ = nullptr;
1168 break;
1169 }
1170 }
1171 }
1172 }
1173
1174 template < typename Key, typename Val >
1176 // for debugging purposes
1177 GUM_DESTRUCTOR(HashTableConstIteratorSafe);
1178
1179 // remove the iterator from the table's iterator list
1182
1183 template < typename Key, typename Val >
1186 // here, no need to avoid self assignment: this would slow down normal
1187 // assignments and, in any case, this would not result in an iterator in
1188 // an incoherent state
1189 // check if the current hashtable is different from that of "from". In such
1190 // a case, we shall remove the iterator from its current hashtable
1191 // iterator's
1192 // list and add it to the new hashtable iterator's list
1193 if (_table_ != from._table_) {
1194 // remove the iterator from its hashtable iterator's list'
1196
1197 _table_ = from._table_;
1198
1199 // add to the new table
1200 if (_table_) { _insertIntoSafeList_(); }
1201 }
1202
1203 _index_ = from._index_;
1204 _bucket_ = from._bucket_;
1206
1207 return *this;
1208 }
1209
1210 template < typename Key, typename Val >
1213 // here, no need to avoid self assignment: this would slow down normal
1214 // assignments and, in any case, this would not result in an iterator in
1215 // an incoherent state
1216 // check if the current hashtable is different from that of "from". In such
1217 // a case, we shall remove the iterator from its current hashtable
1218 // iterator's
1219 // list and add it to the new hashtable iterator's list
1220 if (_table_ != from._table_) {
1221 // remove the iterator from its hashtable iterator's list'
1222 _removeFromSafeList_();
1223
1224 _table_ = from._table_;
1225
1226 // add to the new table
1227 if (_table_) { _insertIntoSafeList_(); }
1228 }
1229
1230 _index_ = from._index_;
1231 _bucket_ = from._bucket_;
1232 _next_bucket_ = nullptr;
1233
1234 return *this;
1235 }
1236
1237 template < typename Key, typename Val >
1240 // here, no need to avoid self assignment: this would slow down normal
1241 // assignments and, in any case, this would not result in an iterator in
1242 // an incoherent state
1243 // check if the current hashtable is different from that of "from". In such
1244 // a case, we shall remove the iterator from its current hashtable
1245 // iterator's
1246 // list and add it to the new hashtable iterator's list
1247 if (_table_ != from._table_) {
1248 // remove the iterator from its hashtable iterator's list'
1250
1251 if (from._table_ != nullptr) {
1252 // substitute from by this in the list of safe iterators
1253 std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect
1254 = from._table_->_safe_iterators_;
1255
1256 for (auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1257 if (*ptr == &from) {
1258 *ptr = this;
1259 break;
1260 }
1261 }
1262 }
1263
1264 _table_ = from._table_;
1265 from._table_ = nullptr;
1266 }
1267
1268 _index_ = from._index_;
1269 _bucket_ = from._bucket_;
1270 _next_bucket_ = from._next_bucket_;
1271
1272 return *this;
1273 }
1274
1275 template < typename Key, typename Val >
1278 if (_bucket_ != nullptr) return _bucket_->key();
1279 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1280 }
1281
1282 template < typename Key, typename Val >
1285 if (_bucket_ != nullptr) return _bucket_->val();
1286 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1287 }
1288
1289 template < typename Key, typename Val >
1291 // remove the iterator from the table's iterator list
1292 _removeFromSafeList_();
1293
1294 // set its table as well as the element it points to to 0
1295 _table_ = nullptr;
1296 _bucket_ = nullptr;
1297 _next_bucket_ = nullptr;
1298 _index_ = Size(0);
1299 }
1300
1301 // WARNING: never inline this function: this result in g++4.3.3 producing a
1302 // code that segfaults.
1303 template < typename Key, typename Val >
1306 // if _bucket_ != nullptr then use it, else use next_bucket
1307 if (_bucket_ == nullptr) {
1308 // note that this case only happens when the iterator pointed to an
1309 // element
1310 // that has just been erased. Fortunately, in this case, the Hashtable's
1311 // erase functions update appropriately the _next_bucket_ and _index_
1312 // fields.
1313 _bucket_ = _next_bucket_;
1314 _next_bucket_ = nullptr;
1315 } else {
1316 // ok, here we can use _bucket_ as a starting point
1317
1318 // if we are not pointing on the first element of the chained list, just
1319 // point to the preceding bucket in this list
1320 if (_bucket_->prev) {
1321 _bucket_ = _bucket_->prev;
1322 // here, no need to update _next_bucket_, which is compulsorily
1323 // equal to nullptr, nor _index_ which has not changed.
1324 } else {
1325 // ok, here we are on the beginning of a chained list,
1326 // so 2 cases can obtain:
1327 // 1/ index = 0 : then we have reached the end of the hashtable
1328 // 2/ index != 0 => we must search for a new slot containing elements
1330 // case 1:
1331 if (_index_ == Size(0)) {
1332 _bucket_ = nullptr;
1333 // we are thus at the end() of the hashTable
1334 }
1335 // case 2:
1336 else {
1337 // arrived here, we need to parse the hash table until we find a new
1338 // bucket because we are pointing on a chained list with no more
1339 // element
1340 // to the left of the current element
1341 if (_index_ > Size(0)) {
1342 for (Size i = _index_ - Size(1); i > Size(0); --i) {
1343 if (_table_->_nodes_[i]._nb_elements_) {
1344 _index_ = i;
1345 _bucket_ = _table_->_nodes_[i]._end_list_;
1346 return *this;
1347 }
1348 }
1349 }
1350
1351 if (_table_->_nodes_[0]._nb_elements_) _bucket_ = _table_->_nodes_[0]._end_list_;
1352 else _bucket_ = nullptr;
1353
1354 _index_ = 0;
1355 }
1356 }
1357 }
1358
1359 return *this;
1360 }
1361
1362 template < typename Key, typename Val >
1365 if ((nb == Size(0)) || (_table_ == nullptr)) return *this;
1366
1367 // if _bucket_ != nullptr then use it, else use next_bucket
1368 if (_bucket_ == nullptr) {
1369 // note that this case only happens when the iterator pointed to an
1370 // element
1371 // that has just been erased. Fortunately, in this case, the Hashtable's
1372 // erase functions update appropriately the _next_bucket_ and _index_
1373 // fields.
1375 _next_bucket_ = nullptr;
1376 --nb;
1377 }
1378
1379 // ok, here we can use _bucket_ as a starting point: parse all the elements
1380 // of the current chained list
1381 for (; nb && _bucket_ != nullptr; --nb, _bucket_ = _bucket_->prev) {}
1382
1383 if (_bucket_ != nullptr) return *this;
1384
1385 // here, we shall skip all the chained list that have not sufficiently
1386 // many elements
1387 --_index_;
1388
1389 for (; _index_ < _table_->_size_ && nb >= _table_->_nodes_[_index_]._nb_elements_;
1390 nb -= _table_->_nodes_[_index_]._nb_elements_, --_index_) {}
1391
1392 // here: either _index_ >= _table_-> _size_, which means that we did not find
1393 // the element we looked for, i.e., we are at the end of the hashtable, or
1394 // nb < _table_-> _nodes_[ _index_]. _nb_elements_, and we should parse the
1395 // chained list to get the element (which, we know for sure, exists)
1396 if (_index_ >= _table_->_size_) {
1397 _index_ = Size(0);
1398 return *this;
1399 }
1400
1401 for (_bucket_ = _table_->_nodes_[_index_]._end_list_; nb; --nb, _bucket_ = _bucket_->prev) {}
1402
1403 return *this;
1404 }
1405
1406 template < typename Key, typename Val >
1411
1412 template < typename Key, typename Val >
1414 const HashTableConstIteratorSafe< Key, Val >& from) const noexcept {
1415 return ((_bucket_ != from._bucket_) || (_index_ != from._index_));
1416 }
1417
1418 template < typename Key, typename Val >
1420 const HashTableConstIteratorSafe< Key, Val >& from) const noexcept {
1421 return ((_bucket_ == from._bucket_) && (_index_ == from._index_));
1422 }
1423
1424 template < typename Key, typename Val >
1427 if (_bucket_) return _bucket_->elt();
1428 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1429 }
1430
1431 template < typename Key, typename Val >
1436
1437 template < typename Key, typename Val >
1439 return _index_;
1440 }
1441
1442 // ===========================================================================
1443 // === SAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1444 // ===========================================================================
1445
1446 template < typename Key, typename Val >
1448 HashTableConstIteratorSafe< Key, Val >() {
1449 GUM_CONSTRUCTOR(HashTableIteratorSafe);
1450 }
1451
1452 template < typename Key, typename Val >
1453 INLINE
1454 HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(const HashTable< Key, Val >& tab) :
1455 HashTableConstIteratorSafe< Key, Val >(tab) {
1456 GUM_CONSTRUCTOR(HashTableIteratorSafe);
1458
1459 template < typename Key, typename Val >
1461 Size ind_elt) :
1462 HashTableConstIteratorSafe< Key, Val >(tab, ind_elt) {
1463 GUM_CONSTRUCTOR(HashTableIteratorSafe);
1464 }
1465
1466 template < typename Key, typename Val >
1469 HashTableConstIteratorSafe< Key, Val >(from) {
1470 GUM_CONS_CPY(HashTableIteratorSafe);
1471 }
1472
1473 template < typename Key, typename Val >
1474 INLINE HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(
1475 const HashTableIterator< Key, Val >& from) : HashTableConstIteratorSafe< Key, Val >(from) {
1476 GUM_CONS_CPY(HashTableIteratorSafe);
1477 }
1478
1479 template < typename Key, typename Val >
1480 INLINE HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(
1481 HashTableIteratorSafe< Key, Val >&& from) noexcept :
1483 GUM_CONS_MOV(HashTableIteratorSafe);
1484 }
1485
1486 template < typename Key, typename Val >
1487 INLINE HashTableIteratorSafe< Key, Val >::~HashTableIteratorSafe() noexcept {
1488 GUM_DESTRUCTOR(HashTableIteratorSafe);
1489 }
1490
1491 template < typename Key, typename Val >
1492 INLINE typename HashTableIteratorSafe< Key, Val >::mapped_type&
1493 HashTableIteratorSafe< Key, Val >::val() {
1494 return const_cast< Val& >(HashTableConstIteratorSafe< Key, Val >::val());
1495 }
1496
1497 template < typename Key, typename Val >
1498 INLINE HashTableIteratorSafe< Key, Val >&
1499 HashTableIteratorSafe< Key, Val >::operator=(const HashTableIteratorSafe< Key, Val >& from) {
1500 GUM_OP_CPY(HashTableIteratorSafe);
1502 return *this;
1503 }
1504
1505 template < typename Key, typename Val >
1506 INLINE HashTableIteratorSafe< Key, Val >&
1508 GUM_OP_CPY(HashTableIteratorSafe);
1510 return *this;
1511 }
1512
1513 template < typename Key, typename Val >
1515 HashTableIteratorSafe< Key, Val >&& from) noexcept {
1517 return *this;
1518 }
1519
1520 template < typename Key, typename Val >
1524 return *this;
1525 }
1526
1527 template < typename Key, typename Val >
1531 return *this;
1532 }
1533
1534 template < typename Key, typename Val >
1538 iter += nb;
1539 return iter;
1540 }
1541
1542 template < typename Key, typename Val >
1544 const HashTableIteratorSafe< Key, Val >& from) const noexcept {
1546 }
1547
1548 template < typename Key, typename Val >
1550 const HashTableIteratorSafe< Key, Val >& from) const noexcept {
1553
1554 template < typename Key, typename Val >
1557 return const_cast< Val& >(HashTableConstIteratorSafe< Key, Val >::operator*());
1558 }
1559
1560 template < typename Key, typename Val >
1564 }
1565
1566 // ===========================================================================
1567 // === UNSAFE HASH TABLE CONST ITERATORS IMPLEMENTATION ===
1568 // ===========================================================================
1569
1570 template < typename Key, typename Val >
1574
1575 template < typename Key, typename Val >
1577 const HashTable< Key, Val >& tab) noexcept :
1578 _table_{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1579 // for debugging purposes
1580 GUM_CONSTRUCTOR(HashTableConstIterator);
1581
1582 if (_table_->_nb_elements_) {
1583 if (_table_->_begin_index_ != std::numeric_limits< Size >::max()) {
1584 _index_ = _table_->_begin_index_;
1585 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1586 } else {
1587 // find the element we shall point to from the start of the hashtable
1588 for (Size i = _table_->_size_ - Size(1);; --i) { // no test on i since
1589 // _nb_elements_ != 0
1590 if (_table_->_nodes_[i]._nb_elements_) {
1591 _index_ = i;
1592 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1593 _table_->_begin_index_ = _index_;
1594 break;
1595 }
1596 }
1597 }
1598 }
1599 }
1600
1601 template < typename Key, typename Val >
1603 Size ind_elt) :
1604 _table_{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1605 Size i;
1606
1607 // check if we are looking for a begin() and we know for sure its index
1608 if ((ind_elt == Size(0)) && (_table_->_begin_index_ != std::numeric_limits< Size >::max())) {
1609 _index_ = _table_->_begin_index_;
1610 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1611 } else {
1612 // check if it is faster to find the ind_eltth element from the start or
1613 // from the end of the hashtable
1614 if (ind_elt < (_table_->_nb_elements_ >> 1)) {
1615 // find the element we shall point to from the start of the hashtable
1616 for (i = _table_->_size_ - 1;; --i) { // no test on i since
1617 // ind_elt < table_-> _nb_elements_
1618 if (_table_->_nodes_[i]._nb_elements_) {
1619 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1620 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1621 else {
1622 for (_bucket_ = _table_->_nodes_[i]._end_list_; ind_elt;
1623 --ind_elt, _bucket_ = _bucket_->prev) {}
1624
1625 _index_ = i;
1626 break;
1627 }
1628 }
1629 }
1630 } else {
1631 // ind_elt = the index of the element we should point to
1632 // check if the index passed as parameter is valid
1633 if (ind_elt >= _table_->_nb_elements_) {
1634 GUM_ERROR(UndefinedIteratorValue, "Not enough elements in the hashtable")
1635 }
1636
1637 // find the element we shall point to from the end of the hashtable
1638 for (i = 0, ind_elt = _table_->_nb_elements_ - ind_elt - 1;; ++i) {
1639 if (_table_->_nodes_[i]._nb_elements_) {
1640 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1641 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1642 else {
1643 for (_bucket_ = _table_->_nodes_[i]._deb_list_; ind_elt;
1644 --ind_elt, _bucket_ = _bucket_->next) {}
1645
1646 _index_ = i;
1647 break;
1648 }
1649 }
1650 }
1651 }
1652 }
1653
1654 // for debugging purposes
1655 GUM_CONSTRUCTOR(HashTableConstIterator);
1656 }
1657
1658 template < typename Key, typename Val >
1660 const HashTableConstIterator< Key, Val >& from) noexcept :
1661 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_} {
1662 GUM_CONS_CPY(HashTableConstIterator);
1663 }
1664
1665 template < typename Key, typename Val >
1667 HashTableConstIterator< Key, Val >&& from) noexcept :
1668 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_} {
1669 GUM_CONS_MOV(HashTableConstIterator);
1670 }
1671
1672 template < typename Key, typename Val >
1674 // for debugging purposes
1675 GUM_DESTRUCTOR(HashTableConstIterator);
1676 }
1677
1678 template < typename Key, typename Val >
1680 const HashTableConstIterator< Key, Val >& from) noexcept {
1681 // here, no need to avoid self assignment: this would slow down normal
1682 // assignments and, in any case, this would not result in an iterator in
1683 // an incoherent state
1684 _table_ = from._table_;
1685 _index_ = from._index_;
1686 _bucket_ = from._bucket_;
1687
1688 return *this;
1690
1691 template < typename Key, typename Val >
1693 HashTableConstIterator< Key, Val >&& from) noexcept {
1694 // here, no need to avoid self assignment: this would slow down normal
1695 // assignments and, in any case, this would not result in an iterator in
1696 // an incoherent state
1697 _table_ = from._table_;
1699 _bucket_ = from._bucket_;
1700
1701 return *this;
1702 }
1703
1704 template < typename Key, typename Val >
1707 if (_bucket_) return _bucket_->pair.first;
1708 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1709 }
1710
1711 template < typename Key, typename Val >
1714 if (_bucket_) return _bucket_->val();
1715 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1716 }
1717
1718 template < typename Key, typename Val >
1720 _table_ = nullptr;
1721 _bucket_ = nullptr;
1722 _index_ = 0;
1723 }
1724
1725 template < typename Key, typename Val >
1727 // if _bucket_ == nullptr then we are at the end of the hashtable
1728 if (_bucket_ == nullptr) return *this;
1729
1730 // if we are not pointing on the first element of the chained list, just
1731 // point to the next bucket in this list
1732 if (_bucket_->prev) {
1733 _bucket_ = _bucket_->prev;
1734 // here, no need to update _index_ which has not changed.
1735 } else {
1736 // ok, here we are on the end of a chained list,
1737 // so 2 cases can obtain:
1738 // 1/ index = 0 : then we have reached the end of the hashtable
1739 // 2/ index != 0 => we must search for a new slot containing elements
1740
1741 // case 1:
1742 if (_index_ == Size(0)) {
1743 _bucket_ = nullptr;
1744 // we are thus at the end() of the hashTable
1745 }
1746
1747 // case 2:
1748 else {
1749 // arrived here, we need to parse the hash table until we find a new
1750 // bucket because we are pointing on a chained list with no more element
1751 // to the right of the current element
1752 for (Size i = _index_ - Size(1); i; --i) {
1753 if (_table_->_nodes_[i]._nb_elements_) {
1755 _bucket_ = _table_->_nodes_[i]._end_list_;
1756 return *this;
1757 }
1758 }
1759
1760 if (_table_->_nodes_[0]._nb_elements_) _bucket_ = _table_->_nodes_[0]._end_list_;
1761 else _bucket_ = nullptr;
1763 _index_ = Size(0);
1764 }
1765 }
1766
1767 return *this;
1768 }
1769
1770 template < typename Key, typename Val >
1773 if ((nb == 0) || (_table_ == nullptr) || (_bucket_ == nullptr)) return *this;
1774
1775 // ok, here we can use _bucket_ as a starting point: parse all the elements
1776 // of the current chained list
1777 for (; nb && _bucket_ != nullptr; --nb, _bucket_ = _bucket_->prev) {}
1779 if (_bucket_ != nullptr) return *this;
1780
1781 // here, we shall skip all the chained list that have not sufficiently
1782 // many elements
1783 --_index_;
1784
1785 for (; _index_ < _table_->_size_ && nb >= _table_->_nodes_[_index_]._nb_elements_;
1786 nb -= _table_->_nodes_[_index_]._nb_elements_, --_index_) {}
1787
1788 // here: either _index_ >= _table_-> _size_, which means that we did not find
1789 // the element we looked for, i.e., we are at the end of the hashtable, or
1790 // nb < _table_-> _nodes_[ _index_]. _nb_elements_, and we should parse the
1791 // chained list to get the element (which, we know for sure, exists)
1792 if (_index_ >= _table_->_size_) {
1794 return *this;
1795 }
1796
1797 for (_bucket_ = _table_->_nodes_[_index_]._end_list_; nb; --nb, _bucket_ = _bucket_->prev) {}
1798
1799 return *this;
1800 }
1801
1802 template < typename Key, typename Val >
1805 return HashTableConstIterator< Key, Val >{*this} += nb;
1806 }
1807
1808 template < typename Key, typename Val >
1810 const HashTableConstIterator< Key, Val >& from) const noexcept {
1811 return (_bucket_ != from._bucket_);
1812 }
1813
1814 template < typename Key, typename Val >
1816 const HashTableConstIterator< Key, Val >& from) const noexcept {
1817 return (_bucket_ == from._bucket_);
1818 }
1819
1820 template < typename Key, typename Val >
1823 if (_bucket_) return _bucket_->elt();
1824 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1825 }
1826
1827 template < typename Key, typename Val >
1828 INLINE typename HashTable< Key, Val >::Bucket*
1830 return _bucket_;
1831 }
1832
1833 template < typename Key, typename Val >
1835 return _index_;
1836 }
1838 // ===========================================================================
1839 // === UNSAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1840 // ===========================================================================
1841
1842 template < typename Key, typename Val >
1844 HashTableConstIterator< Key, Val >() {
1845 GUM_CONSTRUCTOR(HashTableIterator);
1846 }
1848 template < typename Key, typename Val >
1853
1854 template < typename Key, typename Val >
1856 Size ind_elt) :
1857 HashTableConstIterator< Key, Val >(tab, ind_elt) {
1858 GUM_CONSTRUCTOR(HashTableIterator);
1859 }
1860
1861 template < typename Key, typename Val >
1867
1868 template < typename Key, typename Val >
1874
1875 template < typename Key, typename Val >
1877 GUM_DESTRUCTOR(HashTableIterator);
1878 }
1879
1880 template < typename Key, typename Val >
1882 if (this->_bucket_) return this->_bucket_->val();
1883 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1884 }
1885
1886 template < typename Key, typename Val >
1892
1893 template < typename Key, typename Val >
1899
1900 template < typename Key, typename Val >
1905
1906 template < typename Key, typename Val >
1912
1913 template < typename Key, typename Val >
1917 iter += nb;
1918 return iter;
1919 }
1920
1921 template < typename Key, typename Val >
1926
1927 template < typename Key, typename Val >
1932
1933 template < typename Key, typename Val >
1938
1939 template < typename Key, typename Val >
1940 INLINE const typename HashTableIterator< Key, Val >::value_type&
1944
1945} /* namespace gum */
Unsafe Const Iterators for hashtables.
Definition hashTable.h:2146
~HashTableConstIterator() noexcept
Class destructor.
Size _getIndex_() const noexcept
Returns the index in the hashtable's node vector pointed to by the iterator.
HashTableConstIterator< Key, Val > operator+(Size i) const noexcept
Returns a new iterator pointing to i elements further in the hashtable.
HashTableConstIterator< Key, Val > & operator++() noexcept
Makes the iterator point to the next element in the hash table.
HashTableConstIterator< Key, Val > & operator=(const HashTableConstIterator< Key, Val > &from) noexcept
Copy operator.
Val mapped_type
Types for STL compliance.
Definition hashTable.h:2152
HashTableConstIterator< Key, Val > & operator+=(Size i) noexcept
Makes the iterator point to i elements further in the hashtable.
const value_type & operator*() const
Returns the value pointed to by the iterator.
bool operator==(const HashTableConstIterator< Key, Val > &from) const noexcept
Checks whether two iterators are pointing toward equal elements.
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition hashTable.h:2153
HashTable< Key, Val >::Bucket * _getBucket_() const noexcept
Returns the current iterator's bucket.
bool operator!=(const HashTableConstIterator< Key, Val > &from) const noexcept
Checks whether two iterators are pointing toward different elements.
const mapped_type & val() const
Returns the mapped value pointed to by the iterator.
const HashTable< Key, Val > * _table_
The hash table the iterator is pointing to.
Definition hashTable.h:2350
HashTable< Key, Val >::Bucket * _bucket_
The bucket in the chained list pointed to by the iterator.
Definition hashTable.h:2359
Key key_type
Types for STL compliance.
Definition hashTable.h:2151
const key_type & key() const
Returns the key corresponding to the element pointed to by the iterator.
void clear() noexcept
Makes the iterator point toward nothing (in particular, it is not related anymore to its current hash...
Size _index_
The index of the chained list pointed by the iterator in the array of nodes of the hash table.
Definition hashTable.h:2356
friend class HashTable< Key, Val >
Class HashTable must be a friend because it stores iterator end and this one can be properly initiali...
Definition hashTable.h:2344
HashTableConstIterator() noexcept
Basic constructor: creates an iterator pointing to nothing.
Safe Iterators for hashtables.
Unsafe Iterators for hashtables.
Definition hashTable.h:2428
value_type & operator*()
Returns the value pointed to by the iterator.
Val mapped_type
types for STL compliance
Definition hashTable.h:2434
HashTableIterator< Key, Val > & operator++() noexcept
Makes the iterator point to the next element in the hash table.
HashTableIterator< Key, Val > operator+(Size i) const noexcept
Returns a new iterator.
~HashTableIterator() noexcept
Class destructor.
mapped_type & val()
Returns the mapped value pointed to by the iterator.
HashTableIterator< Key, Val > & operator+=(Size i) noexcept
Makes the iterator point to i elements further in the hashtable.
bool operator==(const HashTableIterator< Key, Val > &from) const noexcept
Checks whether two iterators are pointing toward equal elements.
HashTableIterator() noexcept
Basic constructor: creates an iterator pointing to nothing.
HashTableIterator< Key, Val > & operator=(const HashTableIterator< Key, Val > &from) noexcept
Copy operator.
std::pair< const Key, Val > value_type
types for STL compliance
Definition hashTable.h:2435
bool operator!=(const HashTableIterator< Key, Val > &from) const noexcept
Checks whether two iterators are pointing toward different elements.
Exception : a similar element already exists.
Safe Const Iterators for hashtables.
Definition hashTable.h:1602
HashTableConstIteratorSafe< Key, Val > operator+(Size i) const
Returns a new iterator poiting to i elements further in the hashtable.
const key_type & key() const
Returns the key pointed to by the iterator.
Size _index_
the index of the chained list pointed to by the iterator in the array nodes of the hash table.
Definition hashTable.h:1813
const value_type & operator*() const
Returns the element pointed to by the iterator.
Key key_type
Types for STL compliance.
Definition hashTable.h:1607
Size _getIndex_() const noexcept
Returns the index in the hashtable's node vector pointed to by the iterator.
const mapped_type & val() const
Returns the mapped value pointed to by the iterator.
HashTableBucket< Key, Val > * _next_bucket_
the bucket we should start from when we decide to do a ++.
Definition hashTable.h:1826
HashTableConstIteratorSafe< Key, Val > & operator++() noexcept
Makes the iterator point to the next element in the hash table.
HashTableBucket< Key, Val > * _getBucket_() const noexcept
Returns the current iterator's bucket.
bool operator==(const HashTableConstIteratorSafe< Key, Val > &from) const noexcept
Checks whether two iterators are equal.
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition hashTable.h:1609
HashTableConstIteratorSafe< Key, Val > & operator+=(Size i) noexcept
Makes the iterator point to i elements further in the hashtable.
bool operator!=(const HashTableConstIteratorSafe< Key, Val > &from) const noexcept
Checks whether two iterators are not equal.
HashTableConstIteratorSafe()
Basic constructor: creates an iterator pointing to nothing.
const HashTable< Key, Val > * _table_
The hash table the iterator is pointing to.
Definition hashTable.h:1807
HashTableBucket< Key, Val > * _bucket_
The bucket in the chained list pointed to by the iterator.
Definition hashTable.h:1816
void clear() noexcept
Makes the iterator point toward nothing (in particular, it is not related anymore to its current hash...
void _removeFromSafeList_() const
Removes the iterator from its hashtable' safe iterators list.
~HashTableConstIteratorSafe() noexcept
Destructor.
Val mapped_type
Types for STL compliance.
Definition hashTable.h:1608
HashTableConstIteratorSafe< Key, Val > & operator=(const HashTableConstIteratorSafe< Key, Val > &from)
Copy operator.
friend class HashTable< Key, Val >
Class HashTable must be a friend because it stores iterator end and this can be properly initialized ...
Definition hashTable.h:1804
void _insertIntoSafeList_() const
Insert the iterator into the hashtable's list of safe iterators.
Val mapped_type
types for STL compliance
Definition hashTable.h:322
~HashTableList()
Class destructor.
mapped_type & operator[](const key_type &key)
Returns the value corresponding to a given key.
bool exists(const key_type &key) const
Returns true if a value with the given key exists.
Bucket * bucket(const Key &key) const
A method to get the bucket corresponding to a given key.
HashTableBucket< Key, Val > Bucket
types for STL compliance
Definition hashTable.h:329
void erase(Bucket *ptr)
Removes an element from this chained list.
bool empty() const noexcept
Returns true if this chained list is empty.
HashTableBucket< Key, Val > * _end_list_
A pointer on the last element of the chained list.
Definition hashTable.h:503
void clear()
Removes all the elements of this chained list.
value_type & at(Size i)
Function at returns the ith element in the current chained list.
void _copy_(const HashTableList< Key, Val > &from)
A function used to perform copies of HashTableLists.
HashTableList< Key, Val > & operator=(const HashTableList< Key, Val > &from)
Assignment operator.
HashTableBucket< Key, Val > * _deb_list_
A pointer on the first element of the chained list.
Definition hashTable.h:500
HashTableList() noexcept
Basic constructor that creates an empty list.
std::pair< const Key, Val > value_type
types for STL compliance
Definition hashTable.h:323
friend class HashTable< Key, Val >
Friend for faster access.
Definition hashTable.h:488
void insert(Bucket *new_elt) noexcept
Inserts a new element in the chained list.
Size _nb_elements_
The number of elements in the chained list.
Definition hashTable.h:506
The class for generic Hash Tables.
Definition hashTable.h:637
bool _resize_policy_
Is resizing performed automatically?
Definition hashTable.h:1481
void eraseByVal(const Val &val)
Removes a given element from the hash table.
HashTableIterator< Key, Val > iterator
Types for STL compliance.
Definition hashTable.h:650
void eraseAllVal(const Val &val)
Removes all the elements having a certain value from the hash table.
void _create_(Size size)
Used by all default constructors (general and specialized).
HashFunc< Key > _hash_func_
The function used to hash keys (may change when the table is resized).
Definition hashTable.h:1478
void resize(Size new_size)
Changes the number of slots in the 'nodes' vector of the hash table.
Size _begin_index_
Returns where the begin index should be.
Definition hashTable.h:1500
std::vector< HashTableConstIteratorSafe< Key, Val > * > _safe_iterators_
The list of safe iterators pointing to the hash table.
Definition hashTable.h:1503
void _copy_(const HashTable< Key, Val > &table)
A function used to perform copies of HashTables.
iterator begin()
Returns an unsafe iterator pointing to the beginning of the hashtable.
void setKeyUniquenessPolicy(const bool new_policy) noexcept
Enables the user to change dynamically the policy for checking whether there can exist several elemen...
void _insert_(Bucket *bucket)
Adds a new element (actually a copy of this element) in the hash table.
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition hashTable.h:643
void _clearIterators_()
Clear all the safe iterators.
mapped_type & getWithDefault(const Key &key, const Val &default_value)
Returns a reference on the element the key of which is passed in argument.
const iterator_safe & endSafe() noexcept
Returns the safe iterator pointing to the end of the hashtable.
const const_iterator_safe & cendSafe() const noexcept
Returns the safe const_iterator pointing to the end of the hashtable.
void erase(const Key &key)
Removes a given element from the hash table.
bool exists(const Key &key) const
Checks whether there exists an element with a given key in the hashtable.
~HashTable()
Class destructor.
const_iterator cbegin() const
Returns an unsafe const_iterator pointing to the beginning of the hashtable.
Val & operator[](const Key &key)
Returns a reference on the value the key of which is passed in argument.
const Key & key(const Key &key) const
Returns a reference on a given key.
bool empty() const noexcept
Indicates whether the hash table is empty.
bool resizePolicy() const noexcept
Returns the current resizing policy.
HashTable< Key, Val > & operator=(const HashTable< Key, Val > &from)
Copy operator.
HashTable< Key, Mount > map(Mount(*f)(Val), Size size=Size(0), bool resize_pol=HashTableConst::default_resize_policy, bool key_uniqueness_pol=HashTableConst::default_uniqueness_policy) const
Transforms a hashtable of vals into a hashtable of mountains.
const const_iterator & cend() const noexcept
Returns the unsafe const_iterator pointing to the end of the hashtable.
std::vector< HashTableList< Key, Val > > _nodes_
The hash table is represented as a vector of chained lists.
Definition hashTable.h:1469
bool keyUniquenessPolicy() const noexcept
Returns the current checking policy.
HashTableConstIteratorSafe< Key, Val > const_iterator_safe
Types for STL compliance.
Definition hashTable.h:653
HashTableConstIterator< Key, Val > const_iterator
Types for STL compliance.
Definition hashTable.h:651
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
Val mapped_type
Types for STL compliance.
Definition hashTable.h:642
const iterator & end() noexcept
Returns the unsafe iterator pointing to the end of the hashtable.
void _erase_(HashTableBucket< Key, Val > *bucket, Size index)
Erases a given bucket.
void clear()
Removes all the elements in the hash table.
bool operator==(const HashTable< Key, Val > &from) const
Checks whether two hashtables contain the same elements.
Size capacity() const noexcept
Returns the number of slots in the 'nodes' vector of the hashtable.
HashTableBucket< Key, Val > Bucket
The buckets where data are stored.
Definition hashTable.h:657
bool operator!=(const HashTable< Key, Val > &from) const
Checks whether two hashtables contain different sets of elements.
Size size() const noexcept
Returns the number of elements stored into the hashtable.
iterator_safe beginSafe()
Returns the safe iterator pointing to the beginning of the hashtable.
void reset(const Key &key)
Removes a property (i.e., remove an element).
void setResizePolicy(const bool new_policy) noexcept
Enables the user to change dynamically the resizing policy.
bool _key_uniqueness_policy_
Shall we check for key uniqueness in the table?
Definition hashTable.h:1484
void set(const Key &key, const Val &default_value)
Add a new property or modify it if it already existed.
Size _size_
The number of nodes in vector ' __nodes'.
Definition hashTable.h:1472
const Key & keyByVal(const Val &val) const
Returns a reference on the key given a value.
Size _nb_elements_
Number of elements of type Val stored in the hash table.
Definition hashTable.h:1475
HashTable(Size size_param=HashTableConst::default_size, bool resize_pol=HashTableConst::default_resize_policy, bool key_uniqueness_pol=HashTableConst::default_uniqueness_policy)
Default constructor.
const_iterator_safe cbeginSafe() const
Returns the safe const_iterator pointing to the beginning of the hashtable.
value_type & emplace(Args &&... args)
Emplace a new element into the hashTable.
HashTableIteratorSafe< Key, Val > iterator_safe
Types for STL compliance.
Definition hashTable.h:652
Exception : the element we looked for cannot be found.
Exception : a pointer or a reference on a nullptr (0) object.
Exception : generic error on iterator.
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
unsigned int _hashTableLog2_(const Size nb)
Returns the size in bits - 1 necessary to store the smallest power of 2 greater than or equal to nb.
Class hash tables iterators.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
std::ostream & operator<<(std::ostream &stream, const AVLTree< Val, Cmp > &tree)
display the content of a tree
Definition AVLTree.h:913
bool operator==(const HashTableIteratorSafe< Key, Val > &from) const noexcept
Checks whether two iterators are pointing toward equal elements.
STL namespace.
A recipient for a pair of key value in a gum::HashTableList.
Definition hashTable.h:215
HashTableBucket< Key, Val > * prev
A pointer toward the previous bucket in the gum::HashTableList.
Definition hashTable.h:220
Key & key()
Returns the key part of the pair.
Definition hashTable.h:294
std::pair< const Key, Val > & elt()
Returns the pair stored in this bucket.
Definition hashTable.h:288
HashTableBucket< Key, Val > * next
A pointer toward the next bucket in the gum::HashTableList.
Definition hashTable.h:223
Val & val()
Returns the value part of the pair.
Definition hashTable.h:300
static constexpr Size default_mean_val_by_slot
The average number of elements admissible by slots.
Definition hashTable.h:108