You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by yl...@apache.org on 2015/03/17 23:42:47 UTC
svn commit: r1667420 - in /apr/apr/trunk: include/apr_skiplist.h
tables/apr_skiplist.c test/testskiplist.c
Author: ylavic
Date: Tue Mar 17 22:42:46 2015
New Revision: 1667420
URL: http://svn.apache.org/r1667420
Log:
skiplist: Introduce apr_skiplist_replace[_compare]().
Modified:
apr/apr/trunk/include/apr_skiplist.h
apr/apr/trunk/tables/apr_skiplist.c
apr/apr/trunk/test/testskiplist.c
Modified: apr/apr/trunk/include/apr_skiplist.h
URL: http://svn.apache.org/viewvc/apr/apr/trunk/include/apr_skiplist.h?rev=1667420&r1=1667419&r2=1667420&view=diff
==============================================================================
--- apr/apr/trunk/include/apr_skiplist.h (original)
+++ apr/apr/trunk/include/apr_skiplist.h Tue Mar 17 22:42:46 2015
@@ -217,11 +217,37 @@ APR_DECLARE(apr_skiplistnode *) apr_skip
APR_DECLARE(apr_skiplistnode *) apr_skiplist_add(apr_skiplist* sl, void *data);
/**
+ * Add an element into the skip list using the specified comparison function
+ * removing the existing duplicates.
+ * @param sl The skip list
+ * @param data The element to insert
+ * @param comp The comparison function to use for placement into the skip list
+ * @param myfree A function to be called for each replaced element
+ * @remark If no comparison function has been set for the skip list, the element
+ * will not be inserted, none will be replaced, and NULL will be returned.
+ */
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_replace_compare(apr_skiplist *sl,
+ void *data, apr_skiplist_freefunc myfree,
+ apr_skiplist_compare comp);
+
+/**
+ * Add an element into the skip list using the existing comparison function
+ * removing the existing duplicates.
+ * @param sl The skip list
+ * @param data The element to insert
+ * @param myfree A function to be called for each removed duplicate
+ * @remark If no comparison function has been set for the skip list, the element
+ * will not be inserted, none will be replaced, and NULL will be returned.
+ */
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_replace(apr_skiplist *sl,
+ void *data, apr_skiplist_freefunc myfree);
+
+/**
* Remove an element from the skip list using the specified comparison function for
* locating the element. In the case of duplicates, the 1st entry will be removed.
* @param sl The skip list
* @param data The element to remove
- * @param myfree A function to be called for each removed element
+ * @param myfree A function to be called for each removed duplicate
* @param comp The comparison function to use for placement into the skip list
* @remark If the element is not found, 0 will be returned. Otherwise, the heightXXX
* will be returned.
Modified: apr/apr/trunk/tables/apr_skiplist.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/tables/apr_skiplist.c?rev=1667420&r1=1667419&r2=1667420&view=diff
==============================================================================
--- apr/apr/trunk/tables/apr_skiplist.c (original)
+++ apr/apr/trunk/tables/apr_skiplist.c Tue Mar 17 22:42:46 2015
@@ -201,7 +201,7 @@ static apr_skiplistnode *skiplist_new_no
return m;
}
-static apr_status_t skiplist_free_node(apr_skiplist *sl, apr_skiplistnode *m)
+static apr_status_t skiplist_put_node(apr_skiplist *sl, apr_skiplistnode *m)
{
return skiplist_qpush(&sl->nodes_q, m);
}
@@ -304,8 +304,7 @@ static int skiplisti_find_compare(apr_sk
{
int count = 0;
apr_skiplistnode *m;
- m = sl->top;
- while (m) {
+ for (m = sl->top; m; count++) {
if (m->next) {
int compared = comp(data, m->next->data);
if (compared == 0) {
@@ -318,12 +317,10 @@ static int skiplisti_find_compare(apr_sk
}
if (compared > 0) {
m = m->next;
- count++;
continue;
}
}
m = m->down;
- count++;
}
*ret = NULL;
return count;
@@ -398,11 +395,16 @@ APR_DECLARE(void *) apr_skiplist_element
return node->data;
}
+/* forward declared */
+static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m,
+ apr_skiplist_freefunc myfree);
+
static apr_skiplistnode *insert_compare(apr_skiplist *sl, void *data,
- apr_skiplist_compare comp, int add)
+ apr_skiplist_compare comp, int add,
+ apr_skiplist_freefunc myfree)
{
apr_skiplistnode *m, *p, *tmp, *ret = NULL;
- int nh = 1, ch;
+ int ch, nh = 1;
if (sl->preheight) {
while (nh < sl->preheight && get_b_rand()) {
@@ -431,10 +433,26 @@ static apr_skiplistnode *insert_compare(
*/
if (m->next) {
int compared = comp(data, m->next->data);
- if (compared == 0 && !add) {
- /* Keep the existing element(s) */
- skiplist_qclear(&sl->stack_q);
- return NULL;
+ if (compared == 0) {
+ if (!add) {
+ /* Keep the existing element(s) */
+ skiplist_qclear(&sl->stack_q);
+ return NULL;
+ }
+ if (add < 0) {
+ /* Remove this element and continue with the next node
+ * or the new top if the current one is also removed.
+ */
+ apr_skiplistnode *top = sl->top;
+ skiplisti_remove(sl, m->next, myfree);
+ if (top != sl->top) {
+ m = sl->top;
+ skiplist_qclear(&sl->stack_q);
+ ch = sl->height;
+ nh = ch + 1;
+ }
+ continue;
+ }
}
if (compared >= 0) {
m = m->next;
@@ -507,7 +525,7 @@ static apr_skiplistnode *insert_compare(
li = ret;
for (p = apr_skiplist_getlist(sl->index); p; apr_skiplist_next(sl->index, &p)) {
apr_skiplist *sli = (apr_skiplist *)p->data;
- ni = insert_compare(sli, ret->data, sli->compare, add);
+ ni = insert_compare(sli, ret->data, sli->compare, add, myfree);
li->nextindex = ni;
ni->previndex = li;
li = ni;
@@ -523,7 +541,7 @@ APR_DECLARE(apr_skiplistnode *) apr_skip
if (!comp) {
return NULL;
}
- return insert_compare(sl, data, comp, 0);
+ return insert_compare(sl, data, comp, 0, NULL);
}
APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist *sl, void *data)
@@ -537,7 +555,7 @@ APR_DECLARE(apr_skiplistnode *) apr_skip
if (!comp) {
return NULL;
}
- return insert_compare(sl, data, comp, 1);
+ return insert_compare(sl, data, comp, 1, NULL);
}
APR_DECLARE(apr_skiplistnode *) apr_skiplist_add(apr_skiplist *sl, void *data)
@@ -545,6 +563,22 @@ APR_DECLARE(apr_skiplistnode *) apr_skip
return apr_skiplist_add_compare(sl, data, sl->compare);
}
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_replace_compare(apr_skiplist *sl,
+ void *data, apr_skiplist_freefunc myfree,
+ apr_skiplist_compare comp)
+{
+ if (!comp) {
+ return NULL;
+ }
+ return insert_compare(sl, data, comp, -1, myfree);
+}
+
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_replace(apr_skiplist *sl,
+ void *data, apr_skiplist_freefunc myfree)
+{
+ return apr_skiplist_replace_compare(sl, data, myfree, sl->compare);
+}
+
#if 0
void skiplist_print_struct(apr_skiplist * sl, char *prefix)
{
@@ -564,7 +598,8 @@ void skiplist_print_struct(apr_skiplist
}
#endif
-static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m, apr_skiplist_freefunc myfree)
+static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m,
+ apr_skiplist_freefunc myfree)
{
apr_skiplistnode *p;
if (!m) {
@@ -576,19 +611,20 @@ static int skiplisti_remove(apr_skiplist
while (m->up) {
m = m->up;
}
- while (m) {
+ do {
p = m;
- p->prev->next = p->next;/* take me out of the list */
+ /* take me out of the list */
+ p->prev->next = p->next;
if (p->next) {
- p->next->prev = p->prev; /* take me out of the list */
+ p->next->prev = p->prev;
}
m = m->down;
/* This only frees the actual data in the bottom one */
if (!m && myfree && p->data) {
myfree(p->data);
}
- skiplist_free_node(sl, p);
- }
+ skiplist_put_node(sl, p);
+ } while (m);
sl->size--;
while (sl->top && sl->top->next == NULL) {
/* While the row is empty and we are not on the bottom row */
@@ -597,7 +633,7 @@ static int skiplisti_remove(apr_skiplist
if (sl->top) {
sl->top->up = NULL; /* Make it think its the top */
}
- skiplist_free_node(sl, p);
+ skiplist_put_node(sl, p);
sl->height--;
}
if (!sl->top) {
@@ -657,7 +693,7 @@ APR_DECLARE(void) apr_skiplist_remove_al
}
do {
u = m->up;
- skiplist_free_node(sl, m);
+ skiplist_put_node(sl, m);
m = u;
} while (m);
m = p;
Modified: apr/apr/trunk/test/testskiplist.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/test/testskiplist.c?rev=1667420&r1=1667419&r2=1667420&view=diff
==============================================================================
--- apr/apr/trunk/test/testskiplist.c (original)
+++ apr/apr/trunk/test/testskiplist.c Tue Mar 17 22:42:46 2015
@@ -105,12 +105,16 @@ static void skiplist_insert(abts_case *t
ABTS_STR_EQUAL(tc, "atfirst", val);
}
+#define NUM_ADDS 100
static void skiplist_add(abts_case *tc, void *data)
{
const char *val;
- size_t i, n = skiplist_get_size(tc, skiplist);
+ size_t i, n = 0;
- for (i = 0; i < 100; ++i) {
+ apr_skiplist_remove_all(skiplist, NULL);
+ ABTS_TRUE(tc, 0 == skiplist_get_size(tc, skiplist));
+
+ for (i = 0; i < NUM_ADDS; ++i) {
n++;
apr_skiplist_add(skiplist, "daton");
ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist));
@@ -141,10 +145,48 @@ static void skiplist_add(abts_case *tc,
}
}
+static void skiplist_replace(abts_case *tc, void *data)
+{
+ const char *val;
+ size_t n = skiplist_get_size(tc, skiplist);
+
+ n -= NUM_ADDS - 1;
+ apr_skiplist_replace(skiplist, "daton", NULL);
+ ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist));
+ val = apr_skiplist_find(skiplist, "daton", NULL);
+ ABTS_PTR_NOTNULL(tc, val);
+ ABTS_STR_EQUAL(tc, "daton", val);
+
+ n -= NUM_ADDS - 1;
+ apr_skiplist_replace(skiplist, "baton", NULL);
+ ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist));
+ val = apr_skiplist_find(skiplist, "baton", NULL);
+ ABTS_PTR_NOTNULL(tc, val);
+ ABTS_STR_EQUAL(tc, "baton", val);
+
+ n -= NUM_ADDS - 1;
+ apr_skiplist_replace(skiplist, "caton", NULL);
+ ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist));
+ val = apr_skiplist_find(skiplist, "caton", NULL);
+ ABTS_PTR_NOTNULL(tc, val);
+ ABTS_STR_EQUAL(tc, "caton", val);
+
+ n -= NUM_ADDS - 1;
+ apr_skiplist_replace(skiplist, "aaton", NULL);
+ ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist));
+ val = apr_skiplist_find(skiplist, "aaton", NULL);
+ ABTS_PTR_NOTNULL(tc, val);
+ ABTS_STR_EQUAL(tc, "aaton", val);
+
+ ABTS_TRUE(tc, n == 4);
+}
+
static void skiplist_destroy(abts_case *tc, void *data)
{
apr_skiplist_destroy(skiplist, NULL);
- ABTS_TRUE(tc, 0 == skiplist_get_size(tc, skiplist));
+ ABTS_TRUE(tc, 0 == apr_skiplist_size(skiplist));
+ ABTS_TRUE(tc, 0 == apr_skiplist_height(skiplist));
+ ABTS_TRUE(tc, NULL == apr_skiplist_getlist(skiplist));
}
static void skiplist_size(abts_case *tc, void *data)
@@ -399,6 +441,7 @@ abts_suite *testskiplist(abts_suite *sui
abts_run_test(suite, skiplist_dontfind, NULL);
abts_run_test(suite, skiplist_insert, NULL);
abts_run_test(suite, skiplist_add, NULL);
+ abts_run_test(suite, skiplist_replace, NULL);
abts_run_test(suite, skiplist_destroy, NULL);
abts_run_test(suite, skiplist_size, NULL);
abts_run_test(suite, skiplist_remove, NULL);