xref: /kvmtool/util/rbtree-interval.c (revision 9f112beccf29ca0d05d60c936b1e2d3b7cc2bc47)
1e358b4fbSSasha Levin #include <kvm/rbtree-interval.h>
2e358b4fbSSasha Levin #include <stddef.h>
3e358b4fbSSasha Levin 
4e358b4fbSSasha Levin #define rb_int(n) rb_entry(n, struct rb_int_node, node)
5e358b4fbSSasha Levin 
6e358b4fbSSasha Levin struct rb_int_node *rb_int_search_single(struct rb_root *root, u64 point)
7e358b4fbSSasha Levin {
8e358b4fbSSasha Levin 	struct rb_node *node = root->rb_node;
9e358b4fbSSasha Levin 	struct rb_node *lowest = NULL;
10e358b4fbSSasha Levin 
11e358b4fbSSasha Levin 	while (node) {
12e358b4fbSSasha Levin 		struct rb_int_node *cur = rb_int(node);
13e358b4fbSSasha Levin 
14e358b4fbSSasha Levin 		if (node->rb_left && (rb_int(node->rb_left)->max_high > point)) {
15e358b4fbSSasha Levin 			node = node->rb_left;
16e358b4fbSSasha Levin 		} else if (cur->low <= point && cur->high > point) {
17e358b4fbSSasha Levin 			lowest = node;
18e358b4fbSSasha Levin 			break;
19e358b4fbSSasha Levin 		} else if (point > cur->low) {
20e358b4fbSSasha Levin 			node = node->rb_right;
21e358b4fbSSasha Levin 		} else {
22e358b4fbSSasha Levin 			break;
23e358b4fbSSasha Levin 		}
24e358b4fbSSasha Levin 	}
25e358b4fbSSasha Levin 
26e358b4fbSSasha Levin 	if (lowest == NULL)
27e358b4fbSSasha Levin 		return NULL;
28e358b4fbSSasha Levin 
29e358b4fbSSasha Levin 	return rb_int(lowest);
30e358b4fbSSasha Levin }
31e358b4fbSSasha Levin 
32e358b4fbSSasha Levin struct rb_int_node *rb_int_search_range(struct rb_root *root, u64 low, u64 high)
33e358b4fbSSasha Levin {
34e358b4fbSSasha Levin 	struct rb_int_node *range;
35e358b4fbSSasha Levin 
36e358b4fbSSasha Levin 	range = rb_int_search_single(root, low);
37e358b4fbSSasha Levin 	if (range == NULL)
38e358b4fbSSasha Levin 		return NULL;
39e358b4fbSSasha Levin 
40e358b4fbSSasha Levin 	/* We simply verify that 'high' is smaller than the end of the range where 'low' is located */
41e358b4fbSSasha Levin 	if (range->high < high)
42e358b4fbSSasha Levin 		return NULL;
43e358b4fbSSasha Levin 
44e358b4fbSSasha Levin 	return range;
45e358b4fbSSasha Levin }
46e358b4fbSSasha Levin 
47e358b4fbSSasha Levin static void update_node_max_high(struct rb_node *node, void *arg)
48e358b4fbSSasha Levin {
49e358b4fbSSasha Levin 	struct rb_int_node *i_node = rb_int(node);
50e358b4fbSSasha Levin 
51e358b4fbSSasha Levin 	i_node->max_high = i_node->high;
52e358b4fbSSasha Levin 
53e358b4fbSSasha Levin 	if (node->rb_left)
54*9f112becSSasha Levin 		i_node->max_high = max(i_node->max_high, rb_int(node->rb_left)->max_high);
55e358b4fbSSasha Levin 	if (node->rb_right)
56*9f112becSSasha Levin 		i_node->max_high = max(i_node->max_high, rb_int(node->rb_right)->max_high);
57e358b4fbSSasha Levin }
58e358b4fbSSasha Levin 
59e358b4fbSSasha Levin int rb_int_insert(struct rb_root *root, struct rb_int_node *i_node)
60e358b4fbSSasha Levin {
61e358b4fbSSasha Levin 	struct rb_node **node	= &(root->rb_node), *parent = NULL;
62e358b4fbSSasha Levin 
63e358b4fbSSasha Levin 	while (*node) {
64e358b4fbSSasha Levin 		int result	= i_node->low - rb_int(*node)->low;
65e358b4fbSSasha Levin 
66e358b4fbSSasha Levin 		parent = *node;
67e358b4fbSSasha Levin 		if (result < 0)
68e358b4fbSSasha Levin 			node	= &((*node)->rb_left);
69e358b4fbSSasha Levin 		else if (result > 0)
70e358b4fbSSasha Levin 			node	= &((*node)->rb_right);
71e358b4fbSSasha Levin 		else
72e358b4fbSSasha Levin 			return 0;
73e358b4fbSSasha Levin 	}
74e358b4fbSSasha Levin 
75e358b4fbSSasha Levin 	rb_link_node(&i_node->node, parent, node);
76e358b4fbSSasha Levin 	rb_insert_color(&i_node->node, root);
77e358b4fbSSasha Levin 
78*9f112becSSasha Levin 	rb_augment_insert(&i_node->node, update_node_max_high, NULL);
79e358b4fbSSasha Levin 	return 1;
80e358b4fbSSasha Levin }
81e358b4fbSSasha Levin 
82e358b4fbSSasha Levin void rb_int_erase(struct rb_root *root, struct rb_int_node *node)
83e358b4fbSSasha Levin {
84e358b4fbSSasha Levin 	struct rb_node *deepest;
85e358b4fbSSasha Levin 
86e358b4fbSSasha Levin 	deepest = rb_augment_erase_begin(&node->node);
87e358b4fbSSasha Levin 	rb_erase(&node->node, root);
88e358b4fbSSasha Levin 	rb_augment_erase_end(deepest, update_node_max_high, NULL);
89e358b4fbSSasha Levin 
90e358b4fbSSasha Levin }
91