/* splay.c  - code for splay trees    Version of August 18, 2001.
 * Author: Brendan McKay  bdm@cs.anu.edu.au

   This file is not meant to be compiled separately, but to be
   #included into other programs.  Use it like this:

   1. Define a node type SPLAYNODE.  It must be a structure that
   contains at least the pointer fields left, right and parent of
   type SPLAYNODE*.
   Also define a macro SPLAYNODESIZE giving the size of an object
   of type SPLAYNODE, unless  sizeof(SPLAYNODE) is adequate.

   2. Declare a variable of type SPLAYNODE* to point to the root
   of the tree, and initialise it to NULL.

   3. Declare SCAN_ARGS to be the additional arguments needed for
   splay_scan(), including a leading comma.

   4. Declare ACTION(p) for what splay_scan() should do for node p.

   5. Declare INSERT_ARGS to be the additional arguments needed 
   for splay_insert(), including a leading comma.

   6. Declare LOOKUP_ARGS to be the additional arguments needed
   for splay_lookup(), including a leading comma.  The default
   for LOOKUP_ARGS is to be the same as INSERT_ARGS.

   7. Declare COMPARE(p) to compare INSERT_ARGS or LOOKUP_ARGS to the
   contents of node p.  <0, 0, >0 if INSERT_ARGS is greater, equal,
   less, than p.  This has to be an expression with a value, so you will
   need to make it a procedure call if the comparison is complicated.

   If you are using something like strcmp, the correct order is
   strcmp( INSERT_ARGS, p ).

   8. Declare PRESENT(p) for what to do if INSERT_ARGS is already
   present, in node p.  There is a spare int variable i available.
   Typically, this might update some data in the node p.

   9. Declare NOT_PRESENT(p) for what to do if INSERT_ARGS is not
   in the tree and p is a fresh node to hold it.  No need to set
   the left, right, and parent fields.  Use i here too if you like.
   Typically, this might initialise the data in node p.

        PRESENT(p) and NOT_PRESENT(p) should not manipulate the
        tree pointers.  However, each of them can include a
        return if you don't want to change the tree.  In the
        case of NOT_PRESENT(p), do free(p) before returning.

        In the case of PRESENT(p), it is also legal to delete the
        node from the tree using SCAN_DELETE(to_root,p).  In that
        case you MUST return immediately afterwards.

  10. #include "splay.c"


  Calls:

    Suppose "root" is name of the variable described in step 2.

    There is no need to initialise the tree.  Step 2 did that already.

    To insert something in the tree:
        splay_insert(&root, ...stuff...)
    where "stuff" is the stuff you want to insert, declared as INSERT_ARGS.
    If the key (some part of the stuff decided by you) is present in an
    existing tree node p, PRESENT(p) is executed.  Otherwise, a new tree
    node p is created and NOT_PRESENT(p) is executed.

    To look up something in the tree:
        splay_lookup(&root, ...stuff...)
    where "stuff" is the stuff you want to find, declared as LOOKUP_ARGS.
    It will return a pointer to the tree node with the right key, or NULL
    if there is no such tree node.

    To do something for each node of the tree:
        splay_scan(root, ...stuff...)
    where "stuff" is anything you like (including nothing).  This will
    execute ACTION(p) for each node p in inorder.

    To delete the node p (which MUST be in the tree:
        splay_delete(&root, p)
    Nothing happens if p is NULL, so you can use
        splay_delete(&root, splay_lookup(&root, ...stuff...))
    to delete a node, if any, containing stuff.

  It is possible to have splay trees of several types in the same
  program.  Just include "splay.c" several times, with the procedure
  names SPLAY, SPLAY_SCAN, SPLAY_LOOKUP, SPLAY_INSERT, SPLAY_DELETE
  defined to distinct names.  You have to redefine them all even if
  you aren't using them all.

  Threads:

    You cannot use the same splay tree from different threads at the
    same time. You need to use semaphores or other means to serialize
    access. On the other hand, different splay trees are entirely
    independent, so it is fine for different threads to use their
    own private splay trees.
*/

#define S_A 0
#define S_L 1
#define S_R 2
#define S_LL 3
#define S_LR 4
#define S_RL 5
#define S_RR 6

#ifndef SPLAYNODESIZE
#define SPLAYNODESIZE sizeof(SPLAYNODE)
#endif

#ifndef LOOKUP_ARGS
#define LOOKUP_ARGS INSERT_ARGS
#endif

#ifndef SPLAY
#define SPLAY splay
#define SPLAY_SCAN splay_scan
#define SPLAY_LOOKUP splay_lookup
#define SPLAY_INSERT splay_insert
#define SPLAY_DELETE splay_delete
#endif

/*********************************************************************/

void
SPLAY_SCAN(SPLAYNODE *root SCAN_ARGS)
/* Do ACTION(p) for each node of the tree, in inorder.  Nonrecursive! */
{
    int code;
    SPLAYNODE *p;

    p = root;
    code = S_A;

    while (p)
    {
        switch (code)    /* deliberate flow-ons */
        {
         case S_A:
            if (p->left)
            {
                p = p->left;
                break;
            }
         case S_L:
            ACTION(p);
            if (p->right)
            {
                p = p->right;
                code = S_A;
                break;
            }
         case S_R:
            if (p->parent && p->parent->left == p) code = S_L;
            else                                   code = S_R;
            p = p->parent;
            break;
        }
    }
}

/*********************************************************************/

