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