13 [[nodiscard]]
static bool is_linked(
Node const& node)
noexcept {
return Traits::get_next(node) != &node; }
15 static void init(
Node& node)
noexcept {
16 Traits::set_next(node, &node);
17 Traits::set_prev(node, &node);
20 static void link_before(
Node& node,
Node& pos)
noexcept {
21 Node* prev = Traits::get_prev(pos);
22 Traits::set_prev(node, prev);
23 Traits::set_next(node, &pos);
24 Traits::set_next(*prev, &node);
25 Traits::set_prev(pos, &node);
28 static void unlink(
Node& node)
noexcept {
29 Node* next = Traits::get_next(node);
30 Node* prev = Traits::get_prev(node);
31 Traits::set_next(*prev, next);
32 Traits::set_prev(*next, prev);
65 using Link = std::remove_pointer_t<decltype(Traits::get_next(std::declval<Node const&>()))>;
68 struct Sentinel : Link {};
72 static Link* next(Link
const& node)
noexcept {
return Traits::get_next(node); }
73 static Link* prev(Link
const& node)
noexcept {
return Traits::get_prev(node); }
74 static Link* mut(Link
const* node)
noexcept {
return const_cast<Link*
>(node); }
76 static Link& toNode(T& value)
noexcept {
77 static_assert(std::derived_from<T, Node> && std::derived_from<Node, Link>);
78 return static_cast<Node&
>(value);
80 static Link
const& toNode(T
const& value)
noexcept {
81 static_assert(std::derived_from<T, Node> && std::derived_from<Node, Link>);
82 return static_cast<Node const&
>(value);
88 friend Iterator<!Const>;
90 using NodePtr = std::conditional_t<Const, Link const*, Link*>;
94 explicit Iterator(NodePtr cur) noexcept : cur(cur) {}
97 using iterator_category = std::bidirectional_iterator_tag;
99 using difference_type = std::ptrdiff_t;
100 using pointer = std::conditional_t<Const, T const*, T*>;
101 using reference = std::conditional_t<Const, T const&, T&>;
103 Iterator()
noexcept =
default;
104 template <
bool OtherConst>
105 requires(Const && !OtherConst)
106 Iterator(Iterator<OtherConst>
const& other) noexcept : cur(other.cur) {}
108 reference operator*()
const noexcept {
109 using NodeRef = std::conditional_t<Const, Node const&, Node&>;
110 return static_cast<reference
>(
static_cast<NodeRef
>(*cur));
112 pointer operator->()
const noexcept {
return &**
this; }
114 Iterator& operator++()
noexcept {
115 cur = IntrusiveList::next(*cur);
118 Iterator operator++(
int)
noexcept {
123 Iterator& operator--()
noexcept {
124 cur = IntrusiveList::prev(*cur);
127 Iterator operator--(
int)
noexcept {
133 bool operator==(Iterator
const&)
const noexcept =
default;
137 using value_type = T;
138 using node_type =
Node;
139 using size_type = std::size_t;
140 using reference = T&;
141 using const_reference = T
const&;
142 using iterator = Iterator<false>;
143 using const_iterator = Iterator<true>;
144 using reverse_iterator = std::reverse_iterator<iterator>;
145 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
147 IntrusiveList()
noexcept =
default;
149 IntrusiveList(IntrusiveList
const&) =
delete;
150 IntrusiveList& operator=(IntrusiveList
const&) =
delete;
152 IntrusiveList(IntrusiveList&& other)
noexcept { splice(end(), other); }
153 IntrusiveList& operator=(IntrusiveList&& other)
noexcept {
154 if (
this != &other) {
156 splice(end(), other);
161 ~IntrusiveList() { clear(); }
163 [[nodiscard]]
bool empty()
const noexcept {
return !Ops::is_linked(head); }
165 [[nodiscard]] size_type size()
const noexcept {
167 for (Link
const* it = next(head); it != &head; it = next(*it)) ++n;
171 iterator begin()
noexcept {
return iterator{next(head)}; }
172 const_iterator begin()
const noexcept {
return const_iterator{next(head)}; }
173 const_iterator cbegin()
const noexcept {
return begin(); }
174 iterator end()
noexcept {
return iterator{&head}; }
175 const_iterator end()
const noexcept {
return const_iterator{&head}; }
176 const_iterator cend()
const noexcept {
return end(); }
178 reverse_iterator rbegin()
noexcept {
return reverse_iterator{end()}; }
179 const_reverse_iterator rbegin()
const noexcept {
return const_reverse_iterator{end()}; }
180 reverse_iterator rend()
noexcept {
return reverse_iterator{begin()}; }
181 const_reverse_iterator rend()
const noexcept {
return const_reverse_iterator{begin()}; }
183 reference front()
noexcept {
return *begin(); }
184 const_reference front()
const noexcept {
return *begin(); }
185 reference back()
noexcept {
return *--end(); }
186 const_reference back()
const noexcept {
return *--end(); }
188 void push_front(T& value)
noexcept { insert(begin(), value); }
189 void push_back(T& value)
noexcept { insert(end(), value); }
190 void pop_front()
noexcept { Ops::unlink(*next(head)); }
191 void pop_back()
noexcept { Ops::unlink(*prev(head)); }
193 iterator insert(const_iterator pos, T& value)
noexcept {
194 Link& node = toNode(value);
196 Ops::link_before(node, *mut(pos.cur));
197 return iterator{&node};
200 iterator erase(const_iterator pos)
noexcept {
201 Link* following = next(*pos.cur);
202 Ops::unlink(*mut(pos.cur));
203 return iterator{following};
206 iterator erase(const_iterator first, const_iterator last)
noexcept {
207 while (first != last) first = erase(first);
208 return iterator{mut(last.cur)};
211 void remove(T& value)
noexcept { Ops::unlink(toNode(value)); }
213 template <
class Pred>
214 size_type remove_if(Pred pred) {
216 for (
auto it = begin(); it != end();) {
227 void clear()
noexcept {
228 while (!empty()) pop_front();
231 void splice(const_iterator pos, IntrusiveList& other)
noexcept {
232 if (other.empty())
return;
233 Link* at = mut(pos.cur);
234 Link* first = next(other.head);
235 Link* last = prev(other.head);
236 Link* before = prev(*at);
237 Ops::init(other.head);
238 Traits::set_prev(*first, before);
239 Traits::set_next(*before, first);
240 Traits::set_next(*last, at);
241 Traits::set_prev(*at, last);
244 void splice(const_iterator pos, T& value)
noexcept { insert(pos, value); }
246 void swap(IntrusiveList& other)
noexcept {
247 IntrusiveList tmp{std::move(other)};
248 other = std::move(*
this);
249 *
this = std::move(tmp);
252 [[nodiscard]]
static iterator iterator_to(T& value)
noexcept {
return iterator{&toNode(value)}; }
253 [[nodiscard]]
static const_iterator iterator_to(T
const& value)
noexcept {
return const_iterator{&toNode(value)}; }