aGrUM  0.16.0
hashTable_tpl.h
Go to the documentation of this file.
1 
29 #include <iostream>
30 #include <sstream>
31 #include <string>
32 
33 // to help IDE parser
34 #include <agrum/core/hashTable.h>
35 
36 namespace gum {
37 
38 
39  // ===========================================================================
40  // === IMPLEMENTATION OF THE CHAINED LISTS USED IN THE HASH TABLES ===
41  // ===========================================================================
42 
43  template < typename Key, typename Val, typename Alloc >
44  template < typename OtherAlloc >
47  Bucket *ptr, *old_ptr{nullptr}, *new_elt{nullptr};
48  // set the defaults
49  __deb_list = nullptr;
50 
51  // copy from's list
52  try {
53  for (ptr = from.__deb_list; ptr != nullptr; ptr = ptr->next) {
54  // copy the current from's bucket (may throw an exception either because
55  // new cannot allocate the bucket or because the copy constructor of Val
56  // throws an exception)
57  new_elt = __alloc_bucket->allocate(1);
58 
59  try {
60  __alloc_bucket->construct(new_elt, *ptr);
61  } catch (...) {
62  __alloc_bucket->deallocate(new_elt, 1);
63  throw;
64  }
65 
66  // rechain properly the new list
67  new_elt->prev = old_ptr;
68 
69  if (old_ptr != nullptr)
70  old_ptr->next = new_elt;
71  else
72  __deb_list = new_elt;
73 
74  old_ptr = new_elt;
75  }
76 
77  if (old_ptr != nullptr) old_ptr->next = nullptr;
78 
79  // update the number of elements stored into the list and the end of the
80  // list
81  __nb_elements = from.__nb_elements;
82  __end_list = new_elt;
83  } catch (...) {
84  // problem: we could not allocate an element in the list => we delete
85  // the elements created so far and we throw an exception
86  for (; __deb_list != nullptr; __deb_list = new_elt) {
87  new_elt = __deb_list->next;
88  __alloc_bucket->destroy(__deb_list);
89  __alloc_bucket->deallocate(__deb_list, 1);
90  }
91 
92  __nb_elements = 0;
93  __end_list = nullptr;
94 
95  throw;
96  }
97  }
98 
99  template < typename Key, typename Val, typename Alloc >
102  for (Bucket* ptr = __deb_list; ptr != nullptr; ptr = ptr->next)
103  if (ptr->key() == key) return ptr;
104 
105  return nullptr;
106  }
107 
108  template < typename Key, typename Val, typename Alloc >
109  INLINE void
111  // check that the pointer is not nullptr
112  if (ptr == nullptr) {
113  GUM_ERROR(NullElement, "trying to erase a nullptr bucket");
114  }
115 
116  // relink properly the doubly chained list
117  if (ptr->prev != nullptr)
118  ptr->prev->next = ptr->next;
119  else
120  __deb_list = ptr->next;
121 
122  if (ptr->next != nullptr)
123  ptr->next->prev = ptr->prev;
124  else
125  __end_list = ptr->prev;
126 
127  // remove the current element from the list
128  __alloc_bucket->destroy(ptr);
129  __alloc_bucket->deallocate(ptr, 1);
130 
131  --__nb_elements;
132  }
133 
134  template < typename Key, typename Val, typename Alloc >
137  allocator) noexcept :
138  __alloc_bucket{allocator} {}
139 
140  template < typename Key, typename Val, typename Alloc >
142  const HashTableList< Key, Val, Alloc >& from) :
143  __alloc_bucket{from.__alloc_bucket} {
144  __copy(from);
145  }
146 
147  template < typename Key, typename Val, typename Alloc >
149  HashTableList< Key, Val, Alloc >&& from) noexcept :
150  __deb_list{from.__deb_list},
151  __end_list{from.__end_list}, __nb_elements{from.__nb_elements},
152  __alloc_bucket{from.__alloc_bucket} {
153  from.__deb_list = nullptr;
154  }
155 
156  template < typename Key, typename Val, typename Alloc >
158  for (Bucket *next_ptr, *ptr = __deb_list; ptr != nullptr; ptr = next_ptr) {
159  next_ptr = ptr->next;
160  __alloc_bucket->destroy(ptr);
161  __alloc_bucket->deallocate(ptr, 1);
162  }
163  }
164 
165  template < typename Key, typename Val, typename Alloc >
167  for (Bucket *next_ptr, *ptr = __deb_list; ptr != nullptr; ptr = next_ptr) {
168  next_ptr = ptr->next;
169  __alloc_bucket->destroy(ptr);
170  __alloc_bucket->deallocate(ptr, 1);
171  }
172 
173  __nb_elements = Size(0);
174  __deb_list = nullptr;
175  __end_list = nullptr;
176  }
177 
178  template < typename Key, typename Val, typename Alloc >
181  // avoid self assignment
182  if (this != &from) {
183  clear();
184  __copy(from);
185  }
186 
187  return *this;
188  }
189 
190  template < typename Key, typename Val, typename Alloc >
191  template < typename OtherAlloc >
194  // avoid self assignment
195  if (this
196  != reinterpret_cast< const HashTableList< Key, Val, Alloc >* >(&from)) {
197  clear();
198  __copy(from);
199  }
200 
201  return *this;
202  }
203 
204  template < typename Key, typename Val, typename Alloc >
207  // avoid self assignment
208  if (this != &from) {
209  __deb_list = from.__deb_list;
210  __end_list = from.__end_list;
211  __nb_elements = from.__nb_elements;
212  from.__deb_list = nullptr;
213  }
214 
215  return *this;
216  }
217 
218  template < typename Key, typename Val, typename Alloc >
221  __alloc_bucket = &alloc;
222  }
223 
224  template < typename Key, typename Val, typename Alloc >
227  if (i >= __nb_elements) {
228  GUM_ERROR(NotFound, "not enough elements in the chained list");
229  }
230 
231  Bucket* ptr;
232 
233  for (ptr = __deb_list; i; --i, ptr = ptr->next) {}
234 
235  return ptr->elt();
236  }
237 
238  template < typename Key, typename Val, typename Alloc >
239  INLINE const typename HashTableList< Key, Val, Alloc >::value_type&
241  if (i >= __nb_elements) {
242  GUM_ERROR(NotFound, "not enough elements in the chained list");
243  }
244 
245  Bucket* ptr;
246 
247  for (ptr = __deb_list; i; --i, ptr = ptr->next) {}
248 
249  return ptr->elt();
250  }
251 
252  template < typename Key, typename Val, typename Alloc >
253  INLINE const typename HashTableList< Key, Val, Alloc >::mapped_type&
255  for (Bucket* ptr = __deb_list; ptr != nullptr; ptr = ptr->next)
256  if (ptr->key() == key) return ptr->val();
257 
259  "hashtable's chained list contains no element with this key <"
260  << key << ">");
261  }
262 
263  template < typename Key, typename Val, typename Alloc >
266  for (Bucket* ptr = __deb_list; ptr != nullptr; ptr = ptr->next)
267  if (ptr->key() == key) return ptr->val();
268 
270  "hashtable's chained list contains no element with this key <"
271  << key << ">");
272  }
273 
274  template < typename Key, typename Val, typename Alloc >
275  INLINE bool HashTableList< Key, Val, Alloc >::exists(const Key& key) const {
276  for (Bucket* ptr = __deb_list; ptr != nullptr; ptr = ptr->next) {
277  if (ptr->key() == key) { return true; }
278  }
279 
280  return false;
281  }
282 
283  template < typename Key, typename Val, typename Alloc >
284  INLINE bool HashTableList< Key, Val, Alloc >::empty() const noexcept {
285  return (__nb_elements == Size(0));
286  }
287 
288  template < typename Key, typename Val, typename Alloc >
290  HashTableBucket< Key, Val >* new_elt) noexcept {
291  // place the bucket at the beginning of the list
292  new_elt->prev = nullptr;
293  new_elt->next = __deb_list;
294 
295  if (__deb_list != nullptr)
296  __deb_list->prev = new_elt;
297  else
298  __end_list = new_elt;
299 
300  __deb_list = new_elt;
301 
302  ++__nb_elements;
303  }
304 
305  // ===========================================================================
306  // === GENERIC HASH TABLE IMPLEMENTATION ===
307  // ===========================================================================
308 
309  template < typename Key, typename Val, typename Alloc >
310  template < typename OtherAlloc >
312  const HashTable< Key, Val, OtherAlloc >& table) {
313  // in debug mode, check that this and table have '__nodes' arrays of the
314  // same size
315  GUM_ASSERT(table.__size == __size);
316 
317  // try to fill the array of chained lists
318  for (Size i = 0; i < table.__size; ++i) {
319  try {
320  __nodes[i] = table.__nodes[i];
321  } catch (...) {
322  // here we could allocate the __nodes[j], j=0..i-1, so we should
323  // deallocate them
324  for (Size j = 0; j < __size; ++j)
325  __nodes[j].clear();
326 
327  __nb_elements = Size(0);
328 
329  // propagate the exception
330  throw;
331  }
332  }
333 
334  __nb_elements = table.__nb_elements;
335  }
336 
337  template < typename Key, typename Val, typename Alloc >
338  INLINE const typename HashTable< Key, Val, Alloc >::iterator&
340  return *(reinterpret_cast< const iterator* >(
341  HashTableIteratorStaticEnd::end4Statics()));
342  }
343 
344  template < typename Key, typename Val, typename Alloc >
345  INLINE const typename HashTable< Key, Val, Alloc >::const_iterator&
347  return *(reinterpret_cast< const const_iterator* >(
348  HashTableIteratorStaticEnd::constEnd4Statics()));
349  }
350 
351  template < typename Key, typename Val, typename Alloc >
352  INLINE const typename HashTable< Key, Val, Alloc >::iterator_safe&
354  return *(reinterpret_cast< const iterator_safe* >(
355  HashTableIteratorStaticEnd::endSafe4Statics()));
356  }
357 
358  template < typename Key, typename Val, typename Alloc >
361  return *(reinterpret_cast< const const_iterator_safe* >(
362  HashTableIteratorStaticEnd::constEndSafe4Statics()));
363  }
364 
365  template < typename Key, typename Val, typename Alloc >
367  // setup the __nodes vector (contains only empty lists)
368  __nodes.resize(size);
369 
370  for (auto& list : __nodes) {
371  list.setAllocator(__alloc);
372  }
373 
374  // set up properly the hash function
375  __hash_func.resize(size);
376 
377  // make sure the end() iterator is constructed properly
378  end4Statics();
379  endSafe4Statics();
380  }
381 
382  template < typename Key, typename Val, typename Alloc >
384  bool resize_pol,
385  bool key_uniqueness_pol) :
386  // size must be >= 2 else we lose all the bits of the hash function
387  __size{Size(1) << __hashTableLog2(std::max(Size(2), size_param))},
388  __resize_policy{resize_pol}, __key_uniqueness_policy{key_uniqueness_pol} {
389  // for debugging purposes
390  GUM_CONSTRUCTOR(HashTable);
391 
392  // finalize the creation
393  __create(__size);
394  }
395 
396  template < typename Key, typename Val, typename Alloc >
398  std::initializer_list< std::pair< Key, Val > > list) :
399  // size must be >= 2 else we lose all the bits of the hash function
400  __size{Size(1) << __hashTableLog2(
401  std::max< Size >(Size(2), Size(list.size()) / 2))} {
402  // for debugging purposes
403  GUM_CONSTRUCTOR(HashTable);
404 
405  // setup the __nodes vector (contains only empty lists)
406  __create(__size);
407 
408  // insert all the elements
409  for (const auto& elt : list) {
410  insert(elt);
411  }
412  }
413 
414  template < typename Key, typename Val, typename Alloc >
416  const HashTable< Key, Val, Alloc >& table) :
417  __size{table.__size},
418  __resize_policy{table.__resize_policy},
419  __key_uniqueness_policy{table.__key_uniqueness_policy},
420  __begin_index{table.__begin_index} {
421  // for debugging purposes
422  GUM_CONS_CPY(HashTable);
423 
424  // setup the __nodes vector (contains only empty lists)
425  __create(__size);
426 
427  // fill with the content of table
428  __copy(table);
429  }
430 
431  template < typename Key, typename Val, typename Alloc >
432  template < typename OtherAlloc >
434  const HashTable< Key, Val, OtherAlloc >& table) :
435  __size{table.__size},
436  __resize_policy{table.__resize_policy},
437  __key_uniqueness_policy{table.__key_uniqueness_policy},
438  __begin_index{table.__begin_index} {
439  // for debugging purposes
440  GUM_CONS_CPY(HashTable);
441 
442  // setup the __nodes vector (contains only empty lists)
443  __create(__size);
444 
445  // fill with the content of table
446  __copy(table);
447  }
448 
449  template < typename Key, typename Val, typename Alloc >
451  __nodes(std::move(table.__nodes)), __size{table.__size},
452  __nb_elements{table.__nb_elements}, __hash_func{table.__hash_func},
453  __resize_policy{table.__resize_policy},
454  __key_uniqueness_policy{table.__key_uniqueness_policy},
455  __begin_index{table.__begin_index},
456  __safe_iterators(std::move(table.__safe_iterators)),
457  __alloc(std::move(table.__alloc)) {
458  // for debugging purposes
459  table.__size = 0;
460  GUM_CONS_MOV(HashTable);
461  }
462 
463  template < typename Key, typename Val, typename Alloc >
465  const Size len = __safe_iterators.size();
466  for (Size i = Size(0); i < len; ++i)
467  __safe_iterators[i]->clear();
468  }
469 
470  template < typename Key, typename Val, typename Alloc >
472  // update all the registered iterators: they should now point to nullptr
473  // and they are positioned to the end of the hashtable.
474  __clearIterators();
475 
476  // remove the buckets
477  for (Size i = Size(0); i < __size; ++i)
478  __nodes[i].clear();
479 
480  __nb_elements = Size(0);
481  __begin_index = std::numeric_limits< Size >::max();
482  }
483 
484  template < typename Key, typename Val, typename Alloc >
486  // for debugging purposes
487  GUM_DESTRUCTOR(HashTable);
488 
489  // update all the registered iterators: they should now point to nullptr
490  // and their hashtable should be set to nullptr
491  __clearIterators();
492  }
493 
494  template < typename Key, typename Val, typename Alloc >
497  // avoid self assignment
498  if (this != &from) {
499  // for debugging purposes
500  GUM_OP_CPY(HashTable);
501 
502  // first remove the current content of the hashtable and make
503  // the iterators point to end
504  clear();
505 
506  // if sizes of from's and this' __nodes vectors are not the same,
507  // we need to remove the current __nodes' array and to create a
508  // new array with the correct size
509  if (__size != from.__size) {
510  __nodes.resize(from.__size);
511 
512  for (Size i = Size(0); i < from.__size; ++i) {
513  __nodes[i].setAllocator(__alloc);
514  }
515 
516  __size = from.__size;
517 
518  // update the hash function : this is important as the computation of
519  // the hash values heavily depends on the size of the hash table
520  __hash_func.resize(__size);
521  }
522 
523  __resize_policy = from.__resize_policy;
524  __key_uniqueness_policy = from.__key_uniqueness_policy;
525  __begin_index = from.__begin_index;
526 
527  // perform the copy
528  __copy(from);
529  }
530 
531  return *this;
532  }
533 
534  template < typename Key, typename Val, typename Alloc >
535  template < typename OtherAlloc >
538  // avoid self assignment
539  if (this != reinterpret_cast< const HashTable< Key, Val, Alloc >* >(&from)) {
540  // for debugging purposes
541  GUM_OP_CPY(HashTable);
542 
543  // first remove the current content of the hashtable and make
544  // the iterators point to end
545  clear();
546 
547  // if sizes of from's and this' __nodes vectors are not the same,
548  // we need to remove the current __nodes' array and to create a
549  // new array with the correct size
550  if (__size != from.__size) {
551  __nodes.resize(from.__size);
552 
553  for (Size i = 0; i < from.__size; ++i) {
554  __nodes[i].setAllocator(__alloc);
555  }
556 
557  __size = from.__size;
558 
559  // update the hash function : this is important as the computation of
560  // the hash values heavily depends on the size of the hash table
561  __hash_func.resize(__size);
562  }
563 
564  __resize_policy = from.__resize_policy;
565  __key_uniqueness_policy = from.__key_uniqueness_policy;
566  __begin_index = from.__begin_index;
567 
568  // perform the copy
569  __copy(from);
570  }
571 
572  return *this;
573  }
574 
575  template < typename Key, typename Val, typename Alloc >
578  // avoid self assignment
579  if (this != &table) {
580  // for debugging purposes
581  GUM_OP_MOV(HashTable);
582 
583  // first remove the current content of the hashtable and make
584  // the iterators point to end
585  clear();
586 
587  __nodes = std::move(table.__nodes);
588  __safe_iterators = std::move(table.__safe_iterators);
589  __alloc = std::move(table.__alloc);
590  __size = table.__size;
591  __nb_elements = table.__nb_elements;
592  __hash_func = table.__hash_func;
593  __resize_policy = table.__resize_policy;
594  __key_uniqueness_policy = table.__key_uniqueness_policy;
595  __begin_index = table.__begin_index;
596 
597  table.__size = 0; // necessary if we wish to perform moves iteratively,
598  // i.e. x = std::move ( y ); y = std::move ( z ); ...
599  }
600 
601  return *this;
602  }
603 
604  template < typename Key, typename Val, typename Alloc >
605  INLINE const typename HashTable< Key, Val, Alloc >::iterator&
607  // note that, here, we know for sure that HashTableIterEnd has been properly
608  // initialized as it is initialized by end4Statics, which is called by
609  // all hashtables' constructors
610  return *(reinterpret_cast< const iterator* >(
611  HashTableIteratorStaticEnd::__HashTableIterEnd));
612  }
613 
614  template < typename Key, typename Val, typename Alloc >
615  INLINE const typename HashTable< Key, Val, Alloc >::const_iterator&
617  // note that, here, we know for sure that HashTableIterEnd has been properly
618  // initialized as it is initialized by end4Statics, which is called by
619  // all hashtables' constructors
620  return *(reinterpret_cast< const const_iterator* >(
621  HashTableIteratorStaticEnd::__HashTableIterEnd));
622  }
623 
624  template < typename Key, typename Val, typename Alloc >
625  INLINE const typename HashTable< Key, Val, Alloc >::const_iterator&
627  // note that, here, we know for sure that HashTableIterEnd has been properly
628  // initialized as it is initialized by end4Statics, which is called by
629  // all hashtables' constructors
630  return *(reinterpret_cast< const const_iterator* >(
631  HashTableIteratorStaticEnd::__HashTableIterEnd));
632  }
633 
634  template < typename Key, typename Val, typename Alloc >
637  // if the table is empty, make the begin and end point to the same element
638  if (__nb_elements == Size(0))
639  return iterator{end()};
640  else
641  return iterator{*this};
642  }
643 
644  template < typename Key, typename Val, typename Alloc >
647  // if the table is empty, make the begin and end point to the same element
648  if (__nb_elements == Size(0))
649  return const_iterator{end()};
650  else
651  return const_iterator{*this};
652  }
653 
654  template < typename Key, typename Val, typename Alloc >
657  // if the table is empty, make the begin and end point to the same element
658  if (__nb_elements == Size(0))
659  return const_iterator{cend()};
660  else
661  return const_iterator{*this};
662  }
663 
664  template < typename Key, typename Val, typename Alloc >
665  INLINE const typename HashTable< Key, Val, Alloc >::iterator_safe&
667  // note that, here, we know for sure that HashTableIterEnd has been properly
668  // initialized as it is initialized by end4Statics, which is called by
669  // all hashtables' constructors
670  return *(reinterpret_cast< const iterator_safe* >(
671  HashTableIteratorStaticEnd::__HashTableIterEndSafe));
672  }
673 
674  template < typename Key, typename Val, typename Alloc >
677  // note that, here, we know for sure that HashTableIterEnd has been properly
678  // initialized as it is initialized by end4Statics, which is called by
679  // all hashtables' constructors
680  return *(reinterpret_cast< const const_iterator_safe* >(
681  HashTableIteratorStaticEnd::__HashTableIterEndSafe));
682  }
683 
684  template < typename Key, typename Val, typename Alloc >
687  // note that, here, we know for sure that HashTableIterEnd has been properly
688  // initialized as it is initialized by end4Statics, which is called by
689  // all hashtables' constructors
690  return *(reinterpret_cast< const const_iterator_safe* >(
691  HashTableIteratorStaticEnd::__HashTableIterEndSafe));
692  }
693 
694  template < typename Key, typename Val, typename Alloc >
697  // if the table is empty, make the begin and end point to the same element
698  if (__nb_elements == Size(0))
699  return iterator_safe{endSafe()};
700  else
701  return iterator_safe{*this};
702  }
703 
704  template < typename Key, typename Val, typename Alloc >
707  // if the table is empty, make the begin and end point to the same element
708  if (__nb_elements == Size(0))
709  return const_iterator_safe{endSafe()};
710  else
711  return const_iterator_safe{*this};
712  }
713 
714  template < typename Key, typename Val, typename Alloc >
717  // if the table is empty, make the begin and end point to the same element
718  if (__nb_elements == Size(0))
719  return const_iterator_safe{cendSafe()};
720  else
721  return const_iterator_safe{*this};
722  }
723 
724  template < typename Key, typename Val, typename Alloc >
725  INLINE Val& HashTable< Key, Val, Alloc >::operator[](const Key& key) {
726  return __nodes[__hash_func(key)][key];
727  }
728 
729  template < typename Key, typename Val, typename Alloc >
730  INLINE const Val& HashTable< Key, Val, Alloc >::
731  operator[](const Key& key) const {
732  return __nodes[__hash_func(key)][key];
733  }
734 
735  template < typename Key, typename Val, typename Alloc >
736  INLINE Size HashTable< Key, Val, Alloc >::size() const noexcept {
737  return __nb_elements;
738  }
739 
740  template < typename Key, typename Val, typename Alloc >
742  return __size;
743  }
744 
745  template < typename Key, typename Val, typename Alloc >
746  INLINE bool HashTable< Key, Val, Alloc >::exists(const Key& key) const {
747  return __nodes[__hash_func(key)].exists(key);
748  }
749 
750  template < typename Key, typename Val, typename Alloc >
752  const bool new_policy) noexcept {
753  __resize_policy = new_policy;
754  }
755 
756  template < typename Key, typename Val, typename Alloc >
757  INLINE bool HashTable< Key, Val, Alloc >::resizePolicy() const noexcept {
758  return __resize_policy;
759  }
760 
761  template < typename Key, typename Val, typename Alloc >
763  const bool new_policy) noexcept {
764  __key_uniqueness_policy = new_policy;
765  }
766 
767  template < typename Key, typename Val, typename Alloc >
769  return __key_uniqueness_policy;
770  }
771 
772  template < typename Key, typename Val, typename Alloc >
774  // new_size must be >= 2 else all the bits of the hash function are lost
775  new_size = std::max(Size(2), new_size);
776 
777  // find the real size for allocation (the smallest power of 2 greater
778  // than or equal to new_size) and get its base-2 logarithm
779  int log_size = __hashTableLog2(new_size);
780  new_size = Size(1) << log_size;
781 
782  // check if the new size is different from the actual size
783  // if not, nothing else need be done
784 
785  if (new_size != __size) {
786  // under automatic resize policy, check if the new size leaves
787  // enough space for storing all the current elements
788  if (!__resize_policy
789  || (__nb_elements
790  <= new_size * HashTableConst::default_mean_val_by_slot)) {
791  // create a new array of __nodes to store the elements
792  std::vector< HashTableList< Key, Val, Alloc > > new_nodes(new_size);
793 
794  for (auto& list : new_nodes) {
795  list.setAllocator(__alloc);
796  }
797 
798  // set the new hash function
799  __hash_func.resize(new_size);
800 
801  // put all the elements of the current __nodes array into the new one
802  Bucket* bucket;
803  Size new_hashed_key;
804 
805  for (Size i = Size(0); i < __size; ++i) {
806  while ((bucket = __nodes[i].__deb_list) != nullptr) {
807  // compute the new hashed key
808  new_hashed_key = __hash_func(bucket->key());
809 
810  // remove the bucket from the list of buckets of the current
811  // node vector
812  __nodes[i].__deb_list = bucket->next;
813 
814  // put the bucket into the new __nodes vector
815  new_nodes[new_hashed_key].insert(bucket);
816  }
817  }
818 
819  // update the size of the hash table
820  __size = new_size;
821  __begin_index = std::numeric_limits< Size >::max();
822 
823  // substitute the current __nodes array by the new one
824  std::swap(__nodes, new_nodes);
825 
826  // update the iterators
827  for (auto iter : __safe_iterators) {
828  if (iter->__bucket)
829  iter->__index = __hash_func(iter->__bucket->key());
830  else {
831  iter->__next_bucket = nullptr;
832  iter->__index = 0;
833  }
834  }
835  }
836  }
837  }
838 
839  template < typename Key, typename Val, typename Alloc >
840  void
842  Size hash_key = __hash_func(bucket->key());
843 
844  // check that there does not already exist an element with the same key
845  if (__key_uniqueness_policy && __nodes[hash_key].exists(bucket->key())) {
846  // remove the bucket from memory
847  Key k = bucket->key();
848  __alloc.destroy(bucket);
849  __alloc.deallocate(bucket, 1);
851  "the hashtable contains an element with the same key (" << k
852  << ")");
853  }
854 
855  // check whether there is sufficient space to insert the new pair
856  // if not, resize the current hashtable
857  if (__resize_policy
858  && (__nb_elements >= __size * HashTableConst::default_mean_val_by_slot)) {
859  resize(__size << 1);
860  hash_key = __hash_func(bucket->key());
861  }
862 
863  // add the new pair
864  __nodes[hash_key].insert(bucket);
865  ++__nb_elements;
866 
867  // recompute the index of the beginning of the hashtable if possible
868  // WARNING: if __begin_index = std::numeric_limits<Size>::max (), we CANNOT
869  // recompute the index because we cannot know whether the current index is
870  // equal to max because there was no element in the hashtable or whether a
871  // previous __erase() has set the index to max.
872  if (__begin_index < hash_key) { __begin_index = hash_key; }
873  }
874 
875  template < typename Key, typename Val, typename Alloc >
877  HashTable< Key, Val, Alloc >::insert(const Key& thekey, const Val& theval) {
878  Bucket* bucket = __alloc.allocate(1);
879 
880  try {
881  __alloc.construct(bucket, thekey, theval);
882  } catch (...) {
883  __alloc.deallocate(bucket, 1);
884  throw;
885  }
886 
887  __insert(bucket);
888  return bucket->elt();
889  }
890 
891  template < typename Key, typename Val, typename Alloc >
893  HashTable< Key, Val, Alloc >::insert(Key&& thekey, Val&& theval) {
894  Bucket* bucket = __alloc.allocate(1);
895 
896  try {
897  __alloc.construct(bucket, std::move(thekey), std::move(theval));
898  } catch (...) {
899  __alloc.deallocate(bucket, 1);
900  throw;
901  }
902 
903  __insert(bucket);
904  return bucket->elt();
905  }
906 
907  template < typename Key, typename Val, typename Alloc >
909  HashTable< Key, Val, Alloc >::insert(const std::pair< Key, Val >& elt) {
910  Bucket* bucket = __alloc.allocate(1);
911 
912  try {
913  __alloc.construct(bucket, reinterpret_cast< const value_type& >(elt));
914  } catch (...) {
915  __alloc.deallocate(bucket, 1);
916  throw;
917  }
918 
919  __insert(bucket);
920  return bucket->elt();
921  }
922 
923  template < typename Key, typename Val, typename Alloc >
925  HashTable< Key, Val, Alloc >::insert(std::pair< Key, Val >&& elt) {
926  Bucket* bucket = __alloc.allocate(1);
927 
928  try {
929  __alloc.construct(bucket, std::move(reinterpret_cast< value_type& >(elt)));
930  } catch (...) {
931  __alloc.deallocate(bucket, 1);
932  throw;
933  }
934 
935  __insert(bucket);
936  return bucket->elt();
937  }
938 
939  template < typename Key, typename Val, typename Alloc >
940  template < typename... Args >
943  Bucket* bucket = __alloc.allocate(1);
944 
945  try {
946  __alloc.construct(bucket,
948  std::forward< Args >(args)...);
949  } catch (...) {
950  __alloc.deallocate(bucket, 1);
951  throw;
952  }
953 
954  __insert(bucket);
955  return bucket->elt();
956  }
957 
958  template < typename Key, typename Val, typename Alloc >
961  const Val& default_value) {
962  Bucket* bucket = __nodes[__hash_func(key)].bucket(key);
963 
964  if (bucket == nullptr)
965  return insert(key, default_value).second;
966  else
967  return bucket->val();
968  }
969 
970  template < typename Key, typename Val, typename Alloc >
972  HashTable< Key, Val, Alloc >::getWithDefault(Key&& key, Val&& default_value) {
973  Bucket* bucket = __nodes[__hash_func(key)].bucket(key);
974 
975  if (bucket == nullptr)
976  return insert(std::move(key), std::move(default_value)).second;
977  else
978  return bucket->val();
979  }
980 
981  template < typename Key, typename Val, typename Alloc >
982  INLINE void HashTable< Key, Val, Alloc >::set(const Key& key, const Val& value) {
983  Bucket* bucket = __nodes[__hash_func(key)].bucket(key);
984 
985  if (bucket == nullptr)
986  insert(key, value);
987  else
988  bucket->val() = value;
989  }
990 
991  template < typename Key, typename Val, typename Alloc >
993  Size index) {
994  if (bucket == nullptr) return;
995 
996  // update the registered iterators pointing to this bucket
997  for (auto iter : __safe_iterators) {
998  if (iter->__bucket == bucket) {
999  iter->operator++();
1000  iter->__next_bucket = iter->__bucket;
1001  iter->__bucket = nullptr;
1002  } else if (iter->__next_bucket == bucket) {
1003  iter->__bucket = bucket;
1004  iter->operator++();
1005  iter->__next_bucket = iter->__bucket;
1006  iter->__bucket = nullptr;
1007  }
1008  }
1009 
1010  // remove the element from the __nodes vector
1011  __nodes[index].erase(bucket);
1012 
1013  --__nb_elements;
1014 
1015  if ((index == __begin_index) && __nodes[index].empty()) {
1016  __begin_index = std::numeric_limits< Size >::max();
1017  }
1018  }
1019 
1020  template < typename Key, typename Val, typename Alloc >
1021  INLINE void HashTable< Key, Val, Alloc >::erase(const Key& key) {
1022  // get the hashed key
1023  Size hash = __hash_func(key);
1024 
1025  // get the bucket containing the element to erase
1026  HashTableBucket< Key, Val >* bucket = __nodes[hash].bucket(key);
1027 
1028  __erase(bucket, hash);
1029  }
1030 
1031  template < typename Key, typename Val, typename Alloc >
1033  __erase(iter.__getBucket(), iter.__getIndex());
1034  }
1035 
1036  template < typename Key, typename Val, typename Alloc >
1037  INLINE void
1039  __erase(iter.__getBucket(), iter.__getIndex());
1040  }
1041 
1042  template < typename Key, typename Val, typename Alloc >
1043  INLINE void HashTable< Key, Val, Alloc >::eraseByVal(const Val& val) {
1044  for (auto iter = cbegin(); iter != cend(); ++iter)
1045  if (iter.__bucket->val() == val) {
1046  __erase(iter.__getBucket(), iter.__getIndex());
1047  return;
1048  }
1049  }
1050 
1051  template < typename Key, typename Val, typename Alloc >
1052  INLINE void HashTable< Key, Val, Alloc >::reset(const Key& key) {
1053  erase(key);
1054  }
1055 
1056  template < typename Key, typename Val, typename Alloc >
1057  INLINE const Key& HashTable< Key, Val, Alloc >::keyByVal(const Val& val) const {
1058  for (auto iter = begin(); iter != end(); ++iter)
1059  if (iter.__bucket->val() == val) return iter.key();
1060 
1061  GUM_ERROR(NotFound, "not enough elements in the chained list");
1062  }
1063 
1064  template < typename Key, typename Val, typename Alloc >
1065  INLINE const Key& HashTable< Key, Val, Alloc >::key(const Key& key) const {
1066  // get the bucket corresponding to the key
1067  Bucket* bucket = __nodes[__hash_func(key)].bucket(key);
1068 
1069  if (bucket == nullptr) {
1070  GUM_ERROR(NotFound, "key does not belong to the hashtable");
1071  }
1072 
1073  return bucket->key();
1074  }
1075 
1076  template < typename Key, typename Val, typename Alloc >
1078  for (auto iterAll = cbeginSafe(); iterAll != cendSafe(); ++iterAll) {
1079  if (iterAll.__bucket->val() == val) {
1080  __erase(iterAll.__bucket, iterAll.__index);
1081  }
1082  }
1083  }
1084 
1085  template < typename Key, typename Val, typename Alloc >
1086  INLINE bool HashTable< Key, Val, Alloc >::empty() const noexcept {
1087  return (__nb_elements == Size(0));
1088  }
1089 
1090  template < typename Key, typename Val, typename Alloc >
1091  template < typename Mount, typename OtherAlloc >
1093  Mount (*f)(Val), Size size, bool resize_pol, bool key_uniqueness_pol) const {
1094  // determine the proper size of the hashtable
1095  // by default, the size of the table is set so that the table does not take
1096  // too much space while allowing to add a few elements without needing to
1097  // resize in autmatic resizing mode
1098  if (size == 0) size = std::max(Size(2), __nb_elements / 2);
1099 
1100  // create a new table
1102  size, resize_pol, key_uniqueness_pol);
1103 
1104  // fill the new hash table
1105  for (auto iter = begin(); iter != end(); ++iter) {
1106  table.insert(iter.key(), f(iter.val()));
1107  }
1108 
1109  return table;
1110  }
1111 
1112  template < typename Key, typename Val, typename Alloc >
1113  template < typename Mount, typename OtherAlloc >
1115  Mount (*f)(Val&), Size size, bool resize_pol, bool key_uniqueness_pol) const {
1116  // determine the proper size of the hashtable
1117  // by default, the size of the table is set so that the table does not take
1118  // too much space while allowing to add a few elements without needing to
1119  // resize in autmatic resizing mode
1120  if (size == Size(0)) size = std::max(Size(2), __nb_elements / 2);
1121 
1122  // create a new table
1124  size, resize_pol, key_uniqueness_pol);
1125 
1126  // fill the new hash table
1127  for (auto iter = begin(); iter != end(); ++iter) {
1128  table.insert(iter.key(), f(const_cast< Val& >(iter.val())));
1129  }
1130 
1131  return table;
1132  }
1133 
1134  template < typename Key, typename Val, typename Alloc >
1135  template < typename Mount, typename OtherAlloc >
1137  INLINE HashTable< Key, Val, Alloc >::map(Mount (*f)(const Val&),
1138  Size size,
1139  bool resize_pol,
1140  bool key_uniqueness_pol) const {
1141  // determine the proper size of the hashtable
1142  // by default, the size of the table is set so that the table does not take
1143  // too much space while allowing to add a few elements without needing to
1144  // resize in autmatic resizing mode
1145  if (size == Size(0)) size = std::max(Size(2), __nb_elements / 2);
1146 
1147  // create a new table
1149  size, resize_pol, key_uniqueness_pol);
1150 
1151  // fill the new hash table
1152  for (auto iter = begin(); iter != end(); ++iter) {
1153  table.insert(iter.key(), f(iter.val()));
1154  }
1155 
1156  return table;
1157  }
1158 
1159  template < typename Key, typename Val, typename Alloc >
1160  template < typename Mount, typename OtherAlloc >
1162  const Mount& val, Size size, bool resize_pol, bool key_uniqueness_pol) const {
1163  // determine the proper size of the hashtable
1164  // by default, the size of the table is set so that the table does not take
1165  // too much space while allowing to add a few elements without needing to
1166  // resize in autmatic resizing mode
1167  if (size == Size(0)) size = std::max(Size(2), __nb_elements / 2);
1168 
1169  // create a new table
1171  size, resize_pol, key_uniqueness_pol);
1172 
1173  // fill the new hash table
1174  for (auto iter = begin(); iter != end(); ++iter) {
1175  table.insert(iter.key(), val);
1176  }
1177 
1178  return table;
1179  }
1180 
1181  template < typename Key, typename Val, typename Alloc >
1182  template < typename OtherAlloc >
1185  // checks whether the two hashtables contain the same number of elements
1186  if (from.__nb_elements != __nb_elements) return false;
1187 
1188  // parse this and check that each element also belongs to from
1189  for (auto iter = begin(); iter != end(); ++iter) {
1190  try {
1191  if (iter.val() != from[iter.key()]) return false;
1192  } catch (NotFound&) { return false; }
1193  }
1194 
1195  return true;
1196  }
1197 
1198  template < typename Key, typename Val, typename Alloc >
1199  template < typename OtherAlloc >
1200  INLINE bool HashTable< Key, Val, Alloc >::
1202  return !operator==(from);
1203  }
1204 
1205  template < typename Key, typename Val, typename Alloc >
1206  std::ostream& operator<<(std::ostream& stream,
1207  const HashTableList< Key, Val, Alloc >& list) {
1208  bool deja = false;
1209  stream << "[";
1210 
1211  for (HashTableBucket< Key, Val >* ptr = list.__deb_list; ptr;
1212  ptr = ptr->list.next, deja = true) {
1213  if (deja) stream << " , ";
1214 
1215  stream << ptr->key() << "=>" << ptr->val();
1216  }
1217 
1218  stream << "]";
1219 
1220  return stream;
1221  }
1222 
1223  template < typename Key, typename Val, typename Alloc >
1224  std::ostream& operator<<(std::ostream& stream,
1225  const HashTableList< Key*, Val, Alloc >& list) {
1226  bool deja = false;
1227  stream << "[";
1228 
1229  for (HashTableBucket< Key, Val >* ptr = list.__deb_list; ptr;
1230  ptr = ptr->list.next, deja = true) {
1231  if (deja) stream << " , ";
1232 
1233  stream << ptr->key() << "=>" << ptr->val();
1234  }
1235 
1236  stream << "]";
1237 
1238  return stream;
1239  }
1240 
1241  template < typename Key, typename Val, typename Alloc >
1242  std::ostream& operator<<(std::ostream& stream,
1243  const HashTable< Key, Val, Alloc >& table) {
1244  bool deja = false;
1245  stream << "{";
1246 
1247  for (Size i = Size(0); i < table.__size; ++i)
1248  for (auto ptr = table.__nodes[i].__deb_list; ptr; ptr = ptr->next) {
1249  if (deja) stream << " , ";
1250 
1251  stream << ptr->key() << "=>" << ptr->val();
1252 
1253  deja = true;
1254  }
1255 
1256  stream << "}";
1257 
1258  return stream;
1259  }
1260 
1261  template < typename Key, typename Val, typename Alloc >
1262  std::ostream& operator<<(std::ostream& stream,
1263  const HashTable< Key*, Val, Alloc >& table) {
1264  bool deja = false;
1265  stream << "{";
1266 
1267  for (Size i = Size(0); i < table.__size; ++i)
1268  for (auto ptr = table.__nodes[i].__deb_list; ptr; ptr = ptr->next) {
1269  if (deja) stream << " , ";
1270 
1271  stream << ptr->key() << "=>" << ptr->val();
1272 
1273  deja = true;
1274  }
1275 
1276  stream << "}";
1277 
1278  return stream;
1279  }
1280 
1281  // ===========================================================================
1282  // === SAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1283  // ===========================================================================
1284 
1285  template < typename Key, typename Val >
1286  INLINE void
1288  __table->__safe_iterators.push_back(
1289  const_cast< HashTableConstIteratorSafe< Key, Val >* >(this));
1290  }
1291 
1292  template < typename Key, typename Val >
1293  INLINE void
1295  if (__table == nullptr) return;
1296 
1297  // find where the iterator is
1298  std::vector< HashTableConstIteratorSafe< Key, Val >* >& iter_vect =
1299  __table->__safe_iterators;
1300 
1301  auto len = iter_vect.size();
1302  for (Size i = Size(0); i < len; ++i) {
1303  if (iter_vect[i] == this) {
1304  iter_vect.erase(iter_vect.begin() + i);
1305  break;
1306  }
1307  }
1308  }
1309 
1310  template < typename Key, typename Val >
1312  // for debugging purposes
1313  GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1314  }
1315 
1316  template < typename Key, typename Val >
1317  template < typename Alloc >
1319  const HashTable< Key, Val, Alloc >& tab) :
1320  __table{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1321  // for debugging purposes
1322  GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1323 
1324  // make the hashtable keep track of this iterator
1325  __insertIntoSafeList();
1326 
1327  if (__table->__nb_elements) {
1328  if (__table->__begin_index != std::numeric_limits< Size >::max()) {
1329  __index = __table->__begin_index;
1330  __bucket = __table->__nodes[__index].__end_list;
1331  } else {
1332  // find the element we shall point to from the start of the hashtable
1333  for (Size i = __table->__size - Size(1);; --i) { // no test on i since
1334  // __nb_elements != 0
1335  if (__table->__nodes[i].__nb_elements) {
1336  __index = i;
1337  __bucket = __table->__nodes[__index].__end_list;
1338  __table->__begin_index = __index;
1339  break;
1340  }
1341  }
1342  }
1343  }
1344  }
1345 
1346  template < typename Key, typename Val >
1347  template < typename Alloc >
1349  const HashTable< Key, Val, Alloc >& tab, Size ind_elt) :
1350  __table{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1351  Size i;
1352 
1353  // check if we are looking for a begin() and we know for sure its index
1354  if ((ind_elt == Size(0))
1355  && (__table->__begin_index != std::numeric_limits< Size >::max())) {
1356  __index = __table->__begin_index;
1357  __bucket = __table->__nodes[__index].__end_list;
1358  } else {
1359  // check if it is faster to find the ind_eltth element from the start or
1360  // from the end of the hashtable
1361  if (ind_elt < (__table->__nb_elements >> 1)) {
1362  // find the element we shall point to from the start of the hashtable
1363  for (i = __table->__size - 1;; --i) { // no test on i since
1364  // ind_elt < _table->__nb_elements
1365  if (__table->__nodes[i].__nb_elements) {
1366  if (ind_elt >= __table->__nodes[i].__nb_elements)
1367  ind_elt -= __table->__nodes[i].__nb_elements;
1368  else {
1369  for (__bucket = __table->__nodes[i].__end_list; ind_elt;
1370  --ind_elt, __bucket = __bucket->prev) {}
1371 
1372  __index = i;
1373  break;
1374  }
1375  }
1376  }
1377  } else {
1378  // ind_elt = the index of the element we should point to
1379  // check if the index passed as parameter is valid
1380  if (ind_elt >= __table->__nb_elements) {
1382  "Not enough elements in the hashtable");
1383  }
1384 
1385  // find the element we shall point to from the end of the hashtable
1386  for (i = 0, ind_elt = __table->__nb_elements - ind_elt - 1;; ++i) {
1387  if (__table->__nodes[i].__nb_elements) {
1388  if (ind_elt >= __table->__nodes[i].__nb_elements)
1389  ind_elt -= __table->__nodes[i].__nb_elements;
1390  else {
1391  for (__bucket = __table->__nodes[i].__deb_list; ind_elt;
1392  --ind_elt, __bucket = __bucket->next) {}
1393 
1394  __index = i;
1395  break;
1396  }
1397  }
1398  }
1399  }
1400  }
1401 
1402  // for debugging purposes
1403  GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1404 
1405  // make the hashtable keep track of this iterator
1406  __insertIntoSafeList();
1407  }
1408 
1409  template < typename Key, typename Val >
1412  __table{from.__table},
1413  __index{from.__index}, __bucket{from.__bucket}, __next_bucket{
1414  from.__next_bucket} {
1415  // make the hashtable keep track of this iterator
1416  if (__table != nullptr) { __insertIntoSafeList(); }
1417 
1418  // for debugging purposes
1419  GUM_CONS_CPY(HashTableConstIteratorSafe);
1420  }
1421 
1422  template < typename Key, typename Val >
1424  const HashTableConstIterator< Key, Val >& from) :
1425  __table{from.__table},
1426  __index{from.__index}, __bucket{from.__bucket} {
1427  // make the hashtable keep track of this iterator
1428  if (__table != nullptr) { __insertIntoSafeList(); }
1429 
1430  // for debugging purposes
1431  GUM_CONS_CPY(HashTableConstIteratorSafe);
1432  }
1433 
1434  template < typename Key, typename Val >
1437  __table{from.__table},
1438  __index{from.__index}, __bucket{from.__bucket}, __next_bucket{
1439  from.__next_bucket} {
1440  GUM_CONS_MOV(HashTableConstIteratorSafe);
1441 
1442  // find "from" in the hashtable's list of safe iterators and substitute
1443  // it by this
1444  if (__table != nullptr) {
1445  std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect =
1446  __table->__safe_iterators;
1447 
1448  for (auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1449  if (*ptr == &from) {
1450  *ptr = this;
1451  from.__table = nullptr;
1452  break;
1453  }
1454  }
1455  }
1456  }
1457 
1458  template < typename Key, typename Val >
1459  INLINE
1461  Val >::~HashTableConstIteratorSafe() noexcept {
1462  // for debugging purposes
1463  GUM_DESTRUCTOR(HashTableConstIteratorSafe);
1464 
1465  // remove the iterator from the table's iterator list
1466  __removeFromSafeList();
1467  }
1468 
1469  template < typename Key, typename Val >
1472  // here, no need to avoid self assignment: this would slow down normal
1473  // assignments and, in any case, this would not result in an iterator in
1474  // an incoherent state
1475  // check if the current hashtable is different from that of "from". In such
1476  // a case, we shall remove the iterator from its current hashtable
1477  // iterator's
1478  // list and add it to the new hashtable iterator's list
1479  if (__table != from.__table) {
1480  // remove the iterator from its hashtable iterator's list'
1481  __removeFromSafeList();
1482 
1483  __table = from.__table;
1484 
1485  // add to the new table
1486  if (__table) { __insertIntoSafeList(); }
1487  }
1488 
1489  __index = from.__index;
1490  __bucket = from.__bucket;
1491  __next_bucket = from.__next_bucket;
1492 
1493  return *this;
1494  }
1495 
1496  template < typename Key, typename Val >
1499  // here, no need to avoid self assignment: this would slow down normal
1500  // assignments and, in any case, this would not result in an iterator in
1501  // an incoherent state
1502  // check if the current hashtable is different from that of "from". In such
1503  // a case, we shall remove the iterator from its current hashtable
1504  // iterator's
1505  // list and add it to the new hashtable iterator's list
1506  if (__table != from.__table) {
1507  // remove the iterator from its hashtable iterator's list'
1508  __removeFromSafeList();
1509 
1510  __table = from.__table;
1511 
1512  // add to the new table
1513  if (__table) { __insertIntoSafeList(); }
1514  }
1515 
1516  __index = from.__index;
1517  __bucket = from.__bucket;
1518  __next_bucket = nullptr;
1519 
1520  return *this;
1521  }
1522 
1523  template < typename Key, typename Val >
1527  // here, no need to avoid self assignment: this would slow down normal
1528  // assignments and, in any case, this would not result in an iterator in
1529  // an incoherent state
1530  // check if the current hashtable is different from that of "from". In such
1531  // a case, we shall remove the iterator from its current hashtable
1532  // iterator's
1533  // list and add it to the new hashtable iterator's list
1534  if (__table != from.__table) {
1535  // remove the iterator from its hashtable iterator's list'
1536  __removeFromSafeList();
1537 
1538  if (from.__table != nullptr) {
1539  // substitute from by this in the list of safe iterators
1540  std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect =
1541  from.__table->__safe_iterators;
1542 
1543  for (auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1544  if (*ptr == &from) {
1545  *ptr = this;
1546  break;
1547  }
1548  }
1549  }
1550 
1551  __table = from.__table;
1552  from.__table = nullptr;
1553  }
1554 
1555  __index = from.__index;
1556  __bucket = from.__bucket;
1557  __next_bucket = from.__next_bucket;
1558 
1559  return *this;
1560  }
1561 
1562  template < typename Key, typename Val >
1565  if (__bucket != nullptr)
1566  return __bucket->key();
1567  else {
1568  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
1569  }
1570  }
1571 
1572  template < typename Key, typename Val >
1575  if (__bucket != nullptr)
1576  return __bucket->val();
1577  else {
1578  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
1579  }
1580  }
1581 
1582  template < typename Key, typename Val >
1584  // remove the iterator from the table's iterator list
1585  __removeFromSafeList();
1586 
1587  // set its table as well as the element it points to to 0
1588  __table = nullptr;
1589  __bucket = nullptr;
1590  __next_bucket = nullptr;
1591  __index = Size(0);
1592  }
1593 
1594  // WARNING: never inline this function: this result in g++4.3.3 producing a
1595  // code that segfaults.
1596  template < typename Key, typename Val >
1598  operator++() noexcept {
1599  // if __bucket != nullptr then use it, else use next_bucket
1600  if (__bucket == nullptr) {
1601  // note that this case only happens when the iterator pointed to an
1602  // element
1603  // that has just been erased. Fortunately, in this case, the Hashtable's
1604  // erase functions update appropriately the __next_bucket and __index
1605  // fields.
1606  __bucket = __next_bucket;
1607  __next_bucket = nullptr;
1608  } else {
1609  // ok, here we can use __bucket as a starting point
1610 
1611  // if we are not pointing on the first element of the chained list, just
1612  // point to the preceding bucket in this list
1613  if (__bucket->prev) {
1614  __bucket = __bucket->prev;
1615  // here, no need to update __next_bucket, which is compulsorily
1616  // equal to nullptr, nor __index which has not changed.
1617  } else {
1618  // ok, here we are on the beginning of a chained list,
1619  // so 2 cases can obtain:
1620  // 1/ index = 0 : then we have reached the end of the hashtable
1621  // 2/ index != 0 => we must search for a new slot containing elements
1622 
1623  // case 1:
1624  if (__index == Size(0)) {
1625  __bucket = nullptr;
1626  // we are thus at the end() of the hashTable
1627  }
1628  // case 2:
1629  else {
1630  // arrived here, we need to parse the hash table until we find a new
1631  // bucket because we are pointing on a chained list with no more
1632  // element
1633  // to the left of the current element
1634  if (__index > Size(0)) {
1635  for (Size i = __index - Size(1); i > Size(0); --i) {
1636  if (__table->__nodes[i].__nb_elements) {
1637  __index = i;
1638  __bucket = __table->__nodes[i].__end_list;
1639  return *this;
1640  }
1641  }
1642  }
1643 
1644  if (__table->__nodes[0].__nb_elements)
1645  __bucket = __table->__nodes[0].__end_list;
1646  else
1647  __bucket = nullptr;
1648 
1649  __index = 0;
1650  }
1651  }
1652  }
1653 
1654  return *this;
1655  }
1656 
1657  template < typename Key, typename Val >
1659  operator+=(Size nb) noexcept {
1660  if ((nb == Size(0)) || (__table == nullptr)) return *this;
1661 
1662  // if __bucket != nullptr then use it, else use next_bucket
1663  if (__bucket == nullptr) {
1664  // note that this case only happens when the iterator pointed to an
1665  // element
1666  // that has just been erased. Fortunately, in this case, the Hashtable's
1667  // erase functions update appropriately the __next_bucket and __index
1668  // fields.
1669  __bucket = __next_bucket;
1670  __next_bucket = nullptr;
1671  --nb;
1672  }
1673 
1674  // ok, here we can use __bucket as a starting point: parse all the elements
1675  // of the current chained list
1676  for (; nb && __bucket != nullptr; --nb, __bucket = __bucket->prev) {}
1677 
1678  if (__bucket != nullptr) return *this;
1679 
1680  // here, we shall skip all the chained list that have not sufficiently
1681  // many elements
1682  --__index;
1683 
1684  for (; __index < __table->__size
1685  && nb >= __table->__nodes[__index].__nb_elements;
1686  nb -= __table->__nodes[__index].__nb_elements, --__index) {}
1687 
1688  // here: either __index >= __table->__size, which means that we did not find
1689  // the element we looked for, i.e., we are at the end of the hashtable, or
1690  // nb < __table->__nodes[__index].__nb_elements, and we should parse the
1691  // chained list to get the element (which, we know for sure, exists)
1692  if (__index >= __table->__size) {
1693  __index = Size(0);
1694  return *this;
1695  }
1696 
1697  for (__bucket = __table->__nodes[__index].__end_list; nb;
1698  --nb, __bucket = __bucket->prev) {}
1699 
1700  return *this;
1701  }
1702 
1703  template < typename Key, typename Val >
1706  return HashTableConstIteratorSafe< Key, Val >{*this} += nb;
1707  }
1708 
1709  template < typename Key, typename Val >
1712  noexcept {
1713  return ((__bucket != from.__bucket) || (__index != from.__index));
1714  }
1715 
1716  template < typename Key, typename Val >
1719  noexcept {
1720  return ((__bucket == from.__bucket) && (__index == from.__index));
1721  }
1722 
1723  template < typename Key, typename Val >
1726  if (__bucket)
1727  return __bucket->elt();
1728  else {
1729  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
1730  }
1731  }
1732 
1733  template < typename Key, typename Val >
1736  return __bucket;
1737  }
1738 
1739  template < typename Key, typename Val >
1741  return __index;
1742  }
1743 
1744  // ===========================================================================
1745  // === SAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1746  // ===========================================================================
1747 
1748  template < typename Key, typename Val >
1750  HashTableConstIteratorSafe< Key, Val >() {
1751  GUM_CONSTRUCTOR(HashTableIteratorSafe);
1752  }
1753 
1754  template < typename Key, typename Val >
1755  template < typename Alloc >
1757  const HashTable< Key, Val, Alloc >& tab) :
1758  HashTableConstIteratorSafe< Key, Val >(tab) {
1759  GUM_CONSTRUCTOR(HashTableIteratorSafe);
1760  }
1761 
1762  template < typename Key, typename Val >
1763  template < typename Alloc >
1765  const HashTable< Key, Val, Alloc >& tab, Size ind_elt) :
1766  HashTableConstIteratorSafe< Key, Val >(tab, ind_elt) {
1767  GUM_CONSTRUCTOR(HashTableIteratorSafe);
1768  }
1769 
1770  template < typename Key, typename Val >
1772  const HashTableIteratorSafe< Key, Val >& from) :
1773  HashTableConstIteratorSafe< Key, Val >(from) {
1774  GUM_CONS_CPY(HashTableIteratorSafe);
1775  }
1776 
1777  template < typename Key, typename Val >
1779  const HashTableIterator< Key, Val >& from) :
1780  HashTableConstIteratorSafe< Key, Val >(from) {
1781  GUM_CONS_CPY(HashTableIteratorSafe);
1782  }
1783 
1784  template < typename Key, typename Val >
1786  HashTableIteratorSafe< Key, Val >&& from) noexcept :
1787  HashTableConstIteratorSafe< Key, Val >(std::move(from)) {
1788  GUM_CONS_MOV(HashTableIteratorSafe);
1789  }
1790 
1791  template < typename Key, typename Val >
1793  GUM_DESTRUCTOR(HashTableIteratorSafe);
1794  }
1795 
1796  template < typename Key, typename Val >
1799  return const_cast< Val& >(HashTableConstIteratorSafe< Key, Val >::val());
1800  }
1801 
1802  template < typename Key, typename Val >
1805  GUM_OP_CPY(HashTableIteratorSafe);
1807  return *this;
1808  }
1809 
1810  template < typename Key, typename Val >
1813  GUM_OP_CPY(HashTableIteratorSafe);
1815  return *this;
1816  }
1817 
1818  template < typename Key, typename Val >
1822  return *this;
1823  }
1824 
1825  template < typename Key, typename Val >
1827  operator++() noexcept {
1829  return *this;
1830  }
1831 
1832  template < typename Key, typename Val >
1834  operator+=(Size nb) noexcept {
1836  return *this;
1837  }
1838 
1839  template < typename Key, typename Val >
1841  operator+(Size nb) const {
1843  iter += nb;
1844  return iter;
1845  }
1846 
1847  template < typename Key, typename Val >
1849  operator!=(const HashTableIteratorSafe< Key, Val >& from) const noexcept {
1851  }
1852 
1853  template < typename Key, typename Val >
1855  operator==(const HashTableIteratorSafe< Key, Val >& from) const noexcept {
1857  }
1858 
1859  template < typename Key, typename Val >
1862  return const_cast< Val& >(HashTableConstIteratorSafe< Key, Val >::operator*());
1863  }
1864 
1865  template < typename Key, typename Val >
1866  INLINE const typename HashTableIteratorSafe< Key, Val >::value_type&
1869  }
1870 
1871  // ===========================================================================
1872  // === UNSAFE HASH TABLE CONST ITERATORS IMPLEMENTATION ===
1873  // ===========================================================================
1874 
1875  template < typename Key, typename Val >
1877  GUM_CONSTRUCTOR(HashTableConstIterator);
1878  }
1879 
1880  template < typename Key, typename Val >
1881  template < typename Alloc >
1883  const HashTable< Key, Val, Alloc >& tab) noexcept :
1884  __table{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1885  // for debugging purposes
1886  GUM_CONSTRUCTOR(HashTableConstIterator);
1887 
1888  if (__table->__nb_elements) {
1889  if (__table->__begin_index != std::numeric_limits< Size >::max()) {
1890  __index = __table->__begin_index;
1891  __bucket = __table->__nodes[__index].__end_list;
1892  } else {
1893  // find the element we shall point to from the start of the hashtable
1894  for (Size i = __table->__size - Size(1);; --i) { // no test on i since
1895  // __nb_elements != 0
1896  if (__table->__nodes[i].__nb_elements) {
1897  __index = i;
1898  __bucket = __table->__nodes[__index].__end_list;
1899  __table->__begin_index = __index;
1900  break;
1901  }
1902  }
1903  }
1904  }
1905  }
1906 
1907  template < typename Key, typename Val >
1908  template < typename Alloc >
1910  const HashTable< Key, Val, Alloc >& tab, Size ind_elt) :
1911  __table{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1912  Size i;
1913 
1914  // check if we are looking for a begin() and we know for sure its index
1915  if ((ind_elt == Size(0))
1916  && (__table->__begin_index != std::numeric_limits< Size >::max())) {
1917  __index = __table->__begin_index;
1918  __bucket = __table->__nodes[__index].__end_list;
1919  } else {
1920  // check if it is faster to find the ind_eltth element from the start or
1921  // from the end of the hashtable
1922  if (ind_elt < (__table->__nb_elements >> 1)) {
1923  // find the element we shall point to from the start of the hashtable
1924  for (i = __table->__size - 1;; --i) { // no test on i since
1925  // ind_elt < _table->__nb_elements
1926  if (__table->__nodes[i].__nb_elements) {
1927  if (ind_elt >= __table->__nodes[i].__nb_elements)
1928  ind_elt -= __table->__nodes[i].__nb_elements;
1929  else {
1930  for (__bucket = __table->__nodes[i].__end_list; ind_elt;
1931  --ind_elt, __bucket = __bucket->prev) {}
1932 
1933  __index = i;
1934  break;
1935  }
1936  }
1937  }
1938  } else {
1939  // ind_elt = the index of the element we should point to
1940  // check if the index passed as parameter is valid
1941  if (ind_elt >= __table->__nb_elements) {
1943  "Not enough elements in the hashtable");
1944  }
1945 
1946  // find the element we shall point to from the end of the hashtable
1947  for (i = 0, ind_elt = __table->__nb_elements - ind_elt - 1;; ++i) {
1948  if (__table->__nodes[i].__nb_elements) {
1949  if (ind_elt >= __table->__nodes[i].__nb_elements)
1950  ind_elt -= __table->__nodes[i].__nb_elements;
1951  else {
1952  for (__bucket = __table->__nodes[i].__deb_list; ind_elt;
1953  --ind_elt, __bucket = __bucket->next) {}
1954 
1955  __index = i;
1956  break;
1957  }
1958  }
1959  }
1960  }
1961  }
1962 
1963  // for debugging purposes
1964  GUM_CONSTRUCTOR(HashTableConstIterator);
1965  }
1966 
1967  template < typename Key, typename Val >
1969  const HashTableConstIterator< Key, Val >& from) noexcept :
1970  __table{from.__table},
1971  __index{from.__index}, __bucket{from.__bucket} {
1972  GUM_CONS_CPY(HashTableConstIterator);
1973  }
1974 
1975  template < typename Key, typename Val >
1977  HashTableConstIterator< Key, Val >&& from) noexcept :
1978  __table{from.__table},
1979  __index{from.__index}, __bucket{from.__bucket} {
1980  GUM_CONS_MOV(HashTableConstIterator);
1981  }
1982 
1983  template < typename Key, typename Val >
1985  // for debugging purposes
1986  GUM_DESTRUCTOR(HashTableConstIterator);
1987  }
1988 
1989  template < typename Key, typename Val >
1992  // here, no need to avoid self assignment: this would slow down normal
1993  // assignments and, in any case, this would not result in an iterator in
1994  // an incoherent state
1995  __table = from.__table;
1996  __index = from.__index;
1997  __bucket = from.__bucket;
1998 
1999  return *this;
2000  }
2001 
2002  template < typename Key, typename Val >
2005  // here, no need to avoid self assignment: this would slow down normal
2006  // assignments and, in any case, this would not result in an iterator in
2007  // an incoherent state
2008  __table = from.__table;
2009  __index = from.__index;
2010  __bucket = from.__bucket;
2011 
2012  return *this;
2013  }
2014 
2015  template < typename Key, typename Val >
2016  INLINE const typename HashTableConstIterator< Key, Val >::key_type&
2018  if (__bucket)
2019  return __bucket->pair.first;
2020  else {
2021  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
2022  }
2023  }
2024 
2025  template < typename Key, typename Val >
2028  if (__bucket)
2029  return __bucket->val();
2030  else {
2031  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
2032  }
2033  }
2034 
2035  template < typename Key, typename Val >
2037  __table = nullptr;
2038  __bucket = nullptr;
2039  __index = 0;
2040  }
2041 
2042  template < typename Key, typename Val >
2044  operator++() noexcept {
2045  // if __bucket == nullptr then we are at the end of the hashtable
2046  if (__bucket == nullptr) return *this;
2047 
2048  // if we are not pointing on the first element of the chained list, just
2049  // point to the next bucket in this list
2050  if (__bucket->prev) {
2051  __bucket = __bucket->prev;
2052  // here, no need to update __index which has not changed.
2053  } else {
2054  // ok, here we are on the end of a chained list,
2055  // so 2 cases can obtain:
2056  // 1/ index = 0 : then we have reached the end of the hashtable
2057  // 2/ index != 0 => we must search for a new slot containing elements
2058 
2059  // case 1:
2060  if (__index == Size(0)) {
2061  __bucket = nullptr;
2062  // we are thus at the end() of the hashTable
2063  }
2064 
2065  // case 2:
2066  else {
2067  // arrived here, we need to parse the hash table until we find a new
2068  // bucket because we are pointing on a chained list with no more element
2069  // to the right of the current element
2070  for (Size i = __index - Size(1); i; --i) {
2071  if (__table->__nodes[i].__nb_elements) {
2072  __index = i;
2073  __bucket = __table->__nodes[i].__end_list;
2074  return *this;
2075  }
2076  }
2077 
2078  if (__table->__nodes[0].__nb_elements)
2079  __bucket = __table->__nodes[0].__end_list;
2080  else
2081  __bucket = nullptr;
2082 
2083  __index = Size(0);
2084  }
2085  }
2086 
2087  return *this;
2088  }
2089 
2090  template < typename Key, typename Val >
2092  operator+=(Size nb) noexcept {
2093  if ((nb == 0) || (__table == nullptr) || (__bucket == nullptr)) return *this;
2094 
2095  // ok, here we can use __bucket as a starting point: parse all the elements
2096  // of the current chained list
2097  for (; nb && __bucket != nullptr; --nb, __bucket = __bucket->prev) {}
2098 
2099  if (__bucket != nullptr) return *this;
2100 
2101  // here, we shall skip all the chained list that have not sufficiently
2102  // many elements
2103  --__index;
2104 
2105  for (; __index < __table->__size
2106  && nb >= __table->__nodes[__index].__nb_elements;
2107  nb -= __table->__nodes[__index].__nb_elements, --__index) {}
2108 
2109  // here: either __index >= __table->__size, which means that we did not find
2110  // the element we looked for, i.e., we are at the end of the hashtable, or
2111  // nb < __table->__nodes[__index].__nb_elements, and we should parse the
2112  // chained list to get the element (which, we know for sure, exists)
2113  if (__index >= __table->__size) {
2114  __index = 0;
2115  return *this;
2116  }
2117 
2118  for (__bucket = __table->__nodes[__index].__end_list; nb;
2119  --nb, __bucket = __bucket->prev) {}
2120 
2121  return *this;
2122  }
2123 
2124  template < typename Key, typename Val >
2126  operator+(Size nb) const noexcept {
2127  return HashTableConstIterator< Key, Val >{*this} += nb;
2128  }
2129 
2130  template < typename Key, typename Val >
2133  return (__bucket != from.__bucket);
2134  }
2135 
2136  template < typename Key, typename Val >
2139  return (__bucket == from.__bucket);
2140  }
2141 
2142  template < typename Key, typename Val >
2143  INLINE const typename HashTableConstIterator< Key, Val >::value_type&
2145  if (__bucket)
2146  return __bucket->elt();
2147  else {
2148  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
2149  }
2150  }
2151 
2152  template < typename Key, typename Val >
2153  INLINE typename HashTable< Key, Val >::Bucket*
2155  return __bucket;
2156  }
2157 
2158  template < typename Key, typename Val >
2160  return __index;
2161  }
2162 
2163  // ===========================================================================
2164  // === UNSAFE HASH TABLE ITERATORS IMPLEMENTATION ===
2165  // ===========================================================================
2166 
2167  template < typename Key, typename Val >
2169  HashTableConstIterator< Key, Val >() {
2170  GUM_CONSTRUCTOR(HashTableIterator);
2171  }
2172 
2173  template < typename Key, typename Val >
2174  template < typename Alloc >
2176  const HashTable< Key, Val, Alloc >& tab) noexcept :
2178  GUM_CONSTRUCTOR(HashTableIterator);
2179  }
2180 
2181  template < typename Key, typename Val >
2182  template < typename Alloc >
2184  const HashTable< Key, Val, Alloc >& tab, Size ind_elt) :
2185  HashTableConstIterator< Key, Val >(tab, ind_elt) {
2186  GUM_CONSTRUCTOR(HashTableIterator);
2187  }
2188 
2189  template < typename Key, typename Val >
2191  const HashTableIterator< Key, Val >& from) noexcept :
2193  GUM_CONS_CPY(HashTableIterator);
2194  }
2195 
2196  template < typename Key, typename Val >
2198  HashTableIterator< Key, Val >&& from) noexcept :
2199  HashTableConstIterator< Key, Val >(std::move(from)) {
2200  GUM_CONS_MOV(HashTableIterator);
2201  }
2202 
2203  template < typename Key, typename Val >
2205  GUM_DESTRUCTOR(HashTableIterator);
2206  }
2207 
2208  template < typename Key, typename Val >
2211  if (this->__bucket)
2212  return this->__bucket->val();
2213  else {
2214  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
2215  }
2216  }
2217 
2218  template < typename Key, typename Val >
2222  return *this;
2223  }
2224 
2225  template < typename Key, typename Val >
2229  return *this;
2230  }
2231 
2232  template < typename Key, typename Val >
2234  operator++() noexcept {
2236  return *this;
2237  }
2238 
2239  template < typename Key, typename Val >
2241  operator+=(Size nb) noexcept {
2243  return *this;
2244  }
2245 
2246  template < typename Key, typename Val >
2248  operator+(Size nb) const noexcept {
2249  HashTableIterator< Key, Val > iter{*this};
2250  iter += nb;
2251  return iter;
2252  }
2253 
2254  template < typename Key, typename Val >
2256  operator!=(const HashTableIterator< Key, Val >& from) const noexcept {
2258  }
2259 
2260  template < typename Key, typename Val >
2262  operator==(const HashTableIterator< Key, Val >& from) const noexcept {
2264  }
2265 
2266  template < typename Key, typename Val >
2269  return const_cast< value_type& >(
2271  }
2272 
2273  template < typename Key, typename Val >
2274  INLINE const typename HashTableIterator< Key, Val >::value_type&
2277  }
2278 
2279 } /* namespace gum */
void resize(Size new_size)
Changes the number of slots in the &#39;nodes&#39; vector of the hash table.
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...
Size __index
The index of the chained list pointed by the iterator in the array of nodes of the hash table...
Definition: hashTable.h:2678
const HashTable< Key, Val > * __table
The hash table the iterator is pointing to.
Definition: hashTable.h:2672
Key & key()
Returns the key part of the pair.
Definition: hashTable.h:281
bool __resize_policy
Is resizing performed automatically?
Definition: hashTable.h:1730
Key key_type
Types for STL compliance.
Definition: hashTable.h:1923
const mapped_type & val() const
Returns the mapped value pointed to by the iterator.
Size __nb_elements
The number of elements in the chained list.
Definition: hashTable.h:540
Unsafe Const Iterators for hashtablesHashTableConstIterator provides a fast but unsafe way to parse H...
Definition: hashTable.h:2465
Size size() const noexcept
Returns the number of elements stored into the hashtable.
Val mapped_type
Types for STL compliance.
Definition: hashTable.h:1924
const key_type & key() const
Returns the key pointed to by the iterator.
Unsafe Iterators for hashtablesHashTableIterator provides a fast but unsafe way to parse HashTables...
Definition: hashTable.h:2750
Safe Const Iterators for hashtables.
Definition: hashTable.h:1918
void erase(Bucket *ptr)
Removes an element from this chained list.
STL namespace.
HashTableBucket< Key, Val > * __getBucket() const noexcept
Returns the current iterator&#39;s bucket.
bool exists(const Key &key) const
Checks whether there exists an element with a given key in the hashtable.
Size __size
The number of nodes in vector &#39;__nodes&#39;.
Definition: hashTable.h:1721
void swap(HashTable< LpCol, double > *&a, HashTable< LpCol, double > *&b)
Swap the addresses of two pointers to hashTables.
const Key & key(const Key &key) const
Returns a reference on a given key.
Safe Iterators for hashtables.
Definition: hashTable.h:2220
std::vector< HashTableList< Key, Val, Alloc > > __nodes
The hash table is represented as a vector of chained lists.
Definition: hashTable.h:1718
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
BucketAllocator * __alloc_bucket
The allocator of the containing hashTable.
Definition: hashTable.h:543
Size __index
the index of the chained list pointed to by the iterator in the array __nodes of the hash table...
Definition: hashTable.h:2132
const mapped_type & val() const
Returns the mapped value pointed to by the iterator.
The class for generic Hash Tables.
Definition: hashTable.h:679
std::pair< const Key, Val > value_type
types for STL compliance
Definition: hashTable.h:311
Size __nb_elements
Number of elements of type Val stored in the hash table.
Definition: hashTable.h:1724
Key key_type
Types for STL compliance.
Definition: hashTable.h:2470
void __copy(const HashTableList< Key, Val, OtherAlloc > &from)
A function used to perform copies of HashTableLists.
Definition: hashTable_tpl.h:45
HashTableBucket< Key, Val > * __deb_list
A pointer on the first element of the chained list.
Definition: hashTable.h:534
std::ostream & operator<<(std::ostream &output, const BayesNet< GUM_SCALAR > &bn)
Prints map&#39;s DAG in output using the Graphviz-dot format.
Definition: BayesNet_tpl.h:605
HashTableBucket< Key, Val > * __bucket
The bucket in the chained list pointed to by the iterator.
Definition: hashTable.h:2135
Val mapped_type
Types for STL compliance.
Definition: hashTable.h:2471
Val mapped_type
types for STL compliance
Definition: hashTable.h:2756
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition: hashTable.h:2227
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition: hashTable.h:1925
bool __key_uniqueness_policy
Shall we check for key uniqueness in the table?
Definition: hashTable.h:1733
LpExpr operator+(LpExpr &&lhs, const T2 &rhs)
Overload of operator + between anything ( a scalar, a variable or an expression ) and anything except...
Val mapped_type
Types for STL compliance.
Definition: hashTable.h:684
bool operator==(const TiXmlString &a, const TiXmlString &b)
Definition: tinystr.h:243
Val mapped_type
Types for STL compliance.
Definition: hashTable.h:2226
HashTable< Key, Val >::Bucket * __bucket
The bucket in the chained list pointed to by the iterator.
Definition: hashTable.h:2681
Val mapped_type
types for STL compliance
Definition: hashTable.h:310
Size __begin_index
Returns where the begin index should be.
Definition: hashTable.h:1749
Val & val()
Returns the value part of the pair.
Definition: hashTable.h:287
Size __getIndex() const noexcept
Returns the index in the hashtable&#39;s node vector pointed to by the iterator.
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition: hashTable.h:685
HashTableBucket< Key, Val > * next
A pointer toward the next bucket in the gum::HashTableList.
Definition: hashTable.h:210
LpExpr operator*(const SCALAR &lhs, const LpCol &rhs)
Overload of operator * between a scalar and a variable.
std::pair< const Key, Val > value_type
Types for STL compliance.
Definition: hashTable.h:2472
const HashTable< Key, Val > * __table
The hash table the iterator is pointing to.
Definition: hashTable.h:2126
bool operator!=(const TiXmlString &a, const TiXmlString &b)
Definition: tinystr.h:251
A chained list used by gum::HashTable.
Definition: hashTable.h:305
friend class HashTableList
Friend for faster access.
Definition: hashTable.h:517
HashTableBucket< Key, Val > * prev
A pointer toward the previous bucket in the gum::HashTableList.
Definition: hashTable.h:207
Bucket * bucket(const Key &key) const
A method to get the bucket corresponding to a given key.
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
HashTableBucket< Key, Val > * __next_bucket
the bucket we should start from when we decide to do a ++.
Definition: hashTable.h:2145
typename Alloc::template rebind< Bucket >::other BucketAllocator
The Bucket allocator.
Definition: hashTable.h:322
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
mapped_type & val()
Returns the mapped value pointed to by the iterator.
std::pair< const Key, Val > & elt()
Returns the pair stored in this bucket.
Definition: hashTable.h:275
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
std::pair< const Key, Val > value_type
types for STL compliance
Definition: hashTable.h:2757