xref: /openbmc/linux/lib/interval_tree.c (revision fff3fd8a1210a165252cd7cd01206da7a90d3a06)
1*fff3fd8aSMichel Lespinasse #include <linux/init.h>
2*fff3fd8aSMichel Lespinasse #include <linux/interval_tree.h>
3*fff3fd8aSMichel Lespinasse 
4*fff3fd8aSMichel Lespinasse /* Callbacks for augmented rbtree insert and remove */
5*fff3fd8aSMichel Lespinasse 
6*fff3fd8aSMichel Lespinasse static inline unsigned long
7*fff3fd8aSMichel Lespinasse compute_subtree_last(struct interval_tree_node *node)
8*fff3fd8aSMichel Lespinasse {
9*fff3fd8aSMichel Lespinasse 	unsigned long max = node->last, subtree_last;
10*fff3fd8aSMichel Lespinasse 	if (node->rb.rb_left) {
11*fff3fd8aSMichel Lespinasse 		subtree_last = rb_entry(node->rb.rb_left,
12*fff3fd8aSMichel Lespinasse 			struct interval_tree_node, rb)->__subtree_last;
13*fff3fd8aSMichel Lespinasse 		if (max < subtree_last)
14*fff3fd8aSMichel Lespinasse 			max = subtree_last;
15*fff3fd8aSMichel Lespinasse 	}
16*fff3fd8aSMichel Lespinasse 	if (node->rb.rb_right) {
17*fff3fd8aSMichel Lespinasse 		subtree_last = rb_entry(node->rb.rb_right,
18*fff3fd8aSMichel Lespinasse 			struct interval_tree_node, rb)->__subtree_last;
19*fff3fd8aSMichel Lespinasse 		if (max < subtree_last)
20*fff3fd8aSMichel Lespinasse 			max = subtree_last;
21*fff3fd8aSMichel Lespinasse 	}
22*fff3fd8aSMichel Lespinasse 	return max;
23*fff3fd8aSMichel Lespinasse }
24*fff3fd8aSMichel Lespinasse 
25*fff3fd8aSMichel Lespinasse RB_DECLARE_CALLBACKS(static, augment_callbacks, struct interval_tree_node, rb,
26*fff3fd8aSMichel Lespinasse 		     unsigned long, __subtree_last, compute_subtree_last)
27*fff3fd8aSMichel Lespinasse 
28*fff3fd8aSMichel Lespinasse /* Insert / remove interval nodes from the tree */
29*fff3fd8aSMichel Lespinasse 
30*fff3fd8aSMichel Lespinasse void interval_tree_insert(struct interval_tree_node *node,
31*fff3fd8aSMichel Lespinasse 			  struct rb_root *root)
32*fff3fd8aSMichel Lespinasse {
33*fff3fd8aSMichel Lespinasse 	struct rb_node **link = &root->rb_node, *rb_parent = NULL;
34*fff3fd8aSMichel Lespinasse 	unsigned long start = node->start, last = node->last;
35*fff3fd8aSMichel Lespinasse 	struct interval_tree_node *parent;
36*fff3fd8aSMichel Lespinasse 
37*fff3fd8aSMichel Lespinasse 	while (*link) {
38*fff3fd8aSMichel Lespinasse 		rb_parent = *link;
39*fff3fd8aSMichel Lespinasse 		parent = rb_entry(rb_parent, struct interval_tree_node, rb);
40*fff3fd8aSMichel Lespinasse 		if (parent->__subtree_last < last)
41*fff3fd8aSMichel Lespinasse 			parent->__subtree_last = last;
42*fff3fd8aSMichel Lespinasse 		if (start < parent->start)
43*fff3fd8aSMichel Lespinasse 			link = &parent->rb.rb_left;
44*fff3fd8aSMichel Lespinasse 		else
45*fff3fd8aSMichel Lespinasse 			link = &parent->rb.rb_right;
46*fff3fd8aSMichel Lespinasse 	}
47*fff3fd8aSMichel Lespinasse 
48*fff3fd8aSMichel Lespinasse 	node->__subtree_last = last;
49*fff3fd8aSMichel Lespinasse 	rb_link_node(&node->rb, rb_parent, link);
50*fff3fd8aSMichel Lespinasse 	rb_insert_augmented(&node->rb, root, &augment_callbacks);
51*fff3fd8aSMichel Lespinasse }
52*fff3fd8aSMichel Lespinasse 
53*fff3fd8aSMichel Lespinasse void interval_tree_remove(struct interval_tree_node *node,
54*fff3fd8aSMichel Lespinasse 			  struct rb_root *root)
55*fff3fd8aSMichel Lespinasse {
56*fff3fd8aSMichel Lespinasse 	rb_erase_augmented(&node->rb, root, &augment_callbacks);
57*fff3fd8aSMichel Lespinasse }
58*fff3fd8aSMichel Lespinasse 
59*fff3fd8aSMichel Lespinasse /*
60*fff3fd8aSMichel Lespinasse  * Iterate over intervals intersecting [start;last]
61*fff3fd8aSMichel Lespinasse  *
62*fff3fd8aSMichel Lespinasse  * Note that a node's interval intersects [start;last] iff:
63*fff3fd8aSMichel Lespinasse  *   Cond1: node->start <= last
64*fff3fd8aSMichel Lespinasse  * and
65*fff3fd8aSMichel Lespinasse  *   Cond2: start <= node->last
66*fff3fd8aSMichel Lespinasse  */
67*fff3fd8aSMichel Lespinasse 
68*fff3fd8aSMichel Lespinasse static struct interval_tree_node *
69*fff3fd8aSMichel Lespinasse subtree_search(struct interval_tree_node *node,
70*fff3fd8aSMichel Lespinasse 	       unsigned long start, unsigned long last)
71*fff3fd8aSMichel Lespinasse {
72*fff3fd8aSMichel Lespinasse 	while (true) {
73*fff3fd8aSMichel Lespinasse 		/*
74*fff3fd8aSMichel Lespinasse 		 * Loop invariant: start <= node->__subtree_last
75*fff3fd8aSMichel Lespinasse 		 * (Cond2 is satisfied by one of the subtree nodes)
76*fff3fd8aSMichel Lespinasse 		 */
77*fff3fd8aSMichel Lespinasse 		if (node->rb.rb_left) {
78*fff3fd8aSMichel Lespinasse 			struct interval_tree_node *left =
79*fff3fd8aSMichel Lespinasse 				rb_entry(node->rb.rb_left,
80*fff3fd8aSMichel Lespinasse 					 struct interval_tree_node, rb);
81*fff3fd8aSMichel Lespinasse 			if (start <= left->__subtree_last) {
82*fff3fd8aSMichel Lespinasse 				/*
83*fff3fd8aSMichel Lespinasse 				 * Some nodes in left subtree satisfy Cond2.
84*fff3fd8aSMichel Lespinasse 				 * Iterate to find the leftmost such node N.
85*fff3fd8aSMichel Lespinasse 				 * If it also satisfies Cond1, that's the match
86*fff3fd8aSMichel Lespinasse 				 * we are looking for. Otherwise, there is no
87*fff3fd8aSMichel Lespinasse 				 * matching interval as nodes to the right of N
88*fff3fd8aSMichel Lespinasse 				 * can't satisfy Cond1 either.
89*fff3fd8aSMichel Lespinasse 				 */
90*fff3fd8aSMichel Lespinasse 				node = left;
91*fff3fd8aSMichel Lespinasse 				continue;
92*fff3fd8aSMichel Lespinasse 			}
93*fff3fd8aSMichel Lespinasse 		}
94*fff3fd8aSMichel Lespinasse 		if (node->start <= last) {		/* Cond1 */
95*fff3fd8aSMichel Lespinasse 			if (start <= node->last)	/* Cond2 */
96*fff3fd8aSMichel Lespinasse 				return node;	/* node is leftmost match */
97*fff3fd8aSMichel Lespinasse 			if (node->rb.rb_right) {
98*fff3fd8aSMichel Lespinasse 				node = rb_entry(node->rb.rb_right,
99*fff3fd8aSMichel Lespinasse 					struct interval_tree_node, rb);
100*fff3fd8aSMichel Lespinasse 				if (start <= node->__subtree_last)
101*fff3fd8aSMichel Lespinasse 					continue;
102*fff3fd8aSMichel Lespinasse 			}
103*fff3fd8aSMichel Lespinasse 		}
104*fff3fd8aSMichel Lespinasse 		return NULL;	/* No match */
105*fff3fd8aSMichel Lespinasse 	}
106*fff3fd8aSMichel Lespinasse }
107*fff3fd8aSMichel Lespinasse 
108*fff3fd8aSMichel Lespinasse struct interval_tree_node *
109*fff3fd8aSMichel Lespinasse interval_tree_iter_first(struct rb_root *root,
110*fff3fd8aSMichel Lespinasse 			 unsigned long start, unsigned long last)
111*fff3fd8aSMichel Lespinasse {
112*fff3fd8aSMichel Lespinasse 	struct interval_tree_node *node;
113*fff3fd8aSMichel Lespinasse 
114*fff3fd8aSMichel Lespinasse 	if (!root->rb_node)
115*fff3fd8aSMichel Lespinasse 		return NULL;
116*fff3fd8aSMichel Lespinasse 	node = rb_entry(root->rb_node, struct interval_tree_node, rb);
117*fff3fd8aSMichel Lespinasse 	if (node->__subtree_last < start)
118*fff3fd8aSMichel Lespinasse 		return NULL;
119*fff3fd8aSMichel Lespinasse 	return subtree_search(node, start, last);
120*fff3fd8aSMichel Lespinasse }
121*fff3fd8aSMichel Lespinasse 
122*fff3fd8aSMichel Lespinasse struct interval_tree_node *
123*fff3fd8aSMichel Lespinasse interval_tree_iter_next(struct interval_tree_node *node,
124*fff3fd8aSMichel Lespinasse 			unsigned long start, unsigned long last)
125*fff3fd8aSMichel Lespinasse {
126*fff3fd8aSMichel Lespinasse 	struct rb_node *rb = node->rb.rb_right, *prev;
127*fff3fd8aSMichel Lespinasse 
128*fff3fd8aSMichel Lespinasse 	while (true) {
129*fff3fd8aSMichel Lespinasse 		/*
130*fff3fd8aSMichel Lespinasse 		 * Loop invariants:
131*fff3fd8aSMichel Lespinasse 		 *   Cond1: node->start <= last
132*fff3fd8aSMichel Lespinasse 		 *   rb == node->rb.rb_right
133*fff3fd8aSMichel Lespinasse 		 *
134*fff3fd8aSMichel Lespinasse 		 * First, search right subtree if suitable
135*fff3fd8aSMichel Lespinasse 		 */
136*fff3fd8aSMichel Lespinasse 		if (rb) {
137*fff3fd8aSMichel Lespinasse 			struct interval_tree_node *right =
138*fff3fd8aSMichel Lespinasse 				rb_entry(rb, struct interval_tree_node, rb);
139*fff3fd8aSMichel Lespinasse 			if (start <= right->__subtree_last)
140*fff3fd8aSMichel Lespinasse 				return subtree_search(right, start, last);
141*fff3fd8aSMichel Lespinasse 		}
142*fff3fd8aSMichel Lespinasse 
143*fff3fd8aSMichel Lespinasse 		/* Move up the tree until we come from a node's left child */
144*fff3fd8aSMichel Lespinasse 		do {
145*fff3fd8aSMichel Lespinasse 			rb = rb_parent(&node->rb);
146*fff3fd8aSMichel Lespinasse 			if (!rb)
147*fff3fd8aSMichel Lespinasse 				return NULL;
148*fff3fd8aSMichel Lespinasse 			prev = &node->rb;
149*fff3fd8aSMichel Lespinasse 			node = rb_entry(rb, struct interval_tree_node, rb);
150*fff3fd8aSMichel Lespinasse 			rb = node->rb.rb_right;
151*fff3fd8aSMichel Lespinasse 		} while (prev == rb);
152*fff3fd8aSMichel Lespinasse 
153*fff3fd8aSMichel Lespinasse 		/* Check if the node intersects [start;last] */
154*fff3fd8aSMichel Lespinasse 		if (last < node->start)		/* !Cond1 */
155*fff3fd8aSMichel Lespinasse 			return NULL;
156*fff3fd8aSMichel Lespinasse 		else if (start <= node->last)	/* Cond2 */
157*fff3fd8aSMichel Lespinasse 			return node;
158*fff3fd8aSMichel Lespinasse 	}
159*fff3fd8aSMichel Lespinasse }
160