123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
/*******************************************************************************

        copyright:      Copyright (c) 2008 Kris Bell. All rights reserved

        license:        BSD style: $(LICENSE)

        version:        Apr 2008: Initial release

        authors:        Kris, tsalm

        Since:          0.99.7

        Based upon Doug Lea's Java collection package

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

module tango.util.container.RedBlack;

import tango.util.container.model.IContainer;

alias int AttributeDummy;

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

        RedBlack implements basic capabilities of Red-Black trees,
        an efficient kind of balanced binary tree. The particular
        algorithms used are adaptations of those in Corman,
        Lieserson, and Rivest's <EM>Introduction to Algorithms</EM>.
        This class was inspired by (and code cross-checked with) a 
        similar class by Chuck McManis. The implementations of
        rebalancings during insertion and deletion are
        a little trickier than those versions since they
        don't swap Cell contents or use special dummy nilnodes. 

        Doug Lea

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

struct RedBlack (V, A = AttributeDummy)
{
        alias RedBlack!(V, A) Type;
        alias Type            *Ref;

        enum : bool {RED = false, BLACK = true}

        /**
         * Pointer to left child
        **/

        package Ref     left;

        /**
         * Pointer to right child
        **/

        package Ref     right;

        /**
         * Pointer to parent (null if root)
        **/

        package Ref     parent;

        package V       value;

        static if (!is(typeof(A) == AttributeDummy))
        {
               A        attribute;
        }

        /**
         * The node color (RED, BLACK)
        **/

        package bool    color;

        static if (!is(typeof(A) == AttributeDummy))
        {
                final Ref set (V v, A a)
                {
                        attribute = a;
                        return set (v);
                }
        }

        /**
         * Make a new Cell with given value, null links, and BLACK color.
         * Normally only called to establish a new root.
        **/

        final Ref set (V v)
        {
                value = v;
                left = null;
                right = null;
                parent = null;
                color = BLACK;
                return &this;
        }

        /**
         * Return a new Ref with same value and color as self,
         * but with null links. (Since it is never OK to have
         * multiple identical links in a RB tree.)
        **/ 

        protected Ref dup (scope Ref delegate() alloc)
        {
                static if (is(typeof(A) == AttributeDummy))
                           auto t = alloc().set (value);
                       else
                          auto t = alloc().set (value, attribute);

                t.color = color;
                return t;
        }


        /**
         * See_Also: tango.util.collection.model.View.View.checkImplementation.
        **/
        public void checkImplementation ()
        {

                // It's too hard to check the property that every simple
                // path from node to leaf has same number of black nodes.
                // So restrict to the following

                assert(parent is null ||
                       &this is parent.left ||
                       &this is parent.right);

                assert(left is null ||
                       &this is left.parent);

                assert(right is null ||
                       &this is right.parent);

                assert(color is BLACK ||
                       (colorOf(left) is BLACK) && (colorOf(right) is BLACK));

                if (left !is null)
                        left.checkImplementation();
                if (right !is null)
                        right.checkImplementation();
        }

        /**
         * Return the minimum value of the current (sub)tree
        **/

        Ref leftmost ()
        {
                auto p = &this;
                for ( ; p.left; p = p.left) {}
                return p;
        }

        /**
         * Return the maximum value of the current (sub)tree
        **/
        Ref rightmost ()
        {
                auto p = &this;
                for ( ; p.right; p = p.right) {}
                return p;
        }

        /**
         * Return the root (parentless node) of the tree
        **/
        Ref root ()
        {
                auto p = &this;
                for ( ; p.parent; p = p.parent) {}
                return p;
        }

        /**
         * Return true if node is a root (i.e., has a null parent)
        **/

        bool isRoot ()
        {
                return parent is null;
        }


        /**
         * Return the inorder successor, or null if no such
        **/

        Ref successor ()
        {
                if (right)
                    return right.leftmost;

                auto p = parent;
                auto ch = &this;
                while (p && ch is p.right)
                      {
                      ch = p;
                      p = p.parent;
                      }
                return p;
        }

        /**
         * Return the inorder predecessor, or null if no such
        **/

        Ref predecessor ()
        {
                if (left)
                    return left.rightmost;

                auto p = parent;
                auto ch = &this;
                while (p && ch is p.left)
                      {
                      ch = p;
                      p = p.parent;
                      }
                return p;
        }

        /**
         * Return the number of nodes in the subtree
        **/
        @property size_t size ()
        {
                auto c = 1;
                if (left)
                    c += left.size;
                if (right)
                    c += right.size;
                return c;
        }


        /**
         * Return node of current subtree containing value as value(), 
         * if it exists, else null. 
         * Uses Comparator cmp to find and to check equality.
        **/

        Ref find (V value, Compare!(V) cmp)
        {
                auto t = &this;
                for (;;)
                    {
                    auto diff = cmp (value, t.value);
                    if (diff is 0)
                        return t;
                    else
                       if (diff < 0)
                           t = t.left;
                       else
                          t = t.right;
                    if (t is null)
                        break;
                    }
                return null;
        }


        /**
         * Return node of subtree matching "value" 
         * or, if none found, the one just after or before  
         * if it doesn't exist, return null
         * Uses Comparator cmp to find and to check equality.
        **/
        Ref findFirst (V value, Compare!(V) cmp, bool after = true)
        {
                auto t = &this;
                auto tLower = &this;
                auto tGreater  = &this;
            
                for (;;)
                    {
                    auto diff = cmp (value, t.value);
                    if (diff is 0)
                        return t;
                   else
                      if (diff < 0)
                         {
                         tGreater = t;
                         t = t.left;
                         }
                      else
                         {
                         tLower = t;
                         t = t.right;
                         }
                   if (t is null)
                       break;
                   }
    
                if (after)
                   { 
                   if (cmp (value, tGreater.value) <= 0)
                       if (cmp (value, tGreater.value) < 0)
                           return tGreater;
                   }
                else
                   {
                   if (cmp (value, tLower.value) >= 0)
                       if (cmp (value, tLower.value) > 0)
                           return tLower;
                   }

                return null;
        }
        
        /**
         * Return number of nodes of current subtree containing value.
         * Uses Comparator cmp to find and to check equality.
        **/
        int count (V value, Compare!(V) cmp)
        {
                auto c = 0;
                auto t = &this;
                while (t)
                      {
                      int diff = cmp (value, t.value);
                      if (diff is 0)
                         {
                         ++c;
                         if (t.left is null)
                             t = t.right;
                         else
                            if (t.right is null)
                                t = t.left;
                            else
                               {
                               c += t.right.count (value, cmp);
                               t = t.left;
                               }
                            }
                         else
                            if (diff < 0)
                                t = t.left;
                            else
                               t = t.right;
                         }
                return c;
        }
        
        static if (!is(typeof(A) == AttributeDummy))
        {
        Ref findAttribute (A attribute, Compare!(A) cmp)
        {
                auto t = &this;

                while (t)
                      {
                      if (t.attribute == attribute)
                          return t;
                      else
                        if (t.right is null)
                            t = t.left;
                        else
                           if (t.left is null)
                               t = t.right;
                           else
                              {
                              auto p = t.left.findAttribute (attribute, cmp);

                              if (p !is null)
                                  return p;
                              else
                                 t = t.right;
                              }
                      }
                return null; // not reached
        }

        int countAttribute (A attrib, Compare!(A) cmp)
        {
                int c = 0;
                auto t = &this;

                while (t)
                      {
                      if (t.attribute == attribute)
                          ++c;

                      if (t.right is null)
                          t = t.left;
                      else
                         if (t.left is null)
                             t = t.right;
                         else
                            {
                            c += t.left.countAttribute (attribute, cmp);
                            t = t.right;
                            }
                      }
                return c;
        }

        /**
         * find and return a cell holding (key, element), or null if no such
        **/
        Ref find (V value, A attribute, Compare!(V) cmp)
        {
                auto t = &this;

                for (;;)
                    {
                    int diff = cmp (value, t.value);
                    if (diff is 0 && t.attribute == attribute)
                        return t;
                    else
                       if (diff <= 0)
                           t = t.left;
                       else
                          t = t.right;

                    if (t is null)
                        break;
                    }
                return null;
        }

        }



        /**
         * Return a new subtree containing each value of current subtree
        **/

        Ref copyTree (scope Ref delegate() alloc)
        {
                auto t = dup (alloc);

                if (left)
                   {
                   t.left = left.copyTree (alloc);
                   t.left.parent = t;
                   }

                if (right)
                   {
                   t.right = right.copyTree (alloc);
                   t.right.parent = t;
                   }

                return t;
        }


        /**
         * There's no generic value insertion. Instead find the
         * place you want to add a node and then invoke insertLeft
         * or insertRight.
         * <P>
         * Insert Cell as the left child of current node, and then
         * rebalance the tree it is in.
         * @param Cell the Cell to add
         * @param root, the root of the current tree
         * Returns: the new root of the current tree. (Rebalancing
         * can change the root!)
        **/


        Ref insertLeft (Ref cell, Ref root)
        {
                left = cell;
                cell.parent = &this;
                return cell.fixAfterInsertion (root);
        }

        /**
         * Insert Cell as the right child of current node, and then
         * rebalance the tree it is in.
         * @param Cell the Cell to add
         * @param root, the root of the current tree
         * Returns: the new root of the current tree. (Rebalancing
         * can change the root!)
        **/

        Ref insertRight (Ref cell, Ref root)
        {
                right = cell;
                cell.parent = &this;
                return cell.fixAfterInsertion (root);
        }


        /**
         * Delete the current node, and then rebalance the tree it is in
         * @param root the root of the current tree
         * Returns: the new root of the current tree. (Rebalancing
         * can change the root!)
        **/


        Ref remove (Ref root)
        {
                // handle case where we are only node
                if (left is null && right is null && parent is null)
                    return null;

                // if strictly internal, swap places with a successor
                if (left && right)
                   {
                   auto s = successor;

                   // To work nicely with arbitrary subclasses of Ref, we don't want to
                   // just copy successor's fields. since we don't know what
                   // they are.  Instead we swap positions _in the tree.
                   root = swapPosition (&this, s, root);
                   }

                // Start fixup at replacement node (normally a child).
                // But if no children, fake it by using self

                if (left is null && right is null)
                   {
                   if (color is BLACK)
                       root = this.fixAfterDeletion (root);

                   // Unlink  (Couldn't before since fixAfterDeletion needs parent ptr)
                   if (parent)
                      {
                      if (&this is parent.left)
                          parent.left = null;
                      else
                         if (&this is parent.right)
                             parent.right = null;
                      parent = null;
                      }
                   }
                else
                   {
                   auto replacement = left;
                   if (replacement is null)
                       replacement = right;

                   // link replacement to parent
                   replacement.parent = parent;

                   if (parent is null)
                       root = replacement;
                   else
                      if (&this is parent.left)
                          parent.left = replacement;
                      else
                         parent.right = replacement;

                   left = null;
                   right = null;
                   parent = null;
        
                   // fix replacement
                   if (color is BLACK)
                       root = replacement.fixAfterDeletion (root);
                   }
                return root;
        }

        /**
         * Swap the linkages of two nodes in a tree.
         * Return new root, in case it changed.
        **/

        static Ref swapPosition (Ref x, Ref y, Ref root)
        {
                /* Too messy. TODO: find sequence of assigments that are always OK */

                auto px = x.parent;
                bool xpl = px !is null && x is px.left;
                auto lx = x.left;
                auto rx = x.right;

                auto py = y.parent;
                bool ypl = py !is null && y is py.left;
                auto ly = y.left;
                auto ry = y.right;

                if (x is py)
                   {
                   y.parent = px;
                   if (px !is null)
                      {
                       if (xpl)
                           px.left = y;
                       else
                          px.right = y;
                      }
                   x.parent = y;
                   if (ypl)
                      {
                      y.left = x;
                      y.right = rx;
                      if (rx !is null)
                      rx.parent = y;
                      }
                   else
                      {
                      y.right = x;
                      y.left = lx;
                      if (lx !is null)
                      lx.parent = y;
                      }

                   x.left = ly;
                   if (ly !is null)
                       ly.parent = x;

                   x.right = ry;
                   if (ry !is null)
                       ry.parent = x;
                   }
                else
                {
                   if (y is px)
                      {
                      x.parent = py;
                      if (py !is null)
                         {
                          if (ypl)
                              py.left = x;
                          else
                             py.right = x;
                         }
                      y.parent = x;
                      if (xpl)
                         {
                         x.left = y;
                         x.right = ry;
                         if (ry !is null)
                             ry.parent = x;
                         }
                      else
                         {
                         x.right = y;
                         x.left = ly;
                         if (ly !is null)
                             ly.parent = x;
                         }

                      y.left = lx;
                      if (lx !is null)
                          lx.parent = y;

                      y.right = rx;
                      if (rx !is null)
                          rx.parent = y;
                      }
                   else
                      {
                      x.parent = py;
                      if (py !is null)
                         {
                          if (ypl)
                              py.left = x;
                          else
                             py.right = x;
                         }
                      x.left = ly;
                      if (ly !is null)
                          ly.parent = x;

                      x.right = ry;
                      if (ry !is null)
                          ry.parent = x;
        
                      y.parent = px;
                      if (px !is null)
                         {
                          if (xpl)
                              px.left = y;
                          else
                             px.right = y;
                         }
                      y.left = lx;
                      if (lx !is null)
                          lx.parent = y;

                      y.right = rx;
                      if (rx !is null)
                          rx.parent = y;
                      }
                }
                bool c = x.color;
                x.color = y.color;
                y.color = c;

                if (root is x)
                    root = y;
                else
                   if (root is y)
                       root = x;
                return root;
        }



        /**
         * Return color of node p, or BLACK if p is null
         * (In the CLR version, they use
         * a special dummy `nil' node for such purposes, but that doesn't
         * work well here, since it could lead to creating one such special
         * node per real node.)
         *
        **/

        static bool colorOf (Ref p)
        {
                return (p is null) ? BLACK : p.color;
        }

        /**
         * return parent of node p, or null if p is null
        **/
        static Ref parentOf (Ref p)
        {
                return (p is null) ? null : p.parent;
        }

        /**
         * Set the color of node p, or do nothing if p is null
        **/

        static void setColor (Ref p, bool c)
        {
                if (p !is null)
                    p.color = c;
        }

        /**
         * return left child of node p, or null if p is null
        **/

        static Ref leftOf (Ref p)
        {
                return (p is null) ? null : p.left;
        }

        /**
         * return right child of node p, or null if p is null
        **/

        static Ref rightOf (Ref p)
        {
                return (p is null) ? null : p.right;
        }


        /** From CLR **/
        package Ref rotateLeft (Ref root)
        {
                auto r = right;
                right = r.left;

                if (r.left)
                    r.left.parent = &this;

                r.parent = parent;
                if (parent is null)
                    root = r;
                else
                   if (parent.left is &this)
                       parent.left = r;
                   else
                      parent.right = r;

                r.left = &this;
                parent = r;
                return root;
        }

        /** From CLR **/
        package Ref rotateRight (Ref root)
        {
                auto l = left;
                left = l.right;

                if (l.right !is null)
                   l.right.parent = &this;

                l.parent = parent;
                if (parent is null)
                    root = l;
                else
                   if (parent.right is &this)
                       parent.right = l;
                   else
                      parent.left = l;

                l.right = &this;
                parent = l;
                return root;
        }


        /** From CLR **/
        package Ref fixAfterInsertion (Ref root)
        {
                color = RED;
                auto x = &this;

                while (x && x !is root && x.parent.color is RED)
                      {
                      if (parentOf(x) is leftOf(parentOf(parentOf(x))))
                         {
                         auto y = rightOf(parentOf(parentOf(x)));
                         if (colorOf(y) is RED)
                            {
                            setColor(parentOf(x), BLACK);
                            setColor(y, BLACK);
                            setColor(parentOf(parentOf(x)), RED);
                            x = parentOf(parentOf(x));
                            }
                         else
                            {
                            if (x is rightOf(parentOf(x)))
                               {
                               x = parentOf(x);
                               root = x.rotateLeft(root);
                               }

                            setColor(parentOf(x), BLACK);
                            setColor(parentOf(parentOf(x)), RED);
                            if (parentOf(parentOf(x)) !is null)
                                root = parentOf(parentOf(x)).rotateRight(root);
                            }
                         }
                      else
                         {
                         auto y = leftOf(parentOf(parentOf(x)));
                         if (colorOf(y) is RED)
                            {
                            setColor(parentOf(x), BLACK);
                            setColor(y, BLACK);
                            setColor(parentOf(parentOf(x)), RED);
                            x = parentOf(parentOf(x));
                            }
                         else
                            {
                            if (x is leftOf(parentOf(x)))
                               {
                               x = parentOf(x);
                               root = x.rotateRight(root);
                               }
        
                            setColor(parentOf(x), BLACK);
                            setColor(parentOf(parentOf(x)), RED);
                            if (parentOf(parentOf(x)) !is null)
                                root = parentOf(parentOf(x)).rotateLeft(root);
                            }
                         }
                      }
                root.color = BLACK;
                return root;
        }



        /** From CLR **/
        package Ref fixAfterDeletion(Ref root)
        {
                auto x = &this;
                while (x !is root && colorOf(x) is BLACK)
                      {
                      if (x is leftOf(parentOf(x)))
                         {
                         auto sib = rightOf(parentOf(x));
                         if (colorOf(sib) is RED)
                            {
                            setColor(sib, BLACK);
                            setColor(parentOf(x), RED);
                            root = parentOf(x).rotateLeft(root);
                            sib = rightOf(parentOf(x));
                            }
                         if (colorOf(leftOf(sib)) is BLACK && colorOf(rightOf(sib)) is BLACK)
                            {
                            setColor(sib, RED);
                            x = parentOf(x);
                            }
                         else
                            {
                            if (colorOf(rightOf(sib)) is BLACK)
                               {
                               setColor(leftOf(sib), BLACK);
                               setColor(sib, RED);
                               root = sib.rotateRight(root);
                               sib = rightOf(parentOf(x));
                               }

                            setColor(sib, colorOf(parentOf(x)));
                            setColor(parentOf(x), BLACK);
                            setColor(rightOf(sib), BLACK);
                            root = parentOf(x).rotateLeft(root);
                            x = root;
                            }
                         }
                      else
                         {
                         auto sib = leftOf(parentOf(x));
                         if (colorOf(sib) is RED)
                            {
                            setColor(sib, BLACK);
                            setColor(parentOf(x), RED);
                            root = parentOf(x).rotateRight(root);
                            sib = leftOf(parentOf(x));
                            }

                         if (colorOf(rightOf(sib)) is BLACK && colorOf(leftOf(sib)) is BLACK)
                            {
                            setColor(sib, RED);
                            x = parentOf(x);
                            }
                         else
                            {
                            if (colorOf(leftOf(sib)) is BLACK)
                               {
                               setColor(rightOf(sib), BLACK);
                               setColor(sib, RED);
                               root = sib.rotateLeft(root);
                               sib = leftOf(parentOf(x));
                               }

                            setColor(sib, colorOf(parentOf(x)));
                            setColor(parentOf(x), BLACK);
                            setColor(leftOf(sib), BLACK);
                            root = parentOf(x).rotateRight(root);
                            x = root;
                            }
                         }
                      }

                setColor(x, BLACK);
                return root;
        }
}