From 57b6c71c1c2661cefcde6b9c356ef8d3f5915687 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 20 Apr 2021 16:56:33 -0700 Subject: [PATCH] util: implement red black trees as templates over macros --- .../include/mesosphere/kern_k_thread.hpp | 8 +- .../source/kern_k_address_arbiter.cpp | 6 +- .../source/kern_k_condition_variable.cpp | 2 +- .../libvapours/include/freebsd/sys/tree.h | 877 ------------------ .../include/vapours/freebsd/tree.hpp | 623 +++++++++++++ .../util/util_intrusive_red_black_tree.hpp | 311 +++---- 6 files changed, 787 insertions(+), 1040 deletions(-) delete mode 100644 libraries/libvapours/include/freebsd/sys/tree.h create mode 100644 libraries/libvapours/include/vapours/freebsd/tree.hpp diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 27ffe1a2a..63fa28b38 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -136,7 +136,7 @@ namespace ams::kern { static_assert(sizeof(SyncObjectBuffer::m_sync_objects) == sizeof(SyncObjectBuffer::m_handles)); struct ConditionVariableComparator { - struct LightCompareType { + struct RedBlackKeyType { uintptr_t m_cv_key; s32 m_priority; @@ -149,7 +149,7 @@ namespace ams::kern { } }; - template requires (std::same_as || std::same_as) + template requires (std::same_as || std::same_as) static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) { const uintptr_t l_key = lhs.GetConditionVariableKey(); const uintptr_t r_key = rhs.GetConditionVariableKey(); @@ -165,8 +165,8 @@ namespace ams::kern { } } }; - static_assert(ams::util::HasLightCompareType); - static_assert(std::same_as, ConditionVariableComparator::LightCompareType>); + static_assert(ams::util::HasRedBlackKeyType); + static_assert(std::same_as, ConditionVariableComparator::RedBlackKeyType>); private: static inline std::atomic s_next_thread_id = 0; private: diff --git a/libraries/libmesosphere/source/kern_k_address_arbiter.cpp b/libraries/libmesosphere/source/kern_k_address_arbiter.cpp index fa554ea25..32d443709 100644 --- a/libraries/libmesosphere/source/kern_k_address_arbiter.cpp +++ b/libraries/libmesosphere/source/kern_k_address_arbiter.cpp @@ -51,7 +51,7 @@ namespace ams::kern { { KScopedSchedulerLock sl; - auto it = m_tree.nfind_light({ addr, -1 }); + auto it = m_tree.nfind_key({ addr, -1 }); while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { KThread *target_thread = std::addressof(*it); target_thread->SetSyncedObject(nullptr, ResultSuccess()); @@ -78,7 +78,7 @@ namespace ams::kern { R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory()); R_UNLESS(user_value == value, svc::ResultInvalidState()); - auto it = m_tree.nfind_light({ addr, -1 }); + auto it = m_tree.nfind_key({ addr, -1 }); while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { KThread *target_thread = std::addressof(*it); target_thread->SetSyncedObject(nullptr, ResultSuccess()); @@ -100,7 +100,7 @@ namespace ams::kern { { KScopedSchedulerLock sl; - auto it = m_tree.nfind_light({ addr, -1 }); + auto it = m_tree.nfind_key({ addr, -1 }); /* Determine the updated value. */ s32 new_value; if (GetTargetFirmware() >= TargetFirmware_7_0_0) { diff --git a/libraries/libmesosphere/source/kern_k_condition_variable.cpp b/libraries/libmesosphere/source/kern_k_condition_variable.cpp index 7e9a4499f..2bc353b9f 100644 --- a/libraries/libmesosphere/source/kern_k_condition_variable.cpp +++ b/libraries/libmesosphere/source/kern_k_condition_variable.cpp @@ -168,7 +168,7 @@ namespace ams::kern { { KScopedSchedulerLock sl; - auto it = m_tree.nfind_light({ cv_key, -1 }); + auto it = m_tree.nfind_key({ cv_key, -1 }); while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetConditionVariableKey() == cv_key)) { KThread *target_thread = std::addressof(*it); diff --git a/libraries/libvapours/include/freebsd/sys/tree.h b/libraries/libvapours/include/freebsd/sys/tree.h deleted file mode 100644 index 7cfaf1330..000000000 --- a/libraries/libvapours/include/freebsd/sys/tree.h +++ /dev/null @@ -1,877 +0,0 @@ -/* $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 - * 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 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 */ - -#ifndef __inline -#define __inline inline -#endif - -#ifndef __unused -#define __unused __attribute__((__unused__)) -#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, __unused 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, __unused 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, __unused 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, __unused 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_ */ diff --git a/libraries/libvapours/include/vapours/freebsd/tree.hpp b/libraries/libvapours/include/vapours/freebsd/tree.hpp new file mode 100644 index 000000000..c174c54a0 --- /dev/null +++ b/libraries/libvapours/include/vapours/freebsd/tree.hpp @@ -0,0 +1,623 @@ +/* $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 + * 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. + */ +#pragma once +#include +#include + +#pragma GCC push_options +#pragma GCC optimize ("-O3") + +/* + * This file defines data structures for red-black trees. + * + * 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). + */ + +namespace ams::freebsd { + + enum class RBColor { + RB_BLACK = 0, + RB_RED = 1, + }; + + template + class RBEntry { + private: + T *rbe_left = nullptr; + T *rbe_right = nullptr; + T *rbe_parent = nullptr; + RBColor rbe_color = RBColor::RB_BLACK; + public: + [[nodiscard]] constexpr ALWAYS_INLINE T *Left() { return this->rbe_left; } + [[nodiscard]] constexpr ALWAYS_INLINE const T *Left() const { return this->rbe_left; } + + ALWAYS_INLINE void SetLeft(T *e) { this->rbe_left = e; } + + [[nodiscard]] constexpr ALWAYS_INLINE T *Right() { return this->rbe_right; } + [[nodiscard]] constexpr ALWAYS_INLINE const T *Right() const { return this->rbe_right; } + + ALWAYS_INLINE void SetRight(T *e) { this->rbe_right = e; } + + [[nodiscard]] constexpr ALWAYS_INLINE T *Parent() { return this->rbe_parent; } + [[nodiscard]] constexpr ALWAYS_INLINE const T *Parent() const { return this->rbe_parent; } + + ALWAYS_INLINE void SetParent(T *e) { this->rbe_parent = e; } + + [[nodiscard]] constexpr ALWAYS_INLINE bool IsBlack() const { return this->rbe_color == RBColor::RB_BLACK; } + [[nodiscard]] constexpr ALWAYS_INLINE bool IsRed() const { return this->rbe_color == RBColor::RB_RED; } + [[nodiscard]] constexpr ALWAYS_INLINE RBColor Color() const { return this->rbe_color; } + + ALWAYS_INLINE void SetColor(RBColor c) { this->rbe_color = c; } + }; + + template struct CheckRBEntry { static constexpr bool value = false; }; + template struct CheckRBEntry> { static constexpr bool value = true; }; + + template + concept IsRBEntry = CheckRBEntry::value; + + template + concept HasRBEntry = requires (T &t, const T &ct) { + { t.GetRBEntry() } -> std::same_as< RBEntry &>; + { ct.GetRBEntry() } -> std::same_as &>; + }; + + template requires HasRBEntry + class RBHead { + private: + T *rbh_root = nullptr; + public: + [[nodiscard]] constexpr ALWAYS_INLINE T *Root() { return this->rbh_root; } + [[nodiscard]] constexpr ALWAYS_INLINE const T *Root() const { return this->rbh_root; } + ALWAYS_INLINE void SetRoot(T *root) { this->rbh_root = root; } + + [[nodiscard]] constexpr ALWAYS_INLINE bool IsEmpty() const { return this->Root() == nullptr; } + }; + + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE RBEntry &RB_ENTRY( T *t) { return t->GetRBEntry(); } + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE const RBEntry &RB_ENTRY(const T *t) { return t->GetRBEntry(); } + + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE T *RB_LEFT( T *t) { return RB_ENTRY(t).Left(); } + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE const T *RB_LEFT(const T *t) { return RB_ENTRY(t).Left(); } + + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE T *RB_RIGHT( T *t) { return RB_ENTRY(t).Right(); } + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE const T *RB_RIGHT(const T *t) { return RB_ENTRY(t).Right(); } + + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE T *RB_PARENT( T *t) { return RB_ENTRY(t).Parent(); } + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE const T *RB_PARENT(const T *t) { return RB_ENTRY(t).Parent(); } + + template requires HasRBEntry constexpr ALWAYS_INLINE void RB_SET_LEFT(T *t, T *e) { RB_ENTRY(t).SetLeft(e); } + template requires HasRBEntry constexpr ALWAYS_INLINE void RB_SET_RIGHT(T *t, T *e) { RB_ENTRY(t).SetRight(e); } + template requires HasRBEntry constexpr ALWAYS_INLINE void RB_SET_PARENT(T *t, T *e) { RB_ENTRY(t).SetParent(e); } + + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE bool RB_IS_BLACK(const T *t) { return RB_ENTRY(t).IsBlack(); } + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE bool RB_IS_RED(const T *t) { return RB_ENTRY(t).IsRed(); } + + template requires HasRBEntry [[nodiscard]] constexpr ALWAYS_INLINE RBColor RB_COLOR(const T *t) { return RB_ENTRY(t).Color(); } + + template requires HasRBEntry constexpr ALWAYS_INLINE void RB_SET_COLOR(T *t, RBColor c) { RB_ENTRY(t).SetColor(c); } + + template requires HasRBEntry + constexpr ALWAYS_INLINE void RB_SET(T *elm, T *parent) { + auto &rb_entry = RB_ENTRY(elm); + rb_entry.SetParent(parent); + rb_entry.SetLeft(nullptr); + rb_entry.SetRight(nullptr); + rb_entry.SetColor(RBColor::RB_RED); + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE void RB_SET_BLACKRED(T *black, T *red) { + RB_SET_COLOR(black, RBColor::RB_BLACK); + RB_SET_COLOR(red, RBColor::RB_RED); + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE void RB_ROTATE_LEFT(RBHead &head, T *elm, T *&tmp) { + tmp = RB_RIGHT(elm); + if (RB_SET_RIGHT(elm, RB_LEFT(tmp)); RB_RIGHT(elm) != nullptr) { + RB_SET_PARENT(RB_LEFT(tmp), elm); + } + + if (RB_SET_PARENT(tmp, RB_PARENT(elm)); RB_PARENT(tmp) != nullptr) { + if (elm == RB_LEFT(RB_PARENT(elm))) { + RB_SET_LEFT(RB_PARENT(elm), tmp); + } else { + RB_SET_RIGHT(RB_PARENT(elm), tmp); + } + } else { + head.SetRoot(tmp); + } + + RB_SET_LEFT(tmp, elm); + RB_SET_PARENT(elm, tmp); + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE void RB_ROTATE_RIGHT(RBHead &head, T *elm, T *&tmp) { + tmp = RB_LEFT(elm); + if (RB_SET_LEFT(elm, RB_RIGHT(tmp)); RB_LEFT(elm) != nullptr) { + RB_SET_PARENT(RB_RIGHT(tmp), elm); + } + + if (RB_SET_PARENT(tmp, RB_PARENT(elm)); RB_PARENT(tmp) != nullptr) { + if (elm == RB_LEFT(RB_PARENT(elm))) { + RB_SET_LEFT(RB_PARENT(elm), tmp); + } else { + RB_SET_RIGHT(RB_PARENT(elm), tmp); + } + } else { + head.SetRoot(tmp); + } + + RB_SET_RIGHT(tmp, elm); + RB_SET_PARENT(elm, tmp); + } + + template requires HasRBEntry + constexpr void RB_INSERT_COLOR(RBHead &head, T *elm) { + T *parent = nullptr, *tmp = nullptr; + while ((parent = RB_PARENT(elm)) != nullptr && RB_IS_RED(parent)) { + T *gparent = RB_PARENT(parent); + if (parent == RB_LEFT(gparent)) { + tmp = RB_RIGHT(gparent); + if (tmp && RB_IS_RED(tmp)) { + RB_SET_COLOR(tmp, RBColor::RB_BLACK); + RB_SET_BLACKRED(parent, gparent); + elm = gparent; + continue; + } + + if (RB_RIGHT(parent) == elm) { + RB_ROTATE_LEFT(head, parent, tmp); + tmp = parent; + parent = elm; + elm = tmp; + } + + RB_SET_BLACKRED(parent, gparent); + RB_ROTATE_RIGHT(head, gparent, tmp); + } else { + tmp = RB_LEFT(gparent); + if (tmp && RB_IS_RED(tmp)) { + RB_SET_COLOR(tmp, RBColor::RB_BLACK); + RB_SET_BLACKRED(parent, gparent); + elm = gparent; + continue; + } + + if (RB_LEFT(parent) == elm) { + RB_ROTATE_RIGHT(head, parent, tmp); + tmp = parent; + parent = elm; + elm = tmp; + } + + RB_SET_BLACKRED(parent, gparent); + RB_ROTATE_LEFT(head, gparent, tmp); + } + } + + RB_SET_COLOR(head.Root(), RBColor::RB_BLACK); + } + + template requires HasRBEntry + constexpr void RB_REMOVE_COLOR(RBHead &head, T *parent, T *elm) { + T *tmp; + while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head.Root()) { + if (RB_LEFT(parent) == elm) { + tmp = RB_RIGHT(parent); + if (RB_IS_RED(tmp)) { + RB_SET_BLACKRED(tmp, parent); + RB_ROTATE_LEFT(head, parent, tmp); + tmp = RB_RIGHT(parent); + } + + if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) && + (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) { + RB_SET_COLOR(tmp, RBColor::RB_RED); + elm = parent; + parent = RB_PARENT(elm); + } else { + if (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp))) { + T *oleft; + if ((oleft = RB_LEFT(tmp)) != nullptr) { + RB_SET_COLOR(oleft, RBColor::RB_BLACK); + } + + RB_SET_COLOR(tmp, RBColor::RB_RED); + RB_ROTATE_RIGHT(head, tmp, oleft); + tmp = RB_RIGHT(parent); + } + + RB_SET_COLOR(tmp, RB_COLOR(parent)); + RB_SET_COLOR(parent, RBColor::RB_BLACK); + if (RB_RIGHT(tmp)) { + RB_SET_COLOR(RB_RIGHT(tmp), RBColor::RB_BLACK); + } + + RB_ROTATE_LEFT(head, parent, tmp); + elm = head.Root(); + break; + } + } else { + tmp = RB_LEFT(parent); + if (RB_IS_RED(tmp)) { + RB_SET_BLACKRED(tmp, parent); + RB_ROTATE_RIGHT(head, parent, tmp); + tmp = RB_LEFT(parent); + } + + if ((RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) && + (RB_RIGHT(tmp) == nullptr || RB_IS_BLACK(RB_RIGHT(tmp)))) { + RB_SET_COLOR(tmp, RBColor::RB_RED); + elm = parent; + parent = RB_PARENT(elm); + } else { + if (RB_LEFT(tmp) == nullptr || RB_IS_BLACK(RB_LEFT(tmp))) { + T *oright; + if ((oright = RB_RIGHT(tmp)) != nullptr) { + RB_SET_COLOR(oright, RBColor::RB_BLACK); + } + + RB_SET_COLOR(tmp, RBColor::RB_RED); + RB_ROTATE_LEFT(head, tmp, oright); + tmp = RB_LEFT(parent); + } + + RB_SET_COLOR(tmp, RB_COLOR(parent)); + RB_SET_COLOR(parent, RBColor::RB_BLACK); + + if (RB_LEFT(tmp)) { + RB_SET_COLOR(RB_LEFT(tmp), RBColor::RB_BLACK); + } + + RB_ROTATE_RIGHT(head, parent, tmp); + elm = head.Root(); + break; + } + } + } + + if (elm) { + RB_SET_COLOR(elm, RBColor::RB_BLACK); + } + } + + template requires HasRBEntry + constexpr T *RB_REMOVE(RBHead &head, T *elm) { + T *child = nullptr; + T *parent = nullptr; + T *old = elm; + RBColor color = RBColor::RB_BLACK; + + if (RB_LEFT(elm) == nullptr) { + child = RB_RIGHT(elm); + } else if (RB_RIGHT(elm) == nullptr) { + child = RB_LEFT(elm); + } else { + T *left; + elm = RB_RIGHT(elm); + while ((left = RB_LEFT(elm)) != nullptr) { + elm = left; + } + + child = RB_RIGHT(elm); + parent = RB_PARENT(elm); + color = RB_COLOR(elm); + + if (child) { + RB_SET_PARENT(child, parent); + } + + if (parent) { + if (RB_LEFT(parent) == elm) { + RB_SET_LEFT(parent, child); + } else { + RB_SET_RIGHT(parent, child); + } + } else { + head.SetRoot(child); + } + + if (RB_PARENT(elm) == old) { + parent = elm; + } + + elm->SetRBEntry(old->GetRBEntry()); + + if (RB_PARENT(old)) { + if (RB_LEFT(RB_PARENT(old)) == old) { + RB_SET_LEFT(RB_PARENT(old), elm); + } else { + RB_SET_RIGHT(RB_PARENT(old), elm); + } + } else { + head.SetRoot(elm); + } + + RB_SET_PARENT(RB_LEFT(old), elm); + + if (RB_RIGHT(old)) { + RB_SET_PARENT(RB_RIGHT(old), elm); + } + + if (parent) { + left = parent; + } + + if (color == RBColor::RB_BLACK) { + RB_REMOVE_COLOR(head, parent, child); + } + + return old; + } + + parent = RB_PARENT(elm); + color = RB_COLOR(elm); + + if (child) { + RB_SET_PARENT(child, parent); + } + if (parent) { + if (RB_LEFT(parent) == elm) { + RB_SET_LEFT(parent, child); + } else { + RB_SET_RIGHT(parent, child); + } + } else { + head.SetRoot(child); + } + + if (color == RBColor::RB_BLACK) { + RB_REMOVE_COLOR(head, parent, child); + } + + return old; + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_INSERT(RBHead &head, T *elm, Compare cmp) { + T *parent = nullptr; + T *tmp = head.Root(); + int comp = 0; + + while (tmp) { + parent = tmp; + comp = cmp(elm, parent); + if (comp < 0) { + tmp = RB_LEFT(tmp); + } else if (comp > 0) { + tmp = RB_RIGHT(tmp); + } else { + return tmp; + } + } + + RB_SET(elm, parent); + + if (parent != nullptr) { + if (comp < 0) { + RB_SET_LEFT(parent, elm); + } else { + RB_SET_RIGHT(parent, elm); + } + } else { + head.SetRoot(elm); + } + + RB_INSERT_COLOR(head, elm); + return nullptr; + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_FIND(RBHead &head, T *elm, Compare cmp) { + T *tmp = head.Root(); + + while (tmp) { + const int comp = cmp(elm, tmp); + if (comp < 0) { + tmp = RB_LEFT(tmp); + } else if (comp > 0) { + tmp = RB_RIGHT(tmp); + } else { + return tmp; + } + } + + return nullptr; + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_NFIND(RBHead &head, T *elm, Compare cmp) { + T *tmp = head.Root(); + T* res = nullptr; + + while (tmp) { + const int comp = cmp(elm, tmp); + if (comp < 0) { + res = tmp; + tmp = RB_LEFT(tmp); + } else if (comp > 0) { + tmp = RB_RIGHT(tmp); + } else { + return tmp; + } + } + + return res; + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_FIND_KEY(RBHead &head, const U &key, Compare cmp) { + T *tmp = head.Root(); + + while (tmp) { + const int comp = cmp(key, tmp); + if (comp < 0) { + tmp = RB_LEFT(tmp); + } else if (comp > 0) { + tmp = RB_RIGHT(tmp); + } else { + return tmp; + } + } + + return nullptr; + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_NFIND_KEY(RBHead &head, const U &key, Compare cmp) { + T *tmp = head.Root(); + T* res = nullptr; + + while (tmp) { + const int comp = cmp(key, tmp); + if (comp < 0) { + res = tmp; + tmp = RB_LEFT(tmp); + } else if (comp > 0) { + tmp = RB_RIGHT(tmp); + } else { + return tmp; + } + } + + return res; + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_FIND_EXISTING(RBHead &head, T *elm, Compare cmp) { + T *tmp = head.Root(); + + while (true) { + const int comp = cmp(elm, tmp); + if (comp < 0) { + tmp = RB_LEFT(tmp); + } else if (comp > 0) { + tmp = RB_RIGHT(tmp); + } else { + return tmp; + } + } + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_FIND_EXISTING_KEY(RBHead &head, const U &key, Compare cmp) { + T *tmp = head.Root(); + + while (true) { + const int comp = cmp(key, tmp); + if (comp < 0) { + tmp = RB_LEFT(tmp); + } else if (comp > 0) { + tmp = RB_RIGHT(tmp); + } else { + return tmp; + } + } + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_NEXT(T *elm) { + if (RB_RIGHT(elm)) { + elm = RB_RIGHT(elm); + while (RB_LEFT(elm)) { + elm = RB_LEFT(elm); + } + } else { + if (RB_PARENT(elm) && (elm == RB_LEFT(RB_PARENT(elm)))) { + elm = RB_PARENT(elm); + } else { + while (RB_PARENT(elm) && (elm == RB_RIGHT(RB_PARENT(elm)))) { + elm = RB_PARENT(elm); + } + elm = RB_PARENT(elm); + } + } + return elm; + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_PREV(T *elm) { + if (RB_LEFT(elm)) { + elm = RB_LEFT(elm); + while (RB_RIGHT(elm)) { + elm = RB_RIGHT(elm); + } + } else { + if (RB_PARENT(elm) && (elm == RB_RIGHT(RB_PARENT(elm)))) { + elm = RB_PARENT(elm); + } else { + while (RB_PARENT(elm) && (elm == RB_LEFT(RB_PARENT(elm)))) { + elm = RB_PARENT(elm); + } + elm = RB_PARENT(elm); + } + } + return elm; + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_MIN(RBHead &head) { + T *tmp = head.Root(); + T *parent = nullptr; + + while (tmp) { + parent = tmp; + tmp = RB_LEFT(tmp); + } + + return parent; + } + + template requires HasRBEntry + constexpr ALWAYS_INLINE T *RB_MAX(RBHead &head) { + T *tmp = head.Root(); + T *parent = nullptr; + + while (tmp) { + parent = tmp; + tmp = RB_RIGHT(tmp); + } + + return parent; + } + + +} + +#pragma GCC pop_options diff --git a/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp b/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp index f43b2fc0b..c44cab756 100644 --- a/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp +++ b/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp @@ -15,10 +15,10 @@ */ #pragma once -#include #include #include #include +#include namespace ams::util { @@ -33,17 +33,18 @@ namespace ams::util { struct IntrusiveRedBlackTreeNode { NON_COPYABLE(IntrusiveRedBlackTreeNode); - private: - RB_ENTRY(IntrusiveRedBlackTreeNode) entry; - - friend class impl::IntrusiveRedBlackTreeImpl; - - template - friend class IntrusiveRedBlackTree; public: - constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode() : entry() { /* ... */} + using RBEntry = freebsd::RBEntry; + private: + RBEntry m_entry; + public: + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode() = default; + + [[nodiscard]] constexpr ALWAYS_INLINE RBEntry &GetRBEntry() { return m_entry; } + [[nodiscard]] constexpr ALWAYS_INLINE const RBEntry &GetRBEntry() const { return m_entry; } + + constexpr ALWAYS_INLINE void SetRBEntry(const RBEntry &entry) { m_entry = entry; } }; - static_assert(std::is_literal_type::value); template class IntrusiveRedBlackTree; @@ -56,10 +57,9 @@ namespace ams::util { template friend class ::ams::util::IntrusiveRedBlackTree; private: - RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode); - using RootType = IntrusiveRedBlackTreeRoot; + using RootType = freebsd::RBHead; private: - IntrusiveRedBlackTreeRoot root; + RootType m_root; public: template class Iterator; @@ -83,152 +83,142 @@ namespace ams::util { using pointer = typename std::conditional::type; using reference = typename std::conditional::type; private: - pointer node; + pointer m_node; public: - explicit ALWAYS_INLINE Iterator(pointer n) : node(n) { /* ... */ } + constexpr explicit ALWAYS_INLINE Iterator(pointer n) : m_node(n) { /* ... */ } - ALWAYS_INLINE bool operator==(const Iterator &rhs) const { - return this->node == rhs.node; + constexpr ALWAYS_INLINE bool operator==(const Iterator &rhs) const { + return m_node == rhs.m_node; } - ALWAYS_INLINE bool operator!=(const Iterator &rhs) const { + constexpr ALWAYS_INLINE bool operator!=(const Iterator &rhs) const { return !(*this == rhs); } - ALWAYS_INLINE pointer operator->() const { - return this->node; + constexpr ALWAYS_INLINE pointer operator->() const { + return m_node; } - ALWAYS_INLINE reference operator*() const { - return *this->node; + constexpr ALWAYS_INLINE reference operator*() const { + return *m_node; } - ALWAYS_INLINE Iterator &operator++() { - this->node = GetNext(this->node); + constexpr ALWAYS_INLINE Iterator &operator++() { + m_node = GetNext(m_node); return *this; } - ALWAYS_INLINE Iterator &operator--() { - this->node = GetPrev(this->node); + constexpr ALWAYS_INLINE Iterator &operator--() { + m_node = GetPrev(m_node); return *this; } - ALWAYS_INLINE Iterator operator++(int) { + constexpr ALWAYS_INLINE Iterator operator++(int) { const Iterator it{*this}; ++(*this); return it; } - ALWAYS_INLINE Iterator operator--(int) { + constexpr ALWAYS_INLINE Iterator operator--(int) { const Iterator it{*this}; --(*this); return it; } - ALWAYS_INLINE operator Iterator() const { - return Iterator(this->node); + constexpr ALWAYS_INLINE operator Iterator() const { + return Iterator(m_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 ALWAYS_INLINE void InitializeImpl() { - RB_INIT(&this->root); + constexpr ALWAYS_INLINE bool EmptyImpl() const { + return m_root.IsEmpty(); } - ALWAYS_INLINE bool EmptyImpl() const { - return RB_EMPTY(&this->root); + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetMinImpl() const { + return freebsd::RB_MIN(const_cast(m_root)); } - ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetMinImpl() const { - return RB_MIN(IntrusiveRedBlackTreeRoot, const_cast(&this->root)); + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetMaxImpl() const { + return freebsd::RB_MAX(const_cast(m_root)); } - ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetMaxImpl() const { - return RB_MAX(IntrusiveRedBlackTreeRoot, const_cast(&this->root)); - } - - ALWAYS_INLINE IntrusiveRedBlackTreeNode *RemoveImpl(IntrusiveRedBlackTreeNode *node) { - return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node); + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *RemoveImpl(IntrusiveRedBlackTreeNode *node) { + return freebsd::RB_REMOVE(m_root, node); } public: - static ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetNext(IntrusiveRedBlackTreeNode *node) { - return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node); + static constexpr IntrusiveRedBlackTreeNode *GetNext(IntrusiveRedBlackTreeNode *node) { + return freebsd::RB_NEXT(node); } - static ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetPrev(IntrusiveRedBlackTreeNode *node) { - return RB_PREV(IntrusiveRedBlackTreeRoot, nullptr, node); + static constexpr IntrusiveRedBlackTreeNode *GetPrev(IntrusiveRedBlackTreeNode *node) { + return freebsd::RB_PREV(node); } - static ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNext(IntrusiveRedBlackTreeNode const *node) { + static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNext(IntrusiveRedBlackTreeNode const *node) { return static_cast(GetNext(const_cast(node))); } - static ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetPrev(IntrusiveRedBlackTreeNode const *node) { + static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetPrev(IntrusiveRedBlackTreeNode const *node) { return static_cast(GetPrev(const_cast(node))); } public: - ALWAYS_INLINE constexpr IntrusiveRedBlackTreeImpl() : root() { - this->InitializeImpl(); - } + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeImpl() = default; /* Iterator accessors. */ - ALWAYS_INLINE iterator begin() { + constexpr ALWAYS_INLINE iterator begin() { return iterator(this->GetMinImpl()); } - ALWAYS_INLINE const_iterator begin() const { + constexpr ALWAYS_INLINE const_iterator begin() const { return const_iterator(this->GetMinImpl()); } - ALWAYS_INLINE iterator end() { + constexpr ALWAYS_INLINE iterator end() { return iterator(static_cast(nullptr)); } - ALWAYS_INLINE const_iterator end() const { + constexpr ALWAYS_INLINE const_iterator end() const { return const_iterator(static_cast(nullptr)); } - ALWAYS_INLINE const_iterator cbegin() const { + constexpr ALWAYS_INLINE const_iterator cbegin() const { return this->begin(); } - ALWAYS_INLINE const_iterator cend() const { + constexpr ALWAYS_INLINE const_iterator cend() const { return this->end(); } - ALWAYS_INLINE iterator iterator_to(reference ref) { - return iterator(&ref); + constexpr ALWAYS_INLINE iterator iterator_to(reference ref) { + return iterator(std::addressof(ref)); } - ALWAYS_INLINE const_iterator iterator_to(const_reference ref) const { - return const_iterator(&ref); + constexpr ALWAYS_INLINE const_iterator iterator_to(const_reference ref) const { + return const_iterator(std::addressof(ref)); } /* Content management. */ - ALWAYS_INLINE bool empty() const { + constexpr ALWAYS_INLINE bool empty() const { return this->EmptyImpl(); } - ALWAYS_INLINE reference back() { + constexpr ALWAYS_INLINE reference back() { return *this->GetMaxImpl(); } - ALWAYS_INLINE const_reference back() const { + constexpr ALWAYS_INLINE const_reference back() const { return *this->GetMaxImpl(); } - ALWAYS_INLINE reference front() { + constexpr ALWAYS_INLINE reference front() { return *this->GetMinImpl(); } - ALWAYS_INLINE const_reference front() const { + constexpr ALWAYS_INLINE const_reference front() const { return *this->GetMinImpl(); } - ALWAYS_INLINE iterator erase(iterator it) { + constexpr ALWAYS_INLINE iterator erase(iterator it) { auto cur = std::addressof(*it); auto next = GetNext(cur); this->RemoveImpl(cur); @@ -239,16 +229,16 @@ namespace ams::util { } template - concept HasLightCompareType = requires { - { std::is_same::value } -> std::convertible_to; + concept HasRedBlackKeyType = requires { + { std::is_same::value } -> std::convertible_to; }; namespace impl { template - consteval auto *GetLightCompareType() { - if constexpr (HasLightCompareType) { - return static_cast(nullptr); + consteval auto *GetRedBlackKeyType() { + if constexpr (HasRedBlackKeyType) { + return static_cast(nullptr); } else { return static_cast(nullptr); } @@ -257,7 +247,7 @@ namespace ams::util { } template - using LightCompareType = typename std::remove_pointer())>::type; + using RedBlackKeyType = typename std::remove_pointer())>::type; template class IntrusiveRedBlackTree { @@ -265,10 +255,8 @@ namespace ams::util { public: using ImplType = impl::IntrusiveRedBlackTreeImpl; private: - ImplType impl; + ImplType m_impl; public: - struct IntrusiveRedBlackTreeRootWithCompare : ImplType::IntrusiveRedBlackTreeRoot{}; - template class Iterator; @@ -282,9 +270,9 @@ namespace ams::util { using iterator = Iterator; using const_iterator = Iterator; - using light_value_type = LightCompareType; - using const_light_pointer = const light_value_type *; - using const_light_reference = const light_value_type &; + using key_type = RedBlackKeyType; + using const_key_pointer = const key_type *; + using const_key_reference = const key_type &; template class Iterator { @@ -299,171 +287,184 @@ namespace ams::util { using pointer = typename std::conditional::type; using reference = typename std::conditional::type; private: - ImplIterator iterator; + ImplIterator m_impl; private: - explicit ALWAYS_INLINE Iterator(ImplIterator it) : iterator(it) { /* ... */ } + constexpr explicit ALWAYS_INLINE Iterator(ImplIterator it) : m_impl(it) { /* ... */ } - explicit ALWAYS_INLINE Iterator(ImplIterator::pointer p) : iterator(p) { /* ... */ } + constexpr explicit ALWAYS_INLINE Iterator(ImplIterator::pointer p) : m_impl(p) { /* ... */ } - ALWAYS_INLINE ImplIterator GetImplIterator() const { - return this->iterator; + constexpr ALWAYS_INLINE ImplIterator GetImplIterator() const { + return m_impl; } public: - ALWAYS_INLINE bool operator==(const Iterator &rhs) const { - return this->iterator == rhs.iterator; + constexpr ALWAYS_INLINE bool operator==(const Iterator &rhs) const { + return m_impl == rhs.m_impl; } - ALWAYS_INLINE bool operator!=(const Iterator &rhs) const { + constexpr ALWAYS_INLINE bool operator!=(const Iterator &rhs) const { return !(*this == rhs); } - ALWAYS_INLINE pointer operator->() const { - return Traits::GetParent(std::addressof(*this->iterator)); + constexpr ALWAYS_INLINE pointer operator->() const { + return Traits::GetParent(std::addressof(*m_impl)); } - ALWAYS_INLINE reference operator*() const { - return *Traits::GetParent(std::addressof(*this->iterator)); + constexpr ALWAYS_INLINE reference operator*() const { + return *Traits::GetParent(std::addressof(*m_impl)); } - ALWAYS_INLINE Iterator &operator++() { - ++this->iterator; + constexpr ALWAYS_INLINE Iterator &operator++() { + ++m_impl; return *this; } - ALWAYS_INLINE Iterator &operator--() { - --this->iterator; + constexpr ALWAYS_INLINE Iterator &operator--() { + --m_impl; return *this; } - ALWAYS_INLINE Iterator operator++(int) { + constexpr ALWAYS_INLINE Iterator operator++(int) { const Iterator it{*this}; - ++this->iterator; + ++m_impl; return it; } - ALWAYS_INLINE Iterator operator--(int) { + constexpr ALWAYS_INLINE Iterator operator--(int) { const Iterator it{*this}; - --this->iterator; + --m_impl; return it; } - ALWAYS_INLINE operator Iterator() const { - return Iterator(this->iterator); + constexpr ALWAYS_INLINE operator Iterator() const { + return Iterator(m_impl); } }; private: - /* Generate static implementations for comparison operations for IntrusiveRedBlackTreeRoot. */ - RB_GENERATE_WITH_COMPARE_STATIC(IntrusiveRedBlackTreeRootWithCompare, IntrusiveRedBlackTreeNode, entry, CompareImpl, LightCompareImpl); - private: - static ALWAYS_INLINE int CompareImpl(const IntrusiveRedBlackTreeNode *lhs, const IntrusiveRedBlackTreeNode *rhs) { + static constexpr ALWAYS_INLINE int CompareImpl(const IntrusiveRedBlackTreeNode *lhs, const IntrusiveRedBlackTreeNode *rhs) { return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs)); } - static ALWAYS_INLINE int LightCompareImpl(const void *elm, const IntrusiveRedBlackTreeNode *rhs) { - return Comparator::Compare(*static_cast(elm), *Traits::GetParent(rhs)); + static constexpr ALWAYS_INLINE int CompareKeyImpl(const_key_reference key, const IntrusiveRedBlackTreeNode *rhs) { + return Comparator::Compare(key, *Traits::GetParent(rhs)); } /* Define accessors using RB_* functions. */ - ALWAYS_INLINE IntrusiveRedBlackTreeNode *InsertImpl(IntrusiveRedBlackTreeNode *node) { - return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare, static_cast(&this->impl.root), node); + constexpr IntrusiveRedBlackTreeNode *InsertImpl(IntrusiveRedBlackTreeNode *node) { + return freebsd::RB_INSERT(m_impl.m_root, node, CompareImpl); } - ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindImpl(IntrusiveRedBlackTreeNode const *node) const { - return RB_FIND(IntrusiveRedBlackTreeRootWithCompare, const_cast(static_cast(&this->impl.root)), const_cast(node)); + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindImpl(IntrusiveRedBlackTreeNode const *node) const { + return freebsd::RB_FIND(const_cast(m_impl.m_root), const_cast(node), CompareImpl); } - ALWAYS_INLINE IntrusiveRedBlackTreeNode *NFindImpl(IntrusiveRedBlackTreeNode const *node) const { - return RB_NFIND(IntrusiveRedBlackTreeRootWithCompare, const_cast(static_cast(&this->impl.root)), const_cast(node)); + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *NFindImpl(IntrusiveRedBlackTreeNode const *node) const { + return freebsd::RB_NFIND(const_cast(m_impl.m_root), const_cast(node), CompareImpl); } - ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindLightImpl(const_light_pointer lelm) const { - return RB_FIND_LIGHT(IntrusiveRedBlackTreeRootWithCompare, const_cast(static_cast(&this->impl.root)), static_cast(lelm)); + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindKeyImpl(const_key_reference key) const { + return freebsd::RB_FIND_KEY(const_cast(m_impl.m_root), key, CompareKeyImpl); } - ALWAYS_INLINE IntrusiveRedBlackTreeNode *NFindLightImpl(const_light_pointer lelm) const { - return RB_NFIND_LIGHT(IntrusiveRedBlackTreeRootWithCompare, const_cast(static_cast(&this->impl.root)), static_cast(lelm)); + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *NFindKeyImpl(const_key_reference key) const { + return freebsd::RB_NFIND_KEY(const_cast(m_impl.m_root), key, CompareKeyImpl); + } + + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindExistingImpl(IntrusiveRedBlackTreeNode const *node) const { + return freebsd::RB_FIND_EXISTING(const_cast(m_impl.m_root), const_cast(node), CompareImpl); + } + + constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindExistingKeyImpl(const_key_reference key) const { + return freebsd::RB_FIND_EXISTING_KEY(const_cast(m_impl.m_root), key, CompareKeyImpl); } public: - constexpr ALWAYS_INLINE IntrusiveRedBlackTree() : impl() { /* ... */ } + constexpr ALWAYS_INLINE IntrusiveRedBlackTree() = default; /* Iterator accessors. */ - ALWAYS_INLINE iterator begin() { - return iterator(this->impl.begin()); + constexpr ALWAYS_INLINE iterator begin() { + return iterator(m_impl.begin()); } - ALWAYS_INLINE const_iterator begin() const { - return const_iterator(this->impl.begin()); + constexpr ALWAYS_INLINE const_iterator begin() const { + return const_iterator(m_impl.begin()); } - ALWAYS_INLINE iterator end() { - return iterator(this->impl.end()); + constexpr ALWAYS_INLINE iterator end() { + return iterator(m_impl.end()); } - ALWAYS_INLINE const_iterator end() const { - return const_iterator(this->impl.end()); + constexpr ALWAYS_INLINE const_iterator end() const { + return const_iterator(m_impl.end()); } - ALWAYS_INLINE const_iterator cbegin() const { + constexpr ALWAYS_INLINE const_iterator cbegin() const { return this->begin(); } - ALWAYS_INLINE const_iterator cend() const { + constexpr ALWAYS_INLINE const_iterator cend() const { return this->end(); } - ALWAYS_INLINE iterator iterator_to(reference ref) { - return iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); + constexpr ALWAYS_INLINE iterator iterator_to(reference ref) { + return iterator(m_impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); } - ALWAYS_INLINE const_iterator iterator_to(const_reference ref) const { - return const_iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); + constexpr ALWAYS_INLINE const_iterator iterator_to(const_reference ref) const { + return const_iterator(m_impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); } /* Content management. */ - ALWAYS_INLINE bool empty() const { - return this->impl.empty(); + constexpr ALWAYS_INLINE bool empty() const { + return m_impl.empty(); } - ALWAYS_INLINE reference back() { - return *Traits::GetParent(std::addressof(this->impl.back())); + constexpr ALWAYS_INLINE reference back() { + return *Traits::GetParent(std::addressof(m_impl.back())); } - ALWAYS_INLINE const_reference back() const { - return *Traits::GetParent(std::addressof(this->impl.back())); + constexpr ALWAYS_INLINE const_reference back() const { + return *Traits::GetParent(std::addressof(m_impl.back())); } - ALWAYS_INLINE reference front() { - return *Traits::GetParent(std::addressof(this->impl.front())); + constexpr ALWAYS_INLINE reference front() { + return *Traits::GetParent(std::addressof(m_impl.front())); } - ALWAYS_INLINE const_reference front() const { - return *Traits::GetParent(std::addressof(this->impl.front())); + constexpr ALWAYS_INLINE const_reference front() const { + return *Traits::GetParent(std::addressof(m_impl.front())); } - ALWAYS_INLINE iterator erase(iterator it) { - return iterator(this->impl.erase(it.GetImplIterator())); + constexpr ALWAYS_INLINE iterator erase(iterator it) { + return iterator(m_impl.erase(it.GetImplIterator())); } - ALWAYS_INLINE iterator insert(reference ref) { + constexpr ALWAYS_INLINE iterator insert(reference ref) { ImplType::pointer node = Traits::GetNode(std::addressof(ref)); this->InsertImpl(node); return iterator(node); } - ALWAYS_INLINE iterator find(const_reference ref) const { + constexpr ALWAYS_INLINE iterator find(const_reference ref) const { return iterator(this->FindImpl(Traits::GetNode(std::addressof(ref)))); } - ALWAYS_INLINE iterator nfind(const_reference ref) const { + constexpr ALWAYS_INLINE iterator nfind(const_reference ref) const { return iterator(this->NFindImpl(Traits::GetNode(std::addressof(ref)))); } - ALWAYS_INLINE iterator find_light(const_light_reference ref) const { - return iterator(this->FindLightImpl(std::addressof(ref))); + constexpr ALWAYS_INLINE iterator find_key(const_key_reference ref) const { + return iterator(this->FindKeyImpl(ref)); } - ALWAYS_INLINE iterator nfind_light(const_light_reference ref) const { - return iterator(this->NFindLightImpl(std::addressof(ref))); + constexpr ALWAYS_INLINE iterator nfind_key(const_key_reference ref) const { + return iterator(this->NFindKeyImpl(ref)); + } + + constexpr ALWAYS_INLINE iterator find_existing(const_reference ref) const { + return iterator(this->FindExistingImpl(Traits::GetNode(std::addressof(ref)))); + } + + constexpr ALWAYS_INLINE iterator find_existing_key(const_key_reference ref) const { + return iterator(this->FindExistingKeyImpl(ref)); } };