[asterisk-commits] akshayb: branch akshayb/ao2_containers r266520 - /team/akshayb/ao2_containers...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sun May 30 10:56:07 CDT 2010
Author: akshayb
Date: Sun May 30 10:56:04 2010
New Revision: 266520
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=266520
Log:
Adding the variable file for ao2_container in btree data structure
Added:
team/akshayb/ao2_containers/main/astobj2_btree.c (with props)
team/akshayb/ao2_containers/main/btree.c (with props)
Modified:
team/akshayb/ao2_containers/main/astobj2.c
team/akshayb/ao2_containers/main/astobj2_hash.c
Modified: team/akshayb/ao2_containers/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/akshayb/ao2_containers/main/astobj2.c?view=diff&rev=266520&r1=266519&r2=266520
==============================================================================
--- team/akshayb/ao2_containers/main/astobj2.c (original)
+++ team/akshayb/ao2_containers/main/astobj2.c Sun May 30 10:56:04 2010
@@ -378,8 +378,6 @@
struct ao2_container_core {
ao2_callback_fn *cmp_fn;
- ao2_link_fn *link_fn;
- ao2_unlink_fn *unlink_fn;
/*! Number of elements in the container */
int elements;
/*! described above */
@@ -388,6 +386,9 @@
struct ao2_container_var {
ao2_hash_fn *hash_fn;
+ ao2_link_fn *link_fn;
+ ao2_unlink_fn *unlink_fn;
+
int n_buckets;
/*! variable size */
struct bucket buckets[0];
@@ -441,11 +442,9 @@
/* This too can be grouped in a alloc function. But that is un-necessary and would be done later */
c->core.version = 1; /* 0 is a reserved value here */
c->core.cmp_fn = cmp_fn;
- c->core.link_fn = link_fn;
- c->core.unlink_fn = unlink_fn;
/* This can be put in separate allocation function for varialbe an core part. We can just leave core part here and and constructor for variable part,in astobj2_hash.c */
- internal_ao2_container_var_alloc(c, hash_fn, n_buckets);
+ internal_ao2_container_var_alloc(c, hash_fn,link_fn ,unlink_fn n_buckets);
#ifdef AO2_DEBUG
ast_atomic_fetchadd_int(&ao2.total_containers, 1);
@@ -507,61 +506,7 @@
struct astobj2 *astobj; /* pointer to internal data */
};
-/*
- * link an object to a container
- */
-
-static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
-{
- int i;
- /* create a new list entry */
- struct bucket_entry *p;
- struct astobj2 *obj = INTERNAL_OBJ(user_data);
-
- if (obj == NULL)
- return NULL;
-
- if (INTERNAL_OBJ(c) == NULL)
- return NULL;
-
- p = ast_calloc(1, sizeof(*p));
- if (!p)
- return NULL;
-
- i = abs(c->var.hash_fn(user_data, OBJ_POINTER));
-
- ao2_lock(c);
- i %= c->n_buckets;
- p->astobj = obj;
- p->version = ast_atomic_fetchadd_int(&c->version, 1);
- AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
- ast_atomic_fetchadd_int(&c->elements, 1);
-
- /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
- return p;
-}
-
-void *__ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
-{
- struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname);
-
- if (p) {
- __ao2_ref_debug(user_data, +1, tag, file, line, funcname);
- ao2_unlock(c);
- }
- return p;
-}
-
-void *__ao2_link(struct ao2_container *c, void *user_data)
-{
- struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
-
- if (p) {
- __ao2_ref(user_data, +1);
- ao2_unlock(c);
- }
- return p;
-}
+
/*!
* \brief another convenience function is a callback that matches on address
@@ -734,7 +679,8 @@
* link the object into the container that will hold the results.
*/
if (ret && (multi_container != NULL)) {
- __ao2_link(multi_container, ret);
+ //__ao2_link(multi_container, ret);
+ multi_container.ao2_link(multi_container, ret);
ret = NULL;
}
@@ -773,7 +719,7 @@
break;
}
- if (i == c->n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) {
+ if (i == c->var.n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) {
/* Move to the beginning to ensure we check every bucket */
i = -1;
last = start;
@@ -825,12 +771,12 @@
*/
void *__ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname)
{
- return __ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
+ return __ao2_callback_debug(c, flags, c->core.cmp_fn, arg, tag, file, line, funcname);
}
void *__ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
{
- return __ao2_callback(c, flags, c->cmp_fn, arg);
+ return __ao2_callback(c, flags, c->core.cmp_fn, arg);
}
/*!
Added: team/akshayb/ao2_containers/main/astobj2_btree.c
URL: http://svnview.digium.com/svn/asterisk/team/akshayb/ao2_containers/main/astobj2_btree.c?view=auto&rev=266520
==============================================================================
--- team/akshayb/ao2_containers/main/astobj2_btree.c (added)
+++ team/akshayb/ao2_containers/main/astobj2_btree.c Sun May 30 10:56:04 2010
@@ -1,0 +1,100 @@
+#include "asterisk/astobj2.h"
+#include "asterisk/astobj2_hash.h"
+
+void internal_ao2_container_var_alloc(ao2_hash_fn *hash_fn, const unsigned int n_buckets)
+{
+ c->var.hash_fn = hash_fn;
+ c->var.n_buckets = n_buckets;
+}
+
+//This funtion calculates the size of ao2_container. Just replace the code in case of other containers:
+
+size_t get_container_size (const unsigned int num_buckets)
+{
+ return (sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket));
+}
+
+static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
+{
+ int i;
+ /* create a new list entry */
+ struct bucket_entry *p;
+ struct astobj2 *obj = INTERNAL_OBJ(user_data);
+
+ if (obj == NULL)
+ return NULL;
+
+ if (INTERNAL_OBJ(c) == NULL)
+ return NULL;
+
+ p = ast_calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ i = abs(c->var.hash_fn(user_data, OBJ_POINTER));
+
+ ao2_lock(c);
+ i %= c->n_buckets;
+ p->astobj = obj;
+ p->version = ast_atomic_fetchadd_int(&c->version, 1);
+ AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
+ ast_atomic_fetchadd_int(&c->elements, 1);
+
+ /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
+ return p;
+}
+
+void *__ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
+{
+ struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname);
+
+ if (p) {
+ __ao2_ref_debug(user_data, +1, tag, file, line, funcname);
+ ao2_unlock(c);
+ }
+ return p;
+}
+
+void *__ao2_link(struct ao2_container *c, void *user_data)
+{
+ struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+ if (p) {
+ __ao2_ref(user_data, +1);
+ ao2_unlock(c);
+ }
+ return p;
+}
+
+/*!
+ *ao2_unlink
+ *Have to be tested for working, Till now it has been just copied and no testing done for the working of the thing
+*/
+
+/*
+ * Unlink an object from the container
+ * and destroy the associated * bucket_entry structure.
+ */
+
+// link an object to the container.
+void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, char *tag,
+ char *file, int line, const char *funcname)
+{
+ if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
+ return NULL;
+
+ __ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
+
+ return NULL;
+}
+
+void *__ao2_unlink(struct ao2_container *c, void *user_data)
+{
+ if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
+ return NULL;
+
+ __ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
+
+ return NULL;
+}
+
Propchange: team/akshayb/ao2_containers/main/astobj2_btree.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/akshayb/ao2_containers/main/astobj2_btree.c
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Sun May 30 10:56:04 2010
@@ -1,0 +1,1 @@
+Akshay Bhardwaj 30th May 2010, Contains the variable part of ao2_container based on btree data structure
Propchange: team/akshayb/ao2_containers/main/astobj2_btree.c
------------------------------------------------------------------------------
svn:mime-type = text/c
Propchange: team/akshayb/ao2_containers/main/astobj2_btree.c
------------------------------------------------------------------------------
svn:mimetype = text/c
Modified: team/akshayb/ao2_containers/main/astobj2_hash.c
URL: http://svnview.digium.com/svn/asterisk/team/akshayb/ao2_containers/main/astobj2_hash.c?view=diff&rev=266520&r1=266519&r2=266520
==============================================================================
--- team/akshayb/ao2_containers/main/astobj2_hash.c (original)
+++ team/akshayb/ao2_containers/main/astobj2_hash.c Sun May 30 10:56:04 2010
@@ -14,4 +14,87 @@
return (sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket));
}
+static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
+{
+ int i;
+ /* create a new list entry */
+ struct bucket_entry *p;
+ struct astobj2 *obj = INTERNAL_OBJ(user_data);
+ if (obj == NULL)
+ return NULL;
+
+ if (INTERNAL_OBJ(c) == NULL)
+ return NULL;
+
+ p = ast_calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ i = abs(c->var.hash_fn(user_data, OBJ_POINTER));
+
+ ao2_lock(c);
+ i %= c->n_buckets;
+ p->astobj = obj;
+ p->version = ast_atomic_fetchadd_int(&c->version, 1);
+ AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
+ ast_atomic_fetchadd_int(&c->elements, 1);
+
+ /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
+ return p;
+}
+
+void *__ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
+{
+ struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname);
+
+ if (p) {
+ __ao2_ref_debug(user_data, +1, tag, file, line, funcname);
+ ao2_unlock(c);
+ }
+ return p;
+}
+
+void *__ao2_link(struct ao2_container *c, void *user_data)
+{
+ struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+ if (p) {
+ __ao2_ref(user_data, +1);
+ ao2_unlock(c);
+ }
+ return p;
+}
+
+/*!
+ *ao2_unlink
+ *Have to be tested for working, Till now it has been just copied and no testing done for the working of the thing
+*/
+
+/*
+ * Unlink an object from the container
+ * and destroy the associated * bucket_entry structure.
+ */
+
+// link an object to the container.
+void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, char *tag,
+ char *file, int line, const char *funcname)
+{
+ if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
+ return NULL;
+
+ __ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
+
+ return NULL;
+}
+
+void *__ao2_unlink(struct ao2_container *c, void *user_data)
+{
+ if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
+ return NULL;
+
+ __ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
+
+ return NULL;
+}
+
Added: team/akshayb/ao2_containers/main/btree.c
URL: http://svnview.digium.com/svn/asterisk/team/akshayb/ao2_containers/main/btree.c?view=auto&rev=266520
==============================================================================
--- team/akshayb/ao2_containers/main/btree.c (added)
+++ team/akshayb/ao2_containers/main/btree.c Sun May 30 10:56:04 2010
@@ -1,0 +1,857 @@
+#include "btree.h"
+
+typedef enum {left = -1,right = 1} position_t;
+
+typedef struct {
+ bt_node * node;
+ unsigned int index;
+}node_pos;
+
+static void print_single_node(btree *btree, bt_node * node);
+static bt_node * allocate_btree_node (unsigned int order);
+static int free_btree_node (bt_node * node);
+
+static node_pos get_btree_node(btree * btree,void * key);
+
+static int delete_key_from_node(btree * btree, node_pos * node_pos);
+static bt_node * merge_nodes(btree * btree, bt_node * n1, bt_key_val * kv ,bt_node * n2);
+static void move_key(btree * btree, bt_node * node, unsigned int index, position_t pos);
+static node_pos get_max_key_pos(btree * btree, bt_node * subtree);
+static node_pos get_min_key_pos(btree * btree, bt_node * subtree);
+static bt_node * merge_siblings(btree * btree, bt_node * parent,unsigned int index,
+ position_t pos);
+static void copy_key_val(btree * btree,bt_key_val * src, bt_key_val * dst);
+
+/**
+* Used to create a btree with just the root node
+* @param order The order of the B-tree
+* @return The an empty B-tree
+*/
+btree * btree_create(unsigned int order) {
+ btree * btree;
+ btree = mem_alloc(sizeof(*btree));
+ btree->order = order;
+ btree->root = allocate_btree_node(order);
+ btree->root->leaf = true;
+ btree->root->nr_active = 0;
+ btree->root->next = NULL;
+ btree->root->level = 0;
+ return btree;
+}
+
+/**
+* Function used to allocate memory for the btree node
+* @param order Order of the B-Tree
+* @param leaf boolean set true for a leaf node
+* @return The allocated B-tree node
+*/
+static bt_node * allocate_btree_node (unsigned int order) {
+ bt_node * node;
+
+ // Allocate memory for the node
+ node = (bt_node *)mem_alloc(sizeof(bt_node));
+
+ // Initialize the number of active nodes
+ node->nr_active = 0;
+
+ // Initialize the keys
+ node->key_vals = (bt_key_val **)mem_alloc(2*order*sizeof(bt_key_val*) - 1);
+
+ // Initialize the child pointers
+ node->children = (bt_node **)mem_alloc(2*order*sizeof(bt_node*));
+
+ // Use to determine whether it is a leaf
+ node->leaf = true;
+
+ // Use to determine the level in the tree
+ node->level = 0;
+
+ //Initialize the linked list pointer to NULL
+ node->next = NULL;
+
+ return node;
+}
+
+/**
+* Function used to free the memory allocated to the b-tree
+* @param node The node to be freed
+* @param order Order of the B-Tree
+* @return The allocated B-tree node
+*/
+static int free_btree_node (bt_node * node) {
+
+ mem_free(node->children);
+ mem_free(node->key_vals);
+ mem_free(node);
+
+ return 0;
+}
+
+/**
+* Used to split the child node and adjust the parent so that
+* it has two children
+* @param parent Parent Node
+* @param index Index of the child node
+* @param child Full child node
+*
+*/
+static void btree_split_child(btree * btree, bt_node * parent,
+ unsigned int index,
+ bt_node * child) {
+ int i = 0;
+ unsigned int order = btree->order;
+
+ bt_node * new_child = allocate_btree_node(btree->order);
+ new_child->leaf = child->leaf;
+ new_child->level = child->level;
+ new_child->nr_active = btree->order - 1;
+
+ // Copy the higher order keys to the new child
+ for(i=0;i<order - 1;i++) {
+ new_child->key_vals[i] = child->key_vals[i + order];
+ if(!child->leaf) {
+ new_child->children[i] =
+ child->children[i + order];
+ }
+ }
+
+ // Copy the last child pointer
+ if(!child->leaf) {
+ new_child->children[i] =
+ child->children[i + order];
+ }
+
+ child->nr_active = order - 1;
+
+ for(i = parent->nr_active + 1;i > index + 1;i--) {
+ parent->children[i] = parent->children[i - 1];
+ }
+ parent->children[index + 1] = new_child;
+
+ for(i = parent->nr_active;i > index;i--) {
+ parent->key_vals[i] = parent->key_vals[i - 1];
+ }
+
+ parent->key_vals[index] = child->key_vals[order - 1];
+ parent->nr_active++;
+}
+
+/**
+* Used to insert a key in the non-full node
+* @param btree The btree
+* @param node The node to which the key will be added
+* @param the key value pair
+* @return void
+*/
+
+static void btree_insert_nonfull (btree * btree, bt_node * parent_node,
+ bt_key_val * key_val) {
+
+ unsigned int key = btree->value(key_val->key);
+ int i ;
+ bt_node * child;
+ bt_node * node = parent_node;
+
+insert: i = node->nr_active - 1;
+ if(node->leaf) {
+ while(i >= 0 && key < btree->value(node->key_vals[i]->key)) {
+ node->key_vals[i + 1] = node->key_vals[i];
+ i--;
+ }
+ node->key_vals[i + 1] = key_val;
+ node->nr_active++;
+ } else {
+ while (i >= 0 && key < btree->value(node->key_vals[i]->key)) {
+ i--;
+ }
+ i++;
+ child = node->children[i];
+
+ if(child->nr_active == 2*btree->order - 1) {
+ btree_split_child(btree,node,i,child);
+ if(btree->value(key_val->key) >
+ btree->value(node->key_vals[i]->key)) {
+ i++;
+ }
+ }
+ node = node->children[i];
+ goto insert;
+ }
+}
+
+
+/**
+* Function used to insert node into a B-Tree
+* @param root Root of the B-Tree
+* @param node The node to be inserted
+* @param compare Function used to compare the two nodes of the tree
+* @return success or failure
+*/
+int btree_insert_key(btree * btree, bt_key_val * key_val) {
+ bt_node * rnode;
+
+ rnode = btree->root;
+ if(rnode->nr_active == (2*btree->order - 1)) {
+ bt_node * new_root;
+ new_root = allocate_btree_node(btree->order);
+ new_root->level = btree->root->level + 1;
+ btree->root = new_root;
+ new_root->leaf = false;
+ new_root->nr_active = 0;
+ new_root->children[0] = rnode;
+ btree_split_child(btree,new_root,0,rnode);
+ btree_insert_nonfull(btree,new_root,key_val);
+ } else
+ btree_insert_nonfull(btree,rnode,key_val);
+
+ return 0;
+}
+
+/**
+* Used to get the position of the MAX key within the subtree
+* @param btree The btree
+* @param subtree The subtree to be searched
+* @return The node containing the key and position of the key
+*/
+static node_pos get_max_key_pos(btree * btree, bt_node * subtree) {
+ node_pos node_pos;
+ bt_node * node = subtree;
+
+ while(true) {
+ if(node == NULL) {
+ break;
+ }
+
+ if(node->leaf) {
+ node_pos.node = node;
+ node_pos.index = node->nr_active - 1;
+ return node_pos;
+ } else {
+ node_pos.node = node;
+ node_pos.index = node->nr_active - 1;
+ node = node->children[node->nr_active];
+ }
+ }
+ return node_pos;
+}
+
+/**
+* Used to get the position of the MAX key within the subtree
+* @param btree The btree
+* @param subtree The subtree to be searched
+* @return The node containing the key and position of the key
+*/
+static node_pos get_min_key_pos(btree * btree, bt_node * subtree) {
+ node_pos node_pos;
+ bt_node * node = subtree;
+
+ while(true) {
+ if(node == NULL) {
+ break;
+ }
+
+ if(node->leaf) {
+ node_pos.node = node;
+ node_pos.index = 0;
+ return node_pos;
+ } else {
+ node_pos.node = node;
+ node_pos.index = 0;
+ node = node->children[0];
+ }
+ }
+ return node_pos;
+}
+
+/**
+* Merge nodes n1 and n2 (case 3b from Cormen)
+* @param btree The btree
+* @param node The parent node
+* @param index of the child
+* @param pos left or right
+* @return none
+*/
+static bt_node * merge_siblings(btree * btree, bt_node * parent, unsigned int index ,
+ position_t pos) {
+ unsigned int i,j;
+ bt_node * new_node;
+ bt_node * n1, * n2;
+
+ if (index == (parent->nr_active)) {
+ index--;
+ n1 = parent->children[parent->nr_active - 1];
+ n2 = parent->children[parent->nr_active];
+ } else {
+ n1 = parent->children[index];
+ n2 = parent->children[index + 1];
+ }
+
+ //Merge the current node with the left node
+ new_node = allocate_btree_node(btree->order);
+ new_node->level = n1->level;
+ new_node->leaf = n1->leaf;
+
+ for(j=0;j<btree->order - 1; j++) {
+ new_node->key_vals[j] = n1->key_vals[j];
+ new_node->children[j] = n1->children[j];
+ }
+
+ new_node->key_vals[btree->order - 1] = parent->key_vals[index];
+ new_node->children[btree->order - 1] = n1->children[btree->order - 1];
+
+ for(j=0;j<btree->order - 1; j++) {
+ new_node->key_vals[j + btree->order] = n2->key_vals[j];
+ new_node->children[j + btree->order] = n2->children[j];
+ }
+ new_node->children[2*btree->order - 1] = n2->children[btree->order - 1];
+
+ parent->children[index] = new_node;
+
+ for(j = index;j<parent->nr_active;j++) {
+ parent->key_vals[j] = parent->key_vals[j + 1];
+ parent->children[j + 1] = parent->children[j + 2];
+ }
+
+ new_node->nr_active = n1->nr_active + n2->nr_active + 1;
+ parent->nr_active--;
+
+ for(i=parent->nr_active;i < 2*btree->order - 1; i++) {
+ parent->key_vals[i] = NULL;
+ }
+
+ free_btree_node(n1);
+ free_btree_node(n2);
+
+ if (parent->nr_active == 0 && btree->root == parent) {
+ free_btree_node(parent);
+ btree->root = new_node;
+ if(new_node->level)
+ new_node->leaf = false;
+ else
+ new_node->leaf = true;
+ }
+
+ return new_node;
+}
+
+/**
+* Move the key from node to another
+* @param btree The B-Tree
+* @param node The parent node
+* @param index of the key to be moved done
+* @param pos the position of the child to receive the key
+* @return none
+*/
+static void move_key(btree * btree, bt_node * node, unsigned int index, position_t pos) {
+ bt_node * lchild;
+ bt_node * rchild;
+ unsigned int i;
+
+ if(pos == right) {
+ index--;
+ }
+ lchild = node->children[index];
+ rchild = node->children[index + 1];
+
+ // Move the key from the parent to the left child
+ if(pos == left) {
+ lchild->key_vals[lchild->nr_active] = node->key_vals[index];
+ lchild->children[lchild->nr_active + 1] = rchild->children[0];
+ rchild->children[0] = NULL;
+ lchild->nr_active++;
+
+ node->key_vals[index] = rchild->key_vals[0];
+ rchild->key_vals[0] = NULL;
+
+ for(i=0;i<rchild->nr_active - 1;i++) {
+ rchild->key_vals[i] = rchild->key_vals[i + 1];
+ rchild->children[i] = rchild->children[i + 1];
+ }
+ rchild->children[rchild->nr_active - 1] =
+ rchild->children[rchild->nr_active];
+ rchild->nr_active--;
+ } else {
+ // Move the key from the parent to the right child
+ for(i=rchild->nr_active;i > 0 ; i--) {
+ rchild->key_vals[i] = rchild->key_vals[i - 1];
+ rchild->children[i + 1] = rchild->children[i];
+ }
+ rchild->children[1] = rchild->children[0];
+ rchild->children[0] = NULL;
+
+ rchild->key_vals[0] = node->key_vals[index];
+
+ rchild->children[0] = lchild->children[lchild->nr_active];
+ lchild->children[lchild->nr_active] = NULL;
+
+ node->key_vals[index] = lchild->key_vals[lchild->nr_active - 1];
+ lchild->key_vals[lchild->nr_active - 1] = NULL;
+
+ lchild->nr_active--;
+ rchild->nr_active++;
+ }
+}
+
+/**
+* Merge nodes n1 and n2
+* @param n1 First node
+* @param n2 Second node
+* @return combined node
+*/
+static bt_node * merge_nodes(btree * btree, bt_node * n1, bt_key_val * kv,
+ bt_node * n2) {
+ bt_node * new_node;
+ unsigned int i;
+
+ new_node = allocate_btree_node(btree->order);
+ new_node->leaf = true;
+
+ for(i=0;i<n1->nr_active;i++) {
+ new_node->key_vals[i] = n1->key_vals[i];
+ new_node->children[i] = n1->children[i];
+ }
+ new_node->children[n1->nr_active] = n1->children[n1->nr_active];
+ new_node->key_vals[n1->nr_active] = kv;
+
+ for(i=0;i<n2->nr_active;i++) {
+ new_node->key_vals[i + n1->nr_active + 1] = n2->key_vals[i];
+ new_node->children[i + n1->nr_active + 1] = n2->children[i];
+ }
+ new_node->children[2*btree->order - 1] = n2->children[n2->nr_active];
+
+ new_node->nr_active = n1->nr_active + n2->nr_active + 1;
+ new_node->leaf = n1->leaf;
+ new_node->level = n1->level;
+
+ free_btree_node(n1);
+ free_btree_node(n2);
+
+ return new_node;
+}
+
+/**
+* Used to delete a key from the B-tree node
+* @param btree The btree
+* @param node The node from which the key is to be deleted
+* @param key The key to be deleted
+* @return 0 on success -1 on error
+*/
+
+int delete_key_from_node(btree * btree, node_pos * node_pos) {
+ unsigned int keys_max = 2*btree->order - 1;
+ unsigned int i;
+ bt_key_val * key_val;
+ bt_node * node = node_pos->node;
+
+ if(node->leaf == false) {
+ return -1;
+ }
+
+ key_val = node->key_vals[node_pos->index];
+
+ for(i=node_pos->index;i< keys_max - 1;i++) {
+ node->key_vals[i] = node->key_vals[i + 1];
+ }
+
+ if(key_val->key) {
+ mem_free(key_val->key);
+ key_val->key = NULL;
+ }
+
+ if(key_val->val) {
+ mem_free(key_val->val);
+ key_val->val = NULL;
+ }
+
+ node->nr_active--;
+
+ if(node->nr_active == 0 ) {
+ free_btree_node(node);
+ }
+ return 0;
+}
+
+/**
+* Function used to delete a node from a B-Tree
+* @param btree The B-Tree
+* @param key Key of the node to be deleted
+* @param value function to map the key to an unique integer value
+* @param compare Function used to compare the two nodes of the tree
+* @return success or failure
+*/
+
+int btree_delete_key(btree * btree,bt_node * subtree,void * key) {
+ unsigned int i,index;
+ bt_node * node = NULL, * rsibling, *lsibling;
+ bt_node * comb_node, * parent;
+ node_pos sub_node_pos;
+ node_pos node_pos;
+ bt_key_val * key_val, * new_key_val;
+ unsigned int kv = btree->value(key);
+
+ node = subtree;
+ parent = NULL;
+
+del_loop:for (i = 0;;i = 0) {
+
+ //If there are no keys simply return
+ if(!node->nr_active)
+ return -1;
+
+ // Fix the index of the key greater than or equal
+ // to the key that we would like to search
+
+ while (i < node->nr_active && kv >
+ btree->value(node->key_vals[i]->key) ) {
+ i++;
+ }
+ index = i;
+
+ // If we find such key break
+ if(i < node->nr_active &&
+ kv == btree->value(node->key_vals[i]->key)) {
+ break;
+ }
+ if(node->leaf)
+ return -1;
+
+ //Store the parent node
+ parent = node;
+
+ // To get a child node
+ node = node->children[i];
+
+ //If NULL not found
+ if (node == NULL)
+ return -1;
+
+ if (index == (parent->nr_active)) {
+ lsibling = parent->children[parent->nr_active - 1];
+ rsibling = NULL;
+ } else if (index == 0) {
+ lsibling = NULL;
+ rsibling = parent->children[1];
+ } else {
+ lsibling = parent->children[i - 1];
+ rsibling = parent->children[i + 1];
+ }
+
+ if (node->nr_active == btree->order - 1 && parent) {
+ // The current node has (t - 1) keys but the right sibling has > (t - 1)
+ // keys
+ if (rsibling && (rsibling->nr_active > btree->order - 1)) {
+ move_key(btree,parent,i,left);
+ } else
+ // The current node has (t - 1) keys but the left sibling has (t - 1)
+ // keys
+ if (lsibling && (lsibling->nr_active > btree->order - 1)) {
+ move_key(btree,parent,i,right);
+ } else
+ // Left sibling has (t - 1) keys
+ if(lsibling && (lsibling->nr_active == btree->order - 1)) {
+ node = merge_siblings(btree,parent,i,left);
+ } else
+ // Right sibling has (t - 1) keys
+ if(rsibling && (rsibling->nr_active == btree->order - 1)) {
+ node = merge_siblings(btree,parent,i,right);
+ }
+ }
+ }
+
+ //Case 1 : The node containing the key is found and is the leaf node.
+ //Also the leaf node has keys greater than the minimum required.
+ //Simply remove the key
+ if(node->leaf && (node->nr_active > btree->order - 1)) {
+ node_pos.node = node;
+ node_pos.index = index;
+ delete_key_from_node(btree,&node_pos);
+ return 0;
+ }
+
+ //If the leaf node is the root permit deletion even if the number of keys is
+ //less than (t - 1)
+ if(node->leaf && (node == btree->root)) {
+ node_pos.node = node;
+ node_pos.index = index;
+ delete_key_from_node(btree,&node_pos);
+ return 0;
+ }
+
+
+ //Case 2: The node containing the key is found and is an internal node
+ if(node->leaf == false) {
+ if(node->children[index]->nr_active > btree->order - 1 ) {
+ sub_node_pos = get_max_key_pos(btree,node->children[index]);
+ key_val = sub_node_pos.node->key_vals[sub_node_pos.index];
+
+ new_key_val = (bt_key_val *)mem_alloc(sizeof(bt_key_val));
+ copy_key_val(btree,key_val,new_key_val);
+ node->key_vals[index] = new_key_val;
+
+ btree_delete_key(btree,node->children[index],key_val->key);
+ if(sub_node_pos.node->leaf == false) {
+ print("Not leaf\n");
+ }
+ } else if ((node->children[index + 1]->nr_active > btree->order - 1) ) {
+ sub_node_pos =
+ get_min_key_pos(btree,node->children[index + 1]);
+ key_val = sub_node_pos.node->key_vals[sub_node_pos.index];
+
+ new_key_val = (bt_key_val *)mem_alloc(sizeof(bt_key_val));
+ copy_key_val(btree,key_val,new_key_val);
+ node->key_vals[index] = new_key_val;
+
+ btree_delete_key(btree,node->children[index + 1],key_val->key);
+ if(sub_node_pos.node->leaf == false) {
+ print("Not leaf\n");
+ }
+
+ } else if (
+ node->children[index]->nr_active == btree->order - 1 &&
+ node->children[index + 1]->nr_active == btree->order - 1) {
+
+ comb_node = merge_nodes(btree,node->children[index],
+ node->key_vals[index],
+ node->children[index + 1]);
+ node->children[index] = comb_node;
+
+ for(i=index + 1;i<node->nr_active;i++) {
+ node->children[i] = node->children[i + 1];
+ node->key_vals[i - 1] = node->key_vals[i];
+ }
+ node->nr_active--;
+ if (node->nr_active == 0 && btree->root == node) {
+ free_btree_node(node);
+ btree->root = comb_node;
+ }
+ node = comb_node;
+ goto del_loop;
+ }
+ }
+
+ // Case 3:
+ // In this case start from the top of the tree and continue
+ // moving to the leaf node making sure that each node that
+ // we encounter on the way has atleast 't' (order of the tree)
+ // keys
+ if(node->leaf && (node->nr_active > btree->order - 1)) {
+ node_pos.node = node;
+ node_pos.index = index;
+ delete_key_from_node(btree,&node_pos);
+ }
+
+ return 0;
+}
+
+/**
+* Function used to get the node containing the given key
+* @param btree The btree to be searched
+* @param key The the key to be searched
+* @return The node and position of the key within the node
+*/
+node_pos get_btree_node(btree * btree,void * key) {
+ node_pos kp;
+ unsigned int key_val = btree->value(key);
+ bt_node * node;
+ unsigned int i = 0;
+
+ node = btree->root;
+
+
+ for (;;i = 0) {
+
+ // Fix the index of the key greater than or equal
+ // to the key that we would like to search
+
+ while (i < node->nr_active && key_val >
+ btree->value(node->key_vals[i]->key) ) {
+ i++;
+ }
+
+ // If we find such key return the key-value pair
+ if(i < node->nr_active &&
+ key_val == btree->value(node->key_vals[i]->key)) {
+ kp.node = node;
+ kp.index = i;
+ return kp;
+ }
+
+ // If the node is leaf and if we did not find the key
+ // return NULL
+ if(node->leaf) {
+ return kp;
+ }
+
+ // To got a child node
+ node = node->children[i];
+ }
+ return kp;
+
+}
+
+/**
+* Used to destory btree
+* @param btree The B-tree
+* @return none
+*/
+void btree_destroy(btree * btree) {
+ int i = 0;
+ unsigned int current_level;
+
+ bt_node * head, * tail, * node;
+ bt_node * child, * del_node;
+
+ node = btree->root;
+ current_level = node->level;
+ head = node;
+ tail = node;
+
+ while(true) {
+ if(head == NULL) {
+ break;
+ }
+ if (head->level < current_level) {
+ current_level = head->level;
+ }
+
+ if(head->leaf == false) {
+ for(i = 0 ; i < head->nr_active + 1; i++) {
+ child = head->children[i];
+ tail->next = child;
+ tail = child;
+ child->next = NULL;
+ }
+ }
+ del_node = head;
+ head = head->next;
+ free_btree_node(del_node);
+ }
+
+}
+
+/**
+* Function used to search a node in a B-Tree
+* @param btree The B-tree to be searched
+* @param key Key of the node to be search
+* @return The key-value pair
+*/
+bt_key_val * btree_search(btree * btree,void * key) {
+
+ bt_key_val * key_val = NULL;
+ node_pos kp = get_btree_node(btree,key);
+
+ if(kp.node) {
+ key_val = kp.node->key_vals[kp.index];
+ }
+ return key_val;
+}
+
+/**
+* Used to copy key value from source to destination
+* @param src The source key value
+* @param dst The dest key value
+* @return none
+*/
+static void copy_key_val(btree * btree, bt_key_val * src, bt_key_val * dst) {
+ unsigned int keysize;
+ unsigned int datasize;
+
+ keysize = btree->key_size(src->key);
+ dst->key = (void *)mem_alloc(keysize);
+ bcopy(src->key,dst->key,keysize);
+
+ if(src->val) {
+ datasize = btree->data_size(src->val);
+ dst->val = (void *)mem_alloc(datasize);
+ bcopy(src->val,dst->val,datasize);
+ }
+
+}
+
+/**
+* Get the max key in the btree
+* @param btree The btree
+* @return The max key
+*/
+void * btree_get_max_key(btree * btree) {
+ node_pos node_pos;
+ node_pos = get_max_key_pos(btree,btree->root);
+ return node_pos.node->key_vals[node_pos.index]->key;
+}
+
+/**
+* Get the min key in the btree
+* @param btree The btree
+* @return The max key
+*/
+void * btree_get_min_key(btree * btree) {
+ node_pos node_pos;
+ node_pos = get_min_key_pos(btree,btree->root);
+ return node_pos.node->key_vals[node_pos.index]->key;
+}
+
+#ifdef DEBUG
+
+/**
+* Used to print the keys of the bt_node
+* @param node The node whose keys are to be printed
+* @return none
+*/
+
+static void print_single_node(btree *btree, bt_node * node) {
+
+ int i = 0;
+
+ print(" { ");
+ while(i < node->nr_active) {
+ print("0x%x(%d) ", btree->value(node->key_vals[i]->key),
+ node->level);
+ i++;
+ }
+ print("} (0x%x,%d) ", node,node->leaf);
+}
+
+/**
+* Function used to print the B-tree
+* @param root Root of the B-Tree
+* @param print_key Function used to print the key value
+* @return none
+*/
+
+void print_subtree(btree *btree,bt_node * node) {
+
+ int i = 0;
+ unsigned int current_level;
+
+ bt_node * head, * tail;
+ bt_node * child;
+
+ current_level = node->level;
+ head = node;
+ tail = node;
+
+ while(true) {
+ if(head == NULL) {
+ break;
+ }
+ if (head->level < current_level) {
+ current_level = head->level;
+ print("\n");
+ }
+ print_single_node(btree,head);
+
+ if(head->leaf == false) {
+ for(i = 0 ; i < head->nr_active + 1; i++) {
+ child = head->children[i];
+ tail->next = child;
+ tail = child;
+ child->next = NULL;
+ }
+ }
+ head = head->next;
+ }
+ print("\n");
+}
+
+
+#endif
Propchange: team/akshayb/ao2_containers/main/btree.c
------------------------------------------------------------------------------
svn:eol-stlye = native
Propchange: team/akshayb/ao2_containers/main/btree.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/akshayb/ao2_containers/main/btree.c
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Sun May 30 10:56:04 2010
@@ -1,0 +1,1 @@
+Akshay Bhardwaj 30 May 2010, Contains code for btree implementation
Propchange: team/akshayb/ao2_containers/main/btree.c
------------------------------------------------------------------------------
svn:mime-type = text/c
More information about the asterisk-commits
mailing list