/*****************************************************************************
 *
* Copyright (C) 2001 Mark Edel
* Copyright (C) 2008 Andreas Öman

* This 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 of the License, or (at your option) any later
* version.
*
* This software 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.
*
* You should have received a copy of the GNU General Public License along with
* software; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA  02111-1307 USA
*
* Written by Mark Edel
* Macroified + additional support functions by Andreas Öman
*
*****************************************************************************/

#ifndef REDBLACK_H_
#define REDBLACK_H_

#define RB_TREE_NODE_RED      0
#define RB_TREE_NODE_BLACK    1


#define RB_HEAD(name, type)			\
struct name {					\
  struct type *first, *last, *root;		\
  int entries;					\
}

#define RB_ENTRY(type)				\
struct {					\
  struct type *left, *right, *parent;		\
  int color;					\
}

#define RB_INIT(head)				\
do {						\
  (head)->first   = NULL;			\
  (head)->last    = NULL;			\
  (head)->root    = NULL;			\
  (head)->entries = 0;				\
} while(0)



#define RB_ROTATE_LEFT(x, field, root)		\
do {						\
  typeof(x) xx = x;                             \
  typeof(x) yy = xx->field.right;		\
						\
  xx->field.right = yy->field.left;		\
  if(yy->field.left != NULL)			\
    yy->field.left->field.parent = xx;		\
						\
  yy->field.parent = xx->field.parent;		\
						\
  if(xx == root)				\
    root = yy;					\
  else if(xx == xx->field.parent->field.left) 	\
    xx->field.parent->field.left = yy;		\
  else  					\
    xx->field.parent->field.right = yy;		\
  yy->field.left = xx;				\
  xx->field.parent = yy;			\
} while(0)
  

#define RB_ROTATE_RIGHT(x, field, root)			\
do {							\
  typeof(x) xx = x;					\
  typeof(x) yy = xx->field.left;			\
							\
  xx->field.left = yy->field.right;			\
  if (yy->field.right != NULL)   			\
    yy->field.right->field.parent = xx;			\
  yy->field.parent = xx->field.parent;			\
							\
  if (xx == root)    					\
    root = yy;						\
  else if (xx == xx->field.parent->field.right)  	\
    xx->field.parent->field.right = yy;			\
  else  						\
    xx->field.parent->field.left = yy;			\
  yy->field.right = xx;					\
  xx->field.parent = yy;				\
} while(0)



#define RB_INSERT_BALANCE(x, field, root)				  \
do {									  \
  typeof(x) y;								  \
									  \
  x->field.color = RB_TREE_NODE_RED;					  \
  while (x != root && x->field.parent->field.color == RB_TREE_NODE_RED) { \
    if (x->field.parent == x->field.parent->field.parent->field.left) {	  \
      y = x->field.parent->field.parent->field.right;			  \
      if (y && y->field.color == RB_TREE_NODE_RED) {			  \
        x->field.parent->field.color = RB_TREE_NODE_BLACK;		  \
        y->field.color = RB_TREE_NODE_BLACK;				  \
        x->field.parent->field.parent->field.color = RB_TREE_NODE_RED;	  \
        x = x->field.parent->field.parent;				  \
      }									  \
      else {								  \
        if (x == x->field.parent->field.right) {			  \
          x = x->field.parent;						  \
          RB_ROTATE_LEFT(x, field, root);				  \
        }								  \
        x->field.parent->field.color = RB_TREE_NODE_BLACK;		  \
        x->field.parent->field.parent->field.color = RB_TREE_NODE_RED;	  \
        RB_ROTATE_RIGHT(x->field.parent->field.parent, field, root);	  \
      }									  \
    }									  \
    else {								  \
      y = x->field.parent->field.parent->field.left;			  \
      if (y && y->field.color == RB_TREE_NODE_RED) {			  \
        x->field.parent->field.color = RB_TREE_NODE_BLACK;		  \
        y->field.color = RB_TREE_NODE_BLACK;				  \
        x->field.parent->field.parent->field.color = RB_TREE_NODE_RED;	  \
        x = x->field.parent->field.parent;				  \
      }									  \
      else {								  \
        if (x == x->field.parent->field.left) {				  \
          x = x->field.parent;						  \
          RB_ROTATE_RIGHT(x, field, root);				  \
        }								  \
        x->field.parent->field.color = RB_TREE_NODE_BLACK;		  \
        x->field.parent->field.parent->field.color = RB_TREE_NODE_RED;	  \
        RB_ROTATE_LEFT(x->field.parent->field.parent, field, root);	  \
      }									  \
    }									  \
  }									  \
  root->field.color = RB_TREE_NODE_BLACK;				  \
} while(0);


/**
 * Insert a new node, if a collision occures the colliding node is returned
 */
#define RB_INSERT_SORTED(head, skel, field, cmpfunc)			 \
({									 \
  int res, fromleft = 0;						 \
  typeof(skel) x = skel, c, parent = NULL;				 \
									 \
  c = (head)->root;							 \
  while(c != NULL) {							 \
    res = cmpfunc(x, c);						 \
    if(res < 0) {							 \
      parent = c;							 \
      c = c->field.left;						 \
      fromleft = 1;							 \
    } else if(res > 0) {						 \
      parent = c;							 \
      c = c->field.right;						 \
      fromleft = 0;							 \
    } else {								 \
      break;								 \
    }									 \
  }									 \
  if(c == NULL) {							 \
    x->field.parent = parent;						 \
    x->field.left = NULL;						 \
    x->field.right = NULL;						 \
    x->field.color = RB_TREE_NODE_RED;					 \
									 \
    if(parent) {							 \
      if(fromleft)							 \
	parent->field.left = x;						 \
      else								 \
	parent->field.right = x;					 \
    } else {								 \
      (head)->root = x;							 \
    }									 \
    (head)->entries++;							 \
									 \
    if(x->field.parent == (head)->first &&				 \
       (x->field.parent == NULL || x->field.parent->field.left == x)) {	 \
      (head)->first = x;						 \
    }									 \
									 \
    if(x->field.parent == (head)->last &&				 \
       (x->field.parent == NULL || x->field.parent->field.right == x)) { \
      (head)->last = x;							 \
    }									 \
    RB_INSERT_BALANCE(x, field, (head)->root);                           \
  }									 \
  c;									 \
})


/**
 * Returns next node
 */
#define RB_NEXT(e, field)			\
({						\
  typeof(e) xx = e, f;				\
  if (xx->field.right != NULL) {		\
    xx = xx->field.right;			\
    while (xx->field.left != NULL) {		\
      xx = xx->field.left;			\
    }						\
  }						\
  else {					\
    do {					\
      f = xx;					\
      xx = xx->field.parent;			\
    } while (xx && f == xx->field.right);	\
  }						\
  xx;						\
})


/**
 * Returns previous node
 */
#define RB_PREV(e, field)			\
({						\
  typeof(e) xx = e, f;				\
  if (xx->field.left != NULL) {			\
    xx = xx->field.left;			\
    while (xx->field.right != NULL) {		\
      xx = xx->field.right;			\
    }						\
  }						\
  else {					\
    do {					\
      f = xx;					\
      xx = xx->field.parent;			\
    } while (xx && f == xx->field.left);	\
  }						\
  xx;						\
})


/**
 * Returns first node
 */
#define RB_FIRST(head) ((head)->first)

/**
 * Returns last node
 */
#define RB_LAST(head)  ((head)->last)

/**
 * Iterate thru all nodes
 */
#define RB_FOREACH(e, head, field)		\
 for(e = (head)->first; e != NULL; 		\
       ({					\
	 if(e->field.right != NULL) {		\
	   e = e->field.right;			\
	   while(e->field.left != NULL) {	\
	     e = e->field.left;			\
	   }					\
	 } else {				\
	   typeof(e) f;				\
	   do {					\
	     f = e;				\
	     e = e->field.parent;		\
	   } while(e && f == e->field.right);	\
	 }					\
       }))


/**
 * Iterate thru all nodes in reverse order
 */
#define RB_FOREACH_REVERSE(e, head, field)	\
 for(e = (head)->last; e != NULL; 		\
       ({					\
	 if(e->field.left != NULL) {		\
	   e = e->field.left;			\
	   while(e->field.right != NULL) {	\
	     e = e->field.right;		\
	   }					\
	 } else {				\
	   typeof(e) f;				\
	   do {					\
	     f = e;				\
	     e = e->field.parent;		\
	   } while(e && f == e->field.left);	\
	 }					\
       }))

/**
 * Remove the given node
 */
#define RB_REMOVE(head, e, field)					 \
do {									 \
  int swapColor;							 \
  typeof(e) x, y, z = e, x_parent, w;					 \
									 \
  y = z;								 \
  if (y == (head)->first) {						 \
    (head)->first = RB_NEXT(y, field);				         \
  }									 \
  if (y == (head)->last) {						 \
    (head)->last = RB_PREV(y, field);				         \
  }									 \
  if (y->field.left == NULL) {						 \
    x = y->field.right;							 \
  }									 \
  else {								 \
    if (y->field.right == NULL) {					 \
      x = y->field.left;						 \
    }									 \
    else {								 \
      y = y->field.right;						 \
      while (y->field.left != NULL) {					 \
	y = y->field.left;						 \
      }									 \
      x = y->field.right;						 \
    }									 \
  }									 \
  if (y != z) {								 \
    z->field.left->field.parent = y;					 \
    y->field.left = z->field.left;					 \
    if (y != z->field.right) {						 \
      x_parent = y->field.parent;					 \
      if (x != NULL) {							 \
	x->field.parent = y->field.parent;				 \
      }									 \
      y->field.parent->field.left = x;					 \
      y->field.right = z->field.right;					 \
      z->field.right->field.parent = y;					 \
    }									 \
    else {								 \
      x_parent = y;							 \
    }									 \
    if ((head)->root == z) {						 \
      (head)->root = y;							 \
    }									 \
    else if (z->field.parent->field.left == z) {			 \
      z->field.parent->field.left = y;					 \
    }									 \
    else {								 \
      z->field.parent->field.right = y;					 \
    }									 \
    y->field.parent = z->field.parent;					 \
									 \
    swapColor = y->field.color;						 \
    y->field.color = z->field.color;					 \
    z->field.color = swapColor;						 \
									 \
    y = z;								 \
  }									 \
  else {								 \
    x_parent = y->field.parent;						 \
    if (x != NULL) {							 \
      x->field.parent = y->field.parent;				 \
    }									 \
    if ((head)->root == z) {						 \
      (head)->root = x;							 \
    }									 \
    else {								 \
      if (z->field.parent->field.left == z) {				 \
	z->field.parent->field.left = x;				 \
      }									 \
      else {								 \
	z->field.parent->field.right = x;				 \
      }									 \
    }									 \
  }									 \
									 \
  (head)->entries--;							 \
									 \
  if (y->field.color != RB_TREE_NODE_RED) { 				 \
    while (x != (head)->root && 					 \
	   (x == NULL || x->field.color == RB_TREE_NODE_BLACK)) {	 \
      if (x == x_parent->field.left) {					 \
	w = x_parent->field.right;					 \
	if (w->field.color == RB_TREE_NODE_RED) {			 \
	  w->field.color = RB_TREE_NODE_BLACK;				 \
	  x_parent->field.color = RB_TREE_NODE_RED;			 \
	  RB_ROTATE_LEFT(x_parent, field, (head)->root);		 \
	  w = x_parent->field.right;					 \
	}								 \
	if ((w->field.left == NULL || 					 \
	     w->field.left->field.color == RB_TREE_NODE_BLACK) &&	 \
	    (w->field.right == NULL || 					 \
	     w->field.right->field.color == RB_TREE_NODE_BLACK)) {	 \
									 \
	  w->field.color = RB_TREE_NODE_RED;				 \
	  x = x_parent;							 \
	  x_parent = x_parent->field.parent;				 \
	} else {							 \
	  if (w->field.right == NULL || 				 \
	      w->field.right->field.color == RB_TREE_NODE_BLACK) {	 \
									 \
	    if (w->field.left) {					 \
	      w->field.left->field.color = RB_TREE_NODE_BLACK;		 \
	    }								 \
	    w->field.color = RB_TREE_NODE_RED;				 \
	    RB_ROTATE_RIGHT(w, field, (head)->root);			 \
	    w = x_parent->field.right;					 \
	  }								 \
	  w->field.color = x_parent->field.color;			 \
	  x_parent->field.color = RB_TREE_NODE_BLACK;			 \
	  if (w->field.right) {						 \
	    w->field.right->field.color = RB_TREE_NODE_BLACK;		 \
	  }								 \
	  RB_ROTATE_LEFT(x_parent, field, (head)->root);		 \
	  break;							 \
	}								 \
      }									 \
      else {								 \
	w = x_parent->field.left;					 \
	if (w->field.color == RB_TREE_NODE_RED) {			 \
	  w->field.color = RB_TREE_NODE_BLACK;				 \
	  x_parent->field.color = RB_TREE_NODE_RED;			 \
	  RB_ROTATE_RIGHT(x_parent, field, (head)->root);		 \
	  w = x_parent->field.left;					 \
	}								 \
	if ((w->field.right == NULL || 					 \
	     w->field.right->field.color == RB_TREE_NODE_BLACK) &&	 \
	    (w->field.left == NULL || 					 \
	     w->field.left->field.color == RB_TREE_NODE_BLACK)) {	 \
									 \
	  w->field.color = RB_TREE_NODE_RED;				 \
	  x = x_parent;							 \
	  x_parent = x_parent->field.parent;				 \
	}								 \
	else {								 \
	  if (w->field.left == NULL || 					 \
	      w->field.left->field.color == RB_TREE_NODE_BLACK) {	 \
									 \
	    if (w->field.right) {					 \
	      w->field.right->field.color = RB_TREE_NODE_BLACK;		 \
	    }								 \
	    w->field.color = RB_TREE_NODE_RED;				 \
	    RB_ROTATE_LEFT(w, field, (head)->root);			 \
	    w = x_parent->field.left;					 \
	  }								 \
	  w->field.color = x_parent->field.color;			 \
	  x_parent->field.color = RB_TREE_NODE_BLACK;			 \
	  if (w->field.left) {						 \
	    w->field.left->field.color = RB_TREE_NODE_BLACK;		 \
	  }								 \
	  RB_ROTATE_RIGHT(x_parent, field, (head)->root);		 \
	  break;							 \
	}								 \
      }									 \
    }									 \
    if (x) {								 \
      x->field.color = RB_TREE_NODE_BLACK;				 \
    }									 \
  }									 \
} while(0)



/**
 * Finds a node
 */
#define RB_FIND(head, skel, field, cmpfunc)	\
({						\
  int res;                                        \
  typeof(skel) c = (head)->root;		\
  while(c != NULL) {				\
    res = cmpfunc(skel, c);			\
    if(res < 0) {				\
      c = c->field.left;			\
    } else if(res > 0) {			\
      c = c->field.right;			\
    } else {					\
      break;					\
    }						\
  }						\
 c;						\
}) 



/**
 * Finds first node greater than 'skel'
 */
#define RB_FIND_GT(head, skel, field, cmpfunc)	  \
({						  \
  int res;                                        \
  typeof(skel) c = (head)->root, x = NULL;	  \
  while(c != NULL) {				  \
    res = cmpfunc(skel, c);			  \
    if(res < 0) {				  \
      x = c;					  \
      c = c->field.left;			  \
    } else if(res > 0) {			  \
      c = c->field.right;			  \
    } else {					  \
      x = RB_NEXT(c, field);			  \
      break;					  \
    }						  \
  }						  \
 x;						  \
})

/**
 * Finds a node greater or equal to 'skel'
 */
#define RB_FIND_GE(head, skel, field, cmpfunc)	  \
({						  \
  int res;                                        \
  typeof(skel) c = (head)->root, x = NULL;	  \
  while(c != NULL) {				  \
    res = cmpfunc(skel, c);			  \
    if(res < 0) {				  \
      x = c;					  \
      c = c->field.left;			  \
    } else if(res > 0) {			  \
      c = c->field.right;			  \
    } else {					  \
      x = c;                   			  \
      break;					  \
    }						  \
  }						  \
 x;						  \
})


/**
 * Finds first node lesser than 'skel'
 */
#define RB_FIND_LT(head, skel, field, cmpfunc)	  \
({						  \
  int res;                                        \
  typeof(skel) c = (head)->root, x = NULL;	  \
  while(c != NULL) {				  \
    res = cmpfunc(skel, c);			  \
    if(res < 0) {				  \
      c = c->field.left;			  \
    } else if(res > 0) {			  \
      x = c;					  \
      c = c->field.right;			  \
    } else {					  \
      x = RB_PREV(c, field);			  \
      break;					  \
    }						  \
  }						  \
 x;						  \
})

/**
 * Finds a node lesser or equal to 'skel'
 */
#define RB_FIND_LE(head, skel, field, cmpfunc)	  \
({						  \
  int res;                                        \
  typeof(skel) c = (head)->root, x = NULL;	  \
  while(c != NULL) {				  \
    res = cmpfunc(skel, c);			  \
    if(res < 0) {				  \
      c = c->field.left;			  \
    } else if(res > 0) {			  \
      x = c;					  \
      c = c->field.right;			  \
    } else {					  \
      x = c;                   			  \
      break;					  \
    }						  \
  }						  \
 x;						  \
})

#endif /* REDBLACK_H_ */
