1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
23 namespace intrusive_list_impl {
25 template <typename T, typename I>
28 using difference_type = void;
29 using value_type = std::remove_cv_t<T>;
32 using iterator_category = std::forward_iterator_tag;
34 constexpr explicit Iterator() : item_(nullptr) {}
36 constexpr Iterator& operator++() {
37 item_ = static_cast<I*>(item_->next_);
41 constexpr Iterator operator++(int) {
42 Iterator previous_value(item_);
44 return previous_value;
47 constexpr const T& operator*() const { return *static_cast<T*>(item_); }
48 constexpr T& operator*() { return *static_cast<T*>(item_); }
50 constexpr const T* operator->() const { return static_cast<T*>(item_); }
51 constexpr T* operator->() { return static_cast<T*>(item_); }
53 constexpr bool operator==(const Iterator& rhs) const {
54 return item_ == rhs.item_;
56 constexpr bool operator!=(const Iterator& rhs) const {
57 return item_ != rhs.item_;
62 friend class ::pw::IntrusiveList;
64 // Only allow IntrusiveList to create iterators that point to something.
65 constexpr explicit Iterator(I* item) : item_{item} {}
74 constexpr Item() : Item(this) {}
76 bool unlisted() const { return this == next_; }
78 // Unlink this from the list it is apart of, if any. Specifying prev saves
79 // calling previous(), which requires looping around the cycle.
80 void unlist(Item* prev = nullptr);
82 Item* previous(); // Note: O(n) since it loops around the cycle.
89 template <typename T, typename I>
90 friend class Iterator;
92 constexpr Item(Item* next) : next_(next) {}
94 // The next pointer. Unlisted items must be self-cycles (next_ == this).
98 constexpr List() : head_(end()) {}
100 template <typename Iterator>
101 List(Iterator first, Iterator last) : List() {
102 AssignFromIterator(first, last);
105 // Intrusive lists cannot be copied, since each Item can only be in one list.
106 List(const List&) = delete;
107 List& operator=(const List&) = delete;
109 template <typename Iterator>
110 void assign(Iterator first, Iterator last) {
112 AssignFromIterator(first, last);
115 bool empty() const noexcept { return begin() == end(); }
117 static void insert_after(Item* pos, Item& item);
119 static void erase_after(Item* pos);
123 bool remove(const Item& item_to_remove);
125 constexpr Item* before_begin() noexcept { return &head_; }
126 constexpr const Item* before_begin() const noexcept { return &head_; }
128 constexpr Item* begin() noexcept { return head_.next_; }
129 constexpr const Item* begin() const noexcept { return head_.next_; }
131 Item* before_end() noexcept;
133 constexpr Item* end() noexcept { return &head_; }
134 constexpr const Item* end() const noexcept { return &head_; }
139 template <typename Iterator>
140 void AssignFromIterator(Iterator first, Iterator last);
142 // Use an Item for the head pointer. This gives simpler logic for inserting
143 // elements compared to using an Item*. It also makes it possible to use
144 // &head_ for end(), rather than nullptr. This makes end() unique for each
145 // List and ensures that items already in a list cannot be added to another.
149 template <typename Iterator>
150 void List::AssignFromIterator(Iterator first, Iterator last) {
151 Item* current = &head_;
153 for (Iterator it = first; it != last; ++it) {
154 if constexpr (std::is_pointer<std::remove_reference_t<decltype(*it)>>()) {
155 insert_after(current, **it);
158 insert_after(current, *it);
164 } // namespace intrusive_list_impl