From d0adebfb278a17d05387e48502c0f723b777bc00 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 16 Jul 2019 23:06:12 -0700 Subject: [PATCH] util: Add Intrusive List/RBTree --- include/freebsd/sys/tree.h | 812 ++++++++++++++++++ include/meta_tools.hpp | 53 -- include/stratosphere/util.hpp | 2 + .../stratosphere/util/util_intrusive_list.hpp | 607 +++++++++++++ .../util/util_intrusive_red_black_tree.hpp | 301 +++++++ .../util/util_parent_of_member.hpp | 78 ++ include/stratosphere/waitable_manager.hpp | 3 +- 7 files changed, 1801 insertions(+), 55 deletions(-) create mode 100644 include/freebsd/sys/tree.h delete mode 100644 include/meta_tools.hpp create mode 100644 include/stratosphere/util/util_intrusive_list.hpp create mode 100644 include/stratosphere/util/util_intrusive_red_black_tree.hpp create mode 100644 include/stratosphere/util/util_parent_of_member.hpp diff --git a/include/freebsd/sys/tree.h b/include/freebsd/sys/tree.h new file mode 100644 index 00000000..fecde691 --- /dev/null +++ b/include/freebsd/sys/tree.h @@ -0,0 +1,812 @@ +/* $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_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_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(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ + RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ + RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ + RB_GENERATE_INSERT(name, type, field, cmp, attr) \ + RB_GENERATE_REMOVE(name, type, field, attr) \ + RB_GENERATE_FIND(name, type, field, cmp, attr) \ + RB_GENERATE_NFIND(name, type, field, cmp, 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_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_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_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/include/meta_tools.hpp b/include/meta_tools.hpp deleted file mode 100644 index 040680d1..00000000 --- a/include/meta_tools.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2018-2019 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -namespace detail { - -template -struct class_of; - -template -struct class_of { - using type = C; -}; - -template -using class_of_t = typename class_of::type; - -template> -struct member_equals_fn_helper { - T ref; - Mem mem_fn; - - bool operator()(const C& val) const { - return (std::mem_fn(mem_fn)(val) == ref); - } - - bool operator()(C&& val) const { - return (std::mem_fn(mem_fn)(std::move(val)) == ref); - } -}; - -} // namespace detail - -template -auto member_equals_fn(Mem mem, T ref) { - return detail::member_equals_fn_helper{std::move(ref), std::move(mem)}; -} diff --git a/include/stratosphere/util.hpp b/include/stratosphere/util.hpp index 8ef692a3..d33453d6 100644 --- a/include/stratosphere/util.hpp +++ b/include/stratosphere/util.hpp @@ -19,3 +19,5 @@ #include "util/util_compression.hpp" #include "util/util_ini.hpp" +#include "util/util_intrusive_list.hpp" +#include "util/util_intrusive_red_black_tree.hpp" diff --git a/include/stratosphere/util/util_intrusive_list.hpp b/include/stratosphere/util/util_intrusive_list.hpp new file mode 100644 index 00000000..00168503 --- /dev/null +++ b/include/stratosphere/util/util_intrusive_list.hpp @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include "../defines.hpp" + +#include "util_parent_of_member.hpp" + +namespace sts::util { + + /* Forward declare implementation class for Node. */ + namespace impl { + + class IntrusiveListImpl; + + } + + class IntrusiveListNode { + NON_COPYABLE(IntrusiveListNode); + private: + friend class impl::IntrusiveListImpl; + + IntrusiveListNode *prev; + IntrusiveListNode *next; + public: + IntrusiveListNode() { + this->prev = this; + this->next = this; + } + + bool IsLinked() const { + return this->next != this; + } + private: + void LinkPrev(IntrusiveListNode *node) { + /* We can't link an already linked node. */ + if (node->IsLinked()) { + std::abort(); + } + return this->SplicePrev(node, node); + } + + void SplicePrev(IntrusiveListNode *first, IntrusiveListNode *last) { + /* Splice a range into the list. */ + auto last_prev = last->prev; + first->prev = this->prev; + this->prev->next = first; + last_prev->next = this; + this->prev = last_prev; + } + + void LinkNext(IntrusiveListNode *node) { + /* We can't link an already linked node. */ + if (node->IsLinked()) { + std::abort(); + } + return this->SpliceNext(node, node); + } + + void SpliceNext(IntrusiveListNode *first, IntrusiveListNode *last) { + /* Splice a range into the list. */ + auto last_prev = last->prev; + first->prev = this; + this->next = first; + last_prev->next = next; + this->next->prev = last_prev; + } + + void Unlink() { + this->Unlink(this->next); + } + + void Unlink(IntrusiveListNode *last) { + /* Unlink a node from a next node. */ + auto last_prev = last->prev; + this->prev->next = last; + last->prev = this->prev; + last_prev->next = this; + this->prev = last_prev; + } + + IntrusiveListNode *GetPrev() { + return this->prev; + } + + const IntrusiveListNode *GetPrev() const { + return this->prev; + } + + IntrusiveListNode *GetNext() { + return this->prev; + } + + const IntrusiveListNode *GetNext() const { + return this->prev; + } + }; + + namespace impl { + + class IntrusiveListImpl { + NON_COPYABLE(IntrusiveListImpl); + private: + IntrusiveListNode root_node; + public: + template + class Iterator; + + using value_type = IntrusiveListNode; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = value_type *; + using const_pointer = const value_type *; + using reference = value_type &; + using const_reference = const value_type &; + using iterator = Iterator; + using const_iterator = Iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + template + class Iterator { + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename IntrusiveListImpl::value_type; + using difference_type = typename IntrusiveListImpl::difference_type; + using pointer = typename std::conditional::type; + using reference = typename std::conditional::type; + 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 = this->node->next; + return *this; + } + + Iterator &operator--() { + this->node = this->node->prev; + return *this; + } + + Iterator operator++(int) { + const Iterator it{*this}; + ++(*this); + return it; + } + + Iterator operator--(int) { + const Iterator it{*this}; + --(*this); + return it; + } + + operator Iterator() const { + return Iterator(this->node); + } + + Iterator GetNonConstIterator() const { + return Iterator(const_cast(this->node)); + } + }; + public: + IntrusiveListImpl() : root_node() { /* ... */ } + + /* Iterator accessors. */ + iterator begin() { + return iterator(this->root_node.GetNext()); + } + + const_iterator begin() const { + return const_iterator(this->root_node.GetNext()); + } + + iterator end() { + return iterator(&this->root_node); + } + + const_iterator end() const { + return const_iterator(&this->root_node); + } + + iterator iterator_to(reference v) { + /* Only allow iterator_to for values in lists. */ + if (!v.IsLinked()) { + std::abort(); + } + return iterator(&v); + } + + const_iterator iterator_to(const_reference v) const { + /* Only allow iterator_to for values in lists. */ + if (!v.IsLinked()) { + std::abort(); + } + return const_iterator(&v); + } + + /* Content management. */ + bool empty() const { + return !this->root_node.IsLinked(); + } + + size_type size() const { + return static_cast(std::distance(this->begin(), this->end())); + } + + reference back() { + return *this->root_node.GetPrev(); + } + + const_reference back() const { + return *this->root_node.GetPrev(); + } + + reference front() { + return *this->root_node.GetNext(); + } + + const_reference front() const { + return *this->root_node.GetNext(); + } + + void push_back(reference node) { + this->root_node.LinkPrev(&node); + } + + void push_front(reference node) { + this->root_node.LinkNext(&node); + } + + void pop_back() { + this->root_node.GetPrev()->Unlink(); + } + + void pop_front() { + this->root_node.GetNext()->Unlink(); + } + + iterator insert(const_iterator pos, reference node) { + pos.GetNonConstIterator()->LinkPrev(&node); + return iterator(&node); + } + + void splice(const_iterator pos, IntrusiveListImpl &o) { + splice_impl(pos, o.begin(), o.end()); + } + + void splice(const_iterator pos, IntrusiveListImpl &o, const_iterator first) { + const_iterator last(first); + std::advance(last, 1); + splice_impl(pos, first, last); + } + + void splice(const_iterator pos, IntrusiveListImpl &o, const_iterator first, const_iterator last) { + splice_impl(pos, first, last); + } + + iterator erase(const iterator pos) { + if (pos == this->end()) { + return this->end(); + } + iterator it(pos.GetNonConstIterator()); + (it++)->Unlink(); + return it; + } + + void clear() { + while (!this->empty()) { + this->pop_front(); + } + } + private: + void splice_impl(const_iterator _pos, const_iterator _first, const_iterator _last) { + if (_first == _last) { + return; + } + iterator pos(_pos.GetNonConstIterator()); + iterator first(_first.GetNonConstIterator()); + iterator last(_last.GetNonConstIterator()); + first->Unlink(&*last); + pos->SplicePrev(&*first, &*last); + } + + }; + + } + + template + class IntrusiveList { + NON_COPYABLE(IntrusiveList); + private: + impl::IntrusiveListImpl impl; + public: + template + class Iterator; + + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = value_type *; + using const_pointer = const value_type *; + using reference = value_type &; + using const_reference = const value_type &; + using iterator = Iterator; + using const_iterator = Iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + template + class Iterator { + public: + friend class sts::util::IntrusiveList; + + using ImplIterator = typename std::conditional::type; + + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename IntrusiveList::value_type; + using difference_type = typename IntrusiveList::difference_type; + using pointer = typename std::conditional::type; + using reference = typename std::conditional::type; + private: + ImplIterator iterator; + private: + explicit Iterator(ImplIterator it) : iterator(it) { /* ... */ } + + 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(*this->iterator); + } + + reference operator*() const { + return Traits::GetParent(*this->iterator); + } + + Iterator &operator++() { + ++this->iterator; + return *this; + } + + Iterator &operator--() { + --this->iterator; + return *this; + } + + Iterator operator++(int) { + const Iterator it{*this}; + ++this->iterator; + return it; + } + + Iterator operator--(int) { + const Iterator it{*this}; + --this->iterator; + return it; + } + + operator Iterator() const { + return Iterator(this->iterator); + } + }; + private: + static constexpr IntrusiveListNode &GetNode(reference ref) { + return Traits::GetNode(ref); + } + + static constexpr IntrusiveListNode const &GetNode(const_reference ref) { + return Traits::GetNode(ref); + } + + static constexpr reference GetParent(IntrusiveListNode &node) { + return Traits::GetParent(node); + } + + static constexpr const_reference GetParent(IntrusiveListNode const &node) { + return Traits::GetParent(node); + } + public: + IntrusiveList() : impl() { /* ... */ } + + /* 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(); + } + + reverse_iterator rbegin() { + return reverse_iterator(this->end()); + } + + const_reverse_iterator rbegin() const { + return const_reverse_iterator(this->end()); + } + + reverse_iterator rend() { + return reverse_iterator(this->begin()); + } + + const_reverse_iterator rend() const { + return const_reverse_iterator(this->begin()); + } + + const_reverse_iterator crbegin() const { + return this->rbegin(); + } + + const_reverse_iterator crend() const { + return this->rend(); + } + + iterator iterator_to(reference v) { + return iterator(this->impl.iterator_to(GetNode(v))); + } + + const_iterator iterator_to(const_reference v) const { + return const_iterator(this->impl.iterator_to(GetNode(v))); + } + + /* Content management. */ + bool empty() const { + return this->impl.empty(); + } + + size_type size() const { + return this->impl.size(); + } + + reference back() { + if (this->impl.empty()) { std::abort(); } + return this->impl.back(); + } + + const_reference back() const { + if (this->impl.empty()) { std::abort(); } + return this->impl.back(); + } + + reference front() { + if (this->impl.empty()) { std::abort(); } + return this->impl.front(); + } + + const_reference front() const { + if (this->impl.empty()) { std::abort(); } + return this->impl.front(); + } + + void push_back(reference ref) { + this->impl.push_back(GetNode(ref)); + } + + void push_front(reference ref) { + this->impl.push_back(GetNode(ref)); + } + + void pop_back() { + if (this->impl.empty()) { std::abort(); } + return this->impl.pop_back(); + } + + void pop_front() { + if (this->impl.empty()) { std::abort(); } + return this->impl.pop_front(); + } + + iterator insert(const_iterator pos, reference ref) { + return iterator(this->impl.insert(pos.GetImplIterator(), GetNode(ref))); + } + + void splice(const_iterator pos, IntrusiveList &o) { + this->impl.splice(pos.GetImplIterator(), o.impl); + } + + void splice(const_iterator pos, IntrusiveList &o, const_iterator first) { + this->impl.splice(pos.GetImplIterator(), o.impl, first.GetImplIterator()); + } + + void splice(const_iterator pos, IntrusiveList &o, const_iterator first, const_iterator last) { + this->impl.splice(pos.GetImplIterator(), o.impl, first.GetImplIterator(), last.GetImplIterator()); + } + + iterator erase(const iterator pos) { + return iterator(this->impl.erase(pos.GetImplIterator())); + } + + void clear() { + this->impl.clear(); + } + }; + + template> + class IntrusiveListMemberTraits; + + template + class IntrusiveListMemberTraits { + public: + using ListType = IntrusiveList; + private: + friend class IntrusiveList; + + static constexpr IntrusiveListNode &GetNode(Derived &parent) { + return parent.*Member; + } + + static constexpr IntrusiveListNode const &GetNode(Derived const &parent) { + return parent.*Member; + } + + static constexpr Derived &GetParent(IntrusiveListNode &node) { + return static_cast(util::GetParentReference(&node)); + } + + static constexpr Derived const &GetParent(IntrusiveListNode const &node) { + return static_cast(util::GetParentReference(&node)); + } + }; + + template + class IntrusiveListBaseNode : public IntrusiveListNode{}; + + template + class IntrusiveListBaseTraits { + public: + using ListType = IntrusiveList; + private: + friend class IntrusiveList; + + static constexpr IntrusiveListNode &GetNode(Derived &parent) { + return static_cast(parent); + } + + static constexpr IntrusiveListNode const &GetNode(Derived const &parent) { + return static_cast(parent); + } + + static constexpr Derived &GetParent(IntrusiveListNode &node) { + return static_cast(node); + } + + static constexpr Derived const &GetParent(IntrusiveListNode const &node) { + return static_cast(node); + } + }; + +} \ No newline at end of file diff --git a/include/stratosphere/util/util_intrusive_red_black_tree.hpp b/include/stratosphere/util/util_intrusive_red_black_tree.hpp new file mode 100644 index 00000000..eef85307 --- /dev/null +++ b/include/stratosphere/util/util_intrusive_red_black_tree.hpp @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include +#include "../defines.hpp" + +#include "util_parent_of_member.hpp" + +namespace sts::util { + + struct IntrusiveRedBlackTreeNode { + NON_COPYABLE(IntrusiveRedBlackTreeNode); + private: + RB_ENTRY(IntrusiveRedBlackTreeNode) entry; + + template + friend class IntrusiveRedBlackTree; + public: + IntrusiveRedBlackTreeNode() { /* ... */} + }; + + template + class IntrusiveRedBlackTree { + NON_COPYABLE(IntrusiveRedBlackTree); + private: + RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode); + + IntrusiveRedBlackTreeRoot root; + public: + template + class Iterator; + + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = T *; + using const_pointer = const T *; + using reference = T &; + using const_reference = const T &; + using iterator = Iterator; + using const_iterator = Iterator; + + template + class Iterator { + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename IntrusiveRedBlackTree::value_type; + using difference_type = typename IntrusiveRedBlackTree::difference_type; + using pointer = typename std::conditional::type; + using reference = typename std::conditional::type; + private: + 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 = Traits::GetParent(GetNext(Traits::GetNode(this->node))); + return *this; + } + + Iterator &operator--() { + this->node = Traits::GetParent(GetPrev(Traits::GetNode(this->node))); + return *this; + } + + Iterator operator++(int) { + const Iterator it{*this}; + ++(*this); + return it; + } + + Iterator operator--(int) { + const Iterator it{*this}; + --(*this); + return it; + } + + operator Iterator() const { + return Iterator(this->node); + } + }; + private: + static int CompareImpl(const IntrusiveRedBlackTreeNode *lhs, const IntrusiveRedBlackTreeNode *rhs) { + return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs)); + } + + /* Generate static implementations for IntrusiveRedBlackTreeRoot. */ + RB_GENERATE_STATIC(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode, entry, CompareImpl); + + static constexpr inline IntrusiveRedBlackTreeNode *GetNext(IntrusiveRedBlackTreeNode *node) { + return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node); + } + + static constexpr inline IntrusiveRedBlackTreeNode const *GetNext(IntrusiveRedBlackTreeNode const *node) { + return const_cast(GetNext(const_cast(node))); + } + + static constexpr inline IntrusiveRedBlackTreeNode *GetPrev(IntrusiveRedBlackTreeNode *node) { + return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node); + } + + static constexpr inline IntrusiveRedBlackTreeNode const *GetPrev(IntrusiveRedBlackTreeNode const *node) { + return const_cast(GetPrev(const_cast(node))); + } + + /* Define accessors using RB_* functions. */ + void InitializeImpl() { + RB_INIT(&this->root); + } + + bool EmptyImpl() const { + return RB_EMPTY(&this->root); + } + + IntrusiveRedBlackTreeNode *GetMinImpl() const { + return RB_MIN(IntrusiveRedBlackTreeRoot, const_cast(&this->root)); + } + + IntrusiveRedBlackTreeNode *GetMaxImpl() const { + return RB_MIN(IntrusiveRedBlackTreeRoot, const_cast(&this->root)); + } + + IntrusiveRedBlackTreeNode *InsertImpl(IntrusiveRedBlackTreeNode *node) { + return RB_INSERT(IntrusiveRedBlackTreeRoot, &this->root, node); + } + + IntrusiveRedBlackTreeNode *RemoveImpl(IntrusiveRedBlackTreeNode *node) { + return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node); + } + + IntrusiveRedBlackTreeNode *FindImpl(IntrusiveRedBlackTreeNode const *node) const { + return RB_FIND(IntrusiveRedBlackTreeRoot, const_cast(&this->root), const_cast(node)); + } + + IntrusiveRedBlackTreeNode *NFindImpl(IntrusiveRedBlackTreeNode const *node) const { + return RB_NFIND(IntrusiveRedBlackTreeRoot, const_cast(&this->root), const_cast(node)); + } + + public: + IntrusiveRedBlackTree() { + this->InitializeImpl(); + } + + /* Iterator accessors. */ + iterator begin() { + return iterator(Traits::GetParent(this->GetMinImpl())); + } + + const_iterator begin() const { + return const_iterator(Traits::GetParent(this->GetMinImpl())); + } + + iterator end() { + return iterator(Traits::GetParent(static_cast(nullptr))); + } + + const_iterator end() const { + return const_iterator(Traits::GetParent(static_cast(nullptr))); + } + + 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 Traits::GetParent(this->GetMaxImpl()); + } + + const_reference back() const { + return Traits::GetParent(this->GetMaxImpl()); + } + + reference front() { + return Traits::GetParent(this->GetMinImpl()); + } + + const_reference front() const { + return Traits::GetParent(this->GetMinImpl()); + } + + iterator insert(reference ref) { + this->InsertImpl(Traits::GetNode(&ref)); + return iterator(&ref); + } + + iterator erase(iterator it) { + auto cur = Traits::GetNode(&*it); + auto next = Traits::GetParent(GetNext(cur)); + this->RemoveImpl(cur); + return iterator(next); + } + + iterator find(const_reference ref) const { + return iterator(Traits::GetParent(this->FindImpl(Traits::GetNode(&ref)))); + } + + iterator nfind(const_reference ref) const { + return iterator(Traits::GetParent(this->NFindImpl(Traits::GetNode(&ref)))); + } + }; + + template> + class IntrusiveRedBlackTreeMemberTraits; + + template + class IntrusiveRedBlackTreeMemberTraits { + public: + template + using ListType = IntrusiveRedBlackTree; + private: + template + friend class IntrusiveRedBlackTree; + + static constexpr IntrusiveRedBlackTreeNode *GetNode(Derived *parent) { + return &(parent->*Member); + } + + static constexpr IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) { + return &(parent->*Member); + } + + static constexpr Derived *GetParent(IntrusiveRedBlackTreeNode *node) { + return static_cast(util::GetParentPointer(node)); + } + + static constexpr Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) { + return static_cast(util::GetParentPointer(node)); + } + }; + + template + class IntrusiveRedBlackTreeBaseNode : public IntrusiveRedBlackTreeNode{}; + + template + class IntrusiveRedBlackTreeBaseTraits { + public: + template + using ListType = IntrusiveRedBlackTree; + private: + template + friend class IntrusiveRedBlackTree; + + static constexpr IntrusiveRedBlackTreeNode *GetNode(Derived *parent) { + return static_cast(parent); + } + + static constexpr IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) { + return static_cast(parent); + } + + static constexpr Derived *GetParent(IntrusiveRedBlackTreeNode *node) { + return static_cast(node); + } + + static constexpr Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) { + return static_cast(node); + } + }; + +} \ No newline at end of file diff --git a/include/stratosphere/util/util_parent_of_member.hpp b/include/stratosphere/util/util_parent_of_member.hpp new file mode 100644 index 00000000..88fe61e4 --- /dev/null +++ b/include/stratosphere/util/util_parent_of_member.hpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../defines.hpp" + +namespace sts::util { + + namespace impl { + + template + union OffsetOfImpl { + Member Parent::* ptr; + intptr_t offset; + }; + + template + constexpr inline Parent *GetParentOfMemberImpl(Member *member, Member Parent::* ptr) { + return reinterpret_cast(reinterpret_cast(member) - OffsetOfImpl{ ptr }.offset); + } + + template + constexpr inline Parent const *GetParentOfMemberImpl(Member const *member, Member Parent::* ptr) { + return reinterpret_cast(reinterpret_cast(member) - OffsetOfImpl{ ptr }.offset); + } + + template + struct GetMemberPointerTraits; + + template + struct GetMemberPointerTraits { + using Parent = P; + using Member = M; + }; + + template + using GetParentType = typename GetMemberPointerTraits::Parent; + + template + using GetMemberType = typename GetMemberPointerTraits::Member; + + } + + template + constexpr inline impl::GetParentType *GetParentPointer(impl::GetMemberType *member) { + return impl::GetParentOfMemberImpl, impl::GetMemberType>(member, MemberPtr); + } + + template + constexpr inline impl::GetParentType const *GetParentPointer(impl::GetMemberType const *member) { + return impl::GetParentOfMemberImpl, impl::GetMemberType>(member, MemberPtr); + } + + template + constexpr inline impl::GetParentType &GetParentReference(impl::GetMemberType *member) { + return *impl::GetParentOfMemberImpl, impl::GetMemberType>(member, MemberPtr); + } + + template + constexpr inline impl::GetParentType const &GetParentReference(impl::GetMemberType const *member) { + return *impl::GetParentOfMemberImpl, impl::GetMemberType>(member, MemberPtr); + } + +} \ No newline at end of file diff --git a/include/stratosphere/waitable_manager.hpp b/include/stratosphere/waitable_manager.hpp index a39e3524..556a1c44 100644 --- a/include/stratosphere/waitable_manager.hpp +++ b/include/stratosphere/waitable_manager.hpp @@ -18,8 +18,7 @@ #include #include - -#include "../meta_tools.hpp" +#include #include "results.hpp" #include "waitable_manager_base.hpp"