aGrUM 3.1.1
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-2026 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-2026 *
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
41#pragma once
42
43
50#include <iostream>
51#include <sstream>
52#include <string>
53
54// to help IDE parser
56
57namespace gum {
58 // ===========================================================================
59 // === IMPLEMENTATION OF THE CHAINED LISTS USED IN THE HASH TABLES ===
60 // ===========================================================================
61
62 template < typename Key, typename Val >
63 void HashTableList< Key, Val >::_copy_(const HashTableList< Key, Val >& from) {
64 Bucket *ptr, *old_ptr{nullptr}, *new_elt{nullptr};
65 // set the defaults
66 _deb_list_ = nullptr;
67
68 // copy from's list
69 try {
70 for (ptr = from._deb_list_; ptr != nullptr; ptr = ptr->next) {
71 // copy the current from's bucket (may throw an exception either because
72 // new cannot allocate the bucket or because the copy constructor of Val
73 // throws an exception)
74 new_elt = new Bucket(*ptr);
75
76 // rechain properly the new list
77 new_elt->prev = old_ptr;
78
79 if (old_ptr != nullptr) old_ptr->next = new_elt;
80 else _deb_list_ = new_elt;
81
82 old_ptr = new_elt;
83 }
84
85 if (old_ptr != nullptr) old_ptr->next = nullptr;
86
87 // update the number of elements stored into the list and the end of the
88 // list
89 _nb_elements_ = from._nb_elements_;
90 _end_list_ = new_elt;
91 } catch (...) {
92 // problem: we could not allocate an element in the list => we delete
93 // the elements created so far and we throw an exception
94 while (_deb_list_ != nullptr) {
95 Bucket* next_elt = _deb_list_->next;
96 delete _deb_list_;
97 _deb_list_ = next_elt;
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 requires std::same_as< Key, std::string >
118 {
119 for (Bucket* ptr = _deb_list_; ptr != nullptr; ptr = ptr->next)
120 if (ptr->key() == key) return ptr;
121
122 return nullptr;
123 }
124
125 template < typename Key, typename Val >
127 // check that the pointer is not nullptr
128 if (ptr == nullptr) { GUM_ERROR(NullElement, "trying to erase a nullptr bucket") }
129
130 // relink properly the doubly chained list
131 if (ptr->prev != nullptr) ptr->prev->next = ptr->next;
132 else _deb_list_ = ptr->next;
133
134 if (ptr->next != nullptr) ptr->next->prev = ptr->prev;
135 else _end_list_ = ptr->prev;
136
137 // remove the current element from the list
138 delete ptr;
139
141 }
142
143 template < typename Key, typename Val >
144 HashTableList< Key, Val >::HashTableList() noexcept = default;
145
146 template < typename Key, typename Val >
147 HashTableList< Key, Val >::HashTableList(const HashTableList< Key, Val >& from) {
148 _copy_(from);
149 }
150
151 template < typename Key, typename Val >
152 HashTableList< Key, Val >::HashTableList(HashTableList< Key, Val >&& from) noexcept :
153 _deb_list_{from._deb_list_}, _end_list_{from._end_list_}, _nb_elements_{from._nb_elements_} {
154 from._deb_list_ = nullptr;
155 from._end_list_ = nullptr;
156 from._nb_elements_ = 0;
157 }
158
159 template < typename Key, typename Val >
161 for (Bucket *next_ptr, *ptr = _deb_list_; ptr != nullptr; ptr = next_ptr) {
162 next_ptr = ptr->next;
163 delete ptr;
164 }
165 }
166
167 template < typename Key, typename Val >
169 for (Bucket *next_ptr, *ptr = _deb_list_; ptr != nullptr; ptr = next_ptr) {
170 next_ptr = ptr->next;
171 delete ptr;
172 }
173
174 _nb_elements_ = Size(0);
175 _deb_list_ = nullptr;
176 _end_list_ = nullptr;
177 }
178
179 template < typename Key, typename Val >
180 HashTableList< Key, Val >&
181 HashTableList< Key, Val >::operator=(const HashTableList< Key, Val >& from) {
182 // avoid self assignment
183 if (this != &from) {
184 clear();
185 _copy_(from);
186 }
187
188 return *this;
189 }
190
191 template < typename Key, typename Val >
192 HashTableList< Key, Val >&
193 HashTableList< Key, Val >::operator=(HashTableList< Key, Val >&& from) noexcept {
194 // avoid self assignment
195 if (this != &from) {
196 _deb_list_ = from._deb_list_;
197 _end_list_ = from._end_list_;
198 _nb_elements_ = from._nb_elements_;
199 from._deb_list_ = nullptr;
200 }
201
202 return *this;
203 }
204
205 template < typename Key, typename Val >
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 >
219 if (i >= _nb_elements_) { GUM_ERROR(NotFound, "not enough elements in the chained list") }
220
221 Bucket* ptr;
222
223 for (ptr = _deb_list_; i; --i, ptr = ptr->next) {}
224
225 return ptr->elt();
226 }
227
228 template < typename Key, typename Val >
231 for (Bucket* ptr = _deb_list_; ptr != nullptr; ptr = ptr->next)
232 if (ptr->key() == key) return ptr->val();
233
234 GUM_ERROR(NotFound, "No element with the key <" << key << ">")
235 }
236
237 template < typename Key, typename Val >
240 for (Bucket* ptr = _deb_list_; ptr != nullptr; ptr = ptr->next)
241 if (ptr->key() == key) return ptr->val();
242
243 GUM_ERROR(NotFound, "No element with the key <" << key << ">")
244 }
245
246 template < typename Key, typename Val >
247 bool HashTableList< Key, Val >::exists(const Key& key) const {
248 for (Bucket* ptr = _deb_list_; ptr != nullptr; ptr = ptr->next) {
249 if (ptr->key() == key) { return true; }
250 }
251
252 return false;
253 }
254
255 template < typename Key, typename Val >
256 bool HashTableList< Key, Val >::empty() const noexcept {
257 return (_nb_elements_ == Size(0));
258 }
259
260 template < typename Key, typename Val >
262 // place the bucket at the beginning of the list
263 new_elt->prev = nullptr;
264 new_elt->next = _deb_list_;
265
266 if (_deb_list_ != nullptr) _deb_list_->prev = new_elt;
267 else _end_list_ = new_elt;
268
269 _deb_list_ = new_elt;
270
272 }
273
274 // ===========================================================================
275 // === GENERIC HASH TABLE IMPLEMENTATION ===
276 // ===========================================================================
277
278 template < typename Key, typename Val >
280 // in debug mode, check that this and table have ' __nodes' arrays of the
281 // same size
282 GUM_ASSERT(table._size_ == _size_);
283
284 // try to fill the array of chained lists
285 for (Size i = 0; i < table._size_; ++i) {
286 try {
287 _nodes_[i] = table._nodes_[i];
288 } catch (...) {
289 // here we could allocate the _nodes_[j], j=0..i-1, so we should
290 // deallocate them
291 for (Size j = 0; j < _size_; ++j)
292 _nodes_[j].clear();
294 _nb_elements_ = Size(0);
295
296 // propagate the exception
297 throw;
298 }
300
301 _nb_elements_ = table._nb_elements_;
302 }
303
304 template < typename Key, typename Val >
306 // setup the _nodes_ vector (contains only empty lists)
307 _nodes_.resize(size);
308
309 // set up properly the hash function
310 _hash_func_.resize(size);
311 }
312
313 template < typename Key, typename Val >
314 HashTable< Key, Val >::HashTable(Size size_param, bool resize_pol, bool key_uniqueness_pol) :
315 // size must be >= 2 else we lose all the bits of the hash function
316 _size_{Size(1) << _hashTableLog2_(std::max(Size(2), size_param))},
317 _resize_policy_{resize_pol}, _key_uniqueness_policy_{key_uniqueness_pol} {
318 // for debugging purposes
319 GUM_CONSTRUCTOR(HashTable);
320
321 // finalize the creation
323 }
324
325 template < typename Key, typename Val >
326 HashTable< Key, Val >::HashTable(std::initializer_list< std::pair< Key, Val > > list) :
327 // size must be >= 2 else we lose all the bits of the hash function
328 _size_{Size(1) << _hashTableLog2_(std::max< Size >(Size(2), Size(list.size()) / 2))} {
329 // for debugging purposes
330 GUM_CONSTRUCTOR(HashTable);
331
332 // setup the _nodes_ vector (contains only empty lists)
334
335 // insert all the elements
336 for (const auto& elt: list) {
337 insert(elt);
338 }
339 }
340
341 template < typename Key, typename Val >
345 // for debugging purposes
346 GUM_CONS_CPY(HashTable);
347
348 // setup the _nodes_ vector (contains only empty lists)
350
351 // fill with the content of table
352 _copy_(table);
353 }
354
355 template < typename Key, typename Val >
357 _nodes_(std::move(table._nodes_)), _size_{table._size_}, _nb_elements_{table._nb_elements_},
358 _hash_func_{table._hash_func_}, _resize_policy_{table._resize_policy_},
359 _key_uniqueness_policy_{table._key_uniqueness_policy_}, _begin_index_{table._begin_index_} {
360 // clear the safe iterators that pointed to the table
361 for (auto* iter: table._safe_iterators_) {
362 iter->clear();
363 }
365 // for debugging purposes
366 table._size_ = 0;
367 table._nb_elements_ = 0;
368 GUM_CONS_MOV(HashTable);
369 }
370
371 template < typename Key, typename Val >
373 const Size len = _safe_iterators_.size();
374 for (Size i = Size(0); i < len; ++i)
376 }
377
378 template < typename Key, typename Val >
380 // update all the registered iterators: they should now point to nullptr
381 // and they are positioned to the end of the hashtable.
383
384 // remove the buckets
385 for (Size i = Size(0); i < _size_; ++i)
386 _nodes_[i].clear();
387
389 _begin_index_ = std::numeric_limits< Size >::max();
390 }
391
392 template < typename Key, typename Val >
394 // for debugging purposes
395 GUM_DESTRUCTOR(HashTable);
396
397 // update all the registered iterators: they should now point to nullptr
398 // and their hashtable should be set to nullptr
400 }
401
402 template < typename Key, typename Val >
404 // avoid self assignment
405 if (this != &from) {
406 // for debugging purposes
407 GUM_OP_CPY(HashTable);
408
409 // first remove the current content of the hashtable and make
410 // the iterators point to end
412
413 // if sizes of from's and this' _nodes_ vectors are not the same,
414 // we need to remove the current _nodes_' array and to create a
415 // new array with the correct size
416 if (_size_ != from._size_) {
417 _nodes_.resize(from._size_);
418 _size_ = from._size_;
419
420 // update the hash function : this is important as the computation of
421 // the hash values heavily depends on the size of the hash table
422 _hash_func_.resize(_size_);
423 }
424
425 _resize_policy_ = from._resize_policy_;
426 _key_uniqueness_policy_ = from._key_uniqueness_policy_;
427 _begin_index_ = from._begin_index_;
428
429 // perform the copy
430 _copy_(from);
431 }
432
433 return *this;
434 }
435
436 template < typename Key, typename Val >
438 // avoid self assignment
439 if (this != &table) {
440 // for debugging purposes
441 GUM_OP_MOV(HashTable);
442
443 // make the iterators point to nothing
444 for (auto* iter: table._safe_iterators_) {
445 iter->clear();
447
448 // remove the current content of the hashtable and make
449 // the safe iterators of this point to end
450 clear();
451
452 // also make the safe iterators of table point to end
453 for (auto* iter: table._safe_iterators_) {
454 iter->clear();
455 }
456
457 _nodes_ = std::move(table._nodes_);
458 _size_ = table._size_;
459 _nb_elements_ = table._nb_elements_;
460 _hash_func_ = table._hash_func_;
461 _resize_policy_ = table._resize_policy_;
462 _key_uniqueness_policy_ = table._key_uniqueness_policy_;
463 _begin_index_ = table._begin_index_;
464
465 table._size_ = 0; // necessary if we wish to perform moves iteratively,
466 table._nb_elements_ = 0; // i.e. x = std::move ( y ); y = std::move ( z ); ...
467 }
468
469 return *this;
470 }
472 template < typename Key, typename Val >
474 return *(reinterpret_cast< const iterator* >(_HashTable_end_));
475 }
476
477 template < typename Key, typename Val >
479 HashTable< Key, Val >::end() const noexcept {
480 return *(reinterpret_cast< const const_iterator* >(_HashTable_cend_));
481 }
482
483 template < typename Key, typename Val >
486 return *(reinterpret_cast< const const_iterator* >(_HashTable_cend_));
487 }
488
489 template < typename Key, typename Val >
491 // if the table is empty, make the begin and end point to the same element
492 if (_nb_elements_ == Size(0)) return iterator{end()};
493 else return iterator{*this};
494 }
495
496 template < typename Key, typename Val >
498 // if the table is empty, make the begin and end point to the same element
499 if (_nb_elements_ == Size(0)) return const_iterator{end()};
500 else return const_iterator{*this};
501 }
502
503 template < typename Key, typename Val >
505 // if the table is empty, make the begin and end point to the same element
506 if (_nb_elements_ == Size(0)) return const_iterator{cend()};
507 else return const_iterator{*this};
508 }
509
510 template < typename Key, typename Val >
512 return *(reinterpret_cast< const iterator_safe* >(_HashTable_end_safe_));
513 }
514
515 template < typename Key, typename Val >
518 return *(reinterpret_cast< const const_iterator_safe* >(_HashTable_cend_safe_));
519 }
521 template < typename Key, typename Val >
524 return *(reinterpret_cast< const const_iterator_safe* >(_HashTable_cend_safe_));
525 }
526
527 template < typename Key, typename Val >
529 // if the table is empty, make the begin and end point to the same element
530 if (_nb_elements_ == Size(0)) return iterator_safe{endSafe()};
531 else return iterator_safe{*this};
532 }
533
534 template < typename Key, typename Val >
536 // if the table is empty, make the begin and end point to the same element
537 if (_nb_elements_ == Size(0)) return const_iterator_safe{endSafe()};
538 else return const_iterator_safe{*this};
539 }
540
541 template < typename Key, typename Val >
543 // if the table is empty, make the begin and end point to the same element
544 if (_nb_elements_ == Size(0)) return const_iterator_safe{cendSafe()};
545 else return const_iterator_safe{*this};
546 }
547
548 template < typename Key, typename Val >
550 return _nodes_[_hash_func_(key)][key];
551 }
552
553 template < typename Key, typename Val >
554 const Val& HashTable< Key, Val >::operator[](const Key& key) const {
555 return _nodes_[_hash_func_(key)][key];
556 }
557
558 template < typename Key, typename Val >
559 template < typename K >
560 requires(std::same_as< Key, std::string > && std::convertible_to< K, std::string_view >
561 && !std::same_as< std::decay_t< K >, std::string >)
563 std::string_view sv{key};
564 Bucket* b = _nodes_[_hash_func_(sv)].bucket(sv);
565 if (b == nullptr) { GUM_ERROR(NotFound, "No element with the key <" << sv << ">") }
566 return b->val();
567 }
568
569 template < typename Key, typename Val >
570 template < typename K >
571 requires(std::same_as< Key, std::string > && std::convertible_to< K, std::string_view >
572 && !std::same_as< std::decay_t< K >, std::string >)
573 const Val& HashTable< Key, Val >::operator[](const K& key) const {
574 std::string_view sv{key};
575 const Bucket* b = _nodes_[_hash_func_(sv)].bucket(sv);
576 if (b == nullptr) { GUM_ERROR(NotFound, "No element with the key <" << sv << ">") }
577 return b->pair.second;
578 }
579
580 template < typename Key, typename Val >
582 return _nb_elements_;
583 }
584
585 template < typename Key, typename Val >
587 return _size_;
588 }
589
590 template < typename Key, typename Val >
591 bool HashTable< Key, Val >::exists(const Key& key) const {
592 return _nodes_[_hash_func_(key)].exists(key);
593 }
594
595 template < typename Key, typename Val >
596 template < typename K >
597 requires(std::same_as< Key, std::string > && std::convertible_to< K, std::string_view >
598 && !std::same_as< std::decay_t< K >, std::string >)
599 bool HashTable< Key, Val >::exists(const K& key) const {
600 std::string_view sv{key};
601 return _nodes_[_hash_func_(sv)].bucket(sv) != nullptr;
602 }
603
604 template < typename Key, typename Val >
606 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
607 if (bucket == nullptr) return {};
608 return bucket->val();
609 }
610
611 template < typename Key, typename Val >
613 const Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
614 if (bucket == nullptr) return {};
615 return bucket->pair.second;
616 }
617
618 template < typename Key, typename Val >
619 template < typename K >
620 requires(std::same_as< Key, std::string > && std::convertible_to< K, std::string_view >
621 && !std::same_as< std::decay_t< K >, std::string >)
623 std::string_view sv{key};
624 Bucket* b = _nodes_[_hash_func_(sv)].bucket(sv);
625 if (b == nullptr) return {};
626 return b->val();
627 }
628
629 template < typename Key, typename Val >
630 template < typename K >
631 requires(std::same_as< Key, std::string > && std::convertible_to< K, std::string_view >
632 && !std::same_as< std::decay_t< K >, std::string >)
634 std::string_view sv{key};
635 const Bucket* b = _nodes_[_hash_func_(sv)].bucket(sv);
636 if (b == nullptr) return {};
637 return optional_ref< const Val >{b->pair.second};
638 }
639
640 template < typename Key, typename Val >
641 void HashTable< Key, Val >::setResizePolicy(const bool new_policy) noexcept {
642 _resize_policy_ = new_policy;
643 }
644
645 template < typename Key, typename Val >
647 return _resize_policy_;
648 }
649
650 template < typename Key, typename Val >
651 void HashTable< Key, Val >::setKeyUniquenessPolicy(const bool new_policy) noexcept {
652 _key_uniqueness_policy_ = new_policy;
653 }
654
655 template < typename Key, typename Val >
659
660 template < typename Key, typename Val >
662 // new_size must be >= 2 else all the bits of the hash function are lost
663 new_size = std::max(Size(2), new_size);
664
665 // find the real size for allocation (the smallest power of 2 greater
666 // than or equal to new_size) and get its base-2 logarithm
667 int log_size = _hashTableLog2_(new_size);
668 new_size = Size(1) << log_size;
669
670 // check if the new size is different from the actual size
671 // if not, nothing else need be done
672
673 if (new_size != _size_) {
674 // under automatic resize policy, check if the new size leaves
675 // enough space for storing all the current elements
676 if (!_resize_policy_
678 // create a new array of _nodes_ to store the elements
679 std::vector< HashTableList< Key, Val > > new_nodes(new_size);
680
681 // set the new hash function
682 _hash_func_.resize(new_size);
683
684 // put all the elements of the current _nodes_ array into the new one
685 Bucket* bucket;
686 Size new_hashed_key;
687
688 for (Size i = Size(0); i < _size_; ++i) {
689 while ((bucket = _nodes_[i]._deb_list_) != nullptr) {
690 // compute the new hashed key
691 new_hashed_key = _hash_func_(bucket->key());
692
693 // remove the bucket from the list of buckets of the current
694 // node vector
695 _nodes_[i]._deb_list_ = bucket->next;
696
697 // put the bucket into the new _nodes_ vector
698 new_nodes[new_hashed_key].insert(bucket);
699 }
700 }
701
702 // update the size of the hash table
703 _size_ = new_size;
704 _begin_index_ = std::numeric_limits< Size >::max();
705
706 // substitute the current _nodes_ array by the new one
707 std::swap(_nodes_, new_nodes);
708
709 // update the iterators
710 for (auto iter: _safe_iterators_) {
711 if (iter->_bucket_) iter->_index_ = _hash_func_(iter->_bucket_->key());
712 else {
713 iter->_next_bucket_ = nullptr;
714 iter->_index_ = 0;
715 }
716 }
718 }
719 }
720
721 template < typename Key, typename Val >
723 Size hash_key = _hash_func_(bucket->key());
724
725 // check that there does not already exist an element with the same key
726 if (_key_uniqueness_policy_ && _nodes_[hash_key].exists(bucket->key())) {
727 // remove the bucket from memory
728 Key k = bucket->key();
729 delete bucket;
731 "the hashtable contains an element with the same key (" << k << ")");
732 }
733
734 // check whether there is sufficient space to insert the new pair
735 // if not, resize the current hashtable
737 resize(_size_ << 1);
738 hash_key = _hash_func_(bucket->key());
739 }
740
741 // add the new pair
742 _nodes_[hash_key].insert(bucket);
743 ++_nb_elements_;
744
745 // recompute the index of the beginning of the hashtable if possible
746 // WARNING: if _begin_index_ = std::numeric_limits<Size>::max (), we CANNOT
747 // recompute the index because we cannot know whether the current index is
748 // equal to max because there was no element in the hashtable or whether a
749 // previous _erase_() has set the index to max.
750 if (_begin_index_ < hash_key) { _begin_index_ = hash_key; }
751 }
752
753 template < typename Key, typename Val >
755 const Val& theval) {
756 auto bucket = new Bucket(thekey, theval);
757 _insert_(bucket);
758 return bucket->elt();
759 }
760
761 template < typename Key, typename Val >
763 Val&& theval) {
764 auto bucket = new Bucket(std::move(thekey), std::move(theval));
765 _insert_(bucket);
766 return bucket->elt();
767 }
768
769 template < typename Key, typename Val >
771 HashTable< Key, Val >::insert(const std::pair< Key, Val >& elt) {
772 auto bucket = new Bucket(reinterpret_cast< const value_type& >(elt));
773 _insert_(bucket);
774 return bucket->elt();
775 }
776
777 template < typename Key, typename Val >
779 HashTable< Key, Val >::insert(std::pair< Key, Val >&& elt) {
780 auto bucket = new Bucket(std::move(reinterpret_cast< value_type& >(elt)));
781 _insert_(bucket);
782 return bucket->elt();
783 }
784
785 template < typename Key, typename Val >
786 template < typename... Args >
788 auto bucket
789 = new Bucket(HashTableBucket< Key, Val >::Emplace::EMPLACE, std::forward< Args >(args)...);
790 _insert_(bucket);
791 return bucket->elt();
792 }
793
794 template < typename Key, typename Val >
796 HashTable< Key, Val >::getWithDefault(const Key& key, const Val& default_value) {
797 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
798
799 if (bucket == nullptr) return insert(key, default_value).second;
800 else return bucket->val();
801 }
802
803 template < typename Key, typename Val >
805 HashTable< Key, Val >::getWithDefault(Key&& key, Val&& default_value) {
806 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
807
808 if (bucket == nullptr) return insert(std::move(key), std::move(default_value)).second;
809 else return bucket->val();
810 }
811
812 template < typename Key, typename Val >
813 void HashTable< Key, Val >::set(const Key& key, const Val& value) {
814 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
815
816 if (bucket == nullptr) insert(key, value);
817 else bucket->val() = value;
818 }
819
820 template < typename Key, typename Val >
822 if (bucket == nullptr) return;
823
824 // update the registered iterators pointing to this bucket
825 for (auto iter: _safe_iterators_) {
826 if (iter->_bucket_ == bucket) {
827 iter->operator++();
828 iter->_next_bucket_ = iter->_bucket_;
829 iter->_bucket_ = nullptr;
830 } else if (iter->_next_bucket_ == bucket) {
831 iter->_bucket_ = bucket;
832 iter->operator++();
833 iter->_next_bucket_ = iter->_bucket_;
834 iter->_bucket_ = nullptr;
835 }
836 }
837
838 // remove the element from the _nodes_ vector
839 _nodes_[index].erase(bucket);
840
843 if ((index == _begin_index_) && _nodes_[index].empty()) {
844 _begin_index_ = std::numeric_limits< Size >::max();
845 }
846 }
847
848 template < typename Key, typename Val >
850 // get the hashed key
851 Size hash = _hash_func_(key);
852
853 // get the bucket containing the element to erase
854 HashTableBucket< Key, Val >* bucket = _nodes_[hash].bucket(key);
856 _erase_(bucket, hash);
857 }
858
859 template < typename Key, typename Val >
860 template < typename K >
861 requires(std::same_as< Key, std::string > && std::convertible_to< K, std::string_view >
862 && !std::same_as< std::decay_t< K >, std::string >)
864 std::string_view sv{key};
865 Size hash = _hash_func_(sv);
866 HashTableBucket< Key, Val >* bucket = _nodes_[hash].bucket(sv);
867 _erase_(bucket, hash);
868 }
869
870 template < typename Key, typename Val >
872 _erase_(iter._getBucket_(), iter._getIndex_());
873 }
874
875 template < typename Key, typename Val >
877 _erase_(iter._getBucket_(), iter._getIndex_());
878 }
879
880 template < typename Key, typename Val >
882 for (auto iter = cbegin(); iter != cend(); ++iter)
883 if (iter._bucket_->val() == val) {
884 _erase_(iter._getBucket_(), iter._getIndex_());
885 return;
886 }
887 }
888
889 template < typename Key, typename Val >
891 erase(key);
892 }
893
894 template < typename Key, typename Val >
895 const Key& HashTable< Key, Val >::keyByVal(const Val& val) const {
896 for (auto iter = begin(); iter != end(); ++iter)
897 if (iter._bucket_->val() == val) return iter.key();
898
899 GUM_ERROR(NotFound, "not enough elements in the chained list")
900 }
902 template < typename Key, typename Val >
903 const Key& HashTable< Key, Val >::key(const Key& key) const {
904 // get the bucket corresponding to the key
905 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
906
907 if (bucket == nullptr) { GUM_ERROR(NotFound, "key does not belong to the hashtable") }
908
909 return bucket->key();
910 }
911
912 template < typename Key, typename Val >
914 // get the bucket corresponding to the key
915 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
916 return (bucket != nullptr) ? optional_ref< const Key >{bucket->key()}
918 }
919
920 template < typename Key, typename Val >
922 for (auto iterAll = cbeginSafe(); iterAll != cendSafe(); ++iterAll) {
923 if (iterAll._bucket_->val() == val) { _erase_(iterAll._bucket_, iterAll._index_); }
924 }
925 }
926
927 template < typename Key, typename Val >
928 bool HashTable< Key, Val >::empty() const noexcept {
929 return (_nb_elements_ == Size(0));
930 }
931
932 template < typename Key, typename Val >
933 template < typename Mount >
935 Size size,
936 bool resize_pol,
937 bool key_uniqueness_pol) const {
938 // determine the proper size of the hashtable
939 // by default, the size of the table is set so that the table does not take
940 // too much space while allowing to add a few elements without needing to
941 // resize in autmatic resizing mode
942 if (size == 0) size = std::max(Size(2), _nb_elements_ / 2);
943
944 // create a new table
945 HashTable< Key, Mount > table(size, resize_pol, key_uniqueness_pol);
946
947 // fill the new hash table
948 for (auto iter = begin(); iter != end(); ++iter) {
949 table.insert(iter.key(), f(iter.val()));
950 }
951
952 return table;
953 }
955 template < typename Key, typename Val >
956 template < typename Mount >
958 Size size,
959 bool resize_pol,
960 bool key_uniqueness_pol) const {
961 // determine the proper size of the hashtable
962 // by default, the size of the table is set so that the table does not take
963 // too much space while allowing to add a few elements without needing to
964 // resize in autmatic resizing mode
965 if (size == Size(0)) size = std::max(Size(2), _nb_elements_ / 2);
966
967 // create a new table
968 HashTable< Key, Mount > table(size, resize_pol, key_uniqueness_pol);
969
970 // fill the new hash table
971 for (auto iter = begin(); iter != end(); ++iter) {
972 table.insert(iter.key(), f(const_cast< Val& >(iter.val())));
973 }
974
975 return table;
976 }
977
978 template < typename Key, typename Val >
979 template < typename Mount >
981 Size size,
982 bool resize_pol,
983 bool key_uniqueness_pol) const {
984 // determine the proper size of the hashtable
985 // by default, the size of the table is set so that the table does not take
986 // too much space while allowing to add a few elements without needing to
987 // resize in autmatic resizing mode
988 if (size == Size(0)) size = std::max(Size(2), _nb_elements_ / 2);
989
990 // create a new table
991 HashTable< Key, Mount > table(size, resize_pol, key_uniqueness_pol);
993 // fill the new hash table
994 for (auto iter = begin(); iter != end(); ++iter) {
995 table.insert(iter.key(), f(iter.val()));
996 }
997
998 return table;
999 }
1000
1001 template < typename Key, typename Val >
1002 template < typename Mount >
1004 Size size,
1005 bool resize_pol,
1006 bool key_uniqueness_pol) const {
1007 // determine the proper size of the hashtable
1008 // by default, the size of the table is set so that the table does not take
1009 // too much space while allowing to add a few elements without needing to
1010 // resize in autmatic resizing mode
1011 if (size == Size(0)) size = std::max(Size(2), _nb_elements_ / 2);
1012
1013 // create a new table
1014 HashTable< Key, Mount > table(size, resize_pol, key_uniqueness_pol);
1015
1016 // fill the new hash table
1017 for (auto iter = begin(); iter != end(); ++iter) {
1018 table.insert(iter.key(), val);
1019 }
1020
1021 return table;
1022 }
1023
1024 template < typename Key, typename Val >
1026 // checks whether the two hashtables contain the same number of elements
1027 if (from._nb_elements_ != _nb_elements_) return false;
1028
1029 // parse this and check that each element also belongs to from
1030 for (auto iter = begin(); iter != end(); ++iter) {
1031 if (auto p = from.tryGet(iter.key()); !p || iter.val() != *p) return false;
1032 }
1033
1034 return true;
1035 }
1036
1037 template < typename Key, typename Val >
1038 std::ostream& operator<<(std::ostream& stream, const HashTableList< Key, Val >& list) {
1039 bool deja = false;
1040 stream << "[";
1041
1042 for (HashTableBucket< Key, Val >* ptr = list._deb_list_; ptr;
1043 ptr = ptr->list.next, deja = true) {
1044 if (deja) stream << " , ";
1045
1046 stream << ptr->key() << "=>" << ptr->val();
1047 }
1048
1049 stream << "]";
1050
1051 return stream;
1052 }
1053
1054 template < typename Key, typename Val >
1055 std::ostream& operator<<(std::ostream& stream, const HashTableList< Key*, Val >& list) {
1056 bool deja = false;
1057 stream << "[";
1058
1059 for (HashTableBucket< Key, Val >* ptr = list._deb_list_; ptr;
1060 ptr = ptr->list.next, deja = true) {
1061 if (deja) stream << " , ";
1062
1063 stream << ptr->key() << "=>" << ptr->val();
1064 }
1065
1066 stream << "]";
1068 return stream;
1069 }
1070
1071 template < typename Key, typename Val >
1072 std::ostream& operator<<(std::ostream& stream, const HashTable< Key, Val >& table) {
1073 bool deja = false;
1074 stream << "{";
1075
1076 for (Size i = Size(0); i < table._size_; ++i)
1077 for (auto ptr = table._nodes_[i]._deb_list_; ptr; ptr = ptr->next) {
1078 if (deja) stream << " , ";
1079
1080 stream << ptr->key() << "=>" << ptr->val();
1081
1082 deja = true;
1083 }
1084
1085 stream << "}";
1086
1087 return stream;
1088 }
1089
1090 template < typename Key, typename Val >
1091 std::ostream& operator<<(std::ostream& stream, const HashTable< Key*, Val >& table) {
1092 bool deja = false;
1093 stream << "{";
1094
1095 for (Size i = Size(0); i < table._size_; ++i)
1096 for (auto ptr = table._nodes_[i]._deb_list_; ptr; ptr = ptr->next) {
1097 if (deja) stream << " , ";
1098
1099 stream << ptr->key() << "=>" << ptr->val();
1100
1101 deja = true;
1102 }
1103
1104 stream << "}";
1105
1106 return stream;
1107 }
1108
1109 // ===========================================================================
1110 // === SAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1111 // ===========================================================================
1112
1113 template < typename Key, typename Val >
1115 _table_->_safe_iterators_.push_back(
1116 const_cast< HashTableConstIteratorSafe< Key, Val >* >(this));
1117 }
1118
1119 template < typename Key, typename Val >
1121 if (_table_ == nullptr) return;
1122
1123 // find where the iterator is
1124 std::vector< HashTableConstIteratorSafe< Key, Val >* >& iter_vect = _table_->_safe_iterators_;
1125
1126 auto len = iter_vect.size();
1127 for (Size i = Size(0); i < len; ++i) {
1128 if (iter_vect[i] == this) {
1129 iter_vect.erase(iter_vect.begin() + i);
1130 break;
1131 }
1132 }
1133 }
1134
1135 template < typename Key, typename Val >
1137 // for debugging purposes
1138 GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1139 }
1140
1141 template < typename Key, typename Val >
1143 const HashTable< Key, Val >& tab) :
1144 _table_{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1145 // for debugging purposes
1146 GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1147
1148 // make the hashtable keep track of this iterator
1150
1151 if (_table_->_nb_elements_) {
1152 if (_table_->_begin_index_ != std::numeric_limits< Size >::max()) {
1153 _index_ = _table_->_begin_index_;
1154 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1155 } else {
1156 // find the element we shall point to from the start of the hashtable
1157 for (Size i = _table_->_size_ - Size(1);; --i) {
1158 // no test on i since
1159 // _nb_elements_ != 0
1160 if (_table_->_nodes_[i]._nb_elements_) {
1161 _index_ = i;
1162 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1163 _table_->_begin_index_ = _index_;
1164 break;
1165 }
1166 }
1167 }
1168 }
1169 }
1170
1171 template < typename Key, typename Val >
1173 const HashTable< Key, Val >& tab,
1174 Size ind_elt) : _table_{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1175 Size i;
1176
1177 // check if we are looking for a begin() and we know for sure its index
1178 if ((ind_elt == Size(0)) && (_table_->_begin_index_ != std::numeric_limits< Size >::max())) {
1179 _index_ = _table_->_begin_index_;
1180 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1181 } else {
1182 // check if it is faster to find the ind_eltth element from the start or
1183 // from the end of the hashtable
1184 if (ind_elt < (_table_->_nb_elements_ >> 1)) {
1185 // find the element we shall point to from the start of the hashtable
1186 for (i = _table_->_size_ - 1;; --i) {
1187 // no test on i since
1188 // ind_elt < table_-> _nb_elements_
1189 if (_table_->_nodes_[i]._nb_elements_) {
1190 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1191 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1192 else {
1193 for (_bucket_ = _table_->_nodes_[i]._end_list_; ind_elt;
1194 --ind_elt, _bucket_ = _bucket_->prev) {}
1195
1196 _index_ = i;
1197 break;
1198 }
1199 }
1200 }
1201 } else {
1202 // ind_elt = the index of the element we should point to
1203 // check if the index passed as parameter is valid
1204 if (ind_elt >= _table_->_nb_elements_) {
1205 GUM_ERROR(UndefinedIteratorValue, "Not enough elements in the hashtable")
1206 }
1207
1208 // find the element we shall point to from the end of the hashtable
1209 for (i = 0, ind_elt = _table_->_nb_elements_ - ind_elt - 1;; ++i) {
1210 if (_table_->_nodes_[i]._nb_elements_) {
1211 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1212 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1213 else {
1214 for (_bucket_ = _table_->_nodes_[i]._deb_list_; ind_elt;
1215 --ind_elt, _bucket_ = _bucket_->next) {}
1216
1217 _index_ = i;
1218 break;
1219 }
1220 }
1221 }
1222 }
1223 }
1224
1225 // for debugging purposes
1226 GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1227
1228 // make the hashtable keep track of this iterator
1229 _insertIntoSafeList_();
1230 }
1231
1232 template < typename Key, typename Val >
1235 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_},
1237 // make the hashtable keep track of this iterator
1238 if (_table_ != nullptr) { _insertIntoSafeList_(); }
1239
1240 // for debugging purposes
1241 GUM_CONS_CPY(HashTableConstIteratorSafe);
1242 }
1243
1244 template < typename Key, typename Val >
1247 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_} {
1248 // make the hashtable keep track of this iterator
1249 if (_table_ != nullptr) { _insertIntoSafeList_(); }
1250
1251 // for debugging purposes
1252 GUM_CONS_CPY(HashTableConstIteratorSafe);
1253 }
1254
1255 template < typename Key, typename Val >
1258 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_},
1259 _next_bucket_{from._next_bucket_} {
1260 GUM_CONS_MOV(HashTableConstIteratorSafe);
1261
1262 // find "from" in the hashtable's list of safe iterators and substitute
1263 // it by this
1264 if (_table_ != nullptr) {
1265 std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect = _table_->_safe_iterators_;
1266
1267 for (auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1268 if (*ptr == &from) {
1269 *ptr = this;
1270 from._table_ = nullptr;
1271 break;
1272 }
1273 }
1275 }
1276
1277 template < typename Key, typename Val >
1279 // for debugging purposes
1280 GUM_DESTRUCTOR(HashTableConstIteratorSafe);
1281
1282 // remove the iterator from the table's iterator list
1284 }
1285
1286 template < typename Key, typename Val >
1289 // here, no need to avoid self assignment: this would slow down normal
1290 // assignments and, in any case, this would not result in an iterator in
1291 // an incoherent state
1292 // check if the current hashtable is different from that of "from". In such
1293 // a case, we shall remove the iterator from its current hashtable
1294 // iterator's
1295 // list and add it to the new hashtable iterator's list
1296 if (_table_ != from._table_) {
1297 // remove the iterator from its hashtable iterator's list'
1299
1300 _table_ = from._table_;
1301
1302 // add to the new table
1303 if (_table_) { _insertIntoSafeList_(); }
1304 }
1305
1306 _index_ = from._index_;
1307 _bucket_ = from._bucket_;
1309
1310 return *this;
1311 }
1312
1313 template < typename Key, typename Val >
1316 // here, no need to avoid self assignment: this would slow down normal
1317 // assignments and, in any case, this would not result in an iterator in
1318 // an incoherent state
1319 // check if the current hashtable is different from that of "from". In such
1320 // a case, we shall remove the iterator from its current hashtable
1321 // iterator's
1322 // list and add it to the new hashtable iterator's list
1323 if (_table_ != from._table_) {
1324 // remove the iterator from its hashtable iterator's list'
1325 _removeFromSafeList_();
1326
1327 _table_ = from._table_;
1328
1329 // add to the new table
1330 if (_table_) { _insertIntoSafeList_(); }
1331 }
1332
1333 _index_ = from._index_;
1334 _bucket_ = from._bucket_;
1335 _next_bucket_ = nullptr;
1336
1337 return *this;
1338 }
1339
1340 template < typename Key, typename Val >
1343 // here, no need to avoid self assignment: this would slow down normal
1344 // assignments and, in any case, this would not result in an iterator in
1345 // an incoherent state
1346 // check if the current hashtable is different from that of "from". In such
1347 // a case, we shall remove the iterator from its current hashtable
1348 // iterator's
1349 // list and add it to the new hashtable iterator's list
1350 if (_table_ != from._table_) {
1351 // remove the iterator from its hashtable iterator's list'
1352 _removeFromSafeList_();
1353
1354 if (from._table_ != nullptr) {
1355 // substitute from by this in the list of safe iterators
1356 std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect
1357 = from._table_->_safe_iterators_;
1358
1359 for (auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1360 if (*ptr == &from) {
1361 *ptr = this;
1362 break;
1363 }
1364 }
1366
1367 _table_ = from._table_;
1368 from._table_ = nullptr;
1369 }
1370
1371 _index_ = from._index_;
1372 _bucket_ = from._bucket_;
1373 _next_bucket_ = from._next_bucket_;
1374
1375 return *this;
1376 }
1377
1378 template < typename Key, typename Val >
1381 if (_bucket_ != nullptr) return _bucket_->key();
1382 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1383 }
1384
1385 template < typename Key, typename Val >
1388 if (_bucket_ != nullptr) return _bucket_->val();
1389 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1390 }
1391
1392 template < typename Key, typename Val >
1394 // remove the iterator from the table's iterator list
1395 _removeFromSafeList_();
1396
1397 // set its table as well as the element it points to to 0
1398 _table_ = nullptr;
1399 _bucket_ = nullptr;
1400 _next_bucket_ = nullptr;
1401 _index_ = Size(0);
1402 }
1403
1404 // WARNING: never inline this function: this result in g++4.3.3 producing a
1405 // code that segfaults.
1406 template < typename Key, typename Val >
1409 // if _bucket_ != nullptr then use it, else use next_bucket
1410 if (_bucket_ == nullptr) {
1411 // note that this case only happens when the iterator pointed to an
1412 // element that has just been erased. Fortunately, in this case, the
1413 // Hashtable's erase functions update appropriately the _next_bucket_
1414 // and _index_ fields.
1416 _next_bucket_ = nullptr;
1417 } else {
1418 // ok, here we can use _bucket_ as a starting point
1419
1420 // if we are not pointing on the first element of the chained list, just
1421 // point to the preceding bucket in this list
1422 if (_bucket_->prev) {
1423 _bucket_ = _bucket_->prev;
1424 // here, no need to update _next_bucket_, which is compulsorily
1425 // equal to nullptr, nor _index_ which has not changed.
1426 } else {
1427 // ok, here we are on the beginning of a chained list,
1428 // so 2 cases can obtain:
1429 // 1/ index = 0 : then we have reached the end of the hashtable
1430 // 2/ index != 0 => we must search for a new slot containing elements
1431
1432 // case 1:
1433 if (_index_ == Size(0)) {
1434 _bucket_ = nullptr;
1435 // we are thus at the end() of the hashTable
1436 }
1437 // case 2:
1438 else {
1439 // arrived here, we need to parse the hash table until we find a new
1440 // bucket because we are pointing on a chained list with no more
1441 // element
1442 // to the left of the current element
1443 if (_index_ > Size(0)) {
1444 for (Size i = _index_ - Size(1); i > Size(0); --i) {
1445 if (_table_->_nodes_[i]._nb_elements_) {
1446 _index_ = i;
1447 _bucket_ = _table_->_nodes_[i]._end_list_;
1448 return *this;
1449 }
1450 }
1451 }
1452
1453 if (_table_->_nodes_[0]._nb_elements_) _bucket_ = _table_->_nodes_[0]._end_list_;
1454 else _bucket_ = nullptr;
1455
1456 _index_ = 0;
1457 }
1458 }
1459 }
1460
1461 return *this;
1462 }
1463
1464 template < typename Key, typename Val >
1467 if ((nb == Size(0)) || (_table_ == nullptr)) return *this;
1468
1469 // if _bucket_ != nullptr then use it, else use next_bucket
1470 if (_bucket_ == nullptr) {
1471 // note that this case only happens when the iterator pointed to an
1472 // element
1473 // that has just been erased. Fortunately, in this case, the Hashtable's
1474 // erase functions update appropriately the _next_bucket_ and _index_
1475 // fields.
1477 _next_bucket_ = nullptr;
1478 --nb;
1479 }
1480
1481 // ok, here we can use _bucket_ as a starting point: parse all the elements
1482 // of the current chained list
1483 for (; nb && _bucket_ != nullptr; --nb, _bucket_ = _bucket_->prev) {}
1484
1485 if (_bucket_ != nullptr) return *this;
1486
1487 // here, we shall skip all the chained list that have not sufficiently
1488 // many elements
1489 --_index_;
1490
1491 for (; _index_ < _table_->_size_ && nb >= _table_->_nodes_[_index_]._nb_elements_;
1492 nb -= _table_->_nodes_[_index_]._nb_elements_, --_index_) {}
1493
1494 // here: either _index_ >= _table_-> _size_, which means that we did not find
1495 // the element we looked for, i.e., we are at the end of the hashtable, or
1496 // nb < _table_-> _nodes_[ _index_]. _nb_elements_, and we should parse the
1497 // chained list to get the element (which, we know for sure, exists)
1498 if (_index_ >= _table_->_size_) {
1499 _index_ = Size(0);
1500 return *this;
1501 }
1502
1503 for (_bucket_ = _table_->_nodes_[_index_]._end_list_; nb; --nb, _bucket_ = _bucket_->prev) {}
1504
1505 return *this;
1506 }
1507
1508 template < typename Key, typename Val >
1513
1514 template < typename Key, typename Val >
1516 const HashTableConstIteratorSafe< Key, Val >& from) const noexcept {
1517 return ((_bucket_ == from._bucket_) && (_index_ == from._index_));
1518 }
1519
1520 template < typename Key, typename Val >
1523 if (_bucket_) return _bucket_->elt();
1524 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1525 }
1526
1527 template < typename Key, typename Val >
1532
1533 template < typename Key, typename Val >
1537
1538 // ===========================================================================
1539 // === SAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1540 // ===========================================================================
1541
1542 template < typename Key, typename Val >
1544 HashTableConstIteratorSafe< Key, Val >() {
1545 GUM_CONSTRUCTOR(HashTableIteratorSafe);
1546 }
1547
1548 template < typename Key, typename Val >
1549 HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(const HashTable< Key, Val >& tab) :
1550 HashTableConstIteratorSafe< Key, Val >(tab) {
1551 GUM_CONSTRUCTOR(HashTableIteratorSafe);
1552 }
1553
1554 template < typename Key, typename Val >
1555 HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(const HashTable< Key, Val >& tab,
1556 Size ind_elt) :
1557 HashTableConstIteratorSafe< Key, Val >(tab, ind_elt) {
1558 GUM_CONSTRUCTOR(HashTableIteratorSafe);
1559 }
1560
1561 template < typename Key, typename Val >
1562 HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(
1563 const HashTableIteratorSafe< Key, Val >& from) :
1564 HashTableConstIteratorSafe< Key, Val >(from) {
1565 GUM_CONS_CPY(HashTableIteratorSafe);
1566 }
1568 template < typename Key, typename Val >
1570 const HashTableIterator< Key, Val >& from) : HashTableConstIteratorSafe< Key, Val >(from) {
1571 GUM_CONS_CPY(HashTableIteratorSafe);
1572 }
1573
1574 template < typename Key, typename Val >
1576 HashTableIteratorSafe< Key, Val >&& from) noexcept :
1578 GUM_CONS_MOV(HashTableIteratorSafe);
1579 }
1580
1581 template < typename Key, typename Val >
1583 GUM_DESTRUCTOR(HashTableIteratorSafe);
1584 }
1585
1586 template < typename Key, typename Val >
1590 }
1591
1592 template < typename Key, typename Val >
1595 GUM_OP_CPY(HashTableIteratorSafe);
1597 return *this;
1598 }
1599
1600 template < typename Key, typename Val >
1603 GUM_OP_CPY(HashTableIteratorSafe);
1605 return *this;
1606 }
1607
1608 template < typename Key, typename Val >
1610 HashTableIteratorSafe< Key, Val >&& from) noexcept {
1612 return *this;
1613 }
1614
1615 template < typename Key, typename Val >
1618 return *this;
1619 }
1620
1621 template < typename Key, typename Val >
1625 return *this;
1626 }
1627
1628 template < typename Key, typename Val >
1629 HashTableIteratorSafe< Key, Val > HashTableIteratorSafe< Key, Val >::operator+(Size nb) const {
1630 HashTableIteratorSafe< Key, Val > iter{*this};
1631 iter += nb;
1632 return iter;
1633 }
1634
1635 template < typename Key, typename Val >
1636 bool HashTableIteratorSafe< Key, Val >::operator==(
1637 const HashTableIteratorSafe< Key, Val >& from) const noexcept {
1639 }
1640
1641 template < typename Key, typename Val >
1642 typename HashTableIteratorSafe< Key, Val >::value_type&
1643 HashTableIteratorSafe< Key, Val >::operator*() {
1644 return const_cast< Val& >(HashTableConstIteratorSafe< Key, Val >::operator*());
1645 }
1646
1647 template < typename Key, typename Val >
1648 const typename HashTableIteratorSafe< Key, Val >::value_type&
1649 HashTableIteratorSafe< Key, Val >::operator*() const {
1651 }
1652
1653 // ===========================================================================
1654 // === UNSAFE HASH TABLE CONST ITERATORS IMPLEMENTATION ===
1655 // ===========================================================================
1656
1657 template < typename Key, typename Val >
1661
1662 template < typename Key, typename Val >
1664 const HashTable< Key, Val >& tab) noexcept :
1665 _table_{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1666 // for debugging purposes
1667 GUM_CONSTRUCTOR(HashTableConstIterator);
1668
1669 if (_table_->_nb_elements_) {
1670 if (_table_->_begin_index_ != std::numeric_limits< Size >::max()) {
1671 _index_ = _table_->_begin_index_;
1672 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1673 } else {
1674 // find the element we shall point to from the start of the hashtable
1675 for (Size i = _table_->_size_ - Size(1);; --i) {
1676 // no test on i since
1677 // _nb_elements_ != 0
1678 if (_table_->_nodes_[i]._nb_elements_) {
1679 _index_ = i;
1680 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1681 _table_->_begin_index_ = _index_;
1682 break;
1683 }
1684 }
1686 }
1687 }
1688
1689 template < typename Key, typename Val >
1691 Size ind_elt) :
1692 _table_{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1693 Size i;
1694
1695 // check if we are looking for a begin() and we know for sure its index
1696 if ((ind_elt == Size(0)) && (_table_->_begin_index_ != std::numeric_limits< Size >::max())) {
1697 _index_ = _table_->_begin_index_;
1698 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1699 } else {
1700 // check if it is faster to find the ind_eltth element from the start or
1701 // from the end of the hashtable
1702 if (ind_elt < (_table_->_nb_elements_ >> 1)) {
1703 // find the element we shall point to from the start of the hashtable
1704 for (i = _table_->_size_ - 1;; --i) {
1705 // no test on i since
1706 // ind_elt < table_-> _nb_elements_
1707 if (_table_->_nodes_[i]._nb_elements_) {
1708 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1709 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1710 else {
1711 for (_bucket_ = _table_->_nodes_[i]._end_list_; ind_elt;
1712 --ind_elt, _bucket_ = _bucket_->prev) {}
1713
1714 _index_ = i;
1715 break;
1716 }
1717 }
1718 }
1719 } else {
1720 // ind_elt = the index of the element we should point to
1721 // check if the index passed as parameter is valid
1722 if (ind_elt >= _table_->_nb_elements_) {
1723 GUM_ERROR(UndefinedIteratorValue, "Not enough elements in the hashtable")
1724 }
1725
1726 // find the element we shall point to from the end of the hashtable
1727 for (i = 0, ind_elt = _table_->_nb_elements_ - ind_elt - 1;; ++i) {
1728 if (_table_->_nodes_[i]._nb_elements_) {
1729 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1730 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1731 else {
1732 for (_bucket_ = _table_->_nodes_[i]._deb_list_; ind_elt;
1733 --ind_elt, _bucket_ = _bucket_->next) {}
1734
1735 _index_ = i;
1736 break;
1737 }
1738 }
1739 }
1740 }
1741 }
1742
1743 // for debugging purposes
1744 GUM_CONSTRUCTOR(HashTableConstIterator);
1745 }
1746
1747 template < typename Key, typename Val >
1750 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_} {
1751 GUM_CONS_CPY(HashTableConstIterator);
1752 }
1753
1754 template < typename Key, typename Val >
1756 HashTableConstIterator< Key, Val >&& from) noexcept :
1757 _table_{from._table_}, _index_{from._index_}, _bucket_{from._bucket_} {
1759 }
1760
1761 template < typename Key, typename Val >
1763 // for debugging purposes
1764 GUM_DESTRUCTOR(HashTableConstIterator);
1765 }
1766
1767 template < typename Key, typename Val >
1769 const HashTableConstIterator< Key, Val >& from) noexcept = default;
1770
1771 template < typename Key, typename Val >
1773 HashTableConstIterator< Key, Val >&& from) noexcept {
1774 // here, no need to avoid self assignment: this would slow down normal
1775 // assignments and, in any case, this would not result in an iterator in
1776 // an incoherent state
1777 _table_ = from._table_;
1778 _index_ = from._index_;
1779 _bucket_ = from._bucket_;
1780
1781 return *this;
1782 }
1783
1784 template < typename Key, typename Val >
1787 if (_bucket_) return _bucket_->pair.first;
1788 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1789 }
1790
1791 template < typename Key, typename Val >
1794 if (_bucket_) return _bucket_->val();
1795 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1796 }
1797
1798 template < typename Key, typename Val >
1800 _table_ = nullptr;
1801 _bucket_ = nullptr;
1802 _index_ = 0;
1803 }
1804
1805 template < typename Key, typename Val >
1807 // if _bucket_ == nullptr then we are at the end of the hashtable
1808 if (_bucket_ == nullptr) return *this;
1809
1810 // if we are not pointing on the first element of the chained list, just
1811 // point to the next bucket in this list
1812 if (_bucket_->prev) {
1813 _bucket_ = _bucket_->prev;
1814 // here, no need to update _index_ which has not changed.
1815 } else {
1816 // ok, here we are on the end of a chained list,
1817 // so 2 cases can obtain:
1818 // 1/ index = 0 : then we have reached the end of the hashtable
1819 // 2/ index != 0 => we must search for a new slot containing elements
1820
1821 // case 1:
1822 if (_index_ == Size(0)) {
1823 _bucket_ = nullptr;
1824 // we are thus at the end() of the hashTable
1825 }
1826
1827 // case 2:
1828 else {
1829 // arrived here, we need to parse the hash table until we find a new
1830 // bucket because we are pointing on a chained list with no more element
1831 // to the right of the current element
1832 for (Size i = _index_ - Size(1); i; --i) {
1833 if (_table_->_nodes_[i]._nb_elements_) {
1834 _index_ = i;
1835 _bucket_ = _table_->_nodes_[i]._end_list_;
1836 return *this;
1837 }
1839
1840 if (_table_->_nodes_[0]._nb_elements_) _bucket_ = _table_->_nodes_[0]._end_list_;
1841 else _bucket_ = nullptr;
1842
1843 _index_ = Size(0);
1844 }
1845 }
1847 return *this;
1848 }
1849
1850 template < typename Key, typename Val >
1853 if ((nb == 0) || (_table_ == nullptr) || (_bucket_ == nullptr)) return *this;
1854
1855 // ok, here we can use _bucket_ as a starting point: parse all the elements
1856 // of the current chained list
1857 for (; nb && _bucket_ != nullptr; --nb, _bucket_ = _bucket_->prev) {}
1858
1859 if (_bucket_ != nullptr) return *this;
1860
1861 // here, we shall skip all the chained list that have not sufficiently
1862 // many elements
1863 --_index_;
1864
1865 for (; _index_ < _table_->_size_ && nb >= _table_->_nodes_[_index_]._nb_elements_;
1866 nb -= _table_->_nodes_[_index_]._nb_elements_, --_index_) {}
1867
1868 // here: either _index_ >= _table_-> _size_, which means that we did not find
1869 // the element we looked for, i.e., we are at the end of the hashtable, or
1870 // nb < _table_-> _nodes_[ _index_]. _nb_elements_, and we should parse the
1871 // chained list to get the element (which, we know for sure, exists)
1872 if (_index_ >= _table_->_size_) {
1873 _index_ = 0;
1874 return *this;
1875 }
1876
1877 for (_bucket_ = _table_->_nodes_[_index_]._end_list_; nb; --nb, _bucket_ = _bucket_->prev) {}
1878
1879 return *this;
1880 }
1881
1882 template < typename Key, typename Val >
1885 return HashTableConstIterator< Key, Val >{*this} += nb;
1886 }
1887
1888 template < typename Key, typename Val >
1890 const HashTableConstIterator< Key, Val >& from) const noexcept {
1891 return (_bucket_ == from._bucket_);
1892 }
1893
1894 template < typename Key, typename Val >
1897 if (_bucket_) return _bucket_->elt();
1898 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1899 }
1901 template < typename Key, typename Val >
1904 return _bucket_;
1905 }
1906
1907 template < typename Key, typename Val >
1909 return _index_;
1910 }
1911
1912 // ===========================================================================
1913 // === UNSAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1914 // ===========================================================================
1915
1916 template < typename Key, typename Val >
1918 HashTableConstIterator< Key, Val >() {
1919 GUM_CONSTRUCTOR(HashTableIterator);
1920 }
1921
1922 template < typename Key, typename Val >
1927
1928 template < typename Key, typename Val >
1930 HashTableConstIterator< Key, Val >(tab, ind_elt) {
1931 GUM_CONSTRUCTOR(HashTableIterator);
1932 }
1933
1934 template < typename Key, typename Val >
1940
1941 template < typename Key, typename Val >
1946
1947 template < typename Key, typename Val >
1951
1952 template < typename Key, typename Val >
1954 if (this->_bucket_) return this->_bucket_->val();
1955 else { GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object") }
1956 }
1957
1958 template < typename Key, typename Val >
1964
1965 template < typename Key, typename Val >
1971
1972 template < typename Key, typename Val >
1977
1978 template < typename Key, typename Val >
1983
1984 template < typename Key, typename Val >
1987 iter += nb;
1988 return iter;
1989 }
1990
1991 template < typename Key, typename Val >
1996
1997 template < typename Key, typename Val >
2001
2002 template < typename Key, typename Val >
2007
2008 // ===========================================================================
2009 // === IMPLEMENTATION OF HashTableBucket ===
2010 // ===========================================================================
2011
2012 template < typename Key, typename Val >
2013 HashTableBucket< Key, Val >::HashTableBucket(const std::pair< const Key, Val >& p) : pair(p) {}
2014
2015 template < typename Key, typename Val >
2016 HashTableBucket< Key, Val >::HashTableBucket(std::pair< const Key, Val >&& p) :
2017 pair(std::move(p)) {}
2018
2019 template < typename Key, typename Val >
2020 template < typename... Args >
2022 // emplace (universal) constructor
2023 pair(std::forward< Args >(args)...) {}
2024
2025 template < typename Key, typename Val >
2026 std::pair< const Key, Val >& HashTableBucket< Key, Val >::elt() {
2027 return pair;
2028 }
2029
2030 template < typename Key, typename Val >
2032 return const_cast< Key& >(pair.first);
2033 }
2034
2035 template < typename Key, typename Val >
2037 return pair.second;
2038 }
2039
2040} /* namespace gum */
Unsafe Const Iterators for hashtables.
Definition hashTable.h:2191
HashTableConstIterator< Key, Val > & operator++() noexcept
Makes the iterator point to the next element in the hash table.
Val mapped_type
Types for STL compliance.
Definition hashTable.h:2197
const value_type & operator*() const
Returns the value pointed to by the iterator.
HashTableConstIterator< Key, Val > & operator+=(Size i) noexcept
Makes the iterator point to i elements further in the hashtable.
const mapped_type & val() const
Returns the mapped value pointed to by the iterator.
HashTableConstIterator< Key, Val > & operator=(const HashTableConstIterator< Key, Val > &from) noexcept
Copy operator.
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.
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition hashTable.h:2198
const HashTable< Key, Val > * _table_
The hash table the iterator is pointing to.
Definition hashTable.h:2387
HashTable< Key, Val >::Bucket * _bucket_
The bucket in the chained list pointed to by the iterator.
Definition hashTable.h:2396
Key key_type
Types for STL compliance.
Definition hashTable.h:2196
void clear() noexcept
Makes the iterator point toward nothing (in particular, it is not related anymore to its current hash...
~HashTableConstIterator() noexcept
Class destructor.
Size _index_
The index of the chained list pointed by the iterator in the array of nodes of the hash table.
Definition hashTable.h:2393
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:2381
const key_type & key() const
Returns the key corresponding to the element pointed to by the iterator.
bool operator==(const HashTableConstIterator< Key, Val > &from) const noexcept
Checks whether two iterators are pointing toward equal elements.
HashTable< Key, Val >::Bucket * _getBucket_() const noexcept
Returns the current iterator's bucket.
HashTableConstIterator() noexcept
Basic constructor: creates an iterator pointing to nothing.
Safe Iterators for hashtables.
Unsafe Iterators for hashtables.
Definition hashTable.h:2465
Val mapped_type
types for STL compliance
Definition hashTable.h:2471
HashTableIterator< Key, Val > & operator++() noexcept
Makes the iterator point to the next element in the hash table.
HashTableIterator() noexcept
Basic constructor: creates an iterator pointing to nothing.
~HashTableIterator() noexcept
Class destructor.
HashTableIterator< Key, Val > operator+(Size i) const noexcept
Returns a new iterator.
HashTableIterator< Key, Val > & operator=(const HashTableIterator< Key, Val > &from) noexcept
Copy operator.
mapped_type & val()
Returns the mapped value pointed to by the iterator.
value_type & operator*()
Returns the value pointed to by the iterator.
HashTableIterator< Key, Val > & operator+=(Size i) noexcept
Makes the iterator point to i elements further in the hashtable.
std::pair< const Key, Val > value_type
types for STL compliance
Definition hashTable.h:2472
bool operator==(const HashTableIterator< Key, Val > &from) const noexcept
Checks whether two iterators are pointing toward equal elements.
Exception : a similar element already exists.
Safe Const Iterators for hashtables.
Definition hashTable.h:1662
const mapped_type & val() const
Returns the mapped value pointed to by the iterator.
HashTableBucket< Key, Val > * _getBucket_() const noexcept
Returns the current iterator's bucket.
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 to by the iterator in the array nodes of the hash table.
Definition hashTable.h:1866
HashTableConstIteratorSafe()
Basic constructor: creates an iterator pointing to nothing.
void _insertIntoSafeList_() const
Insert the iterator into the hashtable's list of safe iterators.
Key key_type
Types for STL compliance.
Definition hashTable.h:1667
HashTableBucket< Key, Val > * _next_bucket_
the bucket we should start from when we decide to do a ++.
Definition hashTable.h:1879
HashTableConstIteratorSafe< Key, Val > & operator++() noexcept
Makes the iterator point to the next element in the hash table.
bool operator==(const HashTableConstIteratorSafe< Key, Val > &from) const noexcept
Checks whether two iterators are equal.
~HashTableConstIteratorSafe() noexcept
Destructor.
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition hashTable.h:1669
const value_type & operator*() const
Returns the element pointed to by the iterator.
HashTableConstIteratorSafe< Key, Val > & operator+=(Size i) noexcept
Makes the iterator point to i elements further in the hashtable.
const HashTable< Key, Val > * _table_
The hash table the iterator is pointing to.
Definition hashTable.h:1860
void _removeFromSafeList_() const
Removes the iterator from its hashtable' safe iterators list.
HashTableBucket< Key, Val > * _bucket_
The bucket in the chained list pointed to by the iterator.
Definition hashTable.h:1869
Size _getIndex_() const noexcept
Returns the index in the hashtable's node vector pointed to by the iterator.
HashTableConstIteratorSafe< Key, Val > operator+(Size i) const
Returns a new iterator poiting to i elements further in the hashtable.
Val mapped_type
Types for STL compliance.
Definition hashTable.h:1668
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:1857
const key_type & key() const
Returns the key pointed to by the iterator.
Val mapped_type
types for STL compliance
Definition hashTable.h:321
mapped_type & operator[](const key_type &key)
Returns the value corresponding to a given key.
void clear()
Removes all the elements of this chained list.
bool empty() const noexcept
Returns true if this chained list is empty.
HashTableBucket< Key, Val > Bucket
types for STL compliance
Definition hashTable.h:328
value_type & at(Size i)
Function at returns the ith element in the current chained list.
HashTableList< Key, Val > & operator=(const HashTableList< Key, Val > &from)
Assignment operator.
~HashTableList()
Class destructor.
bool exists(const key_type &key) const
Returns true if a value with the given key exists.
void insert(Bucket *new_elt) noexcept
Inserts a new element in the chained list.
HashTableBucket< Key, Val > * _end_list_
A pointer on the last element of the chained list.
Definition hashTable.h:506
void _copy_(const HashTableList< Key, Val > &from)
A function used to perform copies of HashTableLists.
HashTableList() noexcept
Basic constructor that creates an empty list.
HashTableBucket< Key, Val > * _deb_list_
A pointer on the first element of the chained list.
Definition hashTable.h:503
void erase(Bucket *ptr)
Removes an element from this chained list.
std::pair< const Key, Val > value_type
types for STL compliance
Definition hashTable.h:322
friend class HashTable< Key, Val >
Friend for faster access.
Definition hashTable.h:491
Bucket * bucket(const Key &key) const
A method to get the bucket corresponding to a given key.
Size _nb_elements_
The number of elements in the chained list.
Definition hashTable.h:509
The class for generic Hash Tables.
Definition hashTable.h:640
bool resizePolicy() const noexcept
Returns the current resizing policy.
void _create_(Size size)
Used by all default constructors (general and specialized).
iterator_safe beginSafe()
Returns the safe iterator pointing to the beginning of the hashtable.
const const_iterator & cend() const noexcept
Returns the unsafe const_iterator pointing to the end of the hashtable.
const Key & keyByVal(const Val &val) const
Returns a reference on the key given a value.
bool _resize_policy_
Is resizing performed automatically?
Definition hashTable.h:1541
HashTableIterator< Key, Val > iterator
Types for STL compliance.
Definition hashTable.h:653
void eraseAllVal(const Val &val)
Removes all the elements having a certain value from the hash table.
HashFunc< Key > _hash_func_
The function used to hash keys (may change when the table is resized).
Definition hashTable.h:1538
void resize(Size new_size)
Changes the number of slots in the 'nodes' vector of the hash table.
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
Size _begin_index_
Returns where the begin index should be.
Definition hashTable.h:1560
Size capacity() const noexcept
Returns the number of slots in the 'nodes' vector of the hashtable.
std::vector< HashTableConstIteratorSafe< Key, Val > * > _safe_iterators_
The list of safe iterators pointing to the hash table.
Definition hashTable.h:1563
void _copy_(const HashTable< Key, Val > &table)
A function used to perform copies of HashTables.
void clear()
Removes all the elements in the hash table.
const Key & key(const Key &key) const
Returns a reference on a given key.
value_type & emplace(Args &&... args)
Emplace a new element into the hashTable.
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:646
void set(const Key &key, const Val &default_value)
Add a new property or modify it if it already existed.
void setKeyUniquenessPolicy(const bool new_policy) noexcept
Enables the user to change dynamically the policy for checking whether there can exist several elemen...
void erase(const Key &key)
Removes a given element from the hash table.
const_iterator_safe cbeginSafe() const
Returns the safe const_iterator pointing to the beginning of the hashtable.
~HashTable()
Class destructor.
iterator begin()
Returns an unsafe iterator pointing to the beginning of the hashtable.
const iterator_safe & endSafe() noexcept
Returns the safe iterator pointing to the end of the hashtable.
void reset(const Key &key)
Removes a property (i.e., remove an element).
const const_iterator_safe & cendSafe() const noexcept
Returns the safe const_iterator pointing to the end of the hashtable.
const iterator & end() noexcept
Returns the unsafe iterator pointing to the end of the hashtable.
void eraseByVal(const Val &val)
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< Key, Val > & operator=(const HashTable< Key, Val > &from)
Copy operator.
Size size() const noexcept
Returns the number of elements stored into the hashtable.
void setResizePolicy(const bool new_policy) noexcept
Enables the user to change dynamically the resizing policy.
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.
mapped_type & getWithDefault(const Key &key, const Val &default_value)
Returns a reference on the element the key of which is passed in argument.
std::vector< HashTableList< Key, Val > > _nodes_
The hash table is represented as a vector of chained lists.
Definition hashTable.h:1529
HashTableConstIteratorSafe< Key, Val > const_iterator_safe
Types for STL compliance.
Definition hashTable.h:656
HashTableConstIterator< Key, Val > const_iterator
Types for STL compliance.
Definition hashTable.h:654
Val mapped_type
Types for STL compliance.
Definition hashTable.h:645
const_iterator cbegin() const
Returns an unsafe const_iterator pointing to the beginning of the hashtable.
void _erase_(HashTableBucket< Key, Val > *bucket, Size index)
Erases a given bucket.
bool operator==(const HashTable< Key, Val > &from) const
Checks whether two hashtables contain the same elements.
HashTableBucket< Key, Val > Bucket
The buckets where data are stored.
Definition hashTable.h:660
void _clearIterators_()
Clear all the safe iterators.
bool _key_uniqueness_policy_
Shall we check for key uniqueness in the table?
Definition hashTable.h:1544
Size _size_
The number of nodes in vector ' __nodes'.
Definition hashTable.h:1532
Val & operator[](const Key &key)
Returns a reference on the value the key of which is passed in argument.
Size _nb_elements_
Number of elements of type Val stored in the hash table.
Definition hashTable.h:1535
optional_ref< const Key > tryGetKey(const Key &key) const
Returns an optional reference to a given key, or nullptr if the hash table does not contain it.
HashTable(Size size_param=HashTableConst::default_size, bool resize_pol=HashTableConst::default_resize_policy, bool key_uniqueness_pol=HashTableConst::default_uniqueness_policy)
Default constructor.
bool keyUniquenessPolicy() const noexcept
Returns the current checking policy.
optional_ref< Val > tryGet(const Key &key)
Returns a pointer to the value associated with a given key, or nullptr if the key does not exist.
HashTableIteratorSafe< Key, Val > iterator_safe
Types for STL compliance.
Definition hashTable.h:655
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.
A lightweight wrapper around a pointer providing an optional-like API for references (not supported b...
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
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
STL namespace.
A recipient for a pair of key value in a gum::HashTableList.
Definition hashTable.h:216
HashTableBucket< Key, Val > * prev
A pointer toward the previous bucket in the gum::HashTableList.
Definition hashTable.h:221
Key & key()
Returns the key part of the pair.
Emplace
A dummy type for the emplace constructor.
Definition hashTable.h:230
std::pair< const Key, Val > pair
The pair stored in this bucket.
Definition hashTable.h:218
std::pair< const Key, Val > & elt()
Returns the pair stored in this bucket.
HashTableBucket< Key, Val > * next
A pointer toward the next bucket in the gum::HashTableList.
Definition hashTable.h:224
HashTableBucket()=default
Class constructor.
Val & val()
Returns the value part of the pair.
static constexpr Size default_mean_val_by_slot
The average number of elements admissible by slots.
Definition hashTable.h:109