Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

/ray/src/lib/tl/tlbtree.h

Go to the documentation of this file.
00001 /*
00002  * lib/tl/tlbtree.h 
00003  * 
00004  * Complete implementation of B-tree template. 
00005  * 
00006  * Copyright (c) 2004 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 
00007  * 
00008  * This file may be distributed and/or modified under the terms of the 
00009  * GNU General Public License version 2 as published by the Free Software 
00010  * Foundation. (See COPYING.GPL for details.)
00011  * 
00012  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00013  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00014  * 
00015  */
00016 
00017 #ifndef _TemplateLibrary_BTree_H_
00018 #define _TemplateLibrary_BTree_H_ 1
00019 
00028 #include <lib/sconfig.h>    /* MUST be first */
00029 
00030 #include <lib/salloc.h>
00031 #include <lib/tl/defop.h>
00032 
00033 #ifndef TLIB_DEBUG_BTREE
00034 #  define TLIB_DEBUG_BTREE 0
00035 #endif
00036 
00037 #if TLIB_DEBUG_BTREE
00038 // See CheckTree() for this #define: 
00039 #  define TLBT_ASSERT(x)  Assert(x)
00040 //#define TLBT_ASSERT(x)  ++nerr
00041 #endif
00042 
00078 template<typename T,typename _OP=TLDefaultOperators_CDT<T> >class TLBTree
00079 {
00080     public:
00082         struct Node
00083         {
00084             int nelem;      
00085             Node **down;    
00086             char _elem[];   
00087             // Note: For GCC we may use _elem[0]. (zero-length array)
00088             
00090             inline T &elem(int idx,TLBTree *bt)
00091                 {  return(*(T*)(_elem+idx*bt->OP.size()));  }
00093             inline T *elemP(int idx,TLBTree *bt)
00094                 {  return((T*)(_elem+idx*bt->OP.size()));  }
00095             
00104             template<typename K>bool _LBI(const K &e,int *idx,TLBTree *bt)
00105             {
00106                 // The case nelem=0 should not happen here. 
00107             #if 0
00108                 //if(!nelem)  {  *idx=0;  return(0);  }
00109                 int a=0,b=nelem-1;
00110                 if(bt->OP.gt(elem(0,bt),e))  {  *idx=0;  return(0);  }
00111                 if(bt->OP.lt(elem(b,bt),e))  {  *idx=nelem;  return(0);  }
00112                 while(b-a>1)
00113                 {  int m=(a+b)/2;  bt->OP.lt(elem(m,bt),e) ? a=m : b=m;  }
00114                 if(bt->OP.eq(elem(a,bt),e))  {  *idx=a;  return(1);  }
00115                 *idx=b;  return(bt->OP.eq(elem(b,bt),e));
00116             #else
00117                 /*if(nelem<=1) {  if(!nelem)  {  *idx=0;  return(0);  }
00118                     if(bt->OP.lt(elem(0,bt),e))  {  *idx=1;  return(0);  }
00119                     *idx=0;  return(bt->OP.eq(elem(0,bt),e));  }*/
00120                 int a=0,b=nelem-1;
00121                 while(b-a>1)
00122                 {  int m=(a+b)/2;  bt->OP.lt(elem(m,bt),e) ? a=m : b=m;  }
00123                 if(!a && bt->OP.gt(elem(0,bt),e))  {  *idx=0;  return(0);  }
00124                 if(b==nelem-1 && bt->OP.lt(elem(b,bt),e))
00125                     {  *idx=nelem;  return(0);  }
00126                 if(bt->OP.eq(elem(a,bt),e))  {  *idx=a;  return(1);  }
00127                 *idx=b;  return(b && bt->OP.eq(elem(b,bt),e));
00128             #endif
00129             }
00130             
00140             inline void _INSLeafNS(int idx,const T &e,TLBTree *bt)
00141             {
00142                 if(idx==nelem)  {  bt->OP.ini(elemP(nelem++,bt),e);  return;  }
00143                 int i=nelem-1;  bt->OP.ini(elemP(nelem,bt),elem(i,bt));
00144                 for(; i>idx; i--)  bt->OP.ass(elem(i,bt),elem(i-1,bt));
00145                 bt->OP.ass(elem(idx,bt),e);  ++nelem;
00146             }
00147             
00158             inline void _INS_NS(int idx,const T &e,Node *chld,TLBTree *bt)
00159             {
00160                 down[nelem+1]=down[nelem];
00161                 if(idx==nelem)
00162                 {  bt->OP.ini(elemP(nelem++,bt),e);  down[idx]=chld;  return;  }
00163                 int i=nelem-1;
00164                 bt->OP.ini(elemP(nelem,bt),elem(i,bt));  down[nelem]=down[i];
00165                 for(; i>idx; i--)
00166                 {  bt->OP.ass(elem(i,bt),elem(i-1,bt));  down[i]=down[i-1];  }
00167                 bt->OP.ass(elem(idx,bt),e);  down[idx]=chld;  ++nelem;
00168             }
00169             
00171             inline void _DELLeaf(int idx,TLBTree *bt)
00172             {
00173                 --nelem;
00174                 for(int i=idx; i<nelem; i++)
00175                     bt->OP.ass(elem(i,bt),elem(i+1,bt));
00176                 bt->OP.clr(elemP(nelem,bt));
00177             }
00178             
00181             inline void _DEL_L(int idx,TLBTree *bt)
00182             {
00183                 --nelem;
00184                 for(int i=idx; ; i++)
00185                 {
00186                     down[i]=down[i+1];  if(i>=nelem)  break;
00187                     bt->OP.ass(elem(i,bt),elem(i+1,bt));
00188                 }
00189                 bt->OP.clr(elemP(nelem,bt));  down[nelem+1]=NULL;
00190             }
00193             inline void _DEL_R(int idx,TLBTree *bt)
00194             {
00195                 --nelem;
00196                 for(int i=idx; i<nelem; )
00197                 {
00198                     bt->OP.ass(elem(i,bt),elem(i+1,bt));  ++i;
00199                     down[i]=down[i+1];
00200                 }
00201                 bt->OP.clr(elemP(nelem,bt));  down[nelem+1]=NULL;
00202             }
00203             
00204             inline Node() : nelem(0),down(NULL) {}
00205             inline ~Node()
00206                 {  /*down=OP.free(down);must be done by higher level*/  }
00207         };
00208         
00209     private:
00210         // The actual tree data fields: 
00211         int m;   
00212         Node *root;   
00213         T tmp;   
00214         
00215     public:
00216         // These are the operators... normally, the default OPs 
00217         // will not occupy any place (i.e. 1byte compiler dummy or so). 
00218         _OP OP;
00219         
00220     private:
00221         // Some statistics: (Not implemented.)
00222         //size_t n_elems;   // Total number of elements in the tree. 
00223         //size_t n_nodes;   // Total number of nodes in the tree. 
00224         
00230         Node *_AllocLeaf()
00231         {
00232             void *place=OP.alloc( sizeof(Node) + OP.size()*(m+m) );
00233             return(new(place) Node());
00234         }
00236         Node *_AllocNonLeaf()
00237         {
00238             Node *n=_AllocLeaf();
00239             n->down=(Node**)OP.alloc(sizeof(Node*)*(m+m+1));
00240             for(int i=0,e=m+m; i<=e; i++)  n->down[i]=NULL;
00241             return(n);
00242         }
00249         inline Node *_FreeNode(Node *n)
00250             {  OP.free(n->down); n->Node::~Node(); OP.free(n); return(NULL);  }
00251         
00253         void _DeleteTree(Node *tn)
00254         {
00255             if(!tn)  return;
00256             if(tn->down) for(int i=0; i<=tn->nelem; i++)
00257                 _DeleteTree(tn->down[i]);
00258             for(int i=0; i<tn->nelem; i++)  OP.clr(&tn->elem(i,this));
00259             _FreeNode(tn);
00260         }
00261         
00263         template<typename K>T *_Find(const K &key,Node *tn)
00264         {
00265             for(int idx; ; tn=tn->down[idx])
00266             {
00267                 if(tn->_LBI(key,&idx,this))  return(&tn->elem(idx,this));
00268                 if(!tn->down)  break;
00269             }
00270             return(NULL);
00271         }
00272         
00274         Node *_FindSmallestLeaf(Node *n)
00275             {  while(n->down) n=n->down[0];  return(n);  }
00277         Node *_FindLargestLeaf(Node *n)
00278             {  while(n->down) n=n->down[n->nelem];  return(n);  }
00280         T *_FindSmallest(Node *n)
00281             {  return(&_FindSmallestLeaf(n)->elem(0,this));  }
00282         T *_FindLargest(Node *n)
00283             {  n=_FindLargestLeaf(n);  return(&n->elem(n->nelem-1,this));  }
00284         
00286         template<typename K>T *_FindNeighbours(const K &key,Node *tn,
00287             T **p,T **n)
00288         {
00289             int idx;
00290             if(tn->_LBI(key,&idx,this))
00291             {  // Exact match. 
00292                 if(p)  if(tn->down)  *p=_FindLargest(tn->down[idx]);
00293                        else if(idx>0)  *p=&tn->elem(idx-1,this);
00294                 if(n)  if(tn->down)  *n=_FindSmallest(tn->down[idx+1]);
00295                        else if(idx+1<tn->nelem)  *n=&tn->elem(idx+1,this);
00296                 return(&tn->elem(idx,this));
00297             }
00298             T *rv = tn->down ? _FindNeighbours(key,tn->down[idx],p,n) : NULL;
00299             if(p && !*p && idx>0)  *p=&tn->elem(idx-1,this);
00300             if(n && !*n && idx<tn->nelem)  *n=&tn->elem(idx,this);
00301             return(rv);
00302         }
00303         
00311         int _Store(Node *tn,const T &e,Node **split,bool allow_update,
00312             T *oldval)
00313         {
00314             int idx;
00315             if(tn->_LBI(e,&idx,this))
00316             {
00317                 if(oldval) OP.ass(*oldval,tn->elem(idx,this));
00318                 if(allow_update) OP.ass(tn->elem(idx,this),e);
00319                 return(1);
00320             }
00321             if(!tn->down)
00322             {
00323                 if(tn->nelem<m+m)  { tn->_INSLeafNS(idx,e,this); return(0); }
00324                 // Split leaf node: 
00325                 Node *l=_AllocLeaf();
00326                 int d=0,s=0;
00327                 // left...
00328                 while(d<m)  OP.ini(&l->elem(d++,this),
00329                                    s==idx ? (idx=-1,e) : tn->elem(s++,this));
00330                 // ...middle...
00331                 if(s==idx)  OP.ini(&tmp,(idx=-1,e));
00332                 else  {  OP.ini(&tmp,tn->elem(s,this));
00333                          if(s>=m) OP.clr(&tn->elem(s,this));  ++s;  }
00334                 // ...right
00335                 for(d=0; d<m; )
00336                     if(s==idx)  OP.ass(tn->elem(d++,this),(idx=-1,e));
00337                     else  {  OP.ass(tn->elem(d++,this),tn->elem(s,this));
00338                              OP.clr(&tn->elem(s++,this));  }
00339                 tn->nelem=m;  l->nelem=m;  *split=l;  return(3);
00340             }
00341             Node *isplit;
00342             int rv=_Store(tn->down[idx],e,&isplit,allow_update,oldval);
00343             if(rv!=3)  return(rv);
00344             if(tn->nelem<m+m)
00345             {  tn->_INS_NS(idx,tmp,isplit,this);  OP.clr(&tmp);  return(0);  }
00346             // Split non-leaf node: 
00347             T itmp(tmp);  OP.clr(&tmp);
00348             Node *l=_AllocNonLeaf();
00349             int d=0,s=0;
00350             // left...
00351             while(d<m)
00352                 if(s==idx)  {  OP.ini(&l->elem(d,this),(idx=-1,itmp));
00353                                (l->down[d++]=isplit);  }
00354                 else  {  OP.ini(&l->elem(d,this),tn->elem(s,this));
00355                          (l->down[d++]=tn->down[s++]);  }
00356             // ...middle...
00357             if(s==idx)
00358             {
00359                 (l->down[d]=isplit);
00360                 OP.ini(&tmp,(idx=-1,itmp));
00361             } else {
00362                 OP.ini(&tmp,tn->elem(s,this));
00363                 if(s>=m) OP.clr(&tn->elem(s,this));
00364                 (l->down[d]=tn->down[s++]);
00365             }
00366             // ...right
00367             for(d=0; d<m; )
00368                 if(s==idx)
00369                 {  OP.ass(tn->elem(d,this),(idx=-1,itmp));
00370                    tn->down[d++]=isplit;  }
00371                 else
00372                 {  OP.ass(tn->elem(d,this),tn->elem(s,this));
00373                    OP.clr(&tn->elem(s,this));
00374                    tn->down[d++]=tn->down[s];  tn->down[s++]=NULL;  }
00375             tn->down[d]=tn->down[s];  tn->down[s]=NULL;
00376             tn->nelem=m;  l->nelem=m;  *split=l;  return(3);
00377         }
00378         
00386         bool _HandleUnderflow(Node *tn,int idx)
00387         {
00388             Node *l,*r;
00389             if(idx<tn->nelem)
00390             {
00391                 l=tn->down[idx]; r=tn->down[idx+1];
00392                 if(r->nelem>m)  // Transfer from right brother?
00393                 {
00394                     OP.ini(&l->elem(l->nelem++,this),tn->elem(idx,this));
00395                     OP.ass(tn->elem(idx,this),r->elem(0,this));
00396                     if(l->down)
00397                     {  (l->down[l->nelem]=r->down[0]);
00398                        r->_DEL_L(0,this);  }
00399                     else  r->_DELLeaf(0,this);
00400                     return(0);
00401                 }
00402             } else {
00403                 // Check left brother (since there is no right one). 
00404                 l=tn->down[idx-1]; r=tn->down[idx];
00405                 if(l->nelem>m)  // Transfer from left brother?
00406                 {
00407                     // For m==1, I'd need an extra case for r->nelem==0 here. 
00408                     if(!r->down)  r->_INSLeafNS(0,tn->elem(idx-1,this),this);
00409                     else { r->_INS_NS(0,tn->elem(idx-1,this),l->down[l->nelem],
00410                                       this);  }
00411                     OP.ass(tn->elem(idx-1,this),l->elem(l->nelem-1,this));
00412                     if(l->down)  l->_DEL_R(l->nelem-1,this); 
00413                     else  l->_DELLeaf(l->nelem-1,this);
00414                     return(0);
00415                 }  --idx;  // <-- important...
00416             }
00417             // Merge left and right brother: 
00418             int d=l->nelem;
00419             OP.ini(&l->elem(d++,this),tn->elem(idx,this));
00420             tn->_DEL_R(idx,this);
00421             for(int i=0; ; i++)
00422             {
00423                 if(r->down)  (l->down[d]=r->down[i]);
00424                 if(i>=r->nelem)  break;
00425                 OP.ini(&l->elem(d++,this),r->elem(i,this));
00426                 OP.clr(&r->elem(i,this));
00427             }
00428             l->nelem=d;  _FreeNode(r);  return(tn->nelem<m);
00429         }
00430         
00432         inline void _HandleRootUnderflow()
00433         {
00434             if(root->nelem)  return;
00435             if(!root->down)  {  root=_FreeNode(root);  return;  }
00436             Node *oroot=root;  root=root->down[0];  _FreeNode(oroot);  
00437         }
00438         
00447         bool _MoveSmallest(Node *tn,T *ent)
00448         {
00449             if(!tn->down)  {  OP.ass(*ent,tn->elem(0,this));
00450                               tn->_DELLeaf(0,this);  return(tn->nelem<m);  }
00451             if(_MoveSmallest(tn->down[0],ent))  // <- Underflow in tn->down[0]. 
00452                 return(_HandleUnderflow(tn,0));
00453             return(0);
00454         }
00455         
00464         template<typename K>int _Remove(Node *tn,const K &key,T *e)
00465         {
00466             int idx;
00467             if(tn->_LBI(key,&idx,this))
00468             {   // Found it. 
00469                 if(e)  OP.ass(*e,tn->elem(idx,this));
00470                 if(!tn->down)
00471                 {  tn->_DELLeaf(idx,this);  return(tn->nelem<m ? 2 : 0);  }
00472                 if(_MoveSmallest(tn->down[idx+1],&tn->elem(idx,this)) && 
00473                     _HandleUnderflow(tn,idx+1))  return(2);
00474                 return(0);
00475             }
00476             if(!tn->down)  return(1);
00477             int rv=_Remove(tn->down[idx],key,e);  if(rv!=2)  return(rv);
00478             return(_HandleUnderflow(tn,idx) ? 2 : 0);
00479         }
00480         
00482         int _RemoveSL(Node *tn,int sl,T *e)
00483         {
00484             if(tn->down)
00485             {
00486                 int idx = sl<0 ? 0 : tn->nelem;
00487                 int rv=_RemoveSL(tn->down[idx],sl,e);  if(rv!=2) return(rv);
00488                 return(_HandleUnderflow(tn,idx) ? 2 : 0);
00489             }
00490             int idx = sl<0 ? 0 : (tn->nelem-1);
00491             if(e)  OP.ass(*e,tn->elem(idx,this));
00492             tn->_DELLeaf(idx,this);  return(tn->nelem<m ? 2 : 0);
00493         }
00494         
00496         int _DoRemoveSL(int sl,T *e)
00497         {
00498             if(!root)  return(1);
00499             int rv=_RemoveSL(root,sl,e);  if(rv!=2)  return(rv);
00500             _HandleRootUnderflow();  return(0);
00501         }
00502         
00503         #if TLIB_DEBUG_BTREE
00504 
00505         int _CheckTree(Node *tn)
00506         {
00507             int nerr=0;
00508             // Make sure element number is right: 
00509             TLBT_ASSERT(tn->nelem<=m+m);
00510             TLBT_ASSERT(tn==root || tn->nelem>=m);
00511             // Make sure elements are sorted in ascenting order: 
00512             for(int i=1; i<tn->nelem; i++)
00513                 TLBT_ASSERT(OP.lt(tn->elem(i-1,this),tn->elem(i,this)));
00514             if(tn->down) for(int i=0,e=m+m; i<=e; i++)
00515             {
00516                 Node *d=tn->down[i];
00517                 if(i>tn->nelem)
00518                 {   /*fprintf(stderr,"(%d,%d,%d,%p=%d)",i,tn->nelem,tn->elem(0,this),d,d ? d->elem(0,this) : 0);*/
00519                     TLBT_ASSERT(!d);  continue;  }
00520                 TLBT_ASSERT(d);
00521                 /*fprintf(stderr,"(%d,up=%p=%d,shall=%p=%d)",d->elem(0,this),d->up,d->up->elem(0,this),tn,tn->elem(0,this));*/
00522                 if(i>0) TLBT_ASSERT(OP.lt(tn->elem(i-1,this),d->elem(0,this)));
00523                 nerr+=_CheckTree(tn->down[i]);
00524                 if(i<tn->nelem)
00525                     TLBT_ASSERT(OP.lt(d->elem(d->nelem-1,this),tn->elem(i,this)));
00526             }
00527             return(nerr);
00528         }
00529         #endif  /* TLIB_DEBUG_BTREE */
00530         
00532         size_t _CountElements(Node *tn) const
00533         {
00534             size_t c=tn->nelem;
00535             if(tn->down) for(int i=0; i<=tn->nelem; i++)
00536                 c+=_CountElements(tn->down[i]);
00537             return(c);
00538         }
00539         
00541         size_t _CountNodes(Node *tn) const
00542         {
00543             size_t c=1;  // <-- this node
00544             if(tn->down) for(int i=0; i<=tn->nelem; i++)
00545                 c+=_CountNodes(tn->down[i]);
00546             return(c);
00547         }
00548         
00550         TLBTree(const TLBTree &);
00551         void operator=(const TLBTree &);
00552     public:
00561         TLBTree(int _m=16,const _OP &op=_OP()) : 
00562             m(_m<2 ? 2 : _m),root(NULL),tmp(),OP(op) {}
00564         ~TLBTree()  {  _DeleteTree(root); root=NULL;  /*No: clr(&tmp);*/  }
00565         
00567         inline void clear()
00568             {  _DeleteTree(root);  root=NULL;  }
00569         
00571         inline bool IsEmpty() const
00572             {  return(!root);  }
00573         
00579         inline size_t CountElements() const
00580             {  return(root ? _CountElements(root) : 0);  }
00581         
00583         inline size_t CountNodes() const
00584             {  return(root ? _CountNodes(root) : 0);  }
00585         
00589         inline size_t GetNodeSize() const
00590             {  return(sizeof(Node)+OP.size()*(m+m));  }
00591         
00601         template<typename K>inline T *search(const K &key)
00602             {  return(root ? _Find(key,root) : NULL);  }
00603         
00614         template<typename K>T *SearchNeighbours(const K &key,T **prev,T **next)
00615         {
00616             if(prev) *prev=NULL;  if(next) *next=NULL;  // Important for recursion. 
00617             return(root ? _FindNeighbours(key,root,prev,next) : NULL);
00618         }
00619         
00625         inline T *GetSmallest()
00626             {  return(root ? _FindSmallest(root) : NULL);  }
00627         inline T *GetLargest()
00628             {  return(root ? _FindLargest(root) : NULL);  }
00629         
00648         int store(const T &e,bool allow_update,T *oldval=NULL)
00649         {
00650             if(!root)
00651             {
00652                 root=_AllocLeaf();
00653                 OP.ini(&root->elem(0,this),e);  root->nelem=1;  return(0);
00654             }
00655             Node *split;  int rv=_Store(root,e,&split,allow_update,oldval);
00656             if(rv!=3) return(rv);
00657             // Split root. 
00658             Node *nroot=_AllocNonLeaf();
00659             nroot->down[0]=split;
00660             nroot->down[1]=root;
00661             OP.ini(&nroot->elem(0,this),tmp);  OP.clr(&tmp);
00662             nroot->nelem=1;  root=nroot;  return(0);
00663         }
00664         
00677         template<typename K>int remove(const K &key,T *e=NULL)
00678         {
00679             if(!root)  return(1);
00680             int rv=_Remove(root,key,e);  if(rv!=2)  return(rv);
00681             _HandleRootUnderflow();  return(0);
00682         }
00683         
00694         inline int RemoveSmallest(T *e=NULL)
00695             {  return(_DoRemoveSL(-1,e));  }
00696         inline int RemoveLargest(T *e=NULL)
00697             {  return(_DoRemoveSL(+1,e));  }
00698         
00699         #if TLIB_DEBUG_BTREE
00702         void DumpTree(FILE *f,Node *tn=NULL,int lvl=0)
00703         {
00704             if(!tn && !lvl)  tn=root;  if(!tn)  return;
00705             for(int i=0; i<tn->nelem; i++)
00706             {
00707                 if(tn->down) DumpTree(f,tn->down[i],lvl+1);
00708                 for(int j=0; j<lvl; j++)  fprintf(f,"  ");
00709                 fprintf(f,"%d\n",tn->elem(i,this));
00710             }
00711             if(tn->down) DumpTree(f,tn->down[tn->nelem],lvl+1);
00712         }
00713         
00716         int CheckTree()
00717         {
00718             if(!root)  return(0);
00719             int nerr=0;
00720             return(nerr+_CheckTree(root));
00721         }
00722         #endif  /* TLIB_DEBUG_BTREE */
00723 };
00724 
00725 #if TLIB_DEBUG_BTREE
00726 #  undef TLBT_ASSERT
00727 #endif
00728 
00729 #endif  /* _TemplateLibrary_BTree_H_ */

Generated on Sat Feb 19 22:33:46 2005 for Ray by doxygen 1.3.5