/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Red Black Trees
( C ) 1999 Andrea Arcangeli < andrea @ suse . de >
linux / include / linux / rbtree . h
To use rbtrees you ' ll have to implement your own insert and search cores .
This will avoid us to use callbacks and to drop drammatically performances .
I know it ' s not the cleaner way , but in C ( not in C + + ) to get
performances and genericity . . .
See Documentation / core - api / rbtree . rst for documentation and samples .
*/
#ifndef _LINUX_RBTREE_H
#define _LINUX_RBTREE_H
#include <linux/container_of.h>
#include <linux/rbtree_types.h>
#include <linux/stddef.h>
#include <linux/rcupdate.h>
#define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3 ))
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
#define RB_EMPTY_ROOT(root) (READ_ONCE((root)->rb_node) == NULL)
/* 'empty' nodes are nodes that are known not to be inserted in an rbtree */
#define RB_EMPTY_NODE(node) \
((node)->__rb_parent_color == (unsigned long )(node))
#define RB_CLEAR_NODE(node) \
((node)->__rb_parent_color = (unsigned long )(node))
extern void rb_insert_color(struct rb_node *, struct rb_root *);
extern void rb_erase(struct rb_node *, struct rb_root *);
/* Find logical next and previous nodes in a tree */
extern struct rb_node *rb_next(const struct rb_node *);
extern struct rb_node *rb_prev(const struct rb_node *);
extern struct rb_node *rb_first(const struct rb_root *);
extern struct rb_node *rb_last(const struct rb_root *);
/* Postorder iteration - always visit the parent after its children */
extern struct rb_node *rb_first_postorder(const struct rb_root *);
extern struct rb_node *rb_next_postorder(const struct rb_node *);
/* Fast replacement of a single node without remove/rebalance/add/rebalance */
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new ,
struct rb_root *root);
extern void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new ,
struct rb_root *root);
static inline void rb_link_node(struct rb_node *node, struct rb_node *parent,
struct rb_node **rb_link)
{
node->__rb_parent_color = (unsigned long )parent;
node->rb_left = node->rb_right = NULL;
*rb_link = node;
}
static inline void rb_link_node_rcu(struct rb_node *node, struct rb_node *parent,
struct rb_node **rb_link)
{
node->__rb_parent_color = (unsigned long )parent;
node->rb_left = node->rb_right = NULL;
rcu_assign_pointer(*rb_link, node);
}
#define rb_entry_safe(ptr, type, member) \
({ typeof(ptr) ____ptr = (ptr); \
____ptr ? rb_entry(____ptr, type, member) : NULL; \
})
/**
* rbtree_postorder_for_each_entry_safe - iterate in post - order over rb_root of
* given type allowing the backing memory of @ pos to be invalidated
*
* @ pos : the ' type * ' to use as a loop cursor .
* @ n : another ' type * ' to use as temporary storage
* @ root : ' rb_root * ' of the rbtree .
* @ field : the name of the rb_node field within ' type ' .
*
* rbtree_postorder_for_each_entry_safe ( ) provides a similar guarantee as
* list_for_each_entry_safe ( ) and allows the iteration to continue independent
* of changes to @ pos by the body of the loop .
*
* Note , however , that it cannot handle other modifications that re - order the
* rbtree it is iterating over . This includes calling rb_erase ( ) on @ pos , as
* rb_erase ( ) may rebalance the tree , causing us to miss some nodes .
*/
#define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \
for (pos = rb_entry_safe(rb_first_postorder(root), typeof(*pos), field); \
pos && ({ n = rb_entry_safe(rb_next_postorder(&pos->field), \
typeof(*pos), field); 1 ; }); \
pos = n)
/* Same as rb_first(), but O(1) */
#define rb_first_cached(root) (root)->rb_leftmost
static inline void rb_insert_color_cached(struct rb_node *node,
struct rb_root_cached *root,
bool leftmost)
{
if (leftmost)
root->rb_leftmost = node;
rb_insert_color(node, &root->rb_root);
}
static inline struct rb_node *
rb_erase_cached(struct rb_node *node, struct rb_root_cached *root)
{
struct rb_node *leftmost = NULL;
if (root->rb_leftmost == node)
leftmost = root->rb_leftmost = rb_next(node);
rb_erase(node, &root->rb_root);
return leftmost;
}
static inline void rb_replace_node_cached(struct rb_node *victim,
struct rb_node *new ,
struct rb_root_cached *root)
{
if (root->rb_leftmost == victim)
root->rb_leftmost = new ;
rb_replace_node(victim, new , &root->rb_root);
}
/*
* The below helper functions use 2 operators with 3 different
* calling conventions . The operators are related like :
*
* comp ( a - > key , b ) < 0 : = less ( a , b )
* comp ( a - > key , b ) > 0 : = less ( b , a )
* comp ( a - > key , b ) = = 0 : = ! less ( a , b ) & & ! less ( b , a )
*
* If these operators define a partial order on the elements we make no
* guarantee on which of the elements matching the key is found . See
* rb_find ( ) .
*
* The reason for this is to allow the find ( ) interface without requiring an
* on - stack dummy object , which might not be feasible due to object size .
*/
/**
* rb_add_cached ( ) - insert @ node into the leftmost cached tree @ tree
* @ node : node to insert
* @ tree : leftmost cached tree to insert @ node into
* @ less : operator defining the ( partial ) node order
*
* Returns @ node when it is the new leftmost , or NULL .
*/
static __always_inline struct rb_node *
rb_add_cached(struct rb_node *node, struct rb_root_cached *tree,
bool (*less)(struct rb_node *, const struct rb_node *))
{
struct rb_node **link = &tree->rb_root.rb_node;
struct rb_node *parent = NULL;
bool leftmost = true ;
while (*link) {
parent = *link;
if (less(node, parent)) {
link = &parent->rb_left;
} else {
link = &parent->rb_right;
leftmost = false ;
}
}
rb_link_node(node, parent, link);
rb_insert_color_cached(node, tree, leftmost);
return leftmost ? node : NULL;
}
/**
* rb_add ( ) - insert @ node into @ tree
* @ node : node to insert
* @ tree : tree to insert @ node into
* @ less : operator defining the ( partial ) node order
*/
static __always_inline void
rb_add(struct rb_node *node, struct rb_root *tree,
bool (*less)(struct rb_node *, const struct rb_node *))
{
struct rb_node **link = &tree->rb_node;
struct rb_node *parent = NULL;
while (*link) {
parent = *link;
if (less(node, parent))
link = &parent->rb_left;
else
link = &parent->rb_right;
}
rb_link_node(node, parent, link);
rb_insert_color(node, tree);
}
/**
* rb_find_add_cached ( ) - find equivalent @ node in @ tree , or add @ node
* @ node : node to look - for / insert
* @ tree : tree to search / modify
* @ cmp : operator defining the node order
*
* Returns the rb_node matching @ node , or NULL when no match is found and @ node
* is inserted .
*/
static __always_inline struct rb_node *
rb_find_add_cached(struct rb_node *node, struct rb_root_cached *tree,
int (*cmp)(const struct rb_node *new , const struct rb_node *exist))
{
bool leftmost = true ;
struct rb_node **link = &tree->rb_root.rb_node;
struct rb_node *parent = NULL;
int c;
while (*link) {
parent = *link;
c = cmp(node, parent);
if (c < 0 ) {
link = &parent->rb_left;
} else if (c > 0 ) {
link = &parent->rb_right;
leftmost = false ;
} else {
return parent;
}
}
rb_link_node(node, parent, link);
rb_insert_color_cached(node, tree, leftmost);
return NULL;
}
/**
* rb_find_add ( ) - find equivalent @ node in @ tree , or add @ node
* @ node : node to look - for / insert
* @ tree : tree to search / modify
* @ cmp : operator defining the node order
*
* Returns the rb_node matching @ node , or NULL when no match is found and @ node
* is inserted .
*/
static __always_inline struct rb_node *
rb_find_add(struct rb_node *node, struct rb_root *tree,
int (*cmp)(struct rb_node *, const struct rb_node *))
{
struct rb_node **link = &tree->rb_node;
struct rb_node *parent = NULL;
int c;
while (*link) {
parent = *link;
c = cmp(node, parent);
if (c < 0 )
link = &parent->rb_left;
else if (c > 0 )
link = &parent->rb_right;
else
return parent;
}
rb_link_node(node, parent, link);
rb_insert_color(node, tree);
return NULL;
}
/**
* rb_find_add_rcu ( ) - find equivalent @ node in @ tree , or add @ node
* @ node : node to look - for / insert
* @ tree : tree to search / modify
* @ cmp : operator defining the node order
*
* Adds a Store - Release for link_node .
*
* Returns the rb_node matching @ node , or NULL when no match is found and @ node
* is inserted .
*/
static __always_inline struct rb_node *
rb_find_add_rcu(struct rb_node *node, struct rb_root *tree,
int (*cmp)(struct rb_node *, const struct rb_node *))
{
struct rb_node **link = &tree->rb_node;
struct rb_node *parent = NULL;
int c;
while (*link) {
parent = *link;
c = cmp(node, parent);
if (c < 0 )
link = &parent->rb_left;
else if (c > 0 )
link = &parent->rb_right;
else
return parent;
}
rb_link_node_rcu(node, parent, link);
rb_insert_color(node, tree);
return NULL;
}
/**
* rb_find ( ) - find @ key in tree @ tree
* @ key : key to match
* @ tree : tree to search
* @ cmp : operator defining the node order
*
* Returns the rb_node matching @ key or NULL .
*/
static __always_inline struct rb_node *
rb_find(const void *key, const struct rb_root *tree,
int (*cmp)(const void *key, const struct rb_node *))
{
struct rb_node *node = tree->rb_node;
while (node) {
int c = cmp(key, node);
if (c < 0 )
node = node->rb_left;
else if (c > 0 )
node = node->rb_right;
else
return node;
}
return NULL;
}
/**
* rb_find_rcu ( ) - find @ key in tree @ tree
* @ key : key to match
* @ tree : tree to search
* @ cmp : operator defining the node order
*
* Notably , tree descent vs concurrent tree rotations is unsound and can result
* in false - negatives .
*
* Returns the rb_node matching @ key or NULL .
*/
static __always_inline struct rb_node *
rb_find_rcu(const void *key, const struct rb_root *tree,
int (*cmp)(const void *key, const struct rb_node *))
{
struct rb_node *node = tree->rb_node;
while (node) {
int c = cmp(key, node);
if (c < 0 )
node = rcu_dereference_raw(node->rb_left);
else if (c > 0 )
node = rcu_dereference_raw(node->rb_right);
else
return node;
}
return NULL;
}
/**
* rb_find_first ( ) - find the first @ key in @ tree
* @ key : key to match
* @ tree : tree to search
* @ cmp : operator defining node order
*
* Returns the leftmost node matching @ key , or NULL .
*/
static __always_inline struct rb_node *
rb_find_first(const void *key, const struct rb_root *tree,
int (*cmp)(const void *key, const struct rb_node *))
{
struct rb_node *node = tree->rb_node;
struct rb_node *match = NULL;
while (node) {
int c = cmp(key, node);
if (c <= 0 ) {
if (!c)
match = node;
node = node->rb_left;
} else if (c > 0 ) {
node = node->rb_right;
}
}
return match;
}
/**
* rb_next_match ( ) - find the next @ key in @ tree
* @ key : key to match
* @ tree : tree to search
* @ cmp : operator defining node order
*
* Returns the next node matching @ key , or NULL .
*/
static __always_inline struct rb_node *
rb_next_match(const void *key, struct rb_node *node,
int (*cmp)(const void *key, const struct rb_node *))
{
node = rb_next(node);
if (node && cmp(key, node))
node = NULL;
return node;
}
/**
* rb_for_each ( ) - iterates a subtree matching @ key
* @ node : iterator
* @ key : key to match
* @ tree : tree to search
* @ cmp : operator defining node order
*/
#define rb_for_each(node, key, tree, cmp) \
for ((node) = rb_find_first((key), (tree), (cmp)); \
(node); (node) = rb_next_match((key), (node), (cmp)))
#endif /* _LINUX_RBTREE_H */
Messung V0.5 in Prozent C=96 H=93 G=94
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland