• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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