aGrUM  0.16.0
list_tpl.h
Go to the documentation of this file.
1 
30 // to ease parser
31 #include <agrum/core/list.h>
32 
33 namespace gum {
34 
35  // ===========================================================================
36  // ===========================================================================
37  // === BUCKET IMPLEMENTATION ===
38  // ===========================================================================
39  // ===========================================================================
40 
41  // default constructor
42  template < typename Val >
43  INLINE ListBucket< Val >::ListBucket(const Val& v) : __val{v} {
44  // for debugging purposes
45  GUM_CONSTRUCTOR(ListBucket);
46  }
47 
48  // construtor for Val rvalues
49  template < typename Val >
50  INLINE ListBucket< Val >::ListBucket(Val&& v) noexcept : __val{std::move(v)} {
51  // for debugging purposes
52  GUM_CONSTRUCTOR(ListBucket);
53  }
54 
55  // emplace constructor
56  template < typename Val >
57  template < typename... Args >
59  Args&&... args) :
60  __val(std::forward< Args >(args)...) {
61  // for debugging purposes
62  GUM_CONSTRUCTOR(ListBucket);
63  }
64 
65  // copy constructor
66  template < typename Val >
68  __val{src.__val} {
69  // for debugging purposes
70  GUM_CONS_CPY(ListBucket);
71  }
72 
73  // copy operator
74  template < typename Val >
77  // for debugging purposes
78  GUM_OP_CPY(ListBucket);
79 
80  // no need to avoid self assignment
81  __val = src.__val;
82  return *this;
83  }
84 
85  // WARNING: during its deletion, the bucket does not take care of properly
86  // rechaining the chained list. This should be done by the Lists themselves
87  template < typename Val >
89  // for debugging purposes
90  GUM_DESTRUCTOR(ListBucket);
91  }
92 
93  // equality check
94  template < typename Val >
95  INLINE bool ListBucket< Val >::operator==(const ListBucket< Val >& src) const {
96  return (src.__val == __val);
97  }
98 
99  // inequality check
100  template < typename Val >
101  INLINE bool ListBucket< Val >::operator!=(const ListBucket< Val >& src) const {
102  return (src.__val != __val);
103  }
104 
105  // dereferencing operator
106  template < typename Val >
107  INLINE const Val& ListBucket< Val >::operator*() const noexcept {
108  return __val;
109  }
110 
111  // dereferencing operator
112  template < typename Val >
113  INLINE Val& ListBucket< Val >::operator*() noexcept {
114  return __val;
115  }
116 
117  // returns the bucket toward the next element
118  template < typename Val >
119  INLINE const ListBucket< Val >* ListBucket< Val >::next() const noexcept {
120  return __next;
121  }
122 
123  // returns the bucket toward the preceding element
124  template < typename Val >
125  INLINE const ListBucket< Val >* ListBucket< Val >::previous() const noexcept {
126  return __prev;
127  }
128 
129  // ===========================================================================
130  // ===========================================================================
131  // === UNSAFE_CONST_LIST_ITERATOR IMPLEMENTATION ===
132  // ===========================================================================
133  // ===========================================================================
134 
135  // default constructor
136  template < typename Val >
138  // for debugging purposes
139  GUM_CONSTRUCTOR(ListConstIterator);
140  }
141 
142  // default constructor
143  template < typename Val >
144  template < typename Alloc >
146  const List< Val, Alloc >& theList) noexcept :
147  __bucket{theList.__deb_list} {
148  // for debugging purposes
149  GUM_CONSTRUCTOR(ListConstIterator);
150  }
151 
152  // copy constructor
153  template < typename Val >
155  const ListConstIterator< Val >& src) noexcept :
156  __bucket{src.__bucket} {
157  // for debugging purposes
158  GUM_CONS_CPY(ListConstIterator);
159  }
160 
161  // move constructor
162  template < typename Val >
164  ListConstIterator< Val >&& src) noexcept :
165  __bucket{std::move(src.__bucket)} {
166  // for debugging purposes
167  GUM_CONS_MOV(ListConstIterator);
168  }
169 
170  // Constructor for an iterator pointing to the \e ind_eltth element of a
171  // List.
172  template < typename Val >
174  Size ind_elt) {
175  // for debugging purposes
176  GUM_CONSTRUCTOR(ListConstIterator);
177 
178  // check if the index ind_elt passed as parameter is valid
179  if (ind_elt >= theList.__nb_elements) {
180  GUM_ERROR(UndefinedIteratorValue, "Not enough elements in the list");
181  }
182 
183  // check if it is faster to find the indexth element from the start or
184  // from the end of the list
185  if (ind_elt < (theList.__nb_elements >> 1)) {
186  // find the element we shall point to src the start of the list
187  for (__bucket = theList.__deb_list; ind_elt;
188  --ind_elt, __bucket = __bucket->__next) {}
189  } else {
190  // find the element we shall point to src the end of the list
191  for (__bucket = theList.__end_list,
192  ind_elt = theList.__nb_elements - ind_elt - 1;
193  ind_elt;
194  --ind_elt, __bucket = __bucket->__prev) {}
195  }
196  }
197 
198  // Destructor
199  template < typename Val >
201  // for debugging purposes
202  GUM_DESTRUCTOR(ListConstIterator);
203  }
204 
205  // Copy operator
206  template < typename Val >
208  operator=(const ListConstIterator< Val >& src) noexcept {
209  // for debugging purposes
210  GUM_OP_CPY(ListConstIterator);
211 
212  __bucket = src.__bucket;
213  return *this;
214  }
215 
216  // move operator
217  template < typename Val >
220  // for debugging purposes
221  GUM_OP_MOV(ListConstIterator);
222  __bucket = src.__bucket;
223  return *this;
224  }
225 
226  // returns the bucket the iterator is pointing to
227  template < typename Val >
229  noexcept {
230  return __bucket;
231  }
232 
233  // Makes the iterator point toward nothing
234  template < typename Val >
235  INLINE void ListConstIterator< Val >::clear() noexcept {
236  __bucket = nullptr;
237  }
238 
239  // positions the iterator to the end of the list
240  template < typename Val >
241  INLINE void ListConstIterator< Val >::setToEnd() noexcept {
242  __bucket = nullptr;
243  }
244 
245  // returns a bool indicating whether the iterator points to the end of the
246  // list
247  template < typename Val >
248  INLINE bool ListConstIterator< Val >::isEnd() const noexcept {
249  return (__bucket == nullptr);
250  }
251 
252  // makes the iterator point to the next element in the List
253  template < typename Val >
255  operator++() noexcept {
256  // if we are pointing to an element of the chained list, just
257  // point on the next bucket in this list
258  if (__bucket != nullptr) { __bucket = __bucket->__next; }
259 
260  return *this;
261  }
262 
263  // makes the iterator point to the next element in the List
264  template < typename Val >
267  if (i >= 0) {
268  for (; i && (__bucket != nullptr); --i, __bucket = __bucket->__next) {}
269  } else {
270  for (; i && (__bucket != nullptr); ++i, __bucket = __bucket->__prev) {}
271  }
272  return *this;
273  }
274 
275  // makes the iterator point to the preceding element in the List
276  template < typename Val >
278  operator--() noexcept {
279  // if we are pointing to an element of the chained list, just
280  // point on the preceding bucket in this list
281  if (__bucket != nullptr) { __bucket = __bucket->__prev; }
282 
283  return *this;
284  }
285 
286  // makes the iterator point to i elements before in the list
287  template < typename Val >
290  if (i >= 0) {
291  for (; i && (__bucket != nullptr); --i, __bucket = __bucket->__prev) {}
292  } else {
293  for (; i && (__bucket != nullptr); ++i, __bucket = __bucket->__next) {}
294  }
295  return *this;
296  }
297 
298  // returns a new iterator
299  template < typename Val >
302  return ListConstIterator< Val >(*this) += i;
303  }
304 
305  // returns a new iterator
306  template < typename Val >
309  return ListConstIterator< Val >(*this) -= i;
310  }
311 
312  // checks whether two iterators point toward different elements
313  template < typename Val >
314  INLINE bool ListConstIterator< Val >::
315  operator!=(const ListConstIterator< Val >& src) const noexcept {
316  return (__bucket != src.__bucket);
317  }
318 
319  // checks whether two iterators point toward the same elements.
320  template < typename Val >
321  INLINE bool ListConstIterator< Val >::
322  operator==(const ListConstIterator< Val >& src) const noexcept {
323  return (__bucket == src.__bucket);
324  }
325 
326  // dereferences the value pointed to by the iterator
327  template < typename Val >
328  INLINE const Val* ListConstIterator< Val >::operator->() const {
329  if (__bucket != nullptr)
330  return &(__bucket->__val);
331  else {
332  GUM_ERROR(UndefinedIteratorValue, "Accessing a NULL object");
333  }
334  }
335 
336  // gives access to the content of the iterator
337  template < typename Val >
338  INLINE const Val& ListConstIterator< Val >::operator*() const {
339  if (__bucket != nullptr)
340  return __bucket->__val;
341  else {
342  GUM_ERROR(UndefinedIteratorValue, "Accessing a NULL object");
343  }
344  }
345 
346  // for STL compliance, a distance operator
347  template < typename Val >
350  const ListConstIterator< Val >& iter2) {
352 
353  for (ListConstIterator< Val > iter3 = iter2; iter1 != iter3; ++iter3, ++res) {}
354 
355  return res;
356  }
357 
358  // ===========================================================================
359  // ===========================================================================
360  // === UNSAFE_LIST_ITERATOR IMPLEMENTATION ===
361  // ===========================================================================
362  // ===========================================================================
363 
364  // basic constructor
365  template < typename Val >
367  ListConstIterator< Val >() {
368  GUM_CONSTRUCTOR(ListIterator);
369  }
370 
371  // constructor for a begin
372  template < typename Val >
373  template < typename Alloc >
375  const List< Val, Alloc >& theList) noexcept :
376  ListConstIterator< Val >(theList) {
377  GUM_CONSTRUCTOR(ListIterator);
378  }
379 
380  // copy constructor
381  template < typename Val >
382  INLINE
385  GUM_CONS_CPY(ListIterator);
386  }
387 
388  // move constructor
389  template < typename Val >
391  ListConstIterator< Val >(std::move(src)) {
392  GUM_CONS_MOV(ListIterator);
393  }
394 
395  // Constructor for an iterator pointing to the \e ind_eltth element of a
396  // List.
397  template < typename Val >
399  Size ind_elt) :
400  ListConstIterator< Val >(theList, ind_elt) {
401  GUM_CONSTRUCTOR(ListIterator);
402  }
403 
404  // Copy operator
405  template < typename Val >
407  operator=(const ListIterator< Val >& src) noexcept {
408  GUM_OP_CPY(ListIterator);
410  return *this;
411  }
412 
413  // move operator
414  template < typename Val >
417  GUM_OP_MOV(ListIterator);
418  ListConstIterator< Val >::operator=(std::move(src));
419  return *this;
420  }
421 
422  // Destructor
423  template < typename Val >
425  GUM_DESTRUCTOR(ListIterator);
426  }
427 
428  // makes the iterator point to the next element in the List
429  template < typename Val >
432  return *this;
433  }
434 
435  // makes the iterator point to i elements further in the List
436  template < typename Val >
440  return *this;
441  }
442 
443  // makes the iterator point to the preceding element in the List
444  template < typename Val >
447  return *this;
448  }
449 
450  // makes the iterator point to i elements before in the List
451  template < typename Val >
455  return *this;
456  }
457 
458  // returns a new iterator
459  template < typename Val >
462  return ListIterator< Val >(*this) += i;
463  }
464 
465  // returns a new iterator
466  template < typename Val >
469  return ListIterator< Val >(*this) -= i;
470  }
471 
472  // dereferences the value pointed to by the iterator
473  template < typename Val >
475  return const_cast< Val* >(ListConstIterator< Val >::operator->());
476  }
477 
478  // gives access to the content of the iterator
479  template < typename Val >
481  return const_cast< Val& >(ListConstIterator< Val >::operator*());
482  }
483 
484  // ===========================================================================
485  // ===========================================================================
486  // === SAFE LIST CONST ITERATOR IMPLEMENTATION ===
487  // ===========================================================================
488  // ===========================================================================
489 
490  // basic constructor
491  template < typename Val >
493  // for debugging purposes
494  GUM_CONSTRUCTOR(ListConstIteratorSafe);
495  }
496 
497  // Constructor for a begin
498  template < typename Val >
499  template < typename Alloc >
501  const List< Val, Alloc >& theList) :
502  __list{
503  reinterpret_cast< const List< Val, std::allocator< Val > >* >(&theList)},
504  __bucket{theList.__deb_list} {
505  // for debugging purposes
506  GUM_CONSTRUCTOR(ListConstIteratorSafe);
507 
508  // add the iterator to the list of safe iterators
509  theList.__safe_iterators.push_back(this);
510  }
511 
512  // copy constructor
513  template < typename Val >
515  const ListConstIteratorSafe< Val >& src) :
516  __list{src.__list},
517  __bucket{src.__bucket}, __next_current_bucket{src.__next_current_bucket},
518  __prev_current_bucket{src.__prev_current_bucket}, __null_pointing{
519  src.__null_pointing} {
520  // for debugging purposes
521  GUM_CONS_CPY(ListConstIteratorSafe);
522 
523  // add the iterator to the list of safe iterators
524  if (__list != nullptr) __list->__safe_iterators.push_back(this);
525  }
526 
527  // Constructor for an iterator pointing to the \e ind_eltth element of a
528  // List.
529  template < typename Val >
530  template < typename Alloc >
532  const List< Val, Alloc >& theList, Size ind_elt) :
533  __list{
534  reinterpret_cast< const List< Val, std::allocator< Val > >* >(&theList)} {
535  // for debugging purposes
536  GUM_CONSTRUCTOR(ListConstIteratorSafe);
537 
538  // check if the index ind_elt passed as parameter is valid
539  if (ind_elt >= __list->__nb_elements) {
540  GUM_ERROR(UndefinedIteratorValue, "Not enough elements in the list");
541  }
542 
543  // check if it is faster to find the indexth element src the start or
544  // src the end of the list
545  if (ind_elt < (__list->__nb_elements >> 1)) {
546  // find the element we shall point to src the start of the list
547  for (__bucket = __list->__deb_list; ind_elt;
548  --ind_elt, __bucket = __bucket->__next) {}
549  } else {
550  // find the element we shall point to src the end of the list
551  for (__bucket = __list->__end_list,
552  ind_elt = __list->__nb_elements - ind_elt - 1;
553  ind_elt;
554  --ind_elt, __bucket = __bucket->__prev) {}
555  }
556 
557  // add the iterator to the list of safe iterators
558  theList.__safe_iterators.push_back(this);
559  }
560 
561  // move constructor
562  template < typename Val >
565  __list{src.__list},
566  __bucket{src.__bucket}, __next_current_bucket{src.__next_current_bucket},
567  __prev_current_bucket{src.__prev_current_bucket}, __null_pointing{
568  src.__null_pointing} {
569  // for debugging purposes
570  GUM_CONS_MOV(ListConstIteratorSafe);
571 
572  if (__list != nullptr) {
573  // substitute src by this in the list of safe iterators
574  std::vector< ListConstIteratorSafe< Val >* >& vect =
576 
577  for (auto ptr = vect.rbegin(); ptr != vect.rend(); --ptr) {
578  if (*ptr == &src) {
579  *ptr = this;
580  break;
581  }
582  }
583 
584  src.__list = nullptr;
585  src.__bucket = nullptr;
586  src.__null_pointing = false;
587  }
588  }
589 
590  // remove the iterator for its list' safe iterators list
591  template < typename Val >
593  // find where the iterator is
594  std::vector< ListConstIteratorSafe< Val >* >& vect = __list->__safe_iterators;
595 
596  for (auto i = vect.size() - 1; i >= 0; --i) {
597  if (vect[i] == this) {
598  vect.erase(vect.begin() + i);
599  break;
600  }
601  }
602  }
603 
604  // Copy operator
605  template < typename Val >
608  // avoid self assignment
609  if (this != &src) {
610  // for debugging purposes
611  GUM_OP_CPY(ListConstIteratorSafe);
612 
613  // check if src and this belong to the same list. If this is not
614  // the case, we shall remove this from its iterator's list and
615  // put it into src's list one.
616  if (__list && (src.__list != __list)) {
618  __list = nullptr;
619  }
620 
621  // if necessary, put this into the same list of safe iterators as src
622  if (src.__list && (src.__list != __list)) {
623  try {
624  src.__list->__safe_iterators.push_back(this);
625  } catch (...) {
626  __list = nullptr;
627  __bucket = nullptr;
628  __null_pointing = false;
629  throw;
630  }
631  }
632 
633  __list = src.__list;
634  __bucket = src.__bucket;
638  }
639 
640  return *this;
641  }
642 
643  // move operator
644  template < typename Val >
647  // avoid self assignment
648  if (this != &src) {
649  // for debugging purposes
650  GUM_OP_MOV(ListConstIteratorSafe);
651 
652  // if the two iterators do not point to the same list, remove
653  // the current iterator from its safe iterators list
654  if ((__list != nullptr) && (src.__list != __list)) {
656  __list = nullptr;
657  }
658 
659  // now if src points to a list, put this at its location
660  if ((src.__list != nullptr)) {
661  std::vector< ListConstIteratorSafe< Val >* >& vect =
662  src.__list->__safe_iterators;
663  Idx index_src = Size(vect.size()) - 1;
664 
665  for (;; --index_src) {
666  if (vect[index_src] == &src) { break; }
667  }
668 
669  if (__list == nullptr) {
670  vect[index_src] = this;
671  } else {
672  vect.erase(vect.begin() + index_src);
673  }
674  }
675 
676  __list = src.__list;
677  __bucket = src.__bucket;
678  __prev_current_bucket = src.__prev_current_bucket;
679  __next_current_bucket = src.__next_current_bucket;
680  __null_pointing = src.__null_pointing;
681 
682  src.__list = nullptr;
683  src.__bucket = nullptr;
684  src.__null_pointing = false;
685  }
686 
687  return *this;
688  }
689 
690  // Destructor
691  template < typename Val >
693  // for debugging purposes
694  GUM_DESTRUCTOR(ListConstIteratorSafe);
695 
696  // remove the iterator src the table's iterator list
698  }
699 
700  // returns the bucket the iterator is pointing to
701  template < typename Val >
703  noexcept {
704  return __bucket;
705  }
706 
707  // Makes the iterator point toward nothing
708  template < typename Val >
710  // remove the iterator src the list's iterator list
712 
713  // set its list as well as the element it points to to nullptr
714  __list = nullptr;
715  __bucket = nullptr;
716  __null_pointing = false;
717  }
718 
719  // positions the iterator to the end of the list
720  template < typename Val >
722  clear();
723  }
724 
725  // returns a bool indicating whether the iterator points to the end of the
726  // list
727  template < typename Val >
729  return __null_pointing ? (__next_current_bucket == nullptr)
730  && (__prev_current_bucket == nullptr)
731  : (__bucket == nullptr);
732  }
733 
734  // makes the iterator point to the next element in the List
735  template < typename Val >
737  operator++() noexcept {
738  // check if we are pointing to something that has been deleted
739  if (__null_pointing) {
740  __null_pointing = false;
741 
742  // if we are pointing to an element of the chained list that has been
743  // deleted
744  // but that has a next element, just point on the latter
745  if (__next_current_bucket != nullptr) {
747  return *this;
748  }
749 
750  // here we were pointing on an extremity of the list (either end or rend)
751  // if prev_current_bucket is not null, then we are at rend and doing
752  // a ++ shall now point to the beginning of the list
753  if (__prev_current_bucket != nullptr) {
755  return *this;
756  }
757 
758  // here, we are at the end of the chained list, hence we shall remain at
759  // end
760  __bucket = nullptr;
761  return *this;
762  } else {
763  // if we are pointing to an element of the chained list, just
764  // point on the next bucket in this list
765  if (__bucket != nullptr) { __bucket = __bucket->__next; }
766 
767  return *this;
768  }
769  }
770 
771  // makes the iterator point to i elements before in the List
772  template < typename Val >
775  // check if we are pointing to something that has been deleted
776  if (__null_pointing) {
777  __null_pointing = false;
778 
779  // if we are pointing to an element of the chained list that has been
780  // deleted
781  // but that has a preceding element, just point on the latter
782  if (__prev_current_bucket != nullptr) {
784  } else {
785  // here we were pointing on an extremity of the list (either end or
786  // rend)
787  // if next_current_bucket is not null, then we are at end and doing
788  // a -- shall now point to the beginning of the list
789  if (__next_current_bucket != nullptr) {
791  } else {
792  // here, we are at the rend of the chained list, hence we shall remain
793  // at rend
794  __bucket = nullptr;
795  return *this;
796  }
797  }
798  } else {
799  // if we are pointing to an element of the chained list, just
800  // point on the preceding bucket in this list
801  if (__bucket != nullptr) { __bucket = __bucket->__prev; }
802  }
803 
804  for (--i; i && (__bucket != nullptr); --i, __bucket = __bucket->__prev) {}
805 
806  return *this;
807  }
808 
809  // makes the iterator point to the next element in the List
810  template < typename Val >
813  // check if we are pointing to something that has been deleted
814  if (__null_pointing) {
815  __null_pointing = false;
816 
817  // if we are pointing to an element of the chained list that has been
818  // deleted
819  // but that has a next element, just point on the latter
820  if (__next_current_bucket != nullptr) {
822  } else {
823  // here we were pointing on an extremity of the list (either end or
824  // rend)
825  // if prev_current_bucket is not null, then we are at rend and doing
826  // a ++ shall now point to the beginning of the list
827  if (__prev_current_bucket != nullptr) {
829  } else {
830  // here, we are at the end of the chained list, hence we shall
831  // remain at end
832  __bucket = nullptr;
833  return *this;
834  }
835  }
836  } else {
837  // if we are pointing to an element of the chained list, just
838  // point on the next bucket in this list
839  if (__bucket != nullptr) { __bucket = __bucket->__next; }
840  }
841 
842  for (--i; i && (__bucket != nullptr); --i, __bucket = __bucket->__next) {}
843 
844  return *this;
845  }
846 
847  // makes the iterator point to the next element in the List
848  template < typename Val >
850  typename ListConstIteratorSafe< Val >::difference_type i) noexcept {
851  if (!i) return *this;
852 
853  if (i < 0)
854  return __opMinus(-i);
855  else
856  return __opPlus(i);
857  }
858 
859  // makes the iterator point to the preceding element in the List
860  template < typename Val >
862  operator--() noexcept {
863  // check if we are pointing to something that has been deleted
864  if (__null_pointing) {
865  __null_pointing = false;
866 
867  // if we are pointing to an element of the chained list that has been
868  // deleted
869  // but that has a preceding element, just point on the latter
870  if (__prev_current_bucket != nullptr) {
872  return *this;
873  }
874 
875  // here we were pointing on an extremity of the list (either end or rend)
876  // if next_current_bucket is not null, then we are at end and doing
877  // a -- shall now point to the beginning of the list
878  if (__next_current_bucket != nullptr) {
880  return *this;
881  }
882 
883  // here, we are at the rend of the chained list, hence we shall remain
884  // at rend
885  __bucket = nullptr;
886  return *this;
887  } else {
888  // if we are pointing to an element of the chained list, just
889  // point on the preceding bucket in this list
890  if (__bucket != nullptr) { __bucket = __bucket->__prev; }
891 
892  return *this;
893  }
894  }
895 
896  // makes the iterator point to i elements before in the List
897  template < typename Val >
899  typename ListConstIteratorSafe< Val >::difference_type i) noexcept {
900  if (!i) return *this;
901 
902  if (i < 0)
903  return __opPlus(-i);
904  else
905  return __opMinus(i);
906  }
907 
908  // returns a new iterator
909  template < typename Val >
912  return ListConstIteratorSafe< Val >(*this) += i;
913  }
914 
915  // returns a new iterator
916  template < typename Val >
919  return ListConstIteratorSafe< Val >(*this) -= i;
920  }
921 
922  // checks whether two iterators point toward different elements
923  template < typename Val >
926  return __null_pointing
929  : (__bucket != src.__bucket);
930  }
931 
932  // checks whether two iterators point toward the same elements.
933  template < typename Val >
936  return __null_pointing
939  : (__bucket == src.__bucket);
940  }
941 
942  // dereferences the value pointed to by the iterator
943  template < typename Val >
944  INLINE const Val* ListConstIteratorSafe< Val >::operator->() const {
945  if (__bucket != nullptr)
946  return &(__bucket->__val);
947  else {
948  GUM_ERROR(UndefinedIteratorValue, "Accessing a NULL object");
949  }
950  }
951 
952  // gives access to the content of the iterator
953  template < typename Val >
954  INLINE const Val& ListConstIteratorSafe< Val >::operator*() const {
955  if (__bucket != nullptr)
956  return __bucket->__val;
957  else {
958  GUM_ERROR(UndefinedIteratorValue, "Accessing a NULL object");
959  }
960  }
961 
962  // for STL compliance, a distance operator
963  template < typename Val >
966  const ListConstIteratorSafe< Val >& iter2) {
968  ListConstIteratorSafe< Val > iter3{iter2};
969 
970  for (; iter1 != iter3; ++iter3, ++res) {}
971 
972  return res;
973  }
974 
975  // ===========================================================================
976  // ===========================================================================
977  // === LIST ITERATOR IMPLEMENTATION ===
978  // ===========================================================================
979  // ===========================================================================
980 
981  // basic constructor
982  template < typename Val >
984  ListConstIteratorSafe< Val >() {
985  GUM_CONSTRUCTOR(ListIteratorSafe);
986  }
987 
988  // constructor for a begin
989  template < typename Val >
990  template < typename Alloc >
991  INLINE
993  ListConstIteratorSafe< Val >(theList) {
994  GUM_CONSTRUCTOR(ListIteratorSafe);
995  }
996 
997  // copy constructor
998  template < typename Val >
1000  const ListIteratorSafe< Val >& src) :
1001  ListConstIteratorSafe< Val >(src) {
1002  GUM_CONS_CPY(ListIteratorSafe);
1003  }
1004 
1005  // Constructor for an iterator pointing to the \e ind_eltth element of a
1006  // List.
1007  template < typename Val >
1008  template < typename Alloc >
1009  INLINE
1011  Size ind_elt) :
1012  ListConstIteratorSafe< Val >(theList, ind_elt) {
1013  GUM_CONSTRUCTOR(ListIteratorSafe);
1014  }
1015 
1016  // move constructor
1017  template < typename Val >
1019  ListConstIteratorSafe< Val >(std::move(src)) {
1020  GUM_CONS_MOV(ListIteratorSafe);
1021  }
1022 
1023  // Copy operator
1024  template < typename Val >
1027  // for debugging purposes
1028  GUM_OP_CPY(ListIteratorSafe);
1030  return *this;
1031  }
1032 
1033  // move operator
1034  template < typename Val >
1037  // for debugging purposes
1038  GUM_OP_MOV(ListIteratorSafe);
1040  return *this;
1041  }
1042 
1043  // Destructor
1044  template < typename Val >
1046  GUM_DESTRUCTOR(ListIteratorSafe);
1047  }
1048 
1049  // makes the iterator point to the next element in the List
1050  template < typename Val >
1053  return *this;
1054  }
1055 
1056  // makes the iterator point to the next element in the List
1057  template < typename Val >
1061  return *this;
1062  }
1063 
1064  // makes the iterator point to the preceding element in the List
1065  template < typename Val >
1068  return *this;
1069  }
1070 
1071  // makes the iterator point to the preceding element in the List
1072  template < typename Val >
1076  return *this;
1077  }
1078 
1079  // returns a new iterator
1080  template < typename Val >
1083  return ListIteratorSafe< Val >(*this) += i;
1084  }
1085 
1086  // returns a new iterator
1087  template < typename Val >
1090  return ListIteratorSafe< Val >(*this) -= i;
1091  }
1092 
1093  // dereferences the value pointed to by the iterator
1094  template < typename Val >
1096  return const_cast< Val* >(ListConstIteratorSafe< Val >::operator->());
1097  }
1098 
1099  // gives access to the content of the iterator
1100  template < typename Val >
1102  return const_cast< Val& >(ListConstIteratorSafe< Val >::operator*());
1103  }
1104 
1105  // ===========================================================================
1106  // ===========================================================================
1107  // === LIST IMPLEMENTATION ===
1108  // ===========================================================================
1109  // ===========================================================================
1110 
1111  // a function used to perform copies of elements of Lists
1112  template < typename Val, typename Alloc >
1113  template < typename OtherAlloc >
1115  ListBucket< Val >* ptr;
1116  ListBucket< Val >* old_ptr = nullptr;
1117  ListBucket< Val >* new_elt = nullptr;
1118 
1119  // copy src's list
1120  try {
1121  for (ptr = src.__deb_list; ptr != nullptr; ptr = ptr->__next) {
1122  // create a copy bucket
1123  new_elt = __alloc_bucket.allocate(1);
1124 
1125  try {
1126  __alloc_bucket.construct(new_elt, *ptr);
1127  } catch (...) {
1128  __alloc_bucket.deallocate(new_elt, 1);
1129  throw;
1130  }
1131 
1132  // rechain properly the new list (the next field is already initialized
1133  // with nullptr)
1134  new_elt->__prev = old_ptr;
1135 
1136  if (old_ptr)
1137  old_ptr->__next = new_elt;
1138  else
1139  __deb_list = new_elt;
1140 
1141  old_ptr = new_elt;
1142  }
1143  } catch (...) {
1144  // problem: we could not allocate an element in the list => we delete
1145  // the elements created so far and we throw an exception
1146  for (; __deb_list != nullptr;
1147  __deb_list = const_cast< ListBucket< Val >* >(ptr)) {
1148  ptr = __deb_list->__next;
1149  __alloc_bucket.destroy(__deb_list);
1150  __alloc_bucket.deallocate(__deb_list, 1);
1151  }
1152 
1153  __deb_list = nullptr;
1154  throw;
1155  }
1156 
1157  // update properly the end of the chained list and the number of elements
1158  __end_list = old_ptr;
1159  __nb_elements = src.__nb_elements;
1160  }
1161 
1162  // deletes all the elements of a chained list.
1163  template < typename Val, typename Alloc >
1165  // first we update all the safe iterators of the list : they should now
1166  // point to end/rend
1167  for (const auto ptr_iter : __safe_iterators) {
1168  ptr_iter->clear();
1169  }
1170 
1171  // clear all the values
1172  for (ListBucket< Val >*ptr = __deb_list, *next_ptr = nullptr; ptr != nullptr;
1173  ptr = next_ptr) {
1174  next_ptr = ptr->__next;
1175  __alloc_bucket.destroy(ptr);
1176  __alloc_bucket.deallocate(ptr, 1);
1177  }
1178 
1179  __nb_elements = 0;
1180  __deb_list = nullptr;
1181  __end_list = nullptr;
1182  }
1183 
1184  // A basic constructor that creates an empty list
1185  template < typename Val, typename Alloc >
1187  // for debugging purposes
1188  GUM_CONSTRUCTOR(List);
1189 
1190  // reserve space for only the default number of iterators
1191  __safe_iterators.reserve(GUM_DEFAULT_ITERATOR_NUMBER);
1192  }
1193 
1194  // Copy constructor
1195  template < typename Val, typename Alloc >
1197  // for debugging purposes
1198  GUM_CONS_CPY(List);
1199 
1200  // copy the elements
1201  __copy_elements(src);
1202 
1203  // reserve space for only the default number of iterators
1204  __safe_iterators.reserve(GUM_DEFAULT_ITERATOR_NUMBER);
1205  }
1206 
1207  // generalized copy constructor
1208  template < typename Val, typename Alloc >
1209  template < typename OtherAlloc >
1211  // for debugging purposes
1212  GUM_CONS_CPY(List);
1213 
1214  // copy the elements
1215  __copy_elements(src);
1216 
1217  // reserve space for only the default number of iterators
1218  __safe_iterators.reserve(GUM_DEFAULT_ITERATOR_NUMBER);
1219  }
1220 
1221  // move constructor
1222  template < typename Val, typename Alloc >
1224  __deb_list{std::move(src.__deb_list)}, __end_list{std::move(src.__end_list)},
1225  __nb_elements{std::move(src.__nb_elements)},
1226  __safe_iterators{std::move(src.__safe_iterators)}, __alloc_bucket{std::move(
1227  src.__alloc_bucket)} {
1228  // for debugging purposes
1229  GUM_CONS_MOV(List);
1230 
1231  src.__deb_list = nullptr;
1232  src.__end_list = nullptr;
1233  src.__nb_elements = 0;
1234  src.__safe_iterators.clear();
1235  }
1236 
1237  // initializer_list constructor
1238  template < typename Val, typename Alloc >
1239  INLINE List< Val, Alloc >::List(std::initializer_list< Val > list) {
1240  // for debugging purposes
1241  GUM_CONSTRUCTOR(List);
1242 
1243  // adding all the elements
1244  for (const auto& val : list) {
1245  pushBack(val);
1246  }
1247 
1248  // reserve space for only the default number of iterators
1249  __safe_iterators.reserve(GUM_DEFAULT_ITERATOR_NUMBER);
1250  }
1251 
1252  // Destructor
1253  template < typename Val, typename Alloc >
1255  // for debugging (although this program is bug-free)
1256  GUM_DESTRUCTOR(List);
1257 
1258  // we detach all the safe iterators attached to the current List and we
1259  // remove all the elements from the list
1260  clear();
1261  }
1262 
1263  // Copy operator. The List iterator's list is not shared with that of \e src.
1264  template < typename Val, typename Alloc >
1267  // avoid self assignment
1268  if (this != &src) {
1269  // for debugging purposes
1270  GUM_OP_CPY(List);
1271 
1272  // remove the old content of 'this' and update accordingly the iterators
1273  clear();
1274 
1275  // perform the copy
1276  __copy_elements(src);
1277  }
1278 
1279  return *this;
1280  }
1281 
1282  // Generalized copy operator.
1283  template < typename Val, typename Alloc >
1284  template < typename OtherAlloc >
1287  // avoid self assignment
1288  if (this != reinterpret_cast< List< Val, Alloc >* >(&src)) {
1289  // for debugging purposes
1290  GUM_OP_CPY(List);
1291 
1292  // remove the old content of 'this' and update accordingly the iterators
1293  clear();
1294 
1295  // perform the copy
1296  __copy_elements(src);
1297  }
1298 
1299  return *this;
1300  }
1301 
1302  // move operator
1303  template < typename Val, typename Alloc >
1306  // avoid self assignment
1307  if (this != &src) {
1308  // for debugging purposes
1309  GUM_OP_MOV(List);
1310 
1311  // remove the old content of 'this' and update accordingly the iterators
1312  clear();
1313 
1314  // perform the move
1315  __deb_list = std::move(src.__deb_list);
1316  __end_list = std::move(src.__end_list);
1317  __nb_elements = std::move(src.__nb_elements);
1318  __safe_iterators = std::move(src.__safe_iterators);
1319  __alloc_bucket = std::move(src.__alloc_bucket);
1320 
1321  src.__deb_list = nullptr;
1322  src.__end_list = nullptr;
1323  src.__nb_elements = 0;
1324  src.__safe_iterators.clear();
1325  }
1326 
1327  return *this;
1328  }
1329 
1330  // the iterator pointing to the end of the List
1331  template < typename Val, typename Alloc >
1333  noexcept {
1334  return *(
1335  reinterpret_cast< const ListConstIteratorSafe< Val >* >(__list_end_safe));
1336  }
1337 
1338  // the iterator pointing to the end of the List
1339  template < typename Val, typename Alloc >
1341  return *(reinterpret_cast< const ListIteratorSafe< Val >* >(__list_end_safe));
1342  }
1343 
1344  // the iterator pointing to the end of the List
1345  template < typename Val, typename Alloc >
1347  noexcept {
1348  return *(reinterpret_cast< const ListConstIterator< Val >* >(__list_end));
1349  }
1350 
1351  // the iterator pointing to the end of the List
1352  template < typename Val, typename Alloc >
1354  return *(reinterpret_cast< const ListIterator< Val >* >(__list_end));
1355  }
1356 
1357  // the iterator pointing to the end of the List
1358  template < typename Val, typename Alloc >
1359  INLINE const ListConstIterator< Val >& List< Val, Alloc >::end() const noexcept {
1360  return *(reinterpret_cast< const ListConstIterator< Val >* >(__list_end));
1361  }
1362 
1363  // the iterator pointing to the rend (just before the beginning) of the List
1364  template < typename Val, typename Alloc >
1366  noexcept {
1367  return *(
1368  reinterpret_cast< const ListConstIteratorSafe< Val >* >(__list_end_safe));
1369  }
1370 
1371  // the iterator pointing to the rend (just before the beginning) of the List
1372  template < typename Val, typename Alloc >
1374  return *(reinterpret_cast< const ListIteratorSafe< Val >* >(__list_end_safe));
1375  }
1376 
1377  // the iterator pointing to the rend (just before the beginning) of the List
1378  template < typename Val, typename Alloc >
1380  noexcept {
1381  return *(reinterpret_cast< const ListConstIterator< Val >* >(__list_end));
1382  }
1383 
1384  // the iterator pointing to the rend (just before the beginning) of the List
1385  template < typename Val, typename Alloc >
1387  return *(reinterpret_cast< const ListIterator< Val >* >(__list_end));
1388  }
1389 
1390  // the iterator pointing to the rend (just before the beginning) of the List
1391  template < typename Val, typename Alloc >
1393  noexcept {
1394  return *(reinterpret_cast< const ListConstIterator< Val >* >(__list_end));
1395  }
1396 
1397  // the iterator pointing to the beginning of the List
1398  template < typename Val, typename Alloc >
1400  return ListConstIteratorSafe< Val >{*this};
1401  }
1402 
1403  // the iterator pointing to the beginning of the List
1404  template < typename Val, typename Alloc >
1406  return ListIteratorSafe< Val >{*this};
1407  }
1408 
1409  // the iterator pointing to the beginning of the List
1410  template < typename Val, typename Alloc >
1412  return ListConstIterator< Val >{*this};
1413  }
1414 
1415  // the iterator pointing to the beginning of the List
1416  template < typename Val, typename Alloc >
1418  return ListIterator< Val >{*this};
1419  }
1420 
1421  // the iterator pointing to the beginning of the List
1422  template < typename Val, typename Alloc >
1424  return ListConstIterator< Val >{*this};
1425  }
1426 
1427  // the iterator pointing to the rbegin (the last element) of the List
1428  template < typename Val, typename Alloc >
1430  if (__nb_elements)
1431  return ListConstIteratorSafe< Val >{*this, __nb_elements - 1};
1432  else
1434  }
1435 
1436  // the iterator pointing to the rbegin (the last element) of the List
1437  template < typename Val, typename Alloc >
1439  if (__nb_elements)
1440  return ListIteratorSafe< Val >{*this, __nb_elements - 1};
1441  else
1442  return ListIteratorSafe< Val >{};
1443  }
1444 
1445  // the iterator pointing to the rbegin (the last element) of the List
1446  template < typename Val, typename Alloc >
1448  if (__nb_elements)
1449  return ListConstIterator< Val >{*this, __nb_elements - 1};
1450  else
1451  return ListConstIterator< Val >{};
1452  }
1453 
1454  // the iterator pointing to the rbegin (the last element) of the List
1455  template < typename Val, typename Alloc >
1457  if (__nb_elements)
1458  return ListIterator< Val >{*this, __nb_elements - 1};
1459  else
1460  return ListIterator< Val >{};
1461  }
1462 
1463  // the iterator pointing to the rbegin (the last element) of the List
1464  template < typename Val, typename Alloc >
1466  if (__nb_elements)
1467  return ListConstIterator< Val >{*this, __nb_elements - 1};
1468  else
1469  return ListConstIterator< Val >{};
1470  }
1471 
1472  // create a new bucket with a given value
1473  template < typename Val, typename Alloc >
1474  INLINE ListBucket< Val >*
1475  List< Val, Alloc >::__createBucket(const Val& val) const {
1476  // create a new bucket (catch allocation and construction exceptions)
1477  ListBucket< Val >* new_elt = __alloc_bucket.allocate(1);
1478 
1479  try {
1480  __alloc_bucket.construct(new_elt, val);
1481  } catch (...) {
1482  __alloc_bucket.deallocate(new_elt, 1);
1483  throw;
1484  }
1485 
1486  return new_elt;
1487  }
1488 
1489  // create a new bucket with a given value
1490  template < typename Val, typename Alloc >
1492  // create a new bucket (catch allocation and construction exceptions)
1493  ListBucket< Val >* new_elt = __alloc_bucket.allocate(1);
1494 
1495  try {
1496  __alloc_bucket.construct(new_elt, std::move(val));
1497  } catch (...) {
1498  __alloc_bucket.deallocate(new_elt, 1);
1499  throw;
1500  }
1501 
1502  return new_elt;
1503  }
1504 
1505  // create an emplace bucket
1506  template < typename Val, typename Alloc >
1507  template < typename... Args >
1508  INLINE ListBucket< Val >*
1510  // create a new bucket (catch allocation and construction exceptions)
1511  ListBucket< Val >* new_elt = __alloc_bucket.allocate(1);
1512 
1513  try {
1514  __alloc_bucket.construct(new_elt,
1516  std::forward< Args >(args)...);
1517  } catch (...) {
1518  __alloc_bucket.deallocate(new_elt, 1);
1519  throw;
1520  }
1521 
1522  return new_elt;
1523  }
1524 
1525  // insert a bucket at the front of the list
1526  template < typename Val, typename Alloc >
1528  new_elt->__next = __deb_list;
1529 
1530  if (__deb_list != nullptr)
1531  __deb_list->__prev = new_elt;
1532  else
1533  __end_list = new_elt;
1534 
1535  __deb_list = new_elt;
1536 
1537  // update the number of elements
1538  ++__nb_elements;
1539 
1540  // return the inserted element
1541  return new_elt->__val;
1542  }
1543 
1544  // insert a bucket at the end of the list
1545  template < typename Val, typename Alloc >
1547  // place the bucket at the end of the list
1548  new_elt->__prev = __end_list;
1549 
1550  if (__end_list != nullptr)
1551  __end_list->__next = new_elt;
1552  else
1553  __deb_list = new_elt;
1554 
1555  __end_list = new_elt;
1556 
1557  // update the number of elements
1558  ++__nb_elements;
1559 
1560  // returns the current value
1561  return new_elt->__val;
1562  }
1563 
1564  // Insertion of a new element (a copy) at the beginning of the chained list.
1565  template < typename Val, typename Alloc >
1566  INLINE Val& List< Val, Alloc >::pushFront(const Val& val) {
1567  return __pushFront(__createBucket(val));
1568  }
1569 
1570  // Insertion of a new element (a copy) at the beginning of the chained list.
1571  template < typename Val, typename Alloc >
1572  INLINE Val& List< Val, Alloc >::pushFront(Val&& val) {
1573  return __pushFront(__createBucket(std::move(val)));
1574  }
1575 
1576  // an alias for pushFront used for STL compliance
1577  template < typename Val, typename Alloc >
1578  template < typename... Args >
1579  INLINE Val& List< Val, Alloc >::push_front(Args&&... args) {
1580  return pushFront(std::forward< Args >(args)...);
1581  }
1582 
1583  // emplace elements at the beginning of the chained list
1584  template < typename Val, typename Alloc >
1585  template < typename... Args >
1586  INLINE Val& List< Val, Alloc >::emplaceFront(Args&&... args) {
1587  return __pushFront(__createEmplaceBucket(std::forward< Args >(args)...));
1588  }
1589 
1590  // Insertion of a new element (a copy) at the end of the chained list.
1591  template < typename Val, typename Alloc >
1592  INLINE Val& List< Val, Alloc >::pushBack(const Val& val) {
1593  return __pushBack(__createBucket(val));
1594  }
1595 
1596  // pushBack for rvalues
1597  template < typename Val, typename Alloc >
1598  INLINE Val& List< Val, Alloc >::pushBack(Val&& val) {
1599  return __pushBack(__createBucket(std::move(val)));
1600  }
1601 
1602  // an alias for pushBack used for STL compliance
1603  template < typename Val, typename Alloc >
1604  template < typename... Args >
1605  INLINE Val& List< Val, Alloc >::push_back(Args&&... args) {
1606  return pushBack(std::forward< Args >(args)...);
1607  }
1608 
1609  // emplace elements at the end of the chained list
1610  template < typename Val, typename Alloc >
1611  template < typename... Args >
1612  INLINE Val& List< Val, Alloc >::emplaceBack(Args&&... args) {
1613  return __pushBack(__createEmplaceBucket(std::forward< Args >(args)...));
1614  }
1615 
1616  // Insertion of a new element at the end of the chained list (alias of
1617  // pushBack)
1618  template < typename Val, typename Alloc >
1619  INLINE Val& List< Val, Alloc >::insert(const Val& val) {
1620  return pushBack(val);
1621  }
1622 
1623  // insert for rvalues
1624  template < typename Val, typename Alloc >
1625  INLINE Val& List< Val, Alloc >::insert(Val&& val) {
1626  return pushBack(std::move(val));
1627  }
1628 
1629  // returns the bucket corresponding to the ith position
1630  template < typename Val, typename Alloc >
1632  noexcept {
1633  ListBucket< Val >* ptr;
1634 
1635  if (i < __nb_elements / 2) {
1636  for (ptr = __deb_list; i; --i, ptr = ptr->__next) {}
1637  } else {
1638  for (ptr = __end_list, i = __nb_elements - i - 1; i;
1639  --i, ptr = ptr->__prev) {}
1640  }
1641 
1642  return ptr;
1643  }
1644 
1645  // insert a new bucket before another one
1646  template < typename Val, typename Alloc >
1648  ListBucket< Val >* current_elt) {
1649  new_elt->__next = current_elt;
1650  new_elt->__prev = current_elt->__prev;
1651  current_elt->__prev = new_elt;
1652 
1653  if (new_elt->__prev == nullptr)
1654  __deb_list = new_elt;
1655  else
1656  new_elt->__prev->__next = new_elt;
1657 
1658  // update the number of elements
1659  ++__nb_elements;
1660 
1661  // returns the current value
1662  return new_elt->__val;
1663  }
1664 
1665  // insert a new bucket after another one
1666  template < typename Val, typename Alloc >
1668  ListBucket< Val >* current_elt) {
1669  new_elt->__prev = current_elt;
1670  new_elt->__next = current_elt->__next;
1671  current_elt->__next = new_elt;
1672 
1673  if (new_elt->__next == nullptr)
1674  __end_list = new_elt;
1675  else
1676  new_elt->__next->__prev = new_elt;
1677 
1678  // update the number of elements
1679  ++__nb_elements;
1680 
1681  // returns the current value
1682  return new_elt->__val;
1683  }
1684 
1685  // inserts a new element at the ith pos of the chained list
1686  template < typename Val, typename Alloc >
1687  INLINE Val& List< Val, Alloc >::insert(Size pos, const Val& val) {
1688  // if ther are fewer elements than pos, put the value at the end of the list
1689  if (__nb_elements <= pos) { return pushBack(val); }
1690 
1691  return __insertBefore(__createBucket(val), __getIthBucket(pos));
1692  }
1693 
1694  // insert an rvalue at the ith pos of the chained list
1695  template < typename Val, typename Alloc >
1696  INLINE Val& List< Val, Alloc >::insert(Size pos, Val&& val) {
1697  // if ther are fewer elements than pos, put the value at the end of the list
1698  if (__nb_elements <= pos) { return pushBack(std::move(val)); }
1699 
1700  return __insertBefore(__createBucket(std::move(val)), __getIthBucket(pos));
1701  }
1702 
1703  // inserts a new bucket before or after the location pointed to by an
1704  // iterator
1705  template < typename Val, typename Alloc >
1707  ListBucket< Val >* new_elt,
1708  location place) {
1709  // find the location around which the new element should be inserted
1710  ListBucket< Val >* ptr;
1711 
1712  if (iter.__null_pointing) {
1713  if (place == location::BEFORE) {
1714  ptr = iter.__next_current_bucket;
1715  } else {
1716  ptr = iter.__prev_current_bucket;
1717  }
1718  } else {
1719  ptr = iter.__getBucket();
1720  }
1721 
1722  if (ptr == nullptr) {
1723  // here, we are at the end of the list
1724  return __pushBack(new_elt);
1725  } else {
1726  switch (place) {
1727  case location::BEFORE: return __insertBefore(new_elt, ptr);
1728 
1729  case location::AFTER: return __insertAfter(new_elt, ptr);
1730 
1731  default:
1732  GUM_ERROR(FatalError, "List insertion for this location unimplemented");
1733  }
1734  }
1735  }
1736 
1737  // inserts a new bucket before or after the location pointed to by an
1738  // iterator
1739  template < typename Val, typename Alloc >
1741  ListBucket< Val >* new_elt,
1742  location place) {
1743  // find the location around which the new element should be inserted
1744  ListBucket< Val >* ptr = iter.__getBucket();
1745 
1746  if (ptr == nullptr) {
1747  // here, we are at the end of the list
1748  return __pushBack(new_elt);
1749  } else {
1750  switch (place) {
1751  case location::BEFORE: return __insertBefore(new_elt, ptr);
1752 
1753  case location::AFTER: return __insertAfter(new_elt, ptr);
1754 
1755  default:
1756  GUM_ERROR(FatalError, "List insertion for this location unimplemented");
1757  }
1758  }
1759  }
1760 
1761  // inserts a new element before or after the location pointed to by an
1762  // iterator
1763  template < typename Val, typename Alloc >
1765  const Val& val,
1766  location place) {
1767  // if the iterator does not point to the list, raise an exception
1768  if (iter.__list != this) {
1770  "the iterator does not point to the correct list");
1771  }
1772 
1773  return __insert(iter, __createBucket(val), place);
1774  }
1775 
1776  // inserts a new element before or after the location pointed to by an
1777  // iterator
1778  template < typename Val, typename Alloc >
1780  Val&& val,
1781  location place) {
1782  // if the iterator does not point to the list, raise an exception
1783  if (iter.__list != this) {
1785  "the iterator does not point to the correct list");
1786  }
1787 
1788  return __insert(iter, __createBucket(std::move(val)), place);
1789  }
1790 
1791  // inserts a new element before or after the location pointed to by an
1792  // iterator
1793  template < typename Val, typename Alloc >
1795  const Val& val,
1796  location place) {
1797  return __insert(iter, __createBucket(val), place);
1798  }
1799 
1800  // inserts a new element before or after the location pointed to by an
1801  // iterator
1802  template < typename Val, typename Alloc >
1804  Val&& val,
1805  location place) {
1806  return __insert(iter, __createBucket(std::move(val)), place);
1807  }
1808 
1809  // emplace a new element before a given iterator
1810  template < typename Val, typename Alloc >
1811  template < typename... Args >
1813  Args&&... args) {
1814  return __insert(iter,
1815  __createEmplaceBucket(std::forward< Args >(args)...),
1816  location::BEFORE);
1817  }
1818 
1819  // emplace a new element before a given iterator
1820  template < typename Val, typename Alloc >
1821  template < typename... Args >
1823  Args&&... args) {
1824  return __insert(iter,
1825  __createEmplaceBucket(std::forward< Args >(args)...),
1826  location::BEFORE);
1827  }
1828 
1829  // returns a reference to first element of a list
1830  template < typename Val, typename Alloc >
1831  INLINE Val& List< Val, Alloc >::front() const {
1832  if (__nb_elements == Size(0)) {
1833  GUM_ERROR(NotFound, "not enough elements in the chained list");
1834  }
1835 
1836  return __deb_list->__val;
1837  }
1838 
1839  // returns a reference to last element of a list
1840  template < typename Val, typename Alloc >
1841  INLINE Val& List< Val, Alloc >::back() const {
1842  if (__nb_elements == Size(0)) {
1843  GUM_ERROR(NotFound, "not enough elements in the chained list");
1844  }
1845 
1846  return __end_list->__val;
1847  }
1848 
1849  // returns the number of elements in the list.
1850  template < typename Val, typename Alloc >
1851  INLINE Size List< Val, Alloc >::size() const noexcept {
1852  return __nb_elements;
1853  }
1854 
1855  // checks whether there exists a given element in the list.
1856  template < typename Val, typename Alloc >
1857  INLINE bool List< Val, Alloc >::exists(const Val& val) const {
1858  for (ListBucket< Val >* ptr = __deb_list; ptr != nullptr; ptr = ptr->__next)
1859  if (ptr->__val == val) return true;
1860 
1861  return false;
1862  }
1863 
1864  // suppresses a given bucket from a chained list.
1865  template < typename Val, typename Alloc >
1867  // perform deletion only if there is a bucket to remove
1868  if (bucket != nullptr) {
1869  // update the iterators pointing on this element
1870  for (const auto ptr_iter : __safe_iterators) {
1871  if (ptr_iter->__bucket == bucket) {
1872  ptr_iter->__next_current_bucket = bucket->__prev;
1873  ptr_iter->__prev_current_bucket = bucket->__next;
1874  ptr_iter->__bucket = nullptr;
1875  ptr_iter->__null_pointing = true;
1876  } else {
1877  if (ptr_iter->__null_pointing) {
1878  if (ptr_iter->__next_current_bucket == bucket)
1879  ptr_iter->__next_current_bucket = bucket->__prev;
1880 
1881  if (ptr_iter->__prev_current_bucket == bucket)
1882  ptr_iter->__prev_current_bucket = bucket->__next;
1883  }
1884  }
1885  }
1886 
1887  // set properly the begin and end of the chained list (the other chainings
1888  // will be performed by operator delete)
1889  if (bucket->__prev == nullptr)
1890  __deb_list = bucket->__next;
1891  else
1892  bucket->__prev->__next = bucket->__next;
1893 
1894  if (bucket->__next == nullptr)
1895  __end_list = bucket->__prev;
1896  else
1897  bucket->__next->__prev = bucket->__prev;
1898 
1899  // remove the current element src the list
1900  __alloc_bucket.destroy(bucket);
1901  __alloc_bucket.deallocate(bucket, 1);
1902 
1903  --__nb_elements;
1904  }
1905  }
1906 
1907  // erases the ith element of the List (the first one is in position 0)
1908  template < typename Val, typename Alloc >
1910  if (i >= __nb_elements) return;
1911 
1912  // erase the ith bucket
1913  __erase(__getIthBucket(i));
1914  }
1915 
1916  // erases the element of the List pointed to by the iterator
1917  template < typename Val, typename Alloc >
1918  INLINE void List< Val, Alloc >::erase(const iterator_safe& iter) {
1919  __erase(iter.__getBucket());
1920  }
1921 
1922  // erases the element of the List pointed to by the iterator
1923  template < typename Val, typename Alloc >
1925  __erase(iter.__getBucket());
1926  }
1927 
1928  // returns the bucket corresponding to a given value.
1929  template < typename Val, typename Alloc >
1931  noexcept {
1932  for (ListBucket< Val >* ptr = __deb_list; ptr != nullptr; ptr = ptr->__next)
1933  if (ptr->__val == val) return ptr;
1934 
1935  return nullptr;
1936  }
1937 
1938  // erases the first element encountered with a given value
1939  template < typename Val, typename Alloc >
1940  INLINE void List< Val, Alloc >::eraseByVal(const Val& val) {
1941  __erase(__getBucket(val));
1942  }
1943 
1944  // erases all the elements encountered with a given value
1945  template < typename Val, typename Alloc >
1946  INLINE void List< Val, Alloc >::eraseAllVal(const Val& val) {
1947  for (ListBucket< Val >*iter = __deb_list, *next_bucket = nullptr;
1948  iter != nullptr;
1949  iter = next_bucket) {
1950  next_bucket = iter->__next;
1951 
1952  if (val == iter->__val) __erase(iter);
1953  }
1954  }
1955 
1956  // removes the last element of a List
1957  template < typename Val, typename Alloc >
1959  __erase(__end_list);
1960  }
1961 
1962  // removes the first element of a List
1963  template < typename Val, typename Alloc >
1965  __erase(__deb_list);
1966  }
1967 
1968  // returns a boolean indicating whether the chained list is empty
1969  template < typename Val, typename Alloc >
1970  INLINE bool List< Val, Alloc >::empty() const noexcept {
1971  return (__nb_elements == Size(0));
1972  }
1973 
1974  // displays the content of a chained list
1975  template < typename Val, typename Alloc >
1976  std::string List< Val, Alloc >::toString() const {
1977  bool deja = false;
1978  std::stringstream stream;
1979  stream << "[";
1980 
1981  for (ListBucket< Val >* ptr = __deb_list; ptr != nullptr;
1982  ptr = ptr->__next, deja = true) {
1983  if (deja) stream << " --> ";
1984 
1985  stream << ptr->__val;
1986  }
1987 
1988  stream << "]";
1989 
1990  return stream.str();
1991  }
1992 
1993  // creates a list of mountains src a list of val
1994  template < typename Val, typename Alloc >
1995  template < typename Mount, typename OtherAlloc >
1997  // create a new empty list
1999 
2000  // fill the new list
2001  for (const_iterator iter = begin(); iter != end(); ++iter) {
2002  list.pushBack(f(*iter));
2003  }
2004 
2005  return list;
2006  }
2007 
2008  // creates a list of mountains src a list of val
2009  template < typename Val, typename Alloc >
2010  template < typename Mount, typename OtherAlloc >
2012  // create a new empty list
2014 
2015  // fill the new list
2016  for (const_iterator iter = begin(); iter != end(); ++iter) {
2017  list.pushBack(f(*iter));
2018  }
2019 
2020  return list;
2021  }
2022 
2023  // creates a list of mountains src a list of val
2024  template < typename Val, typename Alloc >
2025  template < typename Mount, typename OtherAlloc >
2026  List< Mount, OtherAlloc > List< Val, Alloc >::map(Mount (*f)(const Val&)) const {
2027  // create a new empty list
2029 
2030  // fill the new list
2031  for (const_iterator iter = begin(); iter != end(); ++iter) {
2032  list.pushBack(f(*iter));
2033  }
2034 
2035  return list;
2036  }
2037 
2038  // creates a list of mountains with a given value src a list of val
2039  template < typename Val, typename Alloc >
2040  template < typename Mount, typename OtherAlloc >
2042  // create a new empty list
2044 
2045  // fill the new list
2046  for (Size i = Size(0); i < __nb_elements; ++i)
2047  list.pushBack(mount);
2048 
2049  return list;
2050  }
2051 
2052  // creates and insert a new element at the end of the list (alias of
2053  // pushBack).
2054  template < typename Val, typename Alloc >
2055  INLINE Val& List< Val, Alloc >::operator+=(const Val& val) {
2056  return pushBack(val);
2057  }
2058 
2059  // creates and insert a new element at the end of the list (alias of
2060  // pushBack).
2061  template < typename Val, typename Alloc >
2062  INLINE Val& List< Val, Alloc >::operator+=(Val&& val) {
2063  return pushBack(std::move(val));
2064  }
2065 
2066  // checks whether two lists are identical (same elements in the same order)
2067  template < typename Val, typename Alloc >
2068  template < typename OtherAlloc >
2069  INLINE bool List< Val, Alloc >::
2071  // check if the two lists have at least the same number of elements
2072  if (__nb_elements != src.__nb_elements) return false;
2073 
2074  // parse the two lists
2075  for (ListBucket< Val >*iter1 = __deb_list, *iter2 = src.__deb_list;
2076  iter1 != nullptr;
2077  iter1 = iter1->__next, iter2 = iter2->__next)
2078  if (*iter1 != *iter2) return false;
2079 
2080  return true;
2081  }
2082 
2083  // checks whether two lists are different (different elements or orders)
2084  template < typename Val, typename Alloc >
2085  template < typename OtherAlloc >
2086  INLINE bool List< Val, Alloc >::
2088  return !operator==(src);
2089  }
2090 
2091  // returns the ith element in the current chained list.
2092  template < typename Val, typename Alloc >
2093  INLINE Val& List< Val, Alloc >::operator[](const Size i) {
2094  // check if we can return the element we ask for
2095  if (i >= __nb_elements) {
2096  GUM_ERROR(NotFound, "not enough elements in the chained list");
2097  }
2098 
2099  return **__getIthBucket(i);
2100  }
2101 
2102  // returns the ith element in the current chained list.
2103  template < typename Val, typename Alloc >
2104  INLINE const Val& List< Val, Alloc >::operator[](const Size i) const {
2105  // check if we can return the element we ask for
2106  if (i >= __nb_elements) {
2107  GUM_ERROR(NotFound, "not enough elements in the chained list");
2108  }
2109 
2110  return **__getIthBucket(i);
2111  }
2112 
2113  // replace the current list with another one
2114  template < typename Val, typename Alloc >
2115  INLINE void List< Val, Alloc >::swap(List& other_list) {
2116  std::swap(__deb_list, other_list.__deb_list);
2117  std::swap(__end_list, other_list.__end_list);
2118  std::swap(__nb_elements, other_list.__nb_elements);
2119  std::swap(__safe_iterators, other_list.__safe_iterators);
2120  std::swap(__alloc_bucket, other_list.__alloc_bucket);
2121  }
2122 
2123  // A \c << operator for List
2124  template < typename Val >
2125  std::ostream& operator<<(std::ostream& stream, const List< Val >& list) {
2126  stream << list.toString();
2127  return stream;
2128  }
2129 
2130 } /* namespace gum */
ListBucket< Val > * __next
Chaining toward the adjacent elements.
Definition: list.h:245
ListConstIteratorSafe() noexcept
Default constructor.
Definition: list_tpl.h:492
ListIterator< Val > & operator-=(difference_type i) noexcept
Makes the iterator point to i elements befor in the List.
Definition: list_tpl.h:453
const Val & operator*() const
Gives access to the content of the iterator.
Definition: list_tpl.h:338
ListConstIteratorSafe< Val > & operator+=(difference_type i) noexcept
Makes the iterator point to i elements further in the List.
Definition: list_tpl.h:849
ListConstIteratorSafe< Val > operator+(difference_type i) noexcept
Returns a new iterator pointing to i further elements in the gum::List.
Definition: list_tpl.h:911
ListConstIteratorSafe< Val > & __opPlus(Size i) noexcept
Makes the iterator point to the next element in the List.
Definition: list_tpl.h:812
const Val & operator*() const
Gives access to the content of the iterator.
Definition: list_tpl.h:954
ListBucket< Val > * __next_current_bucket
The bucket we should start from when we are pointing on a deleted bucket and we decide to do a ++...
Definition: list.h:2260
ListConstIterator< Val > & operator+=(difference_type i) noexcept
Makes the iterator point to i elements further in the List.
Definition: list_tpl.h:266
Safe iterators for Lists.
Definition: list.h:2342
ListBucket< Val > * __prev
Chaining toward the adjacent elements.
Definition: list.h:244
Unsafe but fast iterators for Lists.
Definition: list.h:1794
location
Locations around iterators where insertions of new elements can take / place.
Definition: list.h:396
#define GUM_DEFAULT_ITERATOR_NUMBER
Definition: list.h:42
STL namespace.
ListIterator< Val > & operator++() noexcept
Makes the iterator point to the next element in the List.
Definition: list_tpl.h:430
bool __null_pointing
Indicates whether the bucket the iterator points to has been deleted.
Definition: list.h:2267
std::ptrdiff_t difference_type
Types for STL compliance.
Definition: list.h:1518
Val & operator*()
Gives access to the iterator&#39;s content.
Definition: list_tpl.h:480
void swap(HashTable< LpCol, double > *&a, HashTable< LpCol, double > *&b)
Swap the addresses of two pointers to hashTables.
ListConstIteratorSafe< Val > & operator-=(difference_type i) noexcept
Makes the iterator point to i elements befor in the List.
Definition: list_tpl.h:898
Generic doubly linked lists.
Definition: list.h:372
ListConstIterator< Val > & operator++() noexcept
Makes the iterator point to the next element in the List.
Definition: list_tpl.h:255
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
bool operator==(const ListConstIteratorSafe< Val > &src) const
Checks whether two iterators point toward the same elements.
Definition: list_tpl.h:935
ListBucket< Val > * __bucket
The bucket in the chained list pointed to by the iterator.
Definition: list.h:2256
ListIterator< Val > & operator=(const ListIterator< Val > &src) noexcept
Copy operator.
Definition: list_tpl.h:407
Size __nb_elements
The number of elements in the list.
Definition: list.h:1308
ListConstIterator< Val > & operator-=(difference_type i) noexcept
Makes the iterator point to i elements befor in the List.
Definition: list_tpl.h:289
~ListIteratorSafe()
Class Desctructor.
Definition: list_tpl.h:1045
ListIteratorSafe< Val > operator-(difference_type i) noexcept
Returns a new iterator pointing to i preceding elements in the gum::List.
Definition: list_tpl.h:1089
ListIteratorSafe< Val > & operator+=(difference_type i) noexcept
Makes the iterator point to i elements further in the List.
Definition: list_tpl.h:1059
ListIteratorSafe< Val > & operator++() noexcept
Makes the iterator point to the next element in the List.
Definition: list_tpl.h:1051
Emplace
C dummy type for the emplace constructor.
Definition: list.h:112
ListIterator< Val > & operator+=(difference_type i) noexcept
Makes the iterator point to i elements further in the List.
Definition: list_tpl.h:438
std::vector< const_iterator_safe *> __safe_iterators
The list of "safe" iterators attached to the list.
Definition: list.h:1311
ListBucket()=delete
Removes empty constructor.
ListConstIterator< Val > & operator=(const ListConstIterator< Val > &src) noexcept
Copy operator.
Definition: list_tpl.h:208
ListIterator< Val > operator-(difference_type i) noexcept
Returns a new iterator pointing to i preceding elements in the gum::List.
Definition: list_tpl.h:468
ListIteratorSafe< Val > & operator=(const ListIteratorSafe< Val > &src)
Copy operator.
Definition: list_tpl.h:1026
ListConstIteratorSafe< Val > operator-(difference_type i) noexcept
Returns a new iterator pointing to i preceding elements in the gum::List.
Definition: list_tpl.h:918
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
std::ptrdiff_t difference_type
Types for STL compliance.
Definition: list.h:2040
ListConstIteratorSafe< Val > & operator--() noexcept
Makes the iterator point to the preceding element in the List.
Definition: list_tpl.h:862
ListBucket< Val > * __prev_current_bucket
The bucket we should start from when we are pointing on a deleted bucket and we decide to do a –...
Definition: list.h:2264
ListIteratorSafe< Val > & operator-=(difference_type i) noexcept
Makes the iterator point to i elements befor in the List.
Definition: list_tpl.h:1074
LpExpr operator+(LpExpr &&lhs, const T2 &rhs)
Overload of operator + between anything ( a scalar, a variable or an expression ) and anything except...
Val & pushBack(const Val &val)
Inserts a new element (a copy) at the end of the chained list.
Definition: list_tpl.h:1592
bool operator==(const TiXmlString &a, const TiXmlString &b)
Definition: tinystr.h:243
std::ptrdiff_t difference_type
Types for STL compliance.
Definition: list.h:2352
void __removeFromSafeList() const
Remove the iterator for its list&#39; safe iterators list.
Definition: list_tpl.h:592
Unsafe but fast const iterators for Lists.
Definition: list.h:1508
ListIteratorSafe() noexcept
Default constructor.
Definition: list_tpl.h:983
void setToEnd()
Positions the iterator to the end of the list.
Definition: list_tpl.h:721
~ListIterator() noexcept
Class destructor.
Definition: list_tpl.h:424
LpExpr operator*(const SCALAR &lhs, const LpCol &rhs)
Overload of operator * between a scalar and a variable.
Val * operator->()
Dereferences the value pointed to by the iterator.
Definition: list_tpl.h:1095
~ListConstIteratorSafe()
Class Desctructor.
Definition: list_tpl.h:692
Val & operator*()
Gives access to the content of the iterator.
Definition: list_tpl.h:1101
void clear()
Makes the iterator point toward nothing.
Definition: list_tpl.h:709
bool operator!=(const TiXmlString &a, const TiXmlString &b)
Definition: tinystr.h:251
ListBucket< Val > * __getBucket() const noexcept
Returns the bucket the iterator is pointing to.
Definition: list_tpl.h:702
Val __val
Val is the value contained in the box.
Definition: list.h:249
bool operator!=(const ListConstIteratorSafe< Val > &src) const
Checks whether two iterators point toward different elements.
Definition: list_tpl.h:925
List()
A basic constructor that creates an empty list.
Definition: list_tpl.h:1186
ListConstIteratorSafe< Val > & __opMinus(Size i) noexcept
Makes the iterator point to i elements before in the List.
Definition: list_tpl.h:774
Safe const iterators for Lists.
Definition: list.h:2030
ListConstIterator< Val > & operator--() noexcept
Makes the iterator point to the preceding element in the List.
Definition: list_tpl.h:278
Val * operator->()
Dereferences the value pointed to by the iterator.
Definition: list_tpl.h:474
ListConstIteratorSafe< Val > & operator++() noexcept
Makes the iterator point to the next element in the List.
Definition: list_tpl.h:737
Bucket for a chained list.
Definition: list.h:105
Size Idx
Type for indexes.
Definition: types.h:53
INLINE ListConstIteratorSafe< Val >::difference_type operator-(const ListConstIteratorSafe< Val > &iter1, const ListConstIteratorSafe< Val > &iter2)
For STL compliance, a distance operator.
Definition: list_tpl.h:965
ListConstIteratorSafe< Val > & operator=(const ListConstIteratorSafe< Val > &src)
Copy operator.
Definition: list_tpl.h:607
void __copy_elements(const List< Val, OtherAlloc > &src)
A function used to perform copies of elements of Lists.
Definition: list_tpl.h:1114
bool isEnd() const
Returns a bool indicating whether the iterator points to the end of the list.
Definition: list_tpl.h:728
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
ListBucket< Val > * __deb_list
A pointer on the first element of the chained list.
Definition: list.h:1302
BucketAllocator __alloc_bucket
The allocator for the buckets.
Definition: list.h:1314
void clear()
Deletes all the elements of a chained list.
Definition: list_tpl.h:1164
ListIteratorSafe< Val > operator+(difference_type i) noexcept
Returns a new iterator pointing to i further elements in the gum::List.
Definition: list_tpl.h:1082
ListIterator< Val > operator+(difference_type i) noexcept
Returns a new iterator pointing to i further elements in the gum::List.
Definition: list_tpl.h:461
std::ptrdiff_t difference_type
Types for STL compliance.
Definition: list.h:1804
const Val * operator->() const
Dereferences the value pointed to by the iterator.
Definition: list_tpl.h:328
const List< Val, std::allocator< Val > > * __list
The list the iterator is pointing to.
Definition: list.h:2253
ListIteratorSafe< Val > & operator--() noexcept
Makes the iterator point to the preceding element in the List.
Definition: list_tpl.h:1066
ListBucket< Val > * __bucket
The bucket in the chained list pointed to by the iterator.
Definition: list.h:1728
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
ListBucket< Val > * __end_list
A pointer on the last element of the chained list.
Definition: list.h:1305
ListIterator< Val > & operator--() noexcept
Makes the iterator point to the preceding element in the List.
Definition: list_tpl.h:445
ListBucket< Val > * __getBucket() const noexcept
Returns the bucket the iterator is pointing to.
Definition: list_tpl.h:228
const Val * operator->() const
Dereferences the value pointed to by the iterator.
Definition: list_tpl.h:944