Subversion Repositories PlanixRsrch.SVN

Rev

Rev 327 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright 2019, The PLANIX Project
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <string.h>

#include "mavl.h"

void
mavl_rot(struct mavlnode *n, struct mavlnode **parent, int dir)
{
        struct mavlnode *tmp;
        *parent = n->s[dir];
        tmp = n->s[dir]->s[1-dir]; 
        n->s[dir]->s[1-dir]=n;
        n->s[dir]=tmp;
}

void
mavl_drot(struct mavlnode *n, struct mavlnode **parent, int dir)
{
        mavl_rot(n->s[dir],&n->s[dir],1-dir);
        mavl_rot(n,parent,dir);
}

struct mavlnode *
mavlnode_create(struct mavl *t, const void *data)
{
        struct mavlnode *n = t->malloc(sizeof(struct mavlnode) + t->data_size);
        if (!n)
                return NULL;

        n->s[0] = n->s[1] = NULL;
        n->bal = 0;

        (void)memcpy(mavlnode_dataptr(n), data, t->data_size);

        return n;
}

static int
mavl_insert0(struct mavl *t, struct mavlnode **parent, const void **data)
{
        struct mavlnode *n;
        int rc, bal,b;
        int dir,sdir;

        if (*parent==NULL){
                *parent = mavlnode_create(t, *data);
                *data = mavlnode_dataptr(*parent);
                if (*parent==NULL)
                        return MAVL_E_NOMEM;
                t->count++;
                return 1;
        }

        n = *parent;
        rc = t->cmp(*data, mavlnode_dataptr(n));

        if (rc == 0) {
                *data = mavlnode_dataptr(n);
                return 2;
        }

        dir = rc>0 ? 1:0;

        /* rc is > 0  here */
        bal = mavl_insert0(t, &n->s[dir], data);

        if (bal > 1)
                return bal;

        sdir = dir ? 1:-1;
        n->bal += bal*sdir;

        if (n->bal == 0)
                return 0;

        if (n->bal == 2*sdir) {
                if (n->s[dir]->bal == sdir) {
                        n->bal = 0;
                        n->s[dir]->bal = 0;
                        mavl_rot(n, parent,dir);
                        return 0;
                } 
                
                b = n->s[dir]->s[1-dir]->bal;
                if (b==-sdir){
                        n->bal = 0;
                        n->s[dir]->bal = sdir;
                }else if (b==sdir){
                        n->bal = -sdir;
                        n->s[dir]->bal = 0;
                }else{
                        n->bal = 0;
                        n->s[dir]->bal = 0;
                }

                n->s[dir]->s[1-dir]->bal = 0;
                mavl_drot(n, parent,dir);
                return 0;
        }
        return bal;
}

void *
mavl_insert(struct mavl *t, const void *data, int *exists)
{
        const void *d;
        int rc;

        d = data;
        rc = mavl_insert0(t, &t->root, &d);

        if (rc >= 3)
                return NULL;

        if (exists != NULL) {
                if (rc == 2)
                        *exists = 1;
                else
                        *exists = 0;
        }
        return (void *)d;
}