struct skiplistnode *sl_append(Skiplist *sl, void *data) { int nh=1, ch, compared; struct skiplistnode *lastnode, *nodeago; if(sl->bottomend != sl->bottom) { compared=sl->compare(data, sl->bottomend->prev->data); /* If it doesn't belong at the end, then fail */ if(compared<=0) return NULL; } 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 hieght at which we wish to insert our new node */ /* Let us make sure that our tree is a least that tall (grow if necessary)*/ lastnode = sl->bottomend; nodeago = NULL; if(!lastnode) return sl_insert(sl, data); for(;sl->height<nh;sl->height++) { assert(sl->top); sl->top->up = (struct skiplistnode *)malloc(sizeof(struct skiplistnode)); sl->top->up->down = sl->top; sl->top = sl->topend = sl->top->up; sl->top->prev = sl->top->next = sl->top->nextindex = sl->top->previndex = NULL; sl->top->data = NULL; sl->top->sl = sl; } ch = sl->height; while(nh) { struct skiplistnode *anode; anode = (struct skiplistnode *)malloc(sizeof(struct skiplistnode)); anode->next = lastnode; anode->prev = lastnode->prev; anode->up = NULL; anode->down = nodeago; /* If this the bottom, we are appending, so bottomend should change */ if(!nodeago) sl->bottomend = anode; if(lastnode->prev) { if(lastnode == sl->bottom) sl->bottom = anode; else if (lastnode == sl->top) sl->top = anode; } nodeago = anode; lastnode = lastnode->up; nh--; } sl->size++; return(nodeago); }
mtev_skiplist_node *mtev_skiplist_insert_compare(mtev_skiplist *sl, const void *data, mtev_skiplist_comparator_t comp) { mtev_skiplist_node *m, *p, *tmp, *ret = NULL, **stack; int nh=1, ch, stacki; if(!sl->top) { sl->height = 1; sl->top = sl->bottom = calloc(1, sizeof(mtev_skiplist_node)); 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 = (mtev_skiplist_node *)calloc(1, sizeof(mtev_skiplist_node)); sl->top->up->down = sl->top; sl->top = sl->top->up; 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 */ m = sl->top; stack = (mtev_skiplist_node **)alloca(sizeof(mtev_skiplist_node *)*(nh)); stacki=0; while(m) { int compared=-1; if(m->next) compared=comp(data, m->next->data); if(compared == 0) { return 0; } if(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 = calloc(1, sizeof(*tmp)); tmp->next = m->next; if(m->next) m->next->prev=tmp; tmp->prev = m; tmp->down = p; if(p) p->up=tmp; tmp->data = (void *)data; tmp->sl = sl; m->next = tmp; /* This sets ret to the bottom-most node we are inserting */ if(!p) ret=tmp; p = tmp; } if(sl->index != NULL) { /* this is a external insertion, we must insert into each index as well */ mtev_skiplist_node *p, *ni, *li; mtevAssert(ret); li=ret; for(p = mtev_skiplist_getlist(sl->index); p; mtev_skiplist_next(sl->index, &p)) { ni = mtev_skiplist_insert((mtev_skiplist *)p->data, ret->data); mtevAssert(ni); li->nextindex = ni; ni->previndex = li; li = ni; } } sl->size++; return ret; }
struct skiplistnode *sl_insert_compare(Skiplist *sl, void *data, SkiplistComparator comp) { struct skiplistnode *m, *p, *tmp, *ret, **stack; int nh=1, ch, stacki; ret = NULL; /*sl_print_struct(sl, "BI: ");*/ if(!sl->top) { sl->height = 1; sl->topend = sl->bottomend = sl->top = sl->bottom = (struct skiplistnode *)malloc(sizeof(struct skiplistnode)); assert(sl->top); sl->top->next = sl->top->data = sl->top->prev = sl->top->up = sl->top->down = sl->top->nextindex = sl->top->previndex = NULL; 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 = (struct skiplistnode *)malloc(sizeof(struct skiplistnode)); assert(sl->top->up); sl->top->up->down = sl->top; sl->top = sl->topend = sl->top->up; sl->top->prev = sl->top->next = sl->top->nextindex = sl->top->previndex = sl->top->up = NULL; sl->top->data = NULL; 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 */ m = sl->top; stack = (struct skiplistnode **)malloc(sizeof(struct skiplistnode *)*(nh)); stacki=0; while(m) { int compared=-1; if(m->next) compared=comp(data, m->next->data); if(compared == 0) { free(stack); return 0; } if((m->next == NULL) || (compared<0)) { /* FIXME: This if ch<=nh test looks unnecessary. ch==nh at beginning of while(m) */ if(ch<=nh) { /* push on stack */ stack[stacki++] = m; } m = m->down; ch--; } else { m = m->next; } } /* Pop the stack and insert nodes */ p = tmp = NULL; for(;stacki>0;stacki--) { m = stack[stacki-1]; tmp = (struct skiplistnode *)malloc(sizeof(struct 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++; } p = tmp; } free(stack); if(tmp && (tmp->prev == sl->topend)) { /* The last element on the top row is the new inserted one */ sl->topend = tmp; } if(ret && (ret->prev == sl->bottomend)) { /* The last element on the bottom row is the new inserted one */ sl->bottomend = ret; } if(sl->index != NULL) { /* this is a external insertion, we must insert into each index as well */ struct skiplistnode *p, *ni, *li; li=ret; for(p = sl_getlist(sl->index); p; sl_next(sl->index, &p)) { ni = sl_insert((Skiplist *)p->data, ret->data); assert(ni); Alarm(SKIPLIST, "Adding %p to index %p\n", ret->data, p->data); li->nextindex = ni; ni->previndex = li; li = ni; } } /* JRS: move size increment above to where node is inserted else { sl->size++; } */ /*sl_print_struct(sl, "AI: ");*/ return ret; }
static apr_skiplistnode *insert_compare(apr_skiplist *sl, void *data, apr_skiplist_compare comp, int add, apr_skiplist_freefunc myfree) { apr_skiplistnode *m, *p, *tmp, *ret = NULL; int ch, top_nh, nh = 1; ch = skiplist_height(sl); if (sl->preheight) { while (nh < sl->preheight && get_b_rand()) { nh++; } } else { while (nh <= ch && get_b_rand()) { nh++; } } top_nh = nh; /* Now we have in nh the height at which we wish to insert our new node, * and in ch the current height: don't create skip paths to the inserted * element until the walk down through the tree (which decrements ch) * reaches nh. From there, any walk down pushes the current node on a * stack (the node(s) after which we would insert) to pop back through * for insertion later. */ m = sl->top; while (m) { /* * To maintain stability, dups (compared == 0) must be added * AFTER each other. */ if (m->next) { int compared = comp(data, m->next->data); 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 = skiplist_height(sl); nh = top_nh; } continue; } } if (compared >= 0) { m = m->next; continue; } } if (ch <= nh) { /* push on stack */ skiplist_qpush(&sl->stack_q, m); } m = m->down; ch--; } /* Pop the stack and insert nodes */ p = NULL; while ((m = skiplist_qpop(&sl->stack_q))) { tmp = skiplist_new_node(sl); tmp->next = m->next; if (m->next) { m->next->prev = tmp; } m->next = tmp; tmp->prev = m; tmp->up = NULL; tmp->nextindex = tmp->previndex = NULL; tmp->down = p; if (p) { p->up = tmp; } else { /* This sets ret to the bottom-most node we are inserting */ ret = tmp; } tmp->data = data; tmp->sl = sl; p = tmp; } /* Now we are sure the node is inserted, grow our tree to 'nh' tall */ for (; sl->height < nh; sl->height++) { m = skiplist_new_node(sl); tmp = skiplist_new_node(sl); m->up = m->prev = m->nextindex = m->previndex = NULL; m->next = tmp; m->down = sl->top; m->data = NULL; m->sl = sl; if (sl->top) { sl->top->up = m; } else { sl->bottom = sl->bottomend = m; } sl->top = sl->topend = tmp->prev = m; tmp->up = tmp->next = tmp->nextindex = tmp->previndex = NULL; tmp->down = p; tmp->data = data; tmp->sl = sl; if (p) { p->up = tmp; } else { /* This sets ret to the bottom-most node we are inserting */ ret = tmp; } p = tmp; } 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)) { apr_skiplist *sli = (apr_skiplist *)p->data; ni = insert_compare(sli, ret->data, sli->compare, 1, NULL); li->nextindex = ni; ni->previndex = li; li = ni; } } sl->size++; return ret; }