mirror of https://github.com/inolen/redream.git
reenabled interval tree tests
This commit is contained in:
parent
ac6bd3a677
commit
292ce8c38d
|
@ -408,9 +408,9 @@ if(BUILD_TESTS)
|
|||
## build test binary
|
||||
set(RETEST_SOURCES
|
||||
test/test_dead_code_elimination_pass.c
|
||||
test/test_interval_tree.c
|
||||
test/test_list.c
|
||||
test/test_load_store_elimination_pass.c
|
||||
#test/test_interval_tree.cc
|
||||
#test/test_minmax_heap.cc
|
||||
#test/test_sh4.cc
|
||||
#${asm_inc}
|
||||
|
|
|
@ -15,58 +15,56 @@ struct rb_callbacks interval_tree_cb = {
|
|||
&interval_tree_augment_rotate,
|
||||
};
|
||||
|
||||
static interval_type_t interval_tree_node_max(struct interval_node *n) {
|
||||
static interval_type_t interval_node_max(struct interval_node *n) {
|
||||
return n ? n->max : 0;
|
||||
}
|
||||
|
||||
static int interval_tree_node_size(struct interval_node *n) {
|
||||
static int interval_node_size(struct interval_node *n) {
|
||||
return n ? n->size : 0;
|
||||
}
|
||||
|
||||
static int interval_tree_node_height(struct interval_node *n) {
|
||||
static int interval_node_height(struct interval_node *n) {
|
||||
return n ? n->height : 0;
|
||||
}
|
||||
|
||||
static void interval_tree_fix_counts(struct interval_node *n) {
|
||||
static void interval_node_fix_counts(struct interval_node *n) {
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct interval_node *l = INTERVAL_NODE(n->base.left);
|
||||
struct interval_node *r = INTERVAL_NODE(n->base.right);
|
||||
struct interval_node *l = INTERVAL_NODE(n->rb.left);
|
||||
struct interval_node *r = INTERVAL_NODE(n->rb.right);
|
||||
|
||||
n->size = 1 + interval_tree_node_size(l) + interval_tree_node_size(r);
|
||||
n->height =
|
||||
1 + MAX(interval_tree_node_height(l), interval_tree_node_height(r));
|
||||
n->max =
|
||||
MAX(MAX(n->high, interval_tree_node_max(l)), interval_tree_node_max(r));
|
||||
n->size = 1 + interval_node_size(l) + interval_node_size(r);
|
||||
n->height = 1 + MAX(interval_node_height(l), interval_node_height(r));
|
||||
n->max = MAX(MAX(n->high, interval_node_max(l)), interval_node_max(r));
|
||||
}
|
||||
|
||||
static void interval_tree_augment_propagate(struct rb_tree *t,
|
||||
struct rb_node *rb_n) {
|
||||
struct interval_node *n = rb_entry(rb_n, struct interval_node, base);
|
||||
struct interval_node *n = rb_entry(rb_n, struct interval_node, rb);
|
||||
|
||||
while (n) {
|
||||
interval_tree_fix_counts(n);
|
||||
n = INTERVAL_NODE(n->base.parent);
|
||||
interval_node_fix_counts(n);
|
||||
n = INTERVAL_NODE(n->rb.parent);
|
||||
}
|
||||
}
|
||||
|
||||
static void interval_tree_augment_rotate(struct rb_tree *t,
|
||||
struct rb_node *rb_oldn,
|
||||
struct rb_node *rb_newn) {
|
||||
struct interval_node *oldn = rb_entry(rb_oldn, struct interval_node, base);
|
||||
struct interval_node *newn = rb_entry(rb_newn, struct interval_node, base);
|
||||
struct interval_node *oldn = rb_entry(rb_oldn, struct interval_node, rb);
|
||||
struct interval_node *newn = rb_entry(rb_newn, struct interval_node, rb);
|
||||
|
||||
interval_tree_fix_counts(oldn);
|
||||
interval_tree_fix_counts(newn);
|
||||
interval_tree_fix_counts(INTERVAL_NODE(newn->base.parent));
|
||||
interval_node_fix_counts(oldn);
|
||||
interval_node_fix_counts(newn);
|
||||
interval_node_fix_counts(INTERVAL_NODE(newn->rb.parent));
|
||||
}
|
||||
|
||||
static int interval_tree_cmp(const struct rb_node *rb_lhs,
|
||||
const struct rb_node *rb_rhs) {
|
||||
struct interval_node *lhs = rb_entry(rb_lhs, struct interval_node, base);
|
||||
struct interval_node *rhs = rb_entry(rb_rhs, struct interval_node, base);
|
||||
struct interval_node *lhs = rb_entry(rb_lhs, struct interval_node, rb);
|
||||
struct interval_node *rhs = rb_entry(rb_rhs, struct interval_node, rb);
|
||||
|
||||
if (lhs->low < rhs->low) {
|
||||
return -1;
|
||||
|
@ -86,74 +84,19 @@ static int interval_tree_intersects(const struct interval_node *n,
|
|||
return high >= n->low && n->high >= low;
|
||||
}
|
||||
|
||||
static struct interval_node *interval_tree_min_interval(struct interval_node *n,
|
||||
interval_type_t low,
|
||||
interval_type_t high) {
|
||||
struct interval_node *min = NULL;
|
||||
|
||||
while (n) {
|
||||
int intersects = interval_tree_intersects(n, low, high);
|
||||
|
||||
if (intersects) {
|
||||
min = n;
|
||||
}
|
||||
|
||||
// if n->left->max < low, there is no match in the left subtree, there
|
||||
// could be one in the right
|
||||
if (!n->base.left || INTERVAL_NODE(n->base.left)->max < low) {
|
||||
// don't go right if the current node intersected
|
||||
if (intersects) {
|
||||
break;
|
||||
}
|
||||
n = INTERVAL_NODE(n->base.right);
|
||||
}
|
||||
// else if n->left-max >= low, there could be one in the left subtree. if
|
||||
// there isn't one in the left, there wouldn't be one in the right
|
||||
else {
|
||||
n = INTERVAL_NODE(n->base.left);
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
struct interval_node *interval_tree_iter_next(struct interval_tree_it *it) {
|
||||
it->n = interval_tree_next_interval(it->n, it->low, it->high);
|
||||
return it->n;
|
||||
}
|
||||
|
||||
static struct interval_node *interval_tree_next_interval(
|
||||
struct interval_node *n, interval_type_t low, interval_type_t high) {
|
||||
while (n) {
|
||||
// try to find the minimum node in the right subtree
|
||||
if (n->base.right) {
|
||||
struct interval_node *min =
|
||||
interval_tree_min_interval(INTERVAL_NODE(n->base.right), low, high);
|
||||
if (min) {
|
||||
return min;
|
||||
}
|
||||
}
|
||||
|
||||
// else, move up the tree until a left child link is traversed
|
||||
struct interval_node *c = n;
|
||||
n = INTERVAL_NODE(n->base.parent);
|
||||
while (n && INTERVAL_NODE(n->base.right) == c) {
|
||||
c = n;
|
||||
n = INTERVAL_NODE(n->base.parent);
|
||||
}
|
||||
if (n && interval_tree_intersects(n, low, high)) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void interval_tree_insert(struct rb_tree *t, struct interval_node *n) {
|
||||
rb_insert(t, RB_NODE(n), &interval_tree_cb);
|
||||
}
|
||||
|
||||
void interval_tree_remove(struct rb_tree *t, struct interval_node *n) {
|
||||
rb_unlink(t, RB_NODE(n), &interval_tree_cb);
|
||||
}
|
||||
|
||||
void interval_tree_clear(struct rb_tree *t) {
|
||||
t->root = NULL;
|
||||
struct interval_node *interval_tree_iter_first(struct rb_tree *t,
|
||||
interval_type_t low,
|
||||
interval_type_t high,
|
||||
struct interval_tree_it *it) {
|
||||
it->low = low;
|
||||
it->high = high;
|
||||
it->n = interval_tree_min_interval(INTERVAL_NODE(t->root), low, high);
|
||||
return it->n;
|
||||
}
|
||||
|
||||
struct interval_node *interval_tree_find(struct rb_tree *t, interval_type_t low,
|
||||
|
@ -161,8 +104,8 @@ struct interval_node *interval_tree_find(struct rb_tree *t, interval_type_t low,
|
|||
struct interval_node *n = INTERVAL_NODE(t->root);
|
||||
|
||||
while (n) {
|
||||
struct interval_node *l = INTERVAL_NODE(n->base.left);
|
||||
struct interval_node *r = INTERVAL_NODE(n->base.right);
|
||||
struct interval_node *l = INTERVAL_NODE(n->rb.left);
|
||||
struct interval_node *r = INTERVAL_NODE(n->rb.right);
|
||||
|
||||
if (interval_tree_intersects(n, low, high)) {
|
||||
return n;
|
||||
|
@ -176,17 +119,88 @@ struct interval_node *interval_tree_find(struct rb_tree *t, interval_type_t low,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct interval_node *interval_tree_iter_first(struct rb_tree *t,
|
||||
interval_type_t low,
|
||||
interval_type_t high,
|
||||
struct interval_tree_it *it) {
|
||||
it->low = low;
|
||||
it->high = high;
|
||||
it->n = interval_tree_min_interval(INTERVAL_NODE(t->root), low, high);
|
||||
return it->n;
|
||||
struct interval_node *interval_tree_next_interval(struct interval_node *n,
|
||||
interval_type_t low,
|
||||
interval_type_t high) {
|
||||
while (n) {
|
||||
/* try to find the minimum node in the right subtree */
|
||||
if (n->rb.right) {
|
||||
struct interval_node *min =
|
||||
interval_tree_min_interval(INTERVAL_NODE(n->rb.right), low, high);
|
||||
if (min) {
|
||||
return min;
|
||||
}
|
||||
}
|
||||
|
||||
/* else, move up the tree until a left child link is traversed */
|
||||
struct interval_node *c = n;
|
||||
n = INTERVAL_NODE(n->rb.parent);
|
||||
while (n && INTERVAL_NODE(n->rb.right) == c) {
|
||||
c = n;
|
||||
n = INTERVAL_NODE(n->rb.parent);
|
||||
}
|
||||
if (n && interval_tree_intersects(n, low, high)) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct interval_node *interval_tree_iter_next(struct interval_tree_it *it) {
|
||||
it->n = interval_tree_next_interval(it->n, it->low, it->high);
|
||||
return it->n;
|
||||
struct interval_node *interval_tree_min_interval(struct interval_node *n,
|
||||
interval_type_t low,
|
||||
interval_type_t high) {
|
||||
struct interval_node *min = NULL;
|
||||
|
||||
while (n) {
|
||||
int intersects = interval_tree_intersects(n, low, high);
|
||||
|
||||
if (intersects) {
|
||||
min = n;
|
||||
}
|
||||
|
||||
/* if n->left->max < low, there is no match in the left subtree, there
|
||||
could be one in the right */
|
||||
if (!n->rb.left || INTERVAL_NODE(n->rb.left)->max < low) {
|
||||
/* don't go right if the current node intersected */
|
||||
if (intersects) {
|
||||
break;
|
||||
}
|
||||
n = INTERVAL_NODE(n->rb.right);
|
||||
}
|
||||
/* else if n->left-max >= low, there could be one in the left subtree. if
|
||||
there isn't one in the left, there wouldn't be one in the right */
|
||||
else {
|
||||
n = INTERVAL_NODE(n->rb.left);
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
int interval_tree_height(struct rb_tree *t) {
|
||||
struct interval_node *root = INTERVAL_NODE(t->root);
|
||||
return interval_node_height(root);
|
||||
}
|
||||
|
||||
int interval_tree_size(struct rb_tree *t) {
|
||||
struct interval_node *root = INTERVAL_NODE(t->root);
|
||||
return interval_node_size(root);
|
||||
}
|
||||
|
||||
interval_type_t interval_tree_max(struct rb_tree *t) {
|
||||
struct interval_node *root = INTERVAL_NODE(t->root);
|
||||
return interval_node_max(root);
|
||||
}
|
||||
|
||||
void interval_tree_clear(struct rb_tree *t) {
|
||||
t->root = NULL;
|
||||
}
|
||||
|
||||
void interval_tree_remove(struct rb_tree *t, struct interval_node *n) {
|
||||
rb_unlink(t, RB_NODE(n), &interval_tree_cb);
|
||||
}
|
||||
|
||||
void interval_tree_insert(struct rb_tree *t, struct interval_node *n) {
|
||||
rb_insert(t, RB_NODE(n), &interval_tree_cb);
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
#include <stdint.h>
|
||||
#include "core/rb_tree.h"
|
||||
|
||||
#define INTERVAL_NODE(n) ((struct interval_node *)n)
|
||||
#define INTERVAL_NODE(n) (container_of_safe((n), struct interval_node, rb))
|
||||
|
||||
typedef uintptr_t interval_type_t;
|
||||
|
||||
struct interval_node {
|
||||
struct rb_node base;
|
||||
struct rb_node rb;
|
||||
interval_type_t low;
|
||||
interval_type_t high;
|
||||
interval_type_t max;
|
||||
|
@ -26,6 +26,18 @@ struct interval_tree_it {
|
|||
void interval_tree_insert(struct rb_tree *t, struct interval_node *n);
|
||||
void interval_tree_remove(struct rb_tree *t, struct interval_node *n);
|
||||
void interval_tree_clear(struct rb_tree *t);
|
||||
|
||||
interval_type_t interval_tree_max(struct rb_tree *t);
|
||||
int interval_tree_size(struct rb_tree *t);
|
||||
int interval_tree_height(struct rb_tree *t);
|
||||
|
||||
struct interval_node *interval_tree_min_interval(struct interval_node *n,
|
||||
interval_type_t low,
|
||||
interval_type_t high);
|
||||
struct interval_node *interval_tree_next_interval(struct interval_node *n,
|
||||
interval_type_t low,
|
||||
interval_type_t high);
|
||||
|
||||
struct interval_node *interval_tree_find(struct rb_tree *t, interval_type_t low,
|
||||
interval_type_t high);
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ struct rb_node *rb_last(struct rb_tree *t);
|
|||
struct rb_node *rb_prev(struct rb_node *n);
|
||||
struct rb_node *rb_next(struct rb_node *n);
|
||||
|
||||
#define rb_for_each(it, t) \
|
||||
for (struct rb_node *it = rb_first((t)); it; it = rb_next(it))
|
||||
|
||||
#define rb_entry(n, type, member) container_of_safe(n, type, member)
|
||||
|
||||
#define rb_first_entry(t, type, member) rb_entry(rb_first(t), type, member)
|
||||
|
|
|
@ -24,28 +24,27 @@ struct memory_watcher {
|
|||
struct list live_watches;
|
||||
};
|
||||
|
||||
static struct memory_watcher *s_watcher;
|
||||
static struct memory_watcher *watcher;
|
||||
|
||||
static int watcher_handle_exception(void *ctx, struct exception *ex);
|
||||
|
||||
static void watcher_create() {
|
||||
s_watcher = calloc(1, sizeof(struct memory_watcher));
|
||||
watcher = calloc(1, sizeof(struct memory_watcher));
|
||||
|
||||
s_watcher->exc_handler =
|
||||
exception_handler_add(NULL, &watcher_handle_exception);
|
||||
watcher->exc_handler = exception_handler_add(NULL, &watcher_handle_exception);
|
||||
|
||||
for (int i = 0; i < MAX_WATCHES; i++) {
|
||||
struct memory_watch *watch = &s_watcher->watches[i];
|
||||
list_add(&s_watcher->free_watches, &watch->list_it);
|
||||
struct memory_watch *watch = &watcher->watches[i];
|
||||
list_add(&watcher->free_watches, &watch->list_it);
|
||||
}
|
||||
}
|
||||
|
||||
static void watcher_destroy() {
|
||||
exception_handler_remove(s_watcher->exc_handler);
|
||||
exception_handler_remove(watcher->exc_handler);
|
||||
|
||||
free(s_watcher);
|
||||
free(watcher);
|
||||
|
||||
s_watcher = NULL;
|
||||
watcher = NULL;
|
||||
}
|
||||
|
||||
static int watcher_handle_exception(void *ctx, struct exception *ex) {
|
||||
|
@ -53,7 +52,7 @@ static int watcher_handle_exception(void *ctx, struct exception *ex) {
|
|||
|
||||
struct interval_tree_it it;
|
||||
struct interval_node *n = interval_tree_iter_first(
|
||||
&s_watcher->tree, ex->fault_addr, ex->fault_addr, &it);
|
||||
&watcher->tree, ex->fault_addr, ex->fault_addr, &it);
|
||||
|
||||
while (n) {
|
||||
handled = 1;
|
||||
|
@ -61,11 +60,11 @@ static int watcher_handle_exception(void *ctx, struct exception *ex) {
|
|||
struct interval_node *next = interval_tree_iter_next(&it);
|
||||
struct memory_watch *watch = container_of(n, struct memory_watch, tree_it);
|
||||
|
||||
// call callback for this access watch
|
||||
/* call callback for this access watch */
|
||||
watch->cb(ex, watch->data);
|
||||
|
||||
if (watch->type == WATCH_SINGLE_WRITE) {
|
||||
// restore page permissions
|
||||
/* restore page permissions */
|
||||
uintptr_t aligned_begin = n->low;
|
||||
size_t aligned_size = (n->high - n->low) + 1;
|
||||
CHECK(protect_pages((void *)aligned_begin, aligned_size, ACC_READWRITE));
|
||||
|
@ -76,7 +75,7 @@ static int watcher_handle_exception(void *ctx, struct exception *ex) {
|
|||
n = next;
|
||||
}
|
||||
|
||||
if (s_watcher && !s_watcher->tree.root) {
|
||||
if (watcher && !watcher->tree.root) {
|
||||
watcher_destroy();
|
||||
}
|
||||
|
||||
|
@ -85,53 +84,53 @@ static int watcher_handle_exception(void *ctx, struct exception *ex) {
|
|||
|
||||
struct memory_watch *add_single_write_watch(const void *ptr, size_t size,
|
||||
memory_watch_cb cb, void *data) {
|
||||
if (!s_watcher) {
|
||||
if (!watcher) {
|
||||
watcher_create();
|
||||
}
|
||||
|
||||
// page align the range to be watched
|
||||
/* page align the range to be watched */
|
||||
size_t page_size = get_page_size();
|
||||
uintptr_t aligned_begin = align_down((uintptr_t)ptr, page_size);
|
||||
uintptr_t aligned_end = align_up((uintptr_t)ptr + size, page_size) - 1;
|
||||
size_t aligned_size = (aligned_end - aligned_begin) + 1;
|
||||
|
||||
// disable writing to the pages
|
||||
/* disable writing to the pages */
|
||||
CHECK(protect_pages((void *)aligned_begin, aligned_size, ACC_READONLY));
|
||||
|
||||
// allocate new access watch
|
||||
/* allocate new access watch */
|
||||
struct memory_watch *watch =
|
||||
list_first_entry(&s_watcher->free_watches, struct memory_watch, list_it);
|
||||
list_first_entry(&watcher->free_watches, struct memory_watch, list_it);
|
||||
CHECK_NOTNULL(watch);
|
||||
watch->type = WATCH_SINGLE_WRITE;
|
||||
watch->cb = cb;
|
||||
watch->data = data;
|
||||
|
||||
// remove from free list
|
||||
list_remove(&s_watcher->free_watches, &watch->list_it);
|
||||
/* remove from free list */
|
||||
list_remove(&watcher->free_watches, &watch->list_it);
|
||||
|
||||
// add to live list
|
||||
list_add(&s_watcher->live_watches, &watch->list_it);
|
||||
/* add to live list */
|
||||
list_add(&watcher->live_watches, &watch->list_it);
|
||||
|
||||
// add to interval tree
|
||||
/* add to interval tree */
|
||||
watch->tree_it.low = aligned_begin;
|
||||
watch->tree_it.high = aligned_end;
|
||||
|
||||
interval_tree_insert(&s_watcher->tree, &watch->tree_it);
|
||||
interval_tree_insert(&watcher->tree, &watch->tree_it);
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
void remove_memory_watch(struct memory_watch *watch) {
|
||||
// remove from interval tree
|
||||
interval_tree_remove(&s_watcher->tree, &watch->tree_it);
|
||||
/* remove from interval tree */
|
||||
interval_tree_remove(&watcher->tree, &watch->tree_it);
|
||||
|
||||
// remove from live list
|
||||
list_remove(&s_watcher->live_watches, &watch->list_it);
|
||||
/* remove from live list */
|
||||
list_remove(&watcher->live_watches, &watch->list_it);
|
||||
|
||||
// add to free list
|
||||
list_add(&s_watcher->free_watches, &watch->list_it);
|
||||
/* add to free list */
|
||||
list_add(&watcher->free_watches, &watch->list_it);
|
||||
|
||||
if (!s_watcher->tree.root) {
|
||||
if (!watcher->tree.root) {
|
||||
watcher_destroy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ void test_register(struct test *test) {
|
|||
|
||||
int main() {
|
||||
list_for_each_entry(test, &tests, struct test, it) {
|
||||
LOG_INFO("[%s]", test->name);
|
||||
LOG_INFO("%s..", test->name);
|
||||
test->run();
|
||||
LOG_INFO(ANSI_COLOR_GREEN "OK" ANSI_COLOR_RESET);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
#include <math.h>
|
||||
#include "retest.h"
|
||||
#define VERIFY_INTRUSIVE_TREE
|
||||
#include "core/interval_tree.h"
|
||||
|
||||
#define LOW 0x0
|
||||
#define HIGH 0x10000
|
||||
#define INTERVAL 0x2000
|
||||
#define MAX_NODES 0x1000
|
||||
static struct interval_node nodes[MAX_NODES];
|
||||
|
||||
static void init_interval_tree(struct rb_tree *t) {
|
||||
for (int i = 0; i < MAX_NODES; i++) {
|
||||
uint32_t low = 0;
|
||||
uint32_t high = 0;
|
||||
|
||||
while (high <= low) {
|
||||
low = LOW + (rand() % (HIGH - LOW));
|
||||
high = low + INTERVAL;
|
||||
}
|
||||
|
||||
struct interval_node *n = &nodes[i];
|
||||
n->low = low;
|
||||
n->high = high;
|
||||
interval_tree_insert(t, n);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(test_interval_tree_size) {
|
||||
struct rb_tree tree = {0};
|
||||
init_interval_tree(&tree);
|
||||
|
||||
int size = interval_tree_size(&tree);
|
||||
CHECK_EQ(size, MAX_NODES);
|
||||
}
|
||||
|
||||
TEST(test_interval_tree_height) {
|
||||
struct rb_tree tree = {0};
|
||||
init_interval_tree(&tree);
|
||||
|
||||
int height = interval_tree_height(&tree);
|
||||
int size = interval_tree_size(&tree);
|
||||
CHECK(height <= 2 * log2(size + 1));
|
||||
}
|
||||
|
||||
TEST(test_interval_tree_remove) {
|
||||
struct rb_tree tree = {0};
|
||||
init_interval_tree(&tree);
|
||||
|
||||
/* remove all nodes and ensure size is updated in the process */
|
||||
int expected_size = interval_tree_size(&tree);
|
||||
int current_size = 0;
|
||||
|
||||
struct interval_tree_it it;
|
||||
struct interval_node *n = interval_tree_iter_first(&tree, LOW, HIGH, &it);
|
||||
|
||||
while (n) {
|
||||
struct interval_node *next = interval_tree_iter_next(&it);
|
||||
|
||||
interval_tree_remove(&tree, n);
|
||||
|
||||
current_size = interval_tree_size(&tree);
|
||||
CHECK_EQ(current_size, --expected_size);
|
||||
|
||||
n = next;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(test_interval_tree_clear) {
|
||||
struct rb_tree tree = {0};
|
||||
init_interval_tree(&tree);
|
||||
|
||||
interval_tree_clear(&tree);
|
||||
|
||||
int size = interval_tree_size(&tree);
|
||||
CHECK_EQ(size, 0);
|
||||
}
|
||||
|
||||
TEST(test_interval_tree_find) {
|
||||
struct rb_tree tree = {0};
|
||||
init_interval_tree(&tree);
|
||||
|
||||
for (uint32_t i = 0; i < HIGH; i += 0x1000) {
|
||||
/* manually generate a list of expected nodes */
|
||||
static struct interval_node *expected[MAX_NODES];
|
||||
int num_expected = 0;
|
||||
|
||||
rb_for_each(rb, &tree) {
|
||||
struct interval_node *n = INTERVAL_NODE(rb);
|
||||
|
||||
if (i < n->low || i > n->high) {
|
||||
continue;
|
||||
}
|
||||
|
||||
expected[num_expected++] = n;
|
||||
}
|
||||
|
||||
/* query the tree for nodes */
|
||||
struct interval_tree_it it;
|
||||
struct interval_node *n = interval_tree_iter_first(&tree, i, i, &it);
|
||||
|
||||
int found = 0;
|
||||
|
||||
while (n) {
|
||||
/* validate that it's in the expected set */
|
||||
for (int j = 0; j < num_expected; j++) {
|
||||
if (expected[j] == n) {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
n = interval_tree_iter_next(&it);
|
||||
}
|
||||
|
||||
CHECK_EQ(found, num_expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(test_interval_tree_find_destructive) {
|
||||
struct rb_tree tree = {0};
|
||||
init_interval_tree(&tree);
|
||||
|
||||
for (uint32_t i = 0; i < HIGH; i += 0x1000) {
|
||||
/* manually generate a list of results */
|
||||
static struct interval_node *expected[MAX_NODES];
|
||||
int num_expected = 0;
|
||||
|
||||
rb_for_each(rb, &tree) {
|
||||
struct interval_node *n = INTERVAL_NODE(rb);
|
||||
|
||||
if (i < n->low || i > n->high) {
|
||||
continue;
|
||||
}
|
||||
|
||||
expected[num_expected++] = n;
|
||||
}
|
||||
|
||||
/* query the tree for nodes and compare with the expected results */
|
||||
int found = 0;
|
||||
|
||||
while (1) {
|
||||
struct interval_node *root = INTERVAL_NODE(tree.root);
|
||||
struct interval_node *n = interval_tree_min_interval(root, i, i);
|
||||
|
||||
if (!n) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* validate that it's in the expected set */
|
||||
for (int j = 0; j < num_expected; j++) {
|
||||
if (expected[j] == n) {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* delete the current interval to move onto the next */
|
||||
interval_tree_remove(&tree, n);
|
||||
}
|
||||
|
||||
/* validate that the same number of nodes were matched */
|
||||
CHECK_EQ(found, num_expected);
|
||||
}
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <math.h>
|
||||
#include <set>
|
||||
|
||||
extern "C" {
|
||||
#define VERIFY_INTRUSIVE_TREE
|
||||
#include "core/interval_tree.h"
|
||||
}
|
||||
|
||||
using namespace re;
|
||||
|
||||
typedef IntervalTree<void *> TestTree;
|
||||
typedef TestTree::node_type TestNode;
|
||||
|
||||
class IntervalTreeTest : public ::testing::Test {
|
||||
public:
|
||||
IntervalTreeTest() {}
|
||||
|
||||
static const int LOW = 0x0;
|
||||
static const int HIGH = 0x10000;
|
||||
static const int INTERVAL = 0x2000;
|
||||
|
||||
void SetUp() {
|
||||
// insert dummy intervals
|
||||
for (int i = 0; i < 0x1000; i++) {
|
||||
uint32_t low = 0;
|
||||
uint32_t high = 0;
|
||||
|
||||
while (high <= low) {
|
||||
low = LOW + (rand() % (HIGH - LOW));
|
||||
high = low + INTERVAL;
|
||||
}
|
||||
|
||||
TestNode *n = intervals.Insert(low, high, nullptr);
|
||||
nodes.insert(n);
|
||||
}
|
||||
}
|
||||
|
||||
TestTree intervals;
|
||||
std::set<TestNode *> nodes;
|
||||
};
|
||||
|
||||
TEST_F(IntervalTreeTest, ValidateRelations) {
|
||||
// make sure all children parent pointers match
|
||||
for (auto n : nodes) {
|
||||
if (n->left) {
|
||||
ASSERT_EQ(n->left->parent, n);
|
||||
}
|
||||
if (n->right) {
|
||||
ASSERT_EQ(n->right->parent, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IntervalTreeTest, Size) {
|
||||
ASSERT_EQ(intervals.Size(), (int)nodes.size());
|
||||
}
|
||||
|
||||
TEST_F(IntervalTreeTest, Height) {
|
||||
int height = intervals.Height();
|
||||
int size = intervals.Size();
|
||||
ASSERT_TRUE(height <= 2 * log2(size + 1));
|
||||
}
|
||||
|
||||
TEST_F(IntervalTreeTest, Remove) {
|
||||
// remove all results and ensure size is updated in the process
|
||||
int size = static_cast<int>(nodes.size());
|
||||
|
||||
for (auto n : nodes) {
|
||||
intervals.Remove(n);
|
||||
|
||||
ASSERT_EQ(intervals.Size(), --size);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IntervalTreeTest, Clear) {
|
||||
int original_size = intervals.Size();
|
||||
|
||||
intervals.Clear();
|
||||
|
||||
ASSERT_NE(original_size, intervals.Size());
|
||||
ASSERT_EQ(0, intervals.Size());
|
||||
}
|
||||
|
||||
TEST_F(IntervalTreeTest, Find) {
|
||||
for (uint32_t i = 0; i < HIGH; i += 0x1000) {
|
||||
// manually generate a list of results
|
||||
std::set<TestNode *> expected;
|
||||
|
||||
for (auto n : nodes) {
|
||||
if (i < n->low || i > n->high) {
|
||||
continue;
|
||||
}
|
||||
|
||||
expected.insert(n);
|
||||
}
|
||||
|
||||
// query the tree for nodes and compare with the expected results
|
||||
int found = 0;
|
||||
TestNode *n = intervals.Find(i, i);
|
||||
|
||||
while (n) {
|
||||
// validate that it's in the expected set
|
||||
auto it = expected.find(n);
|
||||
ASSERT_NE(it, expected.end());
|
||||
found++;
|
||||
|
||||
// remove from nodes so the node isn't expected by the next loop
|
||||
auto it2 = nodes.find(n);
|
||||
ASSERT_NE(it2, nodes.end());
|
||||
nodes.erase(it2);
|
||||
|
||||
// remove from intervals so Find() can locate the next node
|
||||
intervals.Remove(n);
|
||||
|
||||
// locate the next node
|
||||
n = intervals.Find(i, i);
|
||||
}
|
||||
|
||||
// validate that the same number of nodes were matched
|
||||
ASSERT_EQ(found, (int)expected.size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IntervalTreeTest, Iterate) {
|
||||
for (uint32_t i = 0; i < HIGH; i += 0x1000) {
|
||||
// manually generate a list of expected nodes
|
||||
std::set<TestNode *> expected;
|
||||
|
||||
for (auto n : nodes) {
|
||||
if (i < n->low || i > n->high) {
|
||||
continue;
|
||||
}
|
||||
|
||||
expected.insert(n);
|
||||
}
|
||||
|
||||
// query the tree for nodes
|
||||
auto range_it = intervals.intersect(i, i);
|
||||
|
||||
// compare the results
|
||||
size_t size = 0;
|
||||
for (auto it = range_it.first; it != range_it.second; ++it) {
|
||||
auto it2 = expected.find(*it);
|
||||
ASSERT_NE(it2, expected.end());
|
||||
size++;
|
||||
}
|
||||
|
||||
ASSERT_EQ(expected.size(), size);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue