]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: typesafe rb-tree
authorDavid Lamparter <equinox@opensourcerouting.org>
Thu, 31 Jan 2019 03:25:38 +0000 (04:25 +0100)
committerDavid Lamparter <equinox@diac24.net>
Sat, 27 Apr 2019 16:22:38 +0000 (18:22 +0200)
Typesafe red-black tree, built out of the OpenBSD implementation and the
macro soup layered on top.  API compatible with skiplists & simple
lists.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
lib/subdir.am
lib/typerb.c [new file with mode: 0644]
lib/typerb.h [new file with mode: 0644]
lib/typesafe.h

index d60ebc5d9cc28d91d074cf7cd2ff7345daa1cd99..7e9ee907854af62af348d70eec56cfd738fc2e19 100644 (file)
@@ -80,6 +80,7 @@ lib_libfrr_la_SOURCES = \
        lib/table.c \
        lib/termtable.c \
        lib/thread.c \
+       lib/typerb.c \
        lib/typesafe.c \
        lib/vector.c \
        lib/vrf.c \
@@ -209,6 +210,7 @@ pkginclude_HEADERS += \
        lib/table.h \
        lib/termtable.h \
        lib/thread.h \
+       lib/typerb.h \
        lib/typesafe.h \
        lib/vector.h \
        lib/vlan.h \
diff --git a/lib/typerb.c b/lib/typerb.c
new file mode 100644 (file)
index 0000000..d361e76
--- /dev/null
@@ -0,0 +1,472 @@
+/* RB-tree */
+
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2016 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "typerb.h"
+
+#define RB_BLACK       0
+#define RB_RED         1
+
+#define rb_entry               typed_rb_entry
+#define rbt_tree               typed_rb_root
+
+#define RBE_LEFT(_rbe)         (_rbe)->rbt_left
+#define RBE_RIGHT(_rbe)                (_rbe)->rbt_right
+#define RBE_PARENT(_rbe)       (_rbe)->rbt_parent
+#define RBE_COLOR(_rbe)                (_rbe)->rbt_color
+
+#define RBH_ROOT(_rbt)         (_rbt)->rbt_root
+
+static inline void rbe_set(struct rb_entry *rbe, struct rb_entry *parent)
+{
+       RBE_PARENT(rbe) = parent;
+       RBE_LEFT(rbe) = RBE_RIGHT(rbe) = NULL;
+       RBE_COLOR(rbe) = RB_RED;
+}
+
+static inline void rbe_set_blackred(struct rb_entry *black,
+                                   struct rb_entry *red)
+{
+       RBE_COLOR(black) = RB_BLACK;
+       RBE_COLOR(red) = RB_RED;
+}
+
+static inline void rbe_rotate_left(struct rbt_tree *rbt, struct rb_entry *rbe)
+{
+       struct rb_entry *parent;
+       struct rb_entry *tmp;
+
+       tmp = RBE_RIGHT(rbe);
+       RBE_RIGHT(rbe) = RBE_LEFT(tmp);
+       if (RBE_RIGHT(rbe) != NULL)
+               RBE_PARENT(RBE_LEFT(tmp)) = rbe;
+
+       parent = RBE_PARENT(rbe);
+       RBE_PARENT(tmp) = parent;
+       if (parent != NULL) {
+               if (rbe == RBE_LEFT(parent))
+                       RBE_LEFT(parent) = tmp;
+               else
+                       RBE_RIGHT(parent) = tmp;
+       } else
+               RBH_ROOT(rbt) = tmp;
+
+       RBE_LEFT(tmp) = rbe;
+       RBE_PARENT(rbe) = tmp;
+}
+
+static inline void rbe_rotate_right(struct rbt_tree *rbt, struct rb_entry *rbe)
+{
+       struct rb_entry *parent;
+       struct rb_entry *tmp;
+
+       tmp = RBE_LEFT(rbe);
+       RBE_LEFT(rbe) = RBE_RIGHT(tmp);
+       if (RBE_LEFT(rbe) != NULL)
+               RBE_PARENT(RBE_RIGHT(tmp)) = rbe;
+
+       parent = RBE_PARENT(rbe);
+       RBE_PARENT(tmp) = parent;
+       if (parent != NULL) {
+               if (rbe == RBE_LEFT(parent))
+                       RBE_LEFT(parent) = tmp;
+               else
+                       RBE_RIGHT(parent) = tmp;
+       } else
+               RBH_ROOT(rbt) = tmp;
+
+       RBE_RIGHT(tmp) = rbe;
+       RBE_PARENT(rbe) = tmp;
+}
+
+static inline void rbe_insert_color(struct rbt_tree *rbt, struct rb_entry *rbe)
+{
+       struct rb_entry *parent, *gparent, *tmp;
+
+       rbt->count++;
+
+       while ((parent = RBE_PARENT(rbe)) != NULL
+              && RBE_COLOR(parent) == RB_RED) {
+               gparent = RBE_PARENT(parent);
+
+               if (parent == RBE_LEFT(gparent)) {
+                       tmp = RBE_RIGHT(gparent);
+                       if (tmp != NULL && RBE_COLOR(tmp) == RB_RED) {
+                               RBE_COLOR(tmp) = RB_BLACK;
+                               rbe_set_blackred(parent, gparent);
+                               rbe = gparent;
+                               continue;
+                       }
+
+                       if (RBE_RIGHT(parent) == rbe) {
+                               rbe_rotate_left(rbt, parent);
+                               tmp = parent;
+                               parent = rbe;
+                               rbe = tmp;
+                       }
+
+                       rbe_set_blackred(parent, gparent);
+                       rbe_rotate_right(rbt, gparent);
+               } else {
+                       tmp = RBE_LEFT(gparent);
+                       if (tmp != NULL && RBE_COLOR(tmp) == RB_RED) {
+                               RBE_COLOR(tmp) = RB_BLACK;
+                               rbe_set_blackred(parent, gparent);
+                               rbe = gparent;
+                               continue;
+                       }
+
+                       if (RBE_LEFT(parent) == rbe) {
+                               rbe_rotate_right(rbt, parent);
+                               tmp = parent;
+                               parent = rbe;
+                               rbe = tmp;
+                       }
+
+                       rbe_set_blackred(parent, gparent);
+                       rbe_rotate_left(rbt, gparent);
+               }
+       }
+
+       RBE_COLOR(RBH_ROOT(rbt)) = RB_BLACK;
+}
+
+static inline void rbe_remove_color(struct rbt_tree *rbt,
+                                   struct rb_entry *parent,
+                                   struct rb_entry *rbe)
+{
+       struct rb_entry *tmp;
+
+       while ((rbe == NULL || RBE_COLOR(rbe) == RB_BLACK)
+              && rbe != RBH_ROOT(rbt) && parent) {
+               if (RBE_LEFT(parent) == rbe) {
+                       tmp = RBE_RIGHT(parent);
+                       if (RBE_COLOR(tmp) == RB_RED) {
+                               rbe_set_blackred(tmp, parent);
+                               rbe_rotate_left(rbt, parent);
+                               tmp = RBE_RIGHT(parent);
+                       }
+                       if ((RBE_LEFT(tmp) == NULL
+                            || RBE_COLOR(RBE_LEFT(tmp)) == RB_BLACK)
+                           && (RBE_RIGHT(tmp) == NULL
+                               || RBE_COLOR(RBE_RIGHT(tmp)) == RB_BLACK)) {
+                               RBE_COLOR(tmp) = RB_RED;
+                               rbe = parent;
+                               parent = RBE_PARENT(rbe);
+                       } else {
+                               if (RBE_RIGHT(tmp) == NULL
+                                   || RBE_COLOR(RBE_RIGHT(tmp)) == RB_BLACK) {
+                                       struct rb_entry *oleft;
+
+                                       oleft = RBE_LEFT(tmp);
+                                       if (oleft != NULL)
+                                               RBE_COLOR(oleft) = RB_BLACK;
+
+                                       RBE_COLOR(tmp) = RB_RED;
+                                       rbe_rotate_right(rbt, tmp);
+                                       tmp = RBE_RIGHT(parent);
+                               }
+
+                               RBE_COLOR(tmp) = RBE_COLOR(parent);
+                               RBE_COLOR(parent) = RB_BLACK;
+                               if (RBE_RIGHT(tmp))
+                                       RBE_COLOR(RBE_RIGHT(tmp)) = RB_BLACK;
+
+                               rbe_rotate_left(rbt, parent);
+                               rbe = RBH_ROOT(rbt);
+                               break;
+                       }
+               } else {
+                       tmp = RBE_LEFT(parent);
+                       if (RBE_COLOR(tmp) == RB_RED) {
+                               rbe_set_blackred(tmp, parent);
+                               rbe_rotate_right(rbt, parent);
+                               tmp = RBE_LEFT(parent);
+                       }
+
+                       if ((RBE_LEFT(tmp) == NULL
+                            || RBE_COLOR(RBE_LEFT(tmp)) == RB_BLACK)
+                           && (RBE_RIGHT(tmp) == NULL
+                               || RBE_COLOR(RBE_RIGHT(tmp)) == RB_BLACK)) {
+                               RBE_COLOR(tmp) = RB_RED;
+                               rbe = parent;
+                               parent = RBE_PARENT(rbe);
+                       } else {
+                               if (RBE_LEFT(tmp) == NULL
+                                   || RBE_COLOR(RBE_LEFT(tmp)) == RB_BLACK) {
+                                       struct rb_entry *oright;
+
+                                       oright = RBE_RIGHT(tmp);
+                                       if (oright != NULL)
+                                               RBE_COLOR(oright) = RB_BLACK;
+
+                                       RBE_COLOR(tmp) = RB_RED;
+                                       rbe_rotate_left(rbt, tmp);
+                                       tmp = RBE_LEFT(parent);
+                               }
+
+                               RBE_COLOR(tmp) = RBE_COLOR(parent);
+                               RBE_COLOR(parent) = RB_BLACK;
+                               if (RBE_LEFT(tmp) != NULL)
+                                       RBE_COLOR(RBE_LEFT(tmp)) = RB_BLACK;
+
+                               rbe_rotate_right(rbt, parent);
+                               rbe = RBH_ROOT(rbt);
+                               break;
+                       }
+               }
+       }
+
+       if (rbe != NULL)
+               RBE_COLOR(rbe) = RB_BLACK;
+}
+
+static inline struct rb_entry *
+rbe_remove(struct rbt_tree *rbt, struct rb_entry *rbe)
+{
+       struct rb_entry *child, *parent, *old = rbe;
+       unsigned int color;
+
+       if (RBE_LEFT(rbe) == NULL)
+               child = RBE_RIGHT(rbe);
+       else if (RBE_RIGHT(rbe) == NULL)
+               child = RBE_LEFT(rbe);
+       else {
+               struct rb_entry *tmp;
+
+               rbe = RBE_RIGHT(rbe);
+               while ((tmp = RBE_LEFT(rbe)) != NULL)
+                       rbe = tmp;
+
+               child = RBE_RIGHT(rbe);
+               parent = RBE_PARENT(rbe);
+               color = RBE_COLOR(rbe);
+               if (child != NULL)
+                       RBE_PARENT(child) = parent;
+               if (parent != NULL) {
+                       if (RBE_LEFT(parent) == rbe)
+                               RBE_LEFT(parent) = child;
+                       else
+                               RBE_RIGHT(parent) = child;
+               } else
+                       RBH_ROOT(rbt) = child;
+               if (RBE_PARENT(rbe) == old)
+                       parent = rbe;
+               *rbe = *old;
+
+               tmp = RBE_PARENT(old);
+               if (tmp != NULL) {
+                       if (RBE_LEFT(tmp) == old)
+                               RBE_LEFT(tmp) = rbe;
+                       else
+                               RBE_RIGHT(tmp) = rbe;
+               } else
+                       RBH_ROOT(rbt) = rbe;
+
+               RBE_PARENT(RBE_LEFT(old)) = rbe;
+               if (RBE_RIGHT(old))
+                       RBE_PARENT(RBE_RIGHT(old)) = rbe;
+
+               goto color;
+       }
+
+       parent = RBE_PARENT(rbe);
+       color = RBE_COLOR(rbe);
+
+       if (child != NULL)
+               RBE_PARENT(child) = parent;
+       if (parent != NULL) {
+               if (RBE_LEFT(parent) == rbe)
+                       RBE_LEFT(parent) = child;
+               else
+                       RBE_RIGHT(parent) = child;
+       } else
+               RBH_ROOT(rbt) = child;
+color:
+       if (color == RB_BLACK)
+               rbe_remove_color(rbt, parent, child);
+
+       rbt->count--;
+       return (old);
+}
+
+void typed_rb_remove(struct rbt_tree *rbt, struct rb_entry *rbe)
+{
+       rbe_remove(rbt, rbe);
+}
+
+struct typed_rb_entry *typed_rb_insert(struct rbt_tree *rbt,
+               struct rb_entry *rbe, int (*cmpfn)(
+                       const struct typed_rb_entry *a,
+                       const struct typed_rb_entry *b))
+{
+       struct rb_entry *tmp;
+       struct rb_entry *parent = NULL;
+       int comp = 0;
+
+       tmp = RBH_ROOT(rbt);
+       while (tmp != NULL) {
+               parent = tmp;
+
+               comp = cmpfn(rbe, tmp);
+               if (comp < 0)
+                       tmp = RBE_LEFT(tmp);
+               else if (comp > 0)
+                       tmp = RBE_RIGHT(tmp);
+               else
+                       return tmp;
+       }
+
+       rbe_set(rbe, parent);
+
+       if (parent != NULL) {
+               if (comp < 0)
+                       RBE_LEFT(parent) = rbe;
+               else
+                       RBE_RIGHT(parent) = rbe;
+       } else
+               RBH_ROOT(rbt) = rbe;
+
+       rbe_insert_color(rbt, rbe);
+
+       return NULL;
+}
+
+/* Finds the node with the same key as elm */
+struct rb_entry *typed_rb_find(struct rbt_tree *rbt, const struct rb_entry *key,
+               int (*cmpfn)(
+                       const struct typed_rb_entry *a,
+                       const struct typed_rb_entry *b))
+{
+       struct rb_entry *tmp = RBH_ROOT(rbt);
+       int comp;
+
+       while (tmp != NULL) {
+               comp = cmpfn(key, tmp);
+               if (comp < 0)
+                       tmp = RBE_LEFT(tmp);
+               else if (comp > 0)
+                       tmp = RBE_RIGHT(tmp);
+               else
+                       return tmp;
+       }
+
+       return (NULL);
+}
+
+struct rb_entry *typed_rb_find_gteq(struct rbt_tree *rbt,
+               const struct rb_entry *key,
+               int (*cmpfn)(
+                       const struct typed_rb_entry *a,
+                       const struct typed_rb_entry *b))
+{
+       struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
+       int comp;
+
+       while (tmp != NULL) {
+               comp = cmpfn(key, tmp);
+               if (comp < 0) {
+                       best = tmp;
+                       tmp = RBE_LEFT(tmp);
+               } else if (comp > 0)
+                       tmp = RBE_RIGHT(tmp);
+               else
+                       return tmp;
+       }
+
+       return best;
+}
+
+struct rb_entry *typed_rb_find_lt(struct rbt_tree *rbt,
+               const struct rb_entry *key,
+               int (*cmpfn)(
+                       const struct typed_rb_entry *a,
+                       const struct typed_rb_entry *b))
+{
+       struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
+       int comp;
+
+       while (tmp != NULL) {
+               comp = cmpfn(key, tmp);
+               if (comp <= 0)
+                       tmp = RBE_LEFT(tmp);
+               else {
+                       best = tmp;
+                       tmp = RBE_RIGHT(tmp);
+               }
+       }
+
+       return best;
+}
+
+struct rb_entry *typed_rb_next(struct rb_entry *rbe)
+{
+       if (RBE_RIGHT(rbe) != NULL) {
+               rbe = RBE_RIGHT(rbe);
+               while (RBE_LEFT(rbe) != NULL)
+                       rbe = RBE_LEFT(rbe);
+       } else {
+               if (RBE_PARENT(rbe) && (rbe == RBE_LEFT(RBE_PARENT(rbe))))
+                       rbe = RBE_PARENT(rbe);
+               else {
+                       while (RBE_PARENT(rbe)
+                              && (rbe == RBE_RIGHT(RBE_PARENT(rbe))))
+                               rbe = RBE_PARENT(rbe);
+                       rbe = RBE_PARENT(rbe);
+               }
+       }
+
+       return rbe;
+}
+
+struct rb_entry *typed_rb_min(struct rbt_tree *rbt)
+{
+       struct rb_entry *rbe = RBH_ROOT(rbt);
+       struct rb_entry *parent = NULL;
+
+       while (rbe != NULL) {
+               parent = rbe;
+               rbe = RBE_LEFT(rbe);
+       }
+
+       return parent;
+}
diff --git a/lib/typerb.h b/lib/typerb.h
new file mode 100644 (file)
index 0000000..3d8db06
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * The following Red-Black tree implementation is based off code with
+ * original copyright:
+ *
+ * Copyright (c) 2016 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRR_TYPERB_H
+#define _FRR_TYPERB_H
+
+#include "typesafe.h"
+
+struct typed_rb_entry {
+       struct typed_rb_entry *rbt_parent;
+       struct typed_rb_entry *rbt_left;
+       struct typed_rb_entry *rbt_right;
+       unsigned int rbt_color;
+};
+
+struct typed_rb_root {
+       struct typed_rb_entry *rbt_root;
+       size_t count;
+};
+
+struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *,
+               struct typed_rb_entry *rbe,
+               int (*cmpfn)(
+                       const struct typed_rb_entry *a,
+                       const struct typed_rb_entry *b));
+void typed_rb_remove(struct typed_rb_root *, struct typed_rb_entry *rbe);
+struct typed_rb_entry *typed_rb_find(struct typed_rb_root *,
+               const struct typed_rb_entry *rbe,
+               int (*cmpfn)(
+                       const struct typed_rb_entry *a,
+                       const struct typed_rb_entry *b));
+struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *,
+               const struct typed_rb_entry *rbe,
+               int (*cmpfn)(
+                       const struct typed_rb_entry *a,
+                       const struct typed_rb_entry *b));
+struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *,
+               const struct typed_rb_entry *rbe,
+               int (*cmpfn)(
+                       const struct typed_rb_entry *a,
+                       const struct typed_rb_entry *b));
+struct typed_rb_entry *typed_rb_min(struct typed_rb_root *);
+struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *);
+
+#define _PREDECL_RBTREE(prefix)                                                \
+struct prefix ## _head { struct typed_rb_root rr; };                           \
+struct prefix ## _item { struct typed_rb_entry re; };
+
+#define INIT_RBTREE_UNIQ(var)          { }
+#define INIT_RBTREE_NONUNIQ(var)       { }
+
+#define _DECLARE_RBTREE(prefix, type, field, cmpfn_nuq, cmpfn_uq)              \
+                                                                               \
+macro_inline void prefix ## _init(struct prefix##_head *h)                     \
+{                                                                              \
+       memset(h, 0, sizeof(*h));                                              \
+}                                                                              \
+macro_inline void prefix ## _fini(struct prefix##_head *h)                     \
+{                                                                              \
+       memset(h, 0, sizeof(*h));                                              \
+}                                                                              \
+macro_inline type *prefix ## _add(struct prefix##_head *h, type *item)         \
+{                                                                              \
+       struct typed_rb_entry *re;                                             \
+       re = typed_rb_insert(&h->rr, &item->field.re, cmpfn_uq);               \
+       return container_of_null(re, type, field.re);                          \
+}                                                                              \
+macro_inline type *prefix ## _find_gteq(struct prefix##_head *h,               \
+               const type *item)                                              \
+{                                                                              \
+       struct typed_rb_entry *re;                                             \
+       re = typed_rb_find_gteq(&h->rr, &item->field.re, cmpfn_nuq);           \
+       return container_of_null(re, type, field.re);                          \
+}                                                                              \
+macro_inline type *prefix ## _find_lt(struct prefix##_head *h,                 \
+               const type *item)                                              \
+{                                                                              \
+       struct typed_rb_entry *re;                                             \
+       re = typed_rb_find_lt(&h->rr, &item->field.re, cmpfn_nuq);             \
+       return container_of_null(re, type, field.re);                          \
+}                                                                              \
+macro_inline void prefix ## _del(struct prefix##_head *h, type *item)          \
+{                                                                              \
+       typed_rb_remove(&h->rr, &item->field.re);                              \
+}                                                                              \
+macro_inline type *prefix ## _pop(struct prefix##_head *h)                     \
+{                                                                              \
+       struct typed_rb_entry *re;                                             \
+       re = typed_rb_min(&h->rr);                                             \
+       if (!re)                                                               \
+               return NULL;                                                   \
+       typed_rb_remove(&h->rr, re);                                           \
+       return container_of(re, type, field.re);                               \
+}                                                                              \
+macro_pure type *prefix ## _first(struct prefix##_head *h)                     \
+{                                                                              \
+       struct typed_rb_entry *re;                                             \
+       re = typed_rb_min(&h->rr);                                             \
+       return container_of_null(re, type, field.re);                          \
+}                                                                              \
+macro_pure type *prefix ## _next(struct prefix##_head *h, type *item)          \
+{                                                                              \
+       struct typed_rb_entry *re;                                             \
+       re = typed_rb_next(&item->field.re);                                   \
+       return container_of_null(re, type, field.re);                          \
+}                                                                              \
+macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item)     \
+{                                                                              \
+       struct typed_rb_entry *re;                                             \
+       re = item ? typed_rb_next(&item->field.re) : NULL;                     \
+       return container_of_null(re, type, field.re);                          \
+}                                                                              \
+macro_pure size_t prefix ## _count(struct prefix##_head *h)                    \
+{                                                                              \
+       return h->rr.count;                                                    \
+}                                                                              \
+/* ... */
+
+#define PREDECL_RBTREE_UNIQ(prefix)                                            \
+       _PREDECL_RBTREE(prefix)
+#define DECLARE_RBTREE_UNIQ(prefix, type, field, cmpfn)                        \
+                                                                               \
+macro_inline int prefix ## __cmp(const struct typed_rb_entry *a,               \
+               const struct typed_rb_entry *b)                                \
+{                                                                              \
+       return cmpfn(container_of(a, type, field.re),                          \
+                       container_of(b, type, field.re));                      \
+}                                                                              \
+macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item)  \
+{                                                                              \
+       struct typed_rb_entry *re;                                             \
+       re = typed_rb_find(&h->rr, &item->field.re, &prefix ## __cmp);         \
+       return container_of_null(re, type, field.re);                          \
+}                                                                              \
+                                                                               \
+_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp)         \
+/* ... */
+
+#define PREDECL_RBTREE_NONUNIQ(prefix)                                         \
+       _PREDECL_RBTREE(prefix)
+#define DECLARE_RBTREE_NONUNIQ(prefix, type, field, cmpfn)                     \
+                                                                               \
+macro_inline int prefix ## __cmp(const struct typed_rb_entry *a,               \
+               const struct typed_rb_entry *b)                                \
+{                                                                              \
+       return cmpfn(container_of(a, type, field.re),                          \
+                       container_of(b, type, field.re));                      \
+}                                                                              \
+macro_inline int prefix ## __cmp_uq(const struct typed_rb_entry *a,            \
+               const struct typed_rb_entry *b)                                \
+{                                                                              \
+       int cmpval = cmpfn(container_of(a, type, field.re),                    \
+                       container_of(b, type, field.re));                      \
+       if (cmpval)                                                            \
+               return cmpval;                                                 \
+       if (a < b)                                                             \
+               return -1;                                                     \
+       if (a > b)                                                             \
+               return 1;                                                      \
+       return 0;                                                              \
+}                                                                              \
+                                                                               \
+_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp_uq)      \
+/* ... */
+
+#endif /* _FRR_TYPERB_H */
index 2fa4cae6e94152c1ce152d44780b15b43a0615ae..bbf3ce8f1cb508c8aaa447064f02d67d954509ba 100644 (file)
@@ -637,4 +637,9 @@ extern void typesafe_skiplist_del(struct sskip_head *head,
                        const struct sskip_item *a,
                        const struct sskip_item *b));
 
+/* this needs to stay at the end because both files include each other.
+ * the resolved order is typesafe.h before typerb.h
+ */
+#include "typerb.h"
+
 #endif /* _FRR_TYPESAFE_H */