File: CacheChildrenQuery.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (133 lines) | stat: -rw-r--r-- 5,216 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//------------------------------------------------------------------------------
// <copyright file="CacheChildrenQuery.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------

namespace MS.Internal.Xml.XPath {
    using System;
    using System.Xml;
    using System.Xml.XPath;
    using System.Diagnostics;
    using System.Globalization;
    using System.Collections.Generic;
    using StackInt = ClonableStack<int>;
    using StackNav = ClonableStack<System.Xml.XPath.XPathNavigator>;

    // This class implements Children axis on Ancestor & Descendant imputs. (as well as id(), preciding, following)
    // The problem here is that is descenant::*/child::* and ancestor::*/child::* can produce duplicates nodes
    // The algorithm havily uses the fact that in our implementation of both AncestorQuery and DecsndantQuery return nodes in document order. 
    // As result first child is always before or equal of next input. 
    // So we don't need to call DecideNextNode() when needInput == true && stack is empty.
    internal sealed class CacheChildrenQuery : ChildrenQuery {
        XPathNavigator nextInput = null;
        StackNav elementStk;
        StackInt positionStk;
        bool needInput;
#if DEBUG
        XPathNavigator lastNode = null;
#endif

        public CacheChildrenQuery(Query qyInput, string name, string prefix, XPathNodeType type) : base(qyInput, name, prefix, type) {
            this.elementStk  = new StackNav();
            this.positionStk = new StackInt();
            this.needInput   = true;
        }
        private CacheChildrenQuery(CacheChildrenQuery other) : base(other) {
            this.nextInput   = Clone(other.nextInput);
            this.elementStk  = other.elementStk.Clone();
            this.positionStk = other.positionStk.Clone();
            this.needInput   = other.needInput;
#if DEBUG
            this.lastNode    = Clone(other.lastNode);
#endif
        }

        public override void Reset() {
            nextInput = null;
            elementStk.Clear();
            positionStk.Clear();
            needInput = true;
            base.Reset();
#if DEBUG
            lastNode = null;
#endif
        }

        public override XPathNavigator Advance() {
            do {
                if (needInput) {
                    if (elementStk.Count == 0) {
                        currentNode = GetNextInput();
                        if (currentNode == null) {
                            return null;
                        }
                        if (!currentNode.MoveToFirstChild()) {
                            continue;
                        }
                        position = 0;
                    } else {
                        currentNode = elementStk .Pop();
                        position    = positionStk.Pop();
                        if (!DecideNextNode()) {
                            continue;
                        }
                    }
                    needInput = false;
                } else {
                    if (!currentNode.MoveToNext() || !DecideNextNode()) {
                        needInput = true;
                        continue;
                    }
                }
#if DEBUG
                if (lastNode != null) {
                    if (currentNode.GetType().ToString() == "Microsoft.VisualStudio.Modeling.StoreNavigator") {
                        XmlNodeOrder order = CompareNodes(lastNode, currentNode);
                        Debug.Assert(order == XmlNodeOrder.Before, "Algorith error. Nodes expected to be DocOrderDistinct");
                    }
                }
                lastNode = currentNode.Clone();
#endif
                if (matches(currentNode)) {
                    position++;
                    return currentNode;
                }
            } while (true);
        } // Advance

        private bool DecideNextNode() {
            nextInput = GetNextInput();
            if (nextInput != null) {
                if (CompareNodes(currentNode, nextInput) == XmlNodeOrder.After) {
                    elementStk .Push(currentNode);
                    positionStk.Push(position);
                    currentNode = nextInput;
                    nextInput = null;
                    if (!currentNode.MoveToFirstChild()) {
                        return false;
                    }
                    position = 0;
                }
            }
            return true;
        }

        private XPathNavigator GetNextInput() {
            XPathNavigator result;
            if (nextInput != null) {
                result = nextInput;
                nextInput = null;
            } else {
                result = qyInput.Advance();
                if (result != null) {
                    result = result.Clone();
                }
            }
            return result;
        }

        public override XPathNodeIterator Clone() { return new CacheChildrenQuery(this); }
    } // Children Query}
}