Drizzled Public API Documentation

tree.cc
00001 /* Copyright (C) 2000 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 /*
00017   Code for handling red-black (balanced) binary trees.
00018   key in tree is allocated according to following:
00019 
00020   1) If size < 0 then tree will not allocate keys and only a pointer to
00021      each key is saved in tree.
00022      compare and search functions uses and returns key-pointer
00023 
00024   2) If size == 0 then there are two options:
00025        - key_size != 0 to tree_insert: The key will be stored in the tree.
00026        - key_size == 0 to tree_insert:  A pointer to the key is stored.
00027      compare and search functions uses and returns key-pointer.
00028 
00029   3) if key_size is given to init_tree then each node will continue the
00030      key and calls to insert_key may increase length of key.
00031      if key_size > sizeof(pointer) and key_size is a multiple of 8 (double
00032      align) then key will be put on a 8 aligned address. Else
00033      the key will be on address (element+1). This is transparent for user
00034      compare and search functions uses a pointer to given key-argument.
00035 
00036   - If you use a free function for tree-elements and you are freeing
00037     the element itself, you should use key_size = 0 to init_tree and
00038     tree_search
00039 
00040   The actual key in TREE_ELEMENT is saved as a pointer or after the
00041   TREE_ELEMENT struct.
00042   If one uses only pointers in tree one can use tree_set_pointer() to
00043   change address of data.
00044 
00045   Implemented by monty.
00046 */
00047 
00048 /*
00049   NOTE:
00050   tree->compare function should be ALWAYS called as
00051     (*compare)(custom_arg, element_key(element), key)
00052   and NOT the other way around, as
00053     (*compare)(custom_arg, key, element_key(element))
00054 */
00055 
00056 #include <config.h>
00057 
00058 #include <drizzled/tree.h>
00059 #include <drizzled/internal/my_sys.h>
00060 #include <drizzled/internal/m_string.h>
00061 
00062 #define BLACK   1
00063 #define RED   0
00064 #define DEFAULT_ALLOC_SIZE 8192
00065 #define DEFAULT_ALIGN_SIZE 8192
00066 
00067 
00068 namespace drizzled
00069 {
00070 
00075 void Tree::init_tree(size_t default_alloc_size, uint32_t mem_limit,
00076                uint32_t size, qsort_cmp2 compare_callback, bool free_with_tree,
00077          tree_element_free free_callback, void *caller_arg)
00078 {
00079   if (default_alloc_size < DEFAULT_ALLOC_SIZE)
00080     default_alloc_size= DEFAULT_ALLOC_SIZE;
00081   default_alloc_size= MY_ALIGN(default_alloc_size, DEFAULT_ALIGN_SIZE);
00082   memset(&this->null_element, 0, sizeof(this->null_element));
00083   root= &this->null_element;
00084   compare= compare_callback;
00085   size_of_element= size > 0 ? (uint32_t) size : 0;
00086   memory_limit= mem_limit;
00087   free= free_callback;
00088   allocated= 0;
00089   elements_in_tree= 0;
00090   custom_arg = caller_arg;
00091   null_element.colour= BLACK;
00092   null_element.left=this->null_element.right= 0;
00093   flag= 0;
00094   if (!free_callback &&
00095       (size <= sizeof(void*) || ((uint32_t) size & (sizeof(void*)-1))))
00096   {
00097     /*
00098       We know that the data doesn't have to be aligned (like if the key
00099       contains a double), so we can store the data combined with the
00100       Tree_Element.
00101     */
00102     offset_to_key= sizeof(Tree_Element); /* Put key after element */
00103     /* Fix allocation size so that we don't lose any memory */
00104     default_alloc_size/= (sizeof(Tree_Element)+size);
00105     if (!default_alloc_size)
00106       default_alloc_size= 1;
00107     default_alloc_size*= (sizeof(Tree_Element)+size);
00108   }
00109   else
00110   {
00111     offset_to_key= 0;   /* use key through pointer */
00112     size_of_element+= sizeof(void*);
00113   }
00114   if (! (with_delete= free_with_tree))
00115   {
00116     mem_root.init(default_alloc_size);
00117     mem_root.min_malloc= (sizeof(Tree_Element)+size_of_element);
00118   }
00119 }
00120 
00121 void Tree::delete_tree()
00122 {
00123   free_tree(MYF(0)); /* free() mem_root if applicable */
00124 }
00125 
00126 void Tree::reset_tree()
00127 {
00128   /* do not free mem_root, just mark blocks as free */
00129   free_tree(MYF(memory::MARK_BLOCKS_FREE));
00130 }
00131 
00132 Tree_Element* Tree::tree_insert(void* key, uint32_t key_size, void* caller_arg)
00133 {
00134   int cmp;
00135   Tree_Element *element,***parent;
00136 
00137   parent= this->parents;
00138   *parent = &this->root; element= this->root;
00139   for (;;)
00140   {
00141     if (element == &this->null_element ||
00142   (cmp = (*compare)(caller_arg, element_key(element), key)) == 0)
00143       break;
00144     if (cmp < 0)
00145     {
00146       *++parent= &element->right; element= element->right;
00147     }
00148     else
00149     {
00150       *++parent = &element->left; element= element->left;
00151     }
00152   }
00153   if (element == &this->null_element)
00154   {
00155     size_t alloc_size= sizeof(Tree_Element)+key_size+this->size_of_element;
00156     this->allocated+= alloc_size;
00157 
00158     if (this->memory_limit && this->elements_in_tree
00159                            && this->allocated > this->memory_limit)
00160     {
00161       reset_tree();
00162       return tree_insert(key, key_size, caller_arg);
00163     }
00164 
00165     key_size+= this->size_of_element;
00166     if (this->with_delete)
00167       element= (Tree_Element *) malloc(alloc_size);
00168     else
00169       element= (Tree_Element *) this->mem_root.alloc(alloc_size);
00170     **parent= element;
00171     element->left= element->right= &this->null_element;
00172     if (!this->offset_to_key)
00173     {
00174       if (key_size == sizeof(void*))     /* no length, save pointer */
00175   *((void**) (element+1))= key;
00176       else
00177       {
00178   *((void**) (element+1))= (void*) ((void **) (element+1)+1);
00179   memcpy(*((void **) (element+1)),key, key_size - sizeof(void*));
00180       }
00181     }
00182     else
00183       memcpy((unsigned char*) element + this->offset_to_key, key, key_size);
00184     element->count= 1;      /* May give warning in purify */
00185     this->elements_in_tree++;
00186     rb_insert(parent,element);  /* rebalance tree */
00187   }
00188   else
00189   {
00190     if (this->flag & TREE_NO_DUPS)
00191       return(NULL);
00192     element->count++;
00193     /* Avoid a wrap over of the count. */
00194     if (! element->count)
00195       element->count--;
00196   }
00197 
00198   return element;
00199 }
00200 
00201 int Tree::tree_walk(tree_walk_action action, void *argument, TREE_WALK visit)
00202 {
00203     switch (visit) {
00204     case left_root_right:
00205       return tree_walk_left_root_right(root,action,argument);
00206     case right_root_left:
00207       return tree_walk_right_root_left(root,action,argument);
00208   }
00209 
00210   return 0;     /* Keep gcc happy */
00211 }
00212 
00217 void Tree::free_tree(myf free_flags)
00218 {
00219   if (root)       /* If initialized */
00220   {
00221     if (with_delete)
00222       delete_tree_element(root);
00223     else
00224     {
00225       if (free)
00226       {
00227         if (memory_limit)
00228           (*free)(NULL, free_init, custom_arg);
00229         delete_tree_element(root);
00230         if (memory_limit)
00231           (*free)(NULL, free_end, custom_arg);
00232       }
00233       mem_root.free_root(free_flags);
00234     }
00235   }
00236   root= &null_element;
00237   elements_in_tree= 0;
00238   allocated= 0;
00239 }
00240 
00241 void* Tree::element_key(Tree_Element* element)
00242 {
00243   return offset_to_key ? (void*)((unsigned char*) element + offset_to_key)
00244              : *((void**)(element + 1));
00245 }
00246 
00247 void Tree::delete_tree_element(Tree_Element *element)
00248 {
00249   if (element != &null_element)
00250   {
00251     delete_tree_element(element->left);
00252     if (free)
00253       (*free)(element_key(element), free_free, custom_arg);
00254     delete_tree_element(element->right);
00255     if (with_delete)
00256       delete element;
00257   }
00258 }
00259 
00260 int Tree::tree_walk_left_root_right(Tree_Element *element, tree_walk_action action, void *argument)
00261 {
00262   int error;
00263   if (element->left)        /* Not null_element */
00264   {
00265     if ((error=tree_walk_left_root_right(element->left,action,
00266             argument)) == 0 &&
00267   (error=(*action)(element_key(element), element->count, argument)) == 0)
00268       error=tree_walk_left_root_right(element->right,action,argument);
00269     return error;
00270   }
00271 
00272   return 0;
00273 }
00274 
00275 int Tree::tree_walk_right_root_left(Tree_Element *element, tree_walk_action action, void *argument)
00276 {
00277   int error;
00278   if (element->right)       /* Not null_element */
00279   {
00280     if ((error=tree_walk_right_root_left(element->right,action,
00281             argument)) == 0 &&
00282   (error=(*action)(element_key(element),
00283         element->count,
00284         argument)) == 0)
00285      error=tree_walk_right_root_left(element->left,action,argument);
00286     return error;
00287   }
00288 
00289   return 0;
00290 }
00291 
00292 void Tree::left_rotate(Tree_Element **parent, Tree_Element *element)
00293 {
00294   Tree_Element *y;
00295 
00296   y= element->right;
00297   element->right= y->left;
00298   parent[0]= y;
00299   y->left= element;
00300 }
00301 
00302 void Tree::right_rotate(Tree_Element **parent, Tree_Element *element)
00303 {
00304   Tree_Element *x;
00305 
00306   x= element->left;
00307   element->left= x->right;
00308   parent[0]= x;
00309   x->right= element;
00310 }
00311 
00312 void Tree::rb_insert(Tree_Element ***parent, Tree_Element *element)
00313 {
00314   Tree_Element *y,*par,*par2;
00315 
00316   element->colour=RED;
00317   while (element != root && (par=parent[-1][0])->colour == RED)
00318   {
00319     if (par == (par2=parent[-2][0])->left)
00320     {
00321       y= par2->right;
00322       if (y->colour == RED)
00323       {
00324   par->colour= BLACK;
00325   y->colour= BLACK;
00326   element= par2;
00327   parent-= 2;
00328   element->colour= RED;   /* And the loop continues */
00329       }
00330       else
00331       {
00332   if (element == par->right)
00333   {
00334     left_rotate(parent[-1],par);
00335     par= element;     /* element is now parent to old element */
00336   }
00337   par->colour= BLACK;
00338   par2->colour= RED;
00339   right_rotate(parent[-2],par2);
00340   break;
00341       }
00342     }
00343     else
00344     {
00345       y= par2->left;
00346       if (y->colour == RED)
00347       {
00348   par->colour= BLACK;
00349   y->colour= BLACK;
00350   element= par2;
00351   parent-= 2;
00352   element->colour= RED;   /* And the loop continues */
00353       }
00354       else
00355       {
00356   if (element == par->left)
00357   {
00358     right_rotate(parent[-1],par);
00359     par= element;
00360   }
00361   par->colour= BLACK;
00362   par2->colour= RED;
00363   left_rotate(parent[-2],par2);
00364   break;
00365       }
00366     }
00367   }
00368   root->colour=BLACK;
00369 }
00370 
00371 } /* namespace drizzled */