C/C++ API Reference
Loading...
Searching...
No Matches
intrusive_forward_list.h
1// Copyright 2021 The Pigweed Authors
2//
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
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
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
13// the License.
14#pragma once
15
16#include <cstddef>
17#include <initializer_list>
18#include <iterator>
19#include <limits>
20#include <type_traits>
21
22#include "pw_containers/config.h"
23#include "pw_containers/internal/intrusive_item.h"
24#include "pw_containers/internal/intrusive_list.h"
25#include "pw_containers/internal/intrusive_list_item.h"
26#include "pw_containers/internal/intrusive_list_iterator.h"
27
28namespace pw {
29namespace containers::internal {
30
31// Forward declaration for friending.
32//
33// The LegacyIntrusiveList has methods that run in O(n) time and have no
34// analogue in `std::forward_list`. If any of these behaviors are needed,
35// callers should consider whether a doubly-linked list is more appropriate,
36// or whether they should provide the functionality themselves, e.g. by
37// tracking size explicitly.
38template <typename>
40
41} // namespace containers::internal
42
44
47
90template <typename T>
92 private:
93 using ItemBase = ::pw::containers::internal::IntrusiveForwardListItem;
94
95 public:
96 using element_type = T;
97 using value_type = std::remove_cv_t<element_type>;
98 using size_type = std::size_t;
99 using difference_type = std::ptrdiff_t;
100 using reference = value_type&;
101 using const_reference = const value_type&;
102 using pointer = element_type*;
103 using const_pointer = const element_type*;
104
105 class Item : public ItemBase {
106 protected:
111 constexpr explicit Item() = default;
112
113 private:
114 // IntrusiveItem is used to ensure T inherits from this container's Item
115 // type. See also `CheckItemType`.
116 template <typename, typename, bool>
117 friend struct containers::internal::IntrusiveItem;
118 using ItemType = T;
119 };
120
121 using iterator =
122 typename ::pw::containers::internal::ForwardIterator<T, ItemBase>;
123 using const_iterator =
124 typename ::pw::containers::internal::ForwardIterator<std::add_const_t<T>,
125 const ItemBase>;
126
127 constexpr IntrusiveForwardList() { CheckItemType(); }
128
129 // Intrusive lists cannot be copied, since each Item can only be in one list.
131 IntrusiveForwardList& operator=(const IntrusiveForwardList&) = delete;
132
137
142
146 template <typename Iterator>
147 IntrusiveForwardList(Iterator first, Iterator last) {
148 list_.assign(first, last);
149 }
150
152 IntrusiveForwardList(std::initializer_list<Item*> items)
153 : IntrusiveForwardList(items.begin(), items.end()) {}
154
155 template <typename Iterator>
156 void assign(Iterator first, Iterator last) {
157 list_.assign(first, last);
158 }
159
160 void assign(std::initializer_list<T*> items) {
161 list_.assign(items.begin(), items.end());
162 }
163
164 // Element access
165
167 reference front() { return *static_cast<T*>(list_.begin()); }
168 const_reference front() const {
169 return *static_cast<const T*>(list_.begin());
170 }
171
172 // Iterators
173
174 iterator before_begin() noexcept { return iterator(list_.before_begin()); }
175 const_iterator before_begin() const noexcept {
176 return const_iterator(list_.before_begin());
177 }
178 const_iterator cbefore_begin() const noexcept { return before_begin(); }
179
180 iterator begin() noexcept { return iterator(list_.begin()); }
181 const_iterator begin() const noexcept {
182 return const_iterator(list_.begin());
183 }
184 const_iterator cbegin() const noexcept { return begin(); }
185
186 iterator end() noexcept { return iterator(list_.end()); }
187 const_iterator end() const noexcept { return const_iterator(list_.end()); }
188 const_iterator cend() const noexcept { return end(); }
189
190 // Capacity
191
193 [[nodiscard]] bool empty() const noexcept { return list_.empty(); }
194
196 constexpr size_type max_size() const noexcept {
197 return std::numeric_limits<difference_type>::max();
198 }
199
200 // Modifiers
201
203 void clear() { list_.clear(); }
204
206 iterator insert_after(iterator pos, T& item) {
207 return iterator(list_.insert_after(pos.item_, item));
208 }
209
212 template <typename Iterator>
213 iterator insert_after(iterator pos, Iterator first, Iterator last) {
214 return iterator(list_.insert_after(pos.item_, first, last));
215 }
216
219 iterator insert_after(iterator pos, std::initializer_list<T*> items) {
220 return insert_after(pos, items.begin(), items.end());
221 }
222
224 iterator erase_after(iterator pos) {
225 return iterator(list_.erase_after(pos.item_));
226 }
227
229 iterator erase_after(iterator first, iterator last) {
230 return iterator(list_.erase_after(first.item_, last.item_));
231 }
232
234 void push_front(T& item) { list_.insert_after(list_.before_begin(), item); }
235
237 void pop_front() { remove(front()); }
238
242 void swap(IntrusiveForwardList<T>& other) noexcept {
243 list_.swap(other.list_);
244 }
245
246 // Operations
247
252 list_.merge(other.list_, [](const ItemBase& a, const ItemBase& b) -> bool {
253 return static_cast<const T&>(a) < static_cast<const T&>(b);
254 });
255 }
256
258 template <typename Compare>
259 void merge(IntrusiveForwardList<T>& other, Compare comp) {
260 list_.merge(other.list_, [comp](const ItemBase& a, const ItemBase& b) {
261 return comp(static_cast<const T&>(a), static_cast<const T&>(b));
262 });
263 }
264
267 void splice_after(iterator pos, IntrusiveForwardList<T>& other) {
268 splice_after(pos, other, other.before_begin(), other.end());
269 }
270
273 void splice_after(iterator pos, IntrusiveForwardList<T>& other, iterator it) {
274 splice_after(pos, other, it, std::next(std::next(it)));
275 }
276
279 void splice_after(iterator pos,
281 iterator first,
282 iterator last) {
283 list_.splice_after(pos.item_, other.list_, first.item_, last.item_);
284 }
285
287 bool remove(const T& item) { return list_.remove(item); }
288
290 template <typename UnaryPredicate>
291 size_type remove_if(UnaryPredicate pred) {
292 return list_.remove_if([pred](const ItemBase& item) -> bool {
293 return pred(static_cast<const T&>(item));
294 });
295 }
296
298 void reverse() { list_.reverse(); }
299
303 size_type unique() {
304 return list_.unique([](const ItemBase& a, const ItemBase& b) -> bool {
305 return static_cast<const T&>(a) == static_cast<const T&>(b);
306 });
307 }
308
310 template <typename BinaryPredicate>
311 size_type unique(BinaryPredicate pred) {
312 return list_.unique([pred](const ItemBase& a, const ItemBase& b) {
313 return pred(static_cast<const T&>(a), static_cast<const T&>(b));
314 });
315 }
316
320 void sort() {
321 list_.sort([](const ItemBase& a, const ItemBase& b) -> bool {
322 return static_cast<const T&>(a) < static_cast<const T&>(b);
323 });
324 }
325
327 template <typename Compare>
328 void sort(Compare comp) {
329 list_.sort([comp](const ItemBase& a, const ItemBase& b) {
330 return comp(static_cast<const T&>(a), static_cast<const T&>(b));
331 });
332 }
333
334 private:
335 // Check that T is an Item in a function, since the class T will not be fully
336 // defined when the IntrusiveList<T> class is instantiated.
337 static constexpr void CheckItemType() {
338 using IntrusiveItemType =
339 typename containers::internal::IntrusiveItem<ItemBase, T>::Type;
340 static_assert(
341 std::is_base_of<IntrusiveItemType, T>(),
342 "IntrusiveForwardList items must be derived from "
343 "IntrusiveForwardList<T>::Item, where T is the item or one of its "
344 "bases.");
345 }
346
347 template <typename>
348 friend class containers::internal::LegacyIntrusiveList;
349
351};
352
353} // namespace pw
Definition: intrusive_forward_list.h:105
Definition: intrusive_forward_list.h:91
Definition: intrusive_list.h:38
Definition: intrusive_forward_list.h:39
void merge(IntrusiveForwardList< T > &other, Compare comp)
Definition: intrusive_forward_list.h:259
void pop_front()
Removes the first item in the list. The list must not be empty.
Definition: intrusive_forward_list.h:237
size_t unique(BinaryPredicate pred)
Definition: intrusive_list.h:278
size_type unique(BinaryPredicate pred)
Definition: intrusive_forward_list.h:311
void merge(IntrusiveForwardList< T > &other)
Definition: intrusive_forward_list.h:251
iterator erase_after(iterator pos)
Removes the item following pos from the list. The item is not destructed.
Definition: intrusive_forward_list.h:224
void swap(IntrusiveForwardList< T > &other) noexcept
Definition: intrusive_forward_list.h:242
iterator erase_after(iterator first, iterator last)
Removes the range of items from first (inclusive) to last (exclusive).
Definition: intrusive_forward_list.h:229
void sort(Compare comp)
Definition: intrusive_list.h:305
size_type unique()
Definition: intrusive_forward_list.h:303
void reverse()
Definition: intrusive_forward_list.h:298
size_t remove_if(UnaryPredicate pred, size_t max=std::numeric_limits< size_t >::max())
Definition: intrusive_list.h:239
void splice_after(iterator pos, IntrusiveForwardList< T > &other, iterator first, iterator last)
Definition: intrusive_forward_list.h:279
void reverse()
Reverses the order of items in the list.
Definition: intrusive_list.h:262
void clear()
Definition: intrusive_forward_list.h:203
bool empty() const noexcept
Definition: intrusive_forward_list.h:193
iterator insert_after(iterator pos, T &item)
Inserts the given item after the given position, pos.
Definition: intrusive_forward_list.h:206
void sort()
Definition: intrusive_forward_list.h:320
constexpr Item * before_begin() noexcept
Returns a pointer to the sentinel item.
Definition: intrusive_list.h:77
void sort(Compare comp)
Definition: intrusive_forward_list.h:328
constexpr Item * begin() noexcept
Returns a pointer to the first item.
Definition: intrusive_list.h:81
void splice_after(iterator pos, IntrusiveForwardList< T > &other)
Definition: intrusive_forward_list.h:267
void merge(GenericIntrusiveList< Item > &other, Compare comp)
Definition: intrusive_list.h:178
constexpr Item()=default
constexpr size_type max_size() const noexcept
Definition: intrusive_forward_list.h:196
iterator insert_after(iterator pos, Iterator first, Iterator last)
Definition: intrusive_forward_list.h:213
static Item * insert_after(Item *prev, Item &item)
Definition: intrusive_list.h:120
static void splice_after(Item *pos, GenericIntrusiveList< Item > &other, Item *first, Item *last)
Definition: intrusive_list.h:196
void clear()
Removes all items from the list.
Definition: intrusive_list.h:105
IntrusiveForwardList(IntrusiveForwardList &&)=default
reference front()
Reference to the first element in the list. Undefined behavior if empty().
Definition: intrusive_forward_list.h:167
size_type remove_if(UnaryPredicate pred)
Definition: intrusive_forward_list.h:291
iterator insert_after(iterator pos, std::initializer_list< T * > items)
Definition: intrusive_forward_list.h:219
IntrusiveForwardList & operator=(IntrusiveForwardList &&)=default
bool remove(const T &item)
Definition: intrusive_forward_list.h:287
constexpr Item * end() noexcept
Returns a pointer to the sentinel item.
Definition: intrusive_list.h:88
void push_front(T &item)
Inserts the item at the start of the list.
Definition: intrusive_forward_list.h:234
IntrusiveForwardList(std::initializer_list< Item * > items)
Constructs a list from a std::initializer_list of pointers to items.
Definition: intrusive_forward_list.h:152
IntrusiveForwardList(Iterator first, Iterator last)
Definition: intrusive_forward_list.h:147
static Item * erase_after(Item *item)
Definition: intrusive_list.h:148
void splice_after(iterator pos, IntrusiveForwardList< T > &other, iterator it)
Definition: intrusive_forward_list.h:273
The Pigweed namespace.
Definition: alignment.h:27