// 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 { public: using EntryType = RBEntry; constexpr IntrusiveRedBlackTreeNode() = default; void SetEntry(const EntryType& new_entry) { entry = new_entry; } [[nodiscard]] EntryType& GetEntry() { return entry; } [[nodiscard]] const EntryType& GetEntry() const { return entry; } private: EntryType entry{}; friend class impl::IntrusiveRedBlackTreeImpl; template friend class IntrusiveRedBlackTree; }; template class IntrusiveRedBlackTree; namespace impl { class IntrusiveRedBlackTreeImpl { private: template friend class ::Common::IntrusiveRedBlackTree; using RootType = RBHead; RootType 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); } }; private: // Define accessors using RB_* functions. bool EmptyImpl() const { return root.IsEmpty(); } IntrusiveRedBlackTreeNode* GetMinImpl() const { return RB_MIN(const_cast(&root)); } IntrusiveRedBlackTreeNode* GetMaxImpl() const { return RB_MAX(const_cast(&root)); } IntrusiveRedBlackTreeNode* RemoveImpl(IntrusiveRedBlackTreeNode* node) { return RB_REMOVE(&root, node); } public: static IntrusiveRedBlackTreeNode* GetNext(IntrusiveRedBlackTreeNode* node) { return RB_NEXT(node); } static IntrusiveRedBlackTreeNode* GetPrev(IntrusiveRedBlackTreeNode* node) { return RB_PREV(node); } static const IntrusiveRedBlackTreeNode* GetNext(const IntrusiveRedBlackTreeNode* node) { return static_cast( GetNext(const_cast(node))); } static const IntrusiveRedBlackTreeNode* GetPrev(const IntrusiveRedBlackTreeNode* node) { return static_cast( GetPrev(const_cast(node))); } public: constexpr IntrusiveRedBlackTreeImpl() {} // 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: 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: 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(&impl.root, node, CompareImpl); } IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const { return RB_FIND(const_cast(&impl.root), const_cast(node), CompareImpl); } IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const { return RB_NFIND(const_cast(&impl.root), const_cast(node), CompareImpl); } IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const { return RB_FIND_LIGHT(const_cast(&impl.root), static_cast(lelm), LightCompareImpl); } IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const { return RB_NFIND_LIGHT(const_cast(&impl.root), static_cast(lelm), LightCompareImpl); } 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 TypedStorage DerivedStorage = {}; #ifndef _MSC_VER // TODO(bunnei): Enable on MSVC once this can be const evaluated by the compiler static_assert(GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage)); #endif }; template > class IntrusiveRedBlackTreeMemberTraitsDeferredAssert; template class IntrusiveRedBlackTreeMemberTraitsDeferredAssert { public: template using TreeType = IntrusiveRedBlackTree; using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl; static constexpr bool IsValid() { TypedStorage 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