• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
is_null()163     bool is_null() { return entry_ == nullptr; }
164 
InsertBefore(T * value)165     void InsertBefore(T* value) {
166       T* old_entry_value = *entry_;
167       *entry_ = value;
168       entry_ = TLTraits::next(value);
169       *entry_ = old_entry_value;
170     }
171 
Iterator()172     Iterator() : entry_(nullptr) {}
173 
174    private:
Iterator(T ** entry)175     explicit Iterator(T** entry) : entry_(entry) {}
176 
177     T** entry_;
178 
179     friend class ThreadedListBase;
180   };
181 
182   class ConstIterator final {
183    public:
184     using iterator_category = std::forward_iterator_tag;
185     using difference_type = std::ptrdiff_t;
186     using value_type = T*;
187     using reference = const value_type;
188     using pointer = const value_type*;
189 
190     // Allow implicit conversion to const iterator.
191     // NOLINTNEXTLINE
ConstIterator(Iterator & iterator)192     ConstIterator(Iterator& iterator) : entry_(iterator.entry_) {}
193 
194    public:
195     ConstIterator& operator++() {
196       entry_ = TLTraits::next(*entry_);
197       return *this;
198     }
199     bool operator==(const ConstIterator& other) const {
200       return entry_ == other.entry_;
201     }
202     bool operator!=(const ConstIterator& other) const {
203       return entry_ != other.entry_;
204     }
205     const T* operator*() const { return *entry_; }
206 
207    private:
ConstIterator(T * const * entry)208     explicit ConstIterator(T* const* entry) : entry_(entry) {}
209 
210     T* const* entry_;
211 
212     friend class ThreadedListBase;
213   };
214 
begin()215   Iterator begin() { return Iterator(TLTraits::start(&head_)); }
end()216   Iterator end() { return Iterator(tail_); }
217 
begin()218   ConstIterator begin() const { return ConstIterator(TLTraits::start(&head_)); }
end()219   ConstIterator end() const { return ConstIterator(tail_); }
220 
221   // Rewinds the list's tail to the reset point, i.e., cutting of the rest of
222   // the list, including the reset_point.
Rewind(Iterator reset_point)223   void Rewind(Iterator reset_point) {
224     tail_ = reset_point.entry_;
225     *tail_ = nullptr;
226   }
227 
228   // Moves the tail of the from_list, starting at the from_location, to the end
229   // of this list.
MoveTail(ThreadedListBase * from_list,Iterator from_location)230   void MoveTail(ThreadedListBase* from_list, Iterator from_location) {
231     if (from_list->end() != from_location) {
232       DCHECK_NULL(*tail_);
233       *tail_ = *from_location;
234       tail_ = from_list->tail_;
235       from_list->Rewind(from_location);
236     }
237   }
238 
is_empty()239   bool is_empty() const { return head_ == nullptr; }
240 
first()241   T* first() const { return head_; }
242 
243   // Slow. For testing purposes.
LengthForTest()244   int LengthForTest() {
245     int result = 0;
246     for (Iterator t = begin(); t != end(); ++t) ++result;
247     return result;
248   }
249 
AtForTest(int i)250   T* AtForTest(int i) {
251     Iterator t = begin();
252     while (i-- > 0) ++t;
253     return *t;
254   }
255 
Verify()256   bool Verify() {
257     T* last = this->first();
258     if (last == nullptr) {
259       CHECK_EQ(&head_, tail_);
260     } else {
261       while (*TLTraits::next(last) != nullptr) {
262         last = *TLTraits::next(last);
263       }
264       CHECK_EQ(TLTraits::next(last), tail_);
265     }
266     return true;
267   }
268 
RevalidateTail()269   void RevalidateTail() {
270     T* last = *tail_;
271     if (last != nullptr) {
272       while (*TLTraits::next(last) != nullptr) {
273         last = *TLTraits::next(last);
274       }
275       tail_ = TLTraits::next(last);
276     }
277     SLOW_DCHECK(Verify());
278   }
279 
280  private:
281   T* head_;
282   T** tail_;
283 };
284 
285 struct EmptyBase {};
286 
287 template <typename T, typename TLTraits = ThreadedListTraits<T>>
288 using ThreadedList = ThreadedListBase<T, EmptyBase, TLTraits>;
289 
290 }  // namespace base
291 }  // namespace v8
292 
293 #endif  // V8_BASE_THREADED_LIST_H_
294