Pigweed
 
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
85template <typename T>
87 private:
88 using ItemBase = ::pw::containers::internal::IntrusiveForwardListItem;
89
90 public:
91 using element_type = T;
92 using value_type = std::remove_cv_t<element_type>;
93 using size_type = std::size_t;
94 using difference_type = std::ptrdiff_t;
95 using reference = value_type&;
96 using const_reference = const value_type&;
97 using pointer = element_type*;
98 using const_pointer = const element_type*;
99
100 class Item : public ItemBase {
101 protected:
106 constexpr explicit Item() = default;
107
108 private:
109 // IntrusiveItem is used to ensure T inherits from this container's Item
110 // type. See also `CheckItemType`.
111 template <typename, typename, bool>
112 friend struct containers::internal::IntrusiveItem;
113 using ItemType = T;
114 };
115
116 using iterator =
117 typename ::pw::containers::internal::ForwardIterator<T, ItemBase>;
118 using const_iterator =
119 typename ::pw::containers::internal::ForwardIterator<std::add_const_t<T>,
120 const ItemBase>;
121
122 constexpr IntrusiveForwardList() { CheckItemType(); }
123
124 // Intrusive lists cannot be copied, since each Item can only be in one list.
126 IntrusiveForwardList& operator=(const IntrusiveForwardList&) = delete;
127
132
137
141 template <typename Iterator>
142 IntrusiveForwardList(Iterator first, Iterator last) {
143 list_.assign(first, last);
144 }
145
147 IntrusiveForwardList(std::initializer_list<Item*> items)
148 : IntrusiveForwardList(items.begin(), items.end()) {}
149
150 template <typename Iterator>
151 void assign(Iterator first, Iterator last) {
152 list_.assign(first, last);
153 }
154
155 void assign(std::initializer_list<T*> items) {
156 list_.assign(items.begin(), items.end());
157 }
158
159 // Element access
160
162 reference front() { return *static_cast<T*>(list_.begin()); }
163 const_reference front() const {
164 return *static_cast<const T*>(list_.begin());
165 }
166
167 // Iterators
168
169 iterator before_begin() noexcept { return iterator(list_.before_begin()); }
170 const_iterator before_begin() const noexcept {
171 return const_iterator(list_.before_begin());
172 }
173 const_iterator cbefore_begin() const noexcept { return before_begin(); }
174
175 iterator begin() noexcept { return iterator(list_.begin()); }
176 const_iterator begin() const noexcept {
177 return const_iterator(list_.begin());
178 }
179 const_iterator cbegin() const noexcept { return begin(); }
180
181 iterator end() noexcept { return iterator(list_.end()); }
182 const_iterator end() const noexcept { return const_iterator(list_.end()); }
183 const_iterator cend() const noexcept { return end(); }
184
185 // Capacity
186
188 [[nodiscard]] bool empty() const noexcept { return list_.empty(); }
189
191 constexpr size_type max_size() const noexcept {
192 return std::numeric_limits<difference_type>::max();
193 }
194
195 // Modifiers
196
198 void clear() { list_.clear(); }
199
201 iterator insert_after(iterator pos, T& item) {
202 return iterator(list_.insert_after(pos.item_, item));
203 }
204
207 template <typename Iterator>
208 iterator insert_after(iterator pos, Iterator first, Iterator last) {
209 return iterator(list_.insert_after(pos.item_, first, last));
210 }
211
214 iterator insert_after(iterator pos, std::initializer_list<T*> items) {
215 return insert_after(pos, items.begin(), items.end());
216 }
217
219 iterator erase_after(iterator pos) {
220 return iterator(list_.erase_after(pos.item_));
221 }
222
224 iterator erase_after(iterator first, iterator last) {
225 return iterator(list_.erase_after(first.item_, last.item_));
226 }
227
229 void push_front(T& item) { list_.insert_after(list_.before_begin(), item); }
230
232 void pop_front() { remove(front()); }
233
237 void swap(IntrusiveForwardList<T>& other) noexcept {
238 list_.swap(other.list_);
239 }
240
241 // Operations
242
247 list_.merge(other.list_, [](const ItemBase& a, const ItemBase& b) -> bool {
248 return static_cast<const T&>(a) < static_cast<const T&>(b);
249 });
250 }
251
253 template <typename Compare>
254 void merge(IntrusiveForwardList<T>& other, Compare comp) {
255 list_.merge(other.list_, [comp](const ItemBase& a, const ItemBase& b) {
256 return comp(static_cast<const T&>(a), static_cast<const T&>(b));
257 });
258 }
259
262 void splice_after(iterator pos, IntrusiveForwardList<T>& other) {
263 splice_after(pos, other, other.before_begin(), other.end());
264 }
265
268 void splice_after(iterator pos, IntrusiveForwardList<T>& other, iterator it) {
269 splice_after(pos, other, it, std::next(std::next(it)));
270 }
271
274 void splice_after(iterator pos,
276 iterator first,
277 iterator last) {
278 list_.splice_after(pos.item_, other.list_, first.item_, last.item_);
279 }
280
282 bool remove(const T& item) { return list_.remove(item); }
283
285 template <typename UnaryPredicate>
286 size_type remove_if(UnaryPredicate pred) {
287 return list_.remove_if([pred](const ItemBase& item) -> bool {
288 return pred(static_cast<const T&>(item));
289 });
290 }
291
293 void reverse() { list_.reverse(); }
294
298 size_type unique() {
299 return list_.unique([](const ItemBase& a, const ItemBase& b) -> bool {
300 return static_cast<const T&>(a) == static_cast<const T&>(b);
301 });
302 }
303
305 template <typename BinaryPredicate>
306 size_type unique(BinaryPredicate pred) {
307 return list_.unique([pred](const ItemBase& a, const ItemBase& b) {
308 return pred(static_cast<const T&>(a), static_cast<const T&>(b));
309 });
310 }
311
315 void sort() {
316 list_.sort([](const ItemBase& a, const ItemBase& b) -> bool {
317 return static_cast<const T&>(a) < static_cast<const T&>(b);
318 });
319 }
320
322 template <typename Compare>
323 void sort(Compare comp) {
324 list_.sort([comp](const ItemBase& a, const ItemBase& b) {
325 return comp(static_cast<const T&>(a), static_cast<const T&>(b));
326 });
327 }
328
329 private:
330 // Check that T is an Item in a function, since the class T will not be fully
331 // defined when the IntrusiveList<T> class is instantiated.
332 static constexpr void CheckItemType() {
333 using IntrusiveItemType =
334 typename containers::internal::IntrusiveItem<ItemBase, T>::Type;
335 static_assert(
336 std::is_base_of<IntrusiveItemType, T>(),
337 "IntrusiveForwardList items must be derived from "
338 "IntrusiveForwardList<T>::Item, where T is the item or one of its "
339 "bases.");
340 }
341
342 template <typename>
343 friend class containers::internal::LegacyIntrusiveList;
344
346};
347
348} // namespace pw
Definition: intrusive_forward_list.h:100
constexpr Item()=default
Definition: intrusive_forward_list.h:86
void merge(IntrusiveForwardList< T > &other, Compare comp)
Definition: intrusive_forward_list.h:254
void pop_front()
Removes the first item in the list. The list must not be empty.
Definition: intrusive_forward_list.h:232
size_type unique(BinaryPredicate pred)
Definition: intrusive_forward_list.h:306
void merge(IntrusiveForwardList< T > &other)
Definition: intrusive_forward_list.h:246
iterator erase_after(iterator pos)
Removes the item following pos from the list. The item is not destructed.
Definition: intrusive_forward_list.h:219
void swap(IntrusiveForwardList< T > &other) noexcept
Definition: intrusive_forward_list.h:237
iterator erase_after(iterator first, iterator last)
Removes the range of items from first (inclusive) to last (exclusive).
Definition: intrusive_forward_list.h:224
size_type unique()
Definition: intrusive_forward_list.h:298
void reverse()
Definition: intrusive_forward_list.h:293
void splice_after(iterator pos, IntrusiveForwardList< T > &other, iterator first, iterator last)
Definition: intrusive_forward_list.h:274
void clear()
Definition: intrusive_forward_list.h:198
bool empty() const noexcept
Definition: intrusive_forward_list.h:188
iterator insert_after(iterator pos, T &item)
Inserts the given item after the given position, pos.
Definition: intrusive_forward_list.h:201
void sort()
Definition: intrusive_forward_list.h:315
void sort(Compare comp)
Definition: intrusive_forward_list.h:323
void splice_after(iterator pos, IntrusiveForwardList< T > &other)
Definition: intrusive_forward_list.h:262
constexpr size_type max_size() const noexcept
Definition: intrusive_forward_list.h:191
iterator insert_after(iterator pos, Iterator first, Iterator last)
Definition: intrusive_forward_list.h:208
IntrusiveForwardList(IntrusiveForwardList &&)=default
reference front()
Reference to the first element in the list. Undefined behavior if empty().
Definition: intrusive_forward_list.h:162
size_type remove_if(UnaryPredicate pred)
Definition: intrusive_forward_list.h:286
iterator insert_after(iterator pos, std::initializer_list< T * > items)
Definition: intrusive_forward_list.h:214
IntrusiveForwardList & operator=(IntrusiveForwardList &&)=default
bool remove(const T &item)
Definition: intrusive_forward_list.h:282
void push_front(T &item)
Inserts the item at the start of the list.
Definition: intrusive_forward_list.h:229
IntrusiveForwardList(std::initializer_list< Item * > items)
Constructs a list from a std::initializer_list of pointers to items.
Definition: intrusive_forward_list.h:147
IntrusiveForwardList(Iterator first, Iterator last)
Definition: intrusive_forward_list.h:142
void splice_after(iterator pos, IntrusiveForwardList< T > &other, iterator it)
Definition: intrusive_forward_list.h:268
Definition: intrusive_list.h:33
size_t unique(BinaryPredicate pred)
Definition: intrusive_list.h:273
void sort(Compare comp)
Definition: intrusive_list.h:300
size_t remove_if(UnaryPredicate pred, size_t max=std::numeric_limits< size_t >::max())
Definition: intrusive_list.h:234
void reverse()
Reverses the order of items in the list.
Definition: intrusive_list.h:257
constexpr Item * before_begin() noexcept
Returns a pointer to the sentinel item.
Definition: intrusive_list.h:72
constexpr Item * begin() noexcept
Returns a pointer to the first item.
Definition: intrusive_list.h:76
void merge(GenericIntrusiveList< Item > &other, Compare comp)
Definition: intrusive_list.h:173
static Item * insert_after(Item *prev, Item &item)
Definition: intrusive_list.h:115
static void splice_after(Item *pos, GenericIntrusiveList< Item > &other, Item *first, Item *last)
Definition: intrusive_list.h:191
void clear()
Removes all items from the list.
Definition: intrusive_list.h:100
constexpr Item * end() noexcept
Returns a pointer to the sentinel item.
Definition: intrusive_list.h:83
static Item * erase_after(Item *item)
Definition: intrusive_list.h:143
Definition: intrusive_forward_list.h:39
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27