QueryBranchOp.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Dispatcher / QueryBranchOp.cs / 1 / QueryBranchOp.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{ 
    using System.Diagnostics;
    using System.ServiceModel.Channels; 
    using System.Collections; 
    using System.Collections.Generic;
 
    internal 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 
            {
                DiagnosticUtility.DebugAssert(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) 
        {
            DiagnosticUtility.DebugAssert(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 
            {
                DiagnosticUtility.DebugAssert(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();
            } 
        }

    }
 
    internal 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)
        {
            DiagnosticUtility.DebugAssert(null != context, ""); 

            StackFrame arg = context.TopArg; 
            for (int i = arg.basePtr; i <= arg.endPtr; ++i) 
            {
                DiagnosticUtility.DebugAssert(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
    } 

    internal 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 
    internal 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 
    internal 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; 
        } 
    }
 
    internal class NoOpOpcode : Opcode
    {
        internal NoOpOpcode(OpcodeID id)
            : base(id) 
        {
        } 
 
    }
 
    internal class BlockEndOpcode : Opcode
    {
        QueryBuffer sourceJumps;
 
        internal BlockEndOpcode()
            : base(OpcodeID.BlockEnd) 
        { 
            this.sourceJumps = new QueryBuffer(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();
        }

    } 

    internal 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 
    }
 
    internal 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();
            } 
        }
    }

    internal 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;
            }
        } 
    }
 
    internal 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)
        {
            DiagnosticUtility.DebugAssert(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)
        {
            DiagnosticUtility.DebugAssert(null != branch, "");
            int index = this.IndexOf(branch); 
            if (index >= 0)
            { 
                this.RemoveAt(index); 
                return true;
            } 

            return false;
        }
 
        internal void RemoveAt(int index)
        { 
            DiagnosticUtility.DebugAssert(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();
                } 
            } 
        }
    } 

    internal 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) 
        { 
            DiagnosticUtility.DebugAssert(null != opcode, "");
 
            // Make sure the same opcode doesn't already exist..
            DiagnosticUtility.DebugAssert(-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 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.FxMatch)) 
                            { 
                                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); 
            } 
        }
 
        /// 
        /// 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.
        ///  
        /// 
        ///  
        internal override Opcode Locate(Opcode opcode) 
        {
            DiagnosticUtility.DebugAssert(!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) 
        { 
            DiagnosticUtility.DebugAssert(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(); 
            }
        } 
    }

    internal 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 results; 
        QueryBranchResultSet next;
        internal static SortComparer comparer = new SortComparer(); 
 
        internal QueryBranchResultSet()
            : this(2) 
        {
        }

        internal QueryBranchResultSet(int capacity) 
        {
            this.results = new QueryBuffer(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 
        {
            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;
            }
        } 
    }
 
    internal 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) 
        { 
            DiagnosticUtility.DebugAssert(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) 
        { 
            DiagnosticUtility.DebugAssert(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);
        } 
    }

    internal abstract class QueryBranchIndex
    { 
        internal abstract int Count
        { 
            get; 
        }
        internal abstract QueryBranch this[object key] 
        {
            get;
            set;
        } 

        internal abstract void CollectXPathFilters(ICollection 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();
    } 
 
    internal class QueryConditionalBranchOpcode : Opcode
    { 
        QueryBranchTable alwaysBranches;
        QueryBranchIndex branchIndex;
        int nextID;
 
        internal QueryConditionalBranchOpcode(OpcodeID id, QueryBranchIndex branchIndex)
            : base(id) 
        { 
            DiagnosticUtility.DebugAssert(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
            { 
                DiagnosticUtility.DebugAssert(!object.ReferenceEquals(queryBranch.Branch, literal), "");
                DiagnosticUtility.DebugAssert(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);
            DiagnosticUtility.DebugAssert(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) 
        { 
            DiagnosticUtility.DebugAssert(null != literal && null != next, "");
 
            QueryBranch literalBranch = this.branchIndex[literal.Literal];
            DiagnosticUtility.DebugAssert(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
            { 
                DiagnosticUtility.DebugAssert(!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 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) 
        {
            DiagnosticUtility.DebugAssert(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)
            { 
                DiagnosticUtility.DebugAssert(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)); 
        }
 
        ///  
        /// Returns true if this branch can accept 'opcode' being added to it
        ///  
        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);
            DiagnosticUtility.DebugAssert(null != literal, ""); 
 
            QueryBranch branch = this.branchIndex[literal.Literal];
            DiagnosticUtility.DebugAssert(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; 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK