| // Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | #ifndef RUNTIME_VM_INTRUSIVE_DLIST_H_ | 
 | #define RUNTIME_VM_INTRUSIVE_DLIST_H_ | 
 |  | 
 | #include "platform/assert.h" | 
 | #include "platform/globals.h" | 
 |  | 
 | namespace dart { | 
 |  | 
 | // Abstraction for "intrusive" doubly-linked list in a type-safe way in C++. | 
 | // | 
 | // By "intrusive" we mean that a class Item containing various field members | 
 | // has also next/previous pointers to the next/previous Item. | 
 | // | 
 | // To change a class Item to be part of such a doubly-linked list, one only | 
 | // needs to inherit from IntrusiveDListEntry<Item> (in addition to the normal | 
 | // base class). | 
 | // | 
 | // To change a class Item to be part of multiple doubly-linked lists, one can | 
 | // inherit multiple times from IntrusiveDListEntry<Item, N>, each time with a | 
 | // different value for <N>. | 
 | // | 
 | // To insert an object into a list, one uses a IntrusiveDList<Item, N>. It | 
 | // provides support for insertion/iteration/deletion. | 
 | // | 
 | // Usage example: | 
 | // | 
 | //    class Base { | 
 | //      <arbitrary state here> | 
 | //    }; | 
 | // | 
 | //    class Item : public Base, | 
 | //                 public IntrusiveDListEntry<Item>, | 
 | //                 public IntrusiveDListEntry<Item, 2> { | 
 | //      <arbitrary state here> | 
 | //    }; | 
 | // | 
 | //    Item a1, a2, a3; | 
 | // | 
 | //    IntrusiveDList<Item> all; | 
 | //    all.Append(a2); | 
 | //    all.Prepend(a1); | 
 | //    all.Append(a3); | 
 | // | 
 | //    IntrusiveDList<Item, 2> idle, ready; | 
 | //    idle.Append(a1); | 
 | //    ready.Append(a2); | 
 | //    ready.Append(a3); | 
 | // | 
 |  | 
 | template <typename T, int N> | 
 | class IntrusiveDList; | 
 |  | 
 | template <typename T, int N = 1> | 
 | class IntrusiveDListEntry { | 
 |  public: | 
 |   IntrusiveDListEntry() {} | 
 |  | 
 |   ~IntrusiveDListEntry() { | 
 |     // Either this is an unlinked entry or a head/anchor. | 
 |     ASSERT((next_ == nullptr && prev_ == nullptr) || | 
 |            (next_ == this && prev_ == this)); | 
 |   } | 
 |  | 
 |  private: | 
 |   void MakeHead() { | 
 |     ASSERT(next_ == nullptr && prev_ == nullptr); | 
 |     next_ = prev_ = this; | 
 |   } | 
 |  | 
 |   // This uses the C++ compiler's ability to convert between classes inside a | 
 |   // (possibly multi-) inheritance hierarchy. | 
 |   // | 
 |   // The non-typesafe C equivalent of this is: | 
 |   // | 
 |   //     ((uint8*)this) - offsetof(ContainerType, list_entry); | 
 |   // | 
 |   T* container() { return static_cast<T*>(this); } | 
 |  | 
 |   void Append(IntrusiveDListEntry<T, N>* entry) { | 
 |     ASSERT(entry->next_ == nullptr && entry->prev_ == nullptr); | 
 |     entry->next_ = next_; | 
 |     entry->prev_ = this; | 
 |     next_ = entry; | 
 |     entry->next_->prev_ = entry; | 
 |   } | 
 |  | 
 |   void Prepend(IntrusiveDListEntry<T, N>* entry) { | 
 |     ASSERT(entry->next_ == nullptr && entry->prev_ == nullptr); | 
 |     entry->next_ = this; | 
 |     entry->prev_ = prev_; | 
 |     prev_ = entry; | 
 |     entry->prev_->next_ = entry; | 
 |   } | 
 |  | 
 |   void Remove() { | 
 |     ASSERT(prev_->next_ == this); | 
 |     ASSERT(next_->prev_ == this); | 
 |     ASSERT(prev_ != this && next_ != this); | 
 |  | 
 |     prev_->next_ = next_; | 
 |     next_->prev_ = prev_; | 
 |  | 
 |     next_ = nullptr; | 
 |     prev_ = nullptr; | 
 |   } | 
 |  | 
 |   bool IsEmpty() const { | 
 |     bool result = next_ == this; | 
 |     ASSERT(result == (prev_ == this)); | 
 |     return result; | 
 |   } | 
 |  | 
 |   bool IsLinked() const { | 
 |     ASSERT((next_ == nullptr) == (prev_ == nullptr)); | 
 |     return next_ != nullptr; | 
 |   } | 
 |  | 
 |   IntrusiveDListEntry<T, N>* Prev() const { return prev_; } | 
 |  | 
 |   IntrusiveDListEntry<T, N>* Next() const { return next_; } | 
 |  | 
 |   friend class IntrusiveDList<T, N>; | 
 |  | 
 |   IntrusiveDListEntry<T, N>* next_ = nullptr; | 
 |   IntrusiveDListEntry<T, N>* prev_ = nullptr; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(IntrusiveDListEntry); | 
 | }; | 
 |  | 
 | template <typename T, int N = 1> | 
 | class IntrusiveDList { | 
 |  public: | 
 |   typedef IntrusiveDListEntry<T, N> Entry; | 
 |  | 
 |   template <typename ContainerType, int I = 1> | 
 |   class Iterator { | 
 |    public: | 
 |     Iterator(IntrusiveDList<ContainerType, I>* head, | 
 |              IntrusiveDListEntry<ContainerType, I>* entry) | 
 |         : head_(head), entry_(entry) {} | 
 |  | 
 |     inline ContainerType* operator->() const { return entry_->container(); } | 
 |  | 
 |     inline ContainerType* operator*() const { return entry_->container(); } | 
 |  | 
 |     inline bool operator==(const Iterator<ContainerType, I>& other) const { | 
 |       return entry_ == other.entry_; | 
 |     } | 
 |  | 
 |     inline bool operator!=(const Iterator<ContainerType, I>& other) const { | 
 |       return !(*this == other); | 
 |     } | 
 |  | 
 |     inline Iterator<ContainerType, I>& operator++() { | 
 |       entry_ = entry_->Next(); | 
 |       return *this; | 
 |     } | 
 |  | 
 |     inline Iterator<ContainerType, I>& operator--() { | 
 |       entry_ = entry_->Prev(); | 
 |       return *this; | 
 |     } | 
 |  | 
 |    private: | 
 |     friend IntrusiveDList; | 
 |  | 
 |     IntrusiveDList<ContainerType, I>* head_; | 
 |     IntrusiveDListEntry<ContainerType, I>* entry_; | 
 |   }; | 
 |  | 
 |   inline IntrusiveDList() { head_.MakeHead(); } | 
 |  | 
 |   inline void Append(T* a) { head_.Prepend(convert(a)); } | 
 |  | 
 |   inline void Prepend(T* a) { head_.Append(convert(a)); } | 
 |  | 
 |   // NOTE: This function only checks whether [a] is linked inside *a* | 
 |   // [IntrusiveDList]. | 
 |   inline bool IsInList(T* a) const { return convert(a)->IsLinked(); } | 
 |  | 
 |   inline void Remove(T* a) { convert(a)->Remove(); } | 
 |  | 
 |   inline bool IsEmpty() const { return head_.IsEmpty(); } | 
 |  | 
 |   inline T* First() const { | 
 |     ASSERT(!IsEmpty()); | 
 |     return head_.Next()->container(); | 
 |   } | 
 |  | 
 |   inline T* Last() const { | 
 |     ASSERT(!IsEmpty()); | 
 |     return head_.Prev()->container(); | 
 |   } | 
 |  | 
 |   inline T* RemoveFirst() { | 
 |     ASSERT(!IsEmpty()); | 
 |     auto entry = head_.Next(); | 
 |     T* container = entry->container(); | 
 |     entry->Remove(); | 
 |     return container; | 
 |   } | 
 |  | 
 |   inline T* RemoveLast() { | 
 |     ASSERT(!IsEmpty()); | 
 |     auto entry = head_.Prev(); | 
 |     T* container = entry->container(); | 
 |     entry->Remove(); | 
 |     return container; | 
 |   } | 
 |  | 
 |   inline Iterator<T, N> Begin() { return Iterator<T, N>(this, head_.Next()); } | 
 |  | 
 |   inline Iterator<T, N> End() { return Iterator<T, N>(this, &head_); } | 
 |  | 
 |   inline Iterator<T, N> begin() { return Begin(); } | 
 |  | 
 |   inline Iterator<T, N> end() { return End(); } | 
 |  | 
 |   inline Iterator<T, N> Erase(const Iterator<T, N>& iterator) { | 
 |     ASSERT(iterator.head_ == this); | 
 |     Iterator<T, N> next(this, iterator.entry_->Next()); | 
 |     iterator.entry_->Remove(); | 
 |     return next; | 
 |   } | 
 |  | 
 |   bool ContainsForDebugging(const T* a) { | 
 |     for (auto entry : *this) { | 
 |       if (entry == a) return true; | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |   void AppendList(IntrusiveDList<T, N>* other) { | 
 |     if (other->IsEmpty()) return; | 
 |  | 
 |     auto other_first = other->head_.Next(); | 
 |     auto other_last = other->head_.Prev(); | 
 |     other->head_.next_ = &other->head_; | 
 |     other->head_.prev_ = &other->head_; | 
 |  | 
 |     auto prev = head_.prev_; | 
 |  | 
 |     prev->next_ = other_first; | 
 |     other_first->prev_ = prev; | 
 |  | 
 |     other_last->next_ = &head_; | 
 |     head_.prev_ = other_last; | 
 |   } | 
 |  | 
 |  private: | 
 |   Entry head_; | 
 |  | 
 |   Entry* convert(T* entry) const { return static_cast<Entry*>(entry); } | 
 | }; | 
 |  | 
 | }  // namespace dart. | 
 |  | 
 | #endif  // RUNTIME_VM_INTRUSIVE_DLIST_H_ |