File Index
Files and directories
Sign in
FILE

rbtree_augmented.h

File preview with syntax highlighting.

linux-6.19.14/tools/include/linux/rbtree_augmented.h C
  1/* SPDX-License-Identifier: GPL-2.0-or-later */
  2/*
  3  Red Black Trees
  4  (C) 1999  Andrea Arcangeli <andrea@suse.de>
  5  (C) 2002  David Woodhouse <dwmw2@infradead.org>
  6  (C) 2012  Michel Lespinasse <walken@google.com>
  7
  8
  9  tools/linux/include/linux/rbtree_augmented.h
 10
 11  Copied from:
 12  linux/include/linux/rbtree_augmented.h
 13*/
 14
 15#ifndef _TOOLS_LINUX_RBTREE_AUGMENTED_H
 16#define _TOOLS_LINUX_RBTREE_AUGMENTED_H
 17
 18#include <linux/compiler.h>
 19#include <linux/rbtree.h>
 20
 21/*
 22 * Please note - only struct rb_augment_callbacks and the prototypes for
 23 * rb_insert_augmented() and rb_erase_augmented() are intended to be public.
 24 * The rest are implementation details you are not expected to depend on.
 25 *
 26 * See Documentation/core-api/rbtree.rst for documentation and samples.
 27 */
 28
 29struct rb_augment_callbacks {
 30	void (*propagate)(struct rb_node *node, struct rb_node *stop);
 31	void (*copy)(struct rb_node *old, struct rb_node *new);
 32	void (*rotate)(struct rb_node *old, struct rb_node *new);
 33};
 34
 35extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
 36	void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
 37
 38/*
 39 * Fixup the rbtree and update the augmented information when rebalancing.
 40 *
 41 * On insertion, the user must update the augmented information on the path
 42 * leading to the inserted node, then call rb_link_node() as usual and
 43 * rb_insert_augmented() instead of the usual rb_insert_color() call.
 44 * If rb_insert_augmented() rebalances the rbtree, it will callback into
 45 * a user provided function to update the augmented information on the
 46 * affected subtrees.
 47 */
 48static inline void
 49rb_insert_augmented(struct rb_node *node, struct rb_root *root,
 50		    const struct rb_augment_callbacks *augment)
 51{
 52	__rb_insert_augmented(node, root, augment->rotate);
 53}
 54
 55static inline void
 56rb_insert_augmented_cached(struct rb_node *node,
 57			   struct rb_root_cached *root, bool newleft,
 58			   const struct rb_augment_callbacks *augment)
 59{
 60	if (newleft)
 61		root->rb_leftmost = node;
 62	rb_insert_augmented(node, &root->rb_root, augment);
 63}
 64
 65/*
 66 * Template for declaring augmented rbtree callbacks (generic case)
 67 *
 68 * RBSTATIC:    'static' or empty
 69 * RBNAME:      name of the rb_augment_callbacks structure
 70 * RBSTRUCT:    struct type of the tree nodes
 71 * RBFIELD:     name of struct rb_node field within RBSTRUCT
 72 * RBAUGMENTED: name of field within RBSTRUCT holding data for subtree
 73 * RBCOMPUTE:   name of function that recomputes the RBAUGMENTED data
 74 */
 75
 76#define RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME,				\
 77			     RBSTRUCT, RBFIELD, RBAUGMENTED, RBCOMPUTE)	\
 78static inline void							\
 79RBNAME ## _propagate(struct rb_node *rb, struct rb_node *stop)		\
 80{									\
 81	while (rb != stop) {						\
 82		RBSTRUCT *node = rb_entry(rb, RBSTRUCT, RBFIELD);	\
 83		if (RBCOMPUTE(node, true))				\
 84			break;						\
 85		rb = rb_parent(&node->RBFIELD);				\
 86	}								\
 87}									\
 88static inline void							\
 89RBNAME ## _copy(struct rb_node *rb_old, struct rb_node *rb_new)		\
 90{									\
 91	RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD);		\
 92	RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD);		\
 93	new->RBAUGMENTED = old->RBAUGMENTED;				\
 94}									\
 95static void								\
 96RBNAME ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new)	\
 97{									\
 98	RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD);		\
 99	RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD);		\
