/* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * This software may be used and distributed according to the terms of the GNU * General Public License version 2 or any later version. */ #pragma once #include #include #include "common/assert.h" #include "common/common_types.h" namespace Dynarmic { namespace Common { template class IntrusiveListNode; template class IntrusiveList; template class IntrusiveListIterator; template class IntrusiveListConstIterator; template class IntrusiveListNode { public: void UnlinkFromList() { prev->next = next; next->prev = prev; #if !defined(NDEBUG) next = prev = nullptr; #endif } private: friend class IntrusiveList; friend class IntrusiveListIterator; friend class IntrusiveListConstIterator; IntrusiveListNode* next = this; IntrusiveListNode* prev = this; }; template class IntrusiveList { public: /** * Add an entry to the start of the list. * @param node Node to add to the list. */ void Prepend(T& node) { AddAfter(root.get(), static_cast*>(&node)); } /** * Add an entry to the end of the list * @param node Node to add to the list. */ void Append(T& node) { AddBefore(root.get(), static_cast*>(&node)); } /** * Add an entry after an existing node in this list * @param existing_node Node to add new_node after. Must already be member of the list. * @param new_node Node to add to the list. */ void AddAfter(T& existing, T& node) { AddAfter(static_cast*>(&existing), static_cast*>(&node)); } /** * Add an entry before an existing node in this list * @param existing_node Node to add new_node before. Must already be member of the list. * @param new_node Node to add to the list. */ void AddBefore(T& existing, T& node) { AddBefore(static_cast*>(&existing), static_cast*>(&node)); } /** * Removes node from list * @param node Node to remove from list. */ void Remove(T& node) { node.UnlinkFromList(); } /** * Is this list empty? * @returns true if there are no nodes in this list. */ bool IsEmpty() { return root->next == root.get(); } IntrusiveListIterator begin(); IntrusiveListIterator end(); IntrusiveListIterator erase(const IntrusiveListIterator&); IntrusiveListIterator iterator_to(T&); IntrusiveListConstIterator begin() const; IntrusiveListConstIterator end() const; IntrusiveListConstIterator iterator_to(T&) const; private: friend class IntrusiveListIterator; friend class IntrusiveListConstIterator; void AddAfter(IntrusiveListNode* existing_node, IntrusiveListNode* new_node) { new_node->next = existing_node->next; new_node->prev = existing_node; existing_node->next->prev = new_node; existing_node->next = new_node; } void AddBefore(IntrusiveListNode* existing_node, IntrusiveListNode* new_node) { new_node->next = existing_node; new_node->prev = existing_node->prev; existing_node->prev->next = new_node; existing_node->prev = new_node; } std::shared_ptr> root = std::make_shared>(); }; template class IntrusiveListIterator { public: IntrusiveListIterator() = default; IntrusiveListIterator(const IntrusiveListIterator& other) = default; IntrusiveListIterator& operator=(const IntrusiveListIterator& other) = default; IntrusiveListIterator(IntrusiveList* list, IntrusiveListNode* node) : root(list->root.get()), node(node) { } IntrusiveListIterator& operator++() { node = node == root ? node : node->next; return *this; } IntrusiveListIterator operator++(int) { IntrusiveListIterator it(*this); node = node == root ? node : node->next; return it; } IntrusiveListIterator& operator--() { node = node->prev == root ? node : node->prev; return *this; } IntrusiveListIterator operator--(int) { IntrusiveListIterator it(*this); node = node->prev == root ? node : node->prev; return it; } bool operator==(const IntrusiveListIterator& other) const { DEBUG_ASSERT(root == other.root); return node == other.node; } bool operator!=(const IntrusiveListIterator& other) const { return !(*this == other); } const T& operator*() const { DEBUG_ASSERT(node != root); return *reinterpret_cast(node); } T& operator*() { DEBUG_ASSERT(node != root); return *reinterpret_cast(node); } T* operator->() { DEBUG_ASSERT(node != root); return reinterpret_cast(node); } const T* operator->() const { DEBUG_ASSERT(node != root); return reinterpret_cast(node); } private: friend class IntrusiveList; IntrusiveListNode* root = nullptr; IntrusiveListNode* node = nullptr; }; template class IntrusiveListConstIterator { public: IntrusiveListConstIterator() = default; IntrusiveListConstIterator(const IntrusiveListConstIterator& other) = default; IntrusiveListConstIterator& operator=(const IntrusiveListConstIterator& other) = default; IntrusiveListConstIterator(const IntrusiveList* list, IntrusiveListNode* node) : root(list->root.get()), node(node) { } IntrusiveListConstIterator& operator++() { node = node == root ? node : node->next; return *this; } IntrusiveListConstIterator operator++(int) { IntrusiveListConstIterator it(*this); node = node == root ? node : node->next; return it; } IntrusiveListConstIterator& operator--() { node = node->prev == root ? node : node->prev; return *this; } IntrusiveListConstIterator operator--(int) { IntrusiveListConstIterator it(*this); node = node->prev == root ? node : node->prev; return it; } bool operator==(const IntrusiveListConstIterator& other) const { DEBUG_ASSERT(root == other.root); return node == other.node; } bool operator!=(const IntrusiveListConstIterator& other) const { return !(*this == other); } const T& operator*() const { DEBUG_ASSERT(node != root); return *reinterpret_cast(node); } const T* operator->() const { DEBUG_ASSERT(node != root); return reinterpret_cast(node); } private: friend class IntrusiveList; IntrusiveListNode* root = nullptr; IntrusiveListNode* node = nullptr; }; template IntrusiveListIterator IntrusiveList::begin() { return IntrusiveListIterator(this, root->next); } template IntrusiveListIterator IntrusiveList::end() { return IntrusiveListIterator(this, root.get()); } template IntrusiveListIterator IntrusiveList::erase(const IntrusiveListIterator& it) { DEBUG_ASSERT(it.root == root.get() && it.node != it.root); IntrusiveListNode* to_remove = it.node; IntrusiveListIterator ret = it; ++ret; to_remove->UnlinkFromList(); return ret; } template IntrusiveListIterator IntrusiveList::iterator_to(T& item) { return IntrusiveListIterator(this, static_cast*>(&item)); } template IntrusiveListConstIterator IntrusiveList::begin() const { return IntrusiveListConstIterator(this, root->next); } template IntrusiveListConstIterator IntrusiveList::end() const { return IntrusiveListConstIterator(this, root.get()); } template IntrusiveListConstIterator IntrusiveList::iterator_to(T& item) const { return IntrusiveListConstIterator(this, static_cast*>(&item)); } } // namespace Common } // namespace Dynarmic