Now it's used at UBI module. Of course other modules can use it. If you want to use it, please define CONFIG_RBTREE Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>master
parent
fbd85ad65d
commit
7ba890bf2f
@ -0,0 +1,160 @@ |
||||
/*
|
||||
Red Black Trees |
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de> |
||||
|
||||
This program is free software; you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation; either version 2 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
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... |
||||
|
||||
Some example of insert and search follows here. The search is a plain |
||||
normal search over an ordered tree. The insert instead must be implemented |
||||
int two steps: as first thing the code must insert the element in |
||||
order as a red leaf in the tree, then the support library function |
||||
rb_insert_color() must be called. Such function will do the |
||||
not trivial work to rebalance the rbtree if necessary. |
||||
|
||||
----------------------------------------------------------------------- |
||||
static inline struct page * rb_search_page_cache(struct inode * inode, |
||||
unsigned long offset) |
||||
{ |
||||
struct rb_node * n = inode->i_rb_page_cache.rb_node; |
||||
struct page * page; |
||||
|
||||
while (n) |
||||
{ |
||||
page = rb_entry(n, struct page, rb_page_cache); |
||||
|
||||
if (offset < page->offset) |
||||
n = n->rb_left; |
||||
else if (offset > page->offset) |
||||
n = n->rb_right; |
||||
else |
||||
return page; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
static inline struct page * __rb_insert_page_cache(struct inode * inode, |
||||
unsigned long offset, |
||||
struct rb_node * node) |
||||
{ |
||||
struct rb_node ** p = &inode->i_rb_page_cache.rb_node; |
||||
struct rb_node * parent = NULL; |
||||
struct page * page; |
||||
|
||||
while (*p) |
||||
{ |
||||
parent = *p; |
||||
page = rb_entry(parent, struct page, rb_page_cache); |
||||
|
||||
if (offset < page->offset) |
||||
p = &(*p)->rb_left; |
||||
else if (offset > page->offset) |
||||
p = &(*p)->rb_right; |
||||
else |
||||
return page; |
||||
} |
||||
|
||||
rb_link_node(node, parent, p); |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
static inline struct page * rb_insert_page_cache(struct inode * inode, |
||||
unsigned long offset, |
||||
struct rb_node * node) |
||||
{ |
||||
struct page * ret; |
||||
if ((ret = __rb_insert_page_cache(inode, offset, node))) |
||||
goto out; |
||||
rb_insert_color(node, &inode->i_rb_page_cache); |
||||
out: |
||||
return ret; |
||||
} |
||||
----------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#ifndef _LINUX_RBTREE_H |
||||
#define _LINUX_RBTREE_H |
||||
|
||||
#include <linux/stddef.h> |
||||
|
||||
struct rb_node |
||||
{ |
||||
unsigned long rb_parent_color; |
||||
#define RB_RED 0 |
||||
#define RB_BLACK 1 |
||||
struct rb_node *rb_right; |
||||
struct rb_node *rb_left; |
||||
} __attribute__((aligned(sizeof(long)))); |
||||
/* The alignment might seem pointless, but allegedly CRIS needs it */ |
||||
|
||||
struct rb_root |
||||
{ |
||||
struct rb_node *rb_node; |
||||
}; |
||||
|
||||
|
||||
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) |
||||
#define rb_color(r) ((r)->rb_parent_color & 1) |
||||
#define rb_is_red(r) (!rb_color(r)) |
||||
#define rb_is_black(r) rb_color(r) |
||||
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) |
||||
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) |
||||
|
||||
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) |
||||
{ |
||||
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; |
||||
} |
||||
static inline void rb_set_color(struct rb_node *rb, int color) |
||||
{ |
||||
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; |
||||
} |
||||
|
||||
#define RB_ROOT (struct rb_root) { NULL, } |
||||
#define rb_entry(ptr, type, member) container_of(ptr, type, member) |
||||
|
||||
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) |
||||
#define RB_EMPTY_NODE(node) (rb_parent(node) == node) |
||||
#define RB_CLEAR_NODE(node) (rb_set_parent(node, 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(struct rb_node *); |
||||
extern struct rb_node *rb_prev(struct rb_node *); |
||||
extern struct rb_node *rb_first(struct rb_root *); |
||||
extern struct rb_node *rb_last(struct rb_root *); |
||||
|
||||
/* 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); |
||||
|
||||
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; |
||||
} |
||||
|
||||
#endif /* _LINUX_RBTREE_H */ |
@ -0,0 +1,390 @@ |
||||
/*
|
||||
Red Black Trees |
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de> |
||||
(C) 2002 David Woodhouse <dwmw2@infradead.org> |
||||
|
||||
This program is free software; you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation; either version 2 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
linux/lib/rbtree.c |
||||
*/ |
||||
|
||||
#include <ubi_uboot.h> |
||||
#include <linux/rbtree.h> |
||||
|
||||
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) |
||||
{ |
||||
struct rb_node *right = node->rb_right; |
||||
struct rb_node *parent = rb_parent(node); |
||||
|
||||
if ((node->rb_right = right->rb_left)) |
||||
rb_set_parent(right->rb_left, node); |
||||
right->rb_left = node; |
||||
|
||||
rb_set_parent(right, parent); |
||||
|
||||
if (parent) |
||||
{ |
||||
if (node == parent->rb_left) |
||||
parent->rb_left = right; |
||||
else |
||||
parent->rb_right = right; |
||||
} |
||||
else |
||||
root->rb_node = right; |
||||
rb_set_parent(node, right); |
||||
} |
||||
|
||||
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) |
||||
{ |
||||
struct rb_node *left = node->rb_left; |
||||
struct rb_node *parent = rb_parent(node); |
||||
|
||||
if ((node->rb_left = left->rb_right)) |
||||
rb_set_parent(left->rb_right, node); |
||||
left->rb_right = node; |
||||
|
||||
rb_set_parent(left, parent); |
||||
|
||||
if (parent) |
||||
{ |
||||
if (node == parent->rb_right) |
||||
parent->rb_right = left; |
||||
else |
||||
parent->rb_left = left; |
||||
} |
||||
else |
||||
root->rb_node = left; |
||||
rb_set_parent(node, left); |
||||
} |
||||
|
||||
void rb_insert_color(struct rb_node *node, struct rb_root *root) |
||||
{ |
||||
struct rb_node *parent, *gparent; |
||||
|
||||
while ((parent = rb_parent(node)) && rb_is_red(parent)) |
||||
{ |
||||
gparent = rb_parent(parent); |
||||
|
||||
if (parent == gparent->rb_left) |
||||
{ |
||||
{ |
||||
register struct rb_node *uncle = gparent->rb_right; |
||||
if (uncle && rb_is_red(uncle)) |
||||
{ |
||||
rb_set_black(uncle); |
||||
rb_set_black(parent); |
||||
rb_set_red(gparent); |
||||
node = gparent; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
if (parent->rb_right == node) |
||||
{ |
||||
register struct rb_node *tmp; |
||||
__rb_rotate_left(parent, root); |
||||
tmp = parent; |
||||
parent = node; |
||||
node = tmp; |
||||
} |
||||
|
||||
rb_set_black(parent); |
||||
rb_set_red(gparent); |
||||
__rb_rotate_right(gparent, root); |
||||
} else { |
||||
{ |
||||
register struct rb_node *uncle = gparent->rb_left; |
||||
if (uncle && rb_is_red(uncle)) |
||||
{ |
||||
rb_set_black(uncle); |
||||
rb_set_black(parent); |
||||
rb_set_red(gparent); |
||||
node = gparent; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
if (parent->rb_left == node) |
||||
{ |
||||
register struct rb_node *tmp; |
||||
__rb_rotate_right(parent, root); |
||||
tmp = parent; |
||||
parent = node; |
||||
node = tmp; |
||||
} |
||||
|
||||
rb_set_black(parent); |
||||
rb_set_red(gparent); |
||||
__rb_rotate_left(gparent, root); |
||||
} |
||||
} |
||||
|
||||
rb_set_black(root->rb_node); |
||||
} |
||||
|
||||
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, |
||||
struct rb_root *root) |
||||
{ |
||||
struct rb_node *other; |
||||
|
||||
while ((!node || rb_is_black(node)) && node != root->rb_node) |
||||
{ |
||||
if (parent->rb_left == node) |
||||
{ |
||||
other = parent->rb_right; |
||||
if (rb_is_red(other)) |
||||
{ |
||||
rb_set_black(other); |
||||
rb_set_red(parent); |
||||
__rb_rotate_left(parent, root); |
||||
other = parent->rb_right; |
||||
} |
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) && |
||||
(!other->rb_right || rb_is_black(other->rb_right))) |
||||
{ |
||||
rb_set_red(other); |
||||
node = parent; |
||||
parent = rb_parent(node); |
||||
} |
||||
else |
||||
{ |
||||
if (!other->rb_right || rb_is_black(other->rb_right)) |
||||
{ |
||||
struct rb_node *o_left; |
||||
if ((o_left = other->rb_left)) |
||||
rb_set_black(o_left); |
||||
rb_set_red(other); |
||||
__rb_rotate_right(other, root); |
||||
other = parent->rb_right; |
||||
} |
||||
rb_set_color(other, rb_color(parent)); |
||||
rb_set_black(parent); |
||||
if (other->rb_right) |
||||
rb_set_black(other->rb_right); |
||||
__rb_rotate_left(parent, root); |
||||
node = root->rb_node; |
||||
break; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
other = parent->rb_left; |
||||
if (rb_is_red(other)) |
||||
{ |
||||
rb_set_black(other); |
||||
rb_set_red(parent); |
||||
__rb_rotate_right(parent, root); |
||||
other = parent->rb_left; |
||||
} |
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) && |
||||
(!other->rb_right || rb_is_black(other->rb_right))) |
||||
{ |
||||
rb_set_red(other); |
||||
node = parent; |
||||
parent = rb_parent(node); |
||||
} |
||||
else |
||||
{ |
||||
if (!other->rb_left || rb_is_black(other->rb_left)) |
||||
{ |
||||
register struct rb_node *o_right; |
||||
if ((o_right = other->rb_right)) |
||||
rb_set_black(o_right); |
||||
rb_set_red(other); |
||||
__rb_rotate_left(other, root); |
||||
other = parent->rb_left; |
||||
} |
||||
rb_set_color(other, rb_color(parent)); |
||||
rb_set_black(parent); |
||||
if (other->rb_left) |
||||
rb_set_black(other->rb_left); |
||||
__rb_rotate_right(parent, root); |
||||
node = root->rb_node; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (node) |
||||
rb_set_black(node); |
||||
} |
||||
|
||||
void rb_erase(struct rb_node *node, struct rb_root *root) |
||||
{ |
||||
struct rb_node *child, *parent; |
||||
int color; |
||||
|
||||
if (!node->rb_left) |
||||
child = node->rb_right; |
||||
else if (!node->rb_right) |
||||
child = node->rb_left; |
||||
else |
||||
{ |
||||
struct rb_node *old = node, *left; |
||||
|
||||
node = node->rb_right; |
||||
while ((left = node->rb_left) != NULL) |
||||
node = left; |
||||
child = node->rb_right; |
||||
parent = rb_parent(node); |
||||
color = rb_color(node); |
||||
|
||||
if (child) |
||||
rb_set_parent(child, parent); |
||||
if (parent == old) { |
||||
parent->rb_right = child; |
||||
parent = node; |
||||
} else |
||||
parent->rb_left = child; |
||||
|
||||
node->rb_parent_color = old->rb_parent_color; |
||||
node->rb_right = old->rb_right; |
||||
node->rb_left = old->rb_left; |
||||
|
||||
if (rb_parent(old)) |
||||
{ |
||||
if (rb_parent(old)->rb_left == old) |
||||
rb_parent(old)->rb_left = node; |
||||
else |
||||
rb_parent(old)->rb_right = node; |
||||
} else |
||||
root->rb_node = node; |
||||
|
||||
rb_set_parent(old->rb_left, node); |
||||
if (old->rb_right) |
||||
rb_set_parent(old->rb_right, node); |
||||
goto color; |
||||
} |
||||
|
||||
parent = rb_parent(node); |
||||
color = rb_color(node); |
||||
|
||||
if (child) |
||||
rb_set_parent(child, parent); |
||||
if (parent) |
||||
{ |
||||
if (parent->rb_left == node) |
||||
parent->rb_left = child; |
||||
else |
||||
parent->rb_right = child; |
||||
} |
||||
else |
||||
root->rb_node = child; |
||||
|
||||
color: |
||||
if (color == RB_BLACK) |
||||
__rb_erase_color(child, parent, root); |
||||
} |
||||
|
||||
/*
|
||||
* This function returns the first node (in sort order) of the tree. |
||||
*/ |
||||
struct rb_node *rb_first(struct rb_root *root) |
||||
{ |
||||
struct rb_node *n; |
||||
|
||||
n = root->rb_node; |
||||
if (!n) |
||||
return NULL; |
||||
while (n->rb_left) |
||||
n = n->rb_left; |
||||
return n; |
||||
} |
||||
|
||||
struct rb_node *rb_last(struct rb_root *root) |
||||
{ |
||||
struct rb_node *n; |
||||
|
||||
n = root->rb_node; |
||||
if (!n) |
||||
return NULL; |
||||
while (n->rb_right) |
||||
n = n->rb_right; |
||||
return n; |
||||
} |
||||
|
||||
struct rb_node *rb_next(struct rb_node *node) |
||||
{ |
||||
struct rb_node *parent; |
||||
|
||||
if (rb_parent(node) == node) |
||||
return NULL; |
||||
|
||||
/* If we have a right-hand child, go down and then left as far
|
||||
as we can. */ |
||||
if (node->rb_right) { |
||||
node = node->rb_right; |
||||
while (node->rb_left) |
||||
node=node->rb_left; |
||||
return node; |
||||
} |
||||
|
||||
/* No right-hand children. Everything down and left is
|
||||
smaller than us, so any 'next' node must be in the general |
||||
direction of our parent. Go up the tree; any time the |
||||
ancestor is a right-hand child of its parent, keep going |
||||
up. First time it's a left-hand child of its parent, said |
||||
parent is our 'next' node. */ |
||||
while ((parent = rb_parent(node)) && node == parent->rb_right) |
||||
node = parent; |
||||
|
||||
return parent; |
||||
} |
||||
|
||||
struct rb_node *rb_prev(struct rb_node *node) |
||||
{ |
||||
struct rb_node *parent; |
||||
|
||||
if (rb_parent(node) == node) |
||||
return NULL; |
||||
|
||||
/* If we have a left-hand child, go down and then right as far
|
||||
as we can. */ |
||||
if (node->rb_left) { |
||||
node = node->rb_left; |
||||
while (node->rb_right) |
||||
node=node->rb_right; |
||||
return node; |
||||
} |
||||
|
||||
/* No left-hand children. Go up till we find an ancestor which
|
||||
is a right-hand child of its parent */ |
||||
while ((parent = rb_parent(node)) && node == parent->rb_left) |
||||
node = parent; |
||||
|
||||
return parent; |
||||
} |
||||
|
||||
void rb_replace_node(struct rb_node *victim, struct rb_node *new, |
||||
struct rb_root *root) |
||||
{ |
||||
struct rb_node *parent = rb_parent(victim); |
||||
|
||||
/* Set the surrounding nodes to point to the replacement */ |
||||
if (parent) { |
||||
if (victim == parent->rb_left) |
||||
parent->rb_left = new; |
||||
else |
||||
parent->rb_right = new; |
||||
} else { |
||||
root->rb_node = new; |
||||
} |
||||
if (victim->rb_left) |
||||
rb_set_parent(victim->rb_left, new); |
||||
if (victim->rb_right) |
||||
rb_set_parent(victim->rb_right, new); |
||||
|
||||
/* Copy the pointers/colour from the victim to the replacement */ |
||||
*new = *victim; |
||||
} |
Loading…
Reference in new issue