Skip to content
LeviMC
English
AutoLightDark
LeviLamina
Loading...
Searching...
No Matches
IntrusiveList.h
1#pragma once
2
3#include <concepts>
4#include <cstddef>
5#include <iterator>
6#include <type_traits>
7#include <utility>
8
9namespace ll::data {
10template <class Node, class Traits = Node>
12public:
13 [[nodiscard]] static bool is_linked(Node const& node) noexcept { return Traits::get_next(node) != &node; }
14
15 static void init(Node& node) noexcept {
16 Traits::set_next(node, &node);
17 Traits::set_prev(node, &node);
18 }
19
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);
26 }
27
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);
33 init(node);
34 }
35};
36
37template <class Tag = void>
38class IntrusiveListNode : public IntrusiveListOperations<IntrusiveListNode<Tag>> {
40
41 IntrusiveListNode* next{this};
42 IntrusiveListNode* prev{this};
43
44protected:
45 IntrusiveListNode() noexcept = default;
46
47 IntrusiveListNode(IntrusiveListNode const&) noexcept {}
48 IntrusiveListNode& operator=(IntrusiveListNode const&) noexcept { return *this; }
49
50 ~IntrusiveListNode() { unlink(); }
51
52public:
53 [[nodiscard]] static IntrusiveListNode* get_next(IntrusiveListNode const& node) noexcept { return node.next; }
54 [[nodiscard]] static IntrusiveListNode* get_prev(IntrusiveListNode const& node) noexcept { return node.prev; }
55 static void set_next(IntrusiveListNode& node, IntrusiveListNode* next) noexcept { node.next = next; }
56 static void set_prev(IntrusiveListNode& node, IntrusiveListNode* prev) noexcept { node.prev = prev; }
57
58 [[nodiscard]] bool is_linked() const noexcept { return Ops::is_linked(*this); }
59
60 void unlink() noexcept { Ops::unlink(*this); }
61};
62
63template <class T, class Node = IntrusiveListNode<>, class Traits = Node>
64class IntrusiveList {
65 using Link = std::remove_pointer_t<decltype(Traits::get_next(std::declval<Node const&>()))>;
67
68 struct Sentinel : Link {};
69
70 Sentinel head;
71
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); }
75
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);
79 }
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);
83 }
84
85 template <bool Const>
86 class Iterator {
87 friend IntrusiveList;
88 friend Iterator<!Const>;
89
90 using NodePtr = std::conditional_t<Const, Link const*, Link*>;
91
92 NodePtr cur{};
93
94 explicit Iterator(NodePtr cur) noexcept : cur(cur) {}
95
96 public:
97 using iterator_category = std::bidirectional_iterator_tag;
98 using value_type = T;
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&>;
102
103 Iterator() noexcept = default;
104 template <bool OtherConst>
105 requires(Const && !OtherConst)
106 Iterator(Iterator<OtherConst> const& other) noexcept : cur(other.cur) {}
107
108 reference operator*() const noexcept {
109 using NodeRef = std::conditional_t<Const, Node const&, Node&>;
110 return static_cast<reference>(static_cast<NodeRef>(*cur));
111 }
112 pointer operator->() const noexcept { return &**this; }
113
114 Iterator& operator++() noexcept {
115 cur = IntrusiveList::next(*cur);
116 return *this;
117 }
118 Iterator operator++(int) noexcept {
119 auto res = *this;
120 ++*this;
121 return res;
122 }
123 Iterator& operator--() noexcept {
124 cur = IntrusiveList::prev(*cur);
125 return *this;
126 }
127 Iterator operator--(int) noexcept {
128 auto res = *this;
129 --*this;
130 return res;
131 }
132
133 bool operator==(Iterator const&) const noexcept = default;
134 };
135
136public:
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>;
146
147 IntrusiveList() noexcept = default;
148
149 IntrusiveList(IntrusiveList const&) = delete;
150 IntrusiveList& operator=(IntrusiveList const&) = delete;
151
152 IntrusiveList(IntrusiveList&& other) noexcept { splice(end(), other); }
153 IntrusiveList& operator=(IntrusiveList&& other) noexcept {
154 if (this != &other) {
155 clear();
156 splice(end(), other);
157 }
158 return *this;
159 }
160
161 ~IntrusiveList() { clear(); }
162
163 [[nodiscard]] bool empty() const noexcept { return !Ops::is_linked(head); }
164
165 [[nodiscard]] size_type size() const noexcept {
166 size_type n = 0;
167 for (Link const* it = next(head); it != &head; it = next(*it)) ++n;
168 return n;
169 }
170
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(); }
177
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()}; }
182
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(); }
187
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)); }
192
193 iterator insert(const_iterator pos, T& value) noexcept {
194 Link& node = toNode(value);
195 Ops::unlink(node);
196 Ops::link_before(node, *mut(pos.cur));
197 return iterator{&node};
198 }
199
200 iterator erase(const_iterator pos) noexcept {
201 Link* following = next(*pos.cur);
202 Ops::unlink(*mut(pos.cur));
203 return iterator{following};
204 }
205
206 iterator erase(const_iterator first, const_iterator last) noexcept {
207 while (first != last) first = erase(first);
208 return iterator{mut(last.cur)};
209 }
210
211 void remove(T& value) noexcept { Ops::unlink(toNode(value)); }
212
213 template <class Pred>
214 size_type remove_if(Pred pred) {
215 size_type n = 0;
216 for (auto it = begin(); it != end();) {
217 if (pred(*it)) {
218 it = erase(it);
219 ++n;
220 } else {
221 ++it;
222 }
223 }
224 return n;
225 }
226
227 void clear() noexcept {
228 while (!empty()) pop_front();
229 }
230
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);
242 }
243
244 void splice(const_iterator pos, T& value) noexcept { insert(pos, value); }
245
246 void swap(IntrusiveList& other) noexcept {
247 IntrusiveList tmp{std::move(other)};
248 other = std::move(*this);
249 *this = std::move(tmp);
250 }
251
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)}; }
254};
255} // namespace ll::data
Definition IntrusiveList.h:11
Definition Node.h:5