Copy and simplify the Linux kernel's interval_tree_generic.h, instantiating for uint64_t. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
		
			
				
	
	
		
			210 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Test interval trees
 | 
						|
 *
 | 
						|
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | 
						|
 * See the COPYING.LIB file in the top-level directory.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include "qemu/interval-tree.h"
 | 
						|
 | 
						|
static IntervalTreeNode nodes[20];
 | 
						|
static IntervalTreeRoot root;
 | 
						|
 | 
						|
static void rand_interval(IntervalTreeNode *n, uint64_t start, uint64_t last)
 | 
						|
{
 | 
						|
    gint32 s_ofs, l_ofs, l_max;
 | 
						|
 | 
						|
    if (last - start > INT32_MAX) {
 | 
						|
        l_max = INT32_MAX;
 | 
						|
    } else {
 | 
						|
        l_max = last - start;
 | 
						|
    }
 | 
						|
    s_ofs = g_test_rand_int_range(0, l_max);
 | 
						|
    l_ofs = g_test_rand_int_range(s_ofs, l_max);
 | 
						|
 | 
						|
    n->start = start + s_ofs;
 | 
						|
    n->last = start + l_ofs;
 | 
						|
}
 | 
						|
 | 
						|
static void test_empty(void)
 | 
						|
{
 | 
						|
    g_assert(root.rb_root.rb_node == NULL);
 | 
						|
    g_assert(root.rb_leftmost == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 0, UINT64_MAX) == NULL);
 | 
						|
}
 | 
						|
 | 
						|
static void test_find_one_point(void)
 | 
						|
{
 | 
						|
    /* Create a tree of a single node, which is the point [1,1]. */
 | 
						|
    nodes[0].start = 1;
 | 
						|
    nodes[0].last = 1;
 | 
						|
 | 
						|
    interval_tree_insert(&nodes[0], &root);
 | 
						|
 | 
						|
    g_assert(interval_tree_iter_first(&root, 0, 9) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_next(&nodes[0], 0, 9) == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 0, 0) == NULL);
 | 
						|
    g_assert(interval_tree_iter_next(&nodes[0], 0, 0) == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 0, 1) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 1, 1) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 1, 2) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 2, 2) == NULL);
 | 
						|
 | 
						|
    interval_tree_remove(&nodes[0], &root);
 | 
						|
    g_assert(root.rb_root.rb_node == NULL);
 | 
						|
    g_assert(root.rb_leftmost == NULL);
 | 
						|
}
 | 
						|
 | 
						|
static void test_find_two_point(void)
 | 
						|
{
 | 
						|
    IntervalTreeNode *find0, *find1;
 | 
						|
 | 
						|
    /* Create a tree of a two nodes, which are both the point [1,1]. */
 | 
						|
    nodes[0].start = 1;
 | 
						|
    nodes[0].last = 1;
 | 
						|
    nodes[1] = nodes[0];
 | 
						|
 | 
						|
    interval_tree_insert(&nodes[0], &root);
 | 
						|
    interval_tree_insert(&nodes[1], &root);
 | 
						|
 | 
						|
    find0 = interval_tree_iter_first(&root, 0, 9);
 | 
						|
    g_assert(find0 == &nodes[0] || find0 == &nodes[1]);
 | 
						|
 | 
						|
    find1 = interval_tree_iter_next(find0, 0, 9);
 | 
						|
    g_assert(find1 == &nodes[0] || find1 == &nodes[1]);
 | 
						|
    g_assert(find0 != find1);
 | 
						|
 | 
						|
    interval_tree_remove(&nodes[1], &root);
 | 
						|
 | 
						|
    g_assert(interval_tree_iter_first(&root, 0, 9) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_next(&nodes[0], 0, 9) == NULL);
 | 
						|
 | 
						|
    interval_tree_remove(&nodes[0], &root);
 | 
						|
}
 | 
						|
 | 
						|
static void test_find_one_range(void)
 | 
						|
{
 | 
						|
    /* Create a tree of a single node, which is the range [1,8]. */
 | 
						|
    nodes[0].start = 1;
 | 
						|
    nodes[0].last = 8;
 | 
						|
 | 
						|
    interval_tree_insert(&nodes[0], &root);
 | 
						|
 | 
						|
    g_assert(interval_tree_iter_first(&root, 0, 9) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_next(&nodes[0], 0, 9) == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 0, 0) == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 0, 1) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 1, 1) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 4, 6) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 8, 8) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 9, 9) == NULL);
 | 
						|
 | 
						|
    interval_tree_remove(&nodes[0], &root);
 | 
						|
}
 | 
						|
 | 
						|
static void test_find_one_range_many(void)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Create a tree of many nodes in [0,99] and [200,299],
 | 
						|
     * but only one node with exactly [110,190].
 | 
						|
     */
 | 
						|
    nodes[0].start = 110;
 | 
						|
    nodes[0].last = 190;
 | 
						|
 | 
						|
    for (i = 1; i < ARRAY_SIZE(nodes) / 2; ++i) {
 | 
						|
        rand_interval(&nodes[i], 0, 99);
 | 
						|
    }
 | 
						|
    for (; i < ARRAY_SIZE(nodes); ++i) {
 | 
						|
        rand_interval(&nodes[i], 200, 299);
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < ARRAY_SIZE(nodes); ++i) {
 | 
						|
        interval_tree_insert(&nodes[i], &root);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Test that we find exactly the one node. */
 | 
						|
    g_assert(interval_tree_iter_first(&root, 100, 199) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_next(&nodes[0], 100, 199) == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 100, 109) == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 100, 110) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 111, 120) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 111, 199) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 190, 199) == &nodes[0]);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 192, 199) == NULL);
 | 
						|
 | 
						|
    /*
 | 
						|
     * Test that if there are multiple matches, we return the one
 | 
						|
     * with the minimal start.
 | 
						|
     */
 | 
						|
    g_assert(interval_tree_iter_first(&root, 100, 300) == &nodes[0]);
 | 
						|
 | 
						|
    /* Test that we don't find it after it is removed. */
 | 
						|
    interval_tree_remove(&nodes[0], &root);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 100, 199) == NULL);
 | 
						|
 | 
						|
    for (i = 1; i < ARRAY_SIZE(nodes); ++i) {
 | 
						|
        interval_tree_remove(&nodes[i], &root);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void test_find_many_range(void)
 | 
						|
{
 | 
						|
    IntervalTreeNode *find;
 | 
						|
    int i, n;
 | 
						|
 | 
						|
    n = g_test_rand_int_range(ARRAY_SIZE(nodes) / 3, ARRAY_SIZE(nodes) / 2);
 | 
						|
 | 
						|
    /*
 | 
						|
     * Create a fair few nodes in [2000,2999], with the others
 | 
						|
     * distributed around.
 | 
						|
     */
 | 
						|
    for (i = 0; i < n; ++i) {
 | 
						|
        rand_interval(&nodes[i], 2000, 2999);
 | 
						|
    }
 | 
						|
    for (; i < ARRAY_SIZE(nodes) * 2 / 3; ++i) {
 | 
						|
        rand_interval(&nodes[i], 1000, 1899);
 | 
						|
    }
 | 
						|
    for (; i < ARRAY_SIZE(nodes); ++i) {
 | 
						|
        rand_interval(&nodes[i], 3100, 3999);
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < ARRAY_SIZE(nodes); ++i) {
 | 
						|
        interval_tree_insert(&nodes[i], &root);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Test that we find all of the nodes. */
 | 
						|
    find = interval_tree_iter_first(&root, 2000, 2999);
 | 
						|
    for (i = 0; find != NULL; i++) {
 | 
						|
        find = interval_tree_iter_next(find, 2000, 2999);
 | 
						|
    }
 | 
						|
    g_assert_cmpint(i, ==, n);
 | 
						|
 | 
						|
    g_assert(interval_tree_iter_first(&root,    0,  999) == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 1900, 1999) == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 3000, 3099) == NULL);
 | 
						|
    g_assert(interval_tree_iter_first(&root, 4000, UINT64_MAX) == NULL);
 | 
						|
 | 
						|
    for (i = 0; i < ARRAY_SIZE(nodes); ++i) {
 | 
						|
        interval_tree_remove(&nodes[i], &root);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char **argv)
 | 
						|
{
 | 
						|
    g_test_init(&argc, &argv, NULL);
 | 
						|
 | 
						|
    g_test_add_func("/interval-tree/empty", test_empty);
 | 
						|
    g_test_add_func("/interval-tree/find-one-point", test_find_one_point);
 | 
						|
    g_test_add_func("/interval-tree/find-two-point", test_find_two_point);
 | 
						|
    g_test_add_func("/interval-tree/find-one-range", test_find_one_range);
 | 
						|
    g_test_add_func("/interval-tree/find-one-range-many",
 | 
						|
                    test_find_one_range_many);
 | 
						|
    g_test_add_func("/interval-tree/find-many-range", test_find_many_range);
 | 
						|
 | 
						|
    return g_test_run();
 | 
						|
}
 |