// Copyright 2021 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include "common/parent_of_member.h" #include "common/tree.h" namespace Common { namespace impl { class IntrusiveRedBlackTreeImpl; } struct IntrusiveRedBlackTreeNode { private: RB_ENTRY(IntrusiveRedBlackTreeNode) entry{}; friend class impl::IntrusiveRedBlackTreeImpl; template friend class IntrusiveRedBlackTree; public: constexpr IntrusiveRedBlackTreeNode() = default; }; template class IntrusiveRedBlackTree; namespace impl { class IntrusiveRedBlackTreeImpl { private: template friend class ::Common::IntrusiveRedBlackTree; private: RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode); using RootType = IntrusiveRedBlackTreeRoot; private: IntrusiveRedBlackTreeRoot root; public: template class Iterator; using value_type = IntrusiveRedBlackTreeNode; using size_type = size_t; using difference_type = ptrdiff_t; using pointer = value_type*; using const_pointer = const value_type*; using reference = value_type&; using const_reference = const value_type&; using iterator = Iterator; using const_iterator = Iterator; template class Iterator { public: using iterator_category = std::bidirectional_iterator_tag; using value_type = typename IntrusiveRedBlackTreeImpl::value_type; using difference_type = typename IntrusiveRedBlackTreeImpl::difference_type; using pointer = std::conditional_t; using reference = std::conditional_t; private: pointer node; public: explicit Iterator(pointer n) : node(n) {} bool operator==(const Iterator& rhs) const { return this->node == rhs.node; } bool operator!=(const Iterator& rhs) const { return !(*this == rhs); } pointer operator->() const { return this->node; } reference operator*() const { return *this->node; } Iterator& operator++() { this->node = GetNext(this->node); return *this; } Iterator& operator--() { this->node = GetPrev(this->node); return *this; } Iterator operator++(int) { const Iterator it{*this}; ++(*this); return it; } Iterator operator--(int) { const Iterator it{*this}; --(*this); return it; } operator Iterator() const { return Iterator(this->node); } }; protected: // Generate static implementations for non-comparison operations for IntrusiveRedBlackTreeRoot. RB_GENERATE_WITHOUT_COMPARE_STATIC(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode, entry); private: // Define accessors using RB_* functions. constexpr void InitializeImpl() { RB_INIT(&this->root); } bool EmptyImpl() const { return RB_EMPTY(&this->root); } IntrusiveRedBlackTreeNode* GetMinImpl() const { return RB_MIN(IntrusiveRedBlackTreeRoot, const_cast(&this->root)); } IntrusiveRedBlackTreeNode* GetMaxImpl() const { return RB_MAX(IntrusiveRedBlackTreeRoot, const_cast(&this->root)); } IntrusiveRedBlackTreeNode* RemoveImpl(IntrusiveRedBlackTreeNode* node) { return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node); } public: static IntrusiveRedBlackTreeNode* GetNext(IntrusiveRedBlackTreeNode* node) { return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node); } static IntrusiveRedBlackTreeNode* GetPrev(IntrusiveRedBlackTreeNode* node) { return RB_PREV(IntrusiveRedBlackTreeRoot, nullptr, node); } static IntrusiveRedBlackTreeNode const* GetNext(const IntrusiveRedBlackTreeNode* node) { return static_cast( GetNext(const_cast(node))); } static IntrusiveRedBlackTreeNode const* GetPrev(const IntrusiveRedBlackTreeNode* node) { return static_cast( GetPrev(const_cast(node))); } public: constexpr IntrusiveRedBlackTreeImpl() : root() { this->InitializeImpl(); } // Iterator accessors. iterator begin() { return iterator(this->GetMinImpl()); } const_iterator begin() const { return const_iterator(this->GetMinImpl()); } iterator end() { return iterator(static_cast(nullptr)); } const_iterator end() const { return const_iterator(static_cast(nullptr)); } const_iterator cbegin() const { return this->begin(); } const_iterator cend() const { return this->end(); } iterator iterator_to(reference ref) { return iterator(&ref); } const_iterator iterator_to(const_reference ref) const { return const_iterator(&ref); } // Content management. bool empty() const { return this->EmptyImpl(); } reference back() { return *this->GetMaxImpl(); } const_reference back() const { return *this->GetMaxImpl(); } reference front() { return *this->GetMinImpl(); } const_reference front() const { return *this->GetMinImpl(); } iterator erase(iterator it) { auto cur = std::addressof(*it); auto next = GetNext(cur); this->RemoveImpl(cur); return iterator(next); } }; } // namespace impl template concept HasLightCompareType = requires { { std::is_same::value } ->std::convertible_to; }; namespace impl { template consteval auto* GetLightCompareType() { if constexpr (HasLightCompareType) { return static_cast(nullptr); } else { return static_cast(nullptr); } } } // namespace impl template using LightCompareType = std::remove_pointer_t())>; template class IntrusiveRedBlackTree { public: using ImplType = impl::IntrusiveRedBlackTreeImpl; private: ImplType impl{}; public: struct IntrusiveRedBlackTreeRootWithCompare : ImplType::IntrusiveRedBlackTreeRoot {}; template class Iterator; using value_type = T; using size_type = size_t; using difference_type = ptrdiff_t; using pointer = T*; using const_pointer = const T*; using reference = T&; using const_reference = const T&; using iterator = Iterator; using const_iterator = Iterator; using light_value_type = LightCompareType; using const_light_pointer = const light_value_type*; using const_light_reference = const light_value_type&; template class Iterator { public: friend class IntrusiveRedBlackTree; using ImplIterator = std::conditional_t; using iterator_category = std::bidirectional_iterator_tag; using value_type = typename IntrusiveRedBlackTree::value_type; using difference_type = typename IntrusiveRedBlackTree::difference_type; using pointer = std::conditional_t; using reference = std::conditional_t; private: ImplIterator iterator; private: explicit Iterator(ImplIterator it) : iterator(it) {} explicit Iterator(typename std::conditional::type::pointer ptr) : iterator(ptr) {} ImplIterator GetImplIterator() const { return this->iterator; } public: bool operator==(const Iterator& rhs) const { return this->iterator == rhs.iterator; } bool operator!=(const Iterator& rhs) const { return !(*this == rhs); } pointer operator->() const { return Traits::GetParent(std::addressof(*this->iterator)); } reference operator*() const { return *Traits::GetParent(std::addressof(*this->iterator)); } Iterator& operator++() { ++this->iterator; return *this; } Iterator& operator--() { --this->iterator; return *this; } Iterator operator++(int) { const Iterator it{*this}; ++this->iterator; return it; } Iterator operator--(int) { const Iterator it{*this}; --this->iterator; return it; } operator Iterator() const { return Iterator(this->iterator); } }; private: // Generate static implementations for comparison operations for IntrusiveRedBlackTreeRoot. RB_GENERATE_WITH_COMPARE_STATIC(IntrusiveRedBlackTreeRootWithCompare, IntrusiveRedBlackTreeNode, entry, CompareImpl, LightCompareImpl); private: static int CompareImpl(const IntrusiveRedBlackTreeNode* lhs, const IntrusiveRedBlackTreeNode* rhs) { return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs)); } static int LightCompareImpl(const void* elm, const IntrusiveRedBlackTreeNode* rhs) { return Comparator::Compare(*static_cast(elm), *Traits::GetParent(rhs)); } // Define accessors using RB_* functions. IntrusiveRedBlackTreeNode* InsertImpl(IntrusiveRedBlackTreeNode* node) { return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare, static_cast(&this->impl.root), node); } IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const { return RB_FIND( IntrusiveRedBlackTreeRootWithCompare, const_cast( static_cast(&this->impl.root)), const_cast(node)); } IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const { return RB_NFIND( IntrusiveRedBlackTreeRootWithCompare, const_cast( static_cast(&this->impl.root)), const_cast(node)); } IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const { return RB_FIND_LIGHT( IntrusiveRedBlackTreeRootWithCompare, const_cast( static_cast(&this->impl.root)), static_cast(lelm)); } IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const { return RB_NFIND_LIGHT( IntrusiveRedBlackTreeRootWithCompare, const_cast( static_cast(&this->impl.root)), static_cast(lelm)); } public: constexpr IntrusiveRedBlackTree() = default; // Iterator accessors. iterator begin() { return iterator(this->impl.begin()); } const_iterator begin() const { return const_iterator(this->impl.begin()); } iterator end() { return iterator(this->impl.end()); } const_iterator end() const { return const_iterator(this->impl.end()); } const_iterator cbegin() const { return this->begin(); } const_iterator cend() const { return this->end(); } iterator iterator_to(reference ref) { return iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); } const_iterator iterator_to(const_reference ref) const { return const_iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); } // Content management. bool empty() const { return this->impl.empty(); } reference back() { return *Traits::GetParent(std::addressof(this->impl.back())); } const_reference back() const { return *Traits::GetParent(std::addressof(this->impl.back())); } reference front() { return *Traits::GetParent(std::addressof(this->impl.front())); } const_reference front() const { return *Traits::GetParent(std::addressof(this->impl.front())); } iterator erase(iterator it) { return iterator(this->impl.erase(it.GetImplIterator())); } iterator insert(reference ref) { ImplType::pointer node = Traits::GetNode(std::addressof(ref)); this->InsertImpl(node); return iterator(node); } iterator find(const_reference ref) const { return iterator(this->FindImpl(Traits::GetNode(std::addressof(ref)))); } iterator nfind(const_reference ref) const { return iterator(this->NFindImpl(Traits::GetNode(std::addressof(ref)))); } iterator find_light(const_light_reference ref) const { return iterator(this->FindLightImpl(std::addressof(ref))); } iterator nfind_light(const_light_reference ref) const { return iterator(this->NFindLightImpl(std::addressof(ref))); } }; template > class IntrusiveRedBlackTreeMemberTraits; template class IntrusiveRedBlackTreeMemberTraits { public: template using TreeType = IntrusiveRedBlackTree; using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl; private: template friend class IntrusiveRedBlackTree; friend class impl::IntrusiveRedBlackTreeImpl; static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) { return std::addressof(parent->*Member); } static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) { return std::addressof(parent->*Member); } static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) { return GetParentPointer(node); } static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) { return GetParentPointer(node); } private: static constexpr TYPED_STORAGE(Derived) DerivedStorage = {}; static_assert(GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage)); }; template > class IntrusiveRedBlackTreeMemberTraitsDeferredAssert; template class IntrusiveRedBlackTreeMemberTraitsDeferredAssert { public: template using TreeType = IntrusiveRedBlackTree; using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl; static constexpr bool IsValid() { TYPED_STORAGE(Derived) DerivedStorage = {}; return GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage); } private: template friend class IntrusiveRedBlackTree; friend class impl::IntrusiveRedBlackTreeImpl; static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) { return std::addressof(parent->*Member); } static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) { return std::addressof(parent->*Member); } static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) { return GetParentPointer(node); } static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) { return GetParentPointer(node); } }; template class IntrusiveRedBlackTreeBaseNode : public IntrusiveRedBlackTreeNode { public: constexpr Derived* GetPrev() { return static_cast(impl::IntrusiveRedBlackTreeImpl::GetPrev(this)); } constexpr const Derived* GetPrev() const { return static_cast(impl::IntrusiveRedBlackTreeImpl::GetPrev(this)); } constexpr Derived* GetNext() { return static_cast(impl::IntrusiveRedBlackTreeImpl::GetNext(this)); } constexpr const Derived* GetNext() const { return static_cast(impl::IntrusiveRedBlackTreeImpl::GetNext(this)); } }; template class IntrusiveRedBlackTreeBaseTraits { public: template using TreeType = IntrusiveRedBlackTree; using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl; private: template friend class IntrusiveRedBlackTree; friend class impl::IntrusiveRedBlackTreeImpl; static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) { return static_cast(parent); } static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) { return static_cast(parent); } static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) { return static_cast(node); } static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) { return static_cast(node); } }; } // namespace Common