static void
SPLAY(SPLAYNODE *p)
/* Splay the node p.  It becomes the new root. */
{
    SPLAYNODE *q,*r,*s;
    SPLAYNODE *a,*b,*c;
    int code;

#define LCHILD(x,y) {(x)->left = y; if (y) (y)->parent = x;}
#define RCHILD(x,y) {(x)->right = y; if (y) (y)->parent = x;}

    while (p->parent)
    {
        a = p->left;
        b = p->right;
        q = p->parent;
        if (q->left == p)
        {
            code = S_L;
            c = q->right;
        }
        else
        {
            code = S_R;
            c = q->left;
        }
        r = q->parent;
        if (r)
        {
            if (r->left == q) code = (code == S_L ? S_LL : S_LR);
            else              code = (code == S_L ? S_RL : S_RR);
            s = r->parent;
            p->parent = s;
            if (s)
            {
                if (s->left == r) s->left = p;
                else              s->right = p;
            }
        }
        else
        {
            p->parent = NULL;
        }
        
        switch (code)
        {
         case S_L:
            RCHILD(p,q);
            LCHILD(q,b);
            break;
         case S_R:
            LCHILD(p,q);
            RCHILD(q,a);
            break;
         case S_LL:
            RCHILD(p,q);
            RCHILD(q,r);
            LCHILD(q,b);
            LCHILD(r,c);
            break;
         case S_RR:
            LCHILD(p,q);
            LCHILD(q,r);
            RCHILD(r,c);
            RCHILD(q,a);
            break;
         case S_LR:
            LCHILD(p,q);
            RCHILD(p,r);
            RCHILD(q,a);
            LCHILD(r,b);
            break;
         case S_RL:
            LCHILD(p,r);
            RCHILD(p,q);
            RCHILD(r,a);
            LCHILD(q,b);
            break;
        }
    }
}

/*********************************************************************/

void
SPLAY_INSERT(SPLAYNODE **to_root  INSERT_ARGS)
/* Do insertion operation.  On return, the object being inserted
   is at the root of the tree regardless of whether a new node
   needed to be created for it. */
{
    int i,cmp;   /* i is present for possible macros */
    SPLAYNODE *p,*ppar,*new_node;

    p = *to_root;
    cmp = 0;

    while (p != NULL)
    {
        cmp = COMPARE(p);
        if (cmp == 0)
        {
            PRESENT(p);
            SPLAY(p);
            *to_root = p;
            return;
        }
        else if (cmp < 0)
        {
            ppar = p;
            p = p->left;
        }
        else
        {
            ppar = p;
            p = p->right;
        }
    }

    if ((new_node = (SPLAYNODE*)malloc(SPLAYNODESIZE)) == NULL)
    {
        fprintf(stderr,">E malloc failed in splay_insert()\n");
        exit(1);
    }

    NOT_PRESENT(new_node);

    new_node->left = new_node->right = NULL;

    if (cmp == 0)
    {
        *to_root = new_node;
        new_node->parent = NULL;
    }
    else if (cmp < 0)
    {
        ppar->left = new_node;
        new_node->parent = ppar;
    }
    else
    {
        ppar->right = new_node;
        new_node->parent = ppar;
    }

    SPLAY(new_node);
    *to_root = new_node;
}

/*********************************************************************/

SPLAYNODE*
SPLAY_LOOKUP(SPLAYNODE **to_root  LOOKUP_ARGS)
/* Do a look-up operation.  If found, return a pointer to the
   node containing it.  If not, return NULL.  The tree is not
   modified. */
{
    int i,cmp;   /* i is available for COMPARE */
    SPLAYNODE *p;

    p = *to_root;
    cmp = 0;

    while (p != NULL)
    {
        cmp = COMPARE(p);
        if (cmp == 0)
        {
            SPLAY(p);
            *to_root = p;
            return p;
        }
        else if (cmp < 0)
            p = p->left;
        else
            p = p->right;
    }

    return NULL;
}

/*********************************************************************/

void
SPLAY_DELETE(SPLAYNODE **to_root, SPLAYNODE *p)
/* Remove node p from the tree and free it. */
{
    SPLAYNODE *q;

    if (p == NULL) return;

    SPLAY(p);
    *to_root = p;

    /* Now we have to delete the root. */

    /* No right child (includes no children). */

    if (!p->right)
    {
        *to_root = p->left;
        if (p->left) p->left->parent = NULL;
        free(p);
        return;
    }

    /* right child but no left child */

    if (!p->left)
    {
        *to_root = p->right;
        p->right->parent = NULL;
        free(p);
        return;
    }  

    /* both children exist */

     for (q = p->left; q->right; q = q->right) {}

     if (q->left) q->left->parent = q->parent;
     if (q->parent == p) q->parent->left = q->left;
     else                q->parent->right = q->left;

     q->left = p->left;
     q->right = p->right;
     q->parent = NULL;
     if (p->left) p->left->parent = q;
     if (p->right) p->right->parent = q;
     *to_root = q;
     free(p);
}

/*********************************************************************/

/* The following shows the tree structure for debugging purposes.
   If you define SPLAY_DUMP you must also define DUMP_ARGS,
   DUMP_LEFT, DUMP_RIGHT and DUMP_ACTION(p). */

#ifdef SPLAY_DUMP
void
SPLAY_DUMP(SPLAYNODE *p DUMP_ARGS)
{
    int i;
    
    if (p == NULL) return;

    if (p->right && p->right->parent != p)
        fprintf(stderr,"parent misaligned at %p-%p ************\n",p,p->right);
    if (p->left && p->left->parent != p)
        fprintf(stderr,"parent misaligned at %p-%p ************\n",p,p->left);

    SPLAY_DUMP(p->right  DUMP_RIGHT);
    DUMP_ACTION(p);
    SPLAY_DUMP(p->left  DUMP_LEFT);
}
#endif
