File: DodSequenceMerge.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 (136 lines) | stat: -rw-r--r-- 5,357 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
134
135
136
//------------------------------------------------------------------------------
// <copyright file="DodSequenceMerge.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Xml.XPath;
using System.Diagnostics;
using System.Globalization;
using System.ComponentModel;

namespace System.Xml.Xsl.Runtime {

    /// <summary>
    /// Merges several doc-order-distinct sequences into a single doc-order-distinct sequence.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public struct DodSequenceMerge {
        private IList<XPathNavigator> firstSequence;
        private List<IEnumerator<XPathNavigator>> sequencesToMerge;
        private int nodeCount;
        private XmlQueryRuntime runtime;

        /// <summary>
        /// Initialize this instance of DodSequenceMerge.
        /// </summary>
        public void Create(XmlQueryRuntime runtime) {
            this.firstSequence = null;
            this.sequencesToMerge = null;
            this.nodeCount = 0;
            this.runtime = runtime;
        }

        /// <summary>
        /// Add a new sequence to the list of sequences to merge.
        /// </summary>
        public void AddSequence(IList<XPathNavigator> sequence) {
            // Ignore empty sequences
            if (sequence.Count == 0)
                return;

            if (this.firstSequence == null) {
                this.firstSequence = sequence;
            }
            else {
                if (this.sequencesToMerge == null) {
                    this.sequencesToMerge = new List<IEnumerator<XPathNavigator>>();
                    MoveAndInsertSequence(this.firstSequence.GetEnumerator());
                    this.nodeCount = this.firstSequence.Count;
                }

                MoveAndInsertSequence(sequence.GetEnumerator());
                this.nodeCount += sequence.Count;
            }
        }

        /// <summary>
        /// Return the fully merged sequence.
        /// </summary>
        public IList<XPathNavigator> MergeSequences() {
            XmlQueryNodeSequence newSequence;

            // Zero sequences to merge
            if (this.firstSequence == null)
                return XmlQueryNodeSequence.Empty;

            // One sequence to merge
            if (this.sequencesToMerge == null || this.sequencesToMerge.Count <= 1)
                return this.firstSequence;

            // Two or more sequences to merge
            newSequence = new XmlQueryNodeSequence(this.nodeCount);

            while (this.sequencesToMerge.Count != 1) {
                // Save last item in list in temp variable, and remove it from list
                IEnumerator<XPathNavigator> sequence = this.sequencesToMerge[this.sequencesToMerge.Count - 1];
                this.sequencesToMerge.RemoveAt(this.sequencesToMerge.Count - 1);

                // Add current node to merged sequence
                newSequence.Add(sequence.Current);

                // Now move to the next node, and re-insert it into the list in reverse document order
                MoveAndInsertSequence(sequence);
            }

            // Add nodes in remaining sequence to end of list
            Debug.Assert(this.sequencesToMerge.Count == 1, "While loop should terminate when count == 1");
            do {
                newSequence.Add(this.sequencesToMerge[0].Current);
            }
            while (this.sequencesToMerge[0].MoveNext());

            return newSequence;
        }

        /// <summary>
        /// Move to the next item in the sequence.  If there is no next item, then do not
        /// insert the sequence.  Otherwise, call InsertSequence.
        /// </summary>
        private void MoveAndInsertSequence(IEnumerator<XPathNavigator> sequence) {
            if (sequence.MoveNext())
                InsertSequence(sequence);
        }

        /// <summary>
        /// Insert the specified sequence into the list of sequences to be merged.
        /// Insert it in reverse document order with respect to the current nodes in other sequences.
        /// </summary>
        private void InsertSequence(IEnumerator<XPathNavigator> sequence) {
            for (int i = this.sequencesToMerge.Count - 1; i >= 0; i--) {
                int cmp = this.runtime.ComparePosition(sequence.Current, this.sequencesToMerge[i].Current);

                if (cmp == -1) {
                    // Insert after current item
                    this.sequencesToMerge.Insert(i + 1, sequence);
                    return;
                }
                else if (cmp == 0) {
                    // Found duplicate, so skip the duplicate
                    if (!sequence.MoveNext()) {
                        // No more nodes, so don't insert anything
                        return;
                    }

                    // Next node must be after current node in document order, so don't need to reset loop
                }
            }

            // Insert at beginning of list
            this.sequencesToMerge.Insert(0, sequence);
        }
    }
}