aGrUM  0.17.2
a C++ library for (probabilistic) graphical models
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
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  const HashTableList< Key, Val, Alloc >& from) {
182  // avoid self assignment
183  if (this != &from) {
184  clear();
185  __copy(from);
186  }
187 
188  return *this;
189  }
190 
191  template < typename Key, typename Val, typename Alloc >
192  template < typename OtherAlloc >
196  // avoid self assignment
197  if (this
198  != reinterpret_cast< const HashTableList< Key, Val, Alloc >* >(&from)) {
199  clear();
200  __copy(from);
201  }
202 
203  return *this;
204  }
205 
206  template < typename Key, typename Val, typename Alloc >
209  HashTableList< Key, Val, Alloc >&& from) noexcept {
210  // avoid self assignment
211  if (this != &from) {
212  __deb_list = from.__deb_list;
213  __end_list = from.__end_list;
214  __nb_elements = from.__nb_elements;
215  from.__deb_list = nullptr;
216  }
217 
218  return *this;
219  }
220 
221  template < typename Key, typename Val, typename Alloc >
224  __alloc_bucket = &alloc;
225  }
226 
227  template < typename Key, typename Val, typename Alloc >
230  if (i >= __nb_elements) {
231  GUM_ERROR(NotFound, "not enough elements in the chained list");
232  }
233 
234  Bucket* ptr;
235 
236  for (ptr = __deb_list; i; --i, ptr = ptr->next) {}
237 
238  return ptr->elt();
239  }
240 
241  template < typename Key, typename Val, typename Alloc >
242  INLINE const typename HashTableList< Key, Val, Alloc >::value_type&
244  if (i >= __nb_elements) {
245  GUM_ERROR(NotFound, "not enough elements in the chained list");
246  }
247 
248  Bucket* ptr;
249 
250  for (ptr = __deb_list; i; --i, ptr = ptr->next) {}
251 
252  return ptr->elt();
253  }
254 
255  template < typename Key, typename Val, typename Alloc >
256  INLINE const typename HashTableList< Key, Val, Alloc >::mapped_type&
258  for (Bucket* ptr = __deb_list; ptr != nullptr; ptr = ptr->next)
259  if (ptr->key() == key) return ptr->val();
260 
262  "hashtable's chained list contains no element with this key <"
263  << key << ">");
264  }
265 
266  template < typename Key, typename Val, typename Alloc >
269  for (Bucket* ptr = __deb_list; ptr != nullptr; ptr = ptr->next)
270  if (ptr->key() == key) return ptr->val();
271 
273  "hashtable's chained list contains no element with this key <"
274  << key << ">");
275  }
276 
277  template < typename Key, typename Val, typename Alloc >
278  INLINE bool HashTableList< Key, Val, Alloc >::exists(const Key& key) const {
279  for (Bucket* ptr = __deb_list; ptr != nullptr; ptr = ptr->next) {
280  if (ptr->key() == key) { return true; }
281  }
282 
283  return false;
284  }
285 
286  template < typename Key, typename Val, typename Alloc >
287  INLINE bool HashTableList< Key, Val, Alloc >::empty() const noexcept {
288  return (__nb_elements == Size(0));
289  }
290 
291  template < typename Key, typename Val, typename Alloc >
293  HashTableBucket< Key, Val >* new_elt) noexcept {
294  // place the bucket at the beginning of the list
295  new_elt->prev = nullptr;
296  new_elt->next = __deb_list;
297 
298  if (__deb_list != nullptr)
299  __deb_list->prev = new_elt;
300  else
301  __end_list = new_elt;
302 
303  __deb_list = new_elt;
304 
305  ++__nb_elements;
306  }
307 
308  // ===========================================================================
309  // === GENERIC HASH TABLE IMPLEMENTATION ===
310  // ===========================================================================
311 
312  template < typename Key, typename Val, typename Alloc >
313  template < typename OtherAlloc >
315  const HashTable< Key, Val, OtherAlloc >& table) {
316  // in debug mode, check that this and table have '__nodes' arrays of the
317  // same size
318  GUM_ASSERT(table.__size == __size);
319 
320  // try to fill the array of chained lists
321  for (Size i = 0; i < table.__size; ++i) {
322  try {
323  __nodes[i] = table.__nodes[i];
324  } catch (...) {
325  // here we could allocate the __nodes[j], j=0..i-1, so we should
326  // deallocate them
327  for (Size j = 0; j < __size; ++j)
328  __nodes[j].clear();
329 
330  __nb_elements = Size(0);
331 
332  // propagate the exception
333  throw;
334  }
335  }
336 
337  __nb_elements = table.__nb_elements;
338  }
339 
340  template < typename Key, typename Val, typename Alloc >
341  INLINE const typename HashTable< Key, Val, Alloc >::iterator&
343  return *(reinterpret_cast< const iterator* >(
344  HashTableIteratorStaticEnd::end4Statics()));
345  }
346 
347  template < typename Key, typename Val, typename Alloc >
348  INLINE const typename HashTable< Key, Val, Alloc >::const_iterator&
350  return *(reinterpret_cast< const const_iterator* >(
351  HashTableIteratorStaticEnd::constEnd4Statics()));
352  }
353 
354  template < typename Key, typename Val, typename Alloc >
355  INLINE const typename HashTable< Key, Val, Alloc >::iterator_safe&
357  return *(reinterpret_cast< const iterator_safe* >(
358  HashTableIteratorStaticEnd::endSafe4Statics()));
359  }
360 
361  template < typename Key, typename Val, typename Alloc >
364  return *(reinterpret_cast< const const_iterator_safe* >(
365  HashTableIteratorStaticEnd::constEndSafe4Statics()));
366  }
367 
368  template < typename Key, typename Val, typename Alloc >
370  // setup the __nodes vector (contains only empty lists)
371  __nodes.resize(size);
372 
373  for (auto& list: __nodes) {
374  list.setAllocator(__alloc);
375  }
376 
377  // set up properly the hash function
378  __hash_func.resize(size);
379 
380  // make sure the end() iterator is constructed properly
381  end4Statics();
382  endSafe4Statics();
383  }
384 
385  template < typename Key, typename Val, typename Alloc >
387  bool resize_pol,
388  bool key_uniqueness_pol) :
389  // size must be >= 2 else we lose all the bits of the hash function
390  __size{Size(1) << __hashTableLog2(std::max(Size(2), size_param))},
391  __resize_policy{resize_pol}, __key_uniqueness_policy{key_uniqueness_pol} {
392  // for debugging purposes
393  GUM_CONSTRUCTOR(HashTable);
394 
395  // finalize the creation
396  __create(__size);
397  }
398 
399  template < typename Key, typename Val, typename Alloc >
401  std::initializer_list< std::pair< Key, Val > > list) :
402  // size must be >= 2 else we lose all the bits of the hash function
403  __size{Size(1) << __hashTableLog2(
404  std::max< Size >(Size(2), Size(list.size()) / 2))} {
405  // for debugging purposes
406  GUM_CONSTRUCTOR(HashTable);
407 
408  // setup the __nodes vector (contains only empty lists)
409  __create(__size);
410 
411  // insert all the elements
412  for (const auto& elt: list) {
413  insert(elt);
414  }
415  }
416 
417  template < typename Key, typename Val, typename Alloc >
419  const HashTable< Key, Val, Alloc >& table) :
420  __size{table.__size},
421  __resize_policy{table.__resize_policy},
422  __key_uniqueness_policy{table.__key_uniqueness_policy},
423  __begin_index{table.__begin_index} {
424  // for debugging purposes
425  GUM_CONS_CPY(HashTable);
426 
427  // setup the __nodes vector (contains only empty lists)
428  __create(__size);
429 
430  // fill with the content of table
431  __copy(table);
432  }
433 
434  template < typename Key, typename Val, typename Alloc >
435  template < typename OtherAlloc >
437  const HashTable< Key, Val, OtherAlloc >& table) :
438  __size{table.__size},
439  __resize_policy{table.__resize_policy},
440  __key_uniqueness_policy{table.__key_uniqueness_policy},
441  __begin_index{table.__begin_index} {
442  // for debugging purposes
443  GUM_CONS_CPY(HashTable);
444 
445  // setup the __nodes vector (contains only empty lists)
446  __create(__size);
447 
448  // fill with the content of table
449  __copy(table);
450  }
451 
452  template < typename Key, typename Val, typename Alloc >
454  __nodes(std::move(table.__nodes)), __size{table.__size},
455  __nb_elements{table.__nb_elements}, __hash_func{table.__hash_func},
456  __resize_policy{table.__resize_policy},
457  __key_uniqueness_policy{table.__key_uniqueness_policy},
458  __begin_index{table.__begin_index},
459  __safe_iterators(std::move(table.__safe_iterators)),
460  __alloc(std::move(table.__alloc)) {
461  // for debugging purposes
462  table.__size = 0;
463  GUM_CONS_MOV(HashTable);
464  }
465 
466  template < typename Key, typename Val, typename Alloc >
468  const Size len = __safe_iterators.size();
469  for (Size i = Size(0); i < len; ++i)
470  __safe_iterators[i]->clear();
471  }
472 
473  template < typename Key, typename Val, typename Alloc >
475  // update all the registered iterators: they should now point to nullptr
476  // and they are positioned to the end of the hashtable.
477  __clearIterators();
478 
479  // remove the buckets
480  for (Size i = Size(0); i < __size; ++i)
481  __nodes[i].clear();
482 
483  __nb_elements = Size(0);
484  __begin_index = std::numeric_limits< Size >::max();
485  }
486 
487  template < typename Key, typename Val, typename Alloc >
489  // for debugging purposes
490  GUM_DESTRUCTOR(HashTable);
491 
492  // update all the registered iterators: they should now point to nullptr
493  // and their hashtable should be set to nullptr
494  __clearIterators();
495  }
496 
497  template < typename Key, typename Val, typename Alloc >
499  const HashTable< Key, Val, Alloc >& from) {
500  // avoid self assignment
501  if (this != &from) {
502  // for debugging purposes
503  GUM_OP_CPY(HashTable);
504 
505  // first remove the current content of the hashtable and make
506  // the iterators point to end
507  clear();
508 
509  // if sizes of from's and this' __nodes vectors are not the same,
510  // we need to remove the current __nodes' array and to create a
511  // new array with the correct size
512  if (__size != from.__size) {
513  __nodes.resize(from.__size);
514 
515  for (Size i = Size(0); i < from.__size; ++i) {
516  __nodes[i].setAllocator(__alloc);
517  }
518 
519  __size = from.__size;
520 
521  // update the hash function : this is important as the computation of
522  // the hash values heavily depends on the size of the hash table
523  __hash_func.resize(__size);
524  }
525 
526  __resize_policy = from.__resize_policy;
527  __key_uniqueness_policy = from.__key_uniqueness_policy;
528  __begin_index = from.__begin_index;
529 
530  // perform the copy
531  __copy(from);
532  }
533 
534  return *this;
535  }
536 
537  template < typename Key, typename Val, typename Alloc >
538  template < typename OtherAlloc >
540  const HashTable< Key, Val, OtherAlloc >& from) {
541  // avoid self assignment
542  if (this != reinterpret_cast< const HashTable< Key, Val, Alloc >* >(&from)) {
543  // for debugging purposes
544  GUM_OP_CPY(HashTable);
545 
546  // first remove the current content of the hashtable and make
547  // the iterators point to end
548  clear();
549 
550  // if sizes of from's and this' __nodes vectors are not the same,
551  // we need to remove the current __nodes' array and to create a
552  // new array with the correct size
553  if (__size != from.__size) {
554  __nodes.resize(from.__size);
555 
556  for (Size i = 0; i < from.__size; ++i) {
557  __nodes[i].setAllocator(__alloc);
558  }
559 
560  __size = from.__size;
561 
562  // update the hash function : this is important as the computation of
563  // the hash values heavily depends on the size of the hash table
564  __hash_func.resize(__size);
565  }
566 
567  __resize_policy = from.__resize_policy;
568  __key_uniqueness_policy = from.__key_uniqueness_policy;
569  __begin_index = from.__begin_index;
570 
571  // perform the copy
572  __copy(from);
573  }
574 
575  return *this;
576  }
577 
578  template < typename Key, typename Val, typename Alloc >
581  // avoid self assignment
582  if (this != &table) {
583  // for debugging purposes
584  GUM_OP_MOV(HashTable);
585 
586  // first remove the current content of the hashtable and make
587  // the iterators point to end
588  clear();
589 
590  __nodes = std::move(table.__nodes);
591  __safe_iterators = std::move(table.__safe_iterators);
592  __alloc = std::move(table.__alloc);
593  __size = table.__size;
594  __nb_elements = table.__nb_elements;
595  __hash_func = table.__hash_func;
596  __resize_policy = table.__resize_policy;
597  __key_uniqueness_policy = table.__key_uniqueness_policy;
598  __begin_index = table.__begin_index;
599 
600  table.__size = 0; // necessary if we wish to perform moves iteratively,
601  // i.e. x = std::move ( y ); y = std::move ( z ); ...
602  }
603 
604  return *this;
605  }
606 
607  template < typename Key, typename Val, typename Alloc >
608  INLINE const typename HashTable< Key, Val, Alloc >::iterator&
610  // note that, here, we know for sure that HashTableIterEnd has been properly
611  // initialized as it is initialized by end4Statics, which is called by
612  // all hashtables' constructors
613  return *(reinterpret_cast< const iterator* >(
614  HashTableIteratorStaticEnd::__HashTableIterEnd));
615  }
616 
617  template < typename Key, typename Val, typename Alloc >
618  INLINE const typename HashTable< Key, Val, Alloc >::const_iterator&
620  // note that, here, we know for sure that HashTableIterEnd has been properly
621  // initialized as it is initialized by end4Statics, which is called by
622  // all hashtables' constructors
623  return *(reinterpret_cast< const const_iterator* >(
624  HashTableIteratorStaticEnd::__HashTableIterEnd));
625  }
626 
627  template < typename Key, typename Val, typename Alloc >
628  INLINE const typename HashTable< Key, Val, Alloc >::const_iterator&
630  // note that, here, we know for sure that HashTableIterEnd has been properly
631  // initialized as it is initialized by end4Statics, which is called by
632  // all hashtables' constructors
633  return *(reinterpret_cast< const const_iterator* >(
634  HashTableIteratorStaticEnd::__HashTableIterEnd));
635  }
636 
637  template < typename Key, typename Val, typename Alloc >
640  // if the table is empty, make the begin and end point to the same element
641  if (__nb_elements == Size(0))
642  return iterator{end()};
643  else
644  return iterator{*this};
645  }
646 
647  template < typename Key, typename Val, typename Alloc >
650  // if the table is empty, make the begin and end point to the same element
651  if (__nb_elements == Size(0))
652  return const_iterator{end()};
653  else
654  return const_iterator{*this};
655  }
656 
657  template < typename Key, typename Val, typename Alloc >
660  // if the table is empty, make the begin and end point to the same element
661  if (__nb_elements == Size(0))
662  return const_iterator{cend()};
663  else
664  return const_iterator{*this};
665  }
666 
667  template < typename Key, typename Val, typename Alloc >
668  INLINE const typename HashTable< Key, Val, Alloc >::iterator_safe&
670  // note that, here, we know for sure that HashTableIterEnd has been properly
671  // initialized as it is initialized by end4Statics, which is called by
672  // all hashtables' constructors
673  return *(reinterpret_cast< const iterator_safe* >(
674  HashTableIteratorStaticEnd::__HashTableIterEndSafe));
675  }
676 
677  template < typename Key, typename Val, typename Alloc >
680  // note that, here, we know for sure that HashTableIterEnd has been properly
681  // initialized as it is initialized by end4Statics, which is called by
682  // all hashtables' constructors
683  return *(reinterpret_cast< const const_iterator_safe* >(
684  HashTableIteratorStaticEnd::__HashTableIterEndSafe));
685  }
686 
687  template < typename Key, typename Val, typename Alloc >
690  // note that, here, we know for sure that HashTableIterEnd has been properly
691  // initialized as it is initialized by end4Statics, which is called by
692  // all hashtables' constructors
693  return *(reinterpret_cast< const const_iterator_safe* >(
694  HashTableIteratorStaticEnd::__HashTableIterEndSafe));
695  }
696 
697  template < typename Key, typename Val, typename Alloc >
700  // if the table is empty, make the begin and end point to the same element
701  if (__nb_elements == Size(0))
702  return iterator_safe{endSafe()};
703  else
704  return iterator_safe{*this};
705  }
706 
707  template < typename Key, typename Val, typename Alloc >
710  // if the table is empty, make the begin and end point to the same element
711  if (__nb_elements == Size(0))
712  return const_iterator_safe{endSafe()};
713  else
714  return const_iterator_safe{*this};
715  }
716 
717  template < typename Key, typename Val, typename Alloc >
720  // if the table is empty, make the begin and end point to the same element
721  if (__nb_elements == Size(0))
722  return const_iterator_safe{cendSafe()};
723  else
724  return const_iterator_safe{*this};
725  }
726 
727  template < typename Key, typename Val, typename Alloc >
728  INLINE Val& HashTable< Key, Val, Alloc >::operator[](const Key& key) {
729  return __nodes[__hash_func(key)][key];
730  }
731 
732  template < typename Key, typename Val, typename Alloc >
733  INLINE const Val&
735  return __nodes[__hash_func(key)][key];
736  }
737 
738  template < typename Key, typename Val, typename Alloc >
739  INLINE Size HashTable< Key, Val, Alloc >::size() const noexcept {
740  return __nb_elements;
741  }
742 
743  template < typename Key, typename Val, typename Alloc >
745  return __size;
746  }
747 
748  template < typename Key, typename Val, typename Alloc >
749  INLINE bool HashTable< Key, Val, Alloc >::exists(const Key& key) const {
750  return __nodes[__hash_func(key)].exists(key);
751  }
752 
753  template < typename Key, typename Val, typename Alloc >
755  const bool new_policy) noexcept {
756  __resize_policy = new_policy;
757  }
758 
759  template < typename Key, typename Val, typename Alloc >
760  INLINE bool HashTable< Key, Val, Alloc >::resizePolicy() const noexcept {
761  return __resize_policy;
762  }
763 
764  template < typename Key, typename Val, typename Alloc >
766  const bool new_policy) noexcept {
767  __key_uniqueness_policy = new_policy;
768  }
769 
770  template < typename Key, typename Val, typename Alloc >
772  return __key_uniqueness_policy;
773  }
774 
775  template < typename Key, typename Val, typename Alloc >
777  // new_size must be >= 2 else all the bits of the hash function are lost
778  new_size = std::max(Size(2), new_size);
779 
780  // find the real size for allocation (the smallest power of 2 greater
781  // than or equal to new_size) and get its base-2 logarithm
782  int log_size = __hashTableLog2(new_size);
783  new_size = Size(1) << log_size;
784 
785  // check if the new size is different from the actual size
786  // if not, nothing else need be done
787 
788  if (new_size != __size) {
789  // under automatic resize policy, check if the new size leaves
790  // enough space for storing all the current elements
791  if (!__resize_policy
792  || (__nb_elements
793  <= new_size * HashTableConst::default_mean_val_by_slot)) {
794  // create a new array of __nodes to store the elements
795  std::vector< HashTableList< Key, Val, Alloc > > new_nodes(new_size);
796 
797  for (auto& list: new_nodes) {
798  list.setAllocator(__alloc);
799  }
800 
801  // set the new hash function
802  __hash_func.resize(new_size);
803 
804  // put all the elements of the current __nodes array into the new one
805  Bucket* bucket;
806  Size new_hashed_key;
807 
808  for (Size i = Size(0); i < __size; ++i) {
809  while ((bucket = __nodes[i].__deb_list) != nullptr) {
810  // compute the new hashed key
811  new_hashed_key = __hash_func(bucket->key());
812 
813  // remove the bucket from the list of buckets of the current
814  // node vector
815  __nodes[i].__deb_list = bucket->next;
816 
817  // put the bucket into the new __nodes vector
818  new_nodes[new_hashed_key].insert(bucket);
819  }
820  }
821 
822  // update the size of the hash table
823  __size = new_size;
824  __begin_index = std::numeric_limits< Size >::max();
825 
826  // substitute the current __nodes array by the new one
827  std::swap(__nodes, new_nodes);
828 
829  // update the iterators
830  for (auto iter: __safe_iterators) {
831  if (iter->__bucket)
832  iter->__index = __hash_func(iter->__bucket->key());
833  else {
834  iter->__next_bucket = nullptr;
835  iter->__index = 0;
836  }
837  }
838  }
839  }
840  }
841 
842  template < typename Key, typename Val, typename Alloc >
843  void
845  Size hash_key = __hash_func(bucket->key());
846 
847  // check that there does not already exist an element with the same key
848  if (__key_uniqueness_policy && __nodes[hash_key].exists(bucket->key())) {
849  // remove the bucket from memory
850  Key k = bucket->key();
851  __alloc.destroy(bucket);
852  __alloc.deallocate(bucket, 1);
854  "the hashtable contains an element with the same key (" << k
855  << ")");
856  }
857 
858  // check whether there is sufficient space to insert the new pair
859  // if not, resize the current hashtable
860  if (__resize_policy
861  && (__nb_elements >= __size * HashTableConst::default_mean_val_by_slot)) {
862  resize(__size << 1);
863  hash_key = __hash_func(bucket->key());
864  }
865 
866  // add the new pair
867  __nodes[hash_key].insert(bucket);
868  ++__nb_elements;
869 
870  // recompute the index of the beginning of the hashtable if possible
871  // WARNING: if __begin_index = std::numeric_limits<Size>::max (), we CANNOT
872  // recompute the index because we cannot know whether the current index is
873  // equal to max because there was no element in the hashtable or whether a
874  // previous __erase() has set the index to max.
875  if (__begin_index < hash_key) { __begin_index = hash_key; }
876  }
877 
878  template < typename Key, typename Val, typename Alloc >
880  HashTable< Key, Val, Alloc >::insert(const Key& thekey, const Val& theval) {
881  Bucket* bucket = __alloc.allocate(1);
882 
883  try {
884  __alloc.construct(bucket, thekey, theval);
885  } catch (...) {
886  __alloc.deallocate(bucket, 1);
887  throw;
888  }
889 
890  __insert(bucket);
891  return bucket->elt();
892  }
893 
894  template < typename Key, typename Val, typename Alloc >
896  HashTable< Key, Val, Alloc >::insert(Key&& thekey, Val&& theval) {
897  Bucket* bucket = __alloc.allocate(1);
898 
899  try {
900  __alloc.construct(bucket, std::move(thekey), std::move(theval));
901  } catch (...) {
902  __alloc.deallocate(bucket, 1);
903  throw;
904  }
905 
906  __insert(bucket);
907  return bucket->elt();
908  }
909 
910  template < typename Key, typename Val, typename Alloc >
912  HashTable< Key, Val, Alloc >::insert(const std::pair< Key, Val >& elt) {
913  Bucket* bucket = __alloc.allocate(1);
914 
915  try {
916  __alloc.construct(bucket, reinterpret_cast< const value_type& >(elt));
917  } catch (...) {
918  __alloc.deallocate(bucket, 1);
919  throw;
920  }
921 
922  __insert(bucket);
923  return bucket->elt();
924  }
925 
926  template < typename Key, typename Val, typename Alloc >
928  HashTable< Key, Val, Alloc >::insert(std::pair< Key, Val >&& elt) {
929  Bucket* bucket = __alloc.allocate(1);
930 
931  try {
932  __alloc.construct(bucket, std::move(reinterpret_cast< value_type& >(elt)));
933  } catch (...) {
934  __alloc.deallocate(bucket, 1);
935  throw;
936  }
937 
938  __insert(bucket);
939  return bucket->elt();
940  }
941 
942  template < typename Key, typename Val, typename Alloc >
943  template < typename... Args >
946  Bucket* bucket = __alloc.allocate(1);
947 
948  try {
949  __alloc.construct(bucket,
951  std::forward< Args >(args)...);
952  } catch (...) {
953  __alloc.deallocate(bucket, 1);
954  throw;
955  }
956 
957  __insert(bucket);
958  return bucket->elt();
959  }
960 
961  template < typename Key, typename Val, typename Alloc >
964  const Val& default_value) {
965  Bucket* bucket = __nodes[__hash_func(key)].bucket(key);
966 
967  if (bucket == nullptr)
968  return insert(key, default_value).second;
969  else
970  return bucket->val();
971  }
972 
973  template < typename Key, typename Val, typename Alloc >
975  HashTable< Key, Val, Alloc >::getWithDefault(Key&& key, Val&& default_value) {
976  Bucket* bucket = __nodes[__hash_func(key)].bucket(key);
977 
978  if (bucket == nullptr)
979  return insert(std::move(key), std::move(default_value)).second;
980  else
981  return bucket->val();
982  }
983 
984  template < typename Key, typename Val, typename Alloc >
985  INLINE void HashTable< Key, Val, Alloc >::set(const Key& key, const Val& value) {
986  Bucket* bucket = __nodes[__hash_func(key)].bucket(key);
987 
988  if (bucket == nullptr)
989  insert(key, value);
990  else
991  bucket->val() = value;
992  }
993 
994  template < typename Key, typename Val, typename Alloc >
996  Size index) {
997  if (bucket == nullptr) return;
998 
999  // update the registered iterators pointing to this bucket
1000  for (auto iter: __safe_iterators) {
1001  if (iter->__bucket == bucket) {
1002  iter->operator++();
1003  iter->__next_bucket = iter->__bucket;
1004  iter->__bucket = nullptr;
1005  } else if (iter->__next_bucket == bucket) {
1006  iter->__bucket = bucket;
1007  iter->operator++();
1008  iter->__next_bucket = iter->__bucket;
1009  iter->__bucket = nullptr;
1010  }
1011  }
1012 
1013  // remove the element from the __nodes vector
1014  __nodes[index].erase(bucket);
1015 
1016  --__nb_elements;
1017 
1018  if ((index == __begin_index) && __nodes[index].empty()) {
1019  __begin_index = std::numeric_limits< Size >::max();
1020  }
1021  }
1022 
1023  template < typename Key, typename Val, typename Alloc >
1024  INLINE void HashTable< Key, Val, Alloc >::erase(const Key& key) {
1025  // get the hashed key
1026  Size hash = __hash_func(key);
1027 
1028  // get the bucket containing the element to erase
1029  HashTableBucket< Key, Val >* bucket = __nodes[hash].bucket(key);
1030 
1031  __erase(bucket, hash);
1032  }
1033 
1034  template < typename Key, typename Val, typename Alloc >
1036  __erase(iter.__getBucket(), iter.__getIndex());
1037  }
1038 
1039  template < typename Key, typename Val, typename Alloc >
1040  INLINE void
1042  __erase(iter.__getBucket(), iter.__getIndex());
1043  }
1044 
1045  template < typename Key, typename Val, typename Alloc >
1046  INLINE void HashTable< Key, Val, Alloc >::eraseByVal(const Val& val) {
1047  for (auto iter = cbegin(); iter != cend(); ++iter)
1048  if (iter.__bucket->val() == val) {
1049  __erase(iter.__getBucket(), iter.__getIndex());
1050  return;
1051  }
1052  }
1053 
1054  template < typename Key, typename Val, typename Alloc >
1055  INLINE void HashTable< Key, Val, Alloc >::reset(const Key& key) {
1056  erase(key);
1057  }
1058 
1059  template < typename Key, typename Val, typename Alloc >
1060  INLINE const Key& HashTable< Key, Val, Alloc >::keyByVal(const Val& val) const {
1061  for (auto iter = begin(); iter != end(); ++iter)
1062  if (iter.__bucket->val() == val) return iter.key();
1063 
1064  GUM_ERROR(NotFound, "not enough elements in the chained list");
1065  }
1066 
1067  template < typename Key, typename Val, typename Alloc >
1068  INLINE const Key& HashTable< Key, Val, Alloc >::key(const Key& key) const {
1069  // get the bucket corresponding to the key
1070  Bucket* bucket = __nodes[__hash_func(key)].bucket(key);
1071 
1072  if (bucket == nullptr) {
1073  GUM_ERROR(NotFound, "key does not belong to the hashtable");
1074  }
1075 
1076  return bucket->key();
1077  }
1078 
1079  template < typename Key, typename Val, typename Alloc >
1081  for (auto iterAll = cbeginSafe(); iterAll != cendSafe(); ++iterAll) {
1082  if (iterAll.__bucket->val() == val) {
1083  __erase(iterAll.__bucket, iterAll.__index);
1084  }
1085  }
1086  }
1087 
1088  template < typename Key, typename Val, typename Alloc >
1089  INLINE bool HashTable< Key, Val, Alloc >::empty() const noexcept {
1090  return (__nb_elements == Size(0));
1091  }
1092 
1093  template < typename Key, typename Val, typename Alloc >
1094  template < typename Mount, typename OtherAlloc >
1096  Mount (*f)(Val), Size size, bool resize_pol, bool key_uniqueness_pol) const {
1097  // determine the proper size of the hashtable
1098  // by default, the size of the table is set so that the table does not take
1099  // too much space while allowing to add a few elements without needing to
1100  // resize in autmatic resizing mode
1101  if (size == 0) size = std::max(Size(2), __nb_elements / 2);
1102 
1103  // create a new table
1105  size, resize_pol, key_uniqueness_pol);
1106 
1107  // fill the new hash table
1108  for (auto iter = begin(); iter != end(); ++iter) {
1109  table.insert(iter.key(), f(iter.val()));
1110  }
1111 
1112  return table;
1113  }
1114 
1115  template < typename Key, typename Val, typename Alloc >
1116  template < typename Mount, typename OtherAlloc >
1118  Mount (*f)(Val&), Size size, bool resize_pol, bool key_uniqueness_pol) const {
1119  // determine the proper size of the hashtable
1120  // by default, the size of the table is set so that the table does not take
1121  // too much space while allowing to add a few elements without needing to
1122  // resize in autmatic resizing mode
1123  if (size == Size(0)) size = std::max(Size(2), __nb_elements / 2);
1124 
1125  // create a new table
1127  size, resize_pol, key_uniqueness_pol);
1128 
1129  // fill the new hash table
1130  for (auto iter = begin(); iter != end(); ++iter) {
1131  table.insert(iter.key(), f(const_cast< Val& >(iter.val())));
1132  }
1133 
1134  return table;
1135  }
1136 
1137  template < typename Key, typename Val, typename Alloc >
1138  template < typename Mount, typename OtherAlloc >
1140  INLINE HashTable< Key, Val, Alloc >::map(Mount (*f)(const Val&),
1141  Size size,
1142  bool resize_pol,
1143  bool key_uniqueness_pol) const {
1144  // determine the proper size of the hashtable
1145  // by default, the size of the table is set so that the table does not take
1146  // too much space while allowing to add a few elements without needing to
1147  // resize in autmatic resizing mode
1148  if (size == Size(0)) size = std::max(Size(2), __nb_elements / 2);
1149 
1150  // create a new table
1152  size, resize_pol, key_uniqueness_pol);
1153 
1154  // fill the new hash table
1155  for (auto iter = begin(); iter != end(); ++iter) {
1156  table.insert(iter.key(), f(iter.val()));
1157  }
1158 
1159  return table;
1160  }
1161 
1162  template < typename Key, typename Val, typename Alloc >
1163  template < typename Mount, typename OtherAlloc >
1165  const Mount& val, Size size, bool resize_pol, bool key_uniqueness_pol) const {
1166  // determine the proper size of the hashtable
1167  // by default, the size of the table is set so that the table does not take
1168  // too much space while allowing to add a few elements without needing to
1169  // resize in autmatic resizing mode
1170  if (size == Size(0)) size = std::max(Size(2), __nb_elements / 2);
1171 
1172  // create a new table
1174  size, resize_pol, key_uniqueness_pol);
1175 
1176  // fill the new hash table
1177  for (auto iter = begin(); iter != end(); ++iter) {
1178  table.insert(iter.key(), val);
1179  }
1180 
1181  return table;
1182  }
1183 
1184  template < typename Key, typename Val, typename Alloc >
1185  template < typename OtherAlloc >
1187  const HashTable< Key, Val, OtherAlloc >& from) const {
1188  // checks whether the two hashtables contain the same number of elements
1189  if (from.__nb_elements != __nb_elements) return false;
1190 
1191  // parse this and check that each element also belongs to from
1192  for (auto iter = begin(); iter != end(); ++iter) {
1193  try {
1194  if (iter.val() != from[iter.key()]) return false;
1195  } catch (NotFound&) { return false; }
1196  }
1197 
1198  return true;
1199  }
1200 
1201  template < typename Key, typename Val, typename Alloc >
1202  template < typename OtherAlloc >
1204  const HashTable< Key, Val, OtherAlloc >& from) const {
1205  return !operator==(from);
1206  }
1207 
1208  template < typename Key, typename Val, typename Alloc >
1209  std::ostream& operator<<(std::ostream& stream,
1210  const HashTableList< Key, Val, Alloc >& list) {
1211  bool deja = false;
1212  stream << "[";
1213 
1214  for (HashTableBucket< Key, Val >* ptr = list.__deb_list; ptr;
1215  ptr = ptr->list.next, deja = true) {
1216  if (deja) stream << " , ";
1217 
1218  stream << ptr->key() << "=>" << ptr->val();
1219  }
1220 
1221  stream << "]";
1222 
1223  return stream;
1224  }
1225 
1226  template < typename Key, typename Val, typename Alloc >
1227  std::ostream& operator<<(std::ostream& stream,
1228  const HashTableList< Key*, Val, Alloc >& list) {
1229  bool deja = false;
1230  stream << "[";
1231 
1232  for (HashTableBucket< Key, Val >* ptr = list.__deb_list; ptr;
1233  ptr = ptr->list.next, deja = true) {
1234  if (deja) stream << " , ";
1235 
1236  stream << ptr->key() << "=>" << ptr->val();
1237  }
1238 
1239  stream << "]";
1240 
1241  return stream;
1242  }
1243 
1244  template < typename Key, typename Val, typename Alloc >
1245  std::ostream& operator<<(std::ostream& stream,
1246  const HashTable< Key, Val, Alloc >& table) {
1247  bool deja = false;
1248  stream << "{";
1249 
1250  for (Size i = Size(0); i < table.__size; ++i)
1251  for (auto ptr = table.__nodes[i].__deb_list; ptr; ptr = ptr->next) {
1252  if (deja) stream << " , ";
1253 
1254  stream << ptr->key() << "=>" << ptr->val();
1255 
1256  deja = true;
1257  }
1258 
1259  stream << "}";
1260 
1261  return stream;
1262  }
1263 
1264  template < typename Key, typename Val, typename Alloc >
1265  std::ostream& operator<<(std::ostream& stream,
1266  const HashTable< Key*, Val, Alloc >& table) {
1267  bool deja = false;
1268  stream << "{";
1269 
1270  for (Size i = Size(0); i < table.__size; ++i)
1271  for (auto ptr = table.__nodes[i].__deb_list; ptr; ptr = ptr->next) {
1272  if (deja) stream << " , ";
1273 
1274  stream << ptr->key() << "=>" << ptr->val();
1275 
1276  deja = true;
1277  }
1278 
1279  stream << "}";
1280 
1281  return stream;
1282  }
1283 
1284  // ===========================================================================
1285  // === SAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1286  // ===========================================================================
1287 
1288  template < typename Key, typename Val >
1289  INLINE void
1291  __table->__safe_iterators.push_back(
1292  const_cast< HashTableConstIteratorSafe< Key, Val >* >(this));
1293  }
1294 
1295  template < typename Key, typename Val >
1296  INLINE void
1298  if (__table == nullptr) return;
1299 
1300  // find where the iterator is
1301  std::vector< HashTableConstIteratorSafe< Key, Val >* >& iter_vect =
1302  __table->__safe_iterators;
1303 
1304  auto len = iter_vect.size();
1305  for (Size i = Size(0); i < len; ++i) {
1306  if (iter_vect[i] == this) {
1307  iter_vect.erase(iter_vect.begin() + i);
1308  break;
1309  }
1310  }
1311  }
1312 
1313  template < typename Key, typename Val >
1315  // for debugging purposes
1316  GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1317  }
1318 
1319  template < typename Key, typename Val >
1320  template < typename Alloc >
1322  const HashTable< Key, Val, Alloc >& tab) :
1323  __table{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1324  // for debugging purposes
1325  GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1326 
1327  // make the hashtable keep track of this iterator
1328  __insertIntoSafeList();
1329 
1330  if (__table->__nb_elements) {
1331  if (__table->__begin_index != std::numeric_limits< Size >::max()) {
1332  __index = __table->__begin_index;
1333  __bucket = __table->__nodes[__index].__end_list;
1334  } else {
1335  // find the element we shall point to from the start of the hashtable
1336  for (Size i = __table->__size - Size(1);; --i) { // no test on i since
1337  // __nb_elements != 0
1338  if (__table->__nodes[i].__nb_elements) {
1339  __index = i;
1340  __bucket = __table->__nodes[__index].__end_list;
1341  __table->__begin_index = __index;
1342  break;
1343  }
1344  }
1345  }
1346  }
1347  }
1348 
1349  template < typename Key, typename Val >
1350  template < typename Alloc >
1352  const HashTable< Key, Val, Alloc >& tab, Size ind_elt) :
1353  __table{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1354  Size i;
1355 
1356  // check if we are looking for a begin() and we know for sure its index
1357  if ((ind_elt == Size(0))
1358  && (__table->__begin_index != std::numeric_limits< Size >::max())) {
1359  __index = __table->__begin_index;
1360  __bucket = __table->__nodes[__index].__end_list;
1361  } else {
1362  // check if it is faster to find the ind_eltth element from the start or
1363  // from the end of the hashtable
1364  if (ind_elt < (__table->__nb_elements >> 1)) {
1365  // find the element we shall point to from the start of the hashtable
1366  for (i = __table->__size - 1;; --i) { // no test on i since
1367  // ind_elt < _table->__nb_elements
1368  if (__table->__nodes[i].__nb_elements) {
1369  if (ind_elt >= __table->__nodes[i].__nb_elements)
1370  ind_elt -= __table->__nodes[i].__nb_elements;
1371  else {
1372  for (__bucket = __table->__nodes[i].__end_list; ind_elt;
1373  --ind_elt, __bucket = __bucket->prev) {}
1374 
1375  __index = i;
1376  break;
1377  }
1378  }
1379  }
1380  } else {
1381  // ind_elt = the index of the element we should point to
1382  // check if the index passed as parameter is valid
1383  if (ind_elt >= __table->__nb_elements) {
1385  "Not enough elements in the hashtable");
1386  }
1387 
1388  // find the element we shall point to from the end of the hashtable
1389  for (i = 0, ind_elt = __table->__nb_elements - ind_elt - 1;; ++i) {
1390  if (__table->__nodes[i].__nb_elements) {
1391  if (ind_elt >= __table->__nodes[i].__nb_elements)
1392  ind_elt -= __table->__nodes[i].__nb_elements;
1393  else {
1394  for (__bucket = __table->__nodes[i].__deb_list; ind_elt;
1395  --ind_elt, __bucket = __bucket->next) {}
1396 
1397  __index = i;
1398  break;
1399  }
1400  }
1401  }
1402  }
1403  }
1404 
1405  // for debugging purposes
1406  GUM_CONSTRUCTOR(HashTableConstIteratorSafe);
1407 
1408  // make the hashtable keep track of this iterator
1409  __insertIntoSafeList();
1410  }
1411 
1412  template < typename Key, typename Val >
1415  __table{from.__table},
1416  __index{from.__index}, __bucket{from.__bucket}, __next_bucket{
1417  from.__next_bucket} {
1418  // make the hashtable keep track of this iterator
1419  if (__table != nullptr) { __insertIntoSafeList(); }
1420 
1421  // for debugging purposes
1422  GUM_CONS_CPY(HashTableConstIteratorSafe);
1423  }
1424 
1425  template < typename Key, typename Val >
1427  const HashTableConstIterator< Key, Val >& from) :
1428  __table{from.__table},
1429  __index{from.__index}, __bucket{from.__bucket} {
1430  // make the hashtable keep track of this iterator
1431  if (__table != nullptr) { __insertIntoSafeList(); }
1432 
1433  // for debugging purposes
1434  GUM_CONS_CPY(HashTableConstIteratorSafe);
1435  }
1436 
1437  template < typename Key, typename Val >
1440  __table{from.__table},
1441  __index{from.__index}, __bucket{from.__bucket}, __next_bucket{
1442  from.__next_bucket} {
1443  GUM_CONS_MOV(HashTableConstIteratorSafe);
1444 
1445  // find "from" in the hashtable's list of safe iterators and substitute
1446  // it by this
1447  if (__table != nullptr) {
1448  std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect =
1449  __table->__safe_iterators;
1450 
1451  for (auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1452  if (*ptr == &from) {
1453  *ptr = this;
1454  from.__table = nullptr;
1455  break;
1456  }
1457  }
1458  }
1459  }
1460 
1461  template < typename Key, typename Val >
1462  INLINE
1464  Val >::~HashTableConstIteratorSafe() noexcept {
1465  // for debugging purposes
1466  GUM_DESTRUCTOR(HashTableConstIteratorSafe);
1467 
1468  // remove the iterator from the table's iterator list
1469  __removeFromSafeList();
1470  }
1471 
1472  template < typename Key, typename Val >
1476  // here, no need to avoid self assignment: this would slow down normal
1477  // assignments and, in any case, this would not result in an iterator in
1478  // an incoherent state
1479  // check if the current hashtable is different from that of "from". In such
1480  // a case, we shall remove the iterator from its current hashtable
1481  // iterator's
1482  // list and add it to the new hashtable iterator's list
1483  if (__table != from.__table) {
1484  // remove the iterator from its hashtable iterator's list'
1485  __removeFromSafeList();
1486 
1487  __table = from.__table;
1488 
1489  // add to the new table
1490  if (__table) { __insertIntoSafeList(); }
1491  }
1492 
1493  __index = from.__index;
1494  __bucket = from.__bucket;
1495  __next_bucket = from.__next_bucket;
1496 
1497  return *this;
1498  }
1499 
1500  template < typename Key, typename Val >
1503  const HashTableConstIterator< Key, Val >& from) {
1504  // here, no need to avoid self assignment: this would slow down normal
1505  // assignments and, in any case, this would not result in an iterator in
1506  // an incoherent state
1507  // check if the current hashtable is different from that of "from". In such
1508  // a case, we shall remove the iterator from its current hashtable
1509  // iterator's
1510  // list and add it to the new hashtable iterator's list
1511  if (__table != from.__table) {
1512  // remove the iterator from its hashtable iterator's list'
1513  __removeFromSafeList();
1514 
1515  __table = from.__table;
1516 
1517  // add to the new table
1518  if (__table) { __insertIntoSafeList(); }
1519  }
1520 
1521  __index = from.__index;
1522  __bucket = from.__bucket;
1523  __next_bucket = nullptr;
1524 
1525  return *this;
1526  }
1527 
1528  template < typename Key, typename Val >
1531  HashTableConstIteratorSafe< Key, Val >&& from) noexcept {
1532  // here, no need to avoid self assignment: this would slow down normal
1533  // assignments and, in any case, this would not result in an iterator in
1534  // an incoherent state
1535  // check if the current hashtable is different from that of "from". In such
1536  // a case, we shall remove the iterator from its current hashtable
1537  // iterator's
1538  // list and add it to the new hashtable iterator's list
1539  if (__table != from.__table) {
1540  // remove the iterator from its hashtable iterator's list'
1541  __removeFromSafeList();
1542 
1543  if (from.__table != nullptr) {
1544  // substitute from by this in the list of safe iterators
1545  std::vector< HashTableConstIteratorSafe< Key, Val >* >& vect =
1546  from.__table->__safe_iterators;
1547 
1548  for (auto ptr = vect.rbegin(); ptr != vect.rend(); ++ptr) {
1549  if (*ptr == &from) {
1550  *ptr = this;
1551  break;
1552  }
1553  }
1554  }
1555 
1556  __table = from.__table;
1557  from.__table = nullptr;
1558  }
1559 
1560  __index = from.__index;
1561  __bucket = from.__bucket;
1562  __next_bucket = from.__next_bucket;
1563 
1564  return *this;
1565  }
1566 
1567  template < typename Key, typename Val >
1570  if (__bucket != nullptr)
1571  return __bucket->key();
1572  else {
1573  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
1574  }
1575  }
1576 
1577  template < typename Key, typename Val >
1580  if (__bucket != nullptr)
1581  return __bucket->val();
1582  else {
1583  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
1584  }
1585  }
1586 
1587  template < typename Key, typename Val >
1589  // remove the iterator from the table's iterator list
1590  __removeFromSafeList();
1591 
1592  // set its table as well as the element it points to to 0
1593  __table = nullptr;
1594  __bucket = nullptr;
1595  __next_bucket = nullptr;
1596  __index = Size(0);
1597  }
1598 
1599  // WARNING: never inline this function: this result in g++4.3.3 producing a
1600  // code that segfaults.
1601  template < typename Key, typename Val >
1604  // if __bucket != nullptr then use it, else use next_bucket
1605  if (__bucket == nullptr) {
1606  // note that this case only happens when the iterator pointed to an
1607  // element
1608  // that has just been erased. Fortunately, in this case, the Hashtable's
1609  // erase functions update appropriately the __next_bucket and __index
1610  // fields.
1611  __bucket = __next_bucket;
1612  __next_bucket = nullptr;
1613  } else {
1614  // ok, here we can use __bucket as a starting point
1615 
1616  // if we are not pointing on the first element of the chained list, just
1617  // point to the preceding bucket in this list
1618  if (__bucket->prev) {
1619  __bucket = __bucket->prev;
1620  // here, no need to update __next_bucket, which is compulsorily
1621  // equal to nullptr, nor __index which has not changed.
1622  } else {
1623  // ok, here we are on the beginning of a chained list,
1624  // so 2 cases can obtain:
1625  // 1/ index = 0 : then we have reached the end of the hashtable
1626  // 2/ index != 0 => we must search for a new slot containing elements
1627 
1628  // case 1:
1629  if (__index == Size(0)) {
1630  __bucket = nullptr;
1631  // we are thus at the end() of the hashTable
1632  }
1633  // case 2:
1634  else {
1635  // arrived here, we need to parse the hash table until we find a new
1636  // bucket because we are pointing on a chained list with no more
1637  // element
1638  // to the left of the current element
1639  if (__index > Size(0)) {
1640  for (Size i = __index - Size(1); i > Size(0); --i) {
1641  if (__table->__nodes[i].__nb_elements) {
1642  __index = i;
1643  __bucket = __table->__nodes[i].__end_list;
1644  return *this;
1645  }
1646  }
1647  }
1648 
1649  if (__table->__nodes[0].__nb_elements)
1650  __bucket = __table->__nodes[0].__end_list;
1651  else
1652  __bucket = nullptr;
1653 
1654  __index = 0;
1655  }
1656  }
1657  }
1658 
1659  return *this;
1660  }
1661 
1662  template < typename Key, typename Val >
1665  if ((nb == Size(0)) || (__table == nullptr)) return *this;
1666 
1667  // if __bucket != nullptr then use it, else use next_bucket
1668  if (__bucket == nullptr) {
1669  // note that this case only happens when the iterator pointed to an
1670  // element
1671  // that has just been erased. Fortunately, in this case, the Hashtable's
1672  // erase functions update appropriately the __next_bucket and __index
1673  // fields.
1674  __bucket = __next_bucket;
1675  __next_bucket = nullptr;
1676  --nb;
1677  }
1678 
1679  // ok, here we can use __bucket as a starting point: parse all the elements
1680  // of the current chained list
1681  for (; nb && __bucket != nullptr; --nb, __bucket = __bucket->prev) {}
1682 
1683  if (__bucket != nullptr) return *this;
1684 
1685  // here, we shall skip all the chained list that have not sufficiently
1686  // many elements
1687  --__index;
1688 
1689  for (; __index < __table->__size
1690  && nb >= __table->__nodes[__index].__nb_elements;
1691  nb -= __table->__nodes[__index].__nb_elements, --__index) {}
1692 
1693  // here: either __index >= __table->__size, which means that we did not find
1694  // the element we looked for, i.e., we are at the end of the hashtable, or
1695  // nb < __table->__nodes[__index].__nb_elements, and we should parse the
1696  // chained list to get the element (which, we know for sure, exists)
1697  if (__index >= __table->__size) {
1698  __index = Size(0);
1699  return *this;
1700  }
1701 
1702  for (__bucket = __table->__nodes[__index].__end_list; nb;
1703  --nb, __bucket = __bucket->prev) {}
1704 
1705  return *this;
1706  }
1707 
1708  template < typename Key, typename Val >
1711  return HashTableConstIteratorSafe< Key, Val >{*this} += nb;
1712  }
1713 
1714  template < typename Key, typename Val >
1716  const HashTableConstIteratorSafe< Key, Val >& from) const noexcept {
1717  return ((__bucket != from.__bucket) || (__index != from.__index));
1718  }
1719 
1720  template < typename Key, typename Val >
1722  const HashTableConstIteratorSafe< Key, Val >& from) const noexcept {
1723  return ((__bucket == from.__bucket) && (__index == from.__index));
1724  }
1725 
1726  template < typename Key, typename Val >
1729  if (__bucket)
1730  return __bucket->elt();
1731  else {
1732  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
1733  }
1734  }
1735 
1736  template < typename Key, typename Val >
1739  return __bucket;
1740  }
1741 
1742  template < typename Key, typename Val >
1744  return __index;
1745  }
1746 
1747  // ===========================================================================
1748  // === SAFE HASH TABLE ITERATORS IMPLEMENTATION ===
1749  // ===========================================================================
1750 
1751  template < typename Key, typename Val >
1753  HashTableConstIteratorSafe< Key, Val >() {
1754  GUM_CONSTRUCTOR(HashTableIteratorSafe);
1755  }
1756 
1757  template < typename Key, typename Val >
1758  template < typename Alloc >
1760  const HashTable< Key, Val, Alloc >& tab) :
1761  HashTableConstIteratorSafe< Key, Val >(tab) {
1762  GUM_CONSTRUCTOR(HashTableIteratorSafe);
1763  }
1764 
1765  template < typename Key, typename Val >
1766  template < typename Alloc >
1768  const HashTable< Key, Val, Alloc >& tab, Size ind_elt) :
1769  HashTableConstIteratorSafe< Key, Val >(tab, ind_elt) {
1770  GUM_CONSTRUCTOR(HashTableIteratorSafe);
1771  }
1772 
1773  template < typename Key, typename Val >
1775  const HashTableIteratorSafe< Key, Val >& from) :
1776  HashTableConstIteratorSafe< Key, Val >(from) {
1777  GUM_CONS_CPY(HashTableIteratorSafe);
1778  }
1779 
1780  template < typename Key, typename Val >
1782  const HashTableIterator< Key, Val >& from) :
1783  HashTableConstIteratorSafe< Key, Val >(from) {
1784  GUM_CONS_CPY(HashTableIteratorSafe);
1785  }
1786 
1787  template < typename Key, typename Val >
1789  HashTableIteratorSafe< Key, Val >&& from) noexcept :
1790  HashTableConstIteratorSafe< Key, Val >(std::move(from)) {
1791  GUM_CONS_MOV(HashTableIteratorSafe);
1792  }
1793 
1794  template < typename Key, typename Val >
1796  GUM_DESTRUCTOR(HashTableIteratorSafe);
1797  }
1798 
1799  template < typename Key, typename Val >
1802  return const_cast< Val& >(HashTableConstIteratorSafe< Key, Val >::val());
1803  }
1804 
1805  template < typename Key, typename Val >
1808  const HashTableIteratorSafe< Key, Val >& from) {
1809  GUM_OP_CPY(HashTableIteratorSafe);
1811  return *this;
1812  }
1813 
1814  template < typename Key, typename Val >
1817  const HashTableIterator< Key, Val >& from) {
1818  GUM_OP_CPY(HashTableIteratorSafe);
1820  return *this;
1821  }
1822 
1823  template < typename Key, typename Val >
1826  HashTableIteratorSafe< Key, Val >&& from) noexcept {
1828  return *this;
1829  }
1830 
1831  template < typename Key, typename Val >
1835  return *this;
1836  }
1837 
1838  template < typename Key, typename Val >
1842  return *this;
1843  }
1844 
1845  template < typename Key, typename Val >
1849  iter += nb;
1850  return iter;
1851  }
1852 
1853  template < typename Key, typename Val >
1855  const HashTableIteratorSafe< Key, Val >& from) const noexcept {
1857  }
1858 
1859  template < typename Key, typename Val >
1861  const HashTableIteratorSafe< Key, Val >& from) const noexcept {
1863  }
1864 
1865  template < typename Key, typename Val >
1868  return const_cast< Val& >(HashTableConstIteratorSafe< Key, Val >::operator*());
1869  }
1870 
1871  template < typename Key, typename Val >
1872  INLINE const typename HashTableIteratorSafe< Key, Val >::value_type&
1875  }
1876 
1877  // ===========================================================================
1878  // === UNSAFE HASH TABLE CONST ITERATORS IMPLEMENTATION ===
1879  // ===========================================================================
1880 
1881  template < typename Key, typename Val >
1883  GUM_CONSTRUCTOR(HashTableConstIterator);
1884  }
1885 
1886  template < typename Key, typename Val >
1887  template < typename Alloc >
1889  const HashTable< Key, Val, Alloc >& tab) noexcept :
1890  __table{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1891  // for debugging purposes
1892  GUM_CONSTRUCTOR(HashTableConstIterator);
1893 
1894  if (__table->__nb_elements) {
1895  if (__table->__begin_index != std::numeric_limits< Size >::max()) {
1896  __index = __table->__begin_index;
1897  __bucket = __table->__nodes[__index].__end_list;
1898  } else {
1899  // find the element we shall point to from the start of the hashtable
1900  for (Size i = __table->__size - Size(1);; --i) { // no test on i since
1901  // __nb_elements != 0
1902  if (__table->__nodes[i].__nb_elements) {
1903  __index = i;
1904  __bucket = __table->__nodes[__index].__end_list;
1905  __table->__begin_index = __index;
1906  break;
1907  }
1908  }
1909  }
1910  }
1911  }
1912 
1913  template < typename Key, typename Val >
1914  template < typename Alloc >
1916  const HashTable< Key, Val, Alloc >& tab, Size ind_elt) :
1917  __table{reinterpret_cast< const HashTable< Key, Val >* >(&tab)} {
1918  Size i;
1919 
1920  // check if we are looking for a begin() and we know for sure its index
1921  if ((ind_elt == Size(0))
1922  && (__table->__begin_index != std::numeric_limits< Size >::max())) {
1923  __index = __table->__begin_index;
1924  __bucket = __table->__nodes[__index].__end_list;
1925  } else {
1926  // check if it is faster to find the ind_eltth element from the start or
1927  // from the end of the hashtable
1928  if (ind_elt < (__table->__nb_elements >> 1)) {
1929  // find the element we shall point to from the start of the hashtable
1930  for (i = __table->__size - 1;; --i) { // no test on i since
1931  // ind_elt < _table->__nb_elements
1932  if (__table->__nodes[i].__nb_elements) {
1933  if (ind_elt >= __table->__nodes[i].__nb_elements)
1934  ind_elt -= __table->__nodes[i].__nb_elements;
1935  else {
1936  for (__bucket = __table->__nodes[i].__end_list; ind_elt;
1937  --ind_elt, __bucket = __bucket->prev) {}
1938 
1939  __index = i;
1940  break;
1941  }
1942  }
1943  }
1944  } else {
1945  // ind_elt = the index of the element we should point to
1946  // check if the index passed as parameter is valid
1947  if (ind_elt >= __table->__nb_elements) {
1949  "Not enough elements in the hashtable");
1950  }
1951 
1952  // find the element we shall point to from the end of the hashtable
1953  for (i = 0, ind_elt = __table->__nb_elements - ind_elt - 1;; ++i) {
1954  if (__table->__nodes[i].__nb_elements) {
1955  if (ind_elt >= __table->__nodes[i].__nb_elements)
1956  ind_elt -= __table->__nodes[i].__nb_elements;
1957  else {
1958  for (__bucket = __table->__nodes[i].__deb_list; ind_elt;
1959  --ind_elt, __bucket = __bucket->next) {}
1960 
1961  __index = i;
1962  break;
1963  }
1964  }
1965  }
1966  }
1967  }
1968 
1969  // for debugging purposes
1970  GUM_CONSTRUCTOR(HashTableConstIterator);
1971  }
1972 
1973  template < typename Key, typename Val >
1975  const HashTableConstIterator< Key, Val >& from) noexcept :
1976  __table{from.__table},
1977  __index{from.__index}, __bucket{from.__bucket} {
1978  GUM_CONS_CPY(HashTableConstIterator);
1979  }
1980 
1981  template < typename Key, typename Val >
1983  HashTableConstIterator< Key, Val >&& from) noexcept :
1984  __table{from.__table},
1985  __index{from.__index}, __bucket{from.__bucket} {
1986  GUM_CONS_MOV(HashTableConstIterator);
1987  }
1988 
1989  template < typename Key, typename Val >
1991  // for debugging purposes
1992  GUM_DESTRUCTOR(HashTableConstIterator);
1993  }
1994 
1995  template < typename Key, typename Val >
1998  const HashTableConstIterator< Key, Val >& from) noexcept {
1999  // here, no need to avoid self assignment: this would slow down normal
2000  // assignments and, in any case, this would not result in an iterator in
2001  // an incoherent state
2002  __table = from.__table;
2003  __index = from.__index;
2004  __bucket = from.__bucket;
2005 
2006  return *this;
2007  }
2008 
2009  template < typename Key, typename Val >
2012  HashTableConstIterator< Key, Val >&& from) noexcept {
2013  // here, no need to avoid self assignment: this would slow down normal
2014  // assignments and, in any case, this would not result in an iterator in
2015  // an incoherent state
2016  __table = from.__table;
2017  __index = from.__index;
2018  __bucket = from.__bucket;
2019 
2020  return *this;
2021  }
2022 
2023  template < typename Key, typename Val >
2024  INLINE const typename HashTableConstIterator< Key, Val >::key_type&
2026  if (__bucket)
2027  return __bucket->pair.first;
2028  else {
2029  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
2030  }
2031  }
2032 
2033  template < typename Key, typename Val >
2036  if (__bucket)
2037  return __bucket->val();
2038  else {
2039  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
2040  }
2041  }
2042 
2043  template < typename Key, typename Val >
2045  __table = nullptr;
2046  __bucket = nullptr;
2047  __index = 0;
2048  }
2049 
2050  template < typename Key, typename Val >
2053  // if __bucket == nullptr then we are at the end of the hashtable
2054  if (__bucket == nullptr) return *this;
2055 
2056  // if we are not pointing on the first element of the chained list, just
2057  // point to the next bucket in this list
2058  if (__bucket->prev) {
2059  __bucket = __bucket->prev;
2060  // here, no need to update __index which has not changed.
2061  } else {
2062  // ok, here we are on the end of a chained list,
2063  // so 2 cases can obtain:
2064  // 1/ index = 0 : then we have reached the end of the hashtable
2065  // 2/ index != 0 => we must search for a new slot containing elements
2066 
2067  // case 1:
2068  if (__index == Size(0)) {
2069  __bucket = nullptr;
2070  // we are thus at the end() of the hashTable
2071  }
2072 
2073  // case 2:
2074  else {
2075  // arrived here, we need to parse the hash table until we find a new
2076  // bucket because we are pointing on a chained list with no more element
2077  // to the right of the current element
2078  for (Size i = __index - Size(1); i; --i) {
2079  if (__table->__nodes[i].__nb_elements) {
2080  __index = i;
2081  __bucket = __table->__nodes[i].__end_list;
2082  return *this;
2083  }
2084  }
2085 
2086  if (__table->__nodes[0].__nb_elements)
2087  __bucket = __table->__nodes[0].__end_list;
2088  else
2089  __bucket = nullptr;
2090 
2091  __index = Size(0);
2092  }
2093  }
2094 
2095  return *this;
2096  }
2097 
2098  template < typename Key, typename Val >
2101  if ((nb == 0) || (__table == nullptr) || (__bucket == nullptr)) return *this;
2102 
2103  // ok, here we can use __bucket as a starting point: parse all the elements
2104  // of the current chained list
2105  for (; nb && __bucket != nullptr; --nb, __bucket = __bucket->prev) {}
2106 
2107  if (__bucket != nullptr) return *this;
2108 
2109  // here, we shall skip all the chained list that have not sufficiently
2110  // many elements
2111  --__index;
2112 
2113  for (; __index < __table->__size
2114  && nb >= __table->__nodes[__index].__nb_elements;
2115  nb -= __table->__nodes[__index].__nb_elements, --__index) {}
2116 
2117  // here: either __index >= __table->__size, which means that we did not find
2118  // the element we looked for, i.e., we are at the end of the hashtable, or
2119  // nb < __table->__nodes[__index].__nb_elements, and we should parse the
2120  // chained list to get the element (which, we know for sure, exists)
2121  if (__index >= __table->__size) {
2122  __index = 0;
2123  return *this;
2124  }
2125 
2126  for (__bucket = __table->__nodes[__index].__end_list; nb;
2127  --nb, __bucket = __bucket->prev) {}
2128 
2129  return *this;
2130  }
2131 
2132  template < typename Key, typename Val >
2135  return HashTableConstIterator< Key, Val >{*this} += nb;
2136  }
2137 
2138  template < typename Key, typename Val >
2140  const HashTableConstIterator< Key, Val >& from) const noexcept {
2141  return (__bucket != from.__bucket);
2142  }
2143 
2144  template < typename Key, typename Val >
2146  const HashTableConstIterator< Key, Val >& from) const noexcept {
2147  return (__bucket == from.__bucket);
2148  }
2149 
2150  template < typename Key, typename Val >
2151  INLINE const typename HashTableConstIterator< Key, Val >::value_type&
2153  if (__bucket)
2154  return __bucket->elt();
2155  else {
2156  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
2157  }
2158  }
2159 
2160  template < typename Key, typename Val >
2161  INLINE typename HashTable< Key, Val >::Bucket*
2163  return __bucket;
2164  }
2165 
2166  template < typename Key, typename Val >
2168  return __index;
2169  }
2170 
2171  // ===========================================================================
2172  // === UNSAFE HASH TABLE ITERATORS IMPLEMENTATION ===
2173  // ===========================================================================
2174 
2175  template < typename Key, typename Val >
2177  HashTableConstIterator< Key, Val >() {
2178  GUM_CONSTRUCTOR(HashTableIterator);
2179  }
2180 
2181  template < typename Key, typename Val >
2182  template < typename Alloc >
2184  const HashTable< Key, Val, Alloc >& tab) noexcept :
2186  GUM_CONSTRUCTOR(HashTableIterator);
2187  }
2188 
2189  template < typename Key, typename Val >
2190  template < typename Alloc >
2192  const HashTable< Key, Val, Alloc >& tab, Size ind_elt) :
2193  HashTableConstIterator< Key, Val >(tab, ind_elt) {
2194  GUM_CONSTRUCTOR(HashTableIterator);
2195  }
2196 
2197  template < typename Key, typename Val >
2199  const HashTableIterator< Key, Val >& from) noexcept :
2201  GUM_CONS_CPY(HashTableIterator);
2202  }
2203 
2204  template < typename Key, typename Val >
2206  HashTableIterator< Key, Val >&& from) noexcept :
2207  HashTableConstIterator< Key, Val >(std::move(from)) {
2208  GUM_CONS_MOV(HashTableIterator);
2209  }
2210 
2211  template < typename Key, typename Val >
2213  GUM_DESTRUCTOR(HashTableIterator);
2214  }
2215 
2216  template < typename Key, typename Val >
2219  if (this->__bucket)
2220  return this->__bucket->val();
2221  else {
2222  GUM_ERROR(UndefinedIteratorValue, "Accessing a nullptr object");
2223  }
2224  }
2225 
2226  template < typename Key, typename Val >
2228  const HashTableIterator< Key, Val >& from) noexcept {
2230  return *this;
2231  }
2232 
2233  template < typename Key, typename Val >
2235  HashTableIterator< Key, Val >&& from) noexcept {
2237  return *this;
2238  }
2239 
2240  template < typename Key, typename Val >
2244  return *this;
2245  }
2246 
2247  template < typename Key, typename Val >
2251  return *this;
2252  }
2253 
2254  template < typename Key, typename Val >
2257  HashTableIterator< Key, Val > iter{*this};
2258  iter += nb;
2259  return iter;
2260  }
2261 
2262  template < typename Key, typename Val >
2264  const HashTableIterator< Key, Val >& from) const noexcept {
2266  }
2267 
2268  template < typename Key, typename Val >
2270  const HashTableIterator< Key, Val >& from) const noexcept {
2272  }
2273 
2274  template < typename Key, typename Val >
2277  return const_cast< value_type& >(
2279  }
2280 
2281  template < typename Key, typename Val >
2282  INLINE const typename HashTableIterator< Key, Val >::value_type&
2285  }
2286 
2287 } /* 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-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
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:626
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-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
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