File: System\ServiceModel\Dispatcher\QueryBranchOp.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
    using System.Collections.Generic;
    using System.Runtime;
 
    abstract class JumpOpcode : Opcode
    {
        Opcode jump;
 
        internal JumpOpcode(OpcodeID id, Opcode jump)
            : base(id)
        {
            this.Jump = jump;
            this.flags |= OpcodeFlags.Jump;
        }
 
        internal Opcode Jump
        {
            get
            {
                return this.jump;
            }
            set
            {
                Fx.Assert(value.ID == OpcodeID.BlockEnd, "");
                this.AddJump((BlockEndOpcode)value);
            }
        }
 
        internal void AddJump(BlockEndOpcode jumpTo)
        {
            bool conditional = this.IsReachableFromConditional();
            if (conditional)
            {
                this.prev.DelinkFromConditional(this);
            }
 
            if (null == this.jump)
            {
                this.jump = jumpTo;
            }
            else
            {
                BranchOpcode jumpBranch;
                if (this.jump.ID == OpcodeID.Branch)
                {
                    // already a branch
                    jumpBranch = (BranchOpcode)this.jump;
                }
                else
                {
                    BlockEndOpcode currentJump = (BlockEndOpcode)this.jump;
                    jumpBranch = new BranchOpcode();
                    jumpBranch.Branches.Add(currentJump);
                    this.jump = jumpBranch;
                }
                jumpBranch.Branches.Add(jumpTo);
            }
            jumpTo.LinkJump(this);
 
            if (conditional && null != this.jump)
            {
                this.prev.LinkToConditional(this);
            }
        }
 
        internal override void Remove()
        {
            if (null == this.jump)
            {
                base.Remove();
            }
        }
 
        internal void RemoveJump(BlockEndOpcode jumpTo)
        {
            Fx.Assert(null != this.jump, "");
 
            bool conditional = this.IsReachableFromConditional();
            if (conditional)
            {
                this.prev.DelinkFromConditional(this);
            }
 
            if (this.jump.ID == OpcodeID.Branch)
            {
                BranchOpcode jumpBranch = (BranchOpcode)this.jump;
                jumpTo.DeLinkJump(this);
                jumpBranch.RemoveChild(jumpTo);
                if (0 == jumpBranch.Branches.Count)
                {
                    this.jump = null;
                }
            }
            else
            {
                Fx.Assert(object.ReferenceEquals(jumpTo, this.jump), "");
                jumpTo.DeLinkJump(this);
                this.jump = null;
            }
 
            if (conditional && null != this.jump)
            {
                this.prev.LinkToConditional(this);
            }
        }
 
        internal override void Trim()
        {
            if (this.jump.ID == OpcodeID.Branch)
            {
                this.jump.Trim();
            }
        }
 
    }
 
    class JumpIfOpcode : JumpOpcode
    {
        protected bool test;
 
        internal JumpIfOpcode(Opcode jump, bool test)
            : this(OpcodeID.JumpIfNot, jump, test)
        {
        }
 
        protected JumpIfOpcode(OpcodeID id, Opcode jump, bool test)
            : base(id, jump)
        {
            this.test = test;
        }
 
        internal bool Test
        {
            get
            {
                return this.test;
            }
        }
 
        internal override bool Equals(Opcode op)
        {
            if (base.Equals(op))
            {
                return (this.test == ((JumpIfOpcode)op).test);
            }
 
            return false;
        }
 
        internal override Opcode Eval(ProcessingContext context)
        {
            Fx.Assert(null != context, "");
 
            StackFrame arg = context.TopArg;
            for (int i = arg.basePtr; i <= arg.endPtr; ++i)
            {
                Fx.Assert(context.Values[i].IsType(ValueDataType.Boolean), "");
                if (this.test == context.Values[i].Boolean)
                {
                    // At least one result satisfies the test. Don't branch
                    return this.next;
                }
            }
 
            // Jump, since no result is satisfactory..
            return this.Jump;
        }
 
#if DEBUG_FILTER
        public override string ToString()
        {
            return string.Format("{0} {1}", base.ToString(), this.test);
        }
#endif
    }
 
    class ApplyBooleanOpcode : JumpIfOpcode
    {
        internal ApplyBooleanOpcode(Opcode jump, bool test)
            : this(OpcodeID.ApplyBoolean, jump, test)
        {
        }
 
        protected ApplyBooleanOpcode(OpcodeID id, Opcode jump, bool test)
            : base(id, jump, test)
        {
        }
 
        internal override Opcode Eval(ProcessingContext context)
        {
            int matchCount = this.UpdateResultMask(context);
            context.PopFrame();
            if (0 == matchCount)
            {
                return this.Jump;
            }
 
            return this.next;
        }
 
        protected int UpdateResultMask(ProcessingContext context)
        {
            StackFrame results = context.TopArg;
            StackFrame resultMask = context.SecondArg;
            Value[] values = context.Values;
            int testCount = 0;
 
            for (int maskIndex = resultMask.basePtr, resultIndex = results.basePtr; maskIndex <= resultMask.endPtr; ++maskIndex)
            {
                if (this.test == values[maskIndex].Boolean)
                {
                    bool boolResult = values[resultIndex].Boolean;
                    if (this.test == boolResult)
                    {
                        testCount++;
                    }
                    values[maskIndex].Boolean = boolResult;
                    ++resultIndex;
                }
            }
            return testCount;
        }
 
#if DEBUG_FILTER
        public override string ToString()
        {
            return string.Format("{0} {1}", base.ToString(), this.test);
        }
#endif
    }
 
    // 'And' booleans: test is true
    // 'Or' booleans: test is false
    class StartBooleanOpcode : Opcode
    {
        bool test;
 
        internal StartBooleanOpcode(bool test)
            : base(OpcodeID.StartBoolean)
        {
            this.test = test;
        }
 
        internal override bool Equals(Opcode op)
        {
            if (base.Equals(op))
            {
                return (((StartBooleanOpcode)op).test == this.test);
            }
 
            return false;
        }
 
        internal override Opcode Eval(ProcessingContext context)
        {
            StackFrame sequences = context.TopSequenceArg;
            Value[] values = context.Values;
            StackFrame resultMask = context.TopArg;
            Value[] sequenceBuffer = context.Sequences;
 
            context.PushSequenceFrame();
            for (int seqIndex = sequences.basePtr; seqIndex <= sequences.endPtr; ++seqIndex)
            {
                NodeSequence sourceSeq = sequenceBuffer[seqIndex].Sequence;
                if (sourceSeq.Count > 0)
                {
                    NodeSequenceItem[] items = sourceSeq.Items;
                    NodeSequence newSeq = null;
                    // Loop over the sequence, selecting those items for which the previous expression returned a result that
                    // matches the test value. Only those items will be processed further
                    // Note that the original position and size information is retained.
                    for (int i = resultMask.basePtr, n = 0; i <= resultMask.endPtr; ++i, ++n)
                    {
                        if (this.test == values[i].Boolean)
                        {
                            if (null == newSeq)
                            {
                                newSeq = context.CreateSequence();
                            }
                            newSeq.AddCopy(ref items[n], NodeSequence.GetContextSize(sourceSeq, n));
                        }
                        else
                        {
                            if (items[n].Last && null != newSeq)
                            {
                                newSeq.Items[newSeq.Count - 1].Last = true; // maintain nodeset boundaries...
                            }
                        }
                    }
                    context.PushSequence((null == newSeq) ? NodeSequence.Empty : newSeq);
                    newSeq = null;
                }
            }
 
            return this.next;
        }
 
#if DEBUG_FILTER
        public override string ToString()
        {
            return string.Format("{0} {1}", base.ToString(), this.test);
        }
#endif
    }
 
    // 'And' booleans: test is true
    // 'Or' booleans: test is false
    class EndBooleanOpcode : ApplyBooleanOpcode
    {
        internal EndBooleanOpcode(Opcode jump, bool test)
            : base(OpcodeID.EndBoolean, jump, test)
        {
        }
 
        internal override Opcode Eval(ProcessingContext context)
        {
            int matchCount = this.UpdateResultMask(context);
            context.PopFrame();
            context.PopSequenceFrame();
            if (0 == matchCount)
            {
                return this.Jump;
            }
 
            return this.next;
        }
    }
 
    class NoOpOpcode : Opcode
    {
        internal NoOpOpcode(OpcodeID id)
            : base(id)
        {
        }
    }
 
    class BlockEndOpcode : Opcode
    {
        QueryBuffer<Opcode> sourceJumps;
 
        internal BlockEndOpcode()
            : base(OpcodeID.BlockEnd)
        {
            this.sourceJumps = new QueryBuffer<Opcode>(1);
        }
 
        internal void DeLinkJump(Opcode jump)
        {
            this.sourceJumps.Remove(jump);
        }
 
        internal void LinkJump(Opcode jump)
        {
            this.sourceJumps.Add(jump);
        }
 
        internal override void Remove()
        {
            // Before we can remove this blockEnd from the query tree, we have delink all jumps to it
            while (this.sourceJumps.Count > 0)
            {
                ((JumpOpcode)this.sourceJumps[0]).RemoveJump(this);
            }
            base.Remove();
        }
 
    }
 
    class TypecastOpcode : Opcode
    {
        ValueDataType newType;
#if NO
        internal TypecastOpcode(OpcodeID opcode, ValueDataType newType)
            : base(opcode)
        {
            this.newType = newType;
        }
#endif
        internal TypecastOpcode(ValueDataType newType)
            : base(OpcodeID.Cast)
        {
            this.newType = newType;
        }
 
        internal override bool Equals(Opcode op)
        {
            if (base.Equals(op))
            {
                return (this.newType == ((TypecastOpcode)op).newType);
            }
 
            return false;
        }
 
        internal override Opcode Eval(ProcessingContext context)
        {
            StackFrame frame = context.TopArg;
            Value[] values = context.Values;
            for (int i = frame.basePtr; i <= frame.endPtr; ++i)
            {
                values[i].ConvertTo(context, newType);
            }
 
            return this.next;
        }
 
#if DEBUG_FILTER
        public override string ToString()
        {
            return string.Format("{0} {1}", base.ToString(), this.newType.ToString());
        }
#endif
    }
 
    struct BranchContext
    {
        ProcessingContext branchContext;
        ProcessingContext sourceContext;
 
        internal BranchContext(ProcessingContext context)
        {
            this.sourceContext = context;
            this.branchContext = null;
        }
 
        internal ProcessingContext Create()
        {
            if (null == this.branchContext)
            {
                this.branchContext = this.sourceContext.Clone();
            }
            else
            {
                this.branchContext.CopyFrom(this.sourceContext);
            }
            return this.branchContext;
        }
 
        internal void Release()
        {
            if (null != this.branchContext)
            {
                this.branchContext.Release();
            }
        }
    }
 
    class QueryBranch
    {
        internal Opcode branch;
        internal int id;
#if NO
        internal QueryBranch(Opcode branch)
            : this(branch, int.MinValue)
        {
        }
#endif
        internal QueryBranch(Opcode branch, int id)
        {
            this.branch = branch;
            this.id = id;
        }
 
        internal Opcode Branch
        {
            get
            {
                return this.branch;
            }
#if NO
            set
            {
                this.branch = value;
            }
#endif
        }
 
        internal int ID
        {
            get
            {
                return this.id;
            }
        }
    }
 
    class QueryBranchTable
    {
        int count;
        QueryBranch[] branches;
 
        internal QueryBranchTable()
            : this(1)
        {
        }
 
        internal QueryBranchTable(int capacity)
        {
            this.branches = new QueryBranch[capacity];
        }
 
        internal int Count
        {
            get
            {
                return this.count;
            }
        }
 
        internal QueryBranch this[int index]
        {
            get
            {
                return this.branches[index];
            }
        }
#if NO
        internal void Add(QueryBranch entry)
        {
            Fx.Assert(null != entry, "");
            this.InsertAt(this.count, entry);
        }
#endif
        internal void AddInOrder(QueryBranch branch)
        {
            // Insert in sorted order always
            int index;
            for (index = 0; index < this.count; ++index)
            {
                // if current node is >= key, we've found the spot
                if (this.branches[index].ID >= branch.ID)
                {
                    break;
                }
            }
 
            this.InsertAt(index, branch);
        }
 
        void Grow()
        {
            QueryBranch[] branches = new QueryBranch[this.branches.Length + 1];
            Array.Copy(this.branches, branches, this.branches.Length);
            this.branches = branches;
        }
 
        public int IndexOf(Opcode opcode)
        {
            for (int i = 0; i < this.count; ++i)
            {
                if (object.ReferenceEquals(opcode, this.branches[i].Branch))
                {
                    return i;
                }
            }
            return -1;
        }
 
        public int IndexOfID(int id)
        {
            for (int i = 0; i < this.count; ++i)
            {
                if (this.branches[i].ID == id)
                {
                    return i;
                }
            }
            return -1;
        }
 
#if NO
        public int IndexOfEquals(Opcode opcode)
        {
            for (int i = 0; i < this.count; ++i)
            {
                if (this.branches[i].Branch.Equals(opcode))
                {
                    return i;
                }
            }
            return -1;
        }
#endif
        internal void InsertAt(int index, QueryBranch branch)
        {
            if (this.count == this.branches.Length)
            {
                this.Grow();
            }
            if (index < this.count)
            {
                Array.Copy(this.branches, index, this.branches, index + 1, this.count - index);
            }
            this.branches[index] = branch;
            this.count++;
        }
 
        internal bool Remove(Opcode branch)
        {
            Fx.Assert(null != branch, "");
            int index = this.IndexOf(branch);
            if (index >= 0)
            {
                this.RemoveAt(index);
                return true;
            }
 
            return false;
        }
 
        internal void RemoveAt(int index)
        {
            Fx.Assert(index < this.count, "");
            if (index < this.count - 1)
            {
                Array.Copy(this.branches, index + 1, this.branches, index, this.count - index - 1);
            }
            else
            {
                this.branches[index] = null;
            }
            this.count--;
        }
 
        internal void Trim()
        {
            if (this.count < this.branches.Length)
            {
                QueryBranch[] branches = new QueryBranch[this.count];
                Array.Copy(this.branches, branches, this.count);
                this.branches = branches;
            }
 
            for (int i = 0; i < this.branches.Length; ++i)
            {
                if (this.branches[i] != null && this.branches[i].Branch != null)
                {
                    this.branches[i].Branch.Trim();
                }
            }
        }
    }
 
    class BranchOpcode : Opcode
    {
        OpcodeList branches;
 
        internal BranchOpcode()
            : this(OpcodeID.Branch)
        {
        }
 
        internal BranchOpcode(OpcodeID id)
            : base(id)
        {
            this.flags |= OpcodeFlags.Branch;
            this.branches = new OpcodeList(2);
        }
 
        internal OpcodeList Branches
        {
            get
            {
                return this.branches;
            }
        }
 
        internal override void Add(Opcode opcode)
        {
            // Add with maximum affinity.. find a similar opcode, if we can, and call its Add method
            for (int i = 0; i < this.branches.Count; ++i)
            {
                if (this.branches[i].IsEquivalentForAdd(opcode))
                {
                    this.branches[i].Add(opcode);
                    return;
                }
            }
 
            // Ok.. no similar opcode. Add it just like any other branch
            this.AddBranch(opcode);
        }
 
        internal override void AddBranch(Opcode opcode)
        {
            Fx.Assert(null != opcode, "");
 
            // Make sure the same opcode doesn't already exist..
            Fx.Assert(-1 == this.branches.IndexOf(opcode), "");
            this.branches.Add(opcode);
            opcode.Prev = this;
 
            // If this branch is in a conditional, then this new opcode must be added to that conditional..
            if (this.IsInConditional())
            {
                this.LinkToConditional(opcode);
            }
        }
 
        internal override void CollectXPathFilters(ICollection<MessageFilter> filters)
        {
            for (int i = 0; i < this.branches.Count; ++i)
            {
                this.branches[i].CollectXPathFilters(filters);
            }
        }
 
        internal override void DelinkFromConditional(Opcode child)
        {
            if (null != this.prev)
            {
                this.prev.DelinkFromConditional(child);
            }
        }
        internal override Opcode Eval(ProcessingContext context)
        {
            QueryProcessor processor = context.Processor;
            SeekableXPathNavigator contextNode = processor.ContextNode;
            int marker = processor.CounterMarker;
            long pos = contextNode.CurrentPosition;
            Opcode branch;
            int i = 0;
            int branchCount = this.branches.Count;
            try
            {
                if (context.StacksInUse)
                {
                    // If we have N branches, eval N-1 in a cloned context and the remainder in the
                    // original one
                    if (--branchCount > 0)
                    {
                        // Evaluate all but the first branch with a clone of the current context
                        // The first branch (right most) can be evaluated with the current context                        
                        BranchContext branchContext = new BranchContext(context); // struct. fast
                        for (; i < branchCount; ++i)
                        {
                            branch = this.branches[i];
                            if (0 != (branch.Flags & OpcodeFlags.Fx))
                            {
                                branch.Eval(context);
                            }
                            else
                            {
                                // This allocates a solitary context and then reuses it repeatedly
                                ProcessingContext newContext = branchContext.Create();
                                while (null != branch)
                                {
                                    branch = branch.Eval(newContext);
                                }
                            }
                            contextNode.CurrentPosition = pos;  // restore the navigator to its original position
                            processor.CounterMarker = marker;   // and the node count marker
                        }
                        branchContext.Release();
                    }
 
                    // Do the final branch with the existing context
                    branch = branches[i];
                    while (null != branch)
                    {
                        branch = branch.Eval(context);
                    }
                }
                else // since there is nothing on the stack, there is nothing to clone
                {
                    int nodeCountSav = context.NodeCount;
                    for (; i < branchCount; ++i)
                    {
                        branch = branches[i];
                        // Evaluate this branch
                        while (null != branch)
                        {
                            branch = branch.Eval(context);
                        }
                        // Restore the current context to its pristine state, so we can reuse it
                        context.ClearContext();
                        context.NodeCount = nodeCountSav;
                        contextNode.CurrentPosition = pos;
                        processor.CounterMarker = marker;
                    }
                }
            }
            catch (XPathNavigatorException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(branches[i]));
            }
            catch (NavigatorInvalidBodyAccessException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(branches[i]));
            }
            processor.CounterMarker = marker;
 
            return this.next;
        }
 
        internal override bool IsInConditional()
        {
            if (null != this.prev)
            {
                return this.prev.IsInConditional();
            }
 
            return true;
        }
 
        internal override void LinkToConditional(Opcode child)
        {
            if (null != this.prev)
            {
                this.prev.LinkToConditional(child);
            }
        }
 
        /// <summary>
        /// Loop over all branches, trying to locate one that is equal to the given opcode
        /// If the branch is a branch itself, perform the locate recursively.
        /// </summary>
        /// <param name="opcode"></param>
        /// <returns></returns>
        internal override Opcode Locate(Opcode opcode)
        {
            Fx.Assert(!opcode.TestFlag(OpcodeFlags.Branch), "");
 
            for (int i = 0, count = this.branches.Count; i < count; ++i)
            {
                Opcode branch = this.branches[i];
                if (branch.TestFlag(OpcodeFlags.Branch))
                {
                    // The branch is itself a branch. Since branch opcodes serve as branches in the exection
                    // path for a query, but don't comprise one of the opcodes used to actually perform it, we
                    // recursively try to locate an equivalent opcode inside the branch
                    Opcode subBranch = branch.Locate(opcode);
                    if (null != subBranch)
                    {
                        return subBranch;
                    }
                }
                else if (branch.Equals(opcode))
                {
                    return branch;
                }
            }
 
            return null;
        }
 
        internal override void Remove()
        {
            if (0 == this.branches.Count)
            {
                base.Remove();
            }
        }
 
        internal override void RemoveChild(Opcode opcode)
        {
            Fx.Assert(null != opcode, "");
 
            if (this.IsInConditional())
            {
                this.DelinkFromConditional(opcode);
            }
            this.branches.Remove(opcode);
            this.branches.Trim();
        }
 
        internal override void Replace(Opcode replace, Opcode with)
        {
            int i = this.branches.IndexOf(replace);
            if (i >= 0)
            {
                replace.Prev = null;
                this.branches[i] = with;
                with.Prev = this;
            }
        }
 
        internal override void Trim()
        {
            this.branches.Trim();
            for (int i = 0; i < this.branches.Count; ++i)
            {
                this.branches[i].Trim();
            }
        }
    }
 
    struct QueryBranchResult
    {
        internal QueryBranch branch;
        int valIndex;
 
        internal QueryBranchResult(QueryBranch branch, int valIndex)
        {
            this.branch = branch;
            this.valIndex = valIndex;
        }
 
        internal QueryBranch Branch
        {
            get
            {
                return this.branch;
            }
        }
 
        internal int ValIndex
        {
            get
            {
                return this.valIndex;
            }
        }
#if NO
        internal void Set(QueryBranch branch, int valIndex)
        {
            this.branch = branch;
            this.valIndex = valIndex;
        }
#endif
    }
 
    internal class QueryBranchResultSet
    {
        QueryBuffer<QueryBranchResult> results;
        QueryBranchResultSet next;
        internal static SortComparer comparer = new SortComparer();
 
        internal QueryBranchResultSet()
            : this(2)
        {
        }
 
        internal QueryBranchResultSet(int capacity)
        {
            this.results = new QueryBuffer<QueryBranchResult>(capacity);
        }
 
        internal int Count
        {
            get
            {
                return this.results.count;
            }
        }
 
        internal QueryBranchResult this[int index]
        {
            get
            {
                return this.results[index];
            }
        }
 
        internal QueryBranchResultSet Next
        {
            get
            {
                return this.next;
            }
            set
            {
                this.next = value;
            }
        }
 
        internal void Add(QueryBranch branch, int valIndex)
        {
            this.results.Add(new QueryBranchResult(branch, valIndex));
        }
 
        internal void Clear()
        {
            this.results.count = 0;
        }
 
        internal void Sort()
        {
            this.results.Sort(QueryBranchResultSet.comparer);
        }
 
        internal class SortComparer : IComparer<QueryBranchResult>
        {
            public bool Equals(QueryBranchResult x, QueryBranchResult y)
            {
                return x.branch.id == y.branch.id;
            }
            public int Compare(QueryBranchResult x, QueryBranchResult y)
            {
                return x.branch.id - y.branch.id;
            }
 
            public int GetHashCode(QueryBranchResult obj)
            {
                return obj.branch.id;
            }
        }
    }
 
    struct BranchMatcher
    {
        int resultCount;
        QueryBranchResultSet resultTable;
 
        internal BranchMatcher(int resultCount, QueryBranchResultSet resultTable)
        {
            this.resultCount = resultCount;
            this.resultTable = resultTable;
        }
 
        internal QueryBranchResultSet ResultTable
        {
            get
            {
                return this.resultTable;
            }
        }
 
        void InitResults(ProcessingContext context)
        {
            context.PushFrame();
            // Push this.resultsCount booleans onto the stack, all set to false
            context.Push(false, this.resultCount);
        }
 
        internal void InvokeMatches(ProcessingContext context)
        {
            Fx.Assert(null != context, "");
 
            switch (this.resultTable.Count)
            {
                default:
                    this.InvokeMultiMatch(context);
                    break;
 
                case 0:
                    break;
 
                case 1:
                    this.InvokeSingleMatch(context);
                    break;
            }
        }
 
        void InvokeMultiMatch(ProcessingContext context)
        {
            int marker = context.Processor.CounterMarker;
            BranchContext branchContext = new BranchContext(context);   // struct. quick.
            int resultTableCount = this.resultTable.Count;
            for (int i = 0; i < resultTableCount; )
            {
                QueryBranchResult result = this.resultTable[i];
                QueryBranch branch = result.Branch;
                // Branches can arbitrarily alter context stacks, rendering them unuseable to other branches. 
                // Therefore, before following a branch, we have to clone the context. Cloning is relatively efficient because
                // can avoid allocating memory in most cases. We cannot, unfortunately, avoid Array copies. 
                //
                // Optimization: 
                // We can avoid cloning altogether when we can predict that the branch does NOT tamper with the stack,
                // or does so in a predictable way. If we are sure that we can restore the stack easily after the branch
                // completes, we have no reason to copy the stack.
                ProcessingContext newContext;
                Opcode nextOpcode = branch.Branch.Next;
                if (nextOpcode.TestFlag(OpcodeFlags.NoContextCopy))
                {
                    newContext = context;
                }
                else
                {
                    newContext = branchContext.Create();
                }
 
                this.InitResults(newContext);
 
                //
                // Matches are sorted by their branch ID.
                // It is very possible that the a literal matches multiple times, especially when the value being 
                // compared is a sequence. A literal may match multiple items in a single sequence 
                // OR multiple items in multiple sequences. If there were 4 context sequences, the literal may have 
                // matched one item each in 3 of them. The branchID for that literal will be present 3 times in the
                // resultTable.
                // Sorting the matches groups them by their branch Ids. We only want to take the branch ONCE, so now we
                // iterate over all the duplicate matches..
                // result.ValIndex will give us the index of the value that was matched. Thus if the 3rd sequence 
                // matched, ValIndex == 2 (0 based)
                newContext.Values[newContext.TopArg[result.ValIndex]].Boolean = true;
                while (++i < resultTableCount)
                {
                    result = this.resultTable[i];
                    if (branch.ID == result.Branch.ID)
                    {
                        newContext.Values[newContext.TopArg[result.ValIndex]].Boolean = true;
                    }
                    else
                    {
                        break;
                    }
                }
                try
                {
                    newContext.EvalCodeBlock(nextOpcode);
                }
                catch (XPathNavigatorException e)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(nextOpcode));
                }
                catch (NavigatorInvalidBodyAccessException e)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(nextOpcode));
                }
                context.Processor.CounterMarker = marker;
            }
            branchContext.Release();
        }
 
        internal void InvokeNonMatches(ProcessingContext context, QueryBranchTable nonMatchTable)
        {
            Fx.Assert(null != context && null != nonMatchTable, "");
 
            int marker = context.Processor.CounterMarker;
            BranchContext branchContext = new BranchContext(context);
            int nonMatchIndex = 0;
            int matchIndex = 0;
            while (matchIndex < this.resultTable.Count && nonMatchIndex < nonMatchTable.Count)
            {
                int compare = this.resultTable[matchIndex].Branch.ID - nonMatchTable[nonMatchIndex].ID;
                if (compare > 0)
                {
                    // Nonmatch < match
                    // Invoke..
                    ProcessingContext newContext = branchContext.Create();
                    this.InvokeNonMatch(newContext, nonMatchTable[nonMatchIndex]);
                    context.Processor.CounterMarker = marker;
                    ++nonMatchIndex;
                }
                else if (0 == compare)
                {
                    ++nonMatchIndex;
                }
                else
                {
                    ++matchIndex;
                }
            }
            // Add remaining
            while (nonMatchIndex < nonMatchTable.Count)
            {
                ProcessingContext newContext = branchContext.Create();
                this.InvokeNonMatch(newContext, nonMatchTable[nonMatchIndex]);
                context.Processor.CounterMarker = marker;
                ++nonMatchIndex;
            }
            branchContext.Release();
        }
 
        void InvokeNonMatch(ProcessingContext context, QueryBranch branch)
        {
            context.PushFrame();
            context.Push(false, this.resultCount);
            try
            {
                context.EvalCodeBlock(branch.Branch);
            }
            catch (XPathNavigatorException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(branch.Branch));
            }
            catch (NavigatorInvalidBodyAccessException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(branch.Branch));
            }
        }
 
        void InvokeSingleMatch(ProcessingContext context)
        {
            int marker = context.Processor.CounterMarker;
            QueryBranchResult result = this.resultTable[0];
            this.InitResults(context);
            context.Values[context.TopArg[result.ValIndex]].Boolean = true;
 
            try
            {
                context.EvalCodeBlock(result.Branch.Branch.Next);
            }
            catch (XPathNavigatorException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(result.Branch.Branch.Next));
            }
            catch (NavigatorInvalidBodyAccessException e)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(result.Branch.Branch.Next));
            }
 
            context.Processor.CounterMarker = marker;
        }
 
        internal void Release(ProcessingContext context)
        {
            context.Processor.ReleaseResults(this.resultTable);
        }
    }
 
    abstract class QueryBranchIndex
    {
        internal abstract int Count
        {
            get;
        }
        internal abstract QueryBranch this[object key]
        {
            get;
            set;
        }
 
        internal abstract void CollectXPathFilters(ICollection<MessageFilter> filters);
 
#if NO
        internal abstract IEnumerator GetEnumerator();
#endif
        internal abstract void Match(int valIndex, ref Value val, QueryBranchResultSet results);
        internal abstract void Remove(object key);
 
        internal abstract void Trim();
    }
 
    class QueryConditionalBranchOpcode : Opcode
    {
        QueryBranchTable alwaysBranches;
        QueryBranchIndex branchIndex;
        int nextID;
 
        internal QueryConditionalBranchOpcode(OpcodeID id, QueryBranchIndex branchIndex)
            : base(id)
        {
            Fx.Assert(null != branchIndex, "");
            this.flags |= OpcodeFlags.Branch;
            this.branchIndex = branchIndex;
            this.nextID = 0;
        }
 
        internal QueryBranchTable AlwaysBranches
        {
            get
            {
                if (null == this.alwaysBranches)
                {
                    this.alwaysBranches = new QueryBranchTable();
                }
                return this.alwaysBranches;
            }
        }
#if NO
        internal QueryBranchIndex BranchIndex
        {
            get
            {
                return this.branchIndex;
            }
        }
#endif
        internal override void Add(Opcode opcode)
        {
            LiteralRelationOpcode literal = this.ValidateOpcode(opcode);
            if (null == literal)
            {
                base.Add(opcode);
                return;
            }
 
            // Was this literal already added to the index?
            QueryBranch queryBranch = this.branchIndex[literal.Literal];
            if (null == queryBranch)
            {
                // First time. New branch
                this.nextID++;
                queryBranch = new QueryBranch(literal, this.nextID);
                literal.Prev = this;
                this.branchIndex[literal.Literal] = queryBranch;
            }
            else
            {
                Fx.Assert(!object.ReferenceEquals(queryBranch.Branch, literal), "");
                Fx.Assert(literal.ID == queryBranch.Branch.ID, "");
                // literal already exists.. but what follows the literal must be branched
                // Should never get here, but just in case
                queryBranch.Branch.Next.Add(literal.Next);
            }
            literal.Flags |= OpcodeFlags.InConditional;
 
            this.AddAlwaysBranch(queryBranch, literal.Next);
        }
 
        internal void AddAlwaysBranch(Opcode literal, Opcode next)
        {
            LiteralRelationOpcode literalOp = this.ValidateOpcode(literal);
            Fx.Assert(null != literalOp, "");
            if (null != literalOp)
            {
                this.AddAlwaysBranch(literalOp, next);
            }
        }
 
        // Whether or not the given literal matches, we must always take the branch rooted at 'next'
        // Add to the AlwaysBranches table if not already there..
        internal void AddAlwaysBranch(LiteralRelationOpcode literal, Opcode next)
        {
            Fx.Assert(null != literal && null != next, "");
 
            QueryBranch literalBranch = this.branchIndex[literal.Literal];
            Fx.Assert(null != literalBranch, "");
 
            this.AddAlwaysBranch(literalBranch, next);
        }
 
        void AddAlwaysBranch(QueryBranch literalBranch, Opcode next)
        {
            if (OpcodeID.Branch == next.ID)
            {
                BranchOpcode opcode = (BranchOpcode)next;
                OpcodeList branches = opcode.Branches;
                for (int i = 0; i < branches.Count; ++i)
                {
                    Opcode branch = branches[i];
                    if (this.IsAlwaysBranch(branch))
                    {
                        this.AlwaysBranches.AddInOrder(new QueryBranch(branch, literalBranch.ID));
                    }
                    else
                    {
                        branch.Flags |= OpcodeFlags.NoContextCopy;
                    }
                }
            }
            else
            {
                Fx.Assert(!next.TestFlag(OpcodeFlags.Branch), "");
                if (this.IsAlwaysBranch(next))
                {
                    this.AlwaysBranches.AddInOrder(new QueryBranch(next, literalBranch.ID));
                }
                else
                {
                    next.Flags |= OpcodeFlags.NoContextCopy;
                }
            }
        }
 
        internal virtual void CollectMatches(int valIndex, ref Value val, QueryBranchResultSet results)
        {
            this.branchIndex.Match(valIndex, ref val, results);
        }
 
        internal override void CollectXPathFilters(ICollection<MessageFilter> filters)
        {
            if (this.alwaysBranches != null)
            {
                for (int i = 0; i < this.alwaysBranches.Count; ++i)
                {
                    this.alwaysBranches[i].Branch.CollectXPathFilters(filters);
                }
            }
 
            this.branchIndex.CollectXPathFilters(filters);
        }
 
        internal override Opcode Eval(ProcessingContext context)
        {
            StackFrame arg = context.TopArg;
            int argCount = arg.Count;
 
            if (argCount > 0)
            {
                QueryBranchResultSet resultSet = context.Processor.CreateResultSet();
                BranchMatcher matcher = new BranchMatcher(argCount, resultSet);
                // Operate on values at the the top frame of the value stack
                // For each source value, find the branch that could be taken
                for (int i = 0; i < argCount; ++i)
                {
                    this.CollectMatches(i, ref context.Values[arg[i]], resultSet);
                }
                // Done with whatever we were testing equality against
                context.PopFrame();
                if (resultSet.Count > 1)
                {
                    // Sort results
                    resultSet.Sort();
                }
 
                // First, do non-true branches..
                if (null != this.alwaysBranches && this.alwaysBranches.Count > 0)
                {
                    matcher.InvokeNonMatches(context, this.alwaysBranches);
                }
 
                // Iterate through matches, invoking each matched branch
                matcher.InvokeMatches(context);
 
                matcher.Release(context);
            }
            else
            {
                context.PopFrame();
            }
            return this.next;
        }
 
        internal QueryBranch GetBranch(Opcode op)
        {
            if (op.TestFlag(OpcodeFlags.Literal))
            {
                LiteralRelationOpcode relOp = this.ValidateOpcode(op);
                if (null != relOp)
                {
                    QueryBranch branch = this.branchIndex[relOp.Literal];
                    if (null != branch && branch.Branch.ID == op.ID)
                    {
                        return branch;
                    }
                }
            }
 
            return null;
        }
 
        bool IsAlwaysBranch(Opcode next)
        {
            Fx.Assert(null != next, "");
 
            // Opcodes subsequent to matching literals must obviously be branched to.
            // The question is whether we should branch to the opcodes following those literals that do *not* match.
            // Naturally, the answer depends on the sort of opcode that succeeds the literal.
            //
            // If the literal is within a boolean conjunction, the succeeding opcode will either be a JumpIfNot
            // Or a BlockEnd.
            // 
            // -If the JumpIfNot is multiway, then always evaluate if it contains ANY non-result only opcodes.
            // -If JumpIfNot(False) -i.e. AND - only evaluate if the opcode succeeding the jump is NOT a result opcode.
            // -If JumpIfNot(True) - i.e. OR - always evaluate
            // 
            // -If BlockEnd - evaluate only if not followed by a result
            //
            // When branching for matching literals, we push trues onto the ValueStack corresponding to the items that 
            // matched. When branching for non-matching literals, we push ALL FALSE values... and then eval.
 
            // is it a the termination of a conditional?
            JumpIfOpcode jump = next as JumpIfOpcode;
            if (null != jump)
            {
                // Is the conditional JumpIfNot(False) = i.e. OR? 
                if (!jump.Test)
                {
                    return true;
                }
 
                // Does the conditional actually jump to anything? Should never be the case, but paranoia demands..
                Opcode jumpTo = jump.Jump;
                if (null == jumpTo)
                {
                    return false;
                }
 
                // Lets see where the jump will take us
                Opcode postJump;
                if (jumpTo.TestFlag(OpcodeFlags.Branch))
                {
                    // Multiway jump
                    OpcodeList branches = ((BranchOpcode)jumpTo).Branches;
                    for (int i = 0; i < branches.Count; ++i)
                    {
                        postJump = branches[i].Next;
                        if (null != postJump && !postJump.TestFlag(OpcodeFlags.Result))
                        {
                            // There is at least one jump here that leads to a non-result.
                            // For now, this dooms everybody to being branched to, whether or not their respective literals
                            // matched
                            return true;
                        }
                    }
                    return false;
                }
 
                // single jump
                postJump = jump.Jump.Next;
                if (null != postJump && postJump.TestFlag(OpcodeFlags.Result))
                {
                    return false;
                }
 
                return true;
            }
 
            // If the next opcode is a BlockEnd, then only bother processing if what follows the block is not a result
            if (OpcodeID.BlockEnd == next.ID)
            {
                Fx.Assert(null != next.Next, "");
                return (!next.Next.TestFlag(OpcodeFlags.Result));
            }
 
            // The literal is not inside a boolean conjunction
            // If the literal is not followed by a result, then we must do further processing after the branch
            return (!next.TestFlag(OpcodeFlags.Result));
        }
 
        /// <summary>
        /// Returns true if this branch can accept 'opcode' being added to it
        /// </summary>
        internal override bool IsEquivalentForAdd(Opcode opcode)
        {
            if (null != this.ValidateOpcode(opcode))
            {
                return true;
            }
 
            return base.IsEquivalentForAdd(opcode);
        }
 
        internal override Opcode Locate(Opcode opcode)
        {
            QueryBranch queryBranch = this.GetBranch(opcode);
            if (null != queryBranch)
            {
                return queryBranch.Branch;
            }
 
            return null;
        }
 
        internal override void Remove()
        {
            if (null == this.branchIndex || 0 == this.branchIndex.Count)
            {
                base.Remove();
            }
        }
 
        internal override void RemoveChild(Opcode opcode)
        {
            LiteralRelationOpcode literal = this.ValidateOpcode(opcode);
            Fx.Assert(null != literal, "");
 
            QueryBranch branch = this.branchIndex[literal.Literal];
            Fx.Assert(null != branch, "");
            this.branchIndex.Remove(literal.Literal);
            branch.Branch.Flags &= (~OpcodeFlags.NoContextCopy);
            if (null != this.alwaysBranches)
            {
                int removeAt = this.alwaysBranches.IndexOfID(branch.ID);
                if (removeAt >= 0)
                {
                    this.alwaysBranches.RemoveAt(removeAt);
                    if (0 == this.alwaysBranches.Count)
                    {
                        this.alwaysBranches = null;
                    }
                }
            }
        }
 
        internal void RemoveAlwaysBranch(Opcode opcode)
        {
            if (null == this.alwaysBranches)
            {
                return;
            }
 
            // Note: if the opcodes below are not in the alwaysBranches table, nothing will happen
            // So arbitrary calls are safe - just makes the removal processor slower (we'll speed it up if necessary)
            if (OpcodeID.Branch == opcode.ID)
            {
                OpcodeList branches = ((BranchOpcode)opcode).Branches;
                for (int i = 0; i < branches.Count; ++i)
                {
                    this.alwaysBranches.Remove(branches[i]);
                }
            }
            else
            {
                this.alwaysBranches.Remove(opcode);
            }
            if (0 == this.alwaysBranches.Count)
            {
                this.alwaysBranches = null;
            }
        }
 
        internal override void Replace(Opcode replace, Opcode with)
        {
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new NotImplementedException(SR.GetString(SR.FilterUnexpectedError)));
        }
 
        internal override void Trim()
        {
            if (this.alwaysBranches != null)
            {
                this.alwaysBranches.Trim();
            }
            this.branchIndex.Trim();
        }
 
        internal virtual LiteralRelationOpcode ValidateOpcode(Opcode opcode)
        {
            return opcode as LiteralRelationOpcode;
        }
    }
}