summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
authorluwenpeng <[email protected]>2024-03-21 10:06:11 +0800
committerluwenpeng <[email protected]>2024-03-21 10:06:11 +0800
commit36b9a8282ac00808e5ae60328ee80bd91348beed (patch)
treee3a922bd3dd6e230c8327d8bb69ea9ca2c1d67ac /deps
parent1cdbb7c2a4b1317e7dfef7c6a18e5ee892f09de6 (diff)
Add interval tree
Diffstat (limited to 'deps')
-rw-r--r--deps/CMakeLists.txt3
-rw-r--r--deps/dablooms/test/CMakeLists.txt4
-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/itree.cpp629
-rw-r--r--deps/interval_tree/itree.h77
-rw-r--r--deps/interval_tree/test/CMakeLists.txt5
-rw-r--r--deps/interval_tree/test/gtest_interval_tree.cpp336
11 files changed, 1517 insertions, 5 deletions
diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt
index 59b9a47..d703aef 100644
--- a/deps/CMakeLists.txt
+++ b/deps/CMakeLists.txt
@@ -1,3 +1,4 @@
add_subdirectory(timeout)
add_subdirectory(dablooms)
-add_subdirectory(toml) \ No newline at end of file
+add_subdirectory(toml)
+add_subdirectory(interval_tree) \ No newline at end of file
diff --git a/deps/dablooms/test/CMakeLists.txt b/deps/dablooms/test/CMakeLists.txt
index 3be7b84..a15410c 100644
--- a/deps/dablooms/test/CMakeLists.txt
+++ b/deps/dablooms/test/CMakeLists.txt
@@ -1,7 +1,3 @@
-###############################################################################
-# gtest
-###############################################################################
-
add_executable(gtest_dablooms gtest_dablooms.cpp)
target_link_libraries(gtest_dablooms dablooms gtest)
diff --git a/deps/interval_tree/CMakeLists.txt b/deps/interval_tree/CMakeLists.txt
new file mode 100644
index 0000000..7a6de00
--- /dev/null
+++ b/deps/interval_tree/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(interval_tree STATIC interval.cpp interval_list.cpp itree.cpp)
+target_include_directories(interval_tree PUBLIC ${CMAKE_CURRENT_LIST_DIR})
+
+add_subdirectory(test) \ No newline at end of file
diff --git a/deps/interval_tree/interval.cpp b/deps/interval_tree/interval.cpp
new file mode 100644
index 0000000..bdcebaa
--- /dev/null
+++ b/deps/interval_tree/interval.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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;
+}
diff --git a/deps/interval_tree/interval.h b/deps/interval_tree/interval.h
new file mode 100644
index 0000000..4504c7c
--- /dev/null
+++ b/deps/interval_tree/interval.h
@@ -0,0 +1,59 @@
+/*
+ * 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
new file mode 100644
index 0000000..6700564
--- /dev/null
+++ b/deps/interval_tree/interval_list.cpp
@@ -0,0 +1,277 @@
+/*
+ * 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
new file mode 100644
index 0000000..7333419
--- /dev/null
+++ b/deps/interval_tree/interval_list.h
@@ -0,0 +1,57 @@
+/*
+ * 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/itree.cpp b/deps/interval_tree/itree.cpp
new file mode 100644
index 0000000..5bb68ef
--- /dev/null
+++ b/deps/interval_tree/itree.cpp
@@ -0,0 +1,629 @@
+/*
+ * 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))
+ else if (it->interval->low >= interval->low && it->interval->high <= interval->high)
+ {
+ 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
new file mode 100644
index 0000000..505e272
--- /dev/null
+++ b/deps/interval_tree/itree.h
@@ -0,0 +1,77 @@
+/*
+ * 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);
+// Find the first interval containing the specified interval
+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);
+// Delete the first interval contained by the specified 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/CMakeLists.txt b/deps/interval_tree/test/CMakeLists.txt
new file mode 100644
index 0000000..c56eea6
--- /dev/null
+++ b/deps/interval_tree/test/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(gtest_interval_tree gtest_interval_tree.cpp)
+target_link_libraries(gtest_interval_tree interval_tree gtest)
+
+include(GoogleTest)
+gtest_discover_tests(gtest_interval_tree) \ No newline at end of file
diff --git a/deps/interval_tree/test/gtest_interval_tree.cpp b/deps/interval_tree/test/gtest_interval_tree.cpp
new file mode 100644
index 0000000..417c275
--- /dev/null
+++ b/deps/interval_tree/test/gtest_interval_tree.cpp
@@ -0,0 +1,336 @@
+#include <gtest/gtest.h>
+
+#include "itree.h"
+
+void *my_dup(void *p)
+{
+ return p ? strdup((const char *)p) : NULL;
+}
+
+void my_rel(void *p)
+{
+ if (p)
+ {
+ free(p);
+ }
+}
+
+// find overlap
+#if 1
+TEST(INTERVAL_TREE, FIND)
+{
+ itree_t *tree;
+ 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);
+
+ // 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");
+
+ // not found
+ query = {
+ .low = 1,
+ .high = 4,
+ };
+ result = itree_find(tree, &query);
+ EXPECT_TRUE(result == nullptr);
+
+ // not found
+ query = {
+ .low = 10,
+ .high = 14,
+ };
+ result = itree_find(tree, &query);
+
+ itree_delete(tree);
+}
+#endif
+
+#if 1
+TEST(INTERVAL_TREE, DELETE1)
+{
+ itree_t *tree;
+ 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);
+
+ // 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,
+ };
+ EXPECT_TRUE(itree_remove(tree, &query) == 0);
+ EXPECT_TRUE(itree_size(tree) == 1);
+
+ // delete
+ query = {
+ .low = 5,
+ .high = 9,
+ };
+ EXPECT_TRUE(itree_remove(tree, &query) == 1);
+ EXPECT_TRUE(itree_size(tree) == 0);
+
+ itree_delete(tree);
+}
+#endif
+
+#if 1
+TEST(INTERVAL_TREE, DELETE2)
+{
+ itree_t *tree;
+ 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);
+
+ // insert
+ segment = {
+ .low = 15,
+ .high = 19,
+ .data = (void *)"World",
+ };
+ EXPECT_TRUE(itree_insert(tree, &segment) == 1);
+ EXPECT_TRUE(itree_size(tree) == 2);
+
+ // delete
+ query = {
+ .low = 1,
+ .high = 20,
+ };
+ EXPECT_TRUE(itree_remove(tree, &query) == 1);
+ EXPECT_TRUE(itree_size(tree) == 1);
+
+ // delete
+ query = {
+ .low = 1,
+ .high = 20,
+ };
+ EXPECT_TRUE(itree_remove(tree, &query) == 1);
+ EXPECT_TRUE(itree_size(tree) == 0);
+
+ itree_delete(tree);
+}
+#endif
+
+#if 1
+TEST(INTERVAL_TREE, REPEAT1)
+{
+ itree_t *tree;
+ interval_t segment;
+ interval_t query;
+
+ // 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);
+
+ // insert
+ segment = {
+ .low = 5,
+ .high = 9,
+ .data = (void *)"World",
+ };
+ EXPECT_TRUE(itree_insert(tree, &segment) == 1);
+ EXPECT_TRUE(itree_size(tree) == 2);
+
+ // remove
+ query = {
+ .low = 5,
+ .high = 9,
+ };
+ EXPECT_TRUE(itree_remove(tree, &query) == 1);
+ EXPECT_TRUE(itree_size(tree) == 1);
+ 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)
+{
+ 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);
+
+ // 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);
+}
+#endif
+
+int main(int argc, char **argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}