예제 #1
0
파일: skiplist.c 프로젝트: Elbandi/nagios3
skiplist *skiplist_new(int max_levels, float level_probability, int allow_duplicates, int append_duplicates, int (*compare_function)(void *,void *)){
	skiplist *newlist=NULL;

	/* alloc memory for new list structure */
	if((newlist=(skiplist *)malloc(sizeof(skiplist)))){

		/* initialize levels, etc. */
		newlist->current_level=0;
		newlist->max_levels=max_levels;
		newlist->level_probability=level_probability;
		newlist->allow_duplicates=allow_duplicates;
		newlist->append_duplicates=append_duplicates;
		newlist->items=0;
		newlist->compare_function=compare_function;

		/* initialize head node */
		newlist->head=skiplist_new_node(newlist,max_levels);
		}

	return newlist;
	}
예제 #2
0
파일: skiplist.c 프로젝트: Elbandi/nagios3
int skiplist_insert(skiplist *list, void *data){
	skiplistnode **update=NULL;
	skiplistnode *thisnode=NULL;
	skiplistnode *nextnode=NULL;
	skiplistnode *newnode=NULL;
	int level=0;
	int x=0;

	if(list==NULL || data==NULL){
		return SKIPLIST_ERROR_ARGS;
		}

	/* initialize update vector */
	if((update=(skiplistnode **)malloc(sizeof(skiplistnode *) * list->max_levels))==NULL){
		return SKIPLIST_ERROR_MEMORY;
		}
	for(x=0;x<list->max_levels;x++)
		update[x]=NULL;

	/* check to make sure we don't have duplicates */
	/* NOTE: this could made be more efficient */
	if(list->allow_duplicates==FALSE){
		if(skiplist_find_first(list,data,NULL))
			return SKIPLIST_ERROR_DUPLICATE;
		}

	/* find proper position for insert, remember pointers  with an update vector */
	thisnode=list->head;
	for(level=list->current_level;level>=0;level--){

		while((nextnode=thisnode->forward[level])){
			if(list->append_duplicates==TRUE){
				if(list->compare_function(nextnode->data,data)>0)
					break;
				}
			else{
				if(list->compare_function(nextnode->data,data)>=0)
					break;
				}
			thisnode=nextnode;
			}

		update[level]=thisnode;
		}

	/* get a random level the new node should be inserted at */
	level=skiplist_random_level(list);
	/*printf("INSERTION LEVEL: %d\n",level);*/

	/* we're adding a new level... */
	if(level > list->current_level){
		/*printf("NEW LEVEL!\n");*/
		list->current_level++;
		level=list->current_level;
		update[level]=list->head;
		}

	/* create a new node */
	if((newnode=skiplist_new_node(list,level))==NULL){
		/*printf("NODE ERROR\n");*/
		free(update);
		return SKIPLIST_ERROR_MEMORY;
		}
	newnode->data=data;

	/* update pointers to insert node at proper location */
	do{
		thisnode=update[level];
		newnode->forward[level]=thisnode->forward[level];
		thisnode->forward[level]=newnode;

		}while(--level>=0);

	/* update counters */
	list->items++;

	/* free memory */
	free(update);

	return SKIPLIST_OK;
	}
예제 #3
0
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;
}