/** @file runtime/bushpriv.h
 * Definitions of generic tree operations
 */

/* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi).

   This file is part of MARIA, a reachability analyzer and model checker
   for high-level Petri nets.

   MARIA is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   MARIA is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   The GNU General Public License is often shipped with GNU software, and
   is generally kept in a file called COPYING or LICENSE.  If you do not
   have a copy of the license, write to the Free Software Foundation,
   59 Temple Place, Suite 330, Boston, MA 02111 USA. */

#include "mset.h"
/** deallocate a tree
 * @param node	the root of the tree
 */
void
freetree (void* node)
{
  register struct tree* t = node;
  if (t->left) freetree (t->left);
  if (t->right) freetree (t->right);
  free (t);
}
/** determine whether the multi-set a tree represents is singleton
 * @param node	the root of the tree
 * @return	the singleton node, or 0 if the tree is not singleton
 */
void*
singleton (void* node)
{
  struct tree* u = 0;
  register struct tree* t = node;
  FIRST (t);
  while (t) {
    if (!t->count);
    else if (t->count > 1 || u)
      return 0;
    else
      u = t;
    NEXT (t);
  }
  return u ? u + 1 : 0;
}
/** determine whether the multi-set a tree represents is empty
 * @param node	the root of the tree
 * @return	pointer to the first non-empty item, or 0 if the tree is empty
 */
const void*
nonempty (const void* node)
{
  register const struct tree* t = node;
  FIRST (t);
  while (t) {
    if (t->count)
      return t;
    NEXT (t);
  }
  return 0;
}
#ifdef DEBUG
/** climb to the root of a tree
 * @param node	a tree node
 * @return	the root of the tree
 */
struct tree*
root (void* node)
{
  register struct tree* t = node;
  if (t) while (t->up) t = t->up;
  return t;
}
/** get the minimum item in a tree
 * @param node	the root of the tree
 * @return	minimum item in the tree
 */
struct tree*
first (void* node)
{
  register struct tree* t = node;
  if (t) while (t->left) t = t->left;
  return t;
}
/** get the successor of a tree node
 * @param node	the tree node
 * @return	the successor of the node
 */
struct tree*
next (void* node)
{
  register struct tree* t = node;
  if (t) {
    if (t->right)
      return first (t->right);
    while (t->up && t == t->up->right)
      t = t->up;
    t = t->up;
  }
  return t;
}
#endif /* DEBUG */
#ifdef RED_BLACK
/** left rotate a tree
 * @param node	tree node to be rotated
 */
static void
left_rotate (void* node)
{
  register struct tree *t = node, *u = t->right;
  if ((t->right = u->left))
    u->left->up = t;
  if ((u->up = t->up)) {
    if (t == t->up->left) t->up->left = u; else t->up->right = u;
  }
  u->left = t, t->up = u;
}

/** right rotate a tree
 * @param node	tree node to be rotated
 */
static void
right_rotate (void* node)
{
  register struct tree *t = node, *u = t->left;
  if ((t->left = u->right))
    u->right->up = t;
  if ((u->up = t->up)) {
    if (t == t->up->right) t->up->right = u; else t->up->left = u;
  }
  u->right = t, t->up = u;
}

/** balance a tree
 * @param node	a newly inserted node
 */
static void
balance (void* node)
{
  register struct tree* t = node;
  t->red = 1;
  while (t->up && t->up->red) {
    register struct tree* u = t->up->up;
    if (!u) break;
    if (t->up == u->left) {
      if (u->right && u->right->red)
	u->left->red = u->right->red = 0, u->red = 1, t = u;
      else {
	if (t == t->up->right)
	  left_rotate (t = t->up);
	if (t->up) t->up->red = 0;
	u->red = 1;
	right_rotate (u);
      }
    }
    else {
      if (u->left && u->left->red) {
	if (u->right) u->right->red = 0;
	u->left->red = 0, u->red = 1, t = u;
      }
      else {
	if (t == t->up->left)
	  right_rotate (t = t->up);
	if (t->up) t->up->red = 0;
	u->red = 1;
	left_rotate (u);
      }
    }
  }
}
#endif /* RED_BLACK */
