1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_BASE_THREADED_LIST_H_
6 #define V8_BASE_THREADED_LIST_H_
7 
8 #include <iterator>
9 
10 #include "src/base/compiler-specific.h"
11 #include "src/base/macros.h"
12 
13 namespace v8 {
14 namespace base {
15 
16 template <typename T>
17 struct ThreadedListTraits {
nextThreadedListTraits18   static T** next(T* t) { return t->next(); }
startThreadedListTraits19   static T** start(T** t) { return t; }
startThreadedListTraits20   static T* const* start(T* const* t) { return t; }
21 };
22 
23 // Represents a linked list that threads through the nodes in the linked list.
24 // Entries in the list are pointers to nodes. By default nodes need to have a
25 // T** next() method that returns the location where the next value is stored.
26 // The default can be overwritten by providing a ThreadedTraits class.
27 template <typename T, typename BaseClass,
28           typename TLTraits = ThreadedListTraits<T>>
29 class ThreadedListBase final : public BaseClass {
30  public:
ThreadedListBase()31   ThreadedListBase() : head_(nullptr), tail_(&head_) {}
32   ThreadedListBase(const ThreadedListBase&) = delete;
33   ThreadedListBase& operator=(const ThreadedListBase&) = delete;
34 
Add(T * v)35   void Add(T* v) {
36     DCHECK_NULL(*tail_);
37     DCHECK_NULL(*TLTraits::next(v));
38     *tail_ = v;
39     tail_ = TLTraits::next(v);
40     // Check that only one element was added (and that hasn't created a cycle).
41     DCHECK_NULL(*tail_);
42   }
43 
AddFront(T * v)44   void AddFront(T* v) {
45     DCHECK_NULL(*TLTraits::next(v));
46     DCHECK_NOT_NULL(v);
47     T** const next = TLTraits::next(v);
48 
49     *next = head_;
50     if (head_ == nullptr) tail_ = next;
51     head_ = v;
52   }
53 
DropHead()54   void DropHead() {
55     DCHECK_NOT_NULL(head_);
56 
57     T* old_head = head_;
58     head_ = *TLTraits::next(head_);
59     if (head_ == nullptr) tail_ = &head_;
60     *TLTraits::next(old_head) = nullptr;
61   }
62 
Contains(T * v)63   bool Contains(T* v) {
64     for (Iterator it = begin(); it != end(); ++it) {
65       if (*it == v) return true;
66     }
67     return false;
68   }
69 
Append(ThreadedListBase && list)70   void Append(ThreadedListBase&& list) {
71     if (list.is_empty()) return;
72 
73     *tail_ = list.head_;
74     tail_ = list.tail_;
75     list.Clear();
76   }
77 
Prepend(ThreadedListBase && list)78   void Prepend(ThreadedListBase&& list) {
79     if (list.head_ == nullptr) return;
80 
81     T* new_head = list.head_;
82     *list.tail_ = head_;
83     if (head_ == nullptr) {
84       tail_ = list.tail_;
85     }
86     head_ = new_head;
87     list.Clear();
88   }
89 
Clear()90   void Clear() {
91     head_ = nullptr;
92     tail_ = &head_;
93   }
94 
95   ThreadedListBase& operator=(ThreadedListBase&& other) V8_NOEXCEPT {
96     head_ = other.head_;
97     tail_ = other.head_ ? other.tail_ : &head_;
98 #ifdef DEBUG
99     other.Clear();
100 #endif
101     return *this;
102   }
103 
ThreadedListBase(ThreadedListBase && other)104   ThreadedListBase(ThreadedListBase&& other) V8_NOEXCEPT
105       : head_(other.head_),
106         tail_(other.head_ ? other.tail_ : &head_) {
107 #ifdef DEBUG
108     other.Clear();
109 #endif
110   }
111 
Remove(T * v)112   bool Remove(T* v) {
113     T* current = first();
114     if (current == v) {
115       DropHead();
116       return true;
117     }
118 
119     while (current != nullptr) {
120       T* next = *TLTraits::next(current);
121       if (next == v) {
122         *TLTraits::next(current) = *TLTraits::next(next);
123         *TLTraits::next(next) = nullptr;
124 
125         if (TLTraits::next(next) == tail_) {
126           tail_ = TLTraits::next(current);
127         }
128         return true;
129       }
130       current = next;
131     }
132     return false;
133   }
134 
135   class Iterator final {
136    public:
137     using iterator_category = std::forward_iterator_tag;
138     using difference_type = std::ptrdiff_t;
139     using value_type = T*;
140     using reference = value_type;
141     using pointer = value_type*;
142 
143    public:
144     Iterator& operator++() {
145       entry_ = TLTraits::next(*entry_);
146       return *this;
147     }
148     bool operator==(const Iterator& other) const {
149       return entry_ == other.entry_;
150     }
151     bool operator!=(const Iterator& other) const {
152       return entry_ != other.entry_;
153     }
154     T*& operator*() { return *entry_; }
155     T* operator->() { return *entry_; }
156     Iterator& operator=(T* entry) {
157       T* next = *TLTraits::next(*entry_);
158       *TLTraits::next(entry) = next;
159       *entry_ = entry;
160       return *this;
161     }
162 
Iterator()163     Iterator() : entry_(nullptr) {}
164 
165    private:
Iterator(T ** entry)166     explicit Iterator(T** entry) : entry_(entry) {}
167 
168     T** entry_;
169 
170     friend class ThreadedListBase;
171   };
172 
173   class ConstIterator final {
174    public:
175     using iterator_category = std::forward_iterator_tag;
176     using difference_type = std::ptrdiff_t;
177     using value_type = T*;
178     using reference = const value_type;
179     using pointer = const value_type*;
180 
181    public:
182     ConstIterator& operator++() {
183       entry_ = TLTraits::next(*entry_);
184       return *this;
185     }
186     bool operator==(const ConstIterator& other) const {
187       return entry_ == other.entry_;
188     }
189     bool operator!=(const ConstIterator& other) const {
190       return entry_ != other.entry_;
191     }
192     const T* operator*() const { return *entry_; }
193 
194    private:
ConstIterator(T * const * entry)195     explicit ConstIterator(T* const* entry) : entry_(entry) {}
196 
197     T* const* entry_;
198 
199     friend class ThreadedListBase;
200   };
201 
begin()202   Iterator begin() { return Iterator(TLTraits::start(&head_)); }
end()203   Iterator end() { return Iterator(tail_); }
204 
begin()205   ConstIterator begin() const { return ConstIterator(TLTraits::start(&head_)); }
end()206   ConstIterator end() const { return ConstIterator(tail_); }
207 
208   // Rewinds the list's tail to the reset point, i.e., cutting of the rest of
209   // the list, including the reset_point.
Rewind(Iterator reset_point)210   void Rewind(Iterator reset_point) {
211     tail_ = reset_point.entry_;
212     *tail_ = nullptr;
213   }
214 
215   // Moves the tail of the from_list, starting at the from_location, to the end
216   // of this list.
MoveTail(ThreadedListBase * from_list,Iterator from_location)217   void MoveTail(ThreadedListBase* from_list, Iterator from_location) {
218     if (from_list->end() != from_location) {
219       DCHECK_NULL(*tail_);
220       *tail_ = *from_location;
221       tail_ = from_list->tail_;
222       from_list->Rewind(from_location);
223     }
224   }
225 
is_empty()226   bool is_empty() const { return head_ == nullptr; }
227 
first()228   T* first() const { return head_; }
229 
230   // Slow. For testing purposes.
LengthForTest()231   int LengthForTest() {
232     int result = 0;
233     for (Iterator t = begin(); t != end(); ++t) ++result;
234     return result;
235   }
236 
AtForTest(int i)237   T* AtForTest(int i) {
238     Iterator t = begin();
239     while (i-- > 0) ++t;
240     return *t;
241   }
242 
Verify()243   bool Verify() {
244     T* last = this->first();
245     if (last == nullptr) {
246       CHECK_EQ(&head_, tail_);
247     } else {
248       while (*TLTraits::next(last) != nullptr) {
249         last = *TLTraits::next(last);
250       }
251       CHECK_EQ(TLTraits::next(last), tail_);
252     }
253     return true;
254   }
255 
256  private:
257   T* head_;
258   T** tail_;
259 };
260 
261 struct EmptyBase {};
262 
263 template <typename T, typename TLTraits = ThreadedListTraits<T>>
264 using ThreadedList = ThreadedListBase<T, EmptyBase, TLTraits>;
265 
266 }  // namespace base
267 }  // namespace v8
268 
269 #endif  // V8_BASE_THREADED_LIST_H_
270