xref: /openbmc/linux/lib/interval_tree.c (revision 5fe93786)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fff3fd8aSMichel Lespinasse #include <linux/interval_tree.h>
39826a516SMichel Lespinasse #include <linux/interval_tree_generic.h>
485c5e27cSRasmus Villemoes #include <linux/compiler.h>
585c5e27cSRasmus Villemoes #include <linux/export.h>
6fff3fd8aSMichel Lespinasse 
79826a516SMichel Lespinasse #define START(node) ((node)->start)
89826a516SMichel Lespinasse #define LAST(node)  ((node)->last)
9fff3fd8aSMichel Lespinasse 
109826a516SMichel Lespinasse INTERVAL_TREE_DEFINE(struct interval_tree_node, rb,
119826a516SMichel Lespinasse 		     unsigned long, __subtree_last,
129826a516SMichel Lespinasse 		     START, LAST,, interval_tree)
13a88cc108SChris Wilson 
14a88cc108SChris Wilson EXPORT_SYMBOL_GPL(interval_tree_insert);
15a88cc108SChris Wilson EXPORT_SYMBOL_GPL(interval_tree_remove);
16a88cc108SChris Wilson EXPORT_SYMBOL_GPL(interval_tree_iter_first);
17a88cc108SChris Wilson EXPORT_SYMBOL_GPL(interval_tree_iter_next);
18*5fe93786SJason Gunthorpe 
19*5fe93786SJason Gunthorpe #ifdef CONFIG_INTERVAL_TREE_SPAN_ITER
20*5fe93786SJason Gunthorpe /*
21*5fe93786SJason Gunthorpe  * Roll nodes[1] into nodes[0] by advancing nodes[1] to the end of a contiguous
22*5fe93786SJason Gunthorpe  * span of nodes. This makes nodes[0]->last the end of that contiguous used span
23*5fe93786SJason Gunthorpe  * indexes that started at the original nodes[1]->start. nodes[1] is now the
24*5fe93786SJason Gunthorpe  * first node starting the next used span. A hole span is between nodes[0]->last
25*5fe93786SJason Gunthorpe  * and nodes[1]->start. nodes[1] must be !NULL.
26*5fe93786SJason Gunthorpe  */
27*5fe93786SJason Gunthorpe static void
interval_tree_span_iter_next_gap(struct interval_tree_span_iter * state)28*5fe93786SJason Gunthorpe interval_tree_span_iter_next_gap(struct interval_tree_span_iter *state)
29*5fe93786SJason Gunthorpe {
30*5fe93786SJason Gunthorpe 	struct interval_tree_node *cur = state->nodes[1];
31*5fe93786SJason Gunthorpe 
32*5fe93786SJason Gunthorpe 	state->nodes[0] = cur;
33*5fe93786SJason Gunthorpe 	do {
34*5fe93786SJason Gunthorpe 		if (cur->last > state->nodes[0]->last)
35*5fe93786SJason Gunthorpe 			state->nodes[0] = cur;
36*5fe93786SJason Gunthorpe 		cur = interval_tree_iter_next(cur, state->first_index,
37*5fe93786SJason Gunthorpe 					      state->last_index);
38*5fe93786SJason Gunthorpe 	} while (cur && (state->nodes[0]->last >= cur->start ||
39*5fe93786SJason Gunthorpe 			 state->nodes[0]->last + 1 == cur->start));
40*5fe93786SJason Gunthorpe 	state->nodes[1] = cur;
41*5fe93786SJason Gunthorpe }
42*5fe93786SJason Gunthorpe 
interval_tree_span_iter_first(struct interval_tree_span_iter * iter,struct rb_root_cached * itree,unsigned long first_index,unsigned long last_index)43*5fe93786SJason Gunthorpe void interval_tree_span_iter_first(struct interval_tree_span_iter *iter,
44*5fe93786SJason Gunthorpe 				   struct rb_root_cached *itree,
45*5fe93786SJason Gunthorpe 				   unsigned long first_index,
46*5fe93786SJason Gunthorpe 				   unsigned long last_index)
47*5fe93786SJason Gunthorpe {
48*5fe93786SJason Gunthorpe 	iter->first_index = first_index;
49*5fe93786SJason Gunthorpe 	iter->last_index = last_index;
50*5fe93786SJason Gunthorpe 	iter->nodes[0] = NULL;
51*5fe93786SJason Gunthorpe 	iter->nodes[1] =
52*5fe93786SJason Gunthorpe 		interval_tree_iter_first(itree, first_index, last_index);
53*5fe93786SJason Gunthorpe 	if (!iter->nodes[1]) {
54*5fe93786SJason Gunthorpe 		/* No nodes intersect the span, whole span is hole */
55*5fe93786SJason Gunthorpe 		iter->start_hole = first_index;
56*5fe93786SJason Gunthorpe 		iter->last_hole = last_index;
57*5fe93786SJason Gunthorpe 		iter->is_hole = 1;
58*5fe93786SJason Gunthorpe 		return;
59*5fe93786SJason Gunthorpe 	}
60*5fe93786SJason Gunthorpe 	if (iter->nodes[1]->start > first_index) {
61*5fe93786SJason Gunthorpe 		/* Leading hole on first iteration */
62*5fe93786SJason Gunthorpe 		iter->start_hole = first_index;
63*5fe93786SJason Gunthorpe 		iter->last_hole = iter->nodes[1]->start - 1;
64*5fe93786SJason Gunthorpe 		iter->is_hole = 1;
65*5fe93786SJason Gunthorpe 		interval_tree_span_iter_next_gap(iter);
66*5fe93786SJason Gunthorpe 		return;
67*5fe93786SJason Gunthorpe 	}
68*5fe93786SJason Gunthorpe 
69*5fe93786SJason Gunthorpe 	/* Starting inside a used */
70*5fe93786SJason Gunthorpe 	iter->start_used = first_index;
71*5fe93786SJason Gunthorpe 	iter->is_hole = 0;
72*5fe93786SJason Gunthorpe 	interval_tree_span_iter_next_gap(iter);
73*5fe93786SJason Gunthorpe 	iter->last_used = iter->nodes[0]->last;
74*5fe93786SJason Gunthorpe 	if (iter->last_used >= last_index) {
75*5fe93786SJason Gunthorpe 		iter->last_used = last_index;
76*5fe93786SJason Gunthorpe 		iter->nodes[0] = NULL;
77*5fe93786SJason Gunthorpe 		iter->nodes[1] = NULL;
78*5fe93786SJason Gunthorpe 	}
79*5fe93786SJason Gunthorpe }
80*5fe93786SJason Gunthorpe EXPORT_SYMBOL_GPL(interval_tree_span_iter_first);
81*5fe93786SJason Gunthorpe 
interval_tree_span_iter_next(struct interval_tree_span_iter * iter)82*5fe93786SJason Gunthorpe void interval_tree_span_iter_next(struct interval_tree_span_iter *iter)
83*5fe93786SJason Gunthorpe {
84*5fe93786SJason Gunthorpe 	if (!iter->nodes[0] && !iter->nodes[1]) {
85*5fe93786SJason Gunthorpe 		iter->is_hole = -1;
86*5fe93786SJason Gunthorpe 		return;
87*5fe93786SJason Gunthorpe 	}
88*5fe93786SJason Gunthorpe 
89*5fe93786SJason Gunthorpe 	if (iter->is_hole) {
90*5fe93786SJason Gunthorpe 		iter->start_used = iter->last_hole + 1;
91*5fe93786SJason Gunthorpe 		iter->last_used = iter->nodes[0]->last;
92*5fe93786SJason Gunthorpe 		if (iter->last_used >= iter->last_index) {
93*5fe93786SJason Gunthorpe 			iter->last_used = iter->last_index;
94*5fe93786SJason Gunthorpe 			iter->nodes[0] = NULL;
95*5fe93786SJason Gunthorpe 			iter->nodes[1] = NULL;
96*5fe93786SJason Gunthorpe 		}
97*5fe93786SJason Gunthorpe 		iter->is_hole = 0;
98*5fe93786SJason Gunthorpe 		return;
99*5fe93786SJason Gunthorpe 	}
100*5fe93786SJason Gunthorpe 
101*5fe93786SJason Gunthorpe 	if (!iter->nodes[1]) {
102*5fe93786SJason Gunthorpe 		/* Trailing hole */
103*5fe93786SJason Gunthorpe 		iter->start_hole = iter->nodes[0]->last + 1;
104*5fe93786SJason Gunthorpe 		iter->last_hole = iter->last_index;
105*5fe93786SJason Gunthorpe 		iter->nodes[0] = NULL;
106*5fe93786SJason Gunthorpe 		iter->is_hole = 1;
107*5fe93786SJason Gunthorpe 		return;
108*5fe93786SJason Gunthorpe 	}
109*5fe93786SJason Gunthorpe 
110*5fe93786SJason Gunthorpe 	/* must have both nodes[0] and [1], interior hole */
111*5fe93786SJason Gunthorpe 	iter->start_hole = iter->nodes[0]->last + 1;
112*5fe93786SJason Gunthorpe 	iter->last_hole = iter->nodes[1]->start - 1;
113*5fe93786SJason Gunthorpe 	iter->is_hole = 1;
114*5fe93786SJason Gunthorpe 	interval_tree_span_iter_next_gap(iter);
115*5fe93786SJason Gunthorpe }
116*5fe93786SJason Gunthorpe EXPORT_SYMBOL_GPL(interval_tree_span_iter_next);
117*5fe93786SJason Gunthorpe 
118*5fe93786SJason Gunthorpe /*
119*5fe93786SJason Gunthorpe  * Advance the iterator index to a specific position. The returned used/hole is
120*5fe93786SJason Gunthorpe  * updated to start at new_index. This is faster than calling
121*5fe93786SJason Gunthorpe  * interval_tree_span_iter_first() as it can avoid full searches in several
122*5fe93786SJason Gunthorpe  * cases where the iterator is already set.
123*5fe93786SJason Gunthorpe  */
interval_tree_span_iter_advance(struct interval_tree_span_iter * iter,struct rb_root_cached * itree,unsigned long new_index)124*5fe93786SJason Gunthorpe void interval_tree_span_iter_advance(struct interval_tree_span_iter *iter,
125*5fe93786SJason Gunthorpe 				     struct rb_root_cached *itree,
126*5fe93786SJason Gunthorpe 				     unsigned long new_index)
127*5fe93786SJason Gunthorpe {
128*5fe93786SJason Gunthorpe 	if (iter->is_hole == -1)
129*5fe93786SJason Gunthorpe 		return;
130*5fe93786SJason Gunthorpe 
131*5fe93786SJason Gunthorpe 	iter->first_index = new_index;
132*5fe93786SJason Gunthorpe 	if (new_index > iter->last_index) {
133*5fe93786SJason Gunthorpe 		iter->is_hole = -1;
134*5fe93786SJason Gunthorpe 		return;
135*5fe93786SJason Gunthorpe 	}
136*5fe93786SJason Gunthorpe 
137*5fe93786SJason Gunthorpe 	/* Rely on the union aliasing hole/used */
138*5fe93786SJason Gunthorpe 	if (iter->start_hole <= new_index && new_index <= iter->last_hole) {
139*5fe93786SJason Gunthorpe 		iter->start_hole = new_index;
140*5fe93786SJason Gunthorpe 		return;
141*5fe93786SJason Gunthorpe 	}
142*5fe93786SJason Gunthorpe 	if (new_index == iter->last_hole + 1)
143*5fe93786SJason Gunthorpe 		interval_tree_span_iter_next(iter);
144*5fe93786SJason Gunthorpe 	else
145*5fe93786SJason Gunthorpe 		interval_tree_span_iter_first(iter, itree, new_index,
146*5fe93786SJason Gunthorpe 					      iter->last_index);
147*5fe93786SJason Gunthorpe }
148*5fe93786SJason Gunthorpe EXPORT_SYMBOL_GPL(interval_tree_span_iter_advance);
149*5fe93786SJason Gunthorpe #endif
150