You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by ji...@apache.org on 2013/09/30 15:07:52 UTC

svn commit: r1527540 - in /apr/apr/trunk: apr.dsp include/apr_skiplist.h libapr.dsp tables/apr_skiplist.c

Author: jim
Date: Mon Sep 30 13:07:52 2013
New Revision: 1527540

URL: http://svn.apache.org/r1527540
Log:
Add in apr_skiplist

Added:
    apr/apr/trunk/include/apr_skiplist.h   (with props)
    apr/apr/trunk/tables/apr_skiplist.c   (with props)
Modified:
    apr/apr/trunk/apr.dsp
    apr/apr/trunk/libapr.dsp

Modified: apr/apr/trunk/apr.dsp
URL: http://svn.apache.org/viewvc/apr/apr/trunk/apr.dsp?rev=1527540&r1=1527539&r2=1527540&view=diff
==============================================================================
--- apr/apr/trunk/apr.dsp (original)
+++ apr/apr/trunk/apr.dsp Mon Sep 30 13:07:52 2013
@@ -658,6 +658,10 @@ SOURCE=.\tables\apr_hash.c
 
 SOURCE=.\tables\apr_tables.c
 # End Source File
+# Begin Source File
+
+SOURCE=.\tables\apr_skiplist.c
+# End Source File
 # End Group
 # Begin Group "threadproc"
 
@@ -966,6 +970,10 @@ SOURCE=.\include\apr_signal.h
 # End Source File
 # Begin Source File
 
+SOURCE=.\include\apr_skiplist.h
+# End Source File
+# Begin Source File
+
 SOURCE=.\include\apr_strings.h
 # End Source File
 # Begin Source File

Added: apr/apr/trunk/include/apr_skiplist.h
URL: http://svn.apache.org/viewvc/apr/apr/trunk/include/apr_skiplist.h?rev=1527540&view=auto
==============================================================================
--- apr/apr/trunk/include/apr_skiplist.h (added)
+++ apr/apr/trunk/include/apr_skiplist.h Mon Sep 30 13:07:52 2013
@@ -0,0 +1,82 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _APR_SKIPLIST_P_H
+#define _APR_SKIPLIST_P_H
+
+#include "apr.h"
+#include "apr_portable.h"
+#include <stdlib.h>
+
+
+/* This is the function type that must be implemented per object type
+   that is used in a skiplist for comparisons to maintain order */
+typedef int (*apr_skiplist_compare) (void *, void *);
+typedef void (*apr_skiplist_freefunc) (void *);
+
+struct apr_skiplist;
+struct apr_skiplistnode;
+
+typedef struct apr_skiplistnode apr_skiplistnode;
+typedef struct apr_skiplist apr_skiplist;
+
+APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size);
+
+APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem);
+
+APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **sl, apr_pool_t *p);
+
+APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl, apr_skiplist_compare,
+                             apr_skiplist_compare);
+
+APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl, apr_skiplist_compare,
+                        apr_skiplist_compare);
+
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl);
+
+APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sl,
+                               void *data,
+                               apr_skiplistnode **iter,
+                               apr_skiplist_compare func);
+
+APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter);
+
+APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter);
+
+APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter);
+
+
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl,
+                                          void *data, apr_skiplist_compare comp);
+
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist* sl, void *data);
+
+APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sl, void *data,
+                               apr_skiplist_freefunc myfree, apr_skiplist_compare comp);
+
+APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree);
+
+APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree);
+
+APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree);
+
+APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *a, apr_skiplist_freefunc myfree);
+
+APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *a);
+
+APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2);
+
+#endif

Propchange: apr/apr/trunk/include/apr_skiplist.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: apr/apr/trunk/libapr.dsp
URL: http://svn.apache.org/viewvc/apr/apr/trunk/libapr.dsp?rev=1527540&r1=1527539&r2=1527540&view=diff
==============================================================================
--- apr/apr/trunk/libapr.dsp (original)
+++ apr/apr/trunk/libapr.dsp Mon Sep 30 13:07:52 2013
@@ -688,11 +688,14 @@ SOURCE=.\strmatch\apr_strmatch.c
 # Begin Source File
 
 SOURCE=.\tables\apr_hash.c
