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
31
32namespace pw {
33namespace containers {
34namespace internal {
35
36// Forward declaration for friending.
37//
38// The LegacyIntrusiveList has methods that run in O(n) time and have no
39// analogue in `std::forward_list`. If any of these behaviors are needed,
40// callers should consider whether a doubly-linked list is more appropriate,
41// or whether they should provide the functionality themselves, e.g. by
42// tracking size explicitly.
43template <typename>
45
46} // namespace internal
47
49template <typename T>
50void PushBackSlow(IntrusiveForwardList<T>& forward_list, T& item) {
51 forward_list.list().push_back(item);
52}
53
54} // namespace containers
55
98template <typename T>
100 private:
101 using ItemBase = ::pw::containers::internal::IntrusiveForwardListItem;
102
103 public:
104 using element_type = T;
105 using value_type = std::remove_cv_t<element_type>;
106 using size_type = std::size_t;
107 using difference_type = std::ptrdiff_t;
108 using reference = value_type&;
109 using const_reference = const value_type&;
110 using pointer = element_type*;
111 using const_pointer = const element_type*;
112
113 class Item : public ItemBase {
114 protected:
119 constexpr explicit Item() = default;
120
121 private:
122 // IntrusiveItem is used to ensure T inherits from this container's Item
123 // type. See also `CheckItemType`.
124 template <typename, typename, bool>
125 friend struct containers::internal::IntrusiveItem;
126 using ItemType = T;
127 };
128
129 using iterator =
130 typename ::pw::containers::internal::ForwardIterator<T, ItemBase>;
131 using const_iterator =
132 typename ::pw::containers::internal::ForwardIterator<std::add_const_t<T>,
133 const ItemBase>;
134
135 constexpr IntrusiveForwardList() = default;
136
137 // Intrusive lists cannot be copied, since each Item can only be in one list.
139 IntrusiveForwardList& operator=(const IntrusiveForwardList&) = delete;
140
145
150
154 template <typename Iterator>
155 IntrusiveForwardList(Iterator first, Iterator last) {
156 list().assign(first, last);
157 }
158
160 IntrusiveForwardList(std::initializer_list<Item*> items)
161 : IntrusiveForwardList(items.begin(), items.end()) {}
162
163 template <typename Iterator>
164 void assign(Iterator first, Iterator last) {
165 list().assign(first, last);
166 }
167
168 void assign(std::initializer_list<T*> items) {
169 list().assign(items.begin(), items.end());
170 }
171
172 // Element access
173
175 reference front() { return *static_cast<T*>(list().begin()); }
176 const_reference front() const {
177 return *static_cast<const T*>(list().begin());
178 }
179
180 // Iterators
181
182 iterator before_begin() noexcept { return iterator(list().before_begin()); }
183 const_iterator before_begin() const noexcept {
184 return const_iterator(list().before_begin());
185 }
186 const_iterator cbefore_begin() const noexcept { return before_begin(); }
187
188 iterator begin() noexcept { return iterator(list().begin()); }
189 const_iterator begin() const noexcept {
190 return const_iterator(list().begin());
191 }
192 const_iterator cbegin() const noexcept { return begin(); }
193
194 iterator end() noexcept { return iterator(list().end()); }
195 const_iterator end() const noexcept { return const_iterator(list().end()); }
196 const_iterator cend() const noexcept { return end(); }
197
198 // Capacity
199
201 [[nodiscard]] bool empty() const noexcept { return list().empty(); }
202
204 constexpr size_type max_size() const noexcept {
205 return std::numeric_limits<difference_type>::max();
206 }
207
208 // Modifiers
209
211 void clear() { list().clear(); }
212
214 iterator insert_after(iterator pos, T& item) {
215 return iterator(list().insert_after(pos.item_, item));
216 }
217
220 template <typename Iterator>
221 iterator insert_after(iterator pos, Iterator first, Iterator last) {
222 return iterator(list().insert_after(pos.item_, first, last));
223 }
224
227 iterator insert_after(iterator pos, std::initializer_list<T*> items) {
228 return insert_after(pos, items.begin(), items.end());
229 }
230
232 iterator erase_after(iterator pos) {
233 return iterator(list().erase_after(pos.item_));
234 }
235
237 iterator erase_after(iterator first, iterator last) {
238 return iterator(list().erase_after(first.item_, last.item_));
239 }
240
242 void push_front(T& item) { list().push_front(item); }
243
245 void pop_front() { list().pop_front(); }
246
250 void swap(IntrusiveForwardList<T>& other) noexcept {
251 list().swap(other.list());
252 }
253
254 // Operations
255
260 list().merge(other.list(),
261 [](const ItemBase& a, const ItemBase& b) -> bool {
262 return static_cast<const T&>(a) < static_cast<const T&>(b);
263 });
264 }
265
267 template <typename Compare>
268 void merge(IntrusiveForwardList<T>& other, Compare comp) {
269 list().merge(other.list(), [comp](const ItemBase& a, const ItemBase& b) {
270 return comp(static_cast<const T&>(a), static_cast<const T&>(b));
271 });
272 }
273
276 void splice_after(iterator pos, IntrusiveForwardList<T>& other) {
277 splice_after(pos, other, other.before_begin(), other.end());
278 }
279
282 void splice_after(iterator pos, IntrusiveForwardList<T>& other, iterator it) {
283 splice_after(pos, other, it, std::next(std::next(it)));
284 }
285
288 void splice_after(iterator pos,
290 iterator first,
291 iterator last) {
292 list().splice_after(pos.item_, other.list(), first.item_, last.item_);
293 }
294
296 bool remove(const T& item) { return list().remove(item); }
297
299 template <typename UnaryPredicate>
300 size_type remove_if(UnaryPredicate pred) {
301 return list().remove_if([pred](const ItemBase& item) -> bool {
302 return pred(static_cast<const T&>(item));
303 });
304 }
305
307 void reverse() { list().reverse(); }
308
312 size_type unique() {
313 return list().unique([](const ItemBase& a, const ItemBase& b) -> bool {
314 return static_cast<const T&>(a) == static_cast<const T&>(b);
315 });
316 }
317
319 template <typename BinaryPredicate>
320 size_type unique(BinaryPredicate pred) {
321 return list().unique([pred](const ItemBase& a, const ItemBase& b) {
322 return pred(static_cast<const T&>(a), static_cast<const T&>(b));
323 });
324 }
325
329 void sort() {
330 list().sort([](const ItemBase& a, const ItemBase& b) -> bool {
331 return static_cast<const T&>(a) < static_cast<const T&>(b);
332 });
333 }
334
336 template <typename Compare>
337 void sort(Compare comp) {
338 list().sort([comp](const ItemBase& a, const ItemBase& b) {
339 return comp(static_cast<const T&>(a), static_cast<const T&>(b));
340 });
341 }
342
343 private:
344 template <typename>
346
347 friend void containers::PushBackSlow<T>(IntrusiveForwardList<T>&, T&);
348
349 // Check that T is an Item in a function, since the class T will not be fully
350 // defined when the IntrusiveList<T> class is instantiated.
351 static constexpr void CheckItemType() {
352 using IntrusiveItemType =
353 typename containers::internal::IntrusiveItem<ItemBase, T>::Type;
354 static_assert(
355 std::is_base_of<IntrusiveItemType, T>(),
356 "IntrusiveForwardList items must be derived from "
357 "IntrusiveForwardList<T>::Item, where T is the item or one of its "
358 "bases.");
359 }
360
361 // The generic list is accessed through this function to ensure
362 // CheckItemType() is instantiated. CheckItemType() is not instantiated in the
363 // constructor to allow constructing lists of forward declared items.
364 constexpr auto& list() {
365 CheckItemType();
366 return generic_list_;
367 }
368
369 constexpr const auto& list() const {
370 CheckItemType();
371 return generic_list_;
372 }
373
374 containers::internal::GenericIntrusiveList<ItemBase> generic_list_;
375};
376
380template <typename T>
382 : public IntrusiveForwardList<IntrusiveForwardListItem<T>>::Item {
383 public:
384 using element_type = T;
385 using value_type = std::remove_cv_t<element_type>;
386 using reference = value_type&;
387 using const_reference = const value_type&;
388
389 template <typename... Args>
390 IntrusiveForwardListItem(Args&&... args)
391 : item_(std::forward<Args>(args)...) {}
392
393 reference item() { return item_; }
394 const_reference item() const { return item_; }
395
396 private:
397 element_type item_;
398};
399
400} // namespace pw
Definition: intrusive_forward_list.h:113
Definition: intrusive_forward_list.h:99
Definition: intrusive_forward_list.h:382
Definition: intrusive_forward_list.h:44
void merge(IntrusiveForwardList< T > &other, Compare comp)
Definition: intrusive_forward_list.h:268
void pop_front()
Definition: intrusive_forward_list.h:245
size_type unique(BinaryPredicate pred)
Definition: intrusive_forward_list.h:320
void merge(IntrusiveForwardList< T > &other)
Definition: intrusive_forward_list.h:259
iterator erase_after(iterator pos)
Removes the item following pos from the list. The item is not destructed.
Definition: intrusive_forward_list.h:232
void swap(IntrusiveForwardList< T > &other) noexcept
Definition: intrusive_forward_list.h:250
iterator erase_after(iterator first, iterator last)
Removes the range of items from first (inclusive) to last (exclusive).
Definition: intrusive_forward_list.h:237
size_type unique()
Definition: intrusive_forward_list.h:312
void reverse()
Definition: intrusive_forward_list.h:307
void splice_after(iterator pos, IntrusiveForwardList< T > &other, iterator first, iterator last)
Definition: intrusive_forward_list.h:288
void clear()
Definition: intrusive_forward_list.h:211
bool empty() const noexcept
Definition: intrusive_forward_list.h:201
iterator insert_after(iterator pos, T &item)
Inserts the given item after the given position, pos.
Definition: intrusive_forward_list.h:214
void PushBackSlow(IntrusiveForwardList< T > &forward_list, T &item)
Inserts an element at the end of the forward list. Runs in O(n) time.
Definition: intrusive_forward_list.h:50
void sort()
Definition: intrusive_forward_list.h:329
void sort(Compare comp)
Definition: intrusive_forward_list.h:337
void splice_after(iterator pos, IntrusiveForwardList< T > &other)
Definition: intrusive_forward_list.h:276
constexpr Item()=default
constexpr size_type max_size() const noexcept
Definition: intrusive_forward_list.h:204
iterator insert_after(iterator pos, Iterator first, Iterator last)
Definition: intrusive_forward_list.h:221
IntrusiveForwardList(IntrusiveForwardList &&)=default
reference front()
Reference to the first element in the list. Undefined behavior if empty().
Definition: intrusive_forward_list.h:175
size_type remove_if(UnaryPredicate pred)
Definition: intrusive_forward_list.h:300
iterator insert_after(iterator pos, std::initializer_list< T * > items)
Definition: intrusive_forward_list.h:227
IntrusiveForwardList & operator=(IntrusiveForwardList &&)=default
bool remove(const T &item)
Definition: intrusive_forward_list.h:296
void push_front(T &item)
Definition: intrusive_forward_list.h:242
IntrusiveForwardList(std::initializer_list< Item * > items)
Constructs a list from a std::initializer_list of pointers to items.
Definition: intrusive_forward_list.h:160
IntrusiveForwardList(Iterator first, Iterator last)
Definition: intrusive_forward_list.h:155
void splice_after(iterator pos, IntrusiveForwardList< T > &other, iterator it)
Definition: intrusive_forward_list.h:282
The Pigweed namespace.
Definition: alignment.h:27