11a59d1b8SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */
29826a516SMichel Lespinasse /*
39826a516SMichel Lespinasse   Interval Trees
49826a516SMichel Lespinasse   (C) 2012  Michel Lespinasse <[email protected]>
59826a516SMichel Lespinasse 
69826a516SMichel Lespinasse 
79826a516SMichel Lespinasse   include/linux/interval_tree_generic.h
89826a516SMichel Lespinasse */
99826a516SMichel Lespinasse 
109826a516SMichel Lespinasse #include <linux/rbtree_augmented.h>
119826a516SMichel Lespinasse 
129826a516SMichel Lespinasse /*
139826a516SMichel Lespinasse  * Template for implementing interval trees
149826a516SMichel Lespinasse  *
159826a516SMichel Lespinasse  * ITSTRUCT:   struct type of the interval tree nodes
169826a516SMichel Lespinasse  * ITRB:       name of struct rb_node field within ITSTRUCT
179826a516SMichel Lespinasse  * ITTYPE:     type of the interval endpoints
189826a516SMichel Lespinasse  * ITSUBTREE:  name of ITTYPE field within ITSTRUCT holding last-in-subtree
199826a516SMichel Lespinasse  * ITSTART(n): start endpoint of ITSTRUCT node n
209826a516SMichel Lespinasse  * ITLAST(n):  last endpoint of ITSTRUCT node n
219826a516SMichel Lespinasse  * ITSTATIC:   'static' or empty
229826a516SMichel Lespinasse  * ITPREFIX:   prefix to use for the inline tree definitions
239826a516SMichel Lespinasse  *
24f2686bb4SDavidlohr Bueso  * Note - before using this, please consider if generic version
259826a516SMichel Lespinasse  * (interval_tree.h) would work for you...
269826a516SMichel Lespinasse  */
279826a516SMichel Lespinasse 
289826a516SMichel Lespinasse #define INTERVAL_TREE_DEFINE(ITSTRUCT, ITRB, ITTYPE, ITSUBTREE,		      \
299826a516SMichel Lespinasse 			     ITSTART, ITLAST, ITSTATIC, ITPREFIX)	      \
309826a516SMichel Lespinasse 									      \
319826a516SMichel Lespinasse /* Callbacks for augmented rbtree insert and remove */			      \
329826a516SMichel Lespinasse 									      \
33315cc066SMichel Lespinasse RB_DECLARE_CALLBACKS_MAX(static, ITPREFIX ## _augment,			      \
34315cc066SMichel Lespinasse 			 ITSTRUCT, ITRB, ITTYPE, ITSUBTREE, ITLAST)	      \
359826a516SMichel Lespinasse 									      \
369826a516SMichel Lespinasse /* Insert / remove interval nodes from the tree */			      \
379826a516SMichel Lespinasse 									      \
38f808c13fSDavidlohr Bueso ITSTATIC void ITPREFIX ## _insert(ITSTRUCT *node,			      \
39f808c13fSDavidlohr Bueso 				  struct rb_root_cached *root)	 	      \
409826a516SMichel Lespinasse {									      \
41f808c13fSDavidlohr Bueso 	struct rb_node **link = &root->rb_root.rb_node, *rb_parent = NULL;    \
429826a516SMichel Lespinasse 	ITTYPE start = ITSTART(node), last = ITLAST(node);		      \
439826a516SMichel Lespinasse 	ITSTRUCT *parent;						      \
44f808c13fSDavidlohr Bueso 	bool leftmost = true;						      \
459826a516SMichel Lespinasse 									      \
469826a516SMichel Lespinasse 	while (*link) {							      \
479826a516SMichel Lespinasse 		rb_parent = *link;					      \
489826a516SMichel Lespinasse 		parent = rb_entry(rb_parent, ITSTRUCT, ITRB);		      \
499826a516SMichel Lespinasse 		if (parent->ITSUBTREE < last)				      \
509826a516SMichel Lespinasse 			parent->ITSUBTREE = last;			      \
519826a516SMichel Lespinasse 		if (start < ITSTART(parent))				      \
529826a516SMichel Lespinasse 			link = &parent->ITRB.rb_left;			      \
53f808c13fSDavidlohr Bueso 		else {							      \
549826a516SMichel Lespinasse 			link = &parent->ITRB.rb_right;			      \
55f808c13fSDavidlohr Bueso 			leftmost = false;				      \
56f808c13fSDavidlohr Bueso 		}							      \
579826a516SMichel Lespinasse 	}								      \
589826a516SMichel Lespinasse 									      \
599826a516SMichel Lespinasse 	node->ITSUBTREE = last;						      \
609826a516SMichel Lespinasse 	rb_link_node(&node->ITRB, rb_parent, link);			      \
61f808c13fSDavidlohr Bueso 	rb_insert_augmented_cached(&node->ITRB, root,			      \
62f808c13fSDavidlohr Bueso 				   leftmost, &ITPREFIX ## _augment);	      \
639826a516SMichel Lespinasse }									      \
649826a516SMichel Lespinasse 									      \
65f808c13fSDavidlohr Bueso ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node,			      \
66f808c13fSDavidlohr Bueso 				  struct rb_root_cached *root)		      \
679826a516SMichel Lespinasse {									      \
68f808c13fSDavidlohr Bueso 	rb_erase_augmented_cached(&node->ITRB, root, &ITPREFIX ## _augment);  \
699826a516SMichel Lespinasse }									      \
709826a516SMichel Lespinasse 									      \
719826a516SMichel Lespinasse /*									      \
729826a516SMichel Lespinasse  * Iterate over intervals intersecting [start;last]			      \
739826a516SMichel Lespinasse  *									      \
749826a516SMichel Lespinasse  * Note that a node's interval intersects [start;last] iff:		      \
759826a516SMichel Lespinasse  *   Cond1: ITSTART(node) <= last					      \
769826a516SMichel Lespinasse  * and									      \
779826a516SMichel Lespinasse  *   Cond2: start <= ITLAST(node)					      \
789826a516SMichel Lespinasse  */									      \
799826a516SMichel Lespinasse 									      \
809826a516SMichel Lespinasse static ITSTRUCT *							      \
819826a516SMichel Lespinasse ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last)	      \
829826a516SMichel Lespinasse {									      \
839826a516SMichel Lespinasse 	while (true) {							      \
849826a516SMichel Lespinasse 		/*							      \
859826a516SMichel Lespinasse 		 * Loop invariant: start <= node->ITSUBTREE		      \
869826a516SMichel Lespinasse 		 * (Cond2 is satisfied by one of the subtree nodes)	      \
879826a516SMichel Lespinasse 		 */							      \
889826a516SMichel Lespinasse 		if (node->ITRB.rb_left) {				      \
899826a516SMichel Lespinasse 			ITSTRUCT *left = rb_entry(node->ITRB.rb_left,	      \
909826a516SMichel Lespinasse 						  ITSTRUCT, ITRB);	      \
919826a516SMichel Lespinasse 			if (start <= left->ITSUBTREE) {			      \
929826a516SMichel Lespinasse 				/*					      \
939826a516SMichel Lespinasse 				 * Some nodes in left subtree satisfy Cond2.  \
949826a516SMichel Lespinasse 				 * Iterate to find the leftmost such node N.  \
959826a516SMichel Lespinasse 				 * If it also satisfies Cond1, that's the     \
969826a516SMichel Lespinasse 				 * match we are looking for. Otherwise, there \
979826a516SMichel Lespinasse 				 * is no matching interval as nodes to the    \
989826a516SMichel Lespinasse 				 * right of N can't satisfy Cond1 either.     \
999826a516SMichel Lespinasse 				 */					      \
1009826a516SMichel Lespinasse 				node = left;				      \
1019826a516SMichel Lespinasse 				continue;				      \
1029826a516SMichel Lespinasse 			}						      \
1039826a516SMichel Lespinasse 		}							      \
1049826a516SMichel Lespinasse 		if (ITSTART(node) <= last) {		/* Cond1 */	      \
1059826a516SMichel Lespinasse 			if (start <= ITLAST(node))	/* Cond2 */	      \
1069826a516SMichel Lespinasse 				return node;	/* node is leftmost match */  \
107*19811285SWei Yang 			node = rb_entry(node->ITRB.rb_right, ITSTRUCT, ITRB); \
1089826a516SMichel Lespinasse 			continue;					      \
1099826a516SMichel Lespinasse 		}							      \
1109826a516SMichel Lespinasse 		return NULL;	/* No match */				      \
1119826a516SMichel Lespinasse 	}								      \
1129826a516SMichel Lespinasse }									      \
1139826a516SMichel Lespinasse 									      \
1149826a516SMichel Lespinasse ITSTATIC ITSTRUCT *							      \
115f808c13fSDavidlohr Bueso ITPREFIX ## _iter_first(struct rb_root_cached *root,			      \
116f808c13fSDavidlohr Bueso 			ITTYPE start, ITTYPE last)			      \
1179826a516SMichel Lespinasse {									      \
118f808c13fSDavidlohr Bueso 	ITSTRUCT *node, *leftmost;					      \
1199826a516SMichel Lespinasse 									      \
120f808c13fSDavidlohr Bueso 	if (!root->rb_root.rb_node)					      \
1219826a516SMichel Lespinasse 		return NULL;						      \
122f808c13fSDavidlohr Bueso 									      \
123f808c13fSDavidlohr Bueso 	/*								      \
124f808c13fSDavidlohr Bueso 	 * Fastpath range intersection/overlap between A: [a0, a1] and	      \
125f808c13fSDavidlohr Bueso 	 * B: [b0, b1] is given by:					      \
126f808c13fSDavidlohr Bueso 	 *								      \
127f808c13fSDavidlohr Bueso 	 *         a0 <= b1 && b0 <= a1					      \
128f808c13fSDavidlohr Bueso 	 *								      \
129f808c13fSDavidlohr Bueso 	 *  ... where A holds the lock range and B holds the smallest	      \
130f808c13fSDavidlohr Bueso 	 * 'start' and largest 'last' in the tree. For the later, we	      \
131f808c13fSDavidlohr Bueso 	 * rely on the root node, which by augmented interval tree	      \
132f808c13fSDavidlohr Bueso 	 * property, holds the largest value in its last-in-subtree.	      \
133f808c13fSDavidlohr Bueso 	 * This allows mitigating some of the tree walk overhead for	      \
134f808c13fSDavidlohr Bueso 	 * for non-intersecting ranges, maintained and consulted in O(1).     \
135f808c13fSDavidlohr Bueso 	 */								      \
136f808c13fSDavidlohr Bueso 	node = rb_entry(root->rb_root.rb_node, ITSTRUCT, ITRB);		      \
1379826a516SMichel Lespinasse 	if (node->ITSUBTREE < start)					      \
1389826a516SMichel Lespinasse 		return NULL;						      \
139f808c13fSDavidlohr Bueso 									      \
140f808c13fSDavidlohr Bueso 	leftmost = rb_entry(root->rb_leftmost, ITSTRUCT, ITRB);		      \
141f808c13fSDavidlohr Bueso 	if (ITSTART(leftmost) > last)					      \
142f808c13fSDavidlohr Bueso 		return NULL;						      \
143f808c13fSDavidlohr Bueso 									      \
1449826a516SMichel Lespinasse 	return ITPREFIX ## _subtree_search(node, start, last);		      \
1459826a516SMichel Lespinasse }									      \
1469826a516SMichel Lespinasse 									      \
1479826a516SMichel Lespinasse ITSTATIC ITSTRUCT *							      \
1489826a516SMichel Lespinasse ITPREFIX ## _iter_next(ITSTRUCT *node, ITTYPE start, ITTYPE last)	      \
1499826a516SMichel Lespinasse {									      \
1509826a516SMichel Lespinasse 	struct rb_node *rb = node->ITRB.rb_right, *prev;		      \
1519826a516SMichel Lespinasse 									      \
1529826a516SMichel Lespinasse 	while (true) {							      \
1539826a516SMichel Lespinasse 		/*							      \
1549826a516SMichel Lespinasse 		 * Loop invariants:					      \
1559826a516SMichel Lespinasse 		 *   Cond1: ITSTART(node) <= last			      \
1569826a516SMichel Lespinasse 		 *   rb == node->ITRB.rb_right				      \
1579826a516SMichel Lespinasse 		 *							      \
1589826a516SMichel Lespinasse 		 * First, search right subtree if suitable		      \
1599826a516SMichel Lespinasse 		 */							      \
1609826a516SMichel Lespinasse 		if (rb) {						      \
1619826a516SMichel Lespinasse 			ITSTRUCT *right = rb_entry(rb, ITSTRUCT, ITRB);	      \
1629826a516SMichel Lespinasse 			if (start <= right->ITSUBTREE)			      \
1639826a516SMichel Lespinasse 				return ITPREFIX ## _subtree_search(right,     \
1649826a516SMichel Lespinasse 								start, last); \
1659826a516SMichel Lespinasse 		}							      \
1669826a516SMichel Lespinasse 									      \
1679826a516SMichel Lespinasse 		/* Move up the tree until we come from a node's left child */ \
1689826a516SMichel Lespinasse 		do {							      \
1699826a516SMichel Lespinasse 			rb = rb_parent(&node->ITRB);			      \
1709826a516SMichel Lespinasse 			if (!rb)					      \
1719826a516SMichel Lespinasse 				return NULL;				      \
1729826a516SMichel Lespinasse 			prev = &node->ITRB;				      \
1739826a516SMichel Lespinasse 			node = rb_entry(rb, ITSTRUCT, ITRB);		      \
1749826a516SMichel Lespinasse 			rb = node->ITRB.rb_right;			      \
1759826a516SMichel Lespinasse 		} while (prev == rb);					      \
1769826a516SMichel Lespinasse 									      \
1779826a516SMichel Lespinasse 		/* Check if the node intersects [start;last] */		      \
1789826a516SMichel Lespinasse 		if (last < ITSTART(node))		/* !Cond1 */	      \
1799826a516SMichel Lespinasse 			return NULL;					      \
1809826a516SMichel Lespinasse 		else if (start <= ITLAST(node))		/* Cond2 */	      \
1819826a516SMichel Lespinasse 			return node;					      \
1829826a516SMichel Lespinasse 	}								      \
1839826a516SMichel Lespinasse }
184