#ifndef COMMON_RBTREE_H
#define COMMON_RBTREE_H

/*
 * Copyright (c) 2002, The EROS Group, LLC and Johns Hopkins
 * University. All rights reserved.
 * 
 * This software was developed to support the EROS secure operating
 * system project (http://www.eros-os.org). The latest version of
 * the OpenCM software can be found at http://www.opencm.org.
 * 
 * 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.
 * 
 * 3. Neither the name of the The EROS Group, LLC nor the name of
 *    Johns Hopkins University, nor the names of its contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 * 
 * 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 OWNER 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.
 */

#define TREE_RED 0
#define TREE_BLACK 1

typedef struct rbkey rbkey;
struct rbkey {
  const void *vp;
  uint32_t w;
};

/* The rbnode and rbkey structures are exposed because it is sometimes 
   necessary to build hybrid datas tructures -- e.g. entities that are
   indexed distinctly in multiple trees. It is HIGHLY inadvisable to
   access this structure directly to perform comparisons, as a
   multiKey tree records the fact of multiple keys in the tree
   structure. As a result, a complete compare cannot be done without
   examining the multikey field. */
typedef struct rbnode rbnode;
struct rbnode {
  rbnode *left;
  rbnode *right;
  rbnode *parent;

  unsigned seqNo;
  int color;

  rbkey  value;

  const void *data;
};

/* There is a singleton nil node */
extern rbnode tree_nil_node;
#define TREE_NIL (&tree_nil_node)

typedef struct rbtree rbtree;
struct rbtree {
  unsigned seqNo;
  OC_bool multiKey;

  rbnode *root;
  int (*cmp)(const rbnode *, const rbnode *);
  int (*cmpkey)(const rbnode *, const rbkey *);
};

rbtree *rbtree_create(int (*cmp)(const rbnode *, const rbnode *), 
		      int (*cmpkey)(const rbnode *, const rbkey *),
		      OC_bool multiKey);

rbnode *rbtree_min(rbtree *);
rbnode *rbtree_max(rbtree *);
rbnode *rbtree_succ(rbnode *);
rbnode *rbtree_pred(rbnode *);
void rbtree_insert(rbtree*, rbnode *);
void rbtree_remove(rbtree*, rbnode *);
rbnode *rbtree_find(rbtree*, rbkey *);
OC_bool rbtree_contains(rbtree*, rbnode *);
OC_bool rbtree_isEmpty(rbtree*);
rbnode *rbtree_root(rbtree*);
uint64_t rbtree_size(rbtree*);

int rbtree_compare_node_to_key(rbtree*, rbnode *, rbkey*);
int rbtree_compare_nodes(rbtree*, rbnode *, rbnode *);

/* For situations where the rbnode itself is sufficient: */
rbnode *rbnode_create(const void *kvp, uint32_t kw, const void *data);

#ifndef NDEBUG
/* tree_validate() -- check the subtree of ROOT rooted at NODE for
   consistency */
OC_bool rbtree_validate(rbtree *root, rbnode *node);
#endif

/* RB-Trees containing strings as keys are a particularly common case,
   so provide cmp(), cmpkey() functions for this case: */
int rbtree_s_cmp(const rbnode *rn1, const rbnode *rn2);
int rbtree_s_cmpkey(const rbnode *rn1, const rbkey *rkey);

/* String maps for unique strings are a particularly common
   case. Provide some direct support: */
typedef rbtree *StringMap;
StringMap stringmap_create(void);
void stringmap_add(StringMap, const char *from, const char *to);
const char *stringmap_find(StringMap, const char *from);
uint64_t stringmap_size(StringMap);

#endif /* COMMON_RBTREE_H */
