1 /*
2  * The Spread Toolkit.
3  *
4  * The contents of this file are subject to the Spread Open-Source
5  * License, Version 1.0 (the ``License''); you may not use
6  * this file except in compliance with the License.  You may obtain a
7  * copy of the License at:
8  *
9  * http://www.spread.org/license/
10  *
11  * or in the file ``license.txt'' found in this distribution.
12  *
13  * Software distributed under the License is distributed on an AS IS basis,
14  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15  * for the specific language governing rights and limitations under the
16  * License.
17  *
18  * The Creators of Spread are:
19  *  Yair Amir, Michal Miskin-Amir, Jonathan Stanton.
20  *
21  *  Copyright (C) 1993-2004 Spread Concepts LLC <spread@spreadconcepts.com>
22  *
23  *  All Rights Reserved.
24  *
25  * Major Contributor(s):
26  * ---------------
27  *    Cristina Nita-Rotaru crisn@cs.purdue.edu - group communication security.
28  *    Theo Schlossnagle    jesus@omniti.com - Perl, skiplists, autoconf.
29  *    Dan Schoenblum       dansch@cnds.jhu.edu - Java interface.
30  *    John Schultz         jschultz@cnds.jhu.edu - contribution to process group membership.
31  *
32  */
33 
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <assert.h>
38 
39 #include "skiplist_p.h"
40 #include "alarm.h"
41 
42 #ifndef MIN
43 #define MIN(a,b) ((a<b)?(a):(b))
44 #endif
45 
get_b_rand()46 static int get_b_rand() {
47   static int ph=32; /* More bits than we will ever use */
48   static unsigned long randseq;
49   if(ph > 31) { /* Num bits in return of lrand48() */
50     ph=0;
51     randseq = get_rand();
52   }
53   ph++;
54   return ((randseq & (1 << (ph-1))) >> (ph-1));
55 }
56 
sli_init(Skiplist * sl)57 void sli_init(Skiplist *sl) {
58   sl->compare = (SkiplistComparator)NULL;
59   sl->comparek = (SkiplistComparator)NULL;
60   sl->height=0;
61   sl->preheight=0;
62   sl->size=0;
63   sl->top = NULL;
64    sl->bottom = NULL;
65   sl->index = NULL;
66 }
67 
indexing_comp(const void * a,const void * b)68 static int indexing_comp(const void *a, const void *b)
69 {
70   void *ak = (void *) (((Skiplist *) a)->compare);
71   void *bk = (void *) (((Skiplist *) b)->compare);
72   assert(a);
73   assert(b);
74   if(ak<bk)
75     return -1;
76   if(ak>bk)
77     return 1;
78   return 0;
79 }
indexing_compk(const void * ak,const void * b)80 static int indexing_compk(const void *ak, const void *b)
81 {
82   void *bk = (void *) (((Skiplist *) b)->compare);
83   assert(b);
84   if(ak<bk)
85     return -1;
86   if(ak>bk)
87     return 1;
88   return 0;
89 }
90 
sl_init(Skiplist * sl)91 void sl_init(Skiplist *sl) {
92   sli_init(sl);
93   sl->index = (Skiplist *)malloc(sizeof(Skiplist));
94   sli_init(sl->index);
95   sl_set_compare(sl->index, indexing_comp, indexing_compk);
96 }
97 
sl_set_compare(Skiplist * sl,SkiplistComparator comp,SkiplistComparator compk)98 void sl_set_compare(Skiplist *sl,
99 		    SkiplistComparator comp,
100 		    SkiplistComparator compk) {
101   if(sl->compare && sl->comparek) {
102     sl_add_index(sl, comp, compk);
103   } else {
104     sl->compare = comp;
105     sl->comparek = compk;
106   }
107 }
108 
sl_add_index(Skiplist * sl,SkiplistComparator comp,SkiplistComparator compk)109 void sl_add_index(Skiplist *sl,
110 		  SkiplistComparator comp,
111 		  SkiplistComparator compk) {
112   struct skiplistnode *m;
113   Skiplist *ni;
114   int icount=0;
115   Alarm(SKIPLIST, "Adding index to %p\n", sl);
116   sl_find(sl->index, (void *)comp, &m);
117   if(m) return; /* Index already there! */
118   ni = (Skiplist *)malloc(sizeof(Skiplist));
119   sli_init(ni);
120   sl_set_compare(ni, comp, compk);
121   /* Build the new index... This can be expensive! */
122   m = sl_insert(sl->index, ni);
123   while(m->prev) m=m->prev, icount++;
124   for(m=sl_getlist(sl); m; sl_next(sl, &m)) {
125     int j=icount-1;
126     struct skiplistnode *nsln;
127     nsln = sl_insert(ni, m->data);
128     /* skip from main index down list */
129     while(j>0) m=m->nextindex, j--;
130     /* insert this node in the indexlist after m */
131     nsln->nextindex = m->nextindex;
132     if(m->nextindex) m->nextindex->previndex = nsln;
133     nsln->previndex = m;
134     m->nextindex = nsln;
135   }
136 }
137 
sl_getlist(Skiplist * sl)138 struct skiplistnode *sl_getlist(Skiplist *sl) {
139   if(!sl->bottom) return NULL;
140   return sl->bottom->next;
141 }
142 
sl_find(Skiplist * sl,void * data,struct skiplistnode ** iter)143 void *sl_find(Skiplist *sl,
144 	      void *data,
145 	      struct skiplistnode **iter) {
146   void *ret;
147   if(!sl->compare) return 0;
148   ret = sl_find_compare(sl, data, iter, sl->compare);
149   return ret;
150 }
sl_find_compare(Skiplist * sli,void * data,struct skiplistnode ** iter,SkiplistComparator comp)151 void *sl_find_compare(Skiplist *sli,
152 		      void *data,
153 		      struct skiplistnode **iter,
154 		      SkiplistComparator comp) {
155   struct skiplistnode *m = NULL;
156   Skiplist *sl;
157   if(comp==sli->compare || !sli->index) {
158     sl = sli;
159   } else {
160     sl_find(sli->index, (void *)comp, &m);
161     assert(m);
162     sl=m->data;
163   }
164   sli_find_compare(sl, data, iter, sl->comparek);
165   return (*iter)?((*iter)->data):(*iter);
166 }
sli_find_compare(Skiplist * sl,void * data,struct skiplistnode ** ret,SkiplistComparator comp)167 int sli_find_compare(Skiplist *sl,
168 		     void *data,
169 		     struct skiplistnode **ret,
170 		     SkiplistComparator comp) {
171   struct skiplistnode *m = NULL;
172   int count=0;
173   m = sl->top;
174   while(m) {
175     int compared = 1;
176     if(m->next) compared=comp(data, m->next->data);
177     if(compared == 0) {
178 #ifdef SL_DEBUG
179       Alarm(SKIPLIST, "Looking -- found in %d steps\n", count);
180 #endif
181       m=m->next;
182       while(m->down) m=m->down;
183       *ret = m;
184       return count;
185     }
186     if((m->next == NULL) || (compared<0))
187       m = m->down, count++;
188     else
189       m = m->next, count++;
190   }
191 #ifdef SL_DEBUG
192   Alarm(SKIPLIST, "Looking -- not found in %d steps\n", count);
193 #endif
194   *ret = NULL;
195   return count;
196 }
sl_next(Skiplist * sl,struct skiplistnode ** iter)197 void *sl_next(Skiplist *sl, struct skiplistnode **iter) {
198   if(!*iter) return NULL;
199   *iter = (*iter)->next;
200   return (*iter)?((*iter)->data):NULL;
201 }
sl_previous(Skiplist * sl,struct skiplistnode ** iter)202 void *sl_previous(Skiplist *sl, struct skiplistnode **iter) {
203   if(!*iter) return NULL;
204   *iter = (*iter)->prev;
205   return (*iter)?((*iter)->data):NULL;
206 }
sl_insert(Skiplist * sl,void * data)207 struct skiplistnode *sl_insert(Skiplist *sl,
208 			       void *data) {
209   if(!sl->compare) return 0;
210   return sl_insert_compare(sl, data, sl->compare);
211 }
212 
sl_insert_compare(Skiplist * sl,void * data,SkiplistComparator comp)213 struct skiplistnode *sl_insert_compare(Skiplist *sl,
214 				       void *data,
215 				       SkiplistComparator comp) {
216   struct skiplistnode *m, *p, *tmp, *ret, **stack;
217   int nh=1, ch, stacki;
218   ret = NULL;
219 /*sl_print_struct(sl, "BI: ");*/
220   if(!sl->top) {
221     sl->height = 1;
222     sl->topend = sl->bottomend = sl->top = sl->bottom =
223       (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
224     assert(sl->top);
225     sl->top->next = sl->top->data = sl->top->prev =
226 	sl->top->up = sl->top->down =
227 	sl->top->nextindex = sl->top->previndex = NULL;
228     sl->top->sl = sl;
229   }
230   if(sl->preheight) {
231     while(nh < sl->preheight && get_b_rand()) nh++;
232   } else {
233     while(nh <= sl->height && get_b_rand()) nh++;
234   }
235   /* Now we have the new height at which we wish to insert our new node */
236   /* Let us make sure that our tree is a least that tall (grow if necessary)*/
237   for(;sl->height<nh;sl->height++) {
238     sl->top->up =
239       (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
240     assert(sl->top->up);
241     sl->top->up->down = sl->top;
242     sl->top = sl->topend = sl->top->up;
243     sl->top->prev = sl->top->next = sl->top->nextindex =
244       sl->top->previndex = sl->top->up = NULL;
245     sl->top->data = NULL;
246     sl->top->sl = sl;
247   }
248   ch = sl->height;
249   /* Find the node (or node after which we would insert) */
250   /* Keep a stack to pop back through for insertion */
251   m = sl->top;
252   stack = (struct skiplistnode **)malloc(sizeof(struct skiplistnode *)*(nh));
253   stacki=0;
254   while(m) {
255     int compared=-1;
256     if(m->next) compared=comp(data, m->next->data);
257     if(compared == 0) {
258       free(stack);
259       return 0;
260     }
261     if((m->next == NULL) || (compared<0)) {
262             /* FIXME: This if ch<=nh test looks unnecessary. ch==nh at beginning of while(m)
263              */
264       if(ch<=nh) {
265 	/* push on stack */
266 	stack[stacki++] = m;
267       }
268       m = m->down;
269       ch--;
270     } else {
271       m = m->next;
272     }
273   }
274   /* Pop the stack and insert nodes */
275   p = tmp = NULL;
276   for(;stacki>0;stacki--) {
277     m = stack[stacki-1];
278     tmp = (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
279     tmp->next = m->next;
280     if(m->next) m->next->prev=tmp;
281     tmp->prev = m;
282     tmp->up = NULL;
283     tmp->nextindex = tmp->previndex = NULL;
284     tmp->down = p;
285     if(p) p->up=tmp;
286     tmp->data = data;
287     tmp->sl = sl;
288     m->next = tmp;
289     /* This sets ret to the bottom-most node we are inserting */
290     if(!p)
291     {
292             ret=tmp;
293             sl->size++;
294     }
295     p = tmp;
296   }
297   free(stack);
298   if(tmp && (tmp->prev == sl->topend)) {
299     /* The last element on the top row is the new inserted one */
300     sl->topend = tmp;
301   }
302   if(ret && (ret->prev == sl->bottomend)) {
303     /* The last element on the bottom row is the new inserted one */
304     sl->bottomend = ret;
305   }
306   if(sl->index != NULL) {
307     /* this is a external insertion, we must insert into each index as well */
308     struct skiplistnode *p, *ni, *li;
309     li=ret;
310     for(p = sl_getlist(sl->index); p; sl_next(sl->index, &p)) {
311       ni = sl_insert((Skiplist *)p->data, ret->data);
312       assert(ni);
313       Alarm(SKIPLIST, "Adding %p to index %p\n", ret->data, p->data);
314       li->nextindex = ni;
315       ni->previndex = li;
316       li = ni;
317     }
318   }
319   /* JRS: move size increment above to where node is inserted
320     else {
321     sl->size++;
322   }
323   */
324 /*sl_print_struct(sl, "AI: ");*/
325   return ret;
326 }
sl_append(Skiplist * sl,void * data)327 struct skiplistnode *sl_append(Skiplist *sl, void *data) {
328   return sl_insert(sl, data);
329 }
330 #if 0
331 struct skiplistnode *sl_append(Skiplist *sl, void *data) {
332   int nh=1, ch, compared;
333   struct skiplistnode *lastnode, *nodeago;
334   if(sl->bottomend != sl->bottom) {
335     compared=sl->compare(data, sl->bottomend->prev->data);
336     /* If it doesn't belong at the end, then fail */
337     if(compared<=0) return NULL;
338   }
339   if(sl->preheight) {
340     while(nh < sl->preheight && get_b_rand()) nh++;
341   } else {
342     while(nh <= sl->height && get_b_rand()) nh++;
343   }
344   /* Now we have the new hieght at which we wish to insert our new node */
345   /* Let us make sure that our tree is a least that tall (grow if necessary)*/
346   lastnode = sl->bottomend;
347   nodeago = NULL;
348 
349   if(!lastnode) return sl_insert(sl, data);
350 
351   for(;sl->height<nh;sl->height++) {
352     assert(sl->top);
353     sl->top->up =
354       (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
355     sl->top->up->down = sl->top;
356     sl->top = sl->topend = sl->top->up;
357     sl->top->prev = sl->top->next = sl->top->nextindex =
358       sl->top->previndex = NULL;
359     sl->top->data = NULL;
360     sl->top->sl = sl;
361   }
362   ch = sl->height;
363   while(nh) {
364     struct skiplistnode *anode;
365     anode =
366       (struct skiplistnode *)malloc(sizeof(struct skiplistnode));
367     anode->next = lastnode;
368     anode->prev = lastnode->prev;
369     anode->up = NULL;
370     anode->down = nodeago;
371     /* If this the bottom, we are appending, so bottomend should change */
372     if(!nodeago) sl->bottomend = anode;
373     if(lastnode->prev) {
374       if(lastnode == sl->bottom)
375 	sl->bottom = anode;
376       else if (lastnode == sl->top)
377 	sl->top = anode;
378     }
379     nodeago = anode;
380     lastnode = lastnode->up;
381     nh--;
382   }
383   sl->size++;
384   return(nodeago);
385 }
386 #endif
sl_concat(Skiplist * sl1,Skiplist * sl2)387 Skiplist *sl_concat(Skiplist *sl1, Skiplist *sl2) {
388   /* Check integrity! */
389   Skiplist temp;
390   struct skiplistnode *b2;
391   if(sl1->bottomend == NULL || sl1->bottomend->prev == NULL) {
392     sl_remove_all(sl1, free);
393     temp = *sl1;
394     *sl1 = *sl2;
395     *sl2 = temp;
396     /* swap them so that sl2 can be freed normally upon return. */
397     return sl1;
398   }
399   if(sl2->bottom == NULL || sl2->bottom->next == NULL) {
400     sl_remove_all(sl2, free);
401     return sl1;
402   }
403   b2 = sl_getlist(sl2);
404   while(b2) {
405     sl_insert(sl1, b2->data);
406     sl_next(sl2, &b2);
407   }
408   sl_remove_all(sl2, NULL);
409   return sl1;
410 }
411 #if 0
412 Skiplist *sl_concat(Skiplist *sl1, Skiplist *sl2) {
413   /* Check integrity! */
414   int compared, eheight;
415   Skiplist temp;
416   struct skiplistnode *lbottom, *lbottomend, *b1, *e1, *b2, *e2;
417   if(sl1->bottomend == NULL || sl1->bottomend->prev == NULL) {
418     sl_remove_all(sl1, free);
419     temp = *sl1;
420     *sl1 = *sl2;
421     *sl2 = temp;
422     /* swap them so that sl2 can be freed normally upon return. */
423     return sl1;
424   }
425   if(sl2->bottom == NULL || sl2->bottom->next == NULL) {
426     sl_remove_all(sl2, free);
427     return sl1;
428   }
429   compared = sl1->compare(sl1->bottomend->prev->data, sl2->bottom->data);
430   /* If it doesn't belong at the end, then fail */
431   if(compared<=0) return NULL;
432 
433   /* OK now append sl2 onto sl1 */
434   lbottom = lbottomend = NULL;
435   eheight = MIN(sl1->height, sl2->height);
436   b1 = sl1->bottom; e1 = sl1->bottomend;
437   b2 = sl2->bottom; e2 = sl2->bottomend;
438   while(eheight) {
439     e1->prev->next = b2;
440     b2->prev = e1->prev->next;
441     e2->prev->next = e1;
442     e1->prev = e2->prev;
443     e2->prev = NULL;
444     b2 = e2;
445     b1->down = lbottom;
446     e1->down = lbottomend;
447     if(lbottom) lbottom->up = b1;
448     if(lbottomend) lbottomend->up = e1;
449 
450     lbottom = b1;
451     lbottomend = e1;
452   }
453   /* Take the top of the longer one (if it is sl2) and make it sl1's */
454   if(sl2->height > sl1->height) {
455     b1->up = b2->up;
456     e1->up = e2->up;
457     b1->up->down = b1;
458     e1->up->down = e1;
459     sl1->height = sl2->height;
460     sl1->top = sl2->top;
461     sl1->topend = sl2->topend;
462   }
463 
464   /* move the top pointer to here if it isn't there already */
465   sl2->top = sl2->topend = b2;
466   sl2->top->up = NULL; /* If it isn't already */
467   sl1->size += sl2->size;
468   sl_remove_all(sl2, free);
469   return sl1;
470 }
471 #endif
sl_remove(Skiplist * sl,void * data,FreeFunc myfree)472 int sl_remove(Skiplist *sl,
473 	      void *data, FreeFunc myfree) {
474   if(!sl->compare) return 0;
475   return sl_remove_compare(sl, data, myfree, sl->comparek);
476 }
sl_print_struct(Skiplist * sl,char * prefix,char * (* printdata)(void *))477 void sl_print_struct(Skiplist *sl, char *prefix, char *(*printdata)(void *)) {
478   struct skiplistnode *p, *q;
479   Alarm(SKIPLIST, "Skiplist Structure (height: %d)\n", sl->height);
480   p = sl->bottom;
481   while(p) {
482     q = p;
483     Alarm(SKIPLIST, prefix);
484     while(q) {
485       Alarm(SKIPLIST, "%6s ", printdata(q->data));
486       q=q->up;
487     }
488     Alarm(SKIPLIST, "\n");
489     p=p->next;
490   }
491 }
sli_remove(Skiplist * sl,struct skiplistnode * m,FreeFunc myfree)492 int sli_remove(Skiplist *sl, struct skiplistnode *m, FreeFunc myfree) {
493   struct skiplistnode *p;
494   if(!m) return 0;
495   if(m->nextindex) sli_remove(m->nextindex->sl, m->nextindex, NULL);
496   else sl->size--;
497   /*sl_print_struct(sl, "BR:");*/
498   while(m->up) m=m->up;
499   while(m) {
500     p=m;
501     p->prev->next = p->next; /* take me out of the list */
502     if(p->next) p->next->prev = p->prev; /* take me out of the list */
503     m=m->down;
504     /* This only frees the actual data in the bottom one */
505     if(!m && myfree && p->data) myfree(p->data);
506     free(p);
507   }
508   while(sl->top && sl->top->next == NULL) {
509     /* While the row is empty and we are not on the bottom row */
510     p = sl->top;
511     sl->top = sl->top->down; /* Move top down one */
512     if(sl->top) sl->top->up = NULL;      /* Make it think its the top */
513     free(p);
514     sl->height--;
515   }
516   if(!sl->top) sl->bottom = NULL;
517   assert(sl->height>=0);
518   /*sl_print_struct(sl, "AR: ");*/
519   return sl->height;
520 }
sl_remove_compare(Skiplist * sli,void * data,FreeFunc myfree,SkiplistComparator comp)521 int sl_remove_compare(Skiplist *sli,
522 		      void *data,
523 		      FreeFunc myfree, SkiplistComparator comp) {
524   struct skiplistnode *m;
525   Skiplist *sl;
526   if(comp==sli->comparek || !sli->index) {
527     sl = sli;
528   } else {
529     sl_find(sli->index, (void *)comp, &m);
530     assert(m);
531     sl=m->data;
532   }
533   sli_find_compare(sl, data, &m, comp);
534   if (!m) return( 0 );
535   while(m->previndex) m=m->previndex;
536   return sli_remove(sl, m, myfree);
537 }
sl_remove_all(Skiplist * sl,FreeFunc myfree)538 void sl_remove_all(Skiplist *sl, FreeFunc myfree) {
539   /* This must remove even the place holder nodes (bottom though top)
540      because we specify in the API that one can free the Skiplist after
541      making this call without memory leaks */
542   struct skiplistnode *m, *p, *u;
543   m=sl->bottom;
544   while(m) {
545     p = m->next;
546     if(myfree && p && p->data) myfree(p->data);
547     while(m) {
548       u = m->up;
549       free(m);
550       m=u;
551     }
552     m = p;
553   }
554   sl->top = sl->bottom = NULL;
555   sl->height = 0;
556   sl->size = 0;
557 }
sli_destruct_free(Skiplist * sl,FreeFunc myfree)558 void sli_destruct_free(Skiplist *sl, FreeFunc myfree) {
559   sl_remove_all(sl, NULL);
560   free(sl);
561 }
sl_destruct(Skiplist * sl,FreeFunc myfree)562 void sl_destruct(Skiplist *sl, FreeFunc myfree) {
563   if(sl->index) {
564     sl_remove_all(sl->index, (FreeFunc)sli_destruct_free);
565     free(sl->index);
566   }
567   sl_remove_all(sl, myfree);
568 }
569 
570