Iros
 
Loading...
Searching...
No Matches
forward_list.h
Go to the documentation of this file.
1#pragma once
2
9#include "di/util/addressof.h"
10#include "di/util/exchange.h"
11#include "di/util/immovable.h"
12#include "di/util/movable_box.h"
14
15namespace di::container {
16template<typename Self>
17struct IntrusiveForwardListTag : IntrusiveTagBase<IntrusiveForwardListNode<Self>> {};
18
19struct DefaultIntrusiveForwardListTag : IntrusiveForwardListTag<DefaultIntrusiveForwardListTag> {};
20
21template<typename T, typename Tag, typename Self>
23private:
25 using ConcreteNode = decltype(Tag::node_type(in_place_type<T>));
27
28 constexpr static bool is_sized = Tag::is_sized(in_place_type<T>);
29 constexpr static bool store_tail = Tag::always_store_tail(in_place_type<T>);
30
31 constexpr auto down_cast_self() -> decltype(auto) {
32 if constexpr (concepts::SameAs<Void, Self>) {
33 return *this;
34 } else {
35 return static_cast<Self&>(*this);
36 }
37 }
38
39 struct Iterator : IteratorBase<Iterator, ForwardIteratorTag, T, ssize_t> {
40 private:
41 friend class IntrusiveForwardList;
42
43 public:
44 Iterator() = default;
45
46 constexpr explicit Iterator(Node* node) : m_node(node) {}
47 constexpr explicit Iterator(Node& node) : m_node(util::addressof(node)) {}
48
49 constexpr auto operator*() const -> T& {
50 return Tag::down_cast(in_place_type<T>, static_cast<ConcreteNode&>(*m_node));
51 }
52 constexpr auto operator->() const -> T* { return util::addressof(**this); }
53
54 constexpr void advance_one() { m_node = m_node->next; }
55
56 constexpr auto node() const -> Node* { return m_node; }
57
58 private:
59 constexpr friend auto operator==(Iterator const& a, Iterator const& b) -> bool { return a.m_node == b.m_node; }
60
61 Node* m_node { nullptr };
62 };
63
64 using ConstIterator = container::ConstIteratorImpl<Iterator>;
65
66public:
67 constexpr IntrusiveForwardList() { reset_tail(); }
68
70
71 constexpr IntrusiveForwardList(IntrusiveForwardList&& other) : IntrusiveForwardList() { *this = util::move(other); }
72
74
76 m_head.value().next = util::exchange(other.m_head.value().next, nullptr);
77
78 if constexpr (is_sized) {
79 m_size.value = util::exchange(other.m_size.value, 0);
80 }
81
82 if constexpr (store_tail) {
83 if (!empty()) {
84 m_tail.value = other.m_tail.value;
85 }
86 other.reset_tail();
87 }
88 return *this;
89 }
90
91 constexpr ~IntrusiveForwardList() { clear(); }
92
93 constexpr auto empty() const -> bool { return !head(); }
94 constexpr auto size() const -> usize
95 requires(is_sized)
96 {
97 return m_size.value;
98 }
99 constexpr auto max_size() const -> usize { return math::NumericLimits<usize>::max; }
100
101 constexpr auto before_begin() -> Iterator { return Iterator(util::addressof(m_head.value())); }
102 constexpr auto before_begin() const -> ConstIterator {
103 return Iterator(const_cast<Node*>(util::addressof(m_head.value())));
104 }
105
106 constexpr auto begin() { return Iterator(head()); }
107 constexpr auto end() -> Iterator { return Iterator(); }
108
109 constexpr auto begin() const { return Iterator(head()); }
110 constexpr auto end() const -> ConstIterator { return Iterator(); }
111
112 constexpr auto before_end() -> Iterator
113 requires(store_tail)
114 {
115 return Iterator(m_tail.value);
116 }
117 constexpr auto before_end() const -> ConstIterator
118 requires(store_tail)
119 {
120 return Iterator(m_tail.value);
121 }
122
123 constexpr auto front() {
124 return lift_bool(!empty()) % [&] {
125 return util::ref(*begin());
126 };
127 }
128 constexpr auto front() const {
129 return lift_bool(!empty()) % [&] {
130 return util::cref(*begin());
131 };
132 }
133
134 constexpr auto back()
135 requires(store_tail)
136 {
137 return lift_bool(!empty()) % [&] {
138 return util::ref(*before_end());
139 };
140 }
141 constexpr auto back() const
142 requires(store_tail)
143 {
144 return lift_bool(!empty()) % [&] {
145 return util::cref(*before_end());
146 };
147 }
148
149 constexpr void push_front(Node& node) { insert_after(before_begin(), node); }
150 constexpr void push_back(Node& node)
151 requires(store_tail)
152 {
153 insert_after(before_end(), node);
154 }
155
156 constexpr auto pop_front() -> Optional<T&> {
157 return lift_bool(!empty()) % [&] {
158 auto it = begin();
160 if (empty()) {
161 reset_tail();
162 }
163 return util::ref(*it);
164 };
165 }
166
167 constexpr void clear() { erase_after(before_begin(), end()); }
168
169 constexpr auto insert_after(ConstIterator position, Node& node_ref) -> Iterator {
170 auto* node = util::addressof(node_ref);
171 auto* prev = position.base().node();
172
174 if constexpr (store_tail) {
175 if (prev == m_tail.value) {
176 m_tail.value = node;
177 }
178 }
179
180 node->next = prev->next;
181 prev->next = node;
182
183 if constexpr (is_sized) {
184 ++m_size.value;
185 }
186
187 Tag::did_insert(down_cast_self(), static_cast<ConcreteNode&>(node_ref));
188
189 return Iterator(node);
190 }
191
192 constexpr auto erase_after(ConstIterator position) -> Iterator {
193 if (!position.base().node()) {
194 return end();
195 }
196 auto next = container::next(position);
197 if (!next.base().node()) {
198 return end();
199 }
200 return erase_after(position, container::next(next));
201 }
202 constexpr auto erase_after(ConstIterator first, ConstIterator last) -> Iterator {
203 if (first == last) {
204 return last.base();
205 }
206
207 auto* prev = first.base().node();
208 auto* end = last.base().node();
209 if constexpr (store_tail) {
210 if (!end) {
211 m_tail.value = prev;
212 }
213 }
214 prev->next = end;
215
216 for (auto it = ++first; it != last;) {
217 auto save = it++;
218 Tag::did_remove(down_cast_self(), static_cast<ConcreteNode&>(*save.base().node()));
219
220 if constexpr (is_sized) {
221 --m_size.value;
222 }
223 }
224 return last.base();
225 }
226
227private:
228 template<typename F>
230 constexpr friend auto tag_invoke(di::Tag<erase_if>, ConcreteSelf& self, F&& function) -> usize {
231 auto it = self.before_begin();
232 auto jt = next(it);
233
234 auto result = 0ZU;
235 while (jt != self.end()) {
236 if (function(*jt)) {
237 jt = self.erase_after(it);
238 ++result;
239 } else {
240 ++it;
241 ++jt;
242 }
243 }
244 return result;
245 }
246
247 constexpr auto head() const -> Node* { return m_head.value().next; }
248 constexpr void set_head(Node* head) { m_head.value().next = head; }
249
250 constexpr void reset_tail() {
251 if constexpr (store_tail) {
252 m_tail.value = util::addressof(m_head.value());
253 }
254 }
255
256 util::MovableBox<Node> m_head;
257 [[no_unique_address]] util::StoreIf<Node*, store_tail> m_tail { nullptr };
258 [[no_unique_address]] util::StoreIf<usize, is_sized> m_size { 0 };
259};
260}
261
262namespace di {
265}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Definition forward_list_node.h:9
Definition forward_list_forward_declaration.h:12
constexpr ~IntrusiveForwardList()
Definition forward_list.h:91
auto operator=(IntrusiveForwardList const &) -> IntrusiveForwardList &=delete
constexpr auto max_size() const -> usize
Definition forward_list.h:99
constexpr void clear()
Definition forward_list.h:167
constexpr auto front() const
Definition forward_list.h:128
constexpr auto back()
Definition forward_list.h:134
constexpr auto before_end() const -> ConstIterator requires(store_tail)
Definition forward_list.h:117
constexpr auto end() const -> ConstIterator
Definition forward_list.h:110
constexpr auto insert_after(ConstIterator position, Node &node_ref) -> Iterator
Definition forward_list.h:169
constexpr void push_back(Node &node)
Definition forward_list.h:150
constexpr auto before_begin() const -> ConstIterator
Definition forward_list.h:102
constexpr auto size() const -> usize requires(is_sized)
Definition forward_list.h:94
constexpr auto operator=(IntrusiveForwardList &&other) -> IntrusiveForwardList &
Definition forward_list.h:75
constexpr auto pop_front() -> Optional< T & >
Definition forward_list.h:156
IntrusiveForwardList(IntrusiveForwardList const &)=delete
constexpr auto end() -> Iterator
Definition forward_list.h:107
constexpr auto back() const
Definition forward_list.h:141
constexpr auto erase_after(ConstIterator first, ConstIterator last) -> Iterator
Definition forward_list.h:202
constexpr auto erase_after(ConstIterator position) -> Iterator
Definition forward_list.h:192
constexpr IntrusiveForwardList()
Definition forward_list.h:67
constexpr void push_front(Node &node)
Definition forward_list.h:149
constexpr auto before_end() -> Iterator requires(store_tail)
Definition forward_list.h:112
constexpr auto front()
Definition forward_list.h:123
constexpr auto begin() const
Definition forward_list.h:109
constexpr auto before_begin() -> Iterator
Definition forward_list.h:101
constexpr friend auto tag_invoke(di::Tag< erase_if >, ConcreteSelf &self, F &&function) -> usize
Definition forward_list.h:230
constexpr auto empty() const -> bool
Definition forward_list.h:93
constexpr auto begin()
Definition forward_list.h:106
constexpr IntrusiveForwardList(IntrusiveForwardList &&other)
Definition forward_list.h:71
Definition optional_forward_declaration.h:5
Definition relation.h:7
Definition core.h:114
Definition sequence.h:12
constexpr auto prev
Definition prev.h:28
constexpr auto next
Definition next.h:35
Definition as_bool.h:8
detail::ConditionalHelper< value, T, U >::Type Conditional
Definition core.h:88
size_t usize
Definition integers.h:33
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
constexpr auto ref
Definition reference_wrapper.h:98
constexpr auto cref
Definition reference_wrapper.h:99
constexpr auto exchange(T &object, U &&new_value) -> T
Definition exchange.h:8
Definition zstring_parser.h:9
constexpr auto in_place_type
Definition in_place_type.h:12
constexpr auto lift_bool
Definition lift_bool.h:13
Definition forward_list.h:17
Definition intrusive_tag_base.h:8
Definition numeric_limits.h:7