Skip to content

Commit

Permalink
btrfs-progs: kernel-lib: add rb_root_cached helpers
Browse files Browse the repository at this point in the history
Copy inline helpers for the cached variant of the rbtree, not used yet.
Rename 'new' for C++ compatibility.

Signed-off-by: David Sterba <[email protected]>
  • Loading branch information
kdave committed May 12, 2022
1 parent 2b603d9 commit 68d0437
Show file tree
Hide file tree
Showing 2 changed files with 250 additions and 0 deletions.
230 changes: 230 additions & 0 deletions kernel-lib/rbtree.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
#include <btrfs/rbtree_types.h>
#endif /* BTRFS_FLAT_INCLUDES */

#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -101,6 +103,234 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
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_node,
struct rb_root_cached *root)
{
if (root->rb_leftmost == victim)
root->rb_leftmost = new_node;
rb_replace_node(victim, new_node, &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() - 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() - 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_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)))

#ifdef __cplusplus
}
#endif
Expand Down
20 changes: 20 additions & 0 deletions kernel-lib/rbtree_augmented.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ rb_insert_augmented(struct rb_node *node, struct rb_root *root,
__rb_insert_augmented(node, root, augment->rotate);
}

static inline void
rb_insert_augmented_cached(struct rb_node *node,
struct rb_root_cached *root, bool newleft,
const struct rb_augment_callbacks *augment)
{
if (newleft)
root->rb_leftmost = node;
rb_insert_augmented(node, &root->rb_root, augment);
}


#define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \
rbtype, rbaugmented, rbcompute) \
static inline void \
Expand Down Expand Up @@ -238,4 +249,13 @@ rb_erase_augmented(struct rb_node *node, struct rb_root *root,
__rb_erase_color(rebalance, root, augment->rotate);
}

static __always_inline void
rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root,
const struct rb_augment_callbacks *augment)
{
if (root->rb_leftmost == node)
root->rb_leftmost = rb_next(node);
rb_erase_augmented(node, &root->rb_root, augment);
}

#endif /* _LINUX_RBTREE_AUGMENTED_H */

0 comments on commit 68d0437

Please sign in to comment.