public void walkLessOrEqual(rbNode node, RbKey key)
        {
            if (node == null || !this.inWalk())
            {
                return;
            }

            if (node.left != null)
            {
                this.walkLessOrEqual(node.left, key);
                if (!this.inWalk())
                {
                    return;
                }
            }

            var cmp = node.key.ComparedTo(key);

            if (cmp == KeyComparison.KeyIsLess || cmp == KeyComparison.KeysAreEqual)
            {
                this.incrementCount();
                this.callback(this, node.key, node.value);
                if (!this.inWalk())
                {
                    return;
                }

                if (node.right != null)
                {
                    this.walkLessOrEqual(node.right, key);
                }
            }
        }
        public void walkGreaterThan(rbNode node, RbKey key)
        {
            if (node == null || !this.inWalk())
            {
                return;
            }

            if (node.key.ComparedTo(key) == KeyComparison.KeyIsGreater)
            {
                if (node.left != null)
                {
                    this.walkGreaterThan(node.left, key);
                    if (!this.inWalk())
                    {
                        return;
                    }
                }

                this.incrementCount();
                this.callback(this, node.key, node.value);
                if (!this.inWalk())
                {
                    return;
                }
            }

            if (node.right != null)
            {
                this.walkGreaterThan(node.right, key);
            }
        }
        public void walkAll(rbNode node)
        {
            if (node == null || !this.inWalk())
            {
                return;
            }

            if (node.left != null)
            {
                this.walkAll(node.left);
                if (!this.inWalk())
                {
                    return;
                }
            }

            this.incrementCount();
            this.callback(this, node.key, node.value);
            if (!this.inWalk())
            {
                return;
            }

            if (node.right != null)
            {
                this.walkAll(node.right);
            }
        }
        // insertNode adds the given key and value into the node
        private rbNode insertNode(rbNode node, RbKey key, object value)
        {
            if (node == null)
            {
                this.count++;
                return(newRbNode(key, value));
            }

            var cmp = key.ComparedTo(node.key);

            switch (cmp)
            {
            case KeyComparison.KeyIsLess:
                node.left = this.insertNode(node.left, key, value);
                break;

            case KeyComparison.KeyIsGreater:
                node.right = this.insertNode(node.right, key, value);
                break;

            default:
                if (this.onInsert == null)
                {
                    node.value = value;
                }
                else
                {
                    node.value = this.onInsert(key, value);
                }
                break;
            }
            return(balance(node));
        }
        // ceilig returns the smallest key node in the subtree rooted at x greater than or equal to the given key
        private rbNode ceiling(rbNode node, RbKey key)
        {
            if (node == null)
            {
                return(null);
            }

            var cmp = key.ComparedTo(node.key);

            switch (cmp)
            {
            case KeyComparison.KeysAreEqual:
                return(node);

            case KeyComparison.KeyIsGreater:
                return(ceiling(node.right, key));

            default:
                var cn = ceiling(node.left, key);
                if (cn != null)
                {
                    return(cn);
                }
                return(node);
            }
        }
        // floor returns the largest key node in the subtree rooted at x less than or equal to the given key
        private rbNode floor(rbNode node, RbKey key)
        {
            if (node == null)
            {
                return(null);
            }

            var cmp = key.ComparedTo(node.key);

            switch (cmp)
            {
            case KeyComparison.KeysAreEqual:
                return(node);

            case KeyComparison.KeyIsLess:
                return(floor(node.left, key));

            default:
                var fn = floor(node.right, key);
                if (fn != null)
                {
                    return(fn);
                }
                return(node);
            }
        }
 // Delete deletes the given key from the tree
 public void Delete(RbKey key)
 {
     this.root = this.deleteNode(this.root, key);
     if (this.root != null)
     {
         this.root.color = black;
     }
 }
 // Insert inserts the given key and value into the tree
 public void Insert(RbKey key, object value)
 {
     if (key != null)
     {
         this.root       = this.insertNode(this.root, key, value);
         this.root.color = black;
     }
 }
        // newRbNode creates a new rbNode and returns its address
        private rbNode newRbNode(RbKey key, object value)
        {
            var result = new rbNode {
                key   = key,
                value = value,
                color = red,
            };

            return(result);
        }
 // moveRedRight makes node.right or one of its children red,
 // assuming that node is red and both children are black.
 private rbNode moveRedRight(rbNode node)
 {
     colorFlip(node);
     if (isRed(node.left.left))
     {
         node = rotateRight(node);
         colorFlip(node);
     }
     return(node);
 }
 // flipColor switchs the color of the node from red to black or black to red
 private void flipColor(rbNode node)
 {
     if (node.color == black)
     {
         node.color = red;
     }
     else
     {
         node.color = black;
     }
 }
 // max finds the greatest node key including the given node
 private rbNode max(rbNode node)
 {
     if (node != null)
     {
         for (; node.right != null;)
         {
             node = node.right;
         }
     }
     return(node);
 }
 // min finds the smallest node key including the given node
 private rbNode min(rbNode node)
 {
     if (node != null)
     {
         for (; node.left != null;)
         {
             node = node.left;
         }
     }
     return(node);
 }
        // rotateRight makes a left-leaning link lean to the right
        private rbNode rotateRight(rbNode node)
        {
            var child = node.left;

            node.left   = child.right;
            child.right = node;
            child.color = node.color;
            node.color  = red;

            return(child);
        }
 // deleteMin removes the smallest key and associated value from the tree
 private rbNode deleteMin(rbNode node)
 {
     if (node.left == null)
     {
         return(null);
     }
     if (isBlack(node.left) && !isRed(node.left.left))
     {
         node = moveRedLeft(node);
     }
     node.left = deleteMin(node.left);
     return(balance(node));
 }
 // balance restores red-black tree invariant
 private rbNode balance(rbNode node)
 {
     if (isRed(node.right))
     {
         node = rotateLeft(node);
     }
     if (isRed(node.left) && isRed(node.left.left))
     {
         node = rotateRight(node);
     }
     if (isRed(node.left) && isRed(node.right))
     {
         colorFlip(node);
     }
     return(node);
 }
        public void walkBetween(rbNode node, RbKey loKey, RbKey hiKey)
        {
            if (node == null || !this.inWalk())
            {
                return;
            }

            var cmpLo = (int)loKey.ComparedTo(node.key);

            if (cmpLo < RbTree.zeroOrEqual)
            {
                if (node.left != null)
                {
                    this.walkBetween(node.left, loKey, hiKey);
                    if (!this.inWalk())
                    {
                        return;
                    }
                }
            }

            var cmpHi = (int)hiKey.ComparedTo(node.key);

            if (cmpLo <= RbTree.zeroOrEqual && cmpHi >= RbTree.zeroOrEqual)
            {
                this.incrementCount();
                this.callback(this, node.key, node.value);
                if (!this.inWalk())
                {
                    return;
                }
            }

            if (cmpHi > RbTree.zeroOrEqual)
            {
                if (node.right != null)
                {
                    this.walkBetween(node.right, loKey, hiKey);
                }
            }
        }
 // isRed checks if (node exists and its color is red
 private bool isRed(rbNode node)
 {
     return(node != null && node.color == red);
 }
 // colorFlip switchs the color of the node and its children from red to black or black to red
 private void colorFlip(rbNode node)
 {
     flipColor(node);
     flipColor(node.left);
     flipColor(node.right);
 }
        // deleteNode deletes the given key from the node
        private rbNode deleteNode(rbNode node, RbKey key)
        {
            if (node == null)
            {
                return(null);
            }

            var cmp = key.ComparedTo(node.key);

            if (cmp == KeyComparison.KeyIsLess)
            {
                if (isBlack(node.left) && !isRed(node.left.left))
                {
                    node = moveRedLeft(node);
                }
                node.left = this.deleteNode(node.left, key);
            }
            else
            {
                if (cmp == KeyComparison.KeysAreEqual && this.onDelete != null)
                {
                    var value = this.onInsert(key, node.value);
                    if (value != null)
                    {
                        node.value = value;
                        return(node);
                    }
                }

                if (isRed(node.left))
                {
                    node = rotateRight(node);
                }

                if (isBlack(node.right) && !isRed(node.right.left))
                {
                    node = moveRedRight(node);
                }

                if (key.ComparedTo(node.key) != KeyComparison.KeysAreEqual)
                {
                    node.right = this.deleteNode(node.right, key);
                }
                else
                {
                    if (node.right == null)
                    {
                        return(null);
                    }

                    var rm = min(node.right);
                    node.key   = rm.key;
                    node.value = rm.value;
                    node.right = deleteMin(node.right);

                    rm.left  = null;
                    rm.right = null;

                    this.count--;
                }
            }
            return(balance(node));
        }
 // isBlack checks if (node exists and its color is black
 private bool isBlack(rbNode node)
 {
     return(node != null && node.color == black);
 }