// 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);
            }
        }
        public void LessOrEqual(RbKey key, out int count, out error err)
        {
            count = 0;
            err   = null;
            if (key == null)
            {
                err = ErrorDef.ArgumentNilError("key");
                return;
            }

            RbTree tree;

            this.checkStateAndGetTree(out tree, out err);
            if (err != null)
            {
                return;
            }

            try
            {
                this.walkLessOrEqual(tree.root, key);
                count = this.CurrentCount();
            }
            finally
            {
                Interlocked.CompareExchange(ref this.state, (long)IterationState.iteratorReady,
                                            (long)IterationState.iteratorWalking);
            }
        }
        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 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);
                }
            }
        }
 // 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;
     }
 }
 // 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;
     }
 }
        // 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);
        }
        public void Between(RbKey loKey, RbKey hiKey, out int count, out error err)
        {
            count = 0;
            err   = null;
            if (loKey == null)
            {
                err = ErrorDef.ArgumentNilError("loKey");
                return;
            }
            if (hiKey == null)
            {
                err = ErrorDef.ArgumentNilError("hiKey");
                return;
            }

            RbTree tree;

            this.checkStateAndGetTree(out tree, out err);
            if (err != null)
            {
                return;
            }

            try
            {
                var cmp = loKey.ComparedTo(hiKey);
                switch (cmp)
                {
                case KeyComparison.KeysAreEqual:
                    var node = tree.find(loKey);
                    if (node != null)
                    {
                        count = 1;
                        this.callback(this, node.key, node.value);
                        return;
                    }
                    return;

                case KeyComparison.KeyIsGreater:
                    var tmp = loKey;
                    loKey = hiKey;
                    hiKey = tmp;
                    break;
                }

                this.walkBetween(tree.root, loKey, hiKey);
                count = this.CurrentCount();
            }
            finally
            {
                Interlocked.CompareExchange(ref this.state, (long)IterationState.iteratorReady,
                                            (long)IterationState.iteratorWalking);
            }
        }
 // Max returns the largest key in the this.
 public void Max(out RbKey key, out object value)
 {
     key   = null;
     value = null;
     if (this.root != null)
     {
         var result = max(this.root);
         key   = result.key;
         value = result.value;
     }
 }
        public KeyComparison ComparedTo(RbKey key)
        {
            var diff = this.value - ((IntKey)key).value;

            if (diff > 0)
            {
                return(KeyComparison.KeyIsGreater);
            }
            if (diff < 0)
            {
                return(KeyComparison.KeyIsLess);
            }
            return(KeyComparison.KeysAreEqual);
        }
 // Ceiling returns the smallest key in the tree greater than or equal to key
 public void Ceiling(RbKey key, out RbKey outKey, out object value)
 {
     outKey = null;
     value  = null;
     if (key != null && this.root != null)
     {
         var node = ceiling(this.root, key);
         if (node != null)
         {
             outKey = node.key;
             value  = node.value;
         }
     }
 }
 // Get returns the stored value if (key found and 'true',
 // otherwise returns 'false' with second return param if (key not found
 public void Get(RbKey key, out object value, out bool success)
 {
     value   = null;
     success = false;
     if (key != null && this.root != null)
     {
         var node = this.find(key);
         if (node != null)
         {
             value   = node.value;
             success = true;
         }
     }
 }
        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);
                }
            }
        }
        // find returns the node if (key found, otherwise returns null
        internal rbNode find(RbKey key)
        {
            for (var node = this.root; node != null;)
            {
                var cmp = key.ComparedTo(node.key);
                switch (cmp)
                {
                case KeyComparison.KeyIsLess:
                    node = node.left;
                    break;

                case KeyComparison.KeyIsGreater:
                    node = node.right;
                    break;

                default:
                    return(node);
                }
            }
            return(null);
        }
 public static void nilIterationCallback(RbIterator iterator, RbKey key, object value)
 {
 }
        // 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));
        }