Pigweed
 
Loading...
Searching...
No Matches
intrusive_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 <algorithm>
17#include <cstddef>
18#include <cstdio>
19#include <initializer_list>
20#include <iterator>
21#include <limits>
22#include <type_traits>
23
24#include "pw_containers/config.h"
25#include "pw_containers/internal/intrusive_item.h"
26#include "pw_containers/internal/intrusive_list.h"
27#include "pw_containers/internal/intrusive_list_item.h"
28#include "pw_containers/internal/intrusive_list_iterator.h"
29#include "pw_containers/internal/legacy_intrusive_list.h"
30#include "pw_containers/intrusive_forward_list.h"
31
32namespace pw {
33namespace containers::future {
34
81template <typename T>
83 private:
84 using ItemBase = ::pw::containers::internal::IntrusiveListItem;
85
86 public:
87 using element_type = T;
88 using value_type = std::remove_cv_t<element_type>;
89 using size_type = std::size_t;
90 using difference_type = std::ptrdiff_t;
91 using reference = value_type&;
92 using const_reference = const value_type&;
93 using pointer = element_type*;
94 using const_pointer = const element_type*;
95
96 class Item : public ItemBase {
97 protected:
103 constexpr explicit Item() = default;
104
105 private:
106 // IntrusiveItem is used to ensure T inherits from this container's Item
107 // type. See also `CheckItemType`.
108 template <typename, typename, bool>
109 friend struct containers::internal::IntrusiveItem;
110 using ItemType = T;
111 };
112
113 using iterator =
114 typename ::pw::containers::internal::BidirectionalIterator<T, ItemBase>;
115 using const_iterator = typename ::pw::containers::internal::
116 BidirectionalIterator<std::add_const_t<T>, const ItemBase>;
117 using reverse_iterator = std::reverse_iterator<iterator>;
118 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
119
120 constexpr IntrusiveList() { CheckItemType(); }
121
122 // Intrusive lists cannot be copied, since each Item can only be in one list.
123 IntrusiveList(const IntrusiveList&) = delete;
124 IntrusiveList& operator=(const IntrusiveList&) = delete;
125
130
135
136 // Constructs an IntrusiveList from an iterator over Items. The iterator may
137 // dereference as either Item& (e.g. from std::array<Item>) or Item* (e.g.
138 // from std::initializer_list<Item*>).
139 template <typename Iterator>
140 IntrusiveList(Iterator first, Iterator last) {
141 list_.assign(first, last);
142 }
143
144 // Constructs an IntrusiveList from a std::initializer_list of pointers to
145 // items.
146 IntrusiveList(std::initializer_list<Item*> items)
147 : IntrusiveList(items.begin(), items.end()) {}
148
149 template <typename Iterator>
150 void assign(Iterator first, Iterator last) {
151 list_.assign(first, last);
152 }
153
154 void assign(std::initializer_list<T*> items) {
155 list_.assign(items.begin(), items.end());
156 }
157
158 // Element access
159
161 T& front() { return *static_cast<T*>(list_.begin()); }
162
164 T& back() { return *static_cast<T*>(list_.before_end()); }
165
166 // Iterators
167
168 iterator begin() noexcept {
169 return iterator(static_cast<Item*>(list_.begin()));
170 }
171 const_iterator begin() const noexcept {
172 return const_iterator(static_cast<const Item*>(list_.begin()));
173 }
174 const_iterator cbegin() const noexcept { return begin(); }
175
176 iterator end() noexcept { return iterator(static_cast<Item*>(list_.end())); }
177 const_iterator end() const noexcept {
178 return const_iterator(static_cast<const Item*>(list_.end()));
179 }
180 const_iterator cend() const noexcept { return end(); }
181
182 reverse_iterator rbegin() { return reverse_iterator(end()); }
183 const_reverse_iterator rbegin() const {
184 return const_reverse_iterator(end());
185 }
186 const_reverse_iterator crbegin() const {
187 return const_reverse_iterator(end());
188 }
189
190 reverse_iterator rend() { return reverse_iterator(begin()); }
191 const_reverse_iterator rend() const {
192 return const_reverse_iterator(begin());
193 }
194 const_reverse_iterator crend() const {
195 return const_reverse_iterator(begin());
196 }
197
198 // Capacity
199
201 [[nodiscard]] bool empty() const noexcept { return list_.empty(); }
202
204 size_t size() const {
205 return static_cast<size_type>(std::distance(begin(), end()));
206 }
207
209 constexpr size_type max_size() const noexcept { return list_.max_size(); }
210
211 // Modifiers
212
214 void clear() { list_.clear(); }
215
217 iterator insert(iterator pos, T& item) {
218 return iterator(list_.insert_after((--pos).item_, item));
219 }
220
223 template <typename Iterator>
224 iterator insert(iterator pos, Iterator first, Iterator last) {
225 return iterator(list_.insert_after((--pos).item_, first, last));
226 }
227
230 iterator insert(iterator pos, std::initializer_list<T*> items) {
231 return insert(pos, items.begin(), items.end());
232 }
233
235 iterator erase(T& item) { return erase(iterator(&item)); }
236
239 iterator erase(iterator pos) {
240 return iterator(list_.erase_after((--pos).item_));
241 }
242
244 iterator erase(iterator first, iterator last) {
245 return iterator(list_.erase_after((--first).item_, last.item_));
246 }
247
249 void push_back(T& item) { list_.insert_after(list_.before_end(), item); }
250
252 void pop_back() { remove(back()); }
253
255 void push_front(T& item) { list_.insert_after(list_.before_begin(), item); }
256
258 void pop_front() { remove(front()); }
259
263 void swap(IntrusiveList<T>& other) noexcept { list_.swap(other.list_); }
264
265 // Operations
266
270 void merge(IntrusiveList<T>& other) {
271 list_.merge(other.list_, [](const ItemBase& a, const ItemBase& b) {
272 return static_cast<const T&>(a) < static_cast<const T&>(b);
273 });
274 }
275
277 template <typename Compare>
278 void merge(IntrusiveList<T>& other, Compare comp) {
279 list_.merge(other.list_, [comp](const ItemBase& a, const ItemBase& b) {
280 return comp(static_cast<const T&>(a), static_cast<const T&>(b));
281 });
282 }
283
286 void splice(iterator pos, IntrusiveList<T>& other) {
287 splice(pos, other, other.begin(), other.end());
288 }
289
292 void splice(iterator pos, IntrusiveList<T>& other, iterator it) {
293 splice(pos, other, it, std::next(it));
294 }
295
298 void splice(iterator pos,
299 IntrusiveList<T>& other,
300 iterator first,
301 iterator last) {
302 list_.splice_after((--pos).item_, other.list_, (--first).item_, last.item_);
303 }
304
306 bool remove(const T& item) { return list_.remove(item); }
307
309 template <typename UnaryPredicate>
310 size_type remove_if(UnaryPredicate pred) {
311 return list_.remove_if([pred](const ItemBase& item) -> bool {
312 return pred(static_cast<const T&>(item));
313 });
314 }
315
317 void reverse() { std::reverse(begin(), end()); }
318
322 size_type unique() {
323 return list_.unique([](const ItemBase& a, const ItemBase& b) -> bool {
324 return static_cast<const T&>(a) == static_cast<const T&>(b);
325 });
326 }
327
329 template <typename BinaryPredicate>
330 size_type unique(BinaryPredicate pred) {
331 return list_.unique([pred](const ItemBase& a, const ItemBase& b) -> bool {
332 return pred(static_cast<const T&>(a), static_cast<const T&>(b));
333 });
334 }
335
339 void sort() {
340 list_.sort([](const ItemBase& a, const ItemBase& b) -> bool {
341 return static_cast<const T&>(a) < static_cast<const T&>(b);
342 });
343 }
344
346 template <typename Compare>
347 void sort(Compare comp) {
348 list_.sort([comp](const ItemBase& a, const ItemBase& b) -> bool {
349 return comp(static_cast<const T&>(a), static_cast<const T&>(b));
350 });
351 }
352
353 private:
354 // Check that T is an Item in a function, since the class T will not be fully
355 // defined when the IntrusiveList<T> class is instantiated.
356 static constexpr void CheckItemType() {
357 using IntrusiveItemType =
358 typename containers::internal::IntrusiveItem<ItemBase, T>::Type;
359 static_assert(
360 std::is_base_of<IntrusiveItemType, T>(),
361 "IntrusiveList items must be derived from IntrusiveList<T>::Item, "
362 "where T is the item or one of its bases.");
363 }
364
366};
367
368} // namespace containers::future
369
370// See b/362348318 and comments on `PW_CONTAINERS_USE_LEGACY_INTRUSIVE_LIST` and
371// `PW_CONTAINERS_INTRUSIVE_LIST_SUPPRESS_DEPRECATION_WARNING`.
372#if PW_CONTAINERS_USE_LEGACY_INTRUSIVE_LIST
373#if PW_CONTAINERS_INTRUSIVE_LIST_SUPPRESS_DEPRECATION_WARNING
374#define PW_CONTAINERS_INTRUSIVE_LIST_DEPRECATED
375#else
376#define PW_CONTAINERS_INTRUSIVE_LIST_DEPRECATED \
377 [[deprecated("See b/362348318 for background and workarounds.")]]
378#endif // PW_CONTAINERS_INTRUSIVE_LIST_SUPPRESS_DEPRECATION_WARNING
379
381template <typename T>
382using IntrusiveList PW_CONTAINERS_INTRUSIVE_LIST_DEPRECATED =
383 containers::internal::LegacyIntrusiveList<T>;
384
385#else // PW_CONTAINERS_USE_LEGACY_INTRUSIVE_LIST
386
388template <typename T>
390
391#endif // PW_CONTAINERS_USE_LEGACY_INTRUSIVE_LIST
392
393} // namespace pw
Definition: intrusive_list.h:96
Definition: intrusive_list.h:82
iterator erase(iterator pos)
Definition: intrusive_list.h:239
void swap(IntrusiveList< T > &other) noexcept
Definition: intrusive_list.h:263
void merge(IntrusiveList< T > &other)
Definition: intrusive_list.h:270
iterator erase(T &item)
Removes the given item from the list. The item is not destructed.
Definition: intrusive_list.h:235
iterator insert(iterator pos, T &item)
Inserts the given item before the given position, pos.
Definition: intrusive_list.h:217
IntrusiveList(IntrusiveList &&)=default
void push_front(T &item)
Inserts an element at the beginning of the list.
Definition: intrusive_list.h:255
void push_back(T &item)
Inserts an element at the end of the list.
Definition: intrusive_list.h:249
size_t size() const
Definition: intrusive_list.h:204
void splice(iterator pos, IntrusiveList< T > &other)
Definition: intrusive_list.h:286
size_type remove_if(UnaryPredicate pred)
Definition: intrusive_list.h:310
void clear()
Removes all items from the list.
Definition: intrusive_list.h:214
bool remove(const T &item)
Definition: intrusive_list.h:306
void pop_back()
Removes the last item in the list. The list must not be empty.
Definition: intrusive_list.h:252
void splice(iterator pos, IntrusiveList< T > &other, iterator first, iterator last)
Definition: intrusive_list.h:298
void sort(Compare comp)
Definition: intrusive_list.h:347
iterator erase(iterator first, iterator last)
Removes the range of items from first (inclusive) to last (exclusive).
Definition: intrusive_list.h:244
IntrusiveList & operator=(IntrusiveList &&)=default
void reverse()
Reverses the order of items in the list.
Definition: intrusive_list.h:317
iterator insert(iterator pos, std::initializer_list< T * > items)
Definition: intrusive_list.h:230
iterator insert(iterator pos, Iterator first, Iterator last)
Definition: intrusive_list.h:224
T & back()
Reference to the last element in the list. Undefined behavior if empty().
Definition: intrusive_list.h:164
void sort()
Definition: intrusive_list.h:339
bool empty() const noexcept
Definition: intrusive_list.h:201
constexpr size_type max_size() const noexcept
Definition: intrusive_list.h:209
size_type unique(BinaryPredicate pred)
Definition: intrusive_list.h:330
size_type unique()
Definition: intrusive_list.h:322
void splice(iterator pos, IntrusiveList< T > &other, iterator it)
Definition: intrusive_list.h:292
void merge(IntrusiveList< T > &other, Compare comp)
Definition: intrusive_list.h:278
void pop_front()
Removes the first item in the list. The list must not be empty.
Definition: intrusive_list.h:258
T & front()
Reference to the first element in the list. Undefined behavior if empty().
Definition: intrusive_list.h:161
Definition: intrusive_list.h:33
size_t unique(BinaryPredicate pred)
Definition: intrusive_list.h:273
Item * before_end() noexcept
Returns a pointer to the last item.
Definition: intrusive_list.h:80
void sort(Compare comp)
Definition: intrusive_list.h:300
constexpr size_t max_size() const noexcept
Definition: intrusive_list.h:93
size_t remove_if(UnaryPredicate pred, size_t max=std::numeric_limits< size_t >::max())
Definition: intrusive_list.h:234
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
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27
containers::future::IntrusiveList< T > IntrusiveList
Definition: intrusive_list.h:389