1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Modified to use APR and APR pools.
19 * TODO: Is malloc() better? Will long running skiplists grow too much?
20 * Keep the skiplist_alloc() and skiplist_free() until we know
21 * Yeah, if using pools it means some bogus cycles for checks
22 * (and an useless function call for skiplist_free) which we
23 * can removed if/when needed.
26 #include "apr_skiplist.h"
29 apr_skiplist_compare compare;
30 apr_skiplist_compare comparek;
34 apr_skiplistnode *top;
35 apr_skiplistnode *bottom;
36 /* These two are needed for appending */
37 apr_skiplistnode *topend;
38 apr_skiplistnode *bottomend;
40 apr_array_header_t *memlist;
44 struct apr_skiplistnode {
46 apr_skiplistnode *next;
47 apr_skiplistnode *prev;
48 apr_skiplistnode *down;
50 apr_skiplistnode *previndex;
51 apr_skiplistnode *nextindex;
56 #define MIN(a,b) ((a<b)?(a):(b))
59 static int get_b_rand(void)
61 static int ph = 32; /* More bits than we will ever use */
62 static apr_uint32_t randseq;
63 if (ph > 31) { /* Num bits in return of rand() */
65 randseq = (apr_uint32_t) rand();
68 return ((randseq & (1 << (ph - 1))) >> (ph - 1));
73 apr_array_header_t *list;
81 APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size)
88 memlist_t *memlist = (memlist_t *)sl->memlist->elts;
89 for (i = 0; i < sl->memlist->nelts; i++) {
90 if (memlist->size == size) {
92 chunk_t *chunk = (chunk_t *)memlist->list->elts;
94 for (j = 0; j < memlist->list->nelts; j++) {
101 break; /* no free of this size; punt */
106 ptr = apr_pcalloc(sl->pool, size);
111 * is this a new sized chunk? If so, we need to create a new
112 * array of them. Otherwise, re-use what we already have.
115 memlist = apr_array_push(sl->memlist);
116 memlist->size = size;
117 memlist->list = apr_array_make(sl->pool, 20, sizeof(chunk_t));
119 newchunk = apr_array_push(memlist->list);
125 return calloc(1, size);
129 APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem)
136 memlist_t *memlist = (memlist_t *)sl->memlist->elts;
137 for (i = 0; i < sl->memlist->nelts; i++) {
139 chunk_t *chunk = (chunk_t *)memlist->list->elts;
140 for (j = 0; j < memlist->list->nelts; j++) {
141 if (chunk->ptr == mem) {
152 static apr_status_t skiplisti_init(apr_skiplist **s, apr_pool_t *p)
156 sl = apr_pcalloc(p, sizeof(apr_skiplist));
157 sl->memlist = apr_array_make(p, 20, sizeof(memlist_t));
160 sl = calloc(1, sizeof(apr_skiplist));
163 sl->compare = (apr_skiplist_compare) NULL;
164 sl->comparek = (apr_skiplist_compare) NULL;
177 static int indexing_comp(void *a, void *b)
179 void *ac = (void *) (((apr_skiplist *) a)->compare);
180 void *bc = (void *) (((apr_skiplist *) b)->compare);
181 return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
184 static int indexing_compk(void *ac, void *b)
186 void *bc = (void *) (((apr_skiplist *) b)->compare);
187 return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
190 APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **s, apr_pool_t *p)
193 skiplisti_init(s, p);
195 skiplisti_init(&(sl->index), p);
196 apr_skiplist_set_compare(sl->index, indexing_comp, indexing_compk);
200 APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl,
201 apr_skiplist_compare comp,
202 apr_skiplist_compare compk)
204 if (sl->compare && sl->comparek) {
205 apr_skiplist_add_index(sl, comp, compk);
209 sl->comparek = compk;
213 APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl,
214 apr_skiplist_compare comp,
215 apr_skiplist_compare compk)
220 apr_skiplist_find(sl->index, (void *)comp, &m);
222 return; /* Index already there! */
224 skiplisti_init(&ni, sl->pool);
225 apr_skiplist_set_compare(ni, comp, compk);
226 /* Build the new index... This can be expensive! */
227 m = apr_skiplist_insert(sl->index, ni);
232 for (m = apr_skiplist_getlist(sl); m; apr_skiplist_next(sl, &m)) {
234 apr_skiplistnode *nsln;
235 nsln = apr_skiplist_insert(ni, m->data);
236 /* skip from main index down list */
241 /* insert this node in the indexlist after m */
242 nsln->nextindex = m->nextindex;
244 m->nextindex->previndex = nsln;
251 APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl)
256 return sl->bottom->next;
259 APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter)
262 apr_skiplistnode *aiter;
267 ret = apr_skiplist_find_compare(sl, data, iter, sl->compare);
270 ret = apr_skiplist_find_compare(sl, data, &aiter, sl->compare);
275 static int skiplisti_find_compare(apr_skiplist *sl, void *data,
276 apr_skiplistnode **ret,
277 apr_skiplist_compare comp)
279 apr_skiplistnode *m = NULL;
284 compared = (m->next) ? comp(data, m->next->data) : -1;
293 if ((m->next == NULL) || (compared < 0)) {
306 APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sli, void *data,
307 apr_skiplistnode **iter,
308 apr_skiplist_compare comp)
310 apr_skiplistnode *m = NULL;
312 if (comp == sli->compare || !sli->index) {
316 apr_skiplist_find(sli->index, (void *)comp, &m);
317 sl = (apr_skiplist *) m->data;
319 skiplisti_find_compare(sl, data, iter, sl->comparek);
320 return (iter && *iter) ? ((*iter)->data) : NULL;
324 APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter)
329 *iter = (*iter)->next;
330 return (*iter) ? ((*iter)->data) : NULL;
333 APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter)
338 *iter = (*iter)->prev;
339 return (*iter) ? ((*iter)->data) : NULL;
342 APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist *sl, void *data)
347 return apr_skiplist_insert_compare(sl, data, sl->compare);
350 APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl, void *data,
351 apr_skiplist_compare comp)
353 apr_skiplistnode *m, *p, *tmp, *ret = NULL, **stack;
354 int nh = 1, ch, stacki;
357 sl->topend = sl->bottomend = sl->top = sl->bottom =
358 (apr_skiplistnode *)apr_skiplist_alloc(sl, sizeof(apr_skiplistnode));
360 sl->top->next = (apr_skiplistnode *)NULL;
361 sl->top->data = (apr_skiplistnode *)NULL;
362 sl->top->prev = (apr_skiplistnode *)NULL;
363 sl->top->up = (apr_skiplistnode *)NULL;
364 sl->top->down = (apr_skiplistnode *)NULL;
365 sl->top->nextindex = (apr_skiplistnode *)NULL;
366 sl->top->previndex = (apr_skiplistnode *)NULL;
371 while (nh < sl->preheight && get_b_rand()) {
376 while (nh <= sl->height && get_b_rand()) {
380 /* Now we have the new height at which we wish to insert our new node */
382 * Let us make sure that our tree is a least that tall (grow if
385 for (; sl->height < nh; sl->height++) {
387 (apr_skiplistnode *)apr_skiplist_alloc(sl, sizeof(apr_skiplistnode));
388 sl->top->up->down = sl->top;
389 sl->top = sl->topend = sl->top->up;
391 sl->top->prev = sl->top->next = sl->top->nextindex =
392 sl->top->previndex = sl->top->up = NULL;
393 sl->top->data = NULL;
398 /* Find the node (or node after which we would insert) */
399 /* Keep a stack to pop back through for insertion */
400 /* malloc() is OK since we free the temp stack */
402 stack = (apr_skiplistnode **)malloc(sizeof(apr_skiplistnode *) * (nh));
407 compared = comp(data, m->next->data);
410 free(stack); /* OK. was malloc'ed */
413 if ((m->next == NULL) || (compared < 0)) {
425 /* Pop the stack and insert nodes */
427 for (; stacki > 0; stacki--) {
428 m = stack[stacki - 1];
429 tmp = (apr_skiplistnode *)apr_skiplist_alloc(sl, sizeof(apr_skiplistnode));
436 tmp->nextindex = tmp->previndex = NULL;
444 /* This sets ret to the bottom-most node we are inserting */
447 sl->size++; /* this seems to go here got each element to be counted */
451 free(stack); /* OK. was malloc'ed */
452 if (sl->index != NULL) {
454 * this is a external insertion, we must insert into each index as
457 apr_skiplistnode *ni, *li;
459 for (p = apr_skiplist_getlist(sl->index); p; apr_skiplist_next(sl->index, &p)) {
460 ni = apr_skiplist_insert((apr_skiplist *) p->data, ret->data);
473 APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree)
478 return apr_skiplist_remove_compare(sl, data, myfree, sl->comparek);
482 void skiplist_print_struct(apr_skiplist * sl, char *prefix)
484 apr_skiplistnode *p, *q;
485 fprintf(stderr, "Skiplist Structure (height: %d)\n", sl->height);
489 fprintf(stderr, prefix);
491 fprintf(stderr, "%p ", q->data);
494 fprintf(stderr, "\n");
500 static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m, apr_skiplist_freefunc myfree)
507 skiplisti_remove(m->nextindex->sl, m->nextindex, NULL);
514 p->prev->next = p->next;/* take me out of the list */
516 p->next->prev = p->prev; /* take me out of the list */
519 /* This only frees the actual data in the bottom one */
520 if (!m && myfree && p->data) {
523 apr_skiplist_free(sl, p);
526 while (sl->top && sl->top->next == NULL) {
527 /* While the row is empty and we are not on the bottom row */
529 sl->top = sl->top->down;/* Move top down one */
531 sl->top->up = NULL; /* Make it think its the top */
533 apr_skiplist_free(sl, p);
539 return sl->height; /* return 1; ?? */
542 APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sli,
544 apr_skiplist_freefunc myfree, apr_skiplist_compare comp)
548 if (comp == sli->comparek || !sli->index) {
552 apr_skiplist_find(sli->index, (void *)comp, &m);
553 sl = (apr_skiplist *) m->data;
555 skiplisti_find_compare(sl, data, &m, comp);
559 while (m->previndex) {
562 return skiplisti_remove(sl, m, myfree);
565 APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree)
568 * This must remove even the place holder nodes (bottom though top)
569 * because we specify in the API that one can free the Skiplist after
570 * making this call without memory leaks
572 apr_skiplistnode *m, *p, *u;
576 if (p && myfree && p->data)
580 apr_skiplist_free(sl, p);
585 sl->top = sl->bottom = NULL;
590 APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *a, apr_skiplist_freefunc myfree)
592 apr_skiplistnode *sln;
594 sln = apr_skiplist_getlist(a);
597 skiplisti_remove(a, sln, myfree);
602 APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *a)
604 apr_skiplistnode *sln;
605 sln = apr_skiplist_getlist(a);
612 static void skiplisti_destroy(void *vsl)
614 apr_skiplist_destroy((apr_skiplist *) vsl, NULL);
615 apr_skiplist_free((apr_skiplist *) vsl, vsl);
618 APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree)
620 while (apr_skiplist_pop(sl->index, skiplisti_destroy) != NULL)
622 apr_skiplist_remove_all(sl, myfree);
625 APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2)
627 /* Check integrity! */
629 struct apr_skiplistnode *b2;
630 if (sl1->bottomend == NULL || sl1->bottomend->prev == NULL) {
631 apr_skiplist_remove_all(sl1, NULL);
635 /* swap them so that sl2 can be freed normally upon return. */
638 if(sl2->bottom == NULL || sl2->bottom->next == NULL) {
639 apr_skiplist_remove_all(sl2, NULL);
642 /* This is what makes it brute force... Just insert :/ */
643 b2 = apr_skiplist_getlist(sl2);
645 apr_skiplist_insert(sl1, b2->data);
646 apr_skiplist_next(sl2, &b2);
648 apr_skiplist_remove_all(sl2, NULL);