100	new->RBAUGMENTED = old->RBAUGMENTED;				\
101	RBCOMPUTE(old, false);						\
102}									\
103RBSTATIC const struct rb_augment_callbacks RBNAME = {			\
104	.propagate = RBNAME ## _propagate,				\
105	.copy = RBNAME ## _copy,					\
106	.rotate = RBNAME ## _rotate					\
107};
108
109/*
110 * Template for declaring augmented rbtree callbacks,
111 * computing RBAUGMENTED scalar as max(RBCOMPUTE(node)) for all subtree nodes.
112 *
113 * RBSTATIC:    'static' or empty
114 * RBNAME:      name of the rb_augment_callbacks structure
115 * RBSTRUCT:    struct type of the tree nodes
116 * RBFIELD:     name of struct rb_node field within RBSTRUCT
117 * RBTYPE:      type of the RBAUGMENTED field
118 * RBAUGMENTED: name of RBTYPE field within RBSTRUCT holding data for subtree
119 * RBCOMPUTE:   name of function that returns the per-node RBTYPE scalar
120 */
121
122#define RB_DECLARE_CALLBACKS_MAX(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD,	      \
123				 RBTYPE, RBAUGMENTED, RBCOMPUTE)	      \
124static inline bool RBNAME ## _compute_max(RBSTRUCT *node, bool exit)	      \
125{									      \
126	RBSTRUCT *child;						      \
127	RBTYPE max = RBCOMPUTE(node);					      \
128	if (node->RBFIELD.rb_left) {					      \
129		child = rb_entry(node->RBFIELD.rb_left, RBSTRUCT, RBFIELD);   \
130		if (child->RBAUGMENTED > max)				      \
131			max = child->RBAUGMENTED;			      \
132	}								      \
133	if (node->RBFIELD.rb_right) {					      \
134		child = rb_entry(node->RBFIELD.rb_right, RBSTRUCT, RBFIELD);  \
135		if (child->RBAUGMENTED > max)				      \
136			max = child->RBAUGMENTED;			      \
137	}								      \
138	if (exit && node->RBAUGMENTED == max)				      \
139		return true;						      \
140	node->RBAUGMENTED = max;					      \
141	return false;							      \
142}									      \
143RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME,					      \
144		     RBSTRUCT, RBFIELD, RBAUGMENTED, RBNAME ## _compute_max)
145
146
147#define	RB_RED		0
148#define	RB_BLACK	1
149
150#define __rb_parent(pc)    ((struct rb_node *)(pc & ~3))
151
152#define __rb_color(pc)     ((pc) & 1)
153#define __rb_is_black(pc)  __rb_color(pc)
154#define __rb_is_red(pc)    (!__rb_color(pc))
155#define rb_color(rb)       __rb_color((rb)->__rb_parent_color)
156#define rb_is_red(rb)      __rb_is_red((rb)->__rb_parent_color)
157#define rb_is_black(rb)    __rb_is_black((rb)->__rb_parent_color)
158
159static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
160{
161	rb->__rb_parent_color = rb_color(rb) + (unsigned long)p;
162}
163
164static inline void rb_set_parent_color(struct rb_node *rb,
165				       struct rb_node *p, int color)
166{
167	rb->__rb_parent_color = (unsigned long)p + color;
168}
169
170static inline void
171__rb_change_child(struct rb_node *old, struct rb_node *new,
172		  struct rb_node *parent, struct rb_root *root)
173{
174	if (parent) {
175		if (parent->rb_left == old)
176			WRITE_ONCE(parent->rb_left, new);
177		else
178			WRITE_ONCE(parent->rb_right, new);
179	} else
180		WRITE_ONCE(root->rb_node, new);
181}
182
183extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
184	void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
185
186static __always_inline struct rb_node *
187__rb_erase_augmented(struct rb_node *node, struct rb_root *root,
188		     const struct rb_augment_callbacks *augment)
189{
190	struct rb_node *child = node->rb_right;
191	struct rb_node *tmp = node->rb_left;
192	struct rb_node *parent, *rebalance;
193	unsigned long pc;
194
195	if (!tmp) {
196		/*
197		 * Case 1: node to erase has no more than 1 child (easy!)
198		 *
199		 * Note that if there is one child it must be red due to 5)
200		 * and node must be black due to 4). We adjust colors locally
201		 * so as to bypass __rb_erase_color() later on.
202		 */
203		pc = node->__rb_parent_color;
204		parent = __rb_parent(pc);
205		__rb_change_child(node, child, parent, root);
206		if (child) {
207			child->__rb_parent_color = pc;
208			rebalance = NULL;
209		} else
210			rebalance = __rb_is_black(pc) ? parent : NULL;
211		tmp = parent;
212	} else if (!child) {
213		/* Still case 1, but this time the child is node->rb_left */
214		tmp->__rb_parent_color = pc = node->__rb_parent_color;
215		parent = __rb_parent(pc);
216		__rb_change_child(node, tmp, parent, root);
217		rebalance = NULL;
218		tmp = parent;
219	} else {
220		struct rb_node *successor = child, *child2;
221
222		tmp = child->rb_left;
223		if (!tmp) {
224			/*
225			 * Case 2: node's successor is its right child
226			 *
227			 *    (n)          (s)
228			 *    / \          / \
229			 *  (x) (s)  ->  (x) (c)
230			 *        \
231			 *        (c)
232			 */
233			parent = successor;
234			child2 = successor->rb_right;
235
236			augment->copy(node, successor);
237		} else {
238			/*
239			 * Case 3: node's successor is leftmost under
240			 * node's right child subtree
241			 *
242			 *    (n)          (s)
243			 *    / \          / \
244			 *  (x) (y)  ->  (x) (y)
245			 *      /            /
246			 *    (p)          (p)
247			 *    /            /
248			 *  (s)          (c)
249			 *    \
250			 *    (c)
251			 */
252			do {
253				parent = successor;
254				successor = tmp;
255				tmp = tmp->rb_left;
256			} while (tmp);
257			child2 = successor->rb_right;
258			WRITE_ONCE(parent->rb_left, child2);
259			WRITE_ONCE(successor->rb_right, child);
260			rb_set_parent(child, successor);
261
262			augment->copy(node, successor);
263			augment->propagate(parent, successor);
264		}
265
266		tmp = node->rb_left;
267		WRITE_ONCE(successor->rb_left, tmp);
268		rb_set_parent(tmp, successor);
269
270		pc = node->__rb_parent_color;
271		tmp = __rb_parent(pc);
272		__rb_change_child(node, successor, tmp, root);
273
274		if (child2) {
275			successor->__rb_parent_color = pc;
276			rb_set_parent_color(child2, parent, RB_BLACK);
277			rebalance = NULL;
278		} else {
279			unsigned long pc2 = successor->__rb_parent_color;
280			successor->__rb_parent_color = pc;
281			rebalance = __rb_is_black(pc2) ? parent : NULL;
282		}
283		tmp = successor;
284	}
285
286	augment->propagate(tmp, NULL);
287	return rebalance;
288}
289
290static __always_inline void
291rb_erase_augmented(struct rb_node *node, struct rb_root *root,
292		   const struct rb_augment_callbacks *augment)
293{
294	struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
295	if (rebalance)
296		__rb_erase_color(rebalance, root, augment->rotate);
297}
298
299static __always_inline void
300rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root,
301			  const struct rb_augment_callbacks *augment)
302{
303	if (root->rb_leftmost == node)
304		root->rb_leftmost = rb_next(node);
305	rb_erase_augmented(node, &root->rb_root, augment);
306}
307
308#endif /* _TOOLS_LINUX_RBTREE_AUGMENTED_H */
~/ Read-only file preview.