Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

skiplist.c

00001 /* ======================================================================
00002  * Copyright (c) 2000 Theo Schlossnagle
00003  * All rights reserved.
00004  * The following code was written by Theo Schlossnagle for use in the
00005  * Backhand project at The Center for Networking and Distributed Systems
00006  * at The Johns Hopkins University.
00007  *
00008  * This is a skiplist implementation to be used for abstract structures
00009  * and is release under the LGPL license version 2.1 or later.  A copy
00010  * of this license can be found at http://www.gnu.org/copyleft/lesser.html
00011  * ======================================================================
00012 */
00013 
00014 extern "C"
00015 {
00016 #include <stdio.h>
00017 #include <stdlib.h>
00018 #include <assert.h>
00019 
00020 #include "skiplist.h"
00021 }
00022 
00023 #ifdef USE_DMALLOC
00024 #    include <dmalloc.h>
00025 #endif
00026 
00027 #ifndef MIN
00028 #define MIN(a,b) ((a<b)?(a):(b))
00029 #endif
00030 
00031 static int get_b_rand(void) {
00032   static int ph=32; /* More bits than we will ever use */
00033   static unsigned long randseq;
00034   if(ph > 31) { /* Num bits in return of lrand48() */
00035     ph=0;
00036     randseq = lrand48();
00037   }
00038   ph++;
00039   return ((randseq & (1 << (ph-1))) >> (ph-1));
00040 }
00041 
00042 void skiplisti_init(Skiplist *sl) {
00043   sl->compare = (SkiplistComparator)NULL;
00044   sl->comparek = (SkiplistComparator)NULL;
00045   sl->height=0;
00046   sl->preheight=0;
00047   sl->size=0;
00048   sl->top = NULL;
00049   sl->bottom = NULL;
00050   sl->index = NULL;
00051 }
00052 
00053 static int indexing_comp(void *a, void *b) {
00054   assert(a);
00055   assert(b);
00056   return (void *)(((Skiplist *)a)->compare)>(void *)(((Skiplist *)b)->compare);
00057 }
00058 static int indexing_compk(void *a, void *b) {
00059   assert(b);
00060   return a>(void *)(((Skiplist *)b)->compare);
00061 }
00062 
00063 void skiplist_init(Skiplist *sl) {
00064   skiplisti_init(sl);
00065   sl->index = (Skiplist *)malloc(sizeof(Skiplist));
00066   skiplisti_init(sl->index);
00067   skiplist_set_compare(sl->index, indexing_comp, indexing_compk);
00068 }
00069 
00070 void skiplist_set_compare(Skiplist *sl,
00071                     SkiplistComparator comp,
00072                     SkiplistComparator compk) {
00073   if(sl->compare && sl->comparek) {
00074     skiplist_add_index(sl, comp, compk);
00075   } else {
00076     sl->compare = comp;
00077     sl->comparek = compk;
00078   }
00079 }
00080 
00081 void skiplist_add_index(Skiplist *sl,
00082                   SkiplistComparator comp,
00083                   SkiplistComparator compk) {
00084   struct skiplistnode *m;
00085   Skiplist *ni;
00086   int icount=0;
00087 #ifdef SLDEBUG
00088   fprintf(stderr, "Adding index to %p\n", sl);
00089 #endif
00090   skiplist_find(sl->index, (void *)comp, &m);
00091   if(m) return; /* Index already there! */
00092   ni = (Skiplist *)malloc(sizeof(Skiplist));
00093   skiplisti_init(ni);
00094   skiplist_set_compare(ni, comp, compk);
00095   /* Build the new index... This can be expensive! */
00096   m = skiplist_insert(sl->index, ni);
00097   while(m->prev) m=m->prev, icount++;
00098   for(m=skiplist_getlist(sl); m; skiplist_next(sl, &m)) {
00099     int j=icount-1;
00100     struct skiplistnode *nsln;
00101     nsln = skiplist_insert(ni, m->data);
00102     /* skip from main index down list */
00103     while(j>0) m=m->nextindex, j--;
00104     /* insert this node in the indexlist after m */
00105     nsln->nextindex = m->nextindex;
00106     if(m->nextindex) m->nextindex->previndex = nsln;
00107     nsln->previndex = m;
00108     m->nextindex = nsln;
00109   } 
00110 }
00111 
00112 struct skiplistnode *skiplist_getlist(Skiplist *sl) {
00113   if(!sl->bottom) return NULL;
00114   return sl->bottom->next;
00115 }
00116 
00117 void *skiplist_find(Skiplist *sl,
00118               void *data,
00119               struct skiplistnode **iter) {
00120   void *ret;
00121   struct skiplistnode *aiter;
00122   if(!sl->compare) return 0;
00123   if(iter)
00124     ret = skiplist_find_compare(sl, data, iter, sl->compare);
00125   else
00126     ret = skiplist_find_compare(sl, data, &aiter, sl->compare);
00127   return ret;
00128 }  
00129 void *skiplist_find_compare(Skiplist *sli,
00130                       void *data,
00131                       struct skiplistnode **iter,
00132                       SkiplistComparator comp) {
00133   struct skiplistnode *m = NULL;
00134   Skiplist *sl;
00135   if(comp==sli->compare || !sli->index) {
00136     sl = sli;
00137   } else {
00138     skiplist_find(sli->index, (void *)comp, &m);
00139     assert(m);
00140     sl= (Skiplist *) m->data;
00141   }
00142   skiplisti_find_compare(sl, data, iter, sl->comparek);
00143   return (*iter)?((*iter)->data):(*iter);
00144 }
00145 int skiplisti_find_compare(Skiplist *sl,
00146                      void *data,
00147                      struct skiplistnode **ret,
00148                      SkiplistComparator comp) {
00149   struct skiplistnode *m = NULL;
00150   int count=0;
00151   m = sl->top;
00152   while(m) {
00153     int compared;
00154     if(m->next) compared=comp(data, m->next->data);
00155     if(compared == 0) {
00156 #ifdef SL_DEBUG
00157       printf("Looking -- found in %d steps\n", count);
00158 #endif
00159       m=m->next;
00160       while(m->down) m=m->down;
00161       *ret = m;
00162       return count;
00163     }
00164     if((m->next == NULL) || (compared<0))
00165       m = m->down, count++;
00166     else
00167       m = m->next, count++;
00168   }
00169 #ifdef SL_DEBUG
00170   printf("Looking -- not found in %d steps\n", count);
00171 #endif
00172   *ret = NULL;
00173   return count;
00174 }
00175 void *skiplist_next(Skiplist *sl, struct skiplistnode **iter) {
00176   if(!*iter) return NULL;
00177   *iter = (*iter)->next;
00178   return (*iter)?((*iter)->data):NULL;
00179 }
00180 void *skiplist_previous(Skiplist *sl, struct skiplistnode **iter) {
00181   if(!*iter) return NULL;
00182   *iter = (*iter)->prev;
00183   return (*iter)?((*iter)->data):NULL;
00184 }
00185 struct skiplistnode *skiplist_insert(Skiplist *sl,
00186                                void *data) {
00187   if(!sl->compare) return 0;
00188   return skiplist_insert_compare(sl, data, sl->compare);
00189 }
00190 
00191 struct skiplistnode *skiplist_insert_compare(Skiplist *sl,
00192                                        void *data,
00193                                        SkiplistComparator comp) {
00194   struct skiplistnode *m, *p, *tmp, *ret, **stack;
00195   int nh=1, ch, stacki;
00196 #ifdef SLDEBUG
00197   skiplist_print_struct(sl, "BI: ");
00198 #endif
00199   if(!sl->top) {
00200     sl->height = 1;
00201     sl->topend = sl->bottomend = sl->top = sl->bottom = 
00202       (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
00203     assert(sl->top);
00204     sl->top->next = (struct skiplistnode *) NULL;
00205     sl->top->data = (struct skiplistnode *) NULL;
00206     sl->top->prev =(struct skiplistnode *) NULL;
00207         sl->top->up = (struct skiplistnode *) NULL;
00208     sl->top->down = (struct skiplistnode *) NULL;
00209         sl->top->nextindex=  (struct skiplistnode *) NULL;
00210     sl->top->previndex = (struct skiplistnode *) NULL;
00211     sl->top->sl = sl;
00212   }
00213   if(sl->preheight) {
00214     while(nh < sl->preheight && get_b_rand()) nh++;
00215   } else {
00216     while(nh <= sl->height && get_b_rand()) nh++;
00217   }
00218   /* Now we have the new height at which we wish to insert our new node */
00219   /* Let us make sure that our tree is a least that tall (grow if necessary)*/
00220   for(;sl->height<nh;sl->height++) {
00221     sl->top->up =
00222       (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
00223     assert(sl->top->up);
00224     sl->top->up->down = sl->top;
00225     sl->top = sl->topend = sl->top->up;
00226     sl->top->prev = sl->top->next = sl->top->nextindex =
00227       sl->top->previndex = sl->top->up = NULL;
00228     sl->top->data = NULL;
00229     sl->top->sl = sl;
00230   }
00231   ch = sl->height;
00232   /* Find the node (or node after which we would insert) */
00233   /* Keep a stack to pop back through for insertion */
00234   m = sl->top;
00235   stack = (struct skiplistnode **)malloc(sizeof(struct skiplistnode *)*(nh));
00236   stacki=0;
00237   while(m) {
00238     int compared=-1;
00239     if(m->next) compared=comp(data, m->next->data);
00240     if(compared == 0) {
00241       free(stack);
00242       return 0;
00243     }
00244     if((m->next == NULL) || (compared<0)) {
00245       if(ch<=nh) {
00246         /* push on stack */
00247         stack[stacki++] = m;
00248       }
00249       m = m->down;
00250       ch--;
00251     } else {
00252       m = m->next;
00253     }
00254   }
00255   /* Pop the stack and insert nodes */
00256   p = NULL;
00257   for(;stacki>0;stacki--) {
00258     m = stack[stacki-1];
00259     tmp = (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
00260     tmp->next = m->next;
00261     if(m->next) m->next->prev=tmp;
00262     tmp->prev = m;
00263     tmp->up = NULL;
00264     tmp->nextindex = tmp->previndex = NULL;
00265     tmp->down = p;
00266     if(p) p->up=tmp;
00267     tmp->data = data;
00268     tmp->sl = sl;
00269     m->next = tmp;
00270     /* This sets ret to the bottom-most node we are inserting */
00271     if(!p) ret=tmp;
00272     p = tmp;
00273   }
00274   free(stack);
00275   if(sl->index != NULL) {
00276     /* this is a external insertion, we must insert into each index as well */
00277     struct skiplistnode *p, *ni, *li;
00278     li=ret;
00279     for(p = skiplist_getlist(sl->index); p; skiplist_next(sl->index, &p)) {
00280       ni = skiplist_insert((Skiplist *)p->data, ret->data);
00281       assert(ni);
00282 #ifdef SLDEBUG
00283       fprintf(stderr, "Adding %p to index %p\n", ret->data, p->data);
00284 #endif
00285       li->nextindex = ni;
00286       ni->previndex = li;
00287       li = ni;
00288     }
00289   } else {
00290     sl->size++;
00291   }
00292 #ifdef SLDEBUG
00293   skiplist_print_struct(sl, "AI: ");
00294 #endif
00295   return ret;
00296 }
00297 struct skiplistnode *skiplist_append(Skiplist *sl, void *data) {
00298   int nh=1, ch, compared;
00299   struct skiplistnode *lastnode, *nodeago;
00300   if(sl->bottomend != sl->bottom) {
00301     compared=sl->compare(data, sl->bottomend->prev->data);
00302     /* If it doesn't belong at the end, then fail */
00303     if(compared<=0) return NULL;
00304   }
00305   if(sl->preheight) {
00306     while(nh < sl->preheight && get_b_rand()) nh++;
00307   } else {
00308     while(nh <= sl->height && get_b_rand()) nh++;
00309   }
00310   /* Now we have the new height at which we wish to insert our new node */
00311   /* Let us make sure that our tree is a least that tall (grow if necessary)*/
00312   lastnode = sl->bottomend;
00313   nodeago = NULL;
00314 
00315   if(!lastnode) return skiplist_insert(sl, data);
00316 
00317   for(;sl->height<nh;sl->height++) {
00318     sl->top->up =
00319       (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
00320     assert(sl->top);
00321     sl->top->up->down = sl->top;
00322     sl->top = sl->top->up;
00323     sl->top->prev = sl->top->next = sl->top->nextindex =
00324       sl->top->previndex = NULL;
00325     sl->top->data = NULL;
00326     sl->top->sl = sl;
00327   }
00328   ch = sl->height;
00329   while(nh) {
00330     struct skiplistnode *anode;
00331     anode =
00332       (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
00333     anode->next = lastnode;
00334     anode->prev = lastnode->prev;
00335     anode->up = NULL;
00336     anode->down = nodeago;
00337     if(lastnode->prev) {
00338       if(lastnode == sl->bottom)
00339         sl->bottom = anode;
00340       else if (lastnode == sl->top)
00341         sl->top = anode;
00342     }
00343     nodeago = anode;
00344     lastnode = lastnode->up;
00345     nh--;
00346   }
00347   sl->size++;
00348   return sl->bottomend;
00349 }
00350 Skiplist *skiplist_concat(Skiplist *sl1, Skiplist *sl2) {
00351   /* Check integrity! */
00352   int compared, eheight;
00353   Skiplist temp;
00354   struct skiplistnode *lbottom, *lbottomend, *b1, *e1, *b2, *e2;
00355   if(sl1->bottomend == NULL || sl1->bottomend->prev == NULL) {
00356     skiplist_remove_all(sl1, free);
00357     temp = *sl1;
00358     *sl1 = *sl2;
00359     *sl2 = temp;
00360     /* swap them so that sl2 can be freed normally upon return. */
00361     return sl1;
00362   }
00363   if(sl2->bottom == NULL || sl2->bottom->next == NULL) {
00364     skiplist_remove_all(sl2, free);
00365     return sl1;
00366   }
00367   compared = sl1->compare(sl1->bottomend->prev->data, sl2->bottom->data);
00368   /* If it doesn't belong at the end, then fail */
00369   if(compared<=0) return NULL;
00370   
00371   /* OK now append sl2 onto sl1 */
00372   lbottom = lbottomend = NULL;
00373   eheight = MIN(sl1->height, sl2->height);
00374   b1 = sl1->bottom; e1 = sl1->bottomend;
00375   b2 = sl2->bottom; e2 = sl2->bottomend;
00376   while(eheight) {    
00377     e1->prev->next = b2;
00378     b2->prev = e1->prev->next;
00379     e2->prev->next = e1;
00380     e1->prev = e2->prev;
00381     e2->prev = NULL;
00382     b2 = e2;
00383     b1->down = lbottom;
00384     e1->down = lbottomend;
00385     if(lbottom) lbottom->up = b1;
00386     if(lbottomend) lbottomend->up = e1;
00387     
00388     lbottom = b1;
00389     lbottomend = e1;
00390   }
00391   /* Take the top of the longer one (if it is sl2) and make it sl1's */
00392   if(sl2->height > sl1->height) {
00393     b1->up = b2->up;
00394     e1->up = e2->up;
00395     b1->up->down = b1;
00396     e1->up->down = e1;
00397     sl1->height = sl2->height;
00398     sl1->top = sl2->top;
00399     sl1->topend = sl2->topend;
00400   }
00401 
00402   /* move the top pointer to here if it isn't there already */
00403   sl2->top = sl2->topend = b2;
00404   sl2->top->up = NULL; /* If it isn't already */
00405   sl1->size += sl2->size;
00406   skiplist_remove_all(sl2, free);
00407   return sl1;
00408 }
00409 int skiplist_remove(Skiplist *sl,
00410               void *data, FreeFunc myfree) {
00411   if(!sl->compare) return 0;
00412   return skiplist_remove_compare(sl, data, myfree, sl->comparek);
00413 }
00414 void skiplist_print_struct(Skiplist *sl, char *prefix) {
00415   struct skiplistnode *p, *q;
00416   fprintf(stderr, "Skiplist Structure (height: %d)\n", sl->height);
00417   p = sl->bottom;
00418   while(p) {
00419     q = p;
00420     fprintf(stderr, prefix);
00421     while(q) {
00422       fprintf(stderr, "%p ", q->data);
00423       q=q->up;
00424     }
00425     fprintf(stderr, "\n");
00426     p=p->next;
00427   }
00428 }
00429 int skiplisti_remove(Skiplist *sl, struct skiplistnode *m, FreeFunc myfree) {
00430   struct skiplistnode *p;
00431   if(!m) return 0;
00432   if(m->nextindex) skiplisti_remove(m->nextindex->sl, m->nextindex, NULL);
00433   else sl->size--;
00434 #ifdef SLDEBUG
00435   skiplist_print_struct(sl, "BR:");
00436 #endif
00437   while(m->up) m=m->up;
00438   while(m) {
00439     p=m;
00440     p->prev->next = p->next; /* take me out of the list */
00441     if(p->next) p->next->prev = p->prev; /* take me out of the list */
00442     m=m->down;
00443     /* This only frees the actual data in the bottom one */
00444     if(!m && myfree && p->data) myfree(p->data);
00445     free(p);
00446   }
00447   while(sl->top && sl->top->next == NULL) {
00448     /* While the row is empty and we are not on the bottom row */
00449     p = sl->top;
00450     sl->top = sl->top->down; /* Move top down one */
00451     if(sl->top) sl->top->up = NULL;      /* Make it think its the top */
00452     free(p);
00453     sl->height--;
00454   }
00455   if(!sl->top) sl->bottom = NULL;
00456   assert(sl->height>=0);
00457 #ifdef SLDEBUG
00458   skiplist_print_struct(sl, "AR: ");
00459 #endif
00460   return sl->height;
00461 }
00462 int skiplist_remove_compare(Skiplist *sli,
00463                       void *data,
00464                       FreeFunc myfree, SkiplistComparator comp) {
00465   struct skiplistnode *m;
00466   Skiplist *sl;
00467   if(comp==sli->comparek || !sli->index) {
00468     sl = sli;
00469   } else {
00470     skiplist_find(sli->index, (void *)comp, &m);
00471     assert(m);
00472     sl= (Skiplist *) m->data;
00473   }
00474   skiplisti_find_compare(sl, data, &m, comp);
00475   if(!m) return 0;
00476   while(m->previndex) m=m->previndex;
00477   return skiplisti_remove(sl, m, myfree);
00478 }
00479 void skiplist_remove_all(Skiplist *sl, FreeFunc myfree) {
00480   /* This must remove even the place holder nodes (bottom though top)
00481      because we specify in the API that one can free the Skiplist after
00482      making this call without memory leaks */
00483   struct skiplistnode *m, *p, *u;
00484   m=sl->bottom;
00485   while(m) {
00486     p = m->next;
00487     if(myfree && p->data) myfree(p->data);
00488     while(m) {
00489       u = m->up;
00490       free(m);
00491       m=u;
00492     }
00493     m = p;
00494   }
00495   sl->top = sl->bottom = NULL;
00496   sl->height = 0;
00497   sl->size = 0;
00498 }
00499 
00500 void *skiplist_pop(Skiplist * a, FreeFunc myfree)
00501 {
00502   struct skiplistnode *sln;
00503   void *data = NULL;
00504   sln = skiplist_getlist(a);
00505   if (sln) {
00506     data = sln->data;
00507     skiplisti_remove(a, sln, myfree);
00508   }
00509   return data;
00510 }

Generated on Sun Dec 25 12:14:41 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2