/// <summary>
        /// If the type parameter is <see cref="NoFlip"/>, nodes are iterated from the smallest
        /// to the largest key (left to right); if the parameter is <see cref="DoFlip"/>,
        /// nodes are iterated from the largest to the smallest key (right to left).
        /// </summary>
        internal bool SiftRecursive <T>(NodeTraversalActions <TKey, TValue, BinaryNode <TKey, TValue>, NodeTraversalAction> nodeActions)
            where T : FlipBase <T>
        {
            if (!nodeActions.InvokePreAction(this))
            {
                return(false);
            }

            if (GetLeftChild <T>() != null && !GetLeftChild <T>().SiftRecursive <T>(nodeActions))
            {
                return(false);
            }

            if (!nodeActions.InvokeInAction(this))
            {
                return(false);
            }

            if (GetRightChild <T>() != null && !GetRightChild <T>().SiftRecursive <T>(nodeActions))
            {
                return(false);
            }

            if (!nodeActions.InvokePostAction(this))
            {
                return(false);
            }

            return(true);
        }
        private bool HandleSift <T>(
            Stack <NodeTraversalToken <BinaryNode <TKey, TValue>, NodeTraversalAction> > stack,
            NodeTraversalActions <TKey, TValue, BinaryNode <TKey, TValue>, NodeTraversalAction> nodeActions)
            where T : FlipBase <T>
        {
            // First and only visit to this node
            if (!nodeActions.InvokePreAction(this))
            {
                return(false);
            }


            // Push actions in reverse order
            var right = GetRightChild <T>();
            var left  = GetLeftChild <T>();

            if (right != null)
            {
                if (nodeActions.HasPostAction)
                {
                    stack.Push(GetNodeTraversalToken(this, NodeTraversalAction.PostAction));
                }
                stack.Push(GetNodeTraversalToken(right, NodeTraversalAction.Sift));
            }
            else if (left != null && nodeActions.HasPostAction)
            {
                // We need to store the action (it has to be executed after sifting through Left)
                stack.Push(GetNodeTraversalToken(this, NodeTraversalAction.PostAction));
            }

            if (left != null)
            {
                if (nodeActions.HasInAction)
                {
                    stack.Push(GetNodeTraversalToken(this, NodeTraversalAction.InAction));
                }
                stack.Push(GetNodeTraversalToken(left, NodeTraversalAction.Sift));
            }
            else
            {
                // Handle missing children -- we can only invoke actions right away if children are null from left to right
                if (!nodeActions.InvokeInAction(this))
                {
                    return(false);
                }

                if (right == null)
                {
                    if (!nodeActions.InvokePostAction(this))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
        /// <summary>
        /// If the type parameter is <see cref="NoFlip"/>, nodes are iterated from the smallest
        /// to the largest key (left to right); if the parameter is <see cref="DoFlip"/>,
        /// nodes are iterated from the largest to the smallest key (right to left).
        /// </summary>
        private bool Sift <T>(NodeTraversalActions <TKey, TValue, BinaryNode <TKey, TValue>, NodeTraversalAction> nodeActions)
            where T : FlipBase <T>
        {
            // We have to use an iterative way because the default stack size of .net apps is 1MB
            // and it's impractical to change it.....
            var stack = nodeActions.TraversalStack;

            Debug.Assert(stack.Count == 0);
            stack.Push(GetNodeTraversalToken(this, NodeTraversalAction.Sift));

            try
            {
                while (stack.Count > 0)
                {
                    var token = stack.Pop();

                    switch (token.Action)
                    {
                    case NodeTraversalAction.Sift:
                        if (!token.Node.HandleSift <T>(stack, nodeActions))
                        {
                            return(false);
                        }
                        break;

                    case NodeTraversalAction.InAction:
                        if (!nodeActions.InvokeInAction(token.Node))
                        {
                            return(false);
                        }
                        break;

                    case NodeTraversalAction.PostAction:
                        if (!nodeActions.InvokePostAction(token.Node))
                        {
                            return(false);
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            }
            finally
            {
                stack.Clear();
            }

            return(true);
        }