diff options
| author | bunnei <bunneidev@gmail.com> | 2020-12-27 01:58:16 -0800 | 
|---|---|---|
| committer | bunnei <bunneidev@gmail.com> | 2021-01-11 14:23:16 -0800 | 
| commit | fb43b8efd22eaf0eaccf0c9ddc70cf2e06deafeb (patch) | |
| tree | 021d00f3bcdca20b1e573d9ce91cfbbe9e06b562 | |
| parent | 35c3c078e3c079c0a9192b411e20c71b122ff057 (diff) | |
common: Introduce useful tree structures.
| -rw-r--r-- | src/common/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/common/intrusive_red_black_tree.h | 627 | ||||
| -rw-r--r-- | src/common/parent_of_member.h | 189 | ||||
| -rw-r--r-- | src/common/tree.h | 822 | 
4 files changed, 1641 insertions, 0 deletions
| diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 2c2bd2ee8..5d781cd77 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -123,6 +123,7 @@ add_library(common STATIC      hash.h      hex_util.cpp      hex_util.h +    intrusive_red_black_tree.h      logging/backend.cpp      logging/backend.h      logging/filter.cpp @@ -143,6 +144,7 @@ add_library(common STATIC      page_table.h      param_package.cpp      param_package.h +    parent_of_member.h      quaternion.h      ring_buffer.h      scm_rev.cpp @@ -167,6 +169,7 @@ add_library(common STATIC      time_zone.h      timer.cpp      timer.h +    tree.h      uint128.cpp      uint128.h      uuid.cpp diff --git a/src/common/intrusive_red_black_tree.h b/src/common/intrusive_red_black_tree.h new file mode 100644 index 000000000..929b5497e --- /dev/null +++ b/src/common/intrusive_red_black_tree.h @@ -0,0 +1,627 @@ +// 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 <class, class, class> +    friend class IntrusiveRedBlackTree; + +public: +    constexpr IntrusiveRedBlackTreeNode() = default; +}; + +template <class T, class Traits, class Comparator> +class IntrusiveRedBlackTree; + +namespace impl { + +class IntrusiveRedBlackTreeImpl { + +private: +    template <class, class, class> +    friend class ::Common::IntrusiveRedBlackTree; + +private: +    RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode); +    using RootType = IntrusiveRedBlackTreeRoot; + +private: +    IntrusiveRedBlackTreeRoot root; + +public: +    template <bool Const> +    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<false>; +    using const_iterator = Iterator<true>; + +    template <bool Const> +    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<Const, IntrusiveRedBlackTreeImpl::const_pointer, +                                           IntrusiveRedBlackTreeImpl::pointer>; +        using reference = std::conditional_t<Const, IntrusiveRedBlackTreeImpl::const_reference, +                                             IntrusiveRedBlackTreeImpl::reference>; + +    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<true>() const { +            return Iterator<true>(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<IntrusiveRedBlackTreeRoot*>(&this->root)); +    } + +    IntrusiveRedBlackTreeNode* GetMaxImpl() const { +        return RB_MAX(IntrusiveRedBlackTreeRoot, +                      const_cast<IntrusiveRedBlackTreeRoot*>(&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<const IntrusiveRedBlackTreeNode*>( +            GetNext(const_cast<IntrusiveRedBlackTreeNode*>(node))); +    } + +    static IntrusiveRedBlackTreeNode const* GetPrev(const IntrusiveRedBlackTreeNode* node) { +        return static_cast<const IntrusiveRedBlackTreeNode*>( +            GetPrev(const_cast<IntrusiveRedBlackTreeNode*>(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<IntrusiveRedBlackTreeNode*>(nullptr)); +    } + +    const_iterator end() const { +        return const_iterator(static_cast<const IntrusiveRedBlackTreeNode*>(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 <typename T> +concept HasLightCompareType = requires { +    { std::is_same<typename T::LightCompareType, void>::value } +    ->std::convertible_to<bool>; +}; + +namespace impl { + +template <typename T, typename Default> +consteval auto* GetLightCompareType() { +    if constexpr (HasLightCompareType<T>) { +        return static_cast<typename T::LightCompareType*>(nullptr); +    } else { +        return static_cast<Default*>(nullptr); +    } +} + +} // namespace impl + +template <typename T, typename Default> +using LightCompareType = std::remove_pointer_t<decltype(impl::GetLightCompareType<T, Default>())>; + +template <class T, class Traits, class Comparator> +class IntrusiveRedBlackTree { + +public: +    using ImplType = impl::IntrusiveRedBlackTreeImpl; + +private: +    ImplType impl{}; + +public: +    struct IntrusiveRedBlackTreeRootWithCompare : ImplType::IntrusiveRedBlackTreeRoot {}; + +    template <bool Const> +    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<false>; +    using const_iterator = Iterator<true>; + +    using light_value_type = LightCompareType<Comparator, value_type>; +    using const_light_pointer = const light_value_type*; +    using const_light_reference = const light_value_type&; + +    template <bool Const> +    class Iterator { +    public: +        friend class IntrusiveRedBlackTree<T, Traits, Comparator>; + +        using ImplIterator = +            std::conditional_t<Const, ImplType::const_iterator, ImplType::iterator>; + +        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<Const, IntrusiveRedBlackTree::const_pointer, +                                           IntrusiveRedBlackTree::pointer>; +        using reference = std::conditional_t<Const, IntrusiveRedBlackTree::const_reference, +                                             IntrusiveRedBlackTree::reference>; + +    private: +        ImplIterator iterator; + +    private: +        explicit Iterator(ImplIterator it) : iterator(it) {} + +        explicit Iterator(typename std::conditional<Const, ImplType::const_iterator, +                                                    ImplType::iterator>::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<true>() const { +            return Iterator<true>(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<const_light_pointer>(elm), *Traits::GetParent(rhs)); +    } + +    // Define accessors using RB_* functions. +    IntrusiveRedBlackTreeNode* InsertImpl(IntrusiveRedBlackTreeNode* node) { +        return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare, +                         static_cast<IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root), +                         node); +    } + +    IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const { +        return RB_FIND( +            IntrusiveRedBlackTreeRootWithCompare, +            const_cast<IntrusiveRedBlackTreeRootWithCompare*>( +                static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)), +            const_cast<IntrusiveRedBlackTreeNode*>(node)); +    } + +    IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const { +        return RB_NFIND( +            IntrusiveRedBlackTreeRootWithCompare, +            const_cast<IntrusiveRedBlackTreeRootWithCompare*>( +                static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)), +            const_cast<IntrusiveRedBlackTreeNode*>(node)); +    } + +    IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const { +        return RB_FIND_LIGHT( +            IntrusiveRedBlackTreeRootWithCompare, +            const_cast<IntrusiveRedBlackTreeRootWithCompare*>( +                static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)), +            static_cast<const void*>(lelm)); +    } + +    IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const { +        return RB_NFIND_LIGHT( +            IntrusiveRedBlackTreeRootWithCompare, +            const_cast<IntrusiveRedBlackTreeRootWithCompare*>( +                static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)), +            static_cast<const void*>(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 <auto T, class Derived = impl::GetParentType<T>> +class IntrusiveRedBlackTreeMemberTraits; + +template <class Parent, IntrusiveRedBlackTreeNode Parent::*Member, class Derived> +class IntrusiveRedBlackTreeMemberTraits<Member, Derived> { +public: +    template <class Comparator> +    using TreeType = IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeMemberTraits, Comparator>; +    using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl; + +private: +    template <class, class, class> +    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<Member, Derived>(node); +    } + +    static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) { +        return GetParentPointer<Member, Derived>(node); +    } + +private: +    static constexpr TYPED_STORAGE(Derived) DerivedStorage = {}; +    static_assert(GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage)); +}; + +template <auto T, class Derived = impl::GetParentType<T>> +class IntrusiveRedBlackTreeMemberTraitsDeferredAssert; + +template <class Parent, IntrusiveRedBlackTreeNode Parent::*Member, class Derived> +class IntrusiveRedBlackTreeMemberTraitsDeferredAssert<Member, Derived> { +public: +    template <class Comparator> +    using TreeType = +        IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeMemberTraitsDeferredAssert, Comparator>; +    using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl; + +    static constexpr bool IsValid() { +        TYPED_STORAGE(Derived) DerivedStorage = {}; +        return GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage); +    } + +private: +    template <class, class, class> +    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<Member, Derived>(node); +    } + +    static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) { +        return GetParentPointer<Member, Derived>(node); +    } +}; + +template <class Derived> +class IntrusiveRedBlackTreeBaseNode : public IntrusiveRedBlackTreeNode { +public: +    constexpr Derived* GetPrev() { +        return static_cast<Derived*>(impl::IntrusiveRedBlackTreeImpl::GetPrev(this)); +    } +    constexpr const Derived* GetPrev() const { +        return static_cast<const Derived*>(impl::IntrusiveRedBlackTreeImpl::GetPrev(this)); +    } + +    constexpr Derived* GetNext() { +        return static_cast<Derived*>(impl::IntrusiveRedBlackTreeImpl::GetNext(this)); +    } +    constexpr const Derived* GetNext() const { +        return static_cast<const Derived*>(impl::IntrusiveRedBlackTreeImpl::GetNext(this)); +    } +}; + +template <class Derived> +class IntrusiveRedBlackTreeBaseTraits { +public: +    template <class Comparator> +    using TreeType = IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeBaseTraits, Comparator>; +    using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl; + +private: +    template <class, class, class> +    friend class IntrusiveRedBlackTree; + +    friend class impl::IntrusiveRedBlackTreeImpl; + +    static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) { +        return static_cast<IntrusiveRedBlackTreeNode*>(parent); +    } + +    static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) { +        return static_cast<const IntrusiveRedBlackTreeNode*>(parent); +    } + +    static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) { +        return static_cast<Derived*>(node); +    } + +    static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) { +        return static_cast<const Derived*>(node); +    } +}; + +} // namespace Common diff --git a/src/common/parent_of_member.h b/src/common/parent_of_member.h new file mode 100644 index 000000000..1af31ee44 --- /dev/null +++ b/src/common/parent_of_member.h @@ -0,0 +1,189 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <type_traits> + +#include "common/assert.h" +#include "common/common_types.h" + +namespace Common { + +template <typename T, size_t Size, size_t Align> +struct TypedStorage { +    std::aligned_storage_t<Size, Align> storage_; +}; + +#define TYPED_STORAGE(...) TypedStorage<__VA_ARGS__, sizeof(__VA_ARGS__), alignof(__VA_ARGS__)> + +template <typename T> +static constexpr T* GetPointer(TYPED_STORAGE(T) & ts) { +    return static_cast<T*>(static_cast<void*>(std::addressof(ts.storage_))); +} + +template <typename T> +static constexpr const T* GetPointer(const TYPED_STORAGE(T) & ts) { +    return static_cast<const T*>(static_cast<const void*>(std::addressof(ts.storage_))); +} + +namespace impl { + +template <size_t MaxDepth> +struct OffsetOfUnionHolder { +    template <typename ParentType, typename MemberType, size_t Offset> +    union UnionImpl { +        using PaddingMember = char; +        static constexpr size_t GetOffset() { +            return Offset; +        } + +#pragma pack(push, 1) +        struct { +            PaddingMember padding[Offset]; +            MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1]; +        } data; +#pragma pack(pop) +        UnionImpl<ParentType, MemberType, Offset + 1> next_union; +    }; + +    template <typename ParentType, typename MemberType> +    union UnionImpl<ParentType, MemberType, 0> { +        static constexpr size_t GetOffset() { +            return 0; +        } + +        struct { +            MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1]; +        } data; +        UnionImpl<ParentType, MemberType, 1> next_union; +    }; + +    template <typename ParentType, typename MemberType> +    union UnionImpl<ParentType, MemberType, MaxDepth> {}; +}; + +template <typename ParentType, typename MemberType> +struct OffsetOfCalculator { +    using UnionHolder = +        typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType, +                                                                             0>; +    union Union { +        char c{}; +        UnionHolder first_union; +        TYPED_STORAGE(ParentType) parent; + +        constexpr Union() : c() {} +    }; +    static constexpr Union U = {}; + +    static constexpr const MemberType* GetNextAddress(const MemberType* start, +                                                      const MemberType* target) { +        while (start < target) { +            start++; +        } +        return start; +    } + +    static constexpr std::ptrdiff_t GetDifference(const MemberType* start, +                                                  const MemberType* target) { +        return (target - start) * sizeof(MemberType); +    } + +    template <typename CurUnion> +    static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member, +                                                 CurUnion& cur_union) { +        constexpr size_t Offset = CurUnion::GetOffset(); +        const auto target = std::addressof(GetPointer(U.parent)->*member); +        const auto start = std::addressof(cur_union.data.members[0]); +        const auto next = GetNextAddress(start, target); + +        if (next != target) { +            if constexpr (Offset < sizeof(MemberType) - 1) { +                return OffsetOfImpl(member, cur_union.next_union); +            } else { +                UNREACHABLE(); +            } +        } + +        return (next - start) * sizeof(MemberType) + Offset; +    } + +    static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) { +        return OffsetOfImpl(member, U.first_union); +    } +}; + +template <typename T> +struct GetMemberPointerTraits; + +template <typename P, typename M> +struct GetMemberPointerTraits<M P::*> { +    using Parent = P; +    using Member = M; +}; + +template <auto MemberPtr> +using GetParentType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Parent; + +template <auto MemberPtr> +using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member; + +template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>> +static inline std::ptrdiff_t OffsetOf = [] { +    using DeducedParentType = GetParentType<MemberPtr>; +    using MemberType = GetMemberType<MemberPtr>; +    static_assert(std::is_base_of<DeducedParentType, RealParentType>::value || +                  std::is_same<RealParentType, DeducedParentType>::value); + +    return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr); +}(); + +} // namespace impl + +template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> +constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) { +    std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; +    return *static_cast<RealParentType*>( +        static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset)); +} + +template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> +constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) { +    std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; +    return *static_cast<const RealParentType*>(static_cast<const void*>( +        static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset)); +} + +template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> +constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>* member) { +    return std::addressof(GetParentReference<MemberPtr, RealParentType>(member)); +} + +template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> +constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const* member) { +    return std::addressof(GetParentReference<MemberPtr, RealParentType>(member)); +} + +template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> +constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>& member) { +    return GetParentReference<MemberPtr, RealParentType>(std::addressof(member)); +} + +template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> +constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const& member) { +    return GetParentReference<MemberPtr, RealParentType>(std::addressof(member)); +} + +template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> +constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>& member) { +    return std::addressof(GetParentReference<MemberPtr, RealParentType>(member)); +} + +template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> +constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const& member) { +    return std::addressof(GetParentReference<MemberPtr, RealParentType>(member)); +} + +} // namespace Common diff --git a/src/common/tree.h b/src/common/tree.h new file mode 100644 index 000000000..a6b636646 --- /dev/null +++ b/src/common/tree.h @@ -0,0 +1,822 @@ +/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */ +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* $FreeBSD$ */ + +/*- + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* FreeBSD <sys/cdefs.h> has a lot of defines we don't really want. */ +/* tree.h only actually uses __inline and __unused, so we'll just define those. */ + +/* #include <sys/cdefs.h> */ + +#ifndef __inline +#define __inline inline +#endif + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure.  Every operation + * on the tree causes a splay to happen.  The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree.  On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n).  The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute.  It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + *   same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type)                                                                     \ +    struct name {                                                                                  \ +        struct type* sph_root; /* root of the tree */                                              \ +    } + +#define SPLAY_INITIALIZER(root)                                                                    \ +    { NULL } + +#define SPLAY_INIT(root)                                                                           \ +    do {                                                                                           \ +        (root)->sph_root = NULL;                                                                   \ +    } while (/*CONSTCOND*/ 0) + +#define SPLAY_ENTRY(type)                                                                          \ +    struct {                                                                                       \ +        struct type* spe_left;  /* left element */                                                 \ +        struct type* spe_right; /* right element */                                                \ +    } + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field)                                                       \ +    do {                                                                                           \ +        SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field);                             \ +        SPLAY_RIGHT(tmp, field) = (head)->sph_root;                                                \ +        (head)->sph_root = tmp;                                                                    \ +    } while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field)                                                        \ +    do {                                                                                           \ +        SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field);                             \ +        SPLAY_LEFT(tmp, field) = (head)->sph_root;                                                 \ +        (head)->sph_root = tmp;                                                                    \ +    } while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field)                                                           \ +    do {                                                                                           \ +        SPLAY_LEFT(tmp, field) = (head)->sph_root;                                                 \ +        tmp = (head)->sph_root;                                                                    \ +        (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);                                    \ +    } while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field)                                                          \ +    do {                                                                                           \ +        SPLAY_RIGHT(tmp, field) = (head)->sph_root;                                                \ +        tmp = (head)->sph_root;                                                                    \ +        (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);                                   \ +    } while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field)                                             \ +    do {                                                                                           \ +        SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field);                            \ +        SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);                           \ +        SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field);                            \ +        SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field);                            \ +    } while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp)                                                    \ +    void name##_SPLAY(struct name*, struct type*);                                                 \ +    void name##_SPLAY_MINMAX(struct name*, int);                                                   \ +    struct type* name##_SPLAY_INSERT(struct name*, struct type*);                                  \ +    struct type* name##_SPLAY_REMOVE(struct name*, struct type*);                                  \ +                                                                                                   \ +    /* Finds the node with the same key as elm */                                                  \ +    static __inline struct type* name##_SPLAY_FIND(struct name* head, struct type* elm) {          \ +        if (SPLAY_EMPTY(head))                                                                     \ +            return (NULL);                                                                         \ +        name##_SPLAY(head, elm);                                                                   \ +        if ((cmp)(elm, (head)->sph_root) == 0)                                                     \ +            return (head->sph_root);                                                               \ +        return (NULL);                                                                             \ +    }                                                                                              \ +                                                                                                   \ +    static __inline struct type* name##_SPLAY_NEXT(struct name* head, struct type* elm) {          \ +        name##_SPLAY(head, elm);                                                                   \ +        if (SPLAY_RIGHT(elm, field) != NULL) {                                                     \ +            elm = SPLAY_RIGHT(elm, field);                                                         \ +            while (SPLAY_LEFT(elm, field) != NULL) {                                               \ +                elm = SPLAY_LEFT(elm, field);                                                      \ +            }                                                                                      \ +        } else                                                                                     \ +            elm = NULL;                                                                            \ +        return (elm);                                                                              \ +    }                                                                                              \ +                                                                                                   \ +    static __inline struct type* name##_SPLAY_MIN_MAX(struct name* head, int val) {                \ +        name##_SPLAY_MINMAX(head, val);                                                            \ +        return (SPLAY_ROOT(head));                                                                 \ +    } + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp)                                                     \ +    struct type* name##_SPLAY_INSERT(struct name* head, struct type* elm) {                        \ +        if (SPLAY_EMPTY(head)) {                                                                   \ +            SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL;                               \ +        } else {                                                                                   \ +            int __comp;                                                                            \ +            name##_SPLAY(head, elm);                                                               \ +            __comp = (cmp)(elm, (head)->sph_root);                                                 \ +            if (__comp < 0) {                                                                      \ +                SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);                      \ +                SPLAY_RIGHT(elm, field) = (head)->sph_root;                                        \ +                SPLAY_LEFT((head)->sph_root, field) = NULL;                                        \ +            } else if (__comp > 0) {                                                               \ +                SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);                    \ +                SPLAY_LEFT(elm, field) = (head)->sph_root;                                         \ +                SPLAY_RIGHT((head)->sph_root, field) = NULL;                                       \ +            } else                                                                                 \ +                return ((head)->sph_root);                                                         \ +        }                                                                                          \ +        (head)->sph_root = (elm);                                                                  \ +        return (NULL);                                                                             \ +    }                                                                                              \ +                                                                                                   \ +    struct type* name##_SPLAY_REMOVE(struct name* head, struct type* elm) {                        \ +        struct type* __tmp;                                                                        \ +        if (SPLAY_EMPTY(head))                                                                     \ +            return (NULL);                                                                         \ +        name##_SPLAY(head, elm);                                                                   \ +        if ((cmp)(elm, (head)->sph_root) == 0) {                                                   \ +            if (SPLAY_LEFT((head)->sph_root, field) == NULL) {                                     \ +                (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);                           \ +            } else {                                                                               \ +                __tmp = SPLAY_RIGHT((head)->sph_root, field);                                      \ +                (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);                            \ +                name##_SPLAY(head, elm);                                                           \ +                SPLAY_RIGHT((head)->sph_root, field) = __tmp;                                      \ +            }                                                                                      \ +            return (elm);                                                                          \ +        }                                                                                          \ +        return (NULL);                                                                             \ +    }                                                                                              \ +                                                                                                   \ +    void name##_SPLAY(struct name* head, struct type* elm) {                                       \ +        struct type __node, *__left, *__right, *__tmp;                                             \ +        int __comp;                                                                                \ +                                                                                                   \ +        SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;                           \ +        __left = __right = &__node;                                                                \ +                                                                                                   \ +        while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) {                                     \ +            if (__comp < 0) {                                                                      \ +                __tmp = SPLAY_LEFT((head)->sph_root, field);                                       \ +                if (__tmp == NULL)                                                                 \ +                    break;                                                                         \ +                if ((cmp)(elm, __tmp) < 0) {                                                       \ +                    SPLAY_ROTATE_RIGHT(head, __tmp, field);                                        \ +                    if (SPLAY_LEFT((head)->sph_root, field) == NULL)                               \ +                        break;                                                                     \ +                }                                                                                  \ +                SPLAY_LINKLEFT(head, __right, field);                                              \ +            } else if (__comp > 0) {                                                               \ +                __tmp = SPLAY_RIGHT((head)->sph_root, field);                                      \ +                if (__tmp == NULL)                                                                 \ +                    break;                                                                         \ +                if ((cmp)(elm, __tmp) > 0) {                                                       \ +                    SPLAY_ROTATE_LEFT(head, __tmp, field);                                         \ +                    if (SPLAY_RIGHT((head)->sph_root, field) == NULL)                              \ +                        break;                                                                     \ +                }                                                                                  \ +                SPLAY_LINKRIGHT(head, __left, field);                                              \ +            }                                                                                      \ +        }                                                                                          \ +        SPLAY_ASSEMBLE(head, &__node, __left, __right, field);                                     \ +    }                                                                                              \ +                                                                                                   \ +    /* Splay with either the minimum or the maximum element                                        \ +     * Used to find minimum or maximum element in tree.                                            \ +     */                                                                                            \ +    void name##_SPLAY_MINMAX(struct name* head, int __comp) {                                      \ +        struct type __node, *__left, *__right, *__tmp;                                             \ +                                                                                                   \ +        SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;                           \ +        __left = __right = &__node;                                                                \ +                                                                                                   \ +        while (1) {                                                                                \ +            if (__comp < 0) {                                                                      \ +                __tmp = SPLAY_LEFT((head)->sph_root, field);                                       \ +                if (__tmp == NULL)                                                                 \ +                    break;                                                                         \ +                if (__comp < 0) {                                                                  \ +                    SPLAY_ROTATE_RIGHT(head, __tmp, field);                                        \ +                    if (SPLAY_LEFT((head)->sph_root, field) == NULL)                               \ +                        break;                                                                     \ +                }                                                                                  \ +                SPLAY_LINKLEFT(head, __right, field);                                              \ +            } else if (__comp > 0) {                                                               \ +                __tmp = SPLAY_RIGHT((head)->sph_root, field);                                      \ +                if (__tmp == NULL)                                                                 \ +                    break;                                                                         \ +                if (__comp > 0) {                                                                  \ +                    SPLAY_ROTATE_LEFT(head, __tmp, field);                                         \ +                    if (SPLAY_RIGHT((head)->sph_root, field) == NULL)                              \ +                        break;                                                                     \ +                }                                                                                  \ +                SPLAY_LINKRIGHT(head, __left, field);                                              \ +            }                                                                                      \ +        }                                                                                          \ +        SPLAY_ASSEMBLE(head, &__node, __left, __right, field);                                     \ +    } + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head)                                                               \ +    for ((x) = SPLAY_MIN(name, head); (x) != NULL; (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type)                                                                        \ +    struct name {                                                                                  \ +        struct type* rbh_root; /* root of the tree */                                              \ +    } + +#define RB_INITIALIZER(root)                                                                       \ +    { NULL } + +#define RB_INIT(root)                                                                              \ +    do {                                                                                           \ +        (root)->rbh_root = NULL;                                                                   \ +    } while (/*CONSTCOND*/ 0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type)                                                                             \ +    struct {                                                                                       \ +        struct type* rbe_left;   /* left element */                                                \ +        struct type* rbe_right;  /* right element */                                               \ +        struct type* rbe_parent; /* parent element */                                              \ +        int rbe_color;           /* node color */                                                  \ +    } + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field)                                                                 \ +    do {                                                                                           \ +        RB_PARENT(elm, field) = parent;                                                            \ +        RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL;                                         \ +        RB_COLOR(elm, field) = RB_RED;                                                             \ +    } while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field)                                                         \ +    do {                                                                                           \ +        RB_COLOR(black, field) = RB_BLACK;                                                         \ +        RB_COLOR(red, field) = RB_RED;                                                             \ +    } while (/*CONSTCOND*/ 0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x)                                                                              \ +    do {                                                                                           \ +    } while (0) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field)                                                      \ +    do {                                                                                           \ +        (tmp) = RB_RIGHT(elm, field);                                                              \ +        if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) {                                \ +            RB_PARENT(RB_LEFT(tmp, field), field) = (elm);                                         \ +        }                                                                                          \ +        RB_AUGMENT(elm);                                                                           \ +        if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) {                             \ +            if ((elm) == RB_LEFT(RB_PARENT(elm, field), field))                                    \ +                RB_LEFT(RB_PARENT(elm, field), field) = (tmp);                                     \ +            else                                                                                   \ +                RB_RIGHT(RB_PARENT(elm, field), field) = (tmp);                                    \ +        } else                                                                                     \ +            (head)->rbh_root = (tmp);                                                              \ +        RB_LEFT(tmp, field) = (elm);                                                               \ +        RB_PARENT(elm, field) = (tmp);                                                             \ +        RB_AUGMENT(tmp);                                                                           \ +        if ((RB_PARENT(tmp, field)))                                                               \ +            RB_AUGMENT(RB_PARENT(tmp, field));                                                     \ +    } while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field)                                                     \ +    do {                                                                                           \ +        (tmp) = RB_LEFT(elm, field);                                                               \ +        if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) {                                \ +            RB_PARENT(RB_RIGHT(tmp, field), field) = (elm);                                        \ +        }                                                                                          \ +        RB_AUGMENT(elm);                                                                           \ +        if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) {                             \ +            if ((elm) == RB_LEFT(RB_PARENT(elm, field), field))                                    \ +                RB_LEFT(RB_PARENT(elm, field), field) = (tmp);                                     \ +            else                                                                                   \ +                RB_RIGHT(RB_PARENT(elm, field), field) = (tmp);                                    \ +        } else                                                                                     \ +            (head)->rbh_root = (tmp);                                                              \ +        RB_RIGHT(tmp, field) = (elm);                                                              \ +        RB_PARENT(elm, field) = (tmp);                                                             \ +        RB_AUGMENT(tmp);                                                                           \ +        if ((RB_PARENT(tmp, field)))                                                               \ +            RB_AUGMENT(RB_PARENT(tmp, field));                                                     \ +    } while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) RB_PROTOTYPE_INTERNAL(name, type, field, cmp, ) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp)                                                \ +    RB_PROTOTYPE_INTERNAL(name, type, field, cmp, static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr)                                        \ +    RB_PROTOTYPE_INSERT_COLOR(name, type, attr);                                                   \ +    RB_PROTOTYPE_REMOVE_COLOR(name, type, attr);                                                   \ +    RB_PROTOTYPE_INSERT(name, type, attr);                                                         \ +    RB_PROTOTYPE_REMOVE(name, type, attr);                                                         \ +    RB_PROTOTYPE_FIND(name, type, attr);                                                           \ +    RB_PROTOTYPE_NFIND(name, type, attr);                                                          \ +    RB_PROTOTYPE_FIND_LIGHT(name, type, attr);                                                     \ +    RB_PROTOTYPE_NFIND_LIGHT(name, type, attr);                                                    \ +    RB_PROTOTYPE_NEXT(name, type, attr);                                                           \ +    RB_PROTOTYPE_PREV(name, type, attr);                                                           \ +    RB_PROTOTYPE_MINMAX(name, type, attr); +#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr)                                                \ +    attr void name##_RB_INSERT_COLOR(struct name*, struct type*) +#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr)                                                \ +    attr void name##_RB_REMOVE_COLOR(struct name*, struct type*, struct type*) +#define RB_PROTOTYPE_REMOVE(name, type, attr)                                                      \ +    attr struct type* name##_RB_REMOVE(struct name*, struct type*) +#define RB_PROTOTYPE_INSERT(name, type, attr)                                                      \ +    attr struct type* name##_RB_INSERT(struct name*, struct type*) +#define RB_PROTOTYPE_FIND(name, type, attr)                                                        \ +    attr struct type* name##_RB_FIND(struct name*, struct type*) +#define RB_PROTOTYPE_NFIND(name, type, attr)                                                       \ +    attr struct type* name##_RB_NFIND(struct name*, struct type*) +#define RB_PROTOTYPE_FIND_LIGHT(name, type, attr)                                                  \ +    attr struct type* name##_RB_FIND_LIGHT(struct name*, const void*) +#define RB_PROTOTYPE_NFIND_LIGHT(name, type, attr)                                                 \ +    attr struct type* name##_RB_NFIND_LIGHT(struct name*, const void*) +#define RB_PROTOTYPE_NEXT(name, type, attr) attr struct type* name##_RB_NEXT(struct type*) +#define RB_PROTOTYPE_PREV(name, type, attr) attr struct type* name##_RB_PREV(struct type*) +#define RB_PROTOTYPE_MINMAX(name, type, attr) attr struct type* name##_RB_MINMAX(struct name*, int) + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE_WITHOUT_COMPARE(name, type, field)                                             \ +    RB_GENERATE_WITHOUT_COMPARE_INTERNAL(name, type, field, ) +#define RB_GENERATE_WITHOUT_COMPARE_STATIC(name, type, field)                                      \ +    RB_GENERATE_WITHOUT_COMPARE_INTERNAL(name, type, field, static) +#define RB_GENERATE_WITHOUT_COMPARE_INTERNAL(name, type, field, attr)                              \ +    RB_GENERATE_REMOVE_COLOR(name, type, field, attr)                                              \ +    RB_GENERATE_REMOVE(name, type, field, attr)                                                    \ +    RB_GENERATE_NEXT(name, type, field, attr)                                                      \ +    RB_GENERATE_PREV(name, type, field, attr)                                                      \ +    RB_GENERATE_MINMAX(name, type, field, attr) + +#define RB_GENERATE_WITH_COMPARE(name, type, field, cmp, lcmp)                                     \ +    RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, lcmp, ) +#define RB_GENERATE_WITH_COMPARE_STATIC(name, type, field, cmp, lcmp)                              \ +    RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, lcmp, static) +#define RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, lcmp, attr)                      \ +    RB_GENERATE_INSERT_COLOR(name, type, field, attr)                                              \ +    RB_GENERATE_INSERT(name, type, field, cmp, attr)                                               \ +    RB_GENERATE_FIND(name, type, field, cmp, attr)                                                 \ +    RB_GENERATE_NFIND(name, type, field, cmp, attr)                                                \ +    RB_GENERATE_FIND_LIGHT(name, type, field, lcmp, attr)                                          \ +    RB_GENERATE_NFIND_LIGHT(name, type, field, lcmp, attr) + +#define RB_GENERATE_ALL(name, type, field, cmp) RB_GENERATE_ALL_INTERNAL(name, type, field, cmp, ) +#define RB_GENERATE_ALL_STATIC(name, type, field, cmp)                                             \ +    RB_GENERATE_ALL_INTERNAL(name, type, field, cmp, static) +#define RB_GENERATE_ALL_INTERNAL(name, type, field, cmp, attr)                                     \ +    RB_GENERATE_WITHOUT_COMPARE_INTERNAL(name, type, field, attr)                                  \ +    RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, attr) + +#define RB_GENERATE_INSERT_COLOR(name, type, field, attr)                                          \ +    attr void name##_RB_INSERT_COLOR(struct name* head, struct type* elm) {                        \ +        struct type *parent, *gparent, *tmp;                                                       \ +        while ((parent = RB_PARENT(elm, field)) != NULL && RB_COLOR(parent, field) == RB_RED) {    \ +            gparent = RB_PARENT(parent, field);                                                    \ +            if (parent == RB_LEFT(gparent, field)) {                                               \ +                tmp = RB_RIGHT(gparent, field);                                                    \ +                if (tmp && RB_COLOR(tmp, field) == RB_RED) {                                       \ +                    RB_COLOR(tmp, field) = RB_BLACK;                                               \ +                    RB_SET_BLACKRED(parent, gparent, field);                                       \ +                    elm = gparent;                                                                 \ +                    continue;                                                                      \ +                }                                                                                  \ +                if (RB_RIGHT(parent, field) == elm) {                                              \ +                    RB_ROTATE_LEFT(head, parent, tmp, field);                                      \ +                    tmp = parent;                                                                  \ +                    parent = elm;                                                                  \ +                    elm = tmp;                                                                     \ +                }                                                                                  \ +                RB_SET_BLACKRED(parent, gparent, field);                                           \ +                RB_ROTATE_RIGHT(head, gparent, tmp, field);                                        \ +            } else {                                                                               \ +                tmp = RB_LEFT(gparent, field);                                                     \ +                if (tmp && RB_COLOR(tmp, field) == RB_RED) {                                       \ +                    RB_COLOR(tmp, field) = RB_BLACK;                                               \ +                    RB_SET_BLACKRED(parent, gparent, field);                                       \ +                    elm = gparent;                                                                 \ +                    continue;                                                                      \ +                }                                                                                  \ +                if (RB_LEFT(parent, field) == elm) {                                               \ +                    RB_ROTATE_RIGHT(head, parent, tmp, field);                                     \ +                    tmp = parent;                                                                  \ +                    parent = elm;                                                                  \ +                    elm = tmp;                                                                     \ +                }                                                                                  \ +                RB_SET_BLACKRED(parent, gparent, field);                                           \ +                RB_ROTATE_LEFT(head, gparent, tmp, field);                                         \ +            }                                                                                      \ +        }                                                                                          \ +        RB_COLOR(head->rbh_root, field) = RB_BLACK;                                                \ +    } + +#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr)                                          \ +    attr void name##_RB_REMOVE_COLOR(struct name* head, struct type* parent, struct type* elm) {   \ +        struct type* tmp;                                                                          \ +        while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && elm != RB_ROOT(head)) {        \ +            if (RB_LEFT(parent, field) == elm) {                                                   \ +                tmp = RB_RIGHT(parent, field);                                                     \ +                if (RB_COLOR(tmp, field) == RB_RED) {                                              \ +                    RB_SET_BLACKRED(tmp, parent, field);                                           \ +                    RB_ROTATE_LEFT(head, parent, tmp, field);                                      \ +                    tmp = RB_RIGHT(parent, field);                                                 \ +                }                                                                                  \ +                if ((RB_LEFT(tmp, field) == NULL ||                                                \ +                     RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&                          \ +                    (RB_RIGHT(tmp, field) == NULL ||                                               \ +                     RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {                         \ +                    RB_COLOR(tmp, field) = RB_RED;                                                 \ +                    elm = parent;                                                                  \ +                    parent = RB_PARENT(elm, field);                                                \ +                } else {                                                                           \ +                    if (RB_RIGHT(tmp, field) == NULL ||                                            \ +                        RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {                       \ +                        struct type* oleft;                                                        \ +                        if ((oleft = RB_LEFT(tmp, field)) != NULL)                                 \ +                            RB_COLOR(oleft, field) = RB_BLACK;                                     \ +                        RB_COLOR(tmp, field) = RB_RED;                                             \ +                        RB_ROTATE_RIGHT(head, tmp, oleft, field);                                  \ +                        tmp = RB_RIGHT(parent, field);                                             \ +                    }                                                                              \ +                    RB_COLOR(tmp, field) = RB_COLOR(parent, field);                                \ +                    RB_COLOR(parent, field) = RB_BLACK;                                            \ +                    if (RB_RIGHT(tmp, field))                                                      \ +                        RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;                          \ +                    RB_ROTATE_LEFT(head, parent, tmp, field);                                      \ +                    elm = RB_ROOT(head);                                                           \ +                    break;                                                                         \ +                }                                                                                  \ +            } else {                                                                               \ +                tmp = RB_LEFT(parent, field);                                                      \ +                if (RB_COLOR(tmp, field) == RB_RED) {                                              \ +                    RB_SET_BLACKRED(tmp, parent, field);                                           \ +                    RB_ROTATE_RIGHT(head, parent, tmp, field);                                     \ +                    tmp = RB_LEFT(parent, field);                                                  \ +                }                                                                                  \ +                if ((RB_LEFT(tmp, field) == NULL ||                                                \ +                     RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&                          \ +                    (RB_RIGHT(tmp, field) == NULL ||                                               \ +                     RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {                         \ +                    RB_COLOR(tmp, field) = RB_RED;                                                 \ +                    elm = parent;                                                                  \ +                    parent = RB_PARENT(elm, field);                                                \ +                } else {                                                                           \ +                    if (RB_LEFT(tmp, field) == NULL ||                                             \ +                        RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {                        \ +                        struct type* oright;                                                       \ +                        if ((oright = RB_RIGHT(tmp, field)) != NULL)                               \ +                            RB_COLOR(oright, field) = RB_BLACK;                                    \ +                        RB_COLOR(tmp, field) = RB_RED;                                             \ +                        RB_ROTATE_LEFT(head, tmp, oright, field);                                  \ +                        tmp = RB_LEFT(parent, field);                                              \ +                    }                                                                              \ +                    RB_COLOR(tmp, field) = RB_COLOR(parent, field);                                \ +                    RB_COLOR(parent, field) = RB_BLACK;                                            \ +                    if (RB_LEFT(tmp, field))                                                       \ +                        RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;                           \ +                    RB_ROTATE_RIGHT(head, parent, tmp, field);                                     \ +                    elm = RB_ROOT(head);                                                           \ +                    break;                                                                         \ +                }                                                                                  \ +            }                                                                                      \ +        }                                                                                          \ +        if (elm)                                                                                   \ +            RB_COLOR(elm, field) = RB_BLACK;                                                       \ +    } + +#define RB_GENERATE_REMOVE(name, type, field, attr)                                                \ +    attr struct type* name##_RB_REMOVE(struct name* head, struct type* elm) {                      \ +        struct type *child, *parent, *old = elm;                                                   \ +        int color;                                                                                 \ +        if (RB_LEFT(elm, field) == NULL)                                                           \ +            child = RB_RIGHT(elm, field);                                                          \ +        else if (RB_RIGHT(elm, field) == NULL)                                                     \ +            child = RB_LEFT(elm, field);                                                           \ +        else {                                                                                     \ +            struct type* left;                                                                     \ +            elm = RB_RIGHT(elm, field);                                                            \ +            while ((left = RB_LEFT(elm, field)) != NULL)                                           \ +                elm = left;                                                                        \ +            child = RB_RIGHT(elm, field);                                                          \ +            parent = RB_PARENT(elm, field);                                                        \ +            color = RB_COLOR(elm, field);                                                          \ +            if (child)                                                                             \ +                RB_PARENT(child, field) = parent;                                                  \ +            if (parent) {                                                                          \ +                if (RB_LEFT(parent, field) == elm)                                                 \ +                    RB_LEFT(parent, field) = child;                                                \ +                else                                                                               \ +                    RB_RIGHT(parent, field) = child;                                               \ +                RB_AUGMENT(parent);                                                                \ +            } else                                                                                 \ +                RB_ROOT(head) = child;                                                             \ +            if (RB_PARENT(elm, field) == old)                                                      \ +                parent = elm;                                                                      \ +            (elm)->field = (old)->field;                                                           \ +            if (RB_PARENT(old, field)) {                                                           \ +                if (RB_LEFT(RB_PARENT(old, field), field) == old)                                  \ +                    RB_LEFT(RB_PARENT(old, field), field) = elm;                                   \ +                else                                                                               \ +                    RB_RIGHT(RB_PARENT(old, field), field) = elm;                                  \ +                RB_AUGMENT(RB_PARENT(old, field));                                                 \ +            } else                                                                                 \ +                RB_ROOT(head) = elm;                                                               \ +            RB_PARENT(RB_LEFT(old, field), field) = elm;                                           \ +            if (RB_RIGHT(old, field))                                                              \ +                RB_PARENT(RB_RIGHT(old, field), field) = elm;                                      \ +            if (parent) {                                                                          \ +                left = parent;                                                                     \ +                do {                                                                               \ +                    RB_AUGMENT(left);                                                              \ +                } while ((left = RB_PARENT(left, field)) != NULL);                                 \ +            }                                                                                      \ +            goto color;                                                                            \ +        }                                                                                          \ +        parent = RB_PARENT(elm, field);                                                            \ +        color = RB_COLOR(elm, field);                                                              \ +        if (child)                                                                                 \ +            RB_PARENT(child, field) = parent;                                                      \ +        if (parent) {                                                                              \ +            if (RB_LEFT(parent, field) == elm)                                                     \ +                RB_LEFT(parent, field) = child;                                                    \ +            else                                                                                   \ +                RB_RIGHT(parent, field) = child;                                                   \ +            RB_AUGMENT(parent);                                                                    \ +        } else                                                                                     \ +            RB_ROOT(head) = child;                                                                 \ +    color:                                                                                         \ +        if (color == RB_BLACK)                                                                     \ +            name##_RB_REMOVE_COLOR(head, parent, child);                                           \ +        return (old);                                                                              \ +    } + +#define RB_GENERATE_INSERT(name, type, field, cmp, attr)                                           \ +    /* Inserts a node into the RB tree */                                                          \ +    attr struct type* name##_RB_INSERT(struct name* head, struct type* elm) {                      \ +        struct type* tmp;                                                                          \ +        struct type* parent = NULL;                                                                \ +        int comp = 0;                                                                              \ +        tmp = RB_ROOT(head);                                                                       \ +        while (tmp) {                                                                              \ +            parent = tmp;                                                                          \ +            comp = (cmp)(elm, parent);                                                             \ +            if (comp < 0)                                                                          \ +                tmp = RB_LEFT(tmp, field);                                                         \ +            else if (comp > 0)                                                                     \ +                tmp = RB_RIGHT(tmp, field);                                                        \ +            else                                                                                   \ +                return (tmp);                                                                      \ +        }                                                                                          \ +        RB_SET(elm, parent, field);                                                                \ +        if (parent != NULL) {                                                                      \ +            if (comp < 0)                                                                          \ +                RB_LEFT(parent, field) = elm;                                                      \ +            else                                                                                   \ +                RB_RIGHT(parent, field) = elm;                                                     \ +            RB_AUGMENT(parent);                                                                    \ +        } else                                                                                     \ +            RB_ROOT(head) = elm;                                                                   \ +        name##_RB_INSERT_COLOR(head, elm);                                                         \ +        return (NULL);                                                                             \ +    } + +#define RB_GENERATE_FIND(name, type, field, cmp, attr)                                             \ +    /* Finds the node with the same key as elm */                                                  \ +    attr struct type* name##_RB_FIND(struct name* head, struct type* elm) {                        \ +        struct type* tmp = RB_ROOT(head);                                                          \ +        int comp;                                                                                  \ +        while (tmp) {                                                                              \ +            comp = cmp(elm, tmp);                                                                  \ +            if (comp < 0)                                                                          \ +                tmp = RB_LEFT(tmp, field);                                                         \ +            else if (comp > 0)                                                                     \ +                tmp = RB_RIGHT(tmp, field);                                                        \ +            else                                                                                   \ +                return (tmp);                                                                      \ +        }                                                                                          \ +        return (NULL);                                                                             \ +    } + +#define RB_GENERATE_NFIND(name, type, field, cmp, attr)                                            \ +    /* Finds the first node greater than or equal to the search key */                             \ +    attr struct type* name##_RB_NFIND(struct name* head, struct type* elm) {                       \ +        struct type* tmp = RB_ROOT(head);                                                          \ +        struct type* res = NULL;                                                                   \ +        int comp;                                                                                  \ +        while (tmp) {                                                                              \ +            comp = cmp(elm, tmp);                                                                  \ +            if (comp < 0) {                                                                        \ +                res = tmp;                                                                         \ +                tmp = RB_LEFT(tmp, field);                                                         \ +            } else if (comp > 0)                                                                   \ +                tmp = RB_RIGHT(tmp, field);                                                        \ +            else                                                                                   \ +                return (tmp);                                                                      \ +        }                                                                                          \ +        return (res);                                                                              \ +    } + +#define RB_GENERATE_FIND_LIGHT(name, type, field, lcmp, attr)                                      \ +    /* Finds the node with the same key as elm */                                                  \ +    attr struct type* name##_RB_FIND_LIGHT(struct name* head, const void* lelm) {                  \ +        struct type* tmp = RB_ROOT(head);                                                          \ +        int comp;                                                                                  \ +        while (tmp) {                                                                              \ +            comp = lcmp(lelm, tmp);                                                                \ +            if (comp < 0)                                                                          \ +                tmp = RB_LEFT(tmp, field);                                                         \ +            else if (comp > 0)                                                                     \ +                tmp = RB_RIGHT(tmp, field);                                                        \ +            else                                                                                   \ +                return (tmp);                                                                      \ +        }                                                                                          \ +        return (NULL);                                                                             \ +    } + +#define RB_GENERATE_NFIND_LIGHT(name, type, field, lcmp, attr)                                     \ +    /* Finds the first node greater than or equal to the search key */                             \ +    attr struct type* name##_RB_NFIND_LIGHT(struct name* head, const void* lelm) {                 \ +        struct type* tmp = RB_ROOT(head);                                                          \ +        struct type* res = NULL;                                                                   \ +        int comp;                                                                                  \ +        while (tmp) {                                                                              \ +            comp = lcmp(lelm, tmp);                                                                \ +            if (comp < 0) {                                                                        \ +                res = tmp;                                                                         \ +                tmp = RB_LEFT(tmp, field);                                                         \ +            } else if (comp > 0)                                                                   \ +                tmp = RB_RIGHT(tmp, field);                                                        \ +            else                                                                                   \ +                return (tmp);                                                                      \ +        }                                                                                          \ +        return (res);                                                                              \ +    } + +#define RB_GENERATE_NEXT(name, type, field, attr)                                                  \ +    /* ARGSUSED */                                                                                 \ +    attr struct type* name##_RB_NEXT(struct type* elm) {                                           \ +        if (RB_RIGHT(elm, field)) {                                                                \ +            elm = RB_RIGHT(elm, field);                                                            \ +            while (RB_LEFT(elm, field))                                                            \ +                elm = RB_LEFT(elm, field);                                                         \ +        } else {                                                                                   \ +            if (RB_PARENT(elm, field) && (elm == RB_LEFT(RB_PARENT(elm, field), field)))           \ +                elm = RB_PARENT(elm, field);                                                       \ +            else {                                                                                 \ +                while (RB_PARENT(elm, field) && (elm == RB_RIGHT(RB_PARENT(elm, field), field)))   \ +                    elm = RB_PARENT(elm, field);                                                   \ +                elm = RB_PARENT(elm, field);                                                       \ +            }                                                                                      \ +        }                                                                                          \ +        return (elm);                                                                              \ +    } + +#define RB_GENERATE_PREV(name, type, field, attr)                                                  \ +    /* ARGSUSED */                                                                                 \ +    attr struct type* name##_RB_PREV(struct type* elm) {                                           \ +        if (RB_LEFT(elm, field)) {                                                                 \ +            elm = RB_LEFT(elm, field);                                                             \ +            while (RB_RIGHT(elm, field))                                                           \ +                elm = RB_RIGHT(elm, field);                                                        \ +        } else {                                                                                   \ +            if (RB_PARENT(elm, field) && (elm == RB_RIGHT(RB_PARENT(elm, field), field)))          \ +                elm = RB_PARENT(elm, field);                                                       \ +            else {                                                                                 \ +                while (RB_PARENT(elm, field) && (elm == RB_LEFT(RB_PARENT(elm, field), field)))    \ +                    elm = RB_PARENT(elm, field);                                                   \ +                elm = RB_PARENT(elm, field);                                                       \ +            }                                                                                      \ +        }                                                                                          \ +        return (elm);                                                                              \ +    } + +#define RB_GENERATE_MINMAX(name, type, field, attr)                                                \ +    attr struct type* name##_RB_MINMAX(struct name* head, int val) {                               \ +        struct type* tmp = RB_ROOT(head);                                                          \ +        struct type* parent = NULL;                                                                \ +        while (tmp) {                                                                              \ +            parent = tmp;                                                                          \ +            if (val < 0)                                                                           \ +                tmp = RB_LEFT(tmp, field);                                                         \ +            else                                                                                   \ +                tmp = RB_RIGHT(tmp, field);                                                        \ +        }                                                                                          \ +        return (parent);                                                                           \ +    } + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_FIND_LIGHT(name, x, y) name##_RB_FIND_LIGHT(x, y) +#define RB_NFIND_LIGHT(name, x, y) name##_RB_NFIND_LIGHT(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head)                                                                  \ +    for ((x) = RB_MIN(name, head); (x) != NULL; (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_FROM(x, name, y)                                                                \ +    for ((x) = (y); ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); (x) = (y)) + +#define RB_FOREACH_SAFE(x, name, head, y)                                                          \ +    for ((x) = RB_MIN(name, head); ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL);        \ +         (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head)                                                          \ +    for ((x) = RB_MAX(name, head); (x) != NULL; (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_FROM(x, name, y)                                                        \ +    for ((x) = (y); ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); (x) = (y)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y)                                                  \ +    for ((x) = RB_MAX(name, head); ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL);        \ +         (x) = (y)) + +#endif /* _SYS_TREE_H_ */ | 