-# End Source File
 # Begin Source File
 
 SOURCE=.\tables\apr_tables.c
 # End Source File
+# Begin Source File
+
+SOURCE=.\tables\apr_skiplist.c
+# End Source File
 # End Group
 # Begin Group "threadproc"
 
@@ -1001,6 +1004,10 @@ SOURCE=.\include\apr_signal.h
 # End Source File
 # Begin Source File
 
+SOURCE=.\include\apr_skiplist.h
+# End Source File
+# Begin Source File
+
 SOURCE=.\include\apr_strings.h
 # End Source File
 # Begin Source File

Added: apr/apr/trunk/tables/apr_skiplist.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/tables/apr_skiplist.c?rev=1527540&view=auto
==============================================================================
--- apr/apr/trunk/tables/apr_skiplist.c (added)
+++ apr/apr/trunk/tables/apr_skiplist.c Mon Sep 30 13:07:52 2013
@@ -0,0 +1,650 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Modified to use APR and APR pools.
+ *  TODO: Is malloc() better? Will long running skiplists grow too much?
+ *  Keep the skiplist_alloc() and skiplist_free() until we know
+ *  Yeah, if using pools it means some bogus cycles for checks
+ *  (and an useless function call for skiplist_free) which we
+ *  can removed if/when needed.
+ */
+
+#include "apr_skiplist.h"
+
+struct apr_skiplist {
+    apr_skiplist_compare compare;
+    apr_skiplist_compare comparek;
+    int height;
+    int preheight;
+    int size;
+    apr_skiplistnode *top;
+    apr_skiplistnode *bottom;
+    /* These two are needed for appending */
+    apr_skiplistnode *topend;
+    apr_skiplistnode *bottomend;
+    apr_skiplist *index;
+    apr_array_header_t *memlist;
+    apr_pool_t *pool;
+};
+
+struct apr_skiplistnode {
+    void *data;
+    apr_skiplistnode *next;
+    apr_skiplistnode *prev;
+    apr_skiplistnode *down;
+    apr_skiplistnode *up;
+    apr_skiplistnode *previndex;
+    apr_skiplistnode *nextindex;
+    apr_skiplist *sl;
+};
+
+#ifndef MIN
+#define MIN(a,b) ((a<b)?(a):(b))
+#endif
+
+static int get_b_rand(void)
+{
+    static int ph = 32;         /* More bits than we will ever use */
+    static apr_uint32_t randseq;
+    if (ph > 31) {              /* Num bits in return of rand() */
+        ph = 0;
+        randseq = (apr_uint32_t) rand();
+    }
+    ph++;
+    return ((randseq & (1 << (ph - 1))) >> (ph - 1));
+}
+
+typedef struct {
+    size_t size;
+    apr_array_header_t *list;
+} memlist_t;
+
+typedef struct {
+    void *ptr;
+    char inuse;
+} chunk_t;
+
+APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size)
+{
+    if (sl->pool) {
+        void *ptr;
+        int found_size = 0;
+        int i;
+        chunk_t *newchunk;
+        memlist_t *memlist = (memlist_t *)sl->memlist->elts;
+        for (i = 0; i < sl->memlist->nelts; i++) {
+            if (memlist->size == size) {
+                int j;
+                chunk_t *chunk = (chunk_t *)memlist->list->elts;
+                found_size = 1;
+                for (j = 0; j < memlist->list->nelts; j++) {
+                    if (!chunk->inuse) {
+                        chunk->inuse = 1;
+                        return chunk->ptr;
+                    }
+                    chunk++;
+                }
+                break; /* no free of this size; punt */
+            }
+            memlist++;
+        }
+        /* no free chunks */
+        ptr = apr_pcalloc(sl->pool, size);
+        if (!ptr) {
+            return ptr;
+        }
+        /*
+         * is this a new sized chunk? If so, we need to create a new
+         * array of them. Otherwise, re-use what we already have.
+         */
+        if (!found_size) {
+            memlist = apr_array_push(sl->memlist);
+            memlist->size = size;
+            memlist->list = apr_array_make(sl->pool, 20, sizeof(chunk_t));
+        }
+        newchunk = apr_array_push(memlist->list);
+        newchunk->ptr = ptr;
+        newchunk->inuse = 1;
+        return ptr;
+    }
+    else {
+        return calloc(1, size);
+    }
+}
+
+APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem)
+{
+    if (!sl->pool) {
+        free(mem);
+    }
+    else {
+        int i;
+        memlist_t *memlist = (memlist_t *)sl->memlist->elts;
+        for (i = 0; i < sl->memlist->nelts; i++) {
+            int j;
+            chunk_t *chunk = (chunk_t *)memlist->list->elts;
+            for (j = 0; j < memlist->list->nelts; j++) {
+                if (chunk->ptr == mem) {
+                    chunk->inuse = 0;
+                    return;
+                }
+                chunk++;
+            }
+            memlist++;
+        }
+    }
+}
+
+static apr_status_t skiplisti_init(apr_skiplist **s, apr_pool_t *p)
+{
+    apr_skiplist *sl;
+    if (p) {
+        sl = apr_pcalloc(p, sizeof(apr_skiplist));
+        sl->memlist = apr_array_make(p, 20, sizeof(memlist_t));
+    }
+    else {
+        sl = calloc(1, sizeof(apr_skiplist));
+    }
+#if 0
+    sl->compare = (apr_skiplist_compare) NULL;
+    sl->comparek = (apr_skiplist_compare) NULL;
+    sl->height = 0;
+    sl->preheight = 0;
+    sl->size = 0;
+    sl->top = NULL;
+    sl->bottom = NULL;
+    sl->index = NULL;
+#endif
+    sl->pool = p;
+    *s = sl;
+    return APR_SUCCESS;
+}
+
+static int indexing_comp(void *a, void *b)
+{
+    void *ac = (void *) (((apr_skiplist *) a)->compare);
+    void *bc = (void *) (((apr_skiplist *) b)->compare);
+    return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
+}
+
+static int indexing_compk(void *ac, void *b)
+{
+    void *bc = (void *) (((apr_skiplist *) b)->compare);
+    return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
+}
+
+APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **s, apr_pool_t *p)
+{
+    apr_skiplist *sl;
+    skiplisti_init(s, p);
+    sl = *s;
+    skiplisti_init(&(sl->index), p);
+    apr_skiplist_set_compare(sl->index, indexing_comp, indexing_compk);
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl,
+                          apr_skiplist_compare comp,
+                          apr_skiplist_compare compk)
+{
+    if (sl->compare && sl->comparek) {
+        apr_skiplist_add_index(sl, comp, compk);
+    }
+    else {
+        sl->compare = comp;
+        sl->comparek = compk;
+    }
+}
+
+APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl,
+                        apr_skiplist_compare comp,
+                        apr_skiplist_compare compk)
+{
+    apr_skiplistnode *m;
+    apr_skiplist *ni;
+    int icount = 0;
+    apr_skiplist_find(sl->index, (void *)comp, &m);
+    if (m) {
+        return;                 /* Index already there! */
+    }
+    skiplisti_init(&ni, sl->pool);
+    apr_skiplist_set_compare(ni, comp, compk);
+    /* Build the new index... This can be expensive! */
+    m = apr_skiplist_insert(sl->index, ni);
+    while (m->prev) {
+        m = m->prev;
+        icount++;
+    }
+    for (m = apr_skiplist_getlist(sl); m; apr_skiplist_next(sl, &m)) {
+        int j = icount - 1;
+        apr_skiplistnode *nsln;
+        nsln = apr_skiplist_insert(ni, m->data);
+        /* skip from main index down list */
+        while (j > 0) {
+            m = m->nextindex;
+            j--;
+        }
+        /* insert this node in the indexlist after m */
+        nsln->nextindex = m->nextindex;
+        if (m->nextindex) {
+            m->nextindex->previndex = nsln;
+        }
+        nsln->previndex = m;
+        m->nextindex = nsln;
+    }
+}
+
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl)
+{
+    if (!sl->bottom) {
+        return NULL;
+    }
+    return sl->bottom->next;
+}
+
+APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter)
+{
+    void *ret;
+    apr_skiplistnode *aiter;
+    if (!sl->compare) {
+        return 0;
+    }
+    if (iter) {
+        ret = apr_skiplist_find_compare(sl, data, iter, sl->compare);
+    }
+    else {
+        ret = apr_skiplist_find_compare(sl, data, &aiter, sl->compare);
+    }
+    return ret;
+}
+
+static int skiplisti_find_compare(apr_skiplist *sl, void *data,
+                           apr_skiplistnode **ret,
+                           apr_skiplist_compare comp)
+{
+    apr_skiplistnode *m = NULL;
+    int count = 0;
+    m = sl->top;
+    while (m) {
+        int compared;
+        compared = (m->next) ? comp(data, m->next->data) : -1;
+        if (compared == 0) {
+            m = m->next;
+            while (m->down) {
+                m = m->down;
+            }
+            *ret = m;
+            return count;
+        }
+        if ((m->next == NULL) || (compared < 0)) {
+            m = m->down;
+            count++;
+        }
+        else {
+            m = m->next;
+            count++;
+        }
+    }
+    *ret = NULL;
+    return count;
+}
+
+APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sli, void *data,
+                               apr_skiplistnode **iter,
+                               apr_skiplist_compare comp)
+{
+    apr_skiplistnode *m = NULL;
+    apr_skiplist *sl;
+    if (comp == sli->compare || !sli->index) {
+        sl = sli;
+    }
+    else {
+        apr_skiplist_find(sli->index, (void *)comp, &m);
+        sl = (apr_skiplist *) m->data;
+    }
+    skiplisti_find_compare(sl, data, iter, sl->comparek);
+    return (iter && *iter) ? ((*iter)->data) : NULL;
+}
+
+
+APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter)
+{
+    if (!*iter) {
+        return NULL;
+    }
+    *iter = (*iter)->next;
+    return (*iter) ? ((*iter)->data) : NULL;
+}
+
+APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter)
+{
+    if (!*iter) {
+        return NULL;
+    }
+    *iter = (*iter)->prev;
+    return (*iter) ? ((*iter)->data) : NULL;
+}
+
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist *sl, void *data)
+{
+    if (!sl->compare) {
+        return 0;
+    }
+    return apr_skiplist_insert_compare(sl, data, sl->compare);
+}
+
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl, void *data,
+                                      apr_skiplist_compare comp)
+{
+    apr_skiplistnode *m, *p, *tmp, *ret = NULL, **stack;
+    int nh = 1, ch, stacki;
+    if (!sl->top) {
+        sl->height = 1;
+        sl->topend = sl->bottomend = sl->top = sl->bottom =
+            (apr_skiplistnode *)apr_skiplist_alloc(sl, sizeof(apr_skiplistnode));
+#if 0
+        sl->top->next = (apr_skiplistnode *)NULL;
+        sl->top->data = (apr_skiplistnode *)NULL;
+        sl->top->prev = (apr_skiplistnode *)NULL;
+        sl->top->up = (apr_skiplistnode *)NULL;
+        sl->top->down = (apr_skiplistnode *)NULL;
+        sl->top->nextindex = (apr_skiplistnode *)NULL;
+        sl->top->previndex = (apr_skiplistnode *)NULL;
+#endif
+        sl->top->sl = sl;
+    }
+    if (sl->preheight) {
+        while (nh < sl->preheight && get_b_rand()) {
+            nh++;
+        }
+    }
+    else {
+        while (nh <= sl->height && get_b_rand()) {
+            nh++;
+        }
+    }
+    /* Now we have the new height at which we wish to insert our new node */
+    /*
+     * Let us make sure that our tree is a least that tall (grow if
+     * necessary)
+     */
+    for (; sl->height < nh; sl->height++) {
+        sl->top->up =
+            (apr_skiplistnode *)apr_skiplist_alloc(sl, sizeof(apr_skiplistnode));
+        sl->top->up->down = sl->top;
+        sl->top = sl->topend = sl->top->up;
+#if 0
+        sl->top->prev = sl->top->next = sl->top->nextindex =
+            sl->top->previndex = sl->top->up = NULL;
+        sl->top->data = NULL;
+#endif
+        sl->top->sl = sl;
+    }
+    ch = sl->height;
+    /* Find the node (or node after which we would insert) */
+    /* Keep a stack to pop back through for insertion */
+    /* malloc() is OK since we free the temp stack */
+    m = sl->top;
+    stack = (apr_skiplistnode **)malloc(sizeof(apr_skiplistnode *) * (nh));
+    stacki = 0;
+    while (m) {
+        int compared = -1;
+        if (m->next) {
+            compared = comp(data, m->next->data);
+        }
+        if (compared == 0) {
+            free(stack);    /* OK. was malloc'ed */
+            return 0;
+        }
+        if ((m->next == NULL) || (compared < 0)) {
+            if (ch <= nh) {
+                /* push on stack */
+                stack[stacki++] = m;
+            }
+            m = m->down;
+            ch--;
+        }
+        else {
+            m = m->next;
+        }
+    }
+    /* Pop the stack and insert nodes */
+    p = NULL;
+    for (; stacki > 0; stacki--) {
+        m = stack[stacki - 1];
+        tmp = (apr_skiplistnode *)apr_skiplist_alloc(sl, sizeof(apr_skiplistnode));
+        tmp->next = m->next;
+        if (m->next) {
+            m->next->prev = tmp;
+        }
+        tmp->prev = m;
+        tmp->up = NULL;
+        tmp->nextindex = tmp->previndex = NULL;
+        tmp->down = p;
+        if (p) {
+            p->up = tmp;
+        }
+        tmp->data = data;
+        tmp->sl = sl;
+        m->next = tmp;
+        /* This sets ret to the bottom-most node we are inserting */
+        if (!p) {
+            ret = tmp;
+            sl->size++; /* this seems to go here got each element to be counted */
+        }
+        p = tmp;
+    }
+    free(stack); /* OK. was malloc'ed */
+    if (sl->index != NULL) {
+        /*
+         * this is a external insertion, we must insert into each index as
+         * well
+         */
+        apr_skiplistnode *ni, *li;
+        li = ret;
+        for (p = apr_skiplist_getlist(sl->index); p; apr_skiplist_next(sl->index, &p)) {
+            ni = apr_skiplist_insert((apr_skiplist *) p->data, ret->data);
+            li->nextindex = ni;
+            ni->previndex = li;
+            li = ni;
+        }
+    }
+    else {
+        /* sl->size++; */
+    }
+    sl->size++;
+    return ret;
+}
+
+APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree)
+{
+    if (!sl->compare) {
+        return 0;
+    }
+    return apr_skiplist_remove_compare(sl, data, myfree, sl->comparek);
+}
+
+#if 0
+void skiplist_print_struct(apr_skiplist * sl, char *prefix)
+{
+    apr_skiplistnode *p, *q;
+    fprintf(stderr, "Skiplist Structure (height: %d)\n", sl->height);
+    p = sl->bottom;
+    while (p) {
+        q = p;
+        fprintf(stderr, prefix);
+        while (q) {
+            fprintf(stderr, "%p ", q->data);
+            q = q->up;
+        }
+        fprintf(stderr, "\n");
+        p = p->next;
+    }
+}
+#endif
+
+static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m, apr_skiplist_freefunc myfree)
+{
+    apr_skiplistnode *p;
+    if (!m) {
+        return 0;
+    }
+    if (m->nextindex) {
+        skiplisti_remove(m->nextindex->sl, m->nextindex, NULL);
+    }
+    while (m->up) {
+        m = m->up;
+    }
+    while (m) {
+        p = m;
+        p->prev->next = p->next;/* take me out of the list */
+        if (p->next) {
+            p->next->prev = p->prev;    /* take me out of the list */
+        }
+        m = m->down;
+        /* This only frees the actual data in the bottom one */
+        if (!m && myfree && p->data) {
+            myfree(p->data);
+        }
+        apr_skiplist_free(sl, p);
+    }
+    sl->size--;
+    while (sl->top && sl->top->next == NULL) {
+        /* While the row is empty and we are not on the bottom row */
+        p = sl->top;
+        sl->top = sl->top->down;/* Move top down one */
+        if (sl->top) {
+            sl->top->up = NULL; /* Make it think its the top */
+        }
+        apr_skiplist_free(sl, p);
+        sl->height--;
+    }
+    if (!sl->top) {
+        sl->bottom = NULL;
+    }
+    return sl->height;  /* return 1; ?? */
+}
+
+APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sli,
+                            void *data,
+                            apr_skiplist_freefunc myfree, apr_skiplist_compare comp)
+{
+    apr_skiplistnode *m;
+    apr_skiplist *sl;
+    if (comp == sli->comparek || !sli->index) {
+        sl = sli;
+    }
+    else {
+        apr_skiplist_find(sli->index, (void *)comp, &m);
+        sl = (apr_skiplist *) m->data;
+    }
+    skiplisti_find_compare(sl, data, &m, comp);
+    if (!m) {
+        return 0;
+    }
+    while (m->previndex) {
+        m = m->previndex;
+    }
+    return skiplisti_remove(sl, m, myfree);
+}
+
+APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree)
+{
+    /*
+     * This must remove even the place holder nodes (bottom though top)
+     * because we specify in the API that one can free the Skiplist after
+     * making this call without memory leaks
+     */
+    apr_skiplistnode *m, *p, *u;
+    m = sl->bottom;
+    while (m) {
+        p = m->next;
+        if (p && myfree && p->data)
+            myfree(p->data);
+        while (m) {
+            u = m->up;
+            apr_skiplist_free(sl, p);
+            m = u;
+        }
+        m = p;
+    }
+    sl->top = sl->bottom = NULL;
+    sl->height = 0;
+    sl->size = 0;
+}
+
+APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *a, apr_skiplist_freefunc myfree)
+{
+    apr_skiplistnode *sln;
+    void *data = NULL;
+    sln = apr_skiplist_getlist(a);
+    if (sln) {
+        data = sln->data;
+        skiplisti_remove(a, sln, myfree);
+    }
+    return data;
+}
+
+APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *a)
+{
+    apr_skiplistnode *sln;
+    sln = apr_skiplist_getlist(a);
+    if (sln) {
+        return sln->data;
+    }
+    return NULL;
+}
+
+static void skiplisti_destroy(void *vsl)
+{
+    apr_skiplist_destroy((apr_skiplist *) vsl, NULL);
+    apr_skiplist_free((apr_skiplist *) vsl, vsl);
+}
+
+APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree)
+{
+    while (apr_skiplist_pop(sl->index, skiplisti_destroy) != NULL)
+        ;
+    apr_skiplist_remove_all(sl, myfree);
+}
+
+APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2)
+{
+    /* Check integrity! */
+    apr_skiplist temp;
+    struct apr_skiplistnode *b2;
+    if (sl1->bottomend == NULL || sl1->bottomend->prev == NULL) {
+        apr_skiplist_remove_all(sl1, NULL);
+        temp = *sl1;
+        *sl1 = *sl2;
+        *sl2 = temp;
+        /* swap them so that sl2 can be freed normally upon return. */
+        return sl1;
+    }
+    if(sl2->bottom == NULL || sl2->bottom->next == NULL) {
+        apr_skiplist_remove_all(sl2, NULL);
+        return sl1;
+    }
+    /* This is what makes it brute force... Just insert :/ */
+    b2 = apr_skiplist_getlist(sl2);
+    while (b2) {
+        apr_skiplist_insert(sl1, b2->data);
+        apr_skiplist_next(sl2, &b2);
+    }
+    apr_skiplist_remove_all(sl2, NULL);
+    return sl1;
+}

Propchange: apr/apr/trunk/tables/apr_skiplist.c
------------------------------------------------------------------------------
    svn:eol-style = native