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