diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/rbtree.h | 21 | ||||
| -rw-r--r-- | include/linux/rbtree_augmented.h | 33 |
2 files changed, 51 insertions, 3 deletions
diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index e585018498d5..d574361943ea 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h | |||
| @@ -44,10 +44,25 @@ struct rb_root { | |||
| 44 | struct rb_node *rb_node; | 44 | struct rb_node *rb_node; |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | /* | ||
| 48 | * Leftmost-cached rbtrees. | ||
| 49 | * | ||
| 50 | * We do not cache the rightmost node based on footprint | ||
| 51 | * size vs number of potential users that could benefit | ||
| 52 | * from O(1) rb_last(). Just not worth it, users that want | ||
| 53 | * this feature can always implement the logic explicitly. | ||
| 54 | * Furthermore, users that want to cache both pointers may | ||
| 55 | * find it a bit asymmetric, but that's ok. | ||
| 56 | */ | ||
| 57 | struct rb_root_cached { | ||
| 58 | struct rb_root rb_root; | ||
| 59 | struct rb_node *rb_leftmost; | ||
| 60 | }; | ||
| 47 | 61 | ||
| 48 | #define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3)) | 62 | #define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3)) |
| 49 | 63 | ||
| 50 | #define RB_ROOT (struct rb_root) { NULL, } | 64 | #define RB_ROOT (struct rb_root) { NULL, } |
| 65 | #define RB_ROOT_CACHED (struct rb_root_cached) { {NULL, }, NULL } | ||
| 51 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) | 66 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) |
| 52 | 67 | ||
| 53 | #define RB_EMPTY_ROOT(root) (READ_ONCE((root)->rb_node) == NULL) | 68 | #define RB_EMPTY_ROOT(root) (READ_ONCE((root)->rb_node) == NULL) |
| @@ -69,6 +84,12 @@ extern struct rb_node *rb_prev(const struct rb_node *); | |||
| 69 | extern struct rb_node *rb_first(const struct rb_root *); | 84 | extern struct rb_node *rb_first(const struct rb_root *); |
| 70 | extern struct rb_node *rb_last(const struct rb_root *); | 85 | extern struct rb_node *rb_last(const struct rb_root *); |
| 71 | 86 | ||
| 87 | extern void rb_insert_color_cached(struct rb_node *, | ||
| 88 | struct rb_root_cached *, bool); | ||
| 89 | extern void rb_erase_cached(struct rb_node *node, struct rb_root_cached *); | ||
| 90 | /* Same as rb_first(), but O(1) */ | ||
| 91 | #define rb_first_cached(root) (root)->rb_leftmost | ||
| 92 | |||
| 72 | /* Postorder iteration - always visit the parent after its children */ | 93 | /* Postorder iteration - always visit the parent after its children */ |
| 73 | extern struct rb_node *rb_first_postorder(const struct rb_root *); | 94 | extern struct rb_node *rb_first_postorder(const struct rb_root *); |
| 74 | extern struct rb_node *rb_next_postorder(const struct rb_node *); | 95 | extern struct rb_node *rb_next_postorder(const struct rb_node *); |
diff --git a/include/linux/rbtree_augmented.h b/include/linux/rbtree_augmented.h index 9702b6e183bc..6bfd2b581f75 100644 --- a/include/linux/rbtree_augmented.h +++ b/include/linux/rbtree_augmented.h | |||
| @@ -41,7 +41,9 @@ struct rb_augment_callbacks { | |||
| 41 | void (*rotate)(struct rb_node *old, struct rb_node *new); | 41 | void (*rotate)(struct rb_node *old, struct rb_node *new); |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, | 44 | extern void __rb_insert_augmented(struct rb_node *node, |
| 45 | struct rb_root *root, | ||
| 46 | bool newleft, struct rb_node **leftmost, | ||
| 45 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); | 47 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); |
| 46 | /* | 48 | /* |
| 47 | * Fixup the rbtree and update the augmented information when rebalancing. | 49 | * Fixup the rbtree and update the augmented information when rebalancing. |
| @@ -57,7 +59,16 @@ static inline void | |||
| 57 | rb_insert_augmented(struct rb_node *node, struct rb_root *root, | 59 | rb_insert_augmented(struct rb_node *node, struct rb_root *root, |
| 58 | const struct rb_augment_callbacks *augment) | 60 | const struct rb_augment_callbacks *augment) |
| 59 | { | 61 | { |
| 60 | __rb_insert_augmented(node, root, augment->rotate); | 62 | __rb_insert_augmented(node, root, false, NULL, augment->rotate); |
| 63 | } | ||
| 64 | |||
| 65 | static inline void | ||
| 66 | rb_insert_augmented_cached(struct rb_node *node, | ||
| 67 | struct rb_root_cached *root, bool newleft, | ||
| 68 | const struct rb_augment_callbacks *augment) | ||
| 69 | { | ||
| 70 | __rb_insert_augmented(node, &root->rb_root, | ||
| 71 | newleft, &root->rb_leftmost, augment->rotate); | ||
| 61 | } | 72 | } |
| 62 | 73 | ||
| 63 | #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \ | 74 | #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \ |
| @@ -150,6 +161,7 @@ extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, | |||
| 150 | 161 | ||
| 151 | static __always_inline struct rb_node * | 162 | static __always_inline struct rb_node * |
| 152 | __rb_erase_augmented(struct rb_node *node, struct rb_root *root, | 163 | __rb_erase_augmented(struct rb_node *node, struct rb_root *root, |
| 164 | struct rb_node **leftmost, | ||
| 153 | const struct rb_augment_callbacks *augment) | 165 | const struct rb_augment_callbacks *augment) |
| 154 | { | 166 | { |
| 155 | struct rb_node *child = node->rb_right; | 167 | struct rb_node *child = node->rb_right; |
| @@ -157,6 +169,9 @@ __rb_erase_augmented(struct rb_node *node, struct rb_root *root, | |||
| 157 | struct rb_node *parent, *rebalance; | 169 | struct rb_node *parent, *rebalance; |
| 158 | unsigned long pc; | 170 | unsigned long pc; |
| 159 | 171 | ||
| 172 | if (leftmost && node == *leftmost) | ||
| 173 | *leftmost = rb_next(node); | ||
| 174 | |||
| 160 | if (!tmp) { | 175 | if (!tmp) { |
| 161 | /* | 176 | /* |
| 162 | * Case 1: node to erase has no more than 1 child (easy!) | 177 | * Case 1: node to erase has no more than 1 child (easy!) |
| @@ -256,9 +271,21 @@ static __always_inline void | |||
| 256 | rb_erase_augmented(struct rb_node *node, struct rb_root *root, | 271 | rb_erase_augmented(struct rb_node *node, struct rb_root *root, |
| 257 | const struct rb_augment_callbacks *augment) | 272 | const struct rb_augment_callbacks *augment) |
| 258 | { | 273 | { |
| 259 | struct rb_node *rebalance = __rb_erase_augmented(node, root, augment); | 274 | struct rb_node *rebalance = __rb_erase_augmented(node, root, |
| 275 | NULL, augment); | ||
| 260 | if (rebalance) | 276 | if (rebalance) |
| 261 | __rb_erase_color(rebalance, root, augment->rotate); | 277 | __rb_erase_color(rebalance, root, augment->rotate); |
| 262 | } | 278 | } |
| 263 | 279 | ||
| 280 | static __always_inline void | ||
| 281 | rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root, | ||
| 282 | const struct rb_augment_callbacks *augment) | ||
| 283 | { | ||
| 284 | struct rb_node *rebalance = __rb_erase_augmented(node, &root->rb_root, | ||
| 285 | &root->rb_leftmost, | ||
| 286 | augment); | ||
| 287 | if (rebalance) | ||
| 288 | __rb_erase_color(rebalance, &root->rb_root, augment->rotate); | ||
| 289 | } | ||
| 290 | |||
| 264 | #endif /* _LINUX_RBTREE_AUGMENTED_H */ | 291 | #endif /* _LINUX_RBTREE_AUGMENTED_H */ |
