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