/* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include #include #include namespace ams::util { AMS_PRAGMA_BEGIN_OPTIMIZE("-O3") namespace impl { class IntrusiveRedBlackTreeImpl; } #pragma pack(push, 4) struct IntrusiveRedBlackTreeNode { NON_COPYABLE(IntrusiveRedBlackTreeNode); public: using RBEntry = freebsd::RBEntry; private: RBEntry m_entry; public: constexpr explicit ALWAYS_INLINE IntrusiveRedBlackTreeNode(util::ConstantInitializeTag) : m_entry(util::ConstantInitialize) { /* ... */ } explicit ALWAYS_INLINE IntrusiveRedBlackTreeNode() { /* ... */ } [[nodiscard]] constexpr ALWAYS_INLINE RBEntry &GetRBEntry() { return m_entry; } [[nodiscard]] constexpr ALWAYS_INLINE const RBEntry &GetRBEntry() const { return m_entry; } constexpr ALWAYS_INLINE void SetRBEntry(const RBEntry &entry) { m_entry = entry; } }; static_assert(sizeof(IntrusiveRedBlackTreeNode) == 3 * sizeof(void *) + std::max(sizeof(freebsd::RBColor), 4)); #pragma pack(pop) template class IntrusiveRedBlackTree; namespace impl { class IntrusiveRedBlackTreeImpl { NON_COPYABLE(IntrusiveRedBlackTreeImpl); private: template friend class ::ams::util::IntrusiveRedBlackTree; private: using RootType = freebsd::RBHead; private: RootType m_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 = typename std::conditional::type; using reference = typename std::conditional::type; private: pointer m_node; public: constexpr explicit ALWAYS_INLINE Iterator(pointer n) : m_node(n) { /* ... */ } constexpr ALWAYS_INLINE bool operator==(const Iterator &rhs) const { return m_node == rhs.m_node; } constexpr ALWAYS_INLINE pointer operator->() const { return m_node; } constexpr ALWAYS_INLINE reference operator*() const { return *m_node; } constexpr ALWAYS_INLINE Iterator &operator++() { m_node = GetNext(m_node); return *this; } constexpr ALWAYS_INLINE Iterator &operator--() { m_node = GetPrev(m_node); return *this; } constexpr ALWAYS_INLINE Iterator operator++(int) { const Iterator it{*this}; ++(*this); return it; } constexpr ALWAYS_INLINE Iterator operator--(int) { const Iterator it{*this}; --(*this); return it; } constexpr ALWAYS_INLINE operator Iterator() const { return Iterator(m_node); } }; private: constexpr ALWAYS_INLINE bool EmptyImpl() const { return m_root.IsEmpty(); } constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetMinImpl() const { return freebsd::RB_MIN(const_cast(m_root)); } constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetMaxImpl() const { return freebsd::RB_MAX(const_cast(m_root)); } constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *RemoveImpl(IntrusiveRedBlackTreeNode *node) { return freebsd::RB_REMOVE(m_root, node); } public: static constexpr IntrusiveRedBlackTreeNode *GetNext(IntrusiveRedBlackTreeNode *node) { return freebsd::RB_NEXT(node); } static constexpr IntrusiveRedBlackTreeNode *GetPrev(IntrusiveRedBlackTreeNode *node) { return freebsd::RB_PREV(node); } static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNext(IntrusiveRedBlackTreeNode const *node) { return static_cast(GetNext(const_cast(node))); } static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetPrev(IntrusiveRedBlackTreeNode const *node) { return static_cast(GetPrev(const_cast(node))); } public: constexpr ALWAYS_INLINE IntrusiveRedBlackTreeImpl() = default; /* Iterator accessors. */ constexpr ALWAYS_INLINE iterator begin() { return iterator(this->GetMinImpl()); } constexpr ALWAYS_INLINE const_iterator begin() const { return const_iterator(this->GetMinImpl()); } constexpr ALWAYS_INLINE iterator end() { return iterator(static_cast(nullptr)); } constexpr ALWAYS_INLINE const_iterator end() const { return const_iterator(static_cast(nullptr)); } constexpr ALWAYS_INLINE const_iterator cbegin() const { return this->begin(); } constexpr ALWAYS_INLINE const_iterator cend() const { return this->end(); } constexpr ALWAYS_INLINE iterator iterator_to(reference ref) { return iterator(std::addressof(ref)); } constexpr ALWAYS_INLINE const_iterator iterator_to(const_reference ref) const { return const_iterator(std::addressof(ref)); } /* Content management. */ constexpr ALWAYS_INLINE bool empty() const { return this->EmptyImpl(); } constexpr ALWAYS_INLINE reference back() { return *this->GetMaxImpl(); } constexpr ALWAYS_INLINE const_reference back() const { return *this->GetMaxImpl(); } constexpr ALWAYS_INLINE reference front() { return *this->GetMinImpl(); } constexpr ALWAYS_INLINE const_reference front() const { return *this->GetMinImpl(); } constexpr ALWAYS_INLINE iterator erase(iterator it) { auto cur = std::addressof(*it); auto next = GetNext(cur); this->RemoveImpl(cur); return iterator(next); } }; } template concept HasRedBlackKeyType = requires { { std::is_same::value } -> std::convertible_to; }; namespace impl { template consteval auto *GetRedBlackKeyType() { if constexpr (HasRedBlackKeyType) { return static_cast(nullptr); } else { return static_cast(nullptr); } } } template using RedBlackKeyType = typename std::remove_pointer())>::type; template class IntrusiveRedBlackTree { NON_COPYABLE(IntrusiveRedBlackTree); public: using ImplType = impl::IntrusiveRedBlackTreeImpl; private: ImplType m_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 key_type = RedBlackKeyType; using const_key_pointer = const key_type *; using const_key_reference = const key_type &; template class Iterator { public: friend class IntrusiveRedBlackTree; using ImplIterator = typename std::conditional::type; using iterator_category = std::bidirectional_iterator_tag; using value_type = typename IntrusiveRedBlackTree::value_type; using difference_type = typename IntrusiveRedBlackTree::difference_type; using pointer = typename std::conditional::type; using reference = typename std::conditional::type; private: ImplIterator m_impl; private: constexpr explicit ALWAYS_INLINE Iterator(ImplIterator it) : m_impl(it) { /* ... */ } constexpr explicit ALWAYS_INLINE Iterator(typename ImplIterator::pointer p) : m_impl(p) { /* ... */ } constexpr ALWAYS_INLINE ImplIterator GetImplIterator() const { return m_impl; } public: constexpr ALWAYS_INLINE bool operator==(const Iterator &rhs) const { return m_impl == rhs.m_impl; } constexpr ALWAYS_INLINE pointer operator->() const { return Traits::GetParent(std::addressof(*m_impl)); } constexpr ALWAYS_INLINE reference operator*() const { return *Traits::GetParent(std::addressof(*m_impl)); } constexpr ALWAYS_INLINE Iterator &operator++() { ++m_impl; return *this; } constexpr ALWAYS_INLINE Iterator &operator--() { --m_impl; return *this; } constexpr ALWAYS_INLINE Iterator operator++(int) { const Iterator it{*this}; ++m_impl; return it; } constexpr ALWAYS_INLINE Iterator operator--(int) { const Iterator it{*this}; --m_impl; return it; } constexpr ALWAYS_INLINE operator Iterator() const { return Iterator(m_impl); } }; private: static constexpr ALWAYS_INLINE int CompareImpl(const IntrusiveRedBlackTreeNode *lhs, const IntrusiveRedBlackTreeNode *rhs) { return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs)); } static constexpr ALWAYS_INLINE int CompareKeyImpl(const_key_reference key, const IntrusiveRedBlackTreeNode *rhs) { return Comparator::Compare(key, *Traits::GetParent(rhs)); } /* Define accessors using RB_* functions. */ constexpr IntrusiveRedBlackTreeNode *InsertImpl(IntrusiveRedBlackTreeNode *node) { return freebsd::RB_INSERT(m_impl.m_root, node, CompareImpl); } constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindImpl(IntrusiveRedBlackTreeNode const *node) const { return freebsd::RB_FIND(const_cast(m_impl.m_root), const_cast(node), CompareImpl); } constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *NFindImpl(IntrusiveRedBlackTreeNode const *node) const { return freebsd::RB_NFIND(const_cast(m_impl.m_root), const_cast(node), CompareImpl); } constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindKeyImpl(const_key_reference key) const { return freebsd::RB_FIND_KEY(const_cast(m_impl.m_root), key, CompareKeyImpl); } constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *NFindKeyImpl(const_key_reference key) const { return freebsd::RB_NFIND_KEY(const_cast(m_impl.m_root), key, CompareKeyImpl); } constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindExistingImpl(IntrusiveRedBlackTreeNode const *node) const { return freebsd::RB_FIND_EXISTING(const_cast(m_impl.m_root), const_cast(node), CompareImpl); } constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindExistingKeyImpl(const_key_reference key) const { return freebsd::RB_FIND_EXISTING_KEY(const_cast(m_impl.m_root), key, CompareKeyImpl); } public: constexpr ALWAYS_INLINE IntrusiveRedBlackTree() = default; /* Iterator accessors. */ constexpr ALWAYS_INLINE iterator begin() { return iterator(m_impl.begin()); } constexpr ALWAYS_INLINE const_iterator begin() const { return const_iterator(m_impl.begin()); } constexpr ALWAYS_INLINE iterator end() { return iterator(m_impl.end()); } constexpr ALWAYS_INLINE const_iterator end() const { return const_iterator(m_impl.end()); } constexpr ALWAYS_INLINE const_iterator cbegin() const { return this->begin(); } constexpr ALWAYS_INLINE const_iterator cend() const { return this->end(); } constexpr ALWAYS_INLINE iterator iterator_to(reference ref) { return iterator(m_impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); } constexpr ALWAYS_INLINE const_iterator iterator_to(const_reference ref) const { return const_iterator(m_impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); } /* Content management. */ constexpr ALWAYS_INLINE bool empty() const { return m_impl.empty(); } constexpr ALWAYS_INLINE reference back() { return *Traits::GetParent(std::addressof(m_impl.back())); } constexpr ALWAYS_INLINE const_reference back() const { return *Traits::GetParent(std::addressof(m_impl.back())); } constexpr ALWAYS_INLINE reference front() { return *Traits::GetParent(std::addressof(m_impl.front())); } constexpr ALWAYS_INLINE const_reference front() const { return *Traits::GetParent(std::addressof(m_impl.front())); } constexpr ALWAYS_INLINE iterator erase(iterator it) { return iterator(m_impl.erase(it.GetImplIterator())); } constexpr ALWAYS_INLINE iterator insert(reference ref) { ImplType::pointer node = Traits::GetNode(std::addressof(ref)); this->InsertImpl(node); return iterator(node); } constexpr ALWAYS_INLINE iterator find(const_reference ref) const { return iterator(this->FindImpl(Traits::GetNode(std::addressof(ref)))); } constexpr ALWAYS_INLINE iterator nfind(const_reference ref) const { return iterator(this->NFindImpl(Traits::GetNode(std::addressof(ref)))); } constexpr ALWAYS_INLINE iterator find_key(const_key_reference ref) const { return iterator(this->FindKeyImpl(ref)); } constexpr ALWAYS_INLINE iterator nfind_key(const_key_reference ref) const { return iterator(this->NFindKeyImpl(ref)); } constexpr ALWAYS_INLINE iterator find_existing(const_reference ref) const { return iterator(this->FindExistingImpl(Traits::GetNode(std::addressof(ref)))); } constexpr ALWAYS_INLINE iterator find_existing_key(const_key_reference ref) const { return iterator(this->FindExistingKeyImpl(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 ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetNode(Derived *parent) { return std::addressof(parent->*Member); } static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) { return std::addressof(parent->*Member); } static ALWAYS_INLINE Derived *GetParent(IntrusiveRedBlackTreeNode *node) { return util::GetParentPointer(node); } static ALWAYS_INLINE Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) { return util::GetParentPointer(node); } private: static_assert(util::IsAligned(util::impl::OffsetOf::value, alignof(void *))); }; template> class IntrusiveRedBlackTreeMemberTraitsDeferredAssert; template class IntrusiveRedBlackTreeMemberTraitsDeferredAssert { public: template using TreeType = IntrusiveRedBlackTree; using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl; static constexpr bool IsValid() { return util::IsAligned(util::impl::OffsetOf::value, alignof(void *)); } private: template friend class IntrusiveRedBlackTree; friend class impl::IntrusiveRedBlackTreeImpl; static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetNode(Derived *parent) { return std::addressof(parent->*Member); } static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) { return std::addressof(parent->*Member); } static ALWAYS_INLINE Derived *GetParent(IntrusiveRedBlackTreeNode *node) { return util::GetParentPointer(node); } static ALWAYS_INLINE Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) { return util::GetParentPointer(node); } }; template class alignas(void *) IntrusiveRedBlackTreeBaseNode : public IntrusiveRedBlackTreeNode { public: using IntrusiveRedBlackTreeNode::IntrusiveRedBlackTreeNode; constexpr ALWAYS_INLINE Derived *GetPrev() { return static_cast< Derived *>(static_cast< IntrusiveRedBlackTreeBaseNode *>(impl::IntrusiveRedBlackTreeImpl::GetPrev(this))); } constexpr ALWAYS_INLINE const Derived *GetPrev() const { return static_cast(static_cast(impl::IntrusiveRedBlackTreeImpl::GetPrev(this))); } constexpr ALWAYS_INLINE Derived *GetNext() { return static_cast< Derived *>(static_cast< IntrusiveRedBlackTreeBaseNode *>(impl::IntrusiveRedBlackTreeImpl::GetNext(this))); } constexpr ALWAYS_INLINE const Derived *GetNext() const { return static_cast(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 ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetNode(Derived *parent) { return static_cast(static_cast *>(parent)); } static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) { return static_cast(static_cast *>(parent)); } static constexpr ALWAYS_INLINE Derived *GetParent(IntrusiveRedBlackTreeNode *node) { return static_cast(static_cast *>(node)); } static constexpr ALWAYS_INLINE Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) { return static_cast(static_cast *>(node)); } }; AMS_PRAGMA_END_OPTIMIZE() }