Graphviz 2.29.20120208.0545
lib/cdt/dttree.c
Go to the documentation of this file.
00001 #include        "dthdr.h"
00002 
00003 /*      Ordered set/multiset
00004 **      dt:     dictionary being searched
00005 **      obj:    the object to look for.
00006 **      type:   search type.
00007 **
00008 **      Written by Kiem-Phong Vo (5/25/96)
00009 */
00010 
00011 #if __STD_C
00012 static Void_t* dttree(Dt_t* dt, Void_t* obj, int type)
00013 #else
00014 static Void_t* dttree(dt,obj,type)
00015 Dt_t*           dt;
00016 Void_t*         obj;
00017 int             type;
00018 #endif
00019 {
00020         Dtlink_t        *root, *t;
00021         int             cmp, lk, sz, ky;
00022         Void_t          *o, *k, *key;
00023         Dtlink_t        *l, *r, *me, link;
00024         int             n, minp, turn[DT_MINP];
00025         Dtcompar_f      cmpf;
00026         Dtdisc_t*       disc;
00027 
00028         UNFLATTEN(dt);
00029         disc = dt->disc; _DTDSC(disc,ky,sz,lk,cmpf);
00030         dt->type &= ~DT_FOUND;
00031 
00032         root = dt->data->here;
00033         if(!obj)
00034         {       if(!root || !(type&(DT_CLEAR|DT_FIRST|DT_LAST)) )
00035                         return NIL(Void_t*);
00036 
00037                 if(type&DT_CLEAR) /* delete all objects */
00038                 {       if(disc->freef || disc->link < 0)
00039                         {       do
00040                                 {       while((t = root->left) )
00041                                                 RROTATE(root,t);
00042                                         t = root->right;
00043                                         if(disc->freef)
00044                                                 (*disc->freef)(dt,_DTOBJ(root,lk),disc);
00045                                         if(disc->link < 0)
00046                                                 (*dt->memoryf)(dt,(Void_t*)root,0,disc);
00047                                 } while((root = t) );
00048                         }
00049 
00050                         dt->data->size = 0;
00051                         dt->data->here = NIL(Dtlink_t*);
00052                         return NIL(Void_t*);
00053                 }
00054                 else /* computing largest/smallest element */
00055                 {       if(type&DT_LAST)
00056                         {       while((t = root->right) )
00057                                         LROTATE(root,t);
00058                         }
00059                         else /* type&DT_FIRST */
00060                         {       while((t = root->left) )
00061                                         RROTATE(root,t);
00062                         }
00063 
00064                         dt->data->here = root;
00065                         return _DTOBJ(root,lk);
00066                 }
00067         }
00068 
00069         /* note that link.right is LEFT tree and link.left is RIGHT tree */
00070         l = r = &link;
00071 
00072         /* allow apps to delete an object "actually" in the dictionary */
00073         if(dt->meth->type == DT_OBAG && (type&(DT_DELETE|DT_DETACH)) )
00074         {       key = _DTKEY(obj,ky,sz);
00075                 for(o = dtsearch(dt,obj); o; o = dtnext(dt,o) )
00076                 {       k = _DTKEY(o,ky,sz);
00077                         if(_DTCMP(dt,key,k,disc,cmpf,sz) != 0)
00078                                 break;
00079                         if(o == obj)
00080                         {       root = dt->data->here;
00081                                 l->right = root->left;
00082                                 r->left  = root->right;
00083                                 goto dt_delete;
00084                         }
00085                 }
00086         }
00087 
00088         if(type&(DT_MATCH|DT_SEARCH|DT_INSERT|DT_ATTACH))
00089         {       key = (type&DT_MATCH) ? obj : _DTKEY(obj,ky,sz);
00090                 if(root)
00091                         goto do_search;
00092         }
00093         else if(type&DT_RENEW)
00094         {       me = (Dtlink_t*)obj;
00095                 obj = _DTOBJ(me,lk);
00096                 key = _DTKEY(obj,ky,sz);
00097                 if(root)
00098                         goto do_search;
00099         }
00100         else if(root && _DTOBJ(root,lk) != obj)
00101         {       key = _DTKEY(obj,ky,sz);
00102         do_search:
00103                 if(dt->meth->type == DT_OSET &&
00104                    (minp = dt->data->minp) != 0 && (type&(DT_MATCH|DT_SEARCH)) )
00105                 {       /* simple search, note that minp should be even */
00106                         for(t = root, n = 0; n < minp; ++n)
00107                         {       k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz);
00108                                 if((cmp = _DTCMP(dt,key,k,disc,cmpf,sz)) == 0)
00109                                         return _DTOBJ(t,lk);
00110                                 else
00111                                 {       turn[n] = cmp;  
00112                                         if(!(t = cmp < 0 ? t->left : t->right) )
00113                                                 return NIL(Void_t*);
00114                                 }
00115                         }
00116 
00117                         /* exceed search length, top-down splay now */
00118                         for(n = 0; n < minp; n += 2)
00119                         {       if(turn[n] < 0)
00120                                 {       t = root->left;
00121                                         if(turn[n+1] < 0)
00122                                         {       rrotate(root,t);
00123                                                 rlink(r,t);
00124                                                 root = t->left;
00125                                         }
00126                                         else
00127                                         {       llink(l,t);
00128                                                 rlink(r,root);
00129                                                 root = t->right;
00130                                         }
00131                                 }
00132                                 else
00133                                 {       t = root->right;
00134                                         if(turn[n+1] > 0)
00135                                         {       lrotate(root,t);
00136                                                 llink(l,t);
00137                                                 root = t->right;
00138                                         }
00139                                         else
00140                                         {       rlink(r,t);
00141                                                 llink(l,root);
00142                                                 root = t->left;
00143                                         }
00144                                 }
00145                         }
00146                 }
00147 
00148                 while(1)
00149                 {       k = _DTOBJ(root,lk); k = _DTKEY(k,ky,sz);
00150                         if((cmp = _DTCMP(dt,key,k,disc,cmpf,sz)) == 0)
00151                                 break;
00152                         else if(cmp < 0)
00153                         {       if((t = root->left) )
00154                                 {       k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz);
00155                                         if((cmp = _DTCMP(dt,key,k,disc,cmpf,sz)) < 0)
00156                                         {       rrotate(root,t);
00157                                                 rlink(r,t);
00158                                                 if(!(root = t->left) )
00159                                                         break;
00160                                         }
00161                                         else if(cmp == 0)
00162                                         {       rlink(r,root);
00163                                                 root = t;
00164                                                 break;
00165                                         }
00166                                         else /* if(cmp > 0) */
00167                                         {       llink(l,t);
00168                                                 rlink(r,root);
00169                                                 if(!(root = t->right) )
00170                                                         break;
00171                                         }
00172                                 }
00173                                 else
00174                                 {       rlink(r,root);
00175                                         root = NIL(Dtlink_t*);
00176                                         break;
00177                                 }
00178                         }
00179                         else /* if(cmp > 0) */
00180                         {       if((t = root->right) )
00181                                 {       k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz);
00182                                         if((cmp = _DTCMP(dt,key,k,disc,cmpf,sz)) > 0)
00183                                         {       lrotate(root,t);
00184                                                 llink(l,t);
00185                                                 if(!(root = t->right) )
00186                                                         break;
00187                                         }
00188                                         else if(cmp == 0)
00189                                         {       llink(l,root);
00190                                                 root = t;
00191                                                 break;
00192                                         }
00193                                         else /* if(cmp < 0) */
00194                                         {       rlink(r,t);
00195                                                 llink(l,root);
00196                                                 if(!(root = t->left) )
00197                                                         break;
00198                                         }
00199                                 }
00200                                 else
00201                                 {       llink(l,root);
00202                                         root = NIL(Dtlink_t*);
00203                                         break;
00204                                 }
00205                         }
00206                 }
00207         }
00208 
00209         if(root)
00210         {       /* found it, now isolate it */
00211                 dt->type |= DT_FOUND;
00212                 l->right = root->left;
00213                 r->left = root->right;
00214 
00215                 if(type&(DT_SEARCH|DT_MATCH))
00216                 { has_root:
00217                         root->left = link.right;
00218                         root->right = link.left;
00219                         if((dt->meth->type&DT_OBAG) && (type&(DT_SEARCH|DT_MATCH)) )
00220                         {       key = _DTOBJ(root,lk); key = _DTKEY(key,ky,sz);
00221                                 while((t = root->left) )
00222                                 {       /* find max of left subtree */
00223                                         while((r = t->right) )
00224                                                 LROTATE(t,r);
00225                                         root->left = t;
00226 
00227                                         /* now see if it's in the same group */
00228                                         k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz);
00229                                         if(_DTCMP(dt,key,k,disc,cmpf,sz) != 0)
00230                                                 break;
00231                                         RROTATE(root,t);
00232                                 }
00233                         }
00234                         dt->data->here = root;
00235                         return _DTOBJ(root,lk);
00236                 }
00237                 else if(type&DT_NEXT)
00238                 {       root->left = link.right;
00239                         root->right = NIL(Dtlink_t*);
00240                         link.right = root;
00241                 dt_next:
00242                         if((root = link.left) ) 
00243                         {       while((t = root->left) )
00244                                         RROTATE(root,t);
00245                                 link.left = root->right;
00246                                 goto has_root;
00247                         }
00248                         else    goto no_root;
00249                 }
00250                 else if(type&DT_PREV)
00251                 {       root->right = link.left;
00252                         root->left = NIL(Dtlink_t*);
00253                         link.left = root;
00254                 dt_prev:
00255                         if((root = link.right) )
00256                         {       while((t = root->right) )
00257                                         LROTATE(root,t);
00258                                 link.right = root->left;
00259                                 goto has_root;
00260                         }
00261                         else    goto no_root;
00262                 }
00263                 else if(type&(DT_DELETE|DT_DETACH))
00264                 {       /* taking an object out of the dictionary */
00265                 dt_delete:
00266                         obj = _DTOBJ(root,lk);
00267                         if(disc->freef && (type&DT_DELETE))
00268                                 (*disc->freef)(dt,obj,disc);
00269                         if(disc->link < 0)
00270                                 (*dt->memoryf)(dt,(Void_t*)root,0,disc);
00271                         if((dt->data->size -= 1) < 0)
00272                                 dt->data->size = -1;
00273                         goto no_root;
00274                 }
00275                 else if(type&(DT_INSERT|DT_ATTACH))
00276                 {       if(dt->meth->type&DT_OSET)
00277                                 goto has_root;
00278                         else
00279                         {       root->left = NIL(Dtlink_t*);
00280                                 root->right = link.left;
00281                                 link.left = root;
00282                                 goto dt_insert;
00283                         }
00284                 }
00285                 else if(type&DT_RENEW) /* a duplicate */
00286                 {       if(dt->meth->type&DT_OSET)
00287                         {       if(disc->freef)
00288                                         (*disc->freef)(dt,obj,disc);
00289                                 if(disc->link < 0)
00290                                         (*dt->memoryf)(dt,(Void_t*)me,0,disc);
00291                         }
00292                         else
00293                         {       me->left = NIL(Dtlink_t*);
00294                                 me->right = link.left;
00295                                 link.left = me;
00296                                 dt->data->size += 1;
00297                         }
00298                         goto has_root;
00299                 }
00300         }
00301         else
00302         {       /* not found, finish up LEFT and RIGHT trees */
00303                 r->left = NIL(Dtlink_t*);
00304                 l->right = NIL(Dtlink_t*);
00305 
00306                 if(type&DT_NEXT)
00307                         goto dt_next;
00308                 else if(type&DT_PREV)
00309                         goto dt_prev;
00310                 else if(type&(DT_SEARCH|DT_MATCH))
00311                 { no_root:
00312                         while((t = r->left) )
00313                                 r = t;
00314                         r->left = link.right;
00315                         dt->data->here = link.left;
00316                         return (type&DT_DELETE) ? obj : NIL(Void_t*);
00317                 }
00318                 else if(type&(DT_INSERT|DT_ATTACH))
00319                 { dt_insert:
00320                         if(disc->makef && (type&DT_INSERT))
00321                                 obj = (*disc->makef)(dt,obj,disc);
00322                         if(obj)
00323                         {       if(lk >= 0)
00324                                         root = _DTLNK(obj,lk);
00325                                 else
00326                                 {       root = (Dtlink_t*)(*dt->memoryf)
00327                                                 (dt,NIL(Void_t*),sizeof(Dthold_t),disc);
00328                                         if(root)
00329                                                 ((Dthold_t*)root)->obj = obj;
00330                                         else if(disc->makef && disc->freef &&
00331                                                 (type&DT_INSERT))
00332                                                 (*disc->freef)(dt,obj,disc);
00333                                 }
00334                         }
00335                         if(root)
00336                         {       if(dt->data->size >= 0)
00337                                         dt->data->size += 1;
00338                                 goto has_root;
00339                         }
00340                         else    goto no_root;
00341                 }
00342                 else if(type&DT_RENEW)
00343                 {       root = me;
00344                         dt->data->size += 1;
00345                         goto has_root;
00346                 }
00347                 else /*if(type&DT_DELETE)*/
00348                 {       obj = NIL(Void_t*);
00349                         goto no_root;
00350                 }
00351         }
00352 
00353         return NIL(Void_t*);
00354 }
00355 
00356 /* make this method available */
00357 static Dtmethod_t       _Dtoset =  { dttree, DT_OSET };
00358 static Dtmethod_t       _Dtobag =  { dttree, DT_OBAG };
00359 __DEFINE__(Dtmethod_t*,Dtoset,&_Dtoset);
00360 __DEFINE__(Dtmethod_t*,Dtobag,&_Dtobag);
00361 
00362 #ifndef KPVDEL /* backward compatibility - delete next time around */
00363 Dtmethod_t              _Dttree = { dttree, DT_OSET };
00364 __DEFINE__(Dtmethod_t*,Dtorder,&_Dttree);
00365 __DEFINE__(Dtmethod_t*,Dttree,&_Dttree);
00366 #endif
00367 
00368 #ifdef NoF
00369 NoF(dttree)
00370 #endif