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