33 #include <agrum/tools/core/hashTable.h> 42 template <
typename Key,
typename Val,
typename Alloc >
43 template <
typename OtherAlloc >
44 void HashTableList< Key, Val, Alloc >::_copy_(
const HashTableList< Key, Val, OtherAlloc >& from) {
45 Bucket *ptr, *old_ptr{
nullptr}, *new_elt{
nullptr};
51 for (ptr = from._deb_list_; ptr !=
nullptr; ptr = ptr->next) {
55 new_elt = _alloc_bucket_->allocate(1);
58 _alloc_bucket_->construct(new_elt, *ptr);
60 _alloc_bucket_->deallocate(new_elt, 1);
65 new_elt->prev = old_ptr;
67 if (old_ptr !=
nullptr)
68 old_ptr->next = new_elt;
75 if (old_ptr !=
nullptr) old_ptr->next =
nullptr;
79 _nb_elements_ = from._nb_elements_;
84 for (; _deb_list_ !=
nullptr; _deb_list_ = new_elt) {
85 new_elt = _deb_list_->next;
86 _alloc_bucket_->destroy(_deb_list_);
87 _alloc_bucket_->deallocate(_deb_list_, 1);
97 template <
typename Key,
typename Val,
typename Alloc >
98 INLINE HashTableBucket< Key, Val >*
99 HashTableList< Key, Val, Alloc >::bucket(
const Key& key)
const {
100 for (Bucket* ptr = _deb_list_; ptr !=
nullptr; ptr = ptr->next)
101 if (ptr->key() == key)
return ptr;
106 template <
typename Key,
typename Val,
typename Alloc >
107 INLINE
void HashTableList< Key, Val, Alloc >::erase(HashTableBucket< Key, Val >* ptr) {
109 if (ptr ==
nullptr) { GUM_ERROR(NullElement,
"trying to erase a nullptr bucket") }
112 if (ptr->prev !=
nullptr)
113 ptr->prev->next = ptr->next;
115 _deb_list_ = ptr->next;
117 if (ptr->next !=
nullptr)
118 ptr->next->prev = ptr->prev;
120 _end_list_ = ptr->prev;
123 _alloc_bucket_->destroy(ptr);
124 _alloc_bucket_->deallocate(ptr, 1);
129 template <
typename Key,
typename Val,
typename Alloc >
130 INLINE HashTableList< Key, Val, Alloc >::HashTableList(
131 typename HashTableList< Key, Val, Alloc >::BucketAllocator* allocator)
noexcept :
132 _alloc_bucket_{allocator} {}
134 template <
typename Key,
typename Val,
typename Alloc >
136 HashTableList< Key, Val, Alloc >::HashTableList(
const HashTableList< Key, Val, Alloc >& from) :
137 _alloc_bucket_{from._alloc_bucket_} {
141 template <
typename Key,
typename Val,
typename Alloc >
142 INLINE HashTableList< Key, Val, Alloc >::HashTableList(
143 HashTableList< Key, Val, Alloc >&& from)
noexcept :
144 _deb_list_{from._deb_list_},
145 _end_list_{from._end_list_}, _nb_elements_{from._nb_elements_}, _alloc_bucket_{
146 from._alloc_bucket_} {
147 from._deb_list_ =
nullptr;
150 template <
typename Key,
typename Val,
typename Alloc >
151 INLINE HashTableList< Key, Val, Alloc >::~HashTableList() {
152 for (Bucket *next_ptr, *ptr = _deb_list_; ptr !=
nullptr; ptr = next_ptr) {
153 next_ptr = ptr->next;
154 _alloc_bucket_->destroy(ptr);
155 _alloc_bucket_->deallocate(ptr, 1);
159 template <
typename Key,
typename Val,
typename Alloc >
160 INLINE
void HashTableList< Key, Val, Alloc >::clear() {
161 for (Bucket *next_ptr, *ptr = _deb_list_; ptr !=
nullptr; ptr = next_ptr) {
162 next_ptr = ptr->next;
163 _alloc_bucket_->destroy(ptr);
164 _alloc_bucket_->deallocate(ptr, 1);
167 _nb_elements_ = Size(0);
168 _deb_list_ =
nullptr;
169 _end_list_ =
nullptr;
172 template <
typename Key,
typename Val,
typename Alloc >
173 INLINE HashTableList< Key, Val, Alloc >&
174 HashTableList< Key, Val, Alloc >::operator=(
const HashTableList< Key, Val, Alloc >& from) {
184 template <
typename Key,
typename Val,
typename Alloc >
185 template <
typename OtherAlloc >
186 INLINE HashTableList< Key, Val, Alloc >& HashTableList< Key, Val, Alloc >::operator=(
187 const HashTableList< Key, Val, OtherAlloc >& from) {
189 if (
this !=
reinterpret_cast<
const HashTableList< Key, Val, Alloc >* >(&from)) {
197 template <
typename Key,
typename Val,
typename Alloc >
198 INLINE HashTableList< Key, Val, Alloc >&
199 HashTableList< Key, Val, Alloc >::operator=(HashTableList< Key, Val, Alloc >&& from)
noexcept {
202 _deb_list_ = from._deb_list_;
203 _end_list_ = from._end_list_;
204 _nb_elements_ = from._nb_elements_;
205 from._deb_list_ =
nullptr;
211 template <
typename Key,
typename Val,
typename Alloc >
212 INLINE
void HashTableList< Key, Val, Alloc >::setAllocator(
213 typename HashTableList< Key, Val, Alloc >::BucketAllocator& alloc) {
214 _alloc_bucket_ = &alloc;
217 template <
typename Key,
typename Val,
typename Alloc >
218 INLINE
typename HashTableList< Key, Val, Alloc >::value_type&
219 HashTableList< Key, Val, Alloc >::at(Size i) {
220 if (i >= _nb_elements_) { GUM_ERROR(NotFound,
"not enough elements in the chained list") }
224 for (ptr = _deb_list_; i; --i, ptr = ptr->next) {}
229 template <
typename Key,
typename Val,
typename Alloc >
230 INLINE
const typename HashTableList< Key, Val, Alloc >::value_type&
231 HashTableList< Key, Val, Alloc >::at(Size i)
const {
232 if (i >= _nb_elements_) { GUM_ERROR(NotFound,
"not enough elements in the chained list") }
236 for (ptr = _deb_list_; i; --i, ptr = ptr->next) {}
241 template <
typename Key,
typename Val,
typename Alloc >
242 INLINE
const typename HashTableList< Key, Val, Alloc >::mapped_type&
243 HashTableList< Key, Val, Alloc >::operator[](
const Key& key)
const {
244 for (Bucket* ptr = _deb_list_; ptr !=
nullptr; ptr = ptr->next)
245 if (ptr->key() == key)
return ptr->val();
247 GUM_ERROR(NotFound,
"No element with the key <" << key <<
">")
250 template <
typename Key,
typename Val,
typename Alloc >
251 INLINE
typename HashTableList< Key, Val, Alloc >::mapped_type&
252 HashTableList< Key, Val, Alloc >::operator[](
const Key& key) {
253 for (Bucket* ptr = _deb_list_; ptr !=
nullptr; ptr = ptr->next)
254 if (ptr->key() == key)
return ptr->val();
256 GUM_ERROR(NotFound,
"No element with the key <" << key <<
">")
259 template <
typename Key,
typename Val,
typename Alloc >
260 INLINE
bool HashTableList< Key, Val, Alloc >::exists(
const Key& key)
const {
261 for (Bucket* ptr = _deb_list_; ptr !=
nullptr; ptr = ptr->next) {
262 if (ptr->key() == key) {
return true; }
268 template <
typename Key,
typename Val,
typename Alloc >
269 INLINE
bool HashTableList< Key, Val, Alloc >::empty()
const noexcept {
270 return (_nb_elements_ == Size(0));
273 template <
typename Key,
typename Val,
typename Alloc >
275 HashTableList< Key, Val, Alloc >::insert(HashTableBucket< Key, Val >* new_elt)
noexcept {
277 new_elt->prev =
nullptr;
278 new_elt->next = _deb_list_;
280 if (_deb_list_ !=
nullptr)
281 _deb_list_->prev = new_elt;
283 _end_list_ = new_elt;
285 _deb_list_ = new_elt;
294 template <
typename Key,
typename Val,
typename Alloc >
295 template <
typename OtherAlloc >
296 void HashTable< Key, Val, Alloc >::_copy_(
const HashTable< Key, Val, OtherAlloc >& table) {
299 GUM_ASSERT(table._size_ == _size_);
302 for (Size i = 0; i < table._size_; ++i) {
304 _nodes_[i] = table._nodes_[i];
308 for (Size j = 0; j < _size_; ++j)
311 _nb_elements_ = Size(0);
318 _nb_elements_ = table._nb_elements_;
321 template <
typename Key,
typename Val,
typename Alloc >
322 INLINE
const typename HashTable< Key, Val, Alloc >::iterator&
323 HashTable< Key, Val, Alloc >::end4Statics() {
324 return *(
reinterpret_cast<
const iterator* >(HashTableIteratorStaticEnd::end4Statics()));
327 template <
typename Key,
typename Val,
typename Alloc >
328 INLINE
const typename HashTable< Key, Val, Alloc >::const_iterator&
329 HashTable< Key, Val, Alloc >::constEnd4Statics() {
331 reinterpret_cast<
const const_iterator* >(HashTableIteratorStaticEnd::constEnd4Statics()));
334 template <
typename Key,
typename Val,
typename Alloc >
335 INLINE
const typename HashTable< Key, Val, Alloc >::iterator_safe&
336 HashTable< Key, Val, Alloc >::endSafe4Statics() {
338 reinterpret_cast<
const iterator_safe* >(HashTableIteratorStaticEnd::endSafe4Statics()));
341 template <
typename Key,
typename Val,
typename Alloc >
342 INLINE
const typename HashTable< Key, Val, Alloc >::const_iterator_safe&
343 HashTable< Key, Val, Alloc >::constEndSafe4Statics() {
344 return *(
reinterpret_cast<
const const_iterator_safe* >(
345 HashTableIteratorStaticEnd::constEndSafe4Statics()));
348 template <
typename Key,
typename Val,
typename Alloc >
349 INLINE
void HashTable< Key, Val, Alloc >::_create_(Size size) {
351 _nodes_.resize(size);
353 for (
auto& list: _nodes_) {
354 list.setAllocator(_alloc_);
358 _hash_func_.resize(size);
365 template <
typename Key,
typename Val,
typename Alloc >
366 HashTable< Key, Val, Alloc >::HashTable(Size size_param,
368 bool key_uniqueness_pol) :
370 _size_{Size(1) << _hashTableLog2_(std::max(Size(2), size_param))},
371 _resize_policy_{resize_pol}, _key_uniqueness_policy_{key_uniqueness_pol} {
373 GUM_CONSTRUCTOR(HashTable);
379 template <
typename Key,
typename Val,
typename Alloc >
380 HashTable< Key, Val, Alloc >::HashTable(std::initializer_list< std::pair< Key, Val > > list) :
382 _size_{Size(1) << _hashTableLog2_(std::max< Size >(Size(2), Size(list.size()) / 2))} {
384 GUM_CONSTRUCTOR(HashTable);
390 for (
const auto& elt: list) {
395 template <
typename Key,
typename Val,
typename Alloc >
396 HashTable< Key, Val, Alloc >::HashTable(
const HashTable< Key, Val, Alloc >& table) :
397 _size_{table._size_}, _resize_policy_{table._resize_policy_},
398 _key_uniqueness_policy_{table._key_uniqueness_policy_}, _begin_index_{table._begin_index_} {
400 GUM_CONS_CPY(HashTable);
409 template <
typename Key,
typename Val,
typename Alloc >
410 template <
typename OtherAlloc >
411 HashTable< Key, Val, Alloc >::HashTable(
const HashTable< Key, Val, OtherAlloc >& table) :
412 _size_{table._size_}, _resize_policy_{table._resize_policy_},
413 _key_uniqueness_policy_{table._key_uniqueness_policy_}, _begin_index_{table._begin_index_} {
415 GUM_CONS_CPY(HashTable);
424 template <
typename Key,
typename Val,
typename Alloc >
425 HashTable< Key, Val, Alloc >::HashTable(HashTable< Key, Val, Alloc >&& table) :
426 _nodes_(std::move(table._nodes_)), _size_{table._size_}, _nb_elements_{table._nb_elements_},
427 _hash_func_{table._hash_func_}, _resize_policy_{table._resize_policy_},
428 _key_uniqueness_policy_{table._key_uniqueness_policy_}, _begin_index_{table._begin_index_},
429 _safe_iterators_(std::move(table._safe_iterators_)), _alloc_(std::move(table._alloc_)) {
432 GUM_CONS_MOV(HashTable);
435 template <
typename Key,
typename Val,
typename Alloc >
436 INLINE
void HashTable< Key, Val, Alloc >::_clearIterators_() {
437 const Size len = _safe_iterators_.size();
438 for (Size i = Size(0); i < len; ++i)
439 _safe_iterators_[i]->clear();
442 template <
typename Key,
typename Val,
typename Alloc >
443 INLINE
void HashTable< Key, Val, Alloc >::clear() {
449 for (Size i = Size(0); i < _size_; ++i)
452 _nb_elements_ = Size(0);
453 _begin_index_ = std::numeric_limits< Size >::max();
456 template <
typename Key,
typename Val,
typename Alloc >
457 INLINE HashTable< Key, Val, Alloc >::~HashTable() {
459 GUM_DESTRUCTOR(HashTable);
466 template <
typename Key,
typename Val,
typename Alloc >
467 HashTable< Key, Val, Alloc >&
468 HashTable< Key, Val, Alloc >::operator=(
const HashTable< Key, Val, Alloc >& from) {
472 GUM_OP_CPY(HashTable);
481 if (_size_ != from._size_) {
482 _nodes_.resize(from._size_);
484 for (Size i = Size(0); i < from._size_; ++i) {
485 _nodes_[i].setAllocator(_alloc_);
488 _size_ = from._size_;
492 _hash_func_.resize(_size_);
495 _resize_policy_ = from._resize_policy_;
496 _key_uniqueness_policy_ = from._key_uniqueness_policy_;
497 _begin_index_ = from._begin_index_;
506 template <
typename Key,
typename Val,
typename Alloc >
507 template <
typename OtherAlloc >
508 HashTable< Key, Val, Alloc >&
509 HashTable< Key, Val, Alloc >::operator=(
const HashTable< Key, Val, OtherAlloc >& from) {
511 if (
this !=
reinterpret_cast<
const HashTable< Key, Val, Alloc >* >(&from)) {
513 GUM_OP_CPY(HashTable);
522 if (_size_ != from._size_) {
523 _nodes_.resize(from._size_);
525 for (Size i = 0; i < from._size_; ++i) {
526 _nodes_[i].setAllocator(_alloc_);
529 _size_ = from._size_;
533 _hash_func_.resize(_size_);
536 _resize_policy_ = from._resize_policy_;
537 _key_uniqueness_policy_ = from._key_uniqueness_policy_;
538 _begin_index_ = from._begin_index_;
547 template <
typename Key,
typename Val,
typename Alloc >
548 HashTable< Key, Val, Alloc >&
549 HashTable< Key, Val, Alloc >::operator=(HashTable< Key, Val, Alloc >&& table) {
551 if (
this != &table) {
553 GUM_OP_MOV(HashTable);
559 _nodes_ = std::move(table._nodes_);
560 _safe_iterators_ = std::move(table._safe_iterators_);
561 _alloc_ = std::move(table._alloc_);
562 _size_ = table._size_;
563 _nb_elements_ = table._nb_elements_;
564 _hash_func_ = table._hash_func_;
565 _resize_policy_ = table._resize_policy_;
566 _key_uniqueness_policy_ = table._key_uniqueness_policy_;
567 _begin_index_ = table._begin_index_;
576 template <
typename Key,
typename Val,
typename Alloc >
577 INLINE
const typename HashTable< Key, Val, Alloc >::iterator&
578 HashTable< Key, Val, Alloc >::end()
noexcept {
582 return *(
reinterpret_cast<
const iterator* >(HashTableIteratorStaticEnd::_HashTableIterEnd_));
585 template <
typename Key,
typename Val,
typename Alloc >
586 INLINE
const typename HashTable< Key, Val, Alloc >::const_iterator&
587 HashTable< Key, Val, Alloc >::end()
const noexcept {
592 reinterpret_cast<
const const_iterator* >(HashTableIteratorStaticEnd::_HashTableIterEnd_));
595 template <
typename Key,
typename Val,
typename Alloc >
596 INLINE
const typename HashTable< Key, Val, Alloc >::const_iterator&
597 HashTable< Key, Val, Alloc >::cend()
const noexcept {
602 reinterpret_cast<
const const_iterator* >(HashTableIteratorStaticEnd::_HashTableIterEnd_));
605 template <
typename Key,
typename Val,
typename Alloc >
606 INLINE
typename HashTable< Key, Val, Alloc >::iterator HashTable< Key, Val, Alloc >::begin() {
608 if (_nb_elements_ == Size(0))
609 return iterator{end()};
611 return iterator{*
this};
614 template <
typename Key,
typename Val,
typename Alloc >
615 INLINE
typename HashTable< Key, Val, Alloc >::const_iterator
616 HashTable< Key, Val, Alloc >::begin()
const {
618 if (_nb_elements_ == Size(0))
619 return const_iterator{end()};
621 return const_iterator{*
this};
624 template <
typename Key,
typename Val,
typename Alloc >
625 INLINE
typename HashTable< Key, Val, Alloc >::const_iterator
626 HashTable< Key, Val, Alloc >::cbegin()
const {
628 if (_nb_elements_ == Size(0))
629 return const_iterator{cend()};
631 return const_iterator{*
this};
634 template <
typename Key,
typename Val,
typename Alloc >
635 INLINE
const typename HashTable< Key, Val, Alloc >::iterator_safe&
636 HashTable< Key, Val, Alloc >::endSafe()
noexcept {
640 return *(
reinterpret_cast<
const iterator_safe* >(
641 HashTableIteratorStaticEnd::_HashTableIterEndSafe_));
644 template <
typename Key,
typename Val,
typename Alloc >
645 INLINE
const typename HashTable< Key, Val, Alloc >::const_iterator_safe&
646 HashTable< Key, Val, Alloc >::endSafe()
const noexcept {
650 return *(
reinterpret_cast<
const const_iterator_safe* >(
651 HashTableIteratorStaticEnd::_HashTableIterEndSafe_));
654 template <
typename Key,
typename Val,
typename Alloc >
655 INLINE
const typename HashTable< Key, Val, Alloc >::const_iterator_safe&
656 HashTable< Key, Val, Alloc >::cendSafe()
const noexcept {
660 return *(
reinterpret_cast<
const const_iterator_safe* >(
661 HashTableIteratorStaticEnd::_HashTableIterEndSafe_));
664 template <
typename Key,
typename Val,
typename Alloc >
665 INLINE
typename HashTable< Key, Val, Alloc >::iterator_safe
666 HashTable< Key, Val, Alloc >::beginSafe() {
668 if (_nb_elements_ == Size(0))
669 return iterator_safe{endSafe()};
671 return iterator_safe{*
this};
674 template <
typename Key,
typename Val,
typename Alloc >
675 INLINE
typename HashTable< Key, Val, Alloc >::const_iterator_safe
676 HashTable< Key, Val, Alloc >::beginSafe()
const {
678 if (_nb_elements_ == Size(0))
679 return const_iterator_safe{endSafe()};
681 return const_iterator_safe{*
this};
684 template <
typename Key,
typename Val,
typename Alloc >
685 INLINE
typename HashTable< Key, Val, Alloc >::const_iterator_safe
686 HashTable< Key, Val, Alloc >::cbeginSafe()
const {
688 if (_nb_elements_ == Size(0))
689 return const_iterator_safe{cendSafe()};
691 return const_iterator_safe{*
this};
694 template <
typename Key,
typename Val,
typename Alloc >
695 INLINE Val& HashTable< Key, Val, Alloc >::operator[](
const Key& key) {
696 return _nodes_[_hash_func_(key)][key];
699 template <
typename Key,
typename Val,
typename Alloc >
700 INLINE
const Val& HashTable< Key, Val, Alloc >::operator[](
const Key& key)
const {
701 return _nodes_[_hash_func_(key)][key];
704 template <
typename Key,
typename Val,
typename Alloc >
705 INLINE Size HashTable< Key, Val, Alloc >::size()
const noexcept {
706 return _nb_elements_;
709 template <
typename Key,
typename Val,
typename Alloc >
710 INLINE Size HashTable< Key, Val, Alloc >::capacity()
const noexcept {
714 template <
typename Key,
typename Val,
typename Alloc >
715 INLINE
bool HashTable< Key, Val, Alloc >::exists(
const Key& key)
const {
716 return _nodes_[_hash_func_(key)].exists(key);
719 template <
typename Key,
typename Val,
typename Alloc >
720 INLINE
void HashTable< Key, Val, Alloc >::setResizePolicy(
const bool new_policy)
noexcept {
721 _resize_policy_ = new_policy;
724 template <
typename Key,
typename Val,
typename Alloc >
725 INLINE
bool HashTable< Key, Val, Alloc >::resizePolicy()
const noexcept {
726 return _resize_policy_;
729 template <
typename Key,
typename Val,
typename Alloc >
730 INLINE
void HashTable< Key, Val, Alloc >::setKeyUniquenessPolicy(
const bool new_policy)
noexcept {
731 _key_uniqueness_policy_ = new_policy;
734 template <
typename Key,
typename Val,
typename Alloc >
735 INLINE
bool HashTable< Key, Val, Alloc >::keyUniquenessPolicy()
const noexcept {
736 return _key_uniqueness_policy_;
739 template <
typename Key,
typename Val,
typename Alloc >
740 void HashTable< Key, Val, Alloc >::resize(Size new_size) {
742 new_size = std::max(Size(2), new_size);
746 int log_size = _hashTableLog2_(new_size);
747 new_size = Size(1) << log_size;
752 if (new_size != _size_) {
756 || (_nb_elements_ <= new_size * HashTableConst::default_mean_val_by_slot)) {
758 std::vector< HashTableList< Key, Val, Alloc > > new_nodes(new_size);
760 for (
auto& list: new_nodes) {
761 list.setAllocator(_alloc_);
765 _hash_func_.resize(new_size);
771 for (Size i = Size(0); i < _size_; ++i) {
772 while ((bucket = _nodes_[i]._deb_list_) !=
nullptr) {
774 new_hashed_key = _hash_func_(bucket->key());
778 _nodes_[i]._deb_list_ = bucket->next;
781 new_nodes[new_hashed_key].insert(bucket);
787 _begin_index_ = std::numeric_limits< Size >::max();
790 std::swap(_nodes_, new_nodes);
793 for (
auto iter: _safe_iterators_) {
795 iter->_index_ = _hash_func_(iter->_bucket_->key());
797 iter->_next_bucket_ =
nullptr;
805 template <
typename Key,
typename Val,
typename Alloc >
806 void HashTable< Key, Val, Alloc >::_insert_(HashTableBucket< Key, Val >* bucket) {
807 Size hash_key = _hash_func_(bucket->key());
810 if (_key_uniqueness_policy_ && _nodes_[hash_key].exists(bucket->key())) {
812 Key k = bucket->key();
813 _alloc_.destroy(bucket);
814 _alloc_.deallocate(bucket, 1);
815 GUM_ERROR(DuplicateElement,
816 "the hashtable contains an element with the same key (" << k <<
")");
821 if (_resize_policy_ && (_nb_elements_ >= _size_ * HashTableConst::default_mean_val_by_slot)) {
823 hash_key = _hash_func_(bucket->key());
827 _nodes_[hash_key].insert(bucket);
835 if (_begin_index_ < hash_key) { _begin_index_ = hash_key; }
838 template <
typename Key,
typename Val,
typename Alloc >
839 INLINE
typename HashTable< Key, Val, Alloc >::value_type&
840 HashTable< Key, Val, Alloc >::insert(
const Key& thekey,
const Val& theval) {
841 Bucket* bucket = _alloc_.allocate(1);
844 _alloc_.construct(bucket, thekey, theval);
846 _alloc_.deallocate(bucket, 1);
851 return bucket->elt();
854 template <
typename Key,
typename Val,
typename Alloc >
855 INLINE
typename HashTable< Key, Val, Alloc >::value_type&
856 HashTable< Key, Val, Alloc >::insert(Key&& thekey, Val&& theval) {
857 Bucket* bucket = _alloc_.allocate(1);
860 _alloc_.construct(bucket, std::move(thekey), std::move(theval));
862 _alloc_.deallocate(bucket, 1);
867 return bucket->elt();
870 template <
typename Key,
typename Val,
typename Alloc >
871 INLINE
typename HashTable< Key, Val, Alloc >::value_type&
872 HashTable< Key, Val, Alloc >::insert(
const std::pair< Key, Val >& elt) {
873 Bucket* bucket = _alloc_.allocate(1);
876 _alloc_.construct(bucket,
reinterpret_cast<
const value_type& >(elt));
878 _alloc_.deallocate(bucket, 1);
883 return bucket->elt();
886 template <
typename Key,
typename Val,
typename Alloc >
887 INLINE
typename HashTable< Key, Val, Alloc >::value_type&
888 HashTable< Key, Val, Alloc >::insert(std::pair< Key, Val >&& elt) {
889 Bucket* bucket = _alloc_.allocate(1);
892 _alloc_.construct(bucket, std::move(
reinterpret_cast< value_type& >(elt)));
894 _alloc_.deallocate(bucket, 1);
899 return bucket->elt();
902 template <
typename Key,
typename Val,
typename Alloc >
903 template <
typename... Args >
904 INLINE
typename HashTable< Key, Val, Alloc >::value_type&
905 HashTable< Key, Val, Alloc >::emplace(Args&&... args) {
906 Bucket* bucket = _alloc_.allocate(1);
909 _alloc_.construct(bucket,
910 HashTableBucket< Key, Val >::Emplace::EMPLACE,
911 std::forward< Args >(args)...);
913 _alloc_.deallocate(bucket, 1);
918 return bucket->elt();
921 template <
typename Key,
typename Val,
typename Alloc >
922 INLINE
typename HashTable< Key, Val, Alloc >::mapped_type&
923 HashTable< Key, Val, Alloc >::getWithDefault(
const Key& key,
const Val& default_value) {
924 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
926 if (bucket ==
nullptr)
927 return insert(key, default_value).second;
929 return bucket->val();
932 template <
typename Key,
typename Val,
typename Alloc >
933 INLINE
typename HashTable< Key, Val, Alloc >::mapped_type&
934 HashTable< Key, Val, Alloc >::getWithDefault(Key&& key, Val&& default_value) {
935 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
937 if (bucket ==
nullptr)
938 return insert(std::move(key), std::move(default_value)).second;
940 return bucket->val();
943 template <
typename Key,
typename Val,
typename Alloc >
944 INLINE
void HashTable< Key, Val, Alloc >::set(
const Key& key,
const Val& value) {
945 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
947 if (bucket ==
nullptr)
950 bucket->val() = value;
953 template <
typename Key,
typename Val,
typename Alloc >
954 void HashTable< Key, Val, Alloc >::_erase_(HashTableBucket< Key, Val >* bucket, Size index) {
955 if (bucket ==
nullptr)
return;
958 for (
auto iter: _safe_iterators_) {
959 if (iter->_bucket_ == bucket) {
961 iter->_next_bucket_ = iter->_bucket_;
962 iter->_bucket_ =
nullptr;
963 }
else if (iter->_next_bucket_ == bucket) {
964 iter->_bucket_ = bucket;
966 iter->_next_bucket_ = iter->_bucket_;
967 iter->_bucket_ =
nullptr;
972 _nodes_[index].erase(bucket);
976 if ((index == _begin_index_) && _nodes_[index].empty()) {
977 _begin_index_ = std::numeric_limits< Size >::max();
981 template <
typename Key,
typename Val,
typename Alloc >
982 INLINE
void HashTable< Key, Val, Alloc >::erase(
const Key& key) {
984 Size hash = _hash_func_(key);
987 HashTableBucket< Key, Val >* bucket = _nodes_[hash].bucket(key);
989 _erase_(bucket, hash);
992 template <
typename Key,
typename Val,
typename Alloc >
993 INLINE
void HashTable< Key, Val, Alloc >::erase(
const iterator_safe& iter) {
994 _erase_(iter._getBucket_(), iter._getIndex_());
997 template <
typename Key,
typename Val,
typename Alloc >
998 INLINE
void HashTable< Key, Val, Alloc >::erase(
const const_iterator_safe& iter) {
999 _erase_(iter._getBucket_(), iter._getIndex_());
1002 template <
typename Key,
typename Val,
typename Alloc >
1003 INLINE
void HashTable< Key, Val, Alloc >::eraseByVal(
const Val& val) {
1004 for (
auto iter = cbegin(); iter != cend(); ++iter)
1005 if (iter._bucket_->val() == val) {
1006 _erase_(iter._getBucket_(), iter._getIndex_());
1011 template <
typename Key,
typename Val,
typename Alloc >
1012 INLINE
void HashTable< Key, Val, Alloc >::reset(
const Key& key) {
1016 template <
typename Key,
typename Val,
typename Alloc >
1017 INLINE
const Key& HashTable< Key, Val, Alloc >::keyByVal(
const Val& val)
const {
1018 for (
auto iter = begin(); iter != end(); ++iter)
1019 if (iter._bucket_->val() == val)
return iter.key();
1021 GUM_ERROR(NotFound,
"not enough elements in the chained list")
1024 template <
typename Key,
typename Val,
typename Alloc >
1025 INLINE
const Key& HashTable< Key, Val, Alloc >::key(
const Key& key)
const {
1027 Bucket* bucket = _nodes_[_hash_func_(key)].bucket(key);
1029 if (bucket ==
nullptr) { GUM_ERROR(NotFound,
"key does not belong to the hashtable") }
1031 return bucket->key();
1034 template <
typename Key,
typename Val,
typename Alloc >
1035 void HashTable< Key, Val, Alloc >::eraseAllVal(
const Val& val) {
1036 for (
auto iterAll = cbeginSafe(); iterAll != cendSafe(); ++iterAll) {
1037 if (iterAll._bucket_->val() == val) { _erase_(iterAll._bucket_, iterAll._index_); }
1041 template <
typename Key,
typename Val,
typename Alloc >
1042 INLINE
bool HashTable< Key, Val, Alloc >::empty()
const noexcept {
1043 return (_nb_elements_ == Size(0));
1046 template <
typename Key,
typename Val,
typename Alloc >
1047 template <
typename Mount,
typename OtherAlloc >
1048 HashTable< Key, Mount, OtherAlloc >
1049 INLINE HashTable< Key, Val, Alloc >::map(Mount (*f)(Val),
1052 bool key_uniqueness_pol)
const {
1057 if (size == 0) size = std::max(Size(2), _nb_elements_ / 2);
1060 HashTable< Key, Mount, OtherAlloc > table(size, resize_pol, key_uniqueness_pol);
1063 for (
auto iter = begin(); iter != end(); ++iter) {
1064 table.insert(iter.key(), f(iter.val()));
1070 template <
typename Key,
typename Val,
typename Alloc >
1071 template <
typename Mount,
typename OtherAlloc >
1072 HashTable< Key, Mount, OtherAlloc >
1073 INLINE HashTable< Key, Val, Alloc >::map(Mount (*f)(Val&),
1076 bool key_uniqueness_pol)
const {
1081 if (size == Size(0)) size = std::max(Size(2), _nb_elements_ / 2);
1084 HashTable< Key, Mount, OtherAlloc > table(size, resize_pol, key_uniqueness_pol);
1087 for (
auto iter = begin(); iter != end(); ++iter) {
1088 table.insert(iter.key(), f(
const_cast< Val& >(iter.val())));
1094 template <
typename Key,
typename Val,
typename Alloc >
1095 template <
typename Mount,
typename OtherAlloc >
1096 HashTable< Key, Mount, OtherAlloc >
1097 INLINE HashTable< Key, Val, Alloc >::map(Mount (*f)(
const Val&),
1100 bool key_uniqueness_pol)
const {
1105 if (size == Size(0)) size = std::max(Size(2), _nb_elements_ / 2);
1108 HashTable< Key, Mount, OtherAlloc > table(size, resize_pol, key_uniqueness_pol);
1111 for (
auto iter = begin(); iter != end(); ++iter) {
1112 table.insert(iter.key(), f(iter.val()));
1118 template <
typename Key,
typename Val,
typename Alloc >
1119 template <
typename Mount,
typename OtherAlloc >
1120 HashTable< Key, Mount, OtherAlloc >
1121 INLINE HashTable< Key, Val, Alloc >::map(
const Mount& val,
1124 bool key_uniqueness_pol)
const {
1129 if (size == Size(0)) size = std::max(Size(2), _nb_elements_ / 2);
1132 HashTable< Key, Mount, OtherAlloc > table(size, resize_pol, key_uniqueness_pol);
1135 for (
auto iter = begin(); iter != end(); ++iter) {
1136 table.insert(iter.key(), val);
1142 template <
typename Key,
typename Val,
typename Alloc >
1143 template <
typename OtherAlloc >
1145 HashTable< Key, Val, Alloc >::operator==(
const HashTable< Key, Val, OtherAlloc >& from)
const {
1147 if (from._nb_elements_ != _nb_elements_)
return false;
1150 for (
auto iter = begin(); iter != end(); ++iter) {
1152 if (iter.val() != from[iter.key()])
return false;
1153 }
catch (NotFound&) {
return false; }
1159 template <
typename Key,
typename Val,
typename Alloc >
1160 template <
typename OtherAlloc >
1162 HashTable< Key, Val, Alloc >::operator!=(
const HashTable< Key, Val, OtherAlloc >& from)
const {
1163 return !operator==(from);
1166 template <
typename Key,
typename Val,
typename Alloc >
1167 std::ostream& operator<<(std::ostream& stream,
const HashTableList< Key, Val, Alloc >& list) {
1171 for (HashTableBucket< Key, Val >* ptr = list._deb_list_; ptr;
1172 ptr = ptr->list.next, deja =
true) {
1173 if (deja) stream <<
" , ";
1175 stream << ptr->key() <<
"=>" << ptr->val();
1183 template <
typename Key,
typename Val,
typename Alloc >
1184 std::ostream& operator<<(std::ostream& stream,
const HashTableList< Key*, Val, Alloc >& list) {
1188 for (HashTableBucket< Key, Val >* ptr = list._deb_list_; ptr;
1189 ptr = ptr->list.next, deja =
true) {
1190 if (deja) stream <<
" , ";
1192 stream << ptr->key() <<
"=>" << ptr->val();
1200 template <
typename Key,
typename Val,
typename Alloc >
1201 std::ostream& operator<<(std::ostream& stream,
const HashTable< Key, Val, Alloc >& table) {
1205 for (Size i = Size(0); i < table._size_; ++i)
1206 for (
auto ptr = table._nodes_[i]._deb_list_; ptr; ptr = ptr->next) {
1207 if (deja) stream <<
" , ";
1209 stream << ptr->key() <<
"=>" << ptr->val();
1219 template <
typename Key,
typename Val,
typename Alloc >
1220 std::ostream& operator<<(std::ostream& stream,
const HashTable< Key*, Val, Alloc >& table) {
1224 for (Size i = Size(0); i < table._size_; ++i)
1225 for (
auto ptr = table._nodes_[i]._deb_list_; ptr; ptr = ptr->next) {
1226 if (deja) stream <<
" , ";
1228 stream << ptr->key() <<
"=>" << ptr->val();
1242 template <
typename Key,
typename Val >
1243 INLINE
void HashTableConstIteratorSafe< Key, Val >::_insertIntoSafeList_()
const {
1244 _table_->_safe_iterators_.push_back(
1245 const_cast< HashTableConstIteratorSafe< Key, Val >* >(
this));
1248 template <
typename Key,
typename Val >
1249 INLINE
void HashTableConstIteratorSafe< Key, Val >::_removeFromSafeList_()
const {
1250 if (_table_ ==
nullptr)
return;
1253 std::vector< HashTableConstIteratorSafe< Key, Val >* >& iter_vect = _table_->_safe_iterators_;
1255 auto len = iter_vect.size();
1256 for (Size i = Size(0); i < len; ++i) {
1257 if (iter_vect[i] ==
this) {
1258 iter_vect.erase(iter_vect.begin() + i);
1264 template <
typename Key,
typename Val >
1265 INLINE HashTableConstIteratorSafe< Key, Val >::HashTableConstIteratorSafe() {
1267 GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1270 template <
typename Key,
typename Val >
1271 template <
typename Alloc >
1272 INLINE HashTableConstIteratorSafe< Key, Val >::HashTableConstIteratorSafe(
1273 const HashTable< Key, Val, Alloc >& tab) :
1274 _table_{
reinterpret_cast<
const HashTable< Key, Val >* >(&tab)} {
1276 GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1279 _insertIntoSafeList_();
1281 if (_table_->_nb_elements_) {
1282 if (_table_->_begin_index_ != std::numeric_limits< Size >::max()) {
1283 _index_ = _table_->_begin_index_;
1284 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1287 for (Size i = _table_->_size_ - Size(1);; --i) {
1289 if (_table_->_nodes_[i]._nb_elements_) {
1291 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1292 _table_->_begin_index_ = _index_;
1300 template <
typename Key,
typename Val >
1301 template <
typename Alloc >
1302 HashTableConstIteratorSafe< Key, Val >::HashTableConstIteratorSafe(
1303 const HashTable< Key, Val, Alloc >& tab,
1305 _table_{
reinterpret_cast<
const HashTable< Key, Val >* >(&tab)} {
1309 if ((ind_elt == Size(0)) && (_table_->_begin_index_ != std::numeric_limits< Size >::max())) {
1310 _index_ = _table_->_begin_index_;
1311 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1315 if (ind_elt < (_table_->_nb_elements_ >> 1)) {
1317 for (i = _table_->_size_ - 1;; --i) {
1319 if (_table_->_nodes_[i]._nb_elements_) {
1320 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1321 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1323 for (_bucket_ = _table_->_nodes_[i]._end_list_; ind_elt;
1324 --ind_elt, _bucket_ = _bucket_->prev) {}
1334 if (ind_elt >= _table_->_nb_elements_) {
1335 GUM_ERROR(UndefinedIteratorValue,
"Not enough elements in the hashtable")
1339 for (i = 0, ind_elt = _table_->_nb_elements_ - ind_elt - 1;; ++i) {
1340 if (_table_->_nodes_[i]._nb_elements_) {
1341 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1342 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1344 for (_bucket_ = _table_->_nodes_[i]._deb_list_; ind_elt;
1345 --ind_elt, _bucket_ = _bucket_->next) {}
1356 GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1359 _insertIntoSafeList_();
1362 template <
typename Key,
typename Val >
1363 INLINE HashTableConstIteratorSafe< Key, Val >::HashTableConstIteratorSafe(
1364 const HashTableConstIteratorSafe< Key, Val >& from) :
1365 _table_{from._table_},
1366 _index_{from._index_}, _bucket_{from._bucket_}, _next_bucket_{from._next_bucket_} {
1368 if (_table_ !=
nullptr) { _insertIntoSafeList_(); }
1371 GUM_CONS_CPY(HashTableConstIteratorSafe);
1374 template <
typename Key,
typename Val >
1375 INLINE HashTableConstIteratorSafe< Key, Val >::HashTableConstIteratorSafe(
1376 const HashTableConstIterator< Key, Val >& from) :
1377 _table_{from._table_},
1378 _index_{from._index_}, _bucket_{from._bucket_} {
1380 if (_table_ !=
nullptr) { _insertIntoSafeList_(); }
1383 GUM_CONS_CPY(HashTableConstIteratorSafe);
1386 template <
typename Key,
typename Val >
1387 INLINE HashTableConstIteratorSafe< Key, Val >::HashTableConstIteratorSafe(
1388 HashTableConstIteratorSafe< Key, Val >&& from) :
1389 _table_{from._table_},
1390 _index_{from._index_}, _bucket_{from._bucket_}, _next_bucket_{from._next_bucket_} {
1391 GUM_CONS_MOV(HashTableConstIteratorSafe);
1395 if (_table_ !=
nullptr) {
1396 std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect = _table_->_safe_iterators_;
1398 for (
auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1399 if (*ptr == &from) {
1401 from._table_ =
nullptr;
1408 template <
typename Key,
typename Val >
1409 INLINE HashTableConstIteratorSafe< Key, Val >::~HashTableConstIteratorSafe()
noexcept {
1411 GUM_DESTRUCTOR(HashTableConstIteratorSafe);
1414 _removeFromSafeList_();
1417 template <
typename Key,
typename Val >
1418 HashTableConstIteratorSafe< Key, Val >& HashTableConstIteratorSafe< Key, Val >::operator=(
1419 const HashTableConstIteratorSafe< Key, Val >& from) {
1427 if (_table_ != from._table_) {
1429 _removeFromSafeList_();
1431 _table_ = from._table_;
1434 if (_table_) { _insertIntoSafeList_(); }
1437 _index_ = from._index_;
1438 _bucket_ = from._bucket_;
1439 _next_bucket_ = from._next_bucket_;
1444 template <
typename Key,
typename Val >
1445 HashTableConstIteratorSafe< Key, Val >& HashTableConstIteratorSafe< Key, Val >::operator=(
1446 const HashTableConstIterator< Key, Val >& from) {
1454 if (_table_ != from._table_) {
1456 _removeFromSafeList_();
1458 _table_ = from._table_;
1461 if (_table_) { _insertIntoSafeList_(); }
1464 _index_ = from._index_;
1465 _bucket_ = from._bucket_;
1466 _next_bucket_ =
nullptr;
1471 template <
typename Key,
typename Val >
1472 INLINE HashTableConstIteratorSafe< Key, Val >& HashTableConstIteratorSafe< Key, Val >::operator=(
1473 HashTableConstIteratorSafe< Key, Val >&& from)
noexcept {
1481 if (_table_ != from._table_) {
1483 _removeFromSafeList_();
1485 if (from._table_ !=
nullptr) {
1487 std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect
1488 = from._table_->_safe_iterators_;
1490 for (
auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1491 if (*ptr == &from) {
1498 _table_ = from._table_;
1499 from._table_ =
nullptr;
1502 _index_ = from._index_;
1503 _bucket_ = from._bucket_;
1504 _next_bucket_ = from._next_bucket_;
1509 template <
typename Key,
typename Val >
1510 INLINE
const typename HashTableConstIteratorSafe< Key, Val >::key_type&
1511 HashTableConstIteratorSafe< Key, Val >::key()
const {
1512 if (_bucket_ !=
nullptr)
1513 return _bucket_->key();
1515 GUM_ERROR(UndefinedIteratorValue,
"Accessing a nullptr object")
1519 template <
typename Key,
typename Val >
1520 INLINE
const typename HashTableConstIteratorSafe< Key, Val >::mapped_type&
1521 HashTableConstIteratorSafe< Key, Val >::val()
const {
1522 if (_bucket_ !=
nullptr)
1523 return _bucket_->val();
1525 GUM_ERROR(UndefinedIteratorValue,
"Accessing a nullptr object")
1529 template <
typename Key,
typename Val >
1530 INLINE
void HashTableConstIteratorSafe< Key, Val >::clear()
noexcept {
1532 _removeFromSafeList_();
1537 _next_bucket_ =
nullptr;
1543 template <
typename Key,
typename Val >
1544 HashTableConstIteratorSafe< Key, Val >&
1545 HashTableConstIteratorSafe< Key, Val >::operator++()
noexcept {
1547 if (_bucket_ ==
nullptr) {
1553 _bucket_ = _next_bucket_;
1554 _next_bucket_ =
nullptr;
1560 if (_bucket_->prev) {
1561 _bucket_ = _bucket_->prev;
1571 if (_index_ == Size(0)) {
1581 if (_index_ > Size(0)) {
1582 for (Size i = _index_ - Size(1); i > Size(0); --i) {
1583 if (_table_->_nodes_[i]._nb_elements_) {
1585 _bucket_ = _table_->_nodes_[i]._end_list_;
1591 if (_table_->_nodes_[0]._nb_elements_)
1592 _bucket_ = _table_->_nodes_[0]._end_list_;
1604 template <
typename Key,
typename Val >
1605 HashTableConstIteratorSafe< Key, Val >&
1606 HashTableConstIteratorSafe< Key, Val >::operator+=(Size nb)
noexcept {
1607 if ((nb == Size(0)) || (_table_ ==
nullptr))
return *
this;
1610 if (_bucket_ ==
nullptr) {
1616 _bucket_ = _next_bucket_;
1617 _next_bucket_ =
nullptr;
1623 for (; nb && _bucket_ !=
nullptr; --nb, _bucket_ = _bucket_->prev) {}
1625 if (_bucket_ !=
nullptr)
return *
this;
1631 for (; _index_ < _table_->_size_ && nb >= _table_->_nodes_[_index_]._nb_elements_;
1632 nb -= _table_->_nodes_[_index_]._nb_elements_, --_index_) {}
1638 if (_index_ >= _table_->_size_) {
1643 for (_bucket_ = _table_->_nodes_[_index_]._end_list_; nb; --nb, _bucket_ = _bucket_->prev) {}
1648 template <
typename Key,
typename Val >
1649 INLINE HashTableConstIteratorSafe< Key, Val >
1650 HashTableConstIteratorSafe< Key, Val >::operator+(Size nb)
const {
1651 return HashTableConstIteratorSafe< Key, Val >{*
this} += nb;
1654 template <
typename Key,
typename Val >
1655 INLINE
bool HashTableConstIteratorSafe< Key, Val >::operator!=(
1656 const HashTableConstIteratorSafe< Key, Val >& from)
const noexcept {
1657 return ((_bucket_ != from._bucket_) || (_index_ != from._index_));
1660 template <
typename Key,
typename Val >
1661 INLINE
bool HashTableConstIteratorSafe< Key, Val >::operator==(
1662 const HashTableConstIteratorSafe< Key, Val >& from)
const noexcept {
1663 return ((_bucket_ == from._bucket_) && (_index_ == from._index_));
1666 template <
typename Key,
typename Val >
1667 INLINE
const typename HashTableConstIteratorSafe< Key, Val >::value_type&
1668 HashTableConstIteratorSafe< Key, Val >::operator*()
const {
1670 return _bucket_->elt();
1672 GUM_ERROR(UndefinedIteratorValue,
"Accessing a nullptr object")
1676 template <
typename Key,
typename Val >
1677 INLINE HashTableBucket< Key, Val >*
1678 HashTableConstIteratorSafe< Key, Val >::_getBucket_()
const noexcept {
1682 template <
typename Key,
typename Val >
1683 INLINE Size HashTableConstIteratorSafe< Key, Val >::_getIndex_()
const noexcept {
1691 template <
typename Key,
typename Val >
1692 INLINE HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe() :
1693 HashTableConstIteratorSafe< Key, Val >() {
1694 GUM_CONSTRUCTOR(HashTableIteratorSafe);
1697 template <
typename Key,
typename Val >
1698 template <
typename Alloc >
1699 INLINE HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(
1700 const HashTable< Key, Val, Alloc >& tab) :
1701 HashTableConstIteratorSafe< Key, Val >(tab) {
1702 GUM_CONSTRUCTOR(HashTableIteratorSafe);
1705 template <
typename Key,
typename Val >
1706 template <
typename Alloc >
1707 INLINE HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(
1708 const HashTable< Key, Val, Alloc >& tab,
1710 HashTableConstIteratorSafe< Key, Val >(tab, ind_elt) {
1711 GUM_CONSTRUCTOR(HashTableIteratorSafe);
1714 template <
typename Key,
typename Val >
1715 INLINE HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(
1716 const HashTableIteratorSafe< Key, Val >& from) :
1717 HashTableConstIteratorSafe< Key, Val >(from) {
1718 GUM_CONS_CPY(HashTableIteratorSafe);
1721 template <
typename Key,
typename Val >
1722 INLINE HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(
1723 const HashTableIterator< Key, Val >& from) :
1724 HashTableConstIteratorSafe< Key, Val >(from) {
1725 GUM_CONS_CPY(HashTableIteratorSafe);
1728 template <
typename Key,
typename Val >
1729 INLINE HashTableIteratorSafe< Key, Val >::HashTableIteratorSafe(
1730 HashTableIteratorSafe< Key, Val >&& from)
noexcept :
1731 HashTableConstIteratorSafe< Key, Val >(std::move(from)) {
1732 GUM_CONS_MOV(HashTableIteratorSafe);
1735 template <
typename Key,
typename Val >
1736 INLINE HashTableIteratorSafe< Key, Val >::~HashTableIteratorSafe()
noexcept {
1737 GUM_DESTRUCTOR(HashTableIteratorSafe);
1740 template <
typename Key,
typename Val >
1741 INLINE
typename HashTableIteratorSafe< Key, Val >::mapped_type&
1742 HashTableIteratorSafe< Key, Val >::val() {
1743 return const_cast< Val& >(HashTableConstIteratorSafe< Key, Val >::val());
1746 template <
typename Key,
typename Val >
1747 INLINE HashTableIteratorSafe< Key, Val >&
1748 HashTableIteratorSafe< Key, Val >::operator=(
const HashTableIteratorSafe< Key, Val >& from) {
1749 GUM_OP_CPY(HashTableIteratorSafe);
1750 HashTableConstIteratorSafe< Key, Val >::operator=(from);
1754 template <
typename Key,
typename Val >
1755 INLINE HashTableIteratorSafe< Key, Val >&
1756 HashTableIteratorSafe< Key, Val >::operator=(
const HashTableIterator< Key, Val >& from) {
1757 GUM_OP_CPY(HashTableIteratorSafe);
1758 HashTableConstIteratorSafe< Key, Val >::operator=(from);
1762 template <
typename Key,
typename Val >
1763 INLINE HashTableIteratorSafe< Key, Val >& HashTableIteratorSafe< Key, Val >::operator=(
1764 HashTableIteratorSafe< Key, Val >&& from)
noexcept {
1765 HashTableConstIteratorSafe< Key, Val >::operator=(std::move(from));
1769 template <
typename Key,
typename Val >
1770 INLINE HashTableIteratorSafe< Key, Val >&
1771 HashTableIteratorSafe< Key, Val >::operator++()
noexcept {
1772 HashTableConstIteratorSafe< Key, Val >::operator++();
1776 template <
typename Key,
typename Val >
1777 INLINE HashTableIteratorSafe< Key, Val >&
1778 HashTableIteratorSafe< Key, Val >::operator+=(Size nb)
noexcept {
1779 HashTableConstIteratorSafe< Key, Val >::operator+=(nb);
1783 template <
typename Key,
typename Val >
1784 INLINE HashTableIteratorSafe< Key, Val >
1785 HashTableIteratorSafe< Key, Val >::operator+(Size nb)
const {
1786 HashTableIteratorSafe< Key, Val > iter{*
this};
1791 template <
typename Key,
typename Val >
1792 INLINE
bool HashTableIteratorSafe< Key, Val >::operator!=(
1793 const HashTableIteratorSafe< Key, Val >& from)
const noexcept {
1794 return HashTableConstIteratorSafe< Key, Val >::operator!=(from);
1797 template <
typename Key,
typename Val >
1798 INLINE
bool HashTableIteratorSafe< Key, Val >::operator==(
1799 const HashTableIteratorSafe< Key, Val >& from)
const noexcept {
1800 return HashTableConstIteratorSafe< Key, Val >::operator==(from);
1803 template <
typename Key,
typename Val >
1804 INLINE
typename HashTableIteratorSafe< Key, Val >::value_type&
1805 HashTableIteratorSafe< Key, Val >::operator*() {
1806 return const_cast< Val& >(HashTableConstIteratorSafe< Key, Val >::operator*());
1809 template <
typename Key,
typename Val >
1810 INLINE
const typename HashTableIteratorSafe< Key, Val >::value_type&
1811 HashTableIteratorSafe< Key, Val >::operator*()
const {
1812 return HashTableConstIteratorSafe< Key, Val >::operator*();
1819 template <
typename Key,
typename Val >
1820 INLINE HashTableConstIterator< Key, Val >::HashTableConstIterator()
noexcept {
1821 GUM_CONSTRUCTOR(HashTableConstIterator);
1824 template <
typename Key,
typename Val >
1825 template <
typename Alloc >
1826 INLINE HashTableConstIterator< Key, Val >::HashTableConstIterator(
1827 const HashTable< Key, Val, Alloc >& tab)
noexcept :
1828 _table_{
reinterpret_cast<
const HashTable< Key, Val >* >(&tab)} {
1830 GUM_CONSTRUCTOR(HashTableConstIterator);
1832 if (_table_->_nb_elements_) {
1833 if (_table_->_begin_index_ != std::numeric_limits< Size >::max()) {
1834 _index_ = _table_->_begin_index_;
1835 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1838 for (Size i = _table_->_size_ - Size(1);; --i) {
1840 if (_table_->_nodes_[i]._nb_elements_) {
1842 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1843 _table_->_begin_index_ = _index_;
1851 template <
typename Key,
typename Val >
1852 template <
typename Alloc >
1853 HashTableConstIterator< Key, Val >::HashTableConstIterator(
1854 const HashTable< Key, Val, Alloc >& tab,
1856 _table_{
reinterpret_cast<
const HashTable< Key, Val >* >(&tab)} {
1860 if ((ind_elt == Size(0)) && (_table_->_begin_index_ != std::numeric_limits< Size >::max())) {
1861 _index_ = _table_->_begin_index_;
1862 _bucket_ = _table_->_nodes_[_index_]._end_list_;
1866 if (ind_elt < (_table_->_nb_elements_ >> 1)) {
1868 for (i = _table_->_size_ - 1;; --i) {
1870 if (_table_->_nodes_[i]._nb_elements_) {
1871 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1872 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1874 for (_bucket_ = _table_->_nodes_[i]._end_list_; ind_elt;
1875 --ind_elt, _bucket_ = _bucket_->prev) {}
1885 if (ind_elt >= _table_->_nb_elements_) {
1886 GUM_ERROR(UndefinedIteratorValue,
"Not enough elements in the hashtable")
1890 for (i = 0, ind_elt = _table_->_nb_elements_ - ind_elt - 1;; ++i) {
1891 if (_table_->_nodes_[i]._nb_elements_) {
1892 if (ind_elt >= _table_->_nodes_[i]._nb_elements_)
1893 ind_elt -= _table_->_nodes_[i]._nb_elements_;
1895 for (_bucket_ = _table_->_nodes_[i]._deb_list_; ind_elt;
1896 --ind_elt, _bucket_ = _bucket_->next) {}
1907 GUM_CONSTRUCTOR(HashTableConstIterator);
1910 template <
typename Key,
typename Val >
1911 INLINE HashTableConstIterator< Key, Val >::HashTableConstIterator(
1912 const HashTableConstIterator< Key, Val >& from)
noexcept :
1913 _table_{from._table_},
1914 _index_{from._index_}, _bucket_{from._bucket_} {
1915 GUM_CONS_CPY(HashTableConstIterator);
1918 template <
typename Key,
typename Val >
1919 INLINE HashTableConstIterator< Key, Val >::HashTableConstIterator(
1920 HashTableConstIterator< Key, Val >&& from)
noexcept :
1921 _table_{from._table_},
1922 _index_{from._index_}, _bucket_{from._bucket_} {
1923 GUM_CONS_MOV(HashTableConstIterator);
1926 template <
typename Key,
typename Val >
1927 INLINE HashTableConstIterator< Key, Val >::~HashTableConstIterator()
noexcept {
1929 GUM_DESTRUCTOR(HashTableConstIterator);
1932 template <
typename Key,
typename Val >
1933 INLINE HashTableConstIterator< Key, Val >& HashTableConstIterator< Key, Val >::operator=(
1934 const HashTableConstIterator< Key, Val >& from)
noexcept {
1938 _table_ = from._table_;
1939 _index_ = from._index_;
1940 _bucket_ = from._bucket_;
1945 template <
typename Key,
typename Val >
1946 INLINE HashTableConstIterator< Key, Val >& HashTableConstIterator< Key, Val >::operator=(
1947 HashTableConstIterator< Key, Val >&& from)
noexcept {
1951 _table_ = from._table_;
1952 _index_ = from._index_;
1953 _bucket_ = from._bucket_;
1958 template <
typename Key,
typename Val >
1959 INLINE
const typename HashTableConstIterator< Key, Val >::key_type&
1960 HashTableConstIterator< Key, Val >::key()
const {
1962 return _bucket_->pair.first;
1964 GUM_ERROR(UndefinedIteratorValue,
"Accessing a nullptr object")
1968 template <
typename Key,
typename Val >
1969 INLINE
const typename HashTableConstIterator< Key, Val >::mapped_type&
1970 HashTableConstIterator< Key, Val >::val()
const {
1972 return _bucket_->val();
1974 GUM_ERROR(UndefinedIteratorValue,
"Accessing a nullptr object")
1978 template <
typename Key,
typename Val >
1979 INLINE
void HashTableConstIterator< Key, Val >::clear()
noexcept {
1985 template <
typename Key,
typename Val >
1986 HashTableConstIterator< Key, Val >& HashTableConstIterator< Key, Val >::operator++()
noexcept {
1988 if (_bucket_ ==
nullptr)
return *
this;
1992 if (_bucket_->prev) {
1993 _bucket_ = _bucket_->prev;
2002 if (_index_ == Size(0)) {
2012 for (Size i = _index_ - Size(1); i; --i) {
2013 if (_table_->_nodes_[i]._nb_elements_) {
2015 _bucket_ = _table_->_nodes_[i]._end_list_;
2020 if (_table_->_nodes_[0]._nb_elements_)
2021 _bucket_ = _table_->_nodes_[0]._end_list_;
2032 template <
typename Key,
typename Val >
2033 HashTableConstIterator< Key, Val >&
2034 HashTableConstIterator< Key, Val >::operator+=(Size nb)
noexcept {
2035 if ((nb == 0) || (_table_ ==
nullptr) || (_bucket_ ==
nullptr))
return *
this;
2039 for (; nb && _bucket_ !=
nullptr; --nb, _bucket_ = _bucket_->prev) {}
2041 if (_bucket_ !=
nullptr)
return *
this;
2047 for (; _index_ < _table_->_size_ && nb >= _table_->_nodes_[_index_]._nb_elements_;
2048 nb -= _table_->_nodes_[_index_]._nb_elements_, --_index_) {}
2054 if (_index_ >= _table_->_size_) {
2059 for (_bucket_ = _table_->_nodes_[_index_]._end_list_; nb; --nb, _bucket_ = _bucket_->prev) {}
2064 template <
typename Key,
typename Val >
2065 INLINE HashTableConstIterator< Key, Val >
2066 HashTableConstIterator< Key, Val >::operator+(Size nb)
const noexcept {
2067 return HashTableConstIterator< Key, Val >{*
this} += nb;
2070 template <
typename Key,
typename Val >
2071 INLINE
bool HashTableConstIterator< Key, Val >::operator!=(
2072 const HashTableConstIterator< Key, Val >& from)
const noexcept {
2073 return (_bucket_ != from._bucket_);
2076 template <
typename Key,
typename Val >
2077 INLINE
bool HashTableConstIterator< Key, Val >::operator==(
2078 const HashTableConstIterator< Key, Val >& from)
const noexcept {
2079 return (_bucket_ == from._bucket_);
2082 template <
typename Key,
typename Val >
2083 INLINE
const typename HashTableConstIterator< Key, Val >::value_type&
2084 HashTableConstIterator< Key, Val >::operator*()
const {
2086 return _bucket_->elt();
2088 GUM_ERROR(UndefinedIteratorValue,
"Accessing a nullptr object")
2092 template <
typename Key,
typename Val >
2093 INLINE
typename HashTable< Key, Val >::Bucket*
2094 HashTableConstIterator< Key, Val >::_getBucket_()
const noexcept {
2098 template <
typename Key,
typename Val >
2099 INLINE Size HashTableConstIterator< Key, Val >::_getIndex_()
const noexcept {
2107 template <
typename Key,
typename Val >
2108 INLINE HashTableIterator< Key, Val >::HashTableIterator()
noexcept :
2109 HashTableConstIterator< Key, Val >() {
2110 GUM_CONSTRUCTOR(HashTableIterator);
2113 template <
typename Key,
typename Val >
2114 template <
typename Alloc >
2115 INLINE HashTableIterator< Key, Val >::HashTableIterator(
2116 const HashTable< Key, Val, Alloc >& tab)
noexcept :
2117 HashTableConstIterator< Key, Val >(tab) {
2118 GUM_CONSTRUCTOR(HashTableIterator);
2121 template <
typename Key,
typename Val >
2122 template <
typename Alloc >
2123 INLINE HashTableIterator< Key, Val >::HashTableIterator(
const HashTable< Key, Val, Alloc >& tab,
2125 HashTableConstIterator< Key, Val >(tab, ind_elt) {
2126 GUM_CONSTRUCTOR(HashTableIterator);
2129 template <
typename Key,
typename Val >
2130 INLINE HashTableIterator< Key, Val >::HashTableIterator(
2131 const HashTableIterator< Key, Val >& from)
noexcept :
2132 HashTableConstIterator< Key, Val >(from) {
2133 GUM_CONS_CPY(HashTableIterator);
2136 template <
typename Key,
typename Val >
2138 HashTableIterator< Key, Val >::HashTableIterator(HashTableIterator< Key, Val >&& from)
noexcept 2140 HashTableConstIterator< Key, Val >(std::move(from)) {
2141 GUM_CONS_MOV(HashTableIterator);
2144 template <
typename Key,
typename Val >
2145 INLINE HashTableIterator< Key, Val >::~HashTableIterator()
noexcept {
2146 GUM_DESTRUCTOR(HashTableIterator);
2149 template <
typename Key,
typename Val >
2150 INLINE
typename HashTableIterator< Key, Val >::mapped_type& HashTableIterator< Key, Val >::val() {
2152 return this->_bucket_->val();
2154 GUM_ERROR(UndefinedIteratorValue,
"Accessing a nullptr object")
2158 template <
typename Key,
typename Val >
2159 INLINE HashTableIterator< Key, Val >&
2160 HashTableIterator< Key, Val >::operator=(
const HashTableIterator< Key, Val >& from)
noexcept {
2161 HashTableConstIterator< Key, Val >::operator=(from);
2165 template <
typename Key,
typename Val >
2166 INLINE HashTableIterator< Key, Val >&
2167 HashTableIterator< Key, Val >::operator=(HashTableIterator< Key, Val >&& from)
noexcept {
2168 HashTableConstIterator< Key, Val >::operator=(std::move(from));
2172 template <
typename Key,
typename Val >
2173 INLINE HashTableIterator< Key, Val >& HashTableIterator< Key, Val >::operator++()
noexcept {
2174 HashTableConstIterator< Key, Val >::operator++();
2178 template <
typename Key,
typename Val >
2179 INLINE HashTableIterator< Key, Val >&
2180 HashTableIterator< Key, Val >::operator+=(Size nb)
noexcept {
2181 HashTableConstIterator< Key, Val >::operator+=(nb);
2185 template <
typename Key,
typename Val >
2186 INLINE HashTableIterator< Key, Val >
2187 HashTableIterator< Key, Val >::operator+(Size nb)
const noexcept {
2188 HashTableIterator< Key, Val > iter{*
this};
2193 template <
typename Key,
typename Val >
2194 INLINE
bool HashTableIterator< Key, Val >::operator!=(
2195 const HashTableIterator< Key, Val >& from)
const noexcept {
2196 return HashTableConstIterator< Key, Val >::operator!=(from);
2199 template <
typename Key,
typename Val >
2200 INLINE
bool HashTableIterator< Key, Val >::operator==(
2201 const HashTableIterator< Key, Val >& from)
const noexcept {
2202 return HashTableConstIterator< Key, Val >::operator==(from);
2205 template <
typename Key,
typename Val >
2206 INLINE
typename HashTableIterator< Key, Val >::value_type&
2207 HashTableIterator< Key, Val >::operator*() {
2208 return const_cast< value_type& >(HashTableConstIterator< Key, Val >::operator*());
2211 template <
typename Key,
typename Val >
2212 INLINE
const typename HashTableIterator< Key, Val >::value_type&
2213 HashTableIterator< Key, Val >::operator*()
const {
2214 return HashTableConstIterator< Key, Val >::operator*();