cycle_ptr
llist.h
1 #ifndef CYCLE_PTR_DETAIL_LLIST_H
2 #define CYCLE_PTR_DETAIL_LLIST_H
3 
4 #include <cassert>
5 #include <utility>
6 #include <iterator>
7 #include <initializer_list>
8 
9 namespace cycle_ptr::detail {
10 
11 
13 struct llist_head_tag {};
14 
15 template<typename> class link;
16 
17 
23 template<typename T, typename Tag>
24 class llist
25 : private link<Tag>
26 {
27  static_assert(std::is_base_of_v<link<Tag>, T>,
28  "Require T to derive from link<Tag>.");
29 
30  public:
32  using value_type = T;
34  using reference = T&;
36  using const_reference = const T&;
38  using pointer = T*;
40  using const_pointer = const T*;
42  using size_type = std::uintptr_t;
43 
44  class iterator;
45  class const_iterator;
46 
48  using reverse_iterator = std::reverse_iterator<iterator>;
50  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
51 
53  llist() noexcept
54  : link<Tag>(llist_head_tag())
55  {}
56 
57  llist(const llist&) = delete;
58  auto operator=(const llist&) -> llist& = delete;
59 
61  llist(llist&& other) noexcept
62  : link<Tag>()
63  {
64  splice(end(), other);
65  }
66 
70  template<typename Iter>
71  llist(Iter b, Iter e)
72  : llist()
73  {
74  insert(end(), b, e);
75  }
76 
79  ~llist() noexcept {
80  clear();
81  }
82 
85  auto empty() const
86  noexcept
87  -> bool {
88  return this->pred_ == this;
89  }
90 
94  auto size() const
95  noexcept
96  -> size_type {
97  return static_cast<size_type>(std::distance(begin(), end()));
98  }
99 
101  auto clear()
102  noexcept
103  -> void {
104  erase(begin(), end());
105  }
106 
110  static auto iterator_to(T& elem)
111  noexcept
112  -> iterator {
113  return iterator(std::addressof(elem));
114  }
115 
119  static auto iterator_to(const T& elem)
120  noexcept
121  -> const_iterator {
122  return const_iterator(std::addressof(elem));
123  }
124 
129  auto front()
130  -> T& {
131  assert(!empty());
132  return *begin();
133  }
134 
139  auto front() const
140  -> const T& {
141  assert(!empty());
142  return *begin();
143  }
144 
149  auto back()
150  -> T& {
151  assert(!empty());
152  return *std::prev(end());
153  }
154 
159  auto back() const
160  -> const T& {
161  assert(!empty());
162  return *std::prev(end());
163  }
164 
166  auto begin()
167  noexcept
168  -> iterator {
169  return iterator(this->succ_);
170  }
171 
173  auto begin() const
174  noexcept
175  -> const_iterator {
176  return cbegin();
177  }
178 
180  auto cbegin() const
181  noexcept
182  -> const_iterator {
183  return const_iterator(this->succ_);
184  }
185 
187  auto end()
188  noexcept
189  -> iterator {
190  return iterator(this);
191  }
192 
194  auto end() const
195  noexcept
196  -> const_iterator {
197  return cend();
198  }
199 
201  auto cend() const
202  noexcept
203  -> const_iterator {
204  return const_iterator(this);
205  }
206 
208  auto rbegin()
209  noexcept
210  -> reverse_iterator {
211  return reverse_iterator(end());
212  }
213 
215  auto rbegin() const
216  noexcept
218  return crbegin();
219  }
220 
222  auto crbegin() const
223  noexcept
225  return const_reverse_iterator(cend());
226  }
227 
229  auto rend()
230  noexcept
231  -> reverse_iterator {
232  return reverse_iterator(begin());
233  }
234 
236  auto rend() const
237  noexcept
239  return crend();
240  }
241 
243  auto crend() const
244  noexcept
246  return const_reverse_iterator(cbegin());
247  }
248 
251  auto push_back(T& v)
252  noexcept
253  -> void {
254  insert(end(), v);
255  }
256 
259  auto push_front(T& v)
260  noexcept
261  -> void {
262  insert(begin(), v);
263  }
264 
269  auto insert(const_iterator pos, T& v) noexcept -> iterator;
270 
276  template<typename Iter>
277  auto insert(const_iterator pos, Iter b, Iter e) -> iterator;
278 
283  auto pop_front()
284  -> T& {
285  assert(!empty());
286  T& result = front();
287  erase(begin());
288  return result;
289  }
290 
295  auto pop_back()
296  -> T& {
297  assert(!empty());
298  T& result = back();
299  erase(std::prev(end()));
300  return result;
301  }
302 
306  auto erase(const_iterator b) -> iterator;
311  auto erase(const_iterator b, const_iterator e) -> iterator;
312 
318  auto splice(const_iterator pos, llist& other) noexcept -> void;
325  auto splice(const_iterator pos, llist& other, const_iterator elem) noexcept -> void;
332  auto splice(const_iterator pos, llist& other, const_iterator other_begin, const_iterator other_end) noexcept -> void;
333 };
334 
335 
346 template<typename Tag>
347 class link {
348  template<typename, typename> friend class llist;
349 
350  public:
352  constexpr link() noexcept = default;
353 
355 #ifndef NDEBUG
356  ~link() noexcept {
357  assert((pred_ == nullptr && succ_ == nullptr)
358  || (pred_ == this && succ_ == this));
359  }
360 #else
361  ~link() noexcept = default;
362 #endif
363 
364  protected:
373  constexpr link([[maybe_unused]] const link& other) noexcept
374  : link()
375  {}
376 
385  constexpr auto operator=([[maybe_unused]] const link& other) noexcept
386  -> link& {
387  return *this;
388  }
389 
390  private:
395  link([[maybe_unused]] const llist_head_tag& lht) noexcept
396  : pred_(this),
397  succ_(this)
398  {}
399 
400  protected:
403  constexpr auto linked() const
404  noexcept
405  -> bool {
406  return pred_ != nullptr;
407  }
408 
409  private:
411  link* pred_ = nullptr;
413  link* succ_ = nullptr;
414 };
415 
416 
420 template<typename T, typename Tag>
421 class llist<T, Tag>::iterator {
422  template<typename, typename> friend class llist;
423  friend class llist::const_iterator;
424 
425  public:
427  using value_type = T;
429  using reference = T&;
431  using pointer = T*;
433  using difference_type = std::intptr_t;
435  using iterator_category = std::bidirectional_iterator_tag;
436 
437  private:
441  explicit constexpr iterator(link<Tag>* ptr) noexcept
442  : link_(ptr)
443  {
444  assert(ptr != nullptr);
445  }
446 
447  public:
450  constexpr iterator() noexcept = default;
451 
454  auto operator*() const
455  noexcept
456  -> T& {
457  assert(link_ != nullptr);
458  return *static_cast<T*>(link_);
459  }
460 
463  auto operator->() const
464  noexcept
465  -> T* {
466  assert(link_ != nullptr);
467  return static_cast<T*>(link_);
468  }
469 
472  auto operator++()
473  noexcept
474  -> iterator& {
475  assert(link_ != nullptr);
476  link_ = link_->succ_;
477  return *this;
478  }
479 
482  auto operator--()
483  noexcept
484  -> iterator& {
485  assert(link_ != nullptr);
486  link_ = link_->pred_;
487  return *this;
488  }
489 
492  auto operator++(int)
493  noexcept
494  -> iterator {
495  iterator result = *this;
496  ++*this;
497  return result;
498  }
499 
502  auto operator--(int)
503  noexcept
504  -> iterator {
505  iterator result = *this;
506  --*this;
507  return result;
508  }
509 
511  auto operator==(const iterator& other) const
512  noexcept
513  -> bool {
514  return link_ == other.link_;
515  }
516 
518  auto operator!=(const iterator& other) const
519  noexcept
520  -> bool {
521  return !(*this == other);
522  }
523 
525  auto operator==(const const_iterator& other) const
526  noexcept
527  -> bool {
528  return link_ == other.link_;
529  }
530 
532  auto operator!=(const const_iterator& other) const
533  noexcept
534  -> bool {
535  return !(*this == other);
536  }
537 
538  private:
540  link<Tag>* link_ = nullptr;
541 };
542 
546 template<typename T, typename Tag>
547 class llist<T, Tag>::const_iterator {
548  template<typename, typename> friend class llist;
549  friend class llist::iterator;
550 
551  public:
553  using value_type = T;
555  using reference = const T&;
557  using pointer = const T*;
559  using difference_type = std::intptr_t;
561  using iterator_category = std::bidirectional_iterator_tag;
562 
563  private:
567  explicit constexpr const_iterator(const link<Tag>* ptr) noexcept
568  : link_(ptr)
569  {
570  assert(ptr != nullptr);
571  }
572 
573  public:
576  constexpr const_iterator() noexcept = default;
577 
581  constexpr const_iterator(const iterator& other) noexcept
582  : link_(other.link_)
583  {}
584 
588  constexpr auto operator=(const iterator& other)
589  noexcept
590  -> const_iterator& {
591  link_ = other.link_;
592  return *this;
593  }
594 
597  auto operator*() const
598  noexcept
599  -> const T& {
600  assert(link_ != nullptr);
601  return *static_cast<const T*>(link_);
602  }
603 
606  auto operator->() const
607  noexcept
608  -> const T* {
609  assert(link_ != nullptr);
610  return static_cast<const T*>(link_);
611  }
612 
615  auto operator++()
616  noexcept
617  -> const_iterator& {
618  assert(link_ != nullptr);
619  link_ = link_->succ_;
620  return *this;
621  }
622 
625  auto operator--()
626  noexcept
627  -> const_iterator& {
628  assert(link_ != nullptr);
629  link_ = link_->pred_;
630  return *this;
631  }
632 
635  auto operator++(int)
636  noexcept
637  -> const_iterator {
638  const_iterator result = *this;
639  ++*this;
640  return result;
641  }
642 
645  auto operator--(int)
646  noexcept
647  -> const_iterator {
648  const_iterator result = *this;
649  --*this;
650  return result;
651  }
652 
654  auto operator==(const const_iterator& other) const
655  noexcept
656  -> bool {
657  return link_ == other.link_;
658  }
659 
661  auto operator!=(const const_iterator& other) const
662  noexcept
663  -> bool {
664  return !(*this == other);
665  }
666 
668  auto operator==(const iterator& other) const
669  noexcept
670  -> bool {
671  return link_ == other.link_;
672  }
673 
675  auto operator!=(const iterator& other) const
676  noexcept
677  -> bool {
678  return !(*this == other);
679  }
680 
681  private:
683  const link<Tag>* link_ = nullptr;
684 };
685 
686 
687 template<typename T, typename Tag>
688 auto llist<T, Tag>::insert(const_iterator pos, T& v)
689 noexcept
690 -> iterator {
691  assert(pos.link_ != nullptr);
692 
693  link<Tag>*const vlink = std::addressof(v);
694  assert(vlink->succ_ == nullptr && vlink->pred_ == nullptr);
695  link<Tag>*const succ = const_cast<link<Tag>*>(pos.link_);
696  link<Tag>*const pred = succ->pred_;
697 
698  vlink->pred_ = std::exchange(succ->pred_, vlink);
699  vlink->succ_ = std::exchange(pred->succ_, vlink);
700  return iterator(vlink);
701 }
702 
703 template<typename T, typename Tag>
704 template<typename Iter>
705 auto llist<T, Tag>::insert(const_iterator pos, Iter b, Iter e)
706 -> iterator {
707  assert(pos.link_ != nullptr);
708  if (b == e) return iterator(const_cast<link<Tag>*>(pos.link_));
709 
710  iterator result = insert(pos, *b);
711  while (++b != e) insert(pos, *b);
712  return result;
713 }
714 
715 template<typename T, typename Tag>
716 auto llist<T, Tag>::erase(const_iterator b)
717 -> iterator {
718  assert(b != end());
719  return erase(b, std::next(b));
720 }
721 
722 template<typename T, typename Tag>
723 auto llist<T, Tag>::erase(const_iterator b, const_iterator e)
724 -> iterator {
725  assert(b.link_ != nullptr && e.link_ != nullptr);
726 
727  if (b == e) return iterator(const_cast<link<Tag>*>(e.link_));
728 
729  link<Tag>*const pred = b.link_->pred_;
730  assert(pred->succ_ == b.link_);
731  link<Tag>*const succ = const_cast<link<Tag>*>(e.link_);
732 
733  pred->succ_ = succ;
734  succ->pred_ = pred;
735 
736  while (b != e) {
737  link<Tag>*const l = const_cast<link<Tag>*>(b.link_);
738  ++b;
739  assert(l != this);
740  l->pred_ = l->succ_ = nullptr;
741  }
742  return iterator(succ);
743 }
744 
745 template<typename T, typename Tag>
746 auto llist<T, Tag>::splice(const_iterator pos, llist& other)
747 noexcept
748 -> void {
749  assert(&other != this);
750  splice(pos, other, other.begin(), other.end());
751 }
752 
753 template<typename T, typename Tag>
754 auto llist<T, Tag>::splice(const_iterator pos, llist& other, const_iterator elem)
755 noexcept
756 -> void {
757  assert(pos.link_ != nullptr && elem.link_ != nullptr);
758  if (elem.link_ == pos.link_) return; // Insert before self.
759  splice(pos, other, elem, std::next(elem));
760 }
761 
762 template<typename T, typename Tag>
763 auto llist<T, Tag>::splice(const_iterator pos, llist& other, const_iterator other_begin, const_iterator other_end)
764 noexcept
765 -> void {
766 #ifndef NDEBUG
767  assert(pos.link_ != nullptr && other_begin.link_ != nullptr && other_end.link_ != nullptr);
768  for (const_iterator i = other_begin; i != other_end; ++i)
769  assert(pos != i); // Cannot splice inside of range.
770  for (const_iterator i = other_begin; i != other_end; ++i)
771  assert(other.end() != i); // Cannot splice list head.
772 #endif
773 
774  if (other_begin == other_end) return; // Empty range.
775  if (pos == other_end) {
776  assert(this == &other);
777  return; // Splice into same position.
778  }
779 
780  link<Tag>*const my_succ = const_cast<link<Tag>*>(pos.link_);
781  link<Tag>*const my_pred = my_succ->pred_;
782  link<Tag>*const other_first = const_cast<link<Tag>*>(other_begin.link_);
783  link<Tag>*const other_pred = other_first->pred_;
784  link<Tag>*const other_succ = const_cast<link<Tag>*>(other_end.link_);
785  link<Tag>*const other_last = other_succ->pred_;
786 
787  my_succ->pred_ = other_last;
788  my_pred->succ_ = other_first;
789 
790  other_last->succ_ = my_succ;
791  other_first->pred_ = my_pred;
792 
793  other_succ->pred_ = other_pred;
794  other_pred->succ_ = other_succ;
795 }
796 
797 
798 } /* namespace cycle_ptr::detail */
799 
800 #endif /* CYCLE_PTR_DETAIL_LLIST_H */
auto operator!=(const iterator &other) const noexcept -> bool
Inequality comparator.
Definition: llist.h:675
auto operator->() const noexcept -> const T *
Indirection operation.
Definition: llist.h:606
auto operator!=(const const_iterator &other) const noexcept -> bool
Inequality comparator.
Definition: llist.h:532
std::intptr_t difference_type
Difference type of the iterator.
Definition: llist.h:433
auto begin() const noexcept -> const_iterator
Return iterator to first element in the list.
Definition: llist.h:173
const T * pointer
Pointer type of the list.
Definition: llist.h:557
auto pop_back() -> T &
Unlink the last element in the list.
Definition: llist.h:295
Const iterator for llist.
Definition: llist.h:547
auto operator--() noexcept -> iterator &
Move iterator position backward.
Definition: llist.h:482
static auto iterator_to(const T &elem) noexcept -> const_iterator
Create iterator to element.
Definition: llist.h:119
llist(Iter b, Iter e)
Range constructor.
Definition: llist.h:71
Iterator for llist.
Definition: llist.h:421
auto empty() const noexcept -> bool
Test if this list is empty.
Definition: llist.h:85
~llist() noexcept
Destructor.
Definition: llist.h:79
auto operator++(int) noexcept -> iterator
Advance iterator.
Definition: llist.h:492
Tag used to indicate a link is to be the root of a linked list.
Definition: llist.h:13
auto operator--() noexcept -> const_iterator &
Move iterator position backward.
Definition: llist.h:625
auto operator--(int) noexcept -> iterator
Move iterator position backward.
Definition: llist.h:502
auto operator!=(const iterator &other) const noexcept -> bool
Inequality comparator.
Definition: llist.h:518
auto operator!=(const const_iterator &other) const noexcept -> bool
Inequality comparator.
Definition: llist.h:661
auto operator==(const const_iterator &other) const noexcept -> bool
Equality comparator.
Definition: llist.h:525
auto rend() const noexcept -> const_reverse_iterator
Return iterator past the last element in reverse iteration.
Definition: llist.h:236
auto front() -> T &
Reference to first item in this list.
Definition: llist.h:129
auto crend() const noexcept -> const_reverse_iterator
Return iterator past the last element in reverse iteration.
Definition: llist.h:243
auto back() const -> const T &
Reference to last item in this list.
Definition: llist.h:159
auto back() -> T &
Reference to last item in this list.
Definition: llist.h:149
auto erase(const_iterator b) -> iterator
Erase element from the list.
Definition: llist.h:716
auto operator==(const const_iterator &other) const noexcept -> bool
Equality comparator.
Definition: llist.h:654
std::intptr_t difference_type
Difference type of the iterator.
Definition: llist.h:559
auto end() const noexcept -> const_iterator
Return iterator past the last element in the list.
Definition: llist.h:194
auto push_front(T &v) noexcept -> void
Link element into the list, as the first item.
Definition: llist.h:259
auto cbegin() const noexcept -> const_iterator
Return iterator to first element in the list.
Definition: llist.h:180
std::bidirectional_iterator_tag iterator_category
Iterator is a bidirectional iterator.
Definition: llist.h:435
auto begin() noexcept -> iterator
Return iterator to first element in the list.
Definition: llist.h:166
Intrusive linked list.
Definition: llist.h:24
auto operator++() noexcept -> iterator &
Advance iterator.
Definition: llist.h:472
auto rbegin() noexcept -> reverse_iterator
Return iterator to first element in reverse iteration.
Definition: llist.h:208
auto insert(const_iterator pos, T &v) noexcept -> iterator
Link element into the list.
Definition: llist.h:688
Definition: vertex.h:14
auto splice(const_iterator pos, llist &other) noexcept -> void
Splice elements from list.
Definition: llist.h:746
auto cend() const noexcept -> const_iterator
Return iterator past the last element in the list.
Definition: llist.h:201
T & reference
Reference type of the list.
Definition: llist.h:429
llist(llist &&other) noexcept
Move constructor.
Definition: llist.h:61
auto push_back(T &v) noexcept -> void
Link element into the list, as the last item.
Definition: llist.h:251
std::bidirectional_iterator_tag iterator_category
Iterator is a bidirectional iterator.
Definition: llist.h:561
T value_type
Value type of the list.
Definition: llist.h:427
auto operator->() const noexcept -> T *
Indirection operation.
Definition: llist.h:463
auto operator==(const iterator &other) const noexcept -> bool
Equality comparator.
Definition: llist.h:668
auto size() const noexcept -> size_type
Compute the size of the list.
Definition: llist.h:94
auto crbegin() const noexcept -> const_reverse_iterator
Return iterator to first element in reverse iteration.
Definition: llist.h:222
auto rend() noexcept -> reverse_iterator
Return iterator past the last element in reverse iteration.
Definition: llist.h:229
auto rbegin() const noexcept -> const_reverse_iterator
Return iterator to first element in reverse iteration.
Definition: llist.h:215
constexpr auto operator=(const iterator &other) noexcept -> const_iterator &
Conversion assignment.
Definition: llist.h:588
T value_type
Value type of the list.
Definition: llist.h:553
auto operator++(int) noexcept -> const_iterator
Advance iterator.
Definition: llist.h:635
auto clear() noexcept -> void
Unlink all elements from the list.
Definition: llist.h:101
llist() noexcept
Default constructor.
Definition: llist.h:53
std::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
Definition: llist.h:48
auto front() const -> const T &
Reference to first item in this list.
Definition: llist.h:139
std::reverse_iterator< const_iterator > const_reverse_iterator
Reverse const_iterator type.
Definition: llist.h:50
auto operator++() noexcept -> const_iterator &
Advance iterator.
Definition: llist.h:615
std::uintptr_t size_type
Size type of the list.
Definition: llist.h:42
const T & reference
Reference type of the list.
Definition: llist.h:555
auto operator--(int) noexcept -> const_iterator
Move iterator position backward.
Definition: llist.h:645
auto end() noexcept -> iterator
Return iterator past the last element in the list.
Definition: llist.h:187
auto pop_front() -> T &
Unlink the first element in the list.
Definition: llist.h:283
static auto iterator_to(T &elem) noexcept -> iterator
Create iterator to element.
Definition: llist.h:110
auto operator==(const iterator &other) const noexcept -> bool
Equality comparator.
Definition: llist.h:511
T * pointer
Pointer type of the list.
Definition: llist.h:431