1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ART_LIBARTBASE_BASE_INTRUSIVE_FORWARD_LIST_H_
18 #define ART_LIBARTBASE_BASE_INTRUSIVE_FORWARD_LIST_H_
19
20 #include <stdint.h>
21 #include <functional>
22 #include <iterator>
23 #include <memory>
24 #include <type_traits>
25
26 #include <android-base/logging.h>
27
28 #include "base/casts.h"
29 #include "base/macros.h"
30
31 namespace art {
32
33 struct IntrusiveForwardListHook {
IntrusiveForwardListHookIntrusiveForwardListHook34 IntrusiveForwardListHook() : next_hook(nullptr) { }
IntrusiveForwardListHookIntrusiveForwardListHook35 explicit IntrusiveForwardListHook(const IntrusiveForwardListHook* hook) : next_hook(hook) { }
36
37 // Allow copyable values but do not copy the hook, it is not part of the value.
IntrusiveForwardListHookIntrusiveForwardListHook38 explicit IntrusiveForwardListHook([[maybe_unused]] const IntrusiveForwardListHook& other)
39 : next_hook(nullptr) {}
40 IntrusiveForwardListHook& operator=([[maybe_unused]] const IntrusiveForwardListHook& src) {
41 return *this;
42 }
43
44 mutable const IntrusiveForwardListHook* next_hook;
45 };
46
47 template <typename Derived, typename Tag = void>
48 struct IntrusiveForwardListNode : public IntrusiveForwardListHook {
49 };
50
51 template <typename T, IntrusiveForwardListHook T::* NextPtr = &T::hook>
52 class IntrusiveForwardListMemberHookTraits;
53
54 template <typename T, typename Tag = void>
55 class IntrusiveForwardListBaseHookTraits;
56
57 template <typename T,
58 typename HookTraits = IntrusiveForwardListBaseHookTraits<std::remove_const_t<T>>>
59 class IntrusiveForwardList;
60
61 template <typename T, typename HookTraits>
62 class IntrusiveForwardListIterator {
63 public:
64 using iterator_category = std::forward_iterator_tag;
65 using value_type = T;
66 using difference_type = ptrdiff_t;
67 using pointer = value_type*;
68 using reference = value_type&;
69
70 // Construct/copy/destroy (except the private constructor used by IntrusiveForwardList<>).
IntrusiveForwardListIterator()71 IntrusiveForwardListIterator() : hook_(nullptr) { }
72 IntrusiveForwardListIterator(const IntrusiveForwardListIterator& src) = default;
73 IntrusiveForwardListIterator& operator=(const IntrusiveForwardListIterator& src) = default;
74
75 // Conversion from iterator to const_iterator.
76 template <typename OtherT,
77 typename = std::enable_if_t<std::is_same_v<T, const OtherT>>>
IntrusiveForwardListIterator(const IntrusiveForwardListIterator<OtherT,HookTraits> & src)78 IntrusiveForwardListIterator(const IntrusiveForwardListIterator<OtherT, HookTraits>& src) // NOLINT, implicit
79 : hook_(src.hook_) { }
80
81 // Iteration.
82 IntrusiveForwardListIterator& operator++() {
83 DCHECK(hook_ != nullptr);
84 hook_ = hook_->next_hook;
85 return *this;
86 }
87 IntrusiveForwardListIterator operator++(int) {
88 IntrusiveForwardListIterator tmp(*this);
89 ++*this;
90 return tmp;
91 }
92
93 // Dereference
94 T& operator*() const {
95 DCHECK(hook_ != nullptr);
96 return *HookTraits::GetValue(hook_);
97 }
98 T* operator->() const {
99 return &**this;
100 }
101
102 private:
IntrusiveForwardListIterator(const IntrusiveForwardListHook * hook)103 explicit IntrusiveForwardListIterator(const IntrusiveForwardListHook* hook) : hook_(hook) { }
104
105 const IntrusiveForwardListHook* hook_;
106
107 template <typename OtherT, typename OtherTraits>
108 friend class IntrusiveForwardListIterator;
109
110 template <typename OtherT, typename OtherTraits>
111 friend class IntrusiveForwardList;
112
113 template <typename OtherT1, typename OtherT2, typename OtherTraits>
114 friend std::enable_if_t<std::is_same_v<const OtherT1, const OtherT2>, bool>
115 operator==(const IntrusiveForwardListIterator<OtherT1, OtherTraits>& lhs,
116 const IntrusiveForwardListIterator<OtherT2, OtherTraits>& rhs);
117 };
118
119 template <typename T, typename OtherT, typename HookTraits>
120 std::enable_if_t<std::is_same_v<const T, const OtherT>, bool> operator==(
121 const IntrusiveForwardListIterator<T, HookTraits>& lhs,
122 const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) {
123 return lhs.hook_ == rhs.hook_;
124 }
125
126 template <typename T, typename OtherT, typename HookTraits>
127 std::enable_if_t<std::is_same_v<const T, const OtherT>, bool> operator!=(
128 const IntrusiveForwardListIterator<T, HookTraits>& lhs,
129 const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) {
130 return !(lhs == rhs);
131 }
132
133 // Intrusive version of std::forward_list<>. See also slist<> in Boost.Intrusive.
134 //
135 // This class template provides the same interface as std::forward_list<> as long
136 // as the functions are meaningful for an intrusive container; this excludes emplace
137 // functions and functions taking an std::initializer_list<> as the container does
138 // not construct elements.
139 template <typename T, typename HookTraits>
140 class IntrusiveForwardList {
141 public:
142 using hook_traits = HookTraits;
143 using value_type = T;
144 using reference = T&;
145 using const_reference = const T&;
146 using pointer = T*;
147 using const_pointer = const T*;
148 using iterator = IntrusiveForwardListIterator<T, hook_traits>;
149 using const_iterator = IntrusiveForwardListIterator<const T, hook_traits>;
150
151 // Construct/copy/destroy.
152 IntrusiveForwardList() = default;
153 template <typename InputIterator>
IntrusiveForwardList(InputIterator first,InputIterator last)154 IntrusiveForwardList(InputIterator first, InputIterator last) : IntrusiveForwardList() {
155 insert_after(before_begin(), first, last);
156 }
IntrusiveForwardList(IntrusiveForwardList && src)157 IntrusiveForwardList(IntrusiveForwardList&& src) noexcept : first_(src.first_.next_hook) {
158 src.first_.next_hook = nullptr;
159 }
160 IntrusiveForwardList& operator=(const IntrusiveForwardList& src) = delete;
161 IntrusiveForwardList& operator=(IntrusiveForwardList&& src) noexcept {
162 IntrusiveForwardList tmp(std::move(src));
163 tmp.swap(*this);
164 return *this;
165 }
166 ~IntrusiveForwardList() = default;
167
168 // Iterators.
before_begin()169 iterator before_begin() { return iterator(&first_); }
before_begin()170 const_iterator before_begin() const { return const_iterator(&first_); }
begin()171 iterator begin() { return iterator(first_.next_hook); }
begin()172 const_iterator begin() const { return const_iterator(first_.next_hook); }
end()173 iterator end() { return iterator(nullptr); }
end()174 const_iterator end() const { return const_iterator(nullptr); }
cbefore_begin()175 const_iterator cbefore_begin() const { return const_iterator(&first_); }
cbegin()176 const_iterator cbegin() const { return const_iterator(first_.next_hook); }
cend()177 const_iterator cend() const { return const_iterator(nullptr); }
178
179 // Capacity.
empty()180 bool empty() const { return begin() == end(); }
max_size()181 size_t max_size() { return static_cast<size_t>(-1); }
182
183 // Element access.
front()184 reference front() { return *begin(); }
front()185 const_reference front() const { return *begin(); }
186
187 // Modifiers.
188 template <typename InputIterator>
assign(InputIterator first,InputIterator last)189 void assign(InputIterator first, InputIterator last) {
190 IntrusiveForwardList tmp(first, last);
191 tmp.swap(*this);
192 }
push_front(value_type & value)193 void push_front(value_type& value) {
194 insert_after(before_begin(), value);
195 }
pop_front()196 void pop_front() {
197 DCHECK(!empty());
198 erase_after(before_begin());
199 }
insert_after(const_iterator position,value_type & value)200 iterator insert_after(const_iterator position, value_type& value) {
201 const IntrusiveForwardListHook* new_hook = hook_traits::GetHook(&value);
202 new_hook->next_hook = position.hook_->next_hook;
203 position.hook_->next_hook = new_hook;
204 return iterator(new_hook);
205 }
206 template <typename InputIterator>
insert_after(const_iterator position,InputIterator first,InputIterator last)207 iterator insert_after(const_iterator position, InputIterator first, InputIterator last) {
208 while (first != last) {
209 position = insert_after(position, *first++);
210 }
211 return iterator(position.hook_);
212 }
erase_after(const_iterator position)213 iterator erase_after(const_iterator position) {
214 const_iterator last = position;
215 std::advance(last, 2);
216 return erase_after(position, last);
217 }
erase_after(const_iterator position,const_iterator last)218 iterator erase_after(const_iterator position, const_iterator last) {
219 DCHECK(position != last);
220 position.hook_->next_hook = last.hook_;
221 return iterator(last.hook_);
222 }
swap(IntrusiveForwardList & other)223 void swap(IntrusiveForwardList& other) {
224 std::swap(first_.next_hook, other.first_.next_hook);
225 }
clear()226 void clear() {
227 first_.next_hook = nullptr;
228 }
229
230 // Operations.
splice_after(const_iterator position,IntrusiveForwardList & src)231 void splice_after(const_iterator position, IntrusiveForwardList& src) {
232 DCHECK(position != end());
233 splice_after(position, src, src.before_begin(), src.end());
234 }
splice_after(const_iterator position,IntrusiveForwardList && src)235 void splice_after(const_iterator position, IntrusiveForwardList&& src) {
236 splice_after(position, src); // Use l-value overload.
237 }
238 // Splice the element after `i`.
splice_after(const_iterator position,IntrusiveForwardList & src,const_iterator i)239 void splice_after(const_iterator position, IntrusiveForwardList& src, const_iterator i) {
240 // The standard specifies that this version does nothing if `position == i`
241 // or `position == ++i`. We must handle the latter here because the overload
242 // `splice_after(position, src, first, last)` does not allow `position` inside
243 // the range `(first, last)`.
244 if (++const_iterator(i) == position) {
245 return;
246 }
247 const_iterator last = i;
248 std::advance(last, 2);
249 splice_after(position, src, i, last);
250 }
251 // Splice the element after `i`.
splice_after(const_iterator position,IntrusiveForwardList && src,const_iterator i)252 void splice_after(const_iterator position, IntrusiveForwardList&& src, const_iterator i) {
253 splice_after(position, src, i); // Use l-value overload.
254 }
255 // Splice elements between `first` and `last`, i.e. open range `(first, last)`.
splice_after(const_iterator position,IntrusiveForwardList & src,const_iterator first,const_iterator last)256 void splice_after(const_iterator position,
257 IntrusiveForwardList& src,
258 const_iterator first,
259 const_iterator last) {
260 DCHECK(position != end());
261 DCHECK(first != last);
262 if (++const_iterator(first) == last) {
263 // Nothing to do.
264 return;
265 }
266 // If position is just before end() and last is src.end(), we can finish this quickly.
267 if (++const_iterator(position) == end() && last == src.end()) {
268 position.hook_->next_hook = first.hook_->next_hook;
269 first.hook_->next_hook = nullptr;
270 return;
271 }
272 // Otherwise we need to find the position before last to fix up the hook.
273 const_iterator before_last = first;
274 while (++const_iterator(before_last) != last) {
275 ++before_last;
276 }
277 // Detach (first, last).
278 const IntrusiveForwardListHook* first_taken = first.hook_->next_hook;
279 first.hook_->next_hook = last.hook_;
280 // Attach the sequence to the new position.
281 before_last.hook_->next_hook = position.hook_->next_hook;
282 position.hook_->next_hook = first_taken;
283 }
284 // Splice elements between `first` and `last`, i.e. open range `(first, last)`.
splice_after(const_iterator position,IntrusiveForwardList && src,const_iterator first,const_iterator last)285 void splice_after(const_iterator position,
286 IntrusiveForwardList&& src,
287 const_iterator first,
288 const_iterator last) {
289 splice_after(position, src, first, last); // Use l-value overload.
290 }
remove(const value_type & value)291 void remove(const value_type& value) {
292 remove_if([value](const value_type& v) { return value == v; });
293 }
294 template <typename Predicate>
remove_if(Predicate pred)295 void remove_if(Predicate pred) {
296 iterator prev = before_begin();
297 for (iterator current = begin(); current != end(); ++current) {
298 if (pred(*current)) {
299 erase_after(prev);
300 current = prev;
301 } else {
302 prev = current;
303 }
304 }
305 }
unique()306 void unique() {
307 unique(std::equal_to<value_type>());
308 }
309 template <typename BinaryPredicate>
unique(BinaryPredicate pred)310 void unique(BinaryPredicate pred) {
311 if (!empty()) {
312 iterator prev = begin();
313 iterator current = prev;
314 ++current;
315 for (; current != end(); ++current) {
316 if (pred(*prev, *current)) {
317 erase_after(prev);
318 current = prev;
319 } else {
320 prev = current;
321 }
322 }
323 }
324 }
merge(IntrusiveForwardList & other)325 void merge(IntrusiveForwardList& other) {
326 merge(other, std::less<value_type>());
327 }
merge(IntrusiveForwardList && other)328 void merge(IntrusiveForwardList&& other) {
329 merge(other); // Use l-value overload.
330 }
331 template <typename Compare>
merge(IntrusiveForwardList & other,Compare cmp)332 void merge(IntrusiveForwardList& other, Compare cmp) {
333 iterator prev = before_begin();
334 iterator current = begin();
335 iterator other_prev = other.before_begin();
336 iterator other_current = other.begin();
337 while (current != end() && other_current != other.end()) {
338 if (cmp(*other_current, *current)) {
339 ++other_current;
340 splice_after(prev, other, other_prev);
341 ++prev;
342 } else {
343 prev = current;
344 ++current;
345 }
346 DCHECK(++const_iterator(prev) == current);
347 DCHECK(++const_iterator(other_prev) == other_current);
348 }
349 splice_after(prev, other);
350 }
351 template <typename Compare>
merge(IntrusiveForwardList && other,Compare cmp)352 void merge(IntrusiveForwardList&& other, Compare cmp) {
353 merge(other, cmp); // Use l-value overload.
354 }
sort()355 void sort() {
356 sort(std::less<value_type>());
357 }
358 template <typename Compare>
sort(Compare cmp)359 void sort(Compare cmp) {
360 size_t n = std::distance(begin(), end());
361 if (n >= 2u) {
362 const_iterator middle = before_begin();
363 std::advance(middle, n / 2u);
364 IntrusiveForwardList second_half;
365 second_half.splice_after(second_half.before_begin(), *this, middle, end());
366 sort(cmp);
367 second_half.sort(cmp);
368 merge(second_half, cmp);
369 }
370 }
reverse()371 void reverse() {
372 IntrusiveForwardList reversed;
373 while (!empty()) {
374 value_type& value = front();
375 erase_after(before_begin());
376 reversed.insert_after(reversed.before_begin(), value);
377 }
378 reversed.swap(*this);
379 }
380
381 // Extensions.
HasExactlyOneElement()382 bool HasExactlyOneElement() const {
383 return !empty() && ++begin() == end();
384 }
SizeSlow()385 size_t SizeSlow() const {
386 return std::distance(begin(), end());
387 }
ContainsNode(const_reference node)388 bool ContainsNode(const_reference node) const {
389 for (auto&& n : *this) {
390 if (std::addressof(n) == std::addressof(node)) {
391 return true;
392 }
393 }
394 return false;
395 }
396
397 private:
ModifiableHook(const IntrusiveForwardListHook * hook)398 static IntrusiveForwardListHook* ModifiableHook(const IntrusiveForwardListHook* hook) {
399 return const_cast<IntrusiveForwardListHook*>(hook);
400 }
401
402 IntrusiveForwardListHook first_;
403 };
404
405 template <typename T, typename HookTraits>
swap(IntrusiveForwardList<T,HookTraits> & lhs,IntrusiveForwardList<T,HookTraits> & rhs)406 void swap(IntrusiveForwardList<T, HookTraits>& lhs, IntrusiveForwardList<T, HookTraits>& rhs) {
407 lhs.swap(rhs);
408 }
409
410 template <typename T, typename HookTraits>
411 bool operator==(const IntrusiveForwardList<T, HookTraits>& lhs,
412 const IntrusiveForwardList<T, HookTraits>& rhs) {
413 auto lit = lhs.begin();
414 auto rit = rhs.begin();
415 for (; lit != lhs.end() && rit != rhs.end(); ++lit, ++rit) {
416 if (*lit != *rit) {
417 return false;
418 }
419 }
420 return lit == lhs.end() && rit == rhs.end();
421 }
422
423 template <typename T, typename HookTraits>
424 bool operator!=(const IntrusiveForwardList<T, HookTraits>& lhs,
425 const IntrusiveForwardList<T, HookTraits>& rhs) {
426 return !(lhs == rhs);
427 }
428
429 template <typename T, typename HookTraits>
430 bool operator<(const IntrusiveForwardList<T, HookTraits>& lhs,
431 const IntrusiveForwardList<T, HookTraits>& rhs) {
432 return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
433 }
434
435 template <typename T, typename HookTraits>
436 bool operator>(const IntrusiveForwardList<T, HookTraits>& lhs,
437 const IntrusiveForwardList<T, HookTraits>& rhs) {
438 return rhs < lhs;
439 }
440
441 template <typename T, typename HookTraits>
442 bool operator<=(const IntrusiveForwardList<T, HookTraits>& lhs,
443 const IntrusiveForwardList<T, HookTraits>& rhs) {
444 return !(rhs < lhs);
445 }
446
447 template <typename T, typename HookTraits>
448 bool operator>=(const IntrusiveForwardList<T, HookTraits>& lhs,
449 const IntrusiveForwardList<T, HookTraits>& rhs) {
450 return !(lhs < rhs);
451 }
452
453 template <typename T, IntrusiveForwardListHook T::* NextPtr>
454 class IntrusiveForwardListMemberHookTraits {
455 public:
GetHook(const T * value)456 static const IntrusiveForwardListHook* GetHook(const T* value) {
457 return &(value->*NextPtr);
458 }
459
GetValue(const IntrusiveForwardListHook * hook)460 static T* GetValue(const IntrusiveForwardListHook* hook) {
461 return reinterpret_cast<T*>(
462 reinterpret_cast<uintptr_t>(hook) - OFFSETOF_MEMBERPTR(T, NextPtr));
463 }
464 };
465
466 template <typename T, typename Tag>
467 class IntrusiveForwardListBaseHookTraits {
468 public:
GetHook(const T * value)469 static const IntrusiveForwardListHook* GetHook(const T* value) {
470 // Explicit conversion to the "node" followed by implicit conversion to the "hook".
471 return static_cast<const IntrusiveForwardListNode<T, Tag>*>(value);
472 }
473
GetValue(const IntrusiveForwardListHook * hook)474 static T* GetValue(const IntrusiveForwardListHook* hook) {
475 return down_cast<T*>(down_cast<IntrusiveForwardListNode<T, Tag>*>(
476 const_cast<IntrusiveForwardListHook*>(hook)));
477 }
478 };
479
480 } // namespace art
481
482 #endif // ART_LIBARTBASE_BASE_INTRUSIVE_FORWARD_LIST_H_
483