/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef jit_InlineList_h #define jit_InlineList_h #include "mozilla/Assertions.h" namespace js { template class InlineForwardList; template class InlineForwardListIterator; template class InlineForwardListNode { public: InlineForwardListNode() : next(nullptr) {} explicit InlineForwardListNode(InlineForwardListNode* n) : next(n) {} InlineForwardListNode(const InlineForwardListNode&) = delete; protected: friend class InlineForwardList; friend class InlineForwardListIterator; InlineForwardListNode* next; }; template class InlineForwardList : protected InlineForwardListNode { friend class InlineForwardListIterator; using Node = InlineForwardListNode; Node* tail_; #ifdef DEBUG int modifyCount_; #endif InlineForwardList* thisFromConstructor() { return this; } public: InlineForwardList() : tail_(thisFromConstructor()) { #ifdef DEBUG modifyCount_ = 0; #endif } public: using iterator = InlineForwardListIterator; public: iterator begin() const { return iterator(this); } iterator begin(Node* item) const { return iterator(this, item); } iterator end() const { return iterator(nullptr); } void removeAt(iterator where) { removeAfter(where.prev, where.iter); } void pushFront(Node* t) { insertAfter(this, t); } void pushBack(Node* t) { MOZ_ASSERT(t->next == nullptr); #ifdef DEBUG modifyCount_++; #endif tail_->next = t; tail_ = t; } T* popFront() { MOZ_ASSERT(!empty()); T* result = static_cast(this->next); removeAfter(this, result); return result; } T* back() const { MOZ_ASSERT(!empty()); return static_cast(tail_); } void insertAfter(Node* at, Node* item) { MOZ_ASSERT(item->next == nullptr); #ifdef DEBUG modifyCount_++; #endif if (at == tail_) { tail_ = item; } item->next = at->next; at->next = item; } void removeAfter(Node* at, Node* item) { #ifdef DEBUG modifyCount_++; #endif if (item == tail_) { tail_ = at; } MOZ_ASSERT(at->next == item); at->next = item->next; item->next = nullptr; } void removeAndIncrement(iterator& where) { // Do not change modifyCount_ here. The iterator can still be used // after calling this method, unlike the other methods that modify // the list. Node* item = where.iter; where.iter = item->next; if (item == tail_) { tail_ = where.prev; } MOZ_ASSERT(where.prev->next == item); where.prev->next = where.iter; item->next = nullptr; } void splitAfter(Node* at, InlineForwardList* to) { MOZ_ASSERT(to->empty()); if (!at) { at = this; } if (at == tail_) { return; } #ifdef DEBUG modifyCount_++; #endif to->next = at->next; to->tail_ = tail_; tail_ = at; at->next = nullptr; } bool empty() const { return tail_ == this; } void clear() { this->next = nullptr; tail_ = this; #ifdef DEBUG modifyCount_ = 0; #endif } }; template class InlineForwardListIterator { private: friend class InlineForwardList; using Node = InlineForwardListNode; explicit InlineForwardListIterator(const InlineForwardList* owner) : prev(const_cast(static_cast(owner))), iter(owner ? owner->next : nullptr) #ifdef DEBUG , owner_(owner), modifyCount_(owner ? owner->modifyCount_ : 0) #endif { } InlineForwardListIterator(const InlineForwardList* owner, Node* node) : prev(nullptr), iter(node) #ifdef DEBUG , owner_(owner), modifyCount_(owner ? owner->modifyCount_ : 0) #endif { } public: InlineForwardListIterator& operator++() { MOZ_ASSERT(modifyCount_ == owner_->modifyCount_); prev = iter; iter = iter->next; return *this; } InlineForwardListIterator operator++(int) { InlineForwardListIterator old(*this); operator++(); return old; } T* operator*() const { MOZ_ASSERT(modifyCount_ == owner_->modifyCount_); return static_cast(iter); } T* operator->() const { MOZ_ASSERT(modifyCount_ == owner_->modifyCount_); return static_cast(iter); } bool operator!=(const InlineForwardListIterator& where) const { return iter != where.iter; } bool operator==(const InlineForwardListIterator& where) const { return iter == where.iter; } explicit operator bool() const { return iter != nullptr; } private: Node* prev; Node* iter; #ifdef DEBUG const InlineForwardList* owner_; int modifyCount_; #endif }; template class InlineList; template class InlineListIterator; template class InlineListReverseIterator; template class InlineListNode : public InlineForwardListNode { public: InlineListNode() : InlineForwardListNode(nullptr), prev(nullptr) {} InlineListNode(InlineListNode* n, InlineListNode* p) : InlineForwardListNode(n), prev(p) {} // Move constructor. Nodes may be moved without being removed from their // containing lists. For example, this allows list nodes to be safely // stored in a resizable Vector -- when the Vector resizes, the new storage // is initialized by this move constructor. |other| is a reference to the // old node which the |this| node here is replacing. InlineListNode(InlineListNode&& other) : InlineForwardListNode(other.next) { InlineListNode* newNext = static_cast*>(other.next); InlineListNode* newPrev = other.prev; prev = newPrev; // Update the pointers in the adjacent nodes to point to this node's new // location. newNext->prev = this; newPrev->next = this; } InlineListNode(const InlineListNode&) = delete; void operator=(const InlineListNode&) = delete; bool isInList() { return prev != nullptr && this->next != nullptr; } protected: friend class InlineList; friend class InlineListIterator; friend class InlineListReverseIterator; InlineListNode* prev; }; template class InlineList : protected InlineListNode { using Node = InlineListNode; public: InlineList() : InlineListNode(this, this) {} public: using iterator = InlineListIterator; using reverse_iterator = InlineListReverseIterator; public: iterator begin() const { return iterator(static_cast(this->next)); } iterator begin(Node* t) const { return iterator(t); } iterator end() const { return iterator(this); } reverse_iterator rbegin() const { return reverse_iterator(this->prev); } reverse_iterator rbegin(Node* t) const { return reverse_iterator(t); } reverse_iterator rend() const { return reverse_iterator(this); } void pushFront(Node* t) { insertAfter(this, t); } void pushFrontUnchecked(Node* t) { insertAfterUnchecked(this, t); } void pushBack(Node* t) { insertBefore(this, t); } void pushBackUnchecked(Node* t) { insertBeforeUnchecked(this, t); } T* popFront() { MOZ_ASSERT(!empty()); T* t = static_cast(this->next); remove(t); return t; } T* popBack() { MOZ_ASSERT(!empty()); T* t = static_cast(this->prev); remove(t); return t; } T* peekBack() const { iterator iter = end(); iter--; return *iter; } void insertBefore(Node* at, Node* item) { MOZ_ASSERT(item->prev == nullptr); MOZ_ASSERT(item->next == nullptr); insertBeforeUnchecked(at, item); } void insertBeforeUnchecked(Node* at, Node* item) { Node* atPrev = at->prev; item->next = at; item->prev = atPrev; atPrev->next = item; at->prev = item; } void insertAfter(Node* at, Node* item) { MOZ_ASSERT(item->prev == nullptr); MOZ_ASSERT(item->next == nullptr); insertAfterUnchecked(at, item); } void insertAfterUnchecked(Node* at, Node* item) { Node* atNext = static_cast(at->next); item->next = atNext; item->prev = at; atNext->prev = item; at->next = item; } void remove(Node* t) { Node* tNext = static_cast(t->next); Node* tPrev = t->prev; tPrev->next = tNext; tNext->prev = tPrev; t->next = nullptr; t->prev = nullptr; } // Remove |old| from the list and insert |now| in its place. void replace(Node* old, Node* now) { MOZ_ASSERT(now->next == nullptr && now->prev == nullptr); Node* listNext = static_cast(old->next); Node* listPrev = old->prev; listPrev->next = now; listNext->prev = now; now->next = listNext; now->prev = listPrev; old->next = nullptr; old->prev = nullptr; } void clear() { this->next = this->prev = this; } bool empty() const { return begin() == end(); } void takeElements(InlineList& l) { MOZ_ASSERT(&l != this, "cannot takeElements from this"); Node* lprev = l.prev; static_cast(l.next)->prev = this; lprev->next = this->next; static_cast(this->next)->prev = l.prev; this->next = l.next; l.clear(); } }; template class InlineListIterator { private: friend class InlineList; using Node = InlineListNode; explicit InlineListIterator(const Node* iter) : iter(const_cast(iter)) {} public: InlineListIterator& operator++() { iter = static_cast(iter->next); return *this; } InlineListIterator operator++(int) { InlineListIterator old(*this); operator++(); return old; } InlineListIterator& operator--() { iter = iter->prev; return *this; } InlineListIterator operator--(int) { InlineListIterator old(*this); operator--(); return old; } T* operator*() const { return static_cast(iter); } T* operator->() const { return static_cast(iter); } bool operator!=(const InlineListIterator& where) const { return iter != where.iter; } bool operator==(const InlineListIterator& where) const { return iter == where.iter; } private: Node* iter; }; template class InlineListReverseIterator { private: friend class InlineList; using Node = InlineListNode; explicit InlineListReverseIterator(const Node* iter) : iter(const_cast(iter)) {} public: InlineListReverseIterator& operator++() { iter = iter->prev; return *this; } InlineListReverseIterator operator++(int) { InlineListReverseIterator old(*this); operator++(); return old; } InlineListReverseIterator& operator--() { iter = static_cast(iter->next); return *this; } InlineListReverseIterator operator--(int) { InlineListReverseIterator old(*this); operator--(); return old; } T* operator*() { return static_cast(iter); } T* operator->() { return static_cast(iter); } bool operator!=(const InlineListReverseIterator& where) const { return iter != where.iter; } bool operator==(const InlineListReverseIterator& where) const { return iter == where.iter; } private: Node* iter; }; // This list type is more or less exactly an InlineForwardList without a // sentinel node. It is useful in cases where you are doing algorithms that deal // with many merging singleton lists, rather than often empty ones. template class InlineConcatListIterator; template class InlineConcatList { private: using Node = InlineConcatList; InlineConcatList* thisFromConstructor() { return this; } public: InlineConcatList() : next(nullptr), tail(thisFromConstructor()) {} using iterator = InlineConcatListIterator; iterator begin() const { return iterator(this); } iterator end() const { return iterator(nullptr); } void append(InlineConcatList* adding) { MOZ_ASSERT(tail); MOZ_ASSERT(!tail->next); MOZ_ASSERT(adding->tail); MOZ_ASSERT(!adding->tail->next); tail->next = adding; tail = adding->tail; adding->tail = nullptr; } protected: friend class InlineConcatListIterator; Node* next; Node* tail; }; template class InlineConcatListIterator { private: friend class InlineConcatList; using Node = InlineConcatList; explicit InlineConcatListIterator(const Node* iter) : iter(const_cast(iter)) {} public: InlineConcatListIterator& operator++() { iter = static_cast(iter->next); return *this; } InlineConcatListIterator operator++(int) { InlineConcatListIterator old(*this); operator++(); return old; } T* operator*() const { return static_cast(iter); } T* operator->() const { return static_cast(iter); } bool operator!=(const InlineConcatListIterator& where) const { return iter != where.iter; } bool operator==(const InlineConcatListIterator& where) const { return iter == where.iter; } private: Node* iter; }; template class InlineSpaghettiStack; template class InlineSpaghettiStackNode; template class InlineSpaghettiStackIterator; template class InlineSpaghettiStackNode : public InlineForwardListNode { using Parent = InlineForwardListNode; public: InlineSpaghettiStackNode() : Parent() {} explicit InlineSpaghettiStackNode(InlineSpaghettiStackNode* n) : Parent(n) {} InlineSpaghettiStackNode(const InlineSpaghettiStackNode&) = delete; protected: friend class InlineSpaghettiStack; friend class InlineSpaghettiStackIterator; }; template class InlineSpaghettiStack : protected InlineSpaghettiStackNode { friend class InlineSpaghettiStackIterator; using Node = InlineSpaghettiStackNode; public: InlineSpaghettiStack() = default; public: using iterator = InlineSpaghettiStackIterator; public: iterator begin() const { return iterator(this); } iterator end() const { return iterator(nullptr); } void push(Node* t) { MOZ_ASSERT(t->next == nullptr); t->next = this->next; this->next = t; } void copy(const InlineSpaghettiStack& stack) { this->next = stack.next; } bool empty() const { return this->next == nullptr; } }; template class InlineSpaghettiStackIterator { private: friend class InlineSpaghettiStack; using Node = InlineSpaghettiStackNode; explicit InlineSpaghettiStackIterator(const InlineSpaghettiStack* owner) : iter(owner ? static_cast(owner->next) : nullptr) {} public: InlineSpaghettiStackIterator& operator++() { iter = static_cast(iter->next); return *this; } InlineSpaghettiStackIterator operator++(int) { InlineSpaghettiStackIterator old(*this); operator++(); return old; } T* operator*() const { return static_cast(iter); } T* operator->() const { return static_cast(iter); } bool operator!=(const InlineSpaghettiStackIterator& where) const { return iter != where.iter; } bool operator==(const InlineSpaghettiStackIterator& where) const { return iter == where.iter; } private: Node* iter; }; } // namespace js #endif /* jit_InlineList_h */