/** @file runtime/bush.h
 * Declarations of low-level tree operations for handling multi-sets
 */

/* 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<string.h>
#include<stdlib.h>

#include"Error.h"
#include"types.h"

#ifndef CONST
# ifdef __GNUC__
#  define CONST __attribute__ ((const))
# else
#  define CONST
# endif
#endif

/* multi-set and type declaration stuff */

/** three-way conditional comparison for data items
 * @param f	flag: perform the comparison?
 * @param l	left-hand-side argument
 * @param r	right-hand-side argument
 * @param c	component to compare
 * @param s	action to perform if l is smaller than right
 * @param g	action to perform if l is greater than right
 */
#define CC3(f,l,r,c,s,g) if (f) {if (l c<r c) {s;} else if (l c>r c) {g;}}
/** three-way comparison for data items
 * @param l	left-hand-side argument
 * @param r	right-hand-side argument
 * @param c	component to compare
 * @param s	action to perform if l is smaller than right
 * @param g	action to perform if l is greater than right
 */
#define C3(l,r,c,s,g) if (l c < r c) { s; } else if (l c > r c) { g; }

/** name of the current tree type */
#define TREE ID(tree)
/** name of the current type */
#define TYPE ID(t)

/** generic tree structure */
struct tree
{
  struct tree *up, *left, *right;
#ifdef RED_BLACK
  bool_t red;
#endif /* RED_BLACK */
  card_t count;
};

/** declare a multi-set data structure */
#ifdef RED_BLACK
# define DECLARE_MULTISET			\
struct TREE					\
{						\
  struct TREE *up, *left, *right;		\
  bool_t red;					\
  card_t count;					\
  TYPE item;					\
}
#else /* RED_BLACK */
# define DECLARE_MULTISET			\
struct TREE					\
{						\
  struct TREE *up, *left, *right;		\
  card_t count;					\
  TYPE item;					\
}
#endif /* RED_BLACK */

/** declare multi-set operations */
#define DECLARE_MULTISET_OPS					\
DECLARE_MULTISET;						\
struct TREE* ID(insert) (struct TREE*,const TYPE*,card_t);	\
struct TREE* ID(find) (struct TREE*,const TYPE*) CONST;		\
bool_t ID(equal) (const struct TREE*,const struct TREE*) CONST;	\
bool_t ID(subset) (const struct TREE*,const struct TREE*) CONST;\
void ID(intersect) (struct TREE*,const struct TREE*);		\
void ID(subtract) (struct TREE*,const struct TREE*);		\
struct TREE* ID(copy) (struct TREE*,const struct TREE*);	\
struct TREE* ID(copyc) (struct TREE*,const struct TREE*,card_t)

/** climb to the root of a tree
 * @param t	in: a tree node; out: the root of the tree
 */
#define ROOT(t) if (t) while (t->up) t = t->up
/** get the minimum item in a tree
 * @param t	in: root of the tree; out: minimum item in tree
 */
#define FIRST(t) if (t) while ((t)->left) (t) = (t)->left
/** get the successor of a tree node
 * @param t	in: the tree node; out: successor of the node
 */
#define NEXT(t) do {							\
  if ((t)->right) for ((t) = (t)->right; (t)->left; (t) = (t)->left);	\
  else {								\
    while ((t)->up && (t) == (t)->up->right) (t) = (t)->up;		\
    (t) = (t)->up;							\
  }									\
} while (0)
/** free a tree
 * @param t	in: tree to be freed; out: NULL
 */
#define FREE(t) (t ? (freetree (t), t = 0) : 0)
void freetree (void* node);
/** determine whether the multi-set a tree represents is singleton
 * @param node	the root of the tree
 * @return	pointer to the item, or 0 if the tree is not singleton
 */
void* singleton (void* node) CONST;
/** 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) CONST;
