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