summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
authorluwenpeng <[email protected]>2024-03-27 17:11:38 +0800
committerluwenpeng <[email protected]>2024-03-27 17:16:59 +0800
commit814a0d739f566c064828a695edcdb1be78c523de (patch)
treeee4789958f3fec3842ad762518e416f708dd60e7 /deps
parenteb281ab7897d2181a2740163d00d55728da968d3 (diff)
Add linux kernel interval tree
Diffstat (limited to 'deps')
-rw-r--r--deps/CMakeLists.txt1
-rw-r--r--deps/interval_tree/CMakeLists.txt4
-rw-r--r--deps/interval_tree/interval.cpp71
-rw-r--r--deps/interval_tree/interval.h59
-rw-r--r--deps/interval_tree/interval_list.cpp277
-rw-r--r--deps/interval_tree/interval_list.h57
-rw-r--r--deps/interval_tree/interval_tree.cpp10
-rw-r--r--deps/interval_tree/interval_tree.h33
-rw-r--r--deps/interval_tree/interval_tree_generic.h197
-rw-r--r--deps/interval_tree/itree.cpp628
-rw-r--r--deps/interval_tree/itree.h75
-rw-r--r--deps/interval_tree/test/gtest_interval_tree.cpp406
-rw-r--r--deps/list/list.h356
-rw-r--r--deps/rbtree/CMakeLists.txt2
-rw-r--r--deps/rbtree/rbtree.cpp624
-rw-r--r--deps/rbtree/rbtree.h383
-rw-r--r--deps/rbtree/rbtree_augmented.h320
17 files changed, 2072 insertions, 1431 deletions
diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt
index d703aef..3c9947a 100644
--- a/deps/CMakeLists.txt
+++ b/deps/CMakeLists.txt
@@ -1,4 +1,5 @@
add_subdirectory(timeout)
add_subdirectory(dablooms)
add_subdirectory(toml)
+add_subdirectory(rbtree)
add_subdirectory(interval_tree) \ No newline at end of file
diff --git a/deps/interval_tree/CMakeLists.txt b/deps/interval_tree/CMakeLists.txt
index 7a6de00..2b297fa 100644
--- a/deps/interval_tree/CMakeLists.txt
+++ b/deps/interval_tree/CMakeLists.txt
@@ -1,4 +1,6 @@
-add_library(interval_tree STATIC interval.cpp interval_list.cpp itree.cpp)
+add_library(interval_tree STATIC interval_tree.cpp)
target_include_directories(interval_tree PUBLIC ${CMAKE_CURRENT_LIST_DIR})
+target_include_directories(interval_tree PUBLIC ${CMAKE_SOURCE_DIR}/deps/rbtree)
+target_link_libraries(interval_tree rbtree)
add_subdirectory(test) \ No newline at end of file
diff --git a/deps/interval_tree/interval.cpp b/deps/interval_tree/interval.cpp
deleted file mode 100644
index 4fc7ddf..0000000
--- a/deps/interval_tree/interval.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Libitree: an interval tree library in C
- *
- * Copyright (C) 2018 Alessandro Vullo
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "interval.h"
-
-#include <stdlib.h>
-
-interval_t *interval_new(uint64_t low, uint64_t high, void *data, dup_f dup, rel_f rel)
-{
- interval_t *ri = (interval_t *)malloc(sizeof *ri);
- if (ri == NULL)
- {
- return NULL;
- }
-
- ri->low = low;
- ri->high = high;
- ri->dup = dup;
- ri->rel = rel;
- ri->data = ri->dup(data);
-
- return ri;
-}
-
-interval_t *interval_copy(const interval_t *i)
-{
- return interval_new(i->low, i->high, i->data, i->dup, i->rel);
-}
-
-void interval_delete(interval_t *i)
-{
- if (i != NULL)
- {
- if (i->data)
- {
- i->rel(i->data);
- }
- free(i);
- }
-}
-
-int interval_overlap(const interval_t *i1, const interval_t *i2)
-{
- return i1->low <= i2->high && i2->low <= i1->high;
-}
-
-int interval_equal(const interval_t *i1, const interval_t *i2)
-{
- return i1->low == i2->low && i1->high == i2->high && i1->data == i2->data;
-}
diff --git a/deps/interval_tree/interval.h b/deps/interval_tree/interval.h
deleted file mode 100644
index 4504c7c..0000000
--- a/deps/interval_tree/interval.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Libitree: an interval tree library in C
- *
- * Copyright (C) 2018 Alessandro Vullo
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _INTERVAL_H_
-#define _INTERVAL_H_
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#include <stddef.h>
-#include <stdint.h>
-
-/* User-defined item handling */
-typedef void *(*dup_f)(void *p);
-typedef void (*rel_f)(void *p);
-
-typedef struct interval
-{
- uint64_t low, high; /* Interval boundaries, inclusive */
- void *data; /* User-defined content */
- dup_f dup; /* Clone an interval data item */
- rel_f rel; /* Destroy an interval data item */
-} interval_t;
-
-/* Interval functions */
-interval_t *interval_new(uint64_t low, uint64_t high, void *data, dup_f dup, rel_f rel);
-interval_t *interval_copy(const interval_t *i);
-void interval_delete(interval_t *i);
-int interval_overlap(const interval_t *i1, const interval_t *i2);
-int interval_equal(const interval_t *i1, const interval_t *i2);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _INTERVAL_H_ */
diff --git a/deps/interval_tree/interval_list.cpp b/deps/interval_tree/interval_list.cpp
deleted file mode 100644
index 6700564..0000000
--- a/deps/interval_tree/interval_list.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Libitree: an interval tree library in C
- *
- * Copyright (C) 2018 Alessandro Vullo
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "interval_list.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifndef HEIGHT_LIMIT
-#define HEIGHT_LIMIT 64
-#endif
-
-/* Note: doesn't own the interval, comes from the tree
- which is responsible for deallocating the interval. */
-typedef struct ilistnode
-{
- const interval_t *interval;
- struct ilistnode *next;
-} ilistnode_t;
-
-struct ilist
-{
- ilistnode_t *head, *tail; /* Dummy nodes */
- size_t size;
-};
-
-struct ilisttrav
-{
- ilist_t *list; /* Paired list */
- ilistnode_t *it; /* Current node */
-};
-
-static ilistnode_t *ilistnode_new(const interval_t *i, ilistnode_t *next)
-{
- ilistnode_t *node = (ilistnode_t *)malloc(sizeof *node);
- if (node != NULL)
- {
- node->interval = i; /* NOTE: doesn't own the interval, pointer aliasing */
- node->next = next;
- }
-
- return node;
-}
-
-/*
- Destroy a single node, assuming it's been unlinked.
- Returns the next node specified by the link.
-*/
-ilistnode_t *ilistnode_delete(ilistnode_t *node)
-{
- ilistnode_t *next = NULL;
- if (node != NULL)
- {
- /* Save a reference to the next node
- since we're about to destroy this one */
- next = node->next;
- free(node);
- }
-
- return next;
-}
-
-ilist_t *ilist_new()
-{
- ilist_t *list = (ilist_t *)malloc(sizeof *list);
- if (list != NULL)
- {
- ilistnode_t *tail = ilistnode_new(NULL, NULL);
- if (tail == NULL)
- {
- free(list);
- list = NULL;
- }
- else
- {
- list->tail = tail;
- list->head = ilistnode_new(NULL, list->tail);
-
- if (list->head == NULL)
- {
- free(list);
- list = NULL;
- }
- list->size = 0;
- }
- }
-
- return list;
-}
-
-void ilist_delete(ilist_t *list)
-{
- if (list == NULL)
- {
- return;
- }
-
- ilistnode_t *it = list->head;
- while (it != list->tail)
- {
- it = ilistnode_delete(it);
- }
-
- ilistnode_delete(it); /* Delete tail */
- free(list);
-}
-
-size_t ilist_size(ilist_t *list)
-{
- return list->size;
-}
-
-static ilistnode_t *insert_before(ilist_t *, ilistnode_t *, interval_t *);
-static ilistnode_t *insert_after(ilist_t *list, ilistnode_t *pos, interval_t *i)
-{
- ilistnode_t *node = NULL;
- if (list != NULL && pos != NULL)
- {
- if (pos != list->tail)
- {
- node = ilistnode_new(i, pos->next);
- if (node != NULL)
- {
- pos->next = node;
- ++list->size;
- }
- }
- else
- {
- node = insert_before(list, pos, i);
- }
- }
-
- return node;
-}
-
-static ilistnode_t *insert_before(ilist_t *list, ilistnode_t *pos, interval_t *i)
-{
- ilistnode_t *node = NULL;
- if (list != NULL && pos != NULL)
- {
- if (pos != list->head)
- {
- /* Find the previous node */
- ilistnode_t *it = list->head;
- while (it->next != pos)
- {
- it = it->next;
- }
-
- /* Create a new node and set the new link */
- node = ilistnode_new(i, it->next);
- if (node != NULL)
- {
- it->next = node;
- ++list->size;
- }
- }
- else
- {
- node = insert_after(list, pos, i);
- }
- }
-
- return node;
-}
-
-int ilist_append(ilist_t *list, interval_t *i)
-{
-
- ilistnode_t *node = insert_before(list, list->tail, i);
- if (node != NULL)
- {
- return 1;
- }
-
- return 0;
-}
-
-ilisttrav_t *ilisttrav_new(ilist_t *list)
-{
- if (list == NULL)
- {
- return NULL;
- }
-
- ilisttrav_t *trav = (ilisttrav_t *)malloc(sizeof(ilisttrav_t));
- if (trav != NULL)
- {
- trav->list = list;
- }
-
- return trav;
-}
-
-void ilisttrav_delete(ilisttrav_t *trav)
-{
- free(trav);
-}
-
-const interval_t *ilisttrav_first(ilisttrav_t *trav)
-{
- if (trav->list == NULL)
- {
- return NULL;
- }
-
- trav->it = trav->list->head->next;
-
- return trav->it == NULL || trav->it == trav->list->tail ? NULL : trav->it->interval;
-}
-
-const interval_t *ilisttrav_last(ilisttrav_t *trav)
-{
- if (trav->list == NULL)
- {
- return NULL;
- }
-
- trav->it = trav->list->head;
- while (trav->it->next != trav->list->tail)
- {
- trav->it = trav->it->next;
- }
-
- return trav->it == trav->list->head || trav->it == NULL ? NULL : trav->it->interval;
-}
-
-const interval_t *ilisttrav_next(ilisttrav_t *trav)
-{
- if (trav == NULL)
- {
- return NULL;
- }
-
- trav->it = trav->it->next;
- return trav->it == NULL || trav->it == trav->list->tail ? NULL : trav->it->interval;
-}
-
-/* Very inefficient, need a doubly linked list to properly support this */
-const interval_t *ilisttrav_prev(ilisttrav_t *trav)
-{
- if (trav == NULL)
- {
- return NULL;
- }
-
- ilistnode_t *it = trav->list->head;
- while (it->next != trav->it)
- {
- it = it->next;
- }
-
- trav->it = it;
- return trav->it == trav->list->head || trav->it == NULL ? NULL : trav->it->interval;
-}
diff --git a/deps/interval_tree/interval_list.h b/deps/interval_tree/interval_list.h
deleted file mode 100644
index 7333419..0000000
--- a/deps/interval_tree/interval_list.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Libitree: an interval tree library in C
- *
- * Copyright (C) 2018 Alessandro Vullo
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _INTERVAL_LIST_H_
-#define _INTERVAL_LIST_H_
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#include "interval.h"
-
-/* Declarations for an interval list, opaque types */
-typedef struct ilist ilist_t;
-typedef struct ilisttrav ilisttrav_t;
-
-/* Interval list functions */
-ilist_t *ilist_new();
-void ilist_delete(ilist_t *list);
-size_t ilist_size(ilist_t *list);
-int ilist_append(ilist_t *list, interval_t *i);
-
-/* Interval list traversal functions */
-ilisttrav_t *ilisttrav_new(ilist_t *list);
-void ilisttrav_delete(ilisttrav_t *trav);
-const interval_t *ilisttrav_first(ilisttrav_t *trav);
-const interval_t *ilisttrav_last(ilisttrav_t *trav);
-const interval_t *ilisttrav_next(ilisttrav_t *trav);
-const interval_t *ilisttrav_prev(ilisttrav_t *trav);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _INTERVAL_LIST_H_ */
diff --git a/deps/interval_tree/interval_tree.cpp b/deps/interval_tree/interval_tree.cpp
new file mode 100644
index 0000000..da6d2c5
--- /dev/null
+++ b/deps/interval_tree/interval_tree.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include "interval_tree.h"
+#include "interval_tree_generic.h"
+
+#define START(node) ((node)->start)
+#define LAST(node) ((node)->last)
+
+INTERVAL_TREE_DEFINE(struct interval_tree_node, rb,
+ uint64_t, __subtree_last,
+ START, LAST, , interval_tree)
diff --git a/deps/interval_tree/interval_tree.h b/deps/interval_tree/interval_tree.h
new file mode 100644
index 0000000..0b3d169
--- /dev/null
+++ b/deps/interval_tree/interval_tree.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_INTERVAL_TREE_H
+#define _LINUX_INTERVAL_TREE_H
+
+#include "rbtree.h"
+#include <stdint.h>
+
+struct interval_tree_node
+{
+ struct rb_node rb;
+ uint64_t start; /* Start of interval */
+ uint64_t last; /* Last location _in_ interval */
+ uint64_t __subtree_last;
+ void *user_data;
+};
+
+extern void
+interval_tree_insert(struct interval_tree_node *node,
+ struct rb_root_cached *root);
+
+extern void
+interval_tree_remove(struct interval_tree_node *node,
+ struct rb_root_cached *root);
+
+extern struct interval_tree_node *
+interval_tree_iter_first(struct rb_root_cached *root,
+ uint64_t start, uint64_t last);
+
+extern struct interval_tree_node *
+interval_tree_iter_next(struct interval_tree_node *node,
+ uint64_t start, uint64_t last);
+
+#endif /* _LINUX_INTERVAL_TREE_H */
diff --git a/deps/interval_tree/interval_tree_generic.h b/deps/interval_tree/interval_tree_generic.h
new file mode 100644
index 0000000..872c264
--- /dev/null
+++ b/deps/interval_tree/interval_tree_generic.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ Interval Trees
+ (C) 2012 Michel Lespinasse <[email protected]>
+
+
+ include/linux/interval_tree_generic.h
+*/
+
+#include "rbtree_augmented.h"
+
+/*
+ * Template for implementing interval trees
+ *
+ * ITSTRUCT: struct type of the interval tree nodes
+ * ITRB: name of struct rb_node field within ITSTRUCT
+ * ITTYPE: type of the interval endpoints
+ * ITSUBTREE: name of ITTYPE field within ITSTRUCT holding last-in-subtree
+ * ITSTART(n): start endpoint of ITSTRUCT node n
+ * ITLAST(n): last endpoint of ITSTRUCT node n
+ * ITSTATIC: 'static' or empty
+ * ITPREFIX: prefix to use for the inline tree definitions
+ *
+ * Note - before using this, please consider if generic version
+ * (interval_tree.h) would work for you...
+ */
+
+#define INTERVAL_TREE_DEFINE(ITSTRUCT, ITRB, ITTYPE, ITSUBTREE, \
+ ITSTART, ITLAST, ITSTATIC, ITPREFIX) \
+ \
+ /* Callbacks for augmented rbtree insert and remove */ \
+ \
+ RB_DECLARE_CALLBACKS_MAX(static, ITPREFIX##_augment, \
+ ITSTRUCT, ITRB, ITTYPE, ITSUBTREE, ITLAST) \
+ \
+ /* Insert / remove interval nodes from the tree */ \
+ \
+ ITSTATIC void ITPREFIX##_insert(ITSTRUCT *node, \
+ struct rb_root_cached *root) \
+ { \
+ struct rb_node **link = &root->rb_root.rb_node, *rb_parent = NULL; \
+ ITTYPE start = ITSTART(node), last = ITLAST(node); \
+ ITSTRUCT *parent; \
+ bool leftmost = true; \
+ \
+ while (*link) \
+ { \
+ rb_parent = *link; \
+ parent = rb_entry(rb_parent, ITSTRUCT, ITRB); \
+ if (parent->ITSUBTREE < last) \
+ parent->ITSUBTREE = last; \
+ if (start < ITSTART(parent)) \
+ link = &parent->ITRB.rb_left; \
+ else \
+ { \
+ link = &parent->ITRB.rb_right; \
+ leftmost = false; \
+ } \
+ } \
+ \
+ node->ITSUBTREE = last; \
+ rb_link_node(&node->ITRB, rb_parent, link); \
+ rb_insert_augmented_cached(&node->ITRB, root, \
+ leftmost, &ITPREFIX##_augment); \
+ } \
+ \
+ ITSTATIC void ITPREFIX##_remove(ITSTRUCT *node, \
+ struct rb_root_cached *root) \
+ { \
+ rb_erase_augmented_cached(&node->ITRB, root, &ITPREFIX##_augment); \
+ } \
+ \
+ /* \
+ * Iterate over intervals intersecting [start;last] \
+ * \
+ * Note that a node's interval intersects [start;last] iff: \
+ * Cond1: ITSTART(node) <= last \
+ * and \
+ * Cond2: start <= ITLAST(node) \
+ */ \
+ \
+ static ITSTRUCT * \
+ ITPREFIX##_subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \
+ { \
+ while (true) \
+ { \
+ /* \
+ * Loop invariant: start <= node->ITSUBTREE \
+ * (Cond2 is satisfied by one of the subtree nodes) \
+ */ \
+ if (node->ITRB.rb_left) \
+ { \
+ ITSTRUCT *left = rb_entry(node->ITRB.rb_left, \
+ ITSTRUCT, ITRB); \
+ if (start <= left->ITSUBTREE) \
+ { \
+ /* \
+ * Some nodes in left subtree satisfy Cond2. \
+ * Iterate to find the leftmost such node N. \
+ * If it also satisfies Cond1, that's the \
+ * match we are looking for. Otherwise, there \
+ * is no matching interval as nodes to the \
+ * right of N can't satisfy Cond1 either. \
+ */ \
+ node = left; \
+ continue; \
+ } \
+ } \
+ if (ITSTART(node) <= last) \
+ { /* Cond1 */ \
+ if (start <= ITLAST(node)) /* Cond2 */ \
+ return node; /* node is leftmost match */ \
+ if (node->ITRB.rb_right) \
+ { \
+ node = rb_entry(node->ITRB.rb_right, \
+ ITSTRUCT, ITRB); \
+ if (start <= node->ITSUBTREE) \
+ continue; \
+ } \
+ } \
+ return NULL; /* No match */ \
+ } \
+ } \
+ \
+ ITSTATIC ITSTRUCT * \
+ ITPREFIX##_iter_first(struct rb_root_cached *root, \
+ ITTYPE start, ITTYPE last) \
+ { \
+ ITSTRUCT *node, *leftmost; \
+ \
+ if (!root->rb_root.rb_node) \
+ return NULL; \
+ \
+ /* \
+ * Fastpath range intersection/overlap between A: [a0, a1] and \
+ * B: [b0, b1] is given by: \
+ * \
+ * a0 <= b1 && b0 <= a1 \
+ * \
+ * ... where A holds the lock range and B holds the smallest \
+ * 'start' and largest 'last' in the tree. For the later, we \
+ * rely on the root node, which by augmented interval tree \
+ * property, holds the largest value in its last-in-subtree. \
+ * This allows mitigating some of the tree walk overhead for \
+ * for non-intersecting ranges, maintained and consulted in O(1). \
+ */ \
+ node = rb_entry(root->rb_root.rb_node, ITSTRUCT, ITRB); \
+ if (node->ITSUBTREE < start) \
+ return NULL; \
+ \
+ leftmost = rb_entry(root->rb_leftmost, ITSTRUCT, ITRB); \
+ if (ITSTART(leftmost) > last) \
+ return NULL; \
+ \
+ return ITPREFIX##_subtree_search(node, start, last); \
+ } \
+ \
+ ITSTATIC ITSTRUCT * \
+ ITPREFIX##_iter_next(ITSTRUCT *node, ITTYPE start, ITTYPE last) \
+ { \
+ struct rb_node *rb = node->ITRB.rb_right, *prev; \
+ \
+ while (true) \
+ { \
+ /* \
+ * Loop invariants: \
+ * Cond1: ITSTART(node) <= last \
+ * rb == node->ITRB.rb_right \
+ * \
+ * First, search right subtree if suitable \
+ */ \
+ if (rb) \
+ { \
+ ITSTRUCT *right = rb_entry(rb, ITSTRUCT, ITRB); \
+ if (start <= right->ITSUBTREE) \
+ return ITPREFIX##_subtree_search(right, \
+ start, last); \
+ } \
+ \
+ /* Move up the tree until we come from a node's left child */ \
+ do \
+ { \
+ rb = rb_parent(&node->ITRB); \
+ if (!rb) \
+ return NULL; \
+ prev = &node->ITRB; \
+ node = rb_entry(rb, ITSTRUCT, ITRB); \
+ rb = node->ITRB.rb_right; \
+ } while (prev == rb); \
+ \
+ /* Check if the node intersects [start;last] */ \
+ if (last < ITSTART(node)) /* !Cond1 */ \
+ return NULL; \
+ else if (start <= ITLAST(node)) /* Cond2 */ \
+ return node; \
+ } \
+ }
diff --git a/deps/interval_tree/itree.cpp b/deps/interval_tree/itree.cpp
deleted file mode 100644
index 9d7bf74..0000000
--- a/deps/interval_tree/itree.cpp
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * Libitree: an interval tree library in C
- *
- * Copyright (C) 2018 Alessandro Vullo
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- Interval Tree library
-
- This is an adaptation of the AVL balanced tree C library
- created by Julienne Walker which can be found here:
-
- http://www.eternallyconfuzzled.com/Libraries.aspx
-
-*/
-
-#include "itree.h"
-
-#include <stdlib.h>
-
-#ifndef HEIGHT_LIMIT
-#define HEIGHT_LIMIT 64 /* Tallest allowable tree */
-#endif
-
-typedef struct itreenode
-{
- int balance; /* Balance factor */
- uint64_t max; /* Maximum high value in the subtree rooted at this node */
- interval_t *interval; /* The interval the node represents */
- struct itreenode *link[2]; /* Left (0) and right (1) links */
-} itreenode_t;
-
-struct itree
-{
- itreenode_t *root; /* Top of the tree */
- dup_f dup; /* Clone an interval data item (user-defined) */
- rel_f rel; /* Destroy an interval data item (user-defined) */
- size_t size; /* Number of items (user-defined) */
-};
-
-struct itreetrav
-{
- itree_t *tree; /* Paired tree */
- itreenode_t *it; /* Current node */
- itreenode_t *path[HEIGHT_LIMIT]; /* Traversal path */
- size_t top; /* Top of stack */
-};
-
-/* Two way single rotation */
-#define single(root, dir) \
- do \
- { \
- itreenode_t *save = root->link[!dir]; \
- root->link[!dir] = save->link[dir]; \
- save->link[dir] = root; \
- root = save; \
- } while (0)
-
-/* Two way double rotation */
-#define double(root, dir) \
- do \
- { \
- itreenode_t *save = root->link[!dir]->link[dir]; \
- root->link[!dir]->link[dir] = save->link[!dir]; \
- save->link[!dir] = root->link[!dir]; \
- root->link[!dir] = save; \
- save = root->link[!dir]; \
- root->link[!dir] = save->link[dir]; \
- save->link[dir] = root; \
- root = save; \
- } while (0)
-
-/* Adjust balance before double rotation */
-#define adjust_balance(root, dir, bal) \
- do \
- { \
- itreenode_t *n = root->link[dir]; \
- itreenode_t *nn = n->link[!dir]; \
- if (nn->balance == 0) \
- { \
- root->balance = n->balance = 0; \
- } \
- else if (nn->balance == bal) \
- { \
- root->balance = -bal; \
- n->balance = 0; \
- } \
- else \
- { /* nn->balance == -bal */ \
- root->balance = 0; \
- n->balance = bal; \
- } \
- nn->balance = 0; \
- } while (0)
-
-/* Rebalance after insertion */
-#define insert_balance(root, dir) \
- do \
- { \
- itreenode_t *n = root->link[dir]; \
- int bal = dir == 0 ? -1 : +1; \
- if (n->balance == bal) \
- { \
- root->balance = n->balance = 0; \
- single(root, !dir); \
- } \
- else \
- { /* n->balance == -bal */ \
- adjust_balance(root, dir, bal); \
- double(root, !dir); \
- } \
- } while (0)
-
-/* Rebalance after deletion */
-#define remove_balance(root, dir, done) \
- do \
- { \
- itreenode_t *n = root->link[!dir]; \
- int bal = dir == 0 ? -1 : +1; \
- if (n->balance == -bal) \
- { \
- root->balance = n->balance = 0; \
- single(root, dir); \
- } \
- else if (n->balance == bal) \
- { \
- adjust_balance(root, !dir, -bal); \
- double(root, dir); \
- } \
- else \
- { /* n->balance == 0 */ \
- root->balance = -bal; \
- n->balance = bal; \
- single(root, dir); \
- done = 1; \
- } \
- } while (0)
-
-static itreenode_t *new_node(itree_t *tree, interval_t *i)
-{
- itreenode_t *rn = (itreenode_t *)malloc(sizeof *rn);
- if (rn == NULL)
- {
- return NULL;
- }
-
- rn->interval = (interval_t *)malloc(sizeof(interval_t));
- if (rn->interval == NULL)
- {
- return NULL;
- }
-
- rn->interval->low = i->low;
- rn->interval->high = i->high;
- rn->interval->data = tree->dup(i->data);
-
- rn->balance = 0;
- rn->max = i->high;
- rn->link[0] = rn->link[1] = NULL;
-
- return rn;
-}
-
-itree_t *itree_new(dup_f dup, rel_f rel)
-{
- itree_t *rt = (itree_t *)malloc(sizeof *rt);
- if (rt == NULL)
- {
- return NULL;
- }
-
- rt->root = NULL;
- rt->dup = dup;
- rt->rel = rel;
- rt->size = 0;
-
- return rt;
-}
-
-void itree_delete(itree_t *tree)
-{
- itreenode_t *it = tree->root;
- itreenode_t *save;
-
- /* Destruction by rotation */
- while (it != NULL)
- {
- if (it->link[0] == NULL)
- {
- /* Remove node */
- save = it->link[1];
- tree->rel(it->interval->data);
- free(it->interval);
- free(it);
- }
- else
- {
- /* Rotate right */
- save = it->link[0];
- it->link[0] = save->link[1];
- save->link[1] = it;
- }
-
- it = save;
- }
-
- free(tree);
-}
-
-interval_t *itree_find(itree_t *tree, interval_t *interval)
-{
- itreenode_t *it = tree->root;
- while (it != NULL)
- {
- /* int cmp = tree->cmp ( it->data, data ); */
-
- /* if ( cmp == 0 ) */
- /* break; */
-
- /* it = it->link[cmp < 0]; */
-
- if (interval_overlap(it->interval, interval))
- {
- break;
- }
-
- it = it->link[it->link[0] == NULL || it->link[0]->max < interval->low];
- }
-
- return it == NULL ? NULL : it->interval;
-}
-
-void search(itreenode_t *node, interval_t *interval, ilist_t *results)
-{
- /*
- * If interval is to the right of the rightmost point of any interval
- * in this node and all its children, there won't be any matches
- */
- if (node == NULL || interval->low > node->max)
- {
- return;
- }
-
- /* search the left subtree */
- if (node->link[0] != NULL && node->link[0]->max >= interval->low)
- {
- search(node->link[0], interval, results);
- }
-
- /* search this node */
- if (interval_overlap(node->interval, interval))
- {
- ilist_append(results, node->interval);
- }
-
- /*
- * if interval is to the left of the start of this interval
- * it can't be in any child to the right
- */
- if (interval->high < node->interval->low)
- {
- return;
- }
-
- /* search the right subtree */
- search(node->link[1], interval, results);
-}
-
-ilist_t *itree_findall(itree_t *tree, interval_t *interval)
-{
- ilist_t *results = ilist_new();
- if (results != NULL)
- {
- /* empty tree case */
- if (tree->root == NULL)
- {
- return results;
- }
-
- search(tree->root, interval, results);
- }
-
- return results;
-}
-
-int itree_insert(itree_t *tree, interval_t *interval)
-{
- /* Empty tree case */
- if (tree->root == NULL)
- {
- tree->root = new_node(tree, interval);
- if (tree->root == NULL)
- {
- return 0;
- }
- }
- else
- {
- itreenode_t head = {0}; /* Temporary tree root */
- itreenode_t *s, *t; /* Place to rebalance and parent */
- itreenode_t *p, *q; /* Iterator and save pointer to the newly inserted node */
- int dir;
-
- /* Set up false root to ease maintenance */
- t = &head;
- t->link[1] = tree->root;
-
- /* Search down the tree, saving rebalance points */
- for (s = p = t->link[1];; p = q)
- {
- /* Duplicates admitted, placed in the right subtree */
- dir = p->interval->low <= interval->low; /* tree->cmp ( p->data, data ) < 0; */
- q = p->link[dir];
-
- p->max = p->max < interval->high ? interval->high : p->max; /* Update ancestor's max if needed */
-
- if (q == NULL)
- {
- break;
- }
-
- if (q->balance != 0)
- {
- t = p;
- s = q;
- }
- }
-
- p->link[dir] = q = new_node(tree, interval);
- if (q == NULL)
- {
- return 0; /* TODO: should rollback to previous ancestors' max values */
- }
-
- /* Update balance factors */
- for (p = s; p != q; p = p->link[dir])
- {
- dir = p->interval->low <= interval->low; /* tree->cmp ( p->data, data ) < 0; */
- p->balance += dir == 0 ? -1 : +1;
- }
-
- q = s; /* Save rebalance point for parent fix */
-
- /* Rebalance if necessary */
- if (abs(s->balance) > 1)
- {
- dir = s->interval->low <= interval->low; /* tree->cmp ( s->data, data ) < 0; */
- insert_balance(s, dir);
- }
-
- /* Fix parent */
- if (q == head.link[1])
- {
- tree->root = s;
- }
- else
- {
- t->link[q == t->link[1]] = s;
- }
- }
-
- ++tree->size;
-
- return 1;
-}
-
-int itree_remove(itree_t *tree, interval_t *interval)
-{
- if (tree->root != NULL)
- {
- itreenode_t *it, *up[HEIGHT_LIMIT];
- int upd[HEIGHT_LIMIT], top = 0, top_max;
- int done = 0;
-
- it = tree->root;
-
- /* Search down tree and save path */
- for (;;)
- {
- if (it == NULL)
- {
- return 0;
- }
- else if (interval_equal(it->interval, interval))
- {
- break;
- }
-
- /* Push direction and node onto stack */
- upd[top] = it->interval->low <= interval->low; /* tree->cmp ( it->data, data ) < 0; */
- up[top++] = it;
-
- it = it->link[upd[top - 1]];
- }
-
- /* Remove the node */
- if (it->link[0] == NULL || it->link[1] == NULL)
- {
- /* Which child is not null? */
- int dir = it->link[0] == NULL;
-
- /* Fix parent */
- if (top != 0)
- {
- up[top - 1]->link[upd[top - 1]] = it->link[dir];
- }
- else
- {
- tree->root = it->link[dir];
- }
-
- tree->rel(it->interval->data);
- free(it->interval);
- free(it);
- }
- else
- {
- /* Find the inorder successor */
- itreenode_t *heir = it->link[1];
- void *save;
-
- /* Save this path too */
- upd[top] = 1;
- up[top++] = it;
-
- while (heir->link[0] != NULL)
- {
- upd[top] = 0;
- up[top++] = heir;
- heir = heir->link[0];
- }
-
- /* Swap data */
- save = it->interval;
- it->interval = heir->interval;
- heir->interval = (interval_t *)save;
-
- /* Unlink successor and fix parent */
- up[top - 1]->link[up[top - 1] == it] = heir->link[1];
-
- tree->rel(heir->interval->data);
- free(heir->interval);
- free(heir);
- }
-
- /* Update max: walk back up the search path and bubbles up to root */
- top_max = top;
-
- while (--top_max >= 0)
- {
- itreenode_t *left = up[top_max]->link[0], *right = up[top_max]->link[1];
- if (left != NULL && right != NULL)
- {
- uint64_t left_right_max = left->max < right->max ? right->max : left->max;
- up[top_max]->max = up[top_max]->interval->high < left_right_max ? left_right_max : up[top_max]->interval->high;
- }
- else if (left != NULL && right == NULL)
- {
- up[top_max]->max = up[top_max]->interval->high < left->max ? left->max : up[top_max]->interval->high;
- }
- else if (left == NULL && right != NULL)
- {
- up[top_max]->max = up[top_max]->interval->high < right->max ? right->max : up[top_max]->interval->high;
- }
- else
- {
- up[top_max]->max = up[top_max]->interval->high;
- }
- }
-
- /* Walk back up the search path */
- while (--top >= 0 && !done)
- {
- /* Update balance factors */
- up[top]->balance += upd[top] != 0 ? -1 : +1;
-
- /* Terminate or rebalance as necessary */
- if (abs(up[top]->balance) == 1)
- {
- break;
- }
- else if (abs(up[top]->balance) > 1)
- {
- remove_balance(up[top], upd[top], done);
-
- /* Fix parent */
- if (top != 0)
- {
- up[top - 1]->link[upd[top - 1]] = up[top];
- }
- else
- {
- tree->root = up[0];
- }
- }
- }
-
- --tree->size;
- }
-
- return 1;
-}
-
-size_t itree_size(itree_t *tree)
-{
- return tree->size;
-}
-
-itreetrav_t *itreetnew(void)
-{
- return (itreetrav_t *)malloc(sizeof(itreetrav_t));
-}
-
-void itreetdelete(itreetrav_t *trav)
-{
- free(trav);
-}
-
-/*
- First step in traversal,
- handles min and max
-*/
-static interval_t *start(itreetrav_t *trav, itree_t *tree, int dir)
-{
- trav->tree = tree;
- trav->it = tree->root;
- trav->top = 0;
-
- /* Build a path to work with */
- if (trav->it != NULL)
- {
- while (trav->it->link[dir] != NULL)
- {
- trav->path[trav->top++] = trav->it;
- trav->it = trav->it->link[dir];
- }
- }
-
-#ifdef DEBUG
- if (trav->it)
- printf("[%.1f, %.1f] (%d) (%.1f)\n", trav->it->interval->low, trav->it->interval->high, *(int *)trav->it->interval->data, trav->it->max);
-#endif
-
- return trav->it == NULL ? NULL : trav->it->interval;
-}
-
-/*
- Subsequent traversal steps,
- handles ascending and descending
-*/
-static interval_t *move(itreetrav_t *trav, int dir)
-{
- if (trav->it->link[dir] != NULL)
- {
- /* Continue down this branch */
- trav->path[trav->top++] = trav->it;
- trav->it = trav->it->link[dir];
-
- while (trav->it->link[!dir] != NULL)
- {
- trav->path[trav->top++] = trav->it;
- trav->it = trav->it->link[!dir];
- }
- }
- else
- {
- /* Move to the next branch */
- itreenode_t *last;
- do
- {
- if (trav->top == 0)
- {
- trav->it = NULL;
- {
- break;
- }
- }
-
- last = trav->it;
- trav->it = trav->path[--trav->top];
- } while (last == trav->it->link[dir]);
- }
-
-#ifdef DEBUG
- if (trav->it)
- printf("[%.1f, %.1f] (%d) (%.1f)\n", trav->it->interval->low, trav->it->interval->high, *(int *)trav->it->interval->data, trav->it->max);
-#endif
-
- return trav->it == NULL ? NULL : trav->it->interval;
-}
-
-interval_t *itreetfirst(itreetrav_t *trav, itree_t *tree)
-{
- return start(trav, tree, 0); /* Min value */
-}
-
-interval_t *itreetlast(itreetrav_t *trav, itree_t *tree)
-{
- return start(trav, tree, 1); /* Max value */
-}
-
-interval_t *itreetnext(itreetrav_t *trav)
-{
- return move(trav, 1); /* Toward larger items */
-}
-
-interval_t *itreetprev(itreetrav_t *trav)
-{
- return move(trav, 0); /* Toward smaller items */
-}
diff --git a/deps/interval_tree/itree.h b/deps/interval_tree/itree.h
deleted file mode 100644
index d9abbe1..0000000
--- a/deps/interval_tree/itree.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Libitree: an interval tree library in C
- *
- * Copyright (C) 2018 Alessandro Vullo
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _INTERVAL_TREE_H_
-#define _INTERVAL_TREE_H_
-
-/*
- Interval Tree library
-
- This is an adaptation of the AVL balanced tree C library
- created by Julienne Walker which can be found here:
-
- http://www.eternallyconfuzzled.com/Libraries.aspx
-
-*/
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#include "interval.h"
-#include "interval_list.h"
-
-/* Opaque types */
-typedef struct itree itree_t;
-typedef struct itreetrav itreetrav_t;
-
-/* User-defined interval data item handling */
-typedef void *(*dup_f)(void *p);
-typedef void (*rel_f)(void *p);
-
-/* Interval tree functions */
-itree_t *itree_new(dup_f dup, rel_f rel);
-void itree_delete(itree_t *tree);
-interval_t *itree_find(itree_t *tree, interval_t *interval);
-ilist_t *itree_findall(itree_t *tree, interval_t *interval);
-int itree_insert(itree_t *tree, interval_t *interval);
-int itree_remove(itree_t *tree, interval_t *interval);
-size_t itree_size(itree_t *tree);
-
-/* Tree traversal functions */
-itreetrav_t *itreetnew(void);
-void itreetdelete(itreetrav_t *trav);
-interval_t *itreetfirst(itreetrav_t *trav, itree_t *tree);
-interval_t *itreetlast(itreetrav_t *trav, itree_t *tree);
-interval_t *itreetnext(itreetrav_t *trav);
-interval_t *itreetprev(itreetrav_t *trav);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _INTERVAL_TREE_H_ */
diff --git a/deps/interval_tree/test/gtest_interval_tree.cpp b/deps/interval_tree/test/gtest_interval_tree.cpp
index 7fe0fbc..d8b7a7b 100644
--- a/deps/interval_tree/test/gtest_interval_tree.cpp
+++ b/deps/interval_tree/test/gtest_interval_tree.cpp
@@ -1,298 +1,178 @@
#include <gtest/gtest.h>
-#include "itree.h"
+#include "interval_tree.h"
-void *my_dup(void *p)
+struct interval_tree_node *node_new(uint64_t start, uint64_t last, void *user_data)
{
- return p;
+ uint64_t size = last - start + 1;
+ struct interval_tree_node *node = (struct interval_tree_node *)calloc(1, sizeof(struct interval_tree_node) + size);
+ if (node == nullptr)
+ {
+ return nullptr;
+ }
+ node->start = start;
+ node->last = last;
+ node->user_data = (char *)node + sizeof(struct interval_tree_node);
+ memcpy(node->user_data, user_data, size);
+ printf("new node: %p, start: %lu, last: %lu, user_data: %s\n", node, node->start, node->last, (char *)node->user_data);
+
+ return node;
}
-void my_rel(void *p)
+void node_free(struct interval_tree_node *node)
{
+ if (node)
+ {
+ printf("free node: %p, start: %lu, last: %lu, user_data: %s\n", node, node->start, node->last, (char *)node->user_data);
+ free(node);
+ node = NULL;
+ }
}
-// find overlap
+struct range
+{
+ uint64_t start;
+ uint64_t last;
+};
+
#if 1
TEST(INTERVAL_TREE, FIND)
{
- itree_t *tree;
- interval_t *result;
- interval_t query;
- interval_t segment;
- void *data = (void *)"Hello";
-
- // new
- tree = itree_new(my_dup, my_rel);
- EXPECT_TRUE(tree != nullptr);
- EXPECT_TRUE(itree_size(tree) == 0);
+ struct rb_root_cached root = RB_ROOT_CACHED;
+ struct interval_tree_node *node;
// insert
- segment = {
- .low = 5,
- .high = 9,
- .data = data,
- };
- EXPECT_TRUE(itree_insert(tree, &segment) == 1);
- EXPECT_TRUE(itree_size(tree) == 1);
-
- // find
- query = {
- .low = 5,
- .high = 5,
- };
- result = itree_find(tree, &query);
- EXPECT_TRUE(result != nullptr);
- EXPECT_TRUE(result->low == 5);
- EXPECT_TRUE(result->high == 9);
- EXPECT_STREQ((const char *)result->data, "Hello");
-
- // find
- query = {
- .low = 6,
- .high = 8,
- };
- result = itree_find(tree, &query);
- EXPECT_TRUE(result != nullptr);
- EXPECT_TRUE(result->low == 5);
- EXPECT_TRUE(result->high == 9);
- EXPECT_STREQ((const char *)result->data, "Hello");
-
- // find
- query = {
- .low = 5,
- .high = 9,
- };
- result = itree_find(tree, &query);
- EXPECT_TRUE(result != nullptr);
- EXPECT_TRUE(result->low == 5);
- EXPECT_TRUE(result->high == 9);
- EXPECT_STREQ((const char *)result->data, "Hello");
-
- // find
- query = {
- .low = 9,
- .high = 9,
- };
- result = itree_find(tree, &query);
- EXPECT_TRUE(result != nullptr);
- EXPECT_TRUE(result->low == 5);
- EXPECT_TRUE(result->high == 9);
- EXPECT_STREQ((const char *)result->data, "Hello");
-
- // find
- query = {
- .low = 1,
- .high = 14,
- };
- result = itree_find(tree, &query);
- EXPECT_TRUE(result != nullptr);
- EXPECT_TRUE(result->low == 5);
- EXPECT_TRUE(result->high == 9);
- EXPECT_STREQ((const char *)result->data, "Hello");
+ node = node_new(5, 10, (void *)"Hello");
+ interval_tree_insert(node, &root);
// not found
- query = {
- .low = 1,
- .high = 4,
- };
- result = itree_find(tree, &query);
- EXPECT_TRUE(result == nullptr);
+ struct range ranges_not_found[] = {
+ {0, 4},
+ {11, 15},
+ };
+ for (size_t i = 0; i < sizeof(ranges_not_found) / sizeof(ranges_not_found[0]); i++)
+ {
+ node = interval_tree_iter_first(&root, ranges_not_found[i].start, ranges_not_found[i].last);
+ EXPECT_TRUE(node == nullptr);
+ }
+
+ // found
+ struct range ranges_found[] = {
+ // overlap interval
+ {0, 5},
+ {1, 6},
+ {2, 7},
+ {3, 8},
+ {4, 9},
+ {5, 10},
+ {6, 11},
+ {7, 12},
+ {8, 13},
+ {9, 14},
+ {10, 15},
+ // overlap point
+ {5, 5},
+ {6, 6},
+ {7, 7},
+ {8, 8},
+ {9, 9},
+ {10, 10},
+ // overlap interval
+ {5, 10},
+ {4, 11},
+ };
+ for (size_t i = 0; i < sizeof(ranges_found) / sizeof(ranges_found[0]); i++)
+ {
+ node = interval_tree_iter_first(&root, ranges_found[i].start, ranges_found[i].last);
+ EXPECT_TRUE(node != nullptr);
+ EXPECT_TRUE(node->start == 5);
+ EXPECT_TRUE(node->last == 10);
+ EXPECT_STREQ((const char *)node->user_data, "Hello");
+ }
- // not found
- query = {
- .low = 10,
- .high = 14,
- };
- result = itree_find(tree, &query);
+ // remove
+ interval_tree_remove(node, &root);
+ node_free(node);
- itree_delete(tree);
+ // find
+ node = interval_tree_iter_first(&root, 5, 10);
+ EXPECT_TRUE(node == nullptr);
}
#endif
#if 1
-TEST(INTERVAL_TREE, DELETE)
+TEST(INTERVAL_TREE, REPEAT)
{
- itree_t *tree;
- interval_t query;
- interval_t segment;
- void *data = (void *)"Hello";
-
- // new
- tree = itree_new(my_dup, my_rel);
- EXPECT_TRUE(tree != nullptr);
- EXPECT_TRUE(itree_size(tree) == 0);
+ struct rb_root_cached root = RB_ROOT_CACHED;
+ struct interval_tree_node *node;
// insert
- segment = {
- .low = 5,
- .high = 9,
- .data = data,
- };
- EXPECT_TRUE(itree_insert(tree, &segment) == 1);
- EXPECT_TRUE(itree_size(tree) == 1);
-
- // delete
- query = {
- .low = 5,
- .high = 5,
- };
- EXPECT_TRUE(itree_remove(tree, &query) == 0);
- EXPECT_TRUE(itree_size(tree) == 1);
-
- // delete
- query = {
- .low = 9,
- .high = 9,
- .data = data,
- };
- EXPECT_TRUE(itree_remove(tree, &query) == 0);
- EXPECT_TRUE(itree_size(tree) == 1);
-
- // delete
- query = {
- .low = 1,
- .high = 20,
- .data = data,
- };
- EXPECT_TRUE(itree_remove(tree, &query) == 0);
- EXPECT_TRUE(itree_size(tree) == 1);
-
- // delete
- query = {
- .low = 5,
- .high = 9,
- .data = data,
- };
- EXPECT_TRUE(itree_remove(tree, &query) == 1);
- EXPECT_TRUE(itree_size(tree) == 0);
-
- itree_delete(tree);
+ node = node_new(5, 10, (void *)"Hello");
+ interval_tree_insert(node, &root);
+
+ // insert repeat
+ node = node_new(5, 10, (void *)"World");
+ interval_tree_insert(node, &root);
+
+ node = interval_tree_iter_first(&root, 5, 10);
+ EXPECT_TRUE(node != nullptr);
+ EXPECT_TRUE(node->start == 5);
+ EXPECT_TRUE(node->last == 10);
+ EXPECT_STREQ((const char *)node->user_data, "Hello");
+
+ node = interval_tree_iter_next(node, 5, 10);
+ EXPECT_TRUE(node != nullptr);
+ EXPECT_TRUE(node->start == 5);
+ EXPECT_TRUE(node->last == 10);
+ EXPECT_STREQ((const char *)node->user_data, "World");
+
+ node = interval_tree_iter_next(node, 5, 10);
+ EXPECT_TRUE(node == nullptr);
+
+ // remove all
+ while ((node = interval_tree_iter_first(&root, 5, 10)) != nullptr)
+ {
+ interval_tree_remove(node, &root);
+ node_free(node);
+ }
}
#endif
#if 1
-TEST(INTERVAL_TREE, REPEAT1)
-{
- itree_t *tree;
- interval_t segment;
- interval_t query;
- void *data1 = (void *)"Hello";
- void *data2 = (void *)"World";
-
- // new
- tree = itree_new(my_dup, my_rel);
- EXPECT_TRUE(tree != nullptr);
- EXPECT_TRUE(itree_size(tree) == 0);
-
- // insert
- segment = {
- .low = 5,
- .high = 9,
- .data = data1,
- };
- EXPECT_TRUE(itree_insert(tree, &segment) == 1);
- EXPECT_TRUE(itree_size(tree) == 1);
-
- // insert
- segment = {
- .low = 5,
- .high = 9,
- .data = data2,
- };
- EXPECT_TRUE(itree_insert(tree, &segment) == 1);
- EXPECT_TRUE(itree_size(tree) == 2);
-
- // remove
- query = {
- .low = 5,
- .high = 9,
- .data = data1,
- };
- EXPECT_TRUE(itree_remove(tree, &query) == 1);
- EXPECT_TRUE(itree_size(tree) == 1);
- query = {
- .low = 5,
- .high = 9,
- .data = data2,
- };
- EXPECT_TRUE(itree_remove(tree, &query) == 1);
- EXPECT_TRUE(itree_size(tree) == 0);
-
- itree_delete(tree);
-}
-#endif
-
-#if 1 // repeat, return the fist one
-TEST(INTERVAL_TREE, REPEAT2)
+TEST(INTERVAL_TREE, OVERLAP)
{
- itree_t *tree;
- ilist_t *list;
- ilisttrav_t *trav;
- interval_t *result;
- interval_t query;
- interval_t segment;
-
- // new
- tree = itree_new(my_dup, my_rel);
- EXPECT_TRUE(tree != nullptr);
- EXPECT_TRUE(itree_size(tree) == 0);
-
- // insert
- segment = {
- .low = 5,
- .high = 9,
- .data = (void *)"Hello",
- };
- EXPECT_TRUE(itree_insert(tree, &segment) == 1);
- EXPECT_TRUE(itree_size(tree) == 1);
+ struct rb_root_cached root = RB_ROOT_CACHED;
+ struct interval_tree_node *node;
// insert
- segment = {
- .low = 5,
- .high = 9,
- .data = (void *)"World",
- };
- EXPECT_TRUE(itree_insert(tree, &segment) == 1);
- EXPECT_TRUE(itree_size(tree) == 2);
-
- // find
- query = {
- .low = 5,
- .high = 9,
- };
- result = itree_find(tree, &query);
- EXPECT_TRUE(result != nullptr);
- EXPECT_TRUE(result->low == 5);
- EXPECT_TRUE(result->high == 9);
- EXPECT_STREQ((const char *)result->data, "Hello");
-
- // find all, free the repeat
- query = {
- .low = 5,
- .high = 9,
- };
- list = itree_findall(tree, &query);
- EXPECT_TRUE(list != nullptr);
- EXPECT_TRUE(ilist_size(list) == 2);
- trav = ilisttrav_new(list);
- EXPECT_TRUE(trav != nullptr);
-
- result = (interval_t *)ilisttrav_first(trav);
- EXPECT_TRUE(result != nullptr);
- EXPECT_TRUE(result->low == 5);
- EXPECT_TRUE(result->high == 9);
- EXPECT_STREQ((const char *)result->data, "Hello");
-
- result = (interval_t *)ilisttrav_next(trav);
- EXPECT_TRUE(result != nullptr);
- EXPECT_TRUE(result->low == 5);
- EXPECT_TRUE(result->high == 9);
- EXPECT_STREQ((const char *)result->data, "World");
-
- ilisttrav_delete(trav);
- ilist_delete(list);
-
- itree_delete(tree);
+ node = node_new(5, 10, (void *)"Hello");
+ interval_tree_insert(node, &root);
+
+ // insert repeat
+ node = node_new(7, 12, (void *)"World");
+ interval_tree_insert(node, &root);
+
+ node = interval_tree_iter_first(&root, 5, 10);
+ EXPECT_TRUE(node != nullptr);
+ EXPECT_TRUE(node->start == 5);
+ EXPECT_TRUE(node->last == 10);
+ EXPECT_STREQ((const char *)node->user_data, "Hello");
+
+ node = interval_tree_iter_next(node, 5, 10);
+ EXPECT_TRUE(node != nullptr);
+ EXPECT_TRUE(node->start == 7);
+ EXPECT_TRUE(node->last == 12);
+ EXPECT_STREQ((const char *)node->user_data, "World");
+
+ node = interval_tree_iter_next(node, 5, 10);
+ EXPECT_TRUE(node == nullptr);
+
+ // remove all
+ while ((node = interval_tree_iter_first(&root, 5, 10)) != nullptr)
+ {
+ interval_tree_remove(node, &root);
+ node_free(node);
+ }
}
#endif
diff --git a/deps/list/list.h b/deps/list/list.h
new file mode 100644
index 0000000..f728300
--- /dev/null
+++ b/deps/list/list.h
@@ -0,0 +1,356 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ * Copyright © 2010 Francisco Jerez <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+/* Modified by Ben Skeggs <[email protected]> to match kernel list APIs */
+
+#ifndef _XORG_LIST_H_
+#define _XORG_LIST_H_
+
+/**
+ * @file Classic doubly-link circular list implementation.
+ * For real usage examples of the linked list, see the file test/list.c
+ *
+ * Example:
+ * We need to keep a list of struct foo in the parent struct bar, i.e. what
+ * we want is something like this.
+ *
+ * struct bar {
+ * ...
+ * struct foo *list_of_foos; -----> struct foo {}, struct foo {}, struct foo{}
+ * ...
+ * }
+ *
+ * We need one list head in bar and a list element in all list_of_foos (both are of
+ * data type 'struct list_head').
+ *
+ * struct bar {
+ * ...
+ * struct list_head list_of_foos;
+ * ...
+ * }
+ *
+ * struct foo {
+ * ...
+ * struct list_head entry;
+ * ...
+ * }
+ *
+ * Now we initialize the list head:
+ *
+ * struct bar bar;
+ * ...
+ * INIT_LIST_HEAD(&bar.list_of_foos);
+ *
+ * Then we create the first element and add it to this list:
+ *
+ * struct foo *foo = malloc(...);
+ * ....
+ * list_add(&foo->entry, &bar.list_of_foos);
+ *
+ * Repeat the above for each element you want to add to the list. Deleting
+ * works with the element itself.
+ * list_del(&foo->entry);
+ * free(foo);
+ *
+ * Note: calling list_del(&bar.list_of_foos) will set bar.list_of_foos to an empty
+ * list again.
+ *
+ * Looping through the list requires a 'struct foo' as iterator and the
+ * name of the field the subnodes use.
+ *
+ * struct foo *iterator;
+ * list_for_each_entry(iterator, &bar.list_of_foos, entry) {
+ * if (iterator->something == ...)
+ * ...
+ * }
+ *
+ * Note: You must not call list_del() on the iterator if you continue the
+ * loop. You need to run the safe for-each loop instead:
+ *
+ * struct foo *iterator, *next;
+ * list_for_each_entry_safe(iterator, next, &bar.list_of_foos, entry) {
+ * if (...)
+ * list_del(&iterator->entry);
+ * }
+ *
+ */
+
+/**
+ * The linkage struct for list nodes. This struct must be part of your
+ * to-be-linked struct. struct list_head is required for both the head of the
+ * list and for each list node.
+ *
+ * Position and name of the struct list_head field is irrelevant.
+ * There are no requirements that elements of a list are of the same type.
+ * There are no requirements for a list head, any struct list_head can be a list
+ * head.
+ */
+struct list_head
+{
+ struct list_head *next, *prev;
+};
+
+/**
+ * Initialize the list as an empty list.
+ *
+ * Example:
+ * INIT_LIST_HEAD(&bar->list_of_foos);
+ *
+ * @param The list to initialized.
+ */
+#define LIST_HEAD_INIT(name) \
+ { \
+ &(name), &(name) \
+ }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void
+INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list->prev = list;
+}
+
+static inline void
+__list_add(struct list_head *entry,
+ struct list_head *prev, struct list_head *next)
+{
+ next->prev = entry;
+ entry->next = next;
+ entry->prev = prev;
+ prev->next = entry;
+}
+
+/**
+ * Insert a new element after the given list head. The new element does not
+ * need to be initialised as empty list.
+ * The list changes from:
+ * head → some element → ...
+ * to
+ * head → new element → older element → ...
+ *
+ * Example:
+ * struct foo *newfoo = malloc(...);
+ * list_add(&newfoo->entry, &bar->list_of_foos);
+ *
+ * @param entry The new element to prepend to the list.
+ * @param head The existing list.
+ */
+static inline void
+list_add(struct list_head *entry, struct list_head *head)
+{
+ __list_add(entry, head, head->next);
+}
+
+/**
+ * Append a new element to the end of the list given with this list head.
+ *
+ * The list changes from:
+ * head → some element → ... → lastelement
+ * to
+ * head → some element → ... → lastelement → new element
+ *
+ * Example:
+ * struct foo *newfoo = malloc(...);
+ * list_add_tail(&newfoo->entry, &bar->list_of_foos);
+ *
+ * @param entry The new element to prepend to the list.
+ * @param head The existing list.
+ */
+static inline void
+list_add_tail(struct list_head *entry, struct list_head *head)
+{
+ __list_add(entry, head->prev, head);
+}
+
+static inline void
+__list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * Remove the element from the list it is in. Using this function will reset
+ * the pointers to/from this element so it is removed from the list. It does
+ * NOT free the element itself or manipulate it otherwise.
+ *
+ * Using list_del on a pure list head (like in the example at the top of
+ * this file) will NOT remove the first element from
+ * the list but rather reset the list as empty list.
+ *
+ * Example:
+ * list_del(&foo->entry);
+ *
+ * @param entry The element to remove.
+ */
+static inline void
+list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void
+list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * Check if the list is empty.
+ *
+ * Example:
+ * list_empty(&bar->list_of_foos);
+ *
+ * @return True if the list contains one or more elements or False otherwise.
+ */
+static inline bool
+list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * Returns a pointer to the container of this list element.
+ *
+ * Example:
+ * struct foo* f;
+ * f = container_of(&foo->entry, struct foo, entry);
+ * assert(f == foo);
+ *
+ * @param ptr Pointer to the struct list_head.
+ * @param type Data type of the list element.
+ * @param member Member name of the struct list_head field in the list element.
+ * @return A pointer to the data struct containing the list head.
+ */
+#ifndef container_of
+#define container_of(ptr, type, member) \
+ (type *)((char *)(ptr) - (char *)&((type *)0)->member)
+#endif
+
+/**
+ * Alias of container_of
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * Retrieve the first list entry for the given list pointer.
+ *
+ * Example:
+ * struct foo *first;
+ * first = list_first_entry(&bar->list_of_foos, struct foo, list_of_foos);
+ *
+ * @param ptr The list head
+ * @param type Data type of the list element to retrieve
+ * @param member Member name of the struct list_head field in the list element.
+ * @return A pointer to the first list element.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * Retrieve the last list entry for the given listpointer.
+ *
+ * Example:
+ * struct foo *first;
+ * first = list_last_entry(&bar->list_of_foos, struct foo, list_of_foos);
+ *
+ * @param ptr The list head
+ * @param type Data type of the list element to retrieve
+ * @param member Member name of the struct list_head field in the list element.
+ * @return A pointer to the last list element.
+ */
+#define list_last_entry(ptr, type, member) \
+ list_entry((ptr)->prev, type, member)
+
+#define __container_of(ptr, sample, member) \
+ (void *)container_of((ptr), typeof(*(sample)), member)
+
+/**
+ * Loop through the list given by head and set pos to struct in the list.
+ *
+ * Example:
+ * struct foo *iterator;
+ * list_for_each_entry(iterator, &bar->list_of_foos, entry) {
+ * [modify iterator]
+ * }
+ *
+ * This macro is not safe for node deletion. Use list_for_each_entry_safe
+ * instead.
+ *
+ * @param pos Iterator variable of the type of the list elements.
+ * @param head List head
+ * @param member Member name of the struct list_head in the list elements.
+ *
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = __container_of((head)->next, pos, member); \
+ &pos->member != (head); \
+ pos = __container_of(pos->member.next, pos, member))
+
+/**
+ * Loop through the list, keeping a backup pointer to the element. This
+ * macro allows for the deletion of a list element while looping through the
+ * list.
+ *
+ * See list_for_each_entry for more details.
+ */
+#define list_for_each_entry_safe(pos, tmp, head, member) \
+ for (pos = __container_of((head)->next, pos, member), \
+ tmp = __container_of(pos->member.next, pos, member); \
+ &pos->member != (head); \
+ pos = tmp, tmp = __container_of(pos->member.next, tmp, member))
+
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = __container_of((head)->prev, pos, member); \
+ &pos->member != (head); \
+ pos = __container_of(pos->member.prev, pos, member))
+
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = __container_of(pos->member.next, pos, member); \
+ &pos->member != (head); \
+ pos = __container_of(pos->member.next, pos, member))
+
+#define list_for_each_entry_continue_reverse(pos, head, member) \
+ for (pos = __container_of(pos->member.prev, pos, member); \
+ &pos->member != (head); \
+ pos = __container_of(pos->member.prev, pos, member))
+
+#define list_for_each_entry_from(pos, head, member) \
+ for (; \
+ &pos->member != (head); \
+ pos = __container_of(pos->member.next, pos, member))
+
+#endif
diff --git a/deps/rbtree/CMakeLists.txt b/deps/rbtree/CMakeLists.txt
new file mode 100644
index 0000000..c7debda
--- /dev/null
+++ b/deps/rbtree/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(rbtree STATIC rbtree.cpp)
+target_include_directories(rbtree PUBLIC ${CMAKE_CURRENT_LIST_DIR}) \ No newline at end of file
diff --git a/deps/rbtree/rbtree.cpp b/deps/rbtree/rbtree.cpp
new file mode 100644
index 0000000..d648a94
--- /dev/null
+++ b/deps/rbtree/rbtree.cpp
@@ -0,0 +1,624 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <[email protected]>
+ (C) 2002 David Woodhouse <[email protected]>
+ (C) 2012 Michel Lespinasse <[email protected]>
+
+
+ linux/lib/rbtree.c
+*/
+
+#include "rbtree_augmented.h"
+
+/*
+ * red-black trees properties: https://en.wikipedia.org/wiki/Rbtree
+ *
+ * 1) A node is either red or black
+ * 2) The root is black
+ * 3) All leaves (NULL) are black
+ * 4) Both children of every red node are black
+ * 5) Every simple path from root to leaves contains the same number
+ * of black nodes.
+ *
+ * 4 and 5 give the O(log n) guarantee, since 4 implies you cannot have two
+ * consecutive red nodes in a path and every red node is therefore followed by
+ * a black. So if B is the number of black nodes on every simple path (as per
+ * 5), then the longest possible path due to 4 is 2B.
+ *
+ * We shall indicate color with case, where black nodes are uppercase and red
+ * nodes will be lowercase. Unknown color nodes shall be drawn as red within
+ * parentheses and have some accompanying text comment.
+ */
+
+/*
+ * Notes on lockless lookups:
+ *
+ * All stores to the tree structure (rb_left and rb_right) must be done using
+ * WRITE_ONCE(). And we must not inadvertently cause (temporary) loops in the
+ * tree structure as seen in program order.
+ *
+ * These two requirements will allow lockless iteration of the tree -- not
+ * correct iteration mind you, tree rotations are not atomic so a lookup might
+ * miss entire subtrees.
+ *
+ * But they do guarantee that any such traversal will only see valid elements
+ * and that it will indeed complete -- does not get stuck in a loop.
+ *
+ * It also guarantees that if the lookup returns an element it is the 'correct'
+ * one. But not returning an element does _NOT_ mean it's not present.
+ *
+ * NOTE:
+ *
+ * Stores to __rb_parent_color are not important for simple lookups so those
+ * are left undone as of now. Nor did I check for loops involving parent
+ * pointers.
+ */
+
+#define likely(expr) __builtin_expect((expr), 1)
+#define unlikely(expr) __builtin_expect((expr), 0)
+
+static inline void rb_set_black(struct rb_node *rb)
+{
+ rb->__rb_parent_color |= RB_BLACK;
+}
+
+static inline struct rb_node *rb_red_parent(struct rb_node *red)
+{
+ return (struct rb_node *)red->__rb_parent_color;
+}
+
+/*
+ * Helper function for rotations:
+ * - old's parent and color get assigned to new
+ * - old gets assigned new as a parent and 'color' as a color.
+ */
+static inline void
+__rb_rotate_set_parents(struct rb_node *old, struct rb_node *new_node,
+ struct rb_root *root, int color)
+{
+ struct rb_node *parent = rb_parent(old);
+ new_node->__rb_parent_color = old->__rb_parent_color;
+ rb_set_parent_color(old, new_node, color);
+ __rb_change_child(old, new_node, parent, root);
+}
+
+static inline void
+__rb_insert(struct rb_node *node, struct rb_root *root,
+ void (*augment_rotate)(struct rb_node *old, struct rb_node *new_node))
+{
+ struct rb_node *parent = rb_red_parent(node), *gparent, *tmp;
+
+ while (true)
+ {
+ /*
+ * Loop invariant: node is red.
+ */
+ if (unlikely(!parent))
+ {
+ /*
+ * The inserted node is root. Either this is the
+ * first node, or we recursed at Case 1 below and
+ * are no longer violating 4).
+ */
+ rb_set_parent_color(node, NULL, RB_BLACK);
+ break;
+ }
+
+ /*
+ * If there is a black parent, we are done.
+ * Otherwise, take some corrective action as,
+ * per 4), we don't want a red root or two
+ * consecutive red nodes.
+ */
+ if (rb_is_black(parent))
+ break;
+
+ gparent = rb_red_parent(parent);
+
+ tmp = gparent->rb_right;
+ if (parent != tmp)
+ { /* parent == gparent->rb_left */
+ if (tmp && rb_is_red(tmp))
+ {
+ /*
+ * Case 1 - node's uncle is red (color flips).
+ *
+ * G g
+ * / \ / \
+ * p u --> P U
+ * / /
+ * n n
+ *
+ * However, since g's parent might be red, and
+ * 4) does not allow this, we need to recurse
+ * at g.
+ */
+ rb_set_parent_color(tmp, gparent, RB_BLACK);
+ rb_set_parent_color(parent, gparent, RB_BLACK);
+ node = gparent;
+ parent = rb_parent(node);
+ rb_set_parent_color(node, parent, RB_RED);
+ continue;
+ }
+
+ tmp = parent->rb_right;
+ if (node == tmp)
+ {
+ /*
+ * Case 2 - node's uncle is black and node is
+ * the parent's right child (left rotate at parent).
+ *
+ * G G
+ * / \ / \
+ * p U --> n U
+ * \ /
+ * n p
+ *
+ * This still leaves us in violation of 4), the
+ * continuation into Case 3 will fix that.
+ */
+ tmp = node->rb_left;
+ parent->rb_right = tmp;
+ node->rb_left = parent;
+ if (tmp)
+ rb_set_parent_color(tmp, parent,
+ RB_BLACK);
+ rb_set_parent_color(parent, node, RB_RED);
+ augment_rotate(parent, node);
+ parent = node;
+ tmp = node->rb_right;
+ }
+
+ /*
+ * Case 3 - node's uncle is black and node is
+ * the parent's left child (right rotate at gparent).
+ *
+ * G P
+ * / \ / \
+ * p U --> n g
+ * / \
+ * n U
+ */
+ gparent->rb_left = tmp; /* == parent->rb_right */
+ parent->rb_right = gparent;
+ if (tmp)
+ rb_set_parent_color(tmp, gparent, RB_BLACK);
+ __rb_rotate_set_parents(gparent, parent, root, RB_RED);
+ augment_rotate(gparent, parent);
+ break;
+ }
+ else
+ {
+ tmp = gparent->rb_left;
+ if (tmp && rb_is_red(tmp))
+ {
+ /* Case 1 - color flips */
+ rb_set_parent_color(tmp, gparent, RB_BLACK);
+ rb_set_parent_color(parent, gparent, RB_BLACK);
+ node = gparent;
+ parent = rb_parent(node);
+ rb_set_parent_color(node, parent, RB_RED);
+ continue;
+ }
+
+ tmp = parent->rb_left;
+ if (node == tmp)
+ {
+ /* Case 2 - right rotate at parent */
+ tmp = node->rb_right;
+ parent->rb_left = tmp;
+ node->rb_right = parent;
+ if (tmp)
+ rb_set_parent_color(tmp, parent,
+ RB_BLACK);
+ rb_set_parent_color(parent, node, RB_RED);
+ augment_rotate(parent, node);
+ parent = node;
+ tmp = node->rb_left;
+ }
+
+ /* Case 3 - left rotate at gparent */
+ gparent->rb_right = tmp; /* == parent->rb_left */
+ parent->rb_left = gparent;
+ if (tmp)
+ rb_set_parent_color(tmp, gparent, RB_BLACK);
+ __rb_rotate_set_parents(gparent, parent, root, RB_RED);
+ augment_rotate(gparent, parent);
+ break;
+ }
+ }
+}
+
+/*
+ * Inline version for rb_erase() use - we want to be able to inline
+ * and eliminate the dummy_rotate callback there
+ */
+static inline void
+____rb_erase_color(struct rb_node *parent, struct rb_root *root,
+ void (*augment_rotate)(struct rb_node *old, struct rb_node *new_node))
+{
+ struct rb_node *node = NULL, *sibling, *tmp1, *tmp2;
+
+ while (true)
+ {
+ /*
+ * Loop invariants:
+ * - node is black (or NULL on first iteration)
+ * - node is not the root (parent is not NULL)
+ * - All leaf paths going through parent and node have a
+ * black node count that is 1 lower than other leaf paths.
+ */
+ sibling = parent->rb_right;
+ if (node != sibling)
+ { /* node == parent->rb_left */
+ if (rb_is_red(sibling))
+ {
+ /*
+ * Case 1 - left rotate at parent
+ *
+ * P S
+ * / \ / \
+ * N s --> p Sr
+ * / \ / \
+ * Sl Sr N Sl
+ */
+ tmp1 = sibling->rb_left;
+ parent->rb_right = tmp1;
+ sibling->rb_left = parent;
+ rb_set_parent_color(tmp1, parent, RB_BLACK);
+ __rb_rotate_set_parents(parent, sibling, root,
+ RB_RED);
+ augment_rotate(parent, sibling);
+ sibling = tmp1;
+ }
+ tmp1 = sibling->rb_right;
+ if (!tmp1 || rb_is_black(tmp1))
+ {
+ tmp2 = sibling->rb_left;
+ if (!tmp2 || rb_is_black(tmp2))
+ {
+ /*
+ * Case 2 - sibling color flip
+ * (p could be either color here)
+ *
+ * (p) (p)
+ * / \ / \
+ * N S --> N s
+ * / \ / \
+ * Sl Sr Sl Sr
+ *
+ * This leaves us violating 5) which
+ * can be fixed by flipping p to black
+ * if it was red, or by recursing at p.
+ * p is red when coming from Case 1.
+ */
+ rb_set_parent_color(sibling, parent,
+ RB_RED);
+ if (rb_is_red(parent))
+ rb_set_black(parent);
+ else
+ {
+ node = parent;
+ parent = rb_parent(node);
+ if (parent)
+ continue;
+ }
+ break;
+ }
+ /*
+ * Case 3 - right rotate at sibling
+ * (p could be either color here)
+ *
+ * (p) (p)
+ * / \ / \
+ * N S --> N sl
+ * / \ \
+ * sl Sr S
+ * \
+ * Sr
+ *
+ * Note: p might be red, and then both
+ * p and sl are red after rotation(which
+ * breaks property 4). This is fixed in
+ * Case 4 (in __rb_rotate_set_parents()
+ * which set sl the color of p
+ * and set p RB_BLACK)
+ *
+ * (p) (sl)
+ * / \ / \
+ * N sl --> P S
+ * \ / \
+ * S N Sr
+ * \
+ * Sr
+ */
+ tmp1 = tmp2->rb_right;
+ sibling->rb_left = tmp1;
+ tmp2->rb_right = sibling;
+ parent->rb_right = tmp2;
+ if (tmp1)
+ rb_set_parent_color(tmp1, sibling,
+ RB_BLACK);
+ augment_rotate(sibling, tmp2);
+ tmp1 = sibling;
+ sibling = tmp2;
+ }
+ /*
+ * Case 4 - left rotate at parent + color flips
+ * (p and sl could be either color here.
+ * After rotation, p becomes black, s acquires
+ * p's color, and sl keeps its color)
+ *
+ * (p) (s)
+ * / \ / \
+ * N S --> P Sr
+ * / \ / \
+ * (sl) sr N (sl)
+ */
+ tmp2 = sibling->rb_left;
+ parent->rb_right = tmp2;
+ sibling->rb_left = parent;
+ rb_set_parent_color(tmp1, sibling, RB_BLACK);
+ if (tmp2)
+ rb_set_parent(tmp2, parent);
+ __rb_rotate_set_parents(parent, sibling, root,
+ RB_BLACK);
+ augment_rotate(parent, sibling);
+ break;
+ }
+ else
+ {
+ sibling = parent->rb_left;
+ if (rb_is_red(sibling))
+ {
+ /* Case 1 - right rotate at parent */
+ tmp1 = sibling->rb_right;
+ parent->rb_left = tmp1;
+ sibling->rb_right = parent;
+ rb_set_parent_color(tmp1, parent, RB_BLACK);
+ __rb_rotate_set_parents(parent, sibling, root,
+ RB_RED);
+ augment_rotate(parent, sibling);
+ sibling = tmp1;
+ }
+ tmp1 = sibling->rb_left;
+ if (!tmp1 || rb_is_black(tmp1))
+ {
+ tmp2 = sibling->rb_right;
+ if (!tmp2 || rb_is_black(tmp2))
+ {
+ /* Case 2 - sibling color flip */
+ rb_set_parent_color(sibling, parent,
+ RB_RED);
+ if (rb_is_red(parent))
+ rb_set_black(parent);
+ else
+ {
+ node = parent;
+ parent = rb_parent(node);
+ if (parent)
+ continue;
+ }
+ break;
+ }
+ /* Case 3 - left rotate at sibling */
+ tmp1 = tmp2->rb_left;
+ sibling->rb_right = tmp1;
+ tmp2->rb_left = sibling;
+ parent->rb_left = tmp2;
+ if (tmp1)
+ rb_set_parent_color(tmp1, sibling,
+ RB_BLACK);
+ augment_rotate(sibling, tmp2);
+ tmp1 = sibling;
+ sibling = tmp2;
+ }
+ /* Case 4 - right rotate at parent + color flips */
+ tmp2 = sibling->rb_right;
+ parent->rb_left = tmp2;
+ sibling->rb_right = parent;
+ rb_set_parent_color(tmp1, sibling, RB_BLACK);
+ if (tmp2)
+ rb_set_parent(tmp2, parent);
+ __rb_rotate_set_parents(parent, sibling, root,
+ RB_BLACK);
+ augment_rotate(parent, sibling);
+ break;
+ }
+ }
+}
+
+/* Non-inline version for rb_erase_augmented() use */
+void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
+ void (*augment_rotate)(struct rb_node *old, struct rb_node *new_node))
+{
+ ____rb_erase_color(parent, root, augment_rotate);
+}
+
+/*
+ * Non-augmented rbtree manipulation functions.
+ *
+ * We use dummy augmented callbacks here, and have the compiler optimize them
+ * out of the rb_insert_color() and rb_erase() function definitions.
+ */
+
+static inline void dummy_propagate(struct rb_node *node, struct rb_node *stop) {}
+static inline void dummy_copy(struct rb_node *old, struct rb_node *new_node) {}
+static inline void dummy_rotate(struct rb_node *old, struct rb_node *new_node) {}
+
+static const struct rb_augment_callbacks dummy_callbacks = {
+ .propagate = dummy_propagate,
+ .copy = dummy_copy,
+ .rotate = dummy_rotate};
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+ __rb_insert(node, root, dummy_rotate);
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *rebalance;
+ rebalance = __rb_erase_augmented(node, root, &dummy_callbacks);
+ if (rebalance)
+ ____rb_erase_color(rebalance, root, dummy_rotate);
+}
+
+/*
+ * Augmented rbtree manipulation functions.
+ *
+ * This instantiates the same inline functions as in the non-augmented
+ * case, but this time with user-defined callbacks.
+ */
+
+void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
+ void (*augment_rotate)(struct rb_node *old, struct rb_node *new_node))
+{
+ __rb_insert(node, root, augment_rotate);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(const struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_left)
+ n = n->rb_left;
+ return n;
+}
+
+struct rb_node *rb_last(const struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_right)
+ n = n->rb_right;
+ return n;
+}
+
+struct rb_node *rb_next(const struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (RB_EMPTY_NODE(node))
+ return NULL;
+
+ /*
+ * If we have a right-hand child, go down and then left as far
+ * as we can.
+ */
+ if (node->rb_right)
+ {
+ node = node->rb_right;
+ while (node->rb_left)
+ node = node->rb_left;
+ return (struct rb_node *)node;
+ }
+
+ /*
+ * No right-hand children. Everything down and left is smaller than us,
+ * so any 'next' node must be in the general direction of our parent.
+ * Go up the tree; any time the ancestor is a right-hand child of its
+ * parent, keep going up. First time it's a left-hand child of its
+ * parent, said parent is our 'next' node.
+ */
+ while ((parent = rb_parent(node)) && node == parent->rb_right)
+ node = parent;
+
+ return parent;
+}
+
+struct rb_node *rb_prev(const struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (RB_EMPTY_NODE(node))
+ return NULL;
+
+ /*
+ * If we have a left-hand child, go down and then right as far
+ * as we can.
+ */
+ if (node->rb_left)
+ {
+ node = node->rb_left;
+ while (node->rb_right)
+ node = node->rb_right;
+ return (struct rb_node *)node;
+ }
+
+ /*
+ * No left-hand children. Go up till we find an ancestor which
+ * is a right-hand child of its parent.
+ */
+ while ((parent = rb_parent(node)) && node == parent->rb_left)
+ node = parent;
+
+ return parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new_node,
+ struct rb_root *root)
+{
+ struct rb_node *parent = rb_parent(victim);
+
+ /* Copy the pointers/colour from the victim to the replacement */
+ *new_node = *victim;
+
+ /* Set the surrounding nodes to point to the replacement */
+ if (victim->rb_left)
+ rb_set_parent(victim->rb_left, new_node);
+ if (victim->rb_right)
+ rb_set_parent(victim->rb_right, new_node);
+ __rb_change_child(victim, new_node, parent, root);
+}
+
+static struct rb_node *rb_left_deepest_node(const struct rb_node *node)
+{
+ for (;;)
+ {
+ if (node->rb_left)
+ node = node->rb_left;
+ else if (node->rb_right)
+ node = node->rb_right;
+ else
+ return (struct rb_node *)node;
+ }
+}
+
+struct rb_node *rb_next_postorder(const struct rb_node *node)
+{
+ const struct rb_node *parent;
+ if (!node)
+ return NULL;
+ parent = rb_parent(node);
+
+ /* If we're sitting on node, we've already seen our children */
+ if (parent && node == parent->rb_left && parent->rb_right)
+ {
+ /* If we are the parent's left node, go to the parent's right
+ * node then all the way down to the left */
+ return rb_left_deepest_node(parent->rb_right);
+ }
+ else
+ /* Otherwise we are the parent's right node, and the parent
+ * should be next */
+ return (struct rb_node *)parent;
+}
+
+struct rb_node *rb_first_postorder(const struct rb_root *root)
+{
+ if (!root->rb_node)
+ return NULL;
+
+ return rb_left_deepest_node(root->rb_node);
+}
diff --git a/deps/rbtree/rbtree.h b/deps/rbtree/rbtree.h
new file mode 100644
index 0000000..25bd4da
--- /dev/null
+++ b/deps/rbtree/rbtree.h
@@ -0,0 +1,383 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <[email protected]>
+
+
+ linux/include/linux/rbtree.h
+
+ To use rbtrees you'll have to implement your own insert and search cores.
+ This will avoid us to use callbacks and to drop drammatically performances.
+ I know it's not the cleaner way, but in C (not in C++) to get
+ performances and genericity...
+
+ See Documentation/core-api/rbtree.rst for documentation and samples.
+*/
+
+#ifndef _LINUX_RBTREE_H
+#define _LINUX_RBTREE_H
+
+#include <stdlib.h>
+
+struct rb_node
+{
+ unsigned long __rb_parent_color;
+ struct rb_node *rb_right;
+ struct rb_node *rb_left;
+} __attribute__((aligned(sizeof(long))));
+/* The alignment might seem pointless, but allegedly CRIS needs it */
+
+struct rb_root
+{
+ struct rb_node *rb_node;
+};
+
+/*
+ * Leftmost-cached rbtrees.
+ *
+ * We do not cache the rightmost node based on footprint
+ * size vs number of potential users that could benefit
+ * from O(1) rb_last(). Just not worth it, users that want
+ * this feature can always implement the logic explicitly.
+ * Furthermore, users that want to cache both pointers may
+ * find it a bit asymmetric, but that's ok.
+ */
+struct rb_root_cached
+{
+ struct rb_root rb_root;
+ struct rb_node *rb_leftmost;
+};
+
+#define RB_ROOT \
+ (struct rb_root) { NULL, }
+#define RB_ROOT_CACHED \
+ (struct rb_root_cached) { { \
+ NULL, \
+ }, \
+ NULL }
+
+/**
+ * Returns a pointer to the container of this list element.
+ *
+ * Example:
+ * struct foo* f;
+ * f = container_of(&foo->entry, struct foo, entry);
+ * assert(f == foo);
+ *
+ * @param ptr Pointer to the struct list_head.
+ * @param type Data type of the list element.
+ * @param member Member name of the struct list_head field in the list element.
+ * @return A pointer to the data struct containing the list head.
+ */
+#ifndef container_of
+#define container_of(ptr, type, member) \
+ (type *)((char *)(ptr) - (char *)&((type *)0)->member)
+#endif
+
+#define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3))
+
+#define rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define RB_EMPTY_ROOT(root) (READ_ONCE((root)->rb_node) == NULL)
+
+/* 'empty' nodes are nodes that are known not to be inserted in an rbtree */
+#define RB_EMPTY_NODE(node) \
+ ((node)->__rb_parent_color == (unsigned long)(node))
+#define RB_CLEAR_NODE(node) \
+ ((node)->__rb_parent_color = (unsigned long)(node))
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(const struct rb_node *);
+extern struct rb_node *rb_prev(const struct rb_node *);
+extern struct rb_node *rb_first(const struct rb_root *);
+extern struct rb_node *rb_last(const struct rb_root *);
+
+/* Postorder iteration - always visit the parent after its children */
+extern struct rb_node *rb_first_postorder(const struct rb_root *);
+extern struct rb_node *rb_next_postorder(const struct rb_node *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new_node,
+ struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node *node, struct rb_node *parent,
+ struct rb_node **rb_link)
+{
+ node->__rb_parent_color = (unsigned long)parent;
+ node->rb_left = node->rb_right = NULL;
+
+ *rb_link = node;
+}
+
+#define rb_entry_safe(ptr, type, member) \
+ ({ \
+ typeof(ptr) ____ptr = (ptr); \
+ ____ptr ? rb_entry(____ptr, type, member) : NULL; \
+ })
+
+/**
+ * rbtree_postorder_for_each_entry_safe - iterate in post-order over rb_root of
+ * given type allowing the backing memory of @pos to be invalidated
+ *
+ * @pos: the 'type *' to use as a loop cursor.
+ * @n: another 'type *' to use as temporary storage
+ * @root: 'rb_root *' of the rbtree.
+ * @field: the name of the rb_node field within 'type'.
+ *
+ * rbtree_postorder_for_each_entry_safe() provides a similar guarantee as
+ * list_for_each_entry_safe() and allows the iteration to continue independent
+ * of changes to @pos by the body of the loop.
+ *
+ * Note, however, that it cannot handle other modifications that re-order the
+ * rbtree it is iterating over. This includes calling rb_erase() on @pos, as
+ * rb_erase() may rebalance the tree, causing us to miss some nodes.
+ */
+#define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \
+ for (pos = rb_entry_safe(rb_first_postorder(root), typeof(*pos), field); \
+ pos && ({ n = rb_entry_safe(rb_next_postorder(&pos->field), \
+ typeof(*pos), field); 1; }); \
+ pos = n)
+
+/* Same as rb_first(), but O(1) */
+#define rb_first_cached(root) (root)->rb_leftmost
+
+static inline void rb_insert_color_cached(struct rb_node *node,
+ struct rb_root_cached *root,
+ bool leftmost)
+{
+ if (leftmost)
+ root->rb_leftmost = node;
+ rb_insert_color(node, &root->rb_root);
+}
+
+static inline struct rb_node *
+rb_erase_cached(struct rb_node *node, struct rb_root_cached *root)
+{
+ struct rb_node *leftmost = NULL;
+
+ if (root->rb_leftmost == node)
+ leftmost = root->rb_leftmost = rb_next(node);
+
+ rb_erase(node, &root->rb_root);
+
+ return leftmost;
+}
+
+static inline void rb_replace_node_cached(struct rb_node *victim,
+ struct rb_node *new_node,
+ struct rb_root_cached *root)
+{
+ if (root->rb_leftmost == victim)
+ root->rb_leftmost = new_node;
+ rb_replace_node(victim, new_node, &root->rb_root);
+}
+
+/*
+ * The below helper functions use 2 operators with 3 different
+ * calling conventions. The operators are related like:
+ *
+ * comp(a->key,b) < 0 := less(a,b)
+ * comp(a->key,b) > 0 := less(b,a)
+ * comp(a->key,b) == 0 := !less(a,b) && !less(b,a)
+ *
+ * If these operators define a partial order on the elements we make no
+ * guarantee on which of the elements matching the key is found. See
+ * rb_find().
+ *
+ * The reason for this is to allow the find() interface without requiring an
+ * on-stack dummy object, which might not be feasible due to object size.
+ */
+
+/**
+ * rb_add_cached() - insert @node into the leftmost cached tree @tree
+ * @node: node to insert
+ * @tree: leftmost cached tree to insert @node into
+ * @less: operator defining the (partial) node order
+ *
+ * Returns @node when it is the new leftmost, or NULL.
+ */
+static inline struct rb_node *
+rb_add_cached(struct rb_node *node, struct rb_root_cached *tree,
+ bool (*less)(struct rb_node *, const struct rb_node *))
+{
+ struct rb_node **link = &tree->rb_root.rb_node;
+ struct rb_node *parent = NULL;
+ bool leftmost = true;
+
+ while (*link)
+ {
+ parent = *link;
+ if (less(node, parent))
+ {
+ link = &parent->rb_left;
+ }
+ else
+ {
+ link = &parent->rb_right;
+ leftmost = false;
+ }
+ }
+
+ rb_link_node(node, parent, link);
+ rb_insert_color_cached(node, tree, leftmost);
+
+ return leftmost ? node : NULL;
+}
+
+/**
+ * rb_add() - insert @node into @tree
+ * @node: node to insert
+ * @tree: tree to insert @node into
+ * @less: operator defining the (partial) node order
+ */
+static inline void
+rb_add(struct rb_node *node, struct rb_root *tree,
+ bool (*less)(struct rb_node *, const struct rb_node *))
+{
+ struct rb_node **link = &tree->rb_node;
+ struct rb_node *parent = NULL;
+
+ while (*link)
+ {
+ parent = *link;
+ if (less(node, parent))
+ link = &parent->rb_left;
+ else
+ link = &parent->rb_right;
+ }
+
+ rb_link_node(node, parent, link);
+ rb_insert_color(node, tree);
+}
+
+/**
+ * rb_find_add() - find equivalent @node in @tree, or add @node
+ * @node: node to look-for / insert
+ * @tree: tree to search / modify
+ * @cmp: operator defining the node order
+ *
+ * Returns the rb_node matching @node, or NULL when no match is found and @node
+ * is inserted.
+ */
+static inline struct rb_node *
+rb_find_add(struct rb_node *node, struct rb_root *tree,
+ int (*cmp)(struct rb_node *, const struct rb_node *))
+{
+ struct rb_node **link = &tree->rb_node;
+ struct rb_node *parent = NULL;
+ int c;
+
+ while (*link)
+ {
+ parent = *link;
+ c = cmp(node, parent);
+
+ if (c < 0)
+ link = &parent->rb_left;
+ else if (c > 0)
+ link = &parent->rb_right;
+ else
+ return parent;
+ }
+
+ rb_link_node(node, parent, link);
+ rb_insert_color(node, tree);
+ return NULL;
+}
+
+/**
+ * rb_find() - find @key in tree @tree
+ * @key: key to match
+ * @tree: tree to search
+ * @cmp: operator defining the node order
+ *
+ * Returns the rb_node matching @key or NULL.
+ */
+static inline struct rb_node *
+rb_find(const void *key, const struct rb_root *tree,
+ int (*cmp)(const void *key, const struct rb_node *))
+{
+ struct rb_node *node = tree->rb_node;
+
+ while (node)
+ {
+ int c = cmp(key, node);
+
+ if (c < 0)
+ node = node->rb_left;
+ else if (c > 0)
+ node = node->rb_right;
+ else
+ return node;
+ }
+
+ return NULL;
+}
+
+/**
+ * rb_find_first() - find the first @key in @tree
+ * @key: key to match
+ * @tree: tree to search
+ * @cmp: operator defining node order
+ *
+ * Returns the leftmost node matching @key, or NULL.
+ */
+static inline struct rb_node *
+rb_find_first(const void *key, const struct rb_root *tree,
+ int (*cmp)(const void *key, const struct rb_node *))
+{
+ struct rb_node *node = tree->rb_node;
+ struct rb_node *match = NULL;
+
+ while (node)
+ {
+ int c = cmp(key, node);
+
+ if (c <= 0)
+ {
+ if (!c)
+ match = node;
+ node = node->rb_left;
+ }
+ else if (c > 0)
+ {
+ node = node->rb_right;
+ }
+ }
+
+ return match;
+}
+
+/**
+ * rb_next_match() - find the next @key in @tree
+ * @key: key to match
+ * @tree: tree to search
+ * @cmp: operator defining node order
+ *
+ * Returns the next node matching @key, or NULL.
+ */
+static inline struct rb_node *
+rb_next_match(const void *key, struct rb_node *node,
+ int (*cmp)(const void *key, const struct rb_node *))
+{
+ node = rb_next(node);
+ if (node && cmp(key, node))
+ node = NULL;
+ return node;
+}
+
+/**
+ * rb_for_each() - iterates a subtree matching @key
+ * @node: iterator
+ * @key: key to match
+ * @tree: tree to search
+ * @cmp: operator defining node order
+ */
+#define rb_for_each(node, key, tree, cmp) \
+ for ((node) = rb_find_first((key), (tree), (cmp)); \
+ (node); (node) = rb_next_match((key), (node), (cmp)))
+
+#endif /* _LINUX_RBTREE_H */
diff --git a/deps/rbtree/rbtree_augmented.h b/deps/rbtree/rbtree_augmented.h
new file mode 100644
index 0000000..add1ee5
--- /dev/null
+++ b/deps/rbtree/rbtree_augmented.h
@@ -0,0 +1,320 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <[email protected]>
+ (C) 2002 David Woodhouse <[email protected]>
+ (C) 2012 Michel Lespinasse <[email protected]>
+
+
+ linux/include/linux/rbtree_augmented.h
+*/
+
+#ifndef _LINUX_RBTREE_AUGMENTED_H
+#define _LINUX_RBTREE_AUGMENTED_H
+
+#include "rbtree.h"
+
+/*
+ * Please note - only struct rb_augment_callbacks and the prototypes for
+ * rb_insert_augmented() and rb_erase_augmented() are intended to be public.
+ * The rest are implementation details you are not expected to depend on.
+ *
+ * See Documentation/core-api/rbtree.rst for documentation and samples.
+ */
+
+struct rb_augment_callbacks
+{
+ void (*propagate)(struct rb_node *node, struct rb_node *stop);
+ void (*copy)(struct rb_node *old, struct rb_node *new_node);
+ void (*rotate)(struct rb_node *old, struct rb_node *new_node);
+};
+
+extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
+ void (*augment_rotate)(struct rb_node *old, struct rb_node *new_node));
+
+/*
+ * Fixup the rbtree and update the augmented information when rebalancing.
+ *
+ * On insertion, the user must update the augmented information on the path
+ * leading to the inserted node, then call rb_link_node() as usual and
+ * rb_insert_augmented() instead of the usual rb_insert_color() call.
+ * If rb_insert_augmented() rebalances the rbtree, it will callback into
+ * a user provided function to update the augmented information on the
+ * affected subtrees.
+ */
+static inline void
+rb_insert_augmented(struct rb_node *node, struct rb_root *root,
+ const struct rb_augment_callbacks *augment)
+{
+ __rb_insert_augmented(node, root, augment->rotate);
+}
+
+static inline void
+rb_insert_augmented_cached(struct rb_node *node,
+ struct rb_root_cached *root, bool newleft,
+ const struct rb_augment_callbacks *augment)
+{
+ if (newleft)
+ root->rb_leftmost = node;
+ rb_insert_augmented(node, &root->rb_root, augment);
+}
+
+/*
+ * Template for declaring augmented rbtree callbacks (generic case)
+ *
+ * RBSTATIC: 'static' or empty
+ * RBNAME: name of the rb_augment_callbacks structure
+ * RBSTRUCT: struct type of the tree nodes
+ * RBFIELD: name of struct rb_node field within RBSTRUCT
+ * RBAUGMENTED: name of field within RBSTRUCT holding data for subtree
+ * RBCOMPUTE: name of function that recomputes the RBAUGMENTED data
+ */
+
+#define RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \
+ RBSTRUCT, RBFIELD, RBAUGMENTED, RBCOMPUTE) \
+ static inline void \
+ RBNAME##_propagate(struct rb_node *rb, struct rb_node *stop) \
+ { \
+ while (rb != stop) \
+ { \
+ RBSTRUCT *node = rb_entry(rb, RBSTRUCT, RBFIELD); \
+ if (RBCOMPUTE(node, true)) \
+ break; \
+ rb = rb_parent(&node->RBFIELD); \
+ } \
+ } \
+ static inline void \
+ RBNAME##_copy(struct rb_node *rb_old, struct rb_node *rb_new) \
+ { \
+ RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD); \
+ RBSTRUCT *new_node = rb_entry(rb_new, RBSTRUCT, RBFIELD); \
+ new_node->RBAUGMENTED = old->RBAUGMENTED; \
+ } \
+ static void \
+ RBNAME##_rotate(struct rb_node *rb_old, struct rb_node *rb_new) \
+ { \
+ RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD); \
+ RBSTRUCT *new_node = rb_entry(rb_new, RBSTRUCT, RBFIELD); \
+ new_node->RBAUGMENTED = old->RBAUGMENTED; \
+ RBCOMPUTE(old, false); \
+ } \
+ RBSTATIC const struct rb_augment_callbacks RBNAME = { \
+ .propagate = RBNAME##_propagate, \
+ .copy = RBNAME##_copy, \
+ .rotate = RBNAME##_rotate};
+
+/*
+ * Template for declaring augmented rbtree callbacks,
+ * computing RBAUGMENTED scalar as max(RBCOMPUTE(node)) for all subtree nodes.
+ *
+ * RBSTATIC: 'static' or empty
+ * RBNAME: name of the rb_augment_callbacks structure
+ * RBSTRUCT: struct type of the tree nodes
+ * RBFIELD: name of struct rb_node field within RBSTRUCT
+ * RBTYPE: type of the RBAUGMENTED field
+ * RBAUGMENTED: name of RBTYPE field within RBSTRUCT holding data for subtree
+ * RBCOMPUTE: name of function that returns the per-node RBTYPE scalar
+ */
+
+#define RB_DECLARE_CALLBACKS_MAX(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD, \
+ RBTYPE, RBAUGMENTED, RBCOMPUTE) \
+ static inline bool RBNAME##_compute_max(RBSTRUCT *node, bool exit) \
+ { \
+ RBSTRUCT *child; \
+ RBTYPE max = RBCOMPUTE(node); \
+ if (node->RBFIELD.rb_left) \
+ { \
+ child = rb_entry(node->RBFIELD.rb_left, RBSTRUCT, RBFIELD); \
+ if (child->RBAUGMENTED > max) \
+ max = child->RBAUGMENTED; \
+ } \
+ if (node->RBFIELD.rb_right) \
+ { \
+ child = rb_entry(node->RBFIELD.rb_right, RBSTRUCT, RBFIELD); \
+ if (child->RBAUGMENTED > max) \
+ max = child->RBAUGMENTED; \
+ } \
+ if (exit && node->RBAUGMENTED == max) \
+ return true; \
+ node->RBAUGMENTED = max; \
+ return false; \
+ } \
+ RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \
+ RBSTRUCT, RBFIELD, RBAUGMENTED, RBNAME##_compute_max)
+
+#define RB_RED 0
+#define RB_BLACK 1
+
+#define __rb_parent(pc) ((struct rb_node *)(pc & ~3))
+
+#define __rb_color(pc) ((pc) & 1)
+#define __rb_is_black(pc) __rb_color(pc)
+#define __rb_is_red(pc) (!__rb_color(pc))
+#define rb_color(rb) __rb_color((rb)->__rb_parent_color)
+#define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color)
+#define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color)
+
+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+ rb->__rb_parent_color = rb_color(rb) | (unsigned long)p;
+}
+
+static inline void rb_set_parent_color(struct rb_node *rb,
+ struct rb_node *p, int color)
+{
+ rb->__rb_parent_color = (unsigned long)p | color;
+}
+
+static inline void
+__rb_change_child(struct rb_node *old, struct rb_node *new_node,
+ struct rb_node *parent, struct rb_root *root)
+{
+ if (parent)
+ {
+ if (parent->rb_left == old)
+ parent->rb_left = new_node;
+ else
+ parent->rb_right = new_node;
+ }
+ else
+ root->rb_node = new_node;
+}
+
+extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
+ void (*augment_rotate)(struct rb_node *old, struct rb_node *new_node));
+
+static inline struct rb_node *
+__rb_erase_augmented(struct rb_node *node, struct rb_root *root,
+ const struct rb_augment_callbacks *augment)
+{
+ struct rb_node *child = node->rb_right;
+ struct rb_node *tmp = node->rb_left;
+ struct rb_node *parent, *rebalance;
+ unsigned long pc;
+
+ if (!tmp)
+ {
+ /*
+ * Case 1: node to erase has no more than 1 child (easy!)
+ *
+ * Note that if there is one child it must be red due to 5)
+ * and node must be black due to 4). We adjust colors locally
+ * so as to bypass __rb_erase_color() later on.
+ */
+ pc = node->__rb_parent_color;
+ parent = __rb_parent(pc);
+ __rb_change_child(node, child, parent, root);
+ if (child)
+ {
+ child->__rb_parent_color = pc;
+ rebalance = NULL;
+ }
+ else
+ rebalance = __rb_is_black(pc) ? parent : NULL;
+ tmp = parent;
+ }
+ else if (!child)
+ {
+ /* Still case 1, but this time the child is node->rb_left */
+ tmp->__rb_parent_color = pc = node->__rb_parent_color;
+ parent = __rb_parent(pc);
+ __rb_change_child(node, tmp, parent, root);
+ rebalance = NULL;
+ tmp = parent;
+ }
+ else
+ {
+ struct rb_node *successor = child, *child2;
+
+ tmp = child->rb_left;
+ if (!tmp)
+ {
+ /*
+ * Case 2: node's successor is its right child
+ *
+ * (n) (s)
+ * / \ / \
+ * (x) (s) -> (x) (c)
+ * \
+ * (c)
+ */
+ parent = successor;
+ child2 = successor->rb_right;
+
+ augment->copy(node, successor);
+ }
+ else
+ {
+ /*
+ * Case 3: node's successor is leftmost under
+ * node's right child subtree
+ *
+ * (n) (s)
+ * / \ / \
+ * (x) (y) -> (x) (y)
+ * / /
+ * (p) (p)
+ * / /
+ * (s) (c)
+ * \
+ * (c)
+ */
+ do
+ {
+ parent = successor;
+ successor = tmp;
+ tmp = tmp->rb_left;
+ } while (tmp);
+ child2 = successor->rb_right;
+ parent->rb_left = child2;
+ successor->rb_right = child;
+ rb_set_parent(child, successor);
+
+ augment->copy(node, successor);
+ augment->propagate(parent, successor);
+ }
+
+ tmp = node->rb_left;
+ successor->rb_left = tmp;
+ rb_set_parent(tmp, successor);
+
+ pc = node->__rb_parent_color;
+ tmp = __rb_parent(pc);
+ __rb_change_child(node, successor, tmp, root);
+
+ if (child2)
+ {
+ rb_set_parent_color(child2, parent, RB_BLACK);
+ rebalance = NULL;
+ }
+ else
+ {
+ rebalance = rb_is_black(successor) ? parent : NULL;
+ }
+ successor->__rb_parent_color = pc;
+ tmp = successor;
+ }
+
+ augment->propagate(tmp, NULL);
+ return rebalance;
+}
+
+static inline void
+rb_erase_augmented(struct rb_node *node, struct rb_root *root,
+ const struct rb_augment_callbacks *augment)
+{
+ struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
+ if (rebalance)
+ __rb_erase_color(rebalance, root, augment->rotate);
+}
+
+static inline void
+rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root,
+ const struct rb_augment_callbacks *augment)
+{
+ if (root->rb_leftmost == node)
+ root->rb_leftmost = rb_next(node);
+ rb_erase_augmented(node, &root->rb_root, augment);
+}
+
+#endif /* _LINUX_RBTREE_AUGMENTED_H */