1 //------------------------------------------------------------------------------
2 // <copyright file="SetIterators.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
9 using System.Xml.XPath;
10 using System.Xml.Schema;
11 using System.Diagnostics;
12 using System.Collections;
13 using System.ComponentModel;
15 namespace System.Xml.Xsl.Runtime {
18 /// Set iterators (Union, Intersection, Difference) that use containment to control two nested iterators return
19 /// one of the following values from MoveNext().
21 [EditorBrowsable(EditorBrowsableState.Never)]
22 public enum SetIteratorResult {
23 NoMoreNodes, // Iteration is complete; there are no more nodes
24 InitRightIterator, // Initialize right nested iterator
25 NeedLeftNode, // The next node needs to be fetched from the left nested iterator
26 NeedRightNode, // The next node needs to be fetched from the right nested iterator
27 HaveCurrentNode, // This iterator's Current property is set to the next node in the iteration
32 /// This iterator manages two sets of nodes that are already in document order with no duplicates.
33 /// Using a merge sort, this operator returns the union of these sets in document order with no duplicates.
35 [EditorBrowsable(EditorBrowsableState.Never)]
36 public struct UnionIterator {
37 private XmlQueryRuntime runtime;
38 private XPathNavigator navCurr, navOther;
39 private IteratorState state;
41 private enum IteratorState {
50 /// Create SetIterator.
52 public void Create(XmlQueryRuntime runtime) {
53 this.runtime = runtime;
54 this.state = IteratorState.InitLeft;
58 /// Position this iterator to the next node in the union.
60 public SetIteratorResult MoveNext(XPathNavigator nestedNavigator) {
62 case IteratorState.InitLeft:
63 // Fetched node from left iterator, now get initial node from right iterator
64 this.navOther = nestedNavigator;
65 this.state = IteratorState.NeedRight;
66 return SetIteratorResult.InitRightIterator;
68 case IteratorState.NeedLeft:
69 this.navCurr = nestedNavigator;
70 this.state = IteratorState.LeftIsCurrent;
73 case IteratorState.NeedRight:
74 this.navCurr = nestedNavigator;
75 this.state = IteratorState.RightIsCurrent;
78 case IteratorState.LeftIsCurrent:
79 // Just returned left node as current, so get new left
80 this.state = IteratorState.NeedLeft;
81 return SetIteratorResult.NeedLeftNode;
83 case IteratorState.RightIsCurrent:
84 // Just returned right node as current, so get new right
85 this.state = IteratorState.NeedRight;
86 return SetIteratorResult.NeedRightNode;
89 // Merge left and right nodes
90 if (this.navCurr == null) {
91 // If both navCurr and navOther are null, then iteration is complete
92 if (this.navOther == null)
93 return SetIteratorResult.NoMoreNodes;
97 else if (this.navOther != null) {
98 int order = this.runtime.ComparePosition(this.navOther, this.navCurr);
100 // If navCurr is positioned to same node as navOther,
102 // Skip navCurr, since it is a duplicate
103 if (this.state == IteratorState.LeftIsCurrent) {
104 this.state = IteratorState.NeedLeft;
105 return SetIteratorResult.NeedLeftNode;
108 this.state = IteratorState.NeedRight;
109 return SetIteratorResult.NeedRightNode;
112 // If navOther is before navCurr in document order, then swap navCurr with navOther
118 return SetIteratorResult.HaveCurrentNode;
122 /// Return the current result navigator. This is only defined after MoveNext() has returned -1.
124 public XPathNavigator Current {
125 get { return this.navCurr; }
129 /// Swap navCurr with navOther and invert state to reflect the change.
131 private void Swap() {
132 XPathNavigator navTemp = this.navCurr;
133 this.navCurr = this.navOther;
134 this.navOther = navTemp;
136 if (this.state == IteratorState.LeftIsCurrent)
137 this.state = IteratorState.RightIsCurrent;
139 this.state = IteratorState.LeftIsCurrent;
145 /// This iterator manages two sets of nodes that are already in document order with no duplicates.
146 /// This iterator returns the intersection of these sets in document order with no duplicates.
148 [EditorBrowsable(EditorBrowsableState.Never)]
149 public struct IntersectIterator {
150 private XmlQueryRuntime runtime;
151 private XPathNavigator navLeft, navRight;
152 private IteratorState state;
154 private enum IteratorState {
163 /// Create IntersectIterator.
165 public void Create(XmlQueryRuntime runtime) {
166 this.runtime = runtime;
167 this.state = IteratorState.InitLeft;
171 /// Position this iterator to the next node in the union.
173 public SetIteratorResult MoveNext(XPathNavigator nestedNavigator) {
176 switch (this.state) {
177 case IteratorState.InitLeft:
178 // Fetched node from left iterator, now get initial node from right iterator
179 this.navLeft = nestedNavigator;
180 this.state = IteratorState.NeedRight;
181 return SetIteratorResult.InitRightIterator;
183 case IteratorState.NeedLeft:
184 this.navLeft = nestedNavigator;
187 case IteratorState.NeedRight:
188 this.navRight = nestedNavigator;
191 case IteratorState.NeedLeftAndRight:
192 // After fetching left node, still need right node
193 this.navLeft = nestedNavigator;
194 this.state = IteratorState.NeedRight;
195 return SetIteratorResult.NeedRightNode;
197 case IteratorState.HaveCurrent:
198 // Just returned left node as current, so fetch new left and right nodes
199 Debug.Assert(nestedNavigator == null, "null is passed to MoveNext after IteratorState.HaveCurrent has been returned.");
200 this.state = IteratorState.NeedLeftAndRight;
201 return SetIteratorResult.NeedLeftNode;
204 if (this.navLeft == null || this.navRight == null) {
205 // No more nodes from either left or right iterator (or both), so iteration is complete
206 return SetIteratorResult.NoMoreNodes;
209 // Intersect left and right sets
210 order = this.runtime.ComparePosition(this.navLeft, this.navRight);
213 // If navLeft is positioned to a node that is before navRight, skip left node
214 this.state = IteratorState.NeedLeft;
215 return SetIteratorResult.NeedLeftNode;
217 else if (order > 0) {
218 // If navLeft is positioned to a node that is after navRight, so skip right node
219 this.state = IteratorState.NeedRight;
220 return SetIteratorResult.NeedRightNode;
223 // Otherwise, navLeft is positioned to the same node as navRight, so found one item in the intersection
224 this.state = IteratorState.HaveCurrent;
225 return SetIteratorResult.HaveCurrentNode;
229 /// Return the current result navigator. This is only defined after MoveNext() has returned -1.
231 public XPathNavigator Current {
232 get { return this.navLeft; }
238 /// This iterator manages two sets of nodes that are already in document order with no duplicates.
239 /// This iterator returns the difference of these sets (Left - Right) in document order with no duplicates.
241 [EditorBrowsable(EditorBrowsableState.Never)]
242 public struct DifferenceIterator {
243 private XmlQueryRuntime runtime;
244 private XPathNavigator navLeft, navRight;
245 private IteratorState state;
247 private enum IteratorState {
256 /// Create DifferenceIterator.
258 public void Create(XmlQueryRuntime runtime) {
259 this.runtime = runtime;
260 this.state = IteratorState.InitLeft;
264 /// Position this iterator to the next node in the union.
266 public SetIteratorResult MoveNext(XPathNavigator nestedNavigator) {
267 switch (this.state) {
268 case IteratorState.InitLeft:
269 // Fetched node from left iterator, now get initial node from right iterator
270 this.navLeft = nestedNavigator;
271 this.state = IteratorState.NeedRight;
272 return SetIteratorResult.InitRightIterator;
274 case IteratorState.NeedLeft:
275 this.navLeft = nestedNavigator;
278 case IteratorState.NeedRight:
279 this.navRight = nestedNavigator;
282 case IteratorState.NeedLeftAndRight:
283 // After fetching left node, still need right node
284 this.navLeft = nestedNavigator;
285 this.state = IteratorState.NeedRight;
286 return SetIteratorResult.NeedRightNode;
288 case IteratorState.HaveCurrent:
289 // Just returned left node as current, so fetch new left node
290 Debug.Assert(nestedNavigator == null, "null is passed to MoveNext after IteratorState.HaveCurrent has been returned.");
291 this.state = IteratorState.NeedLeft;
292 return SetIteratorResult.NeedLeftNode;
295 if (this.navLeft == null) {
296 // If navLeft is null, then difference operation is complete
297 return SetIteratorResult.NoMoreNodes;
299 else if (this.navRight != null) {
300 int order = this.runtime.ComparePosition(this.navLeft, this.navRight);
302 // If navLeft is positioned to same node as navRight,
304 // Skip navLeft and navRight
305 this.state = IteratorState.NeedLeftAndRight;
306 return SetIteratorResult.NeedLeftNode;
309 // If navLeft is after navRight in document order, then skip navRight
311 this.state = IteratorState.NeedRight;
312 return SetIteratorResult.NeedRightNode;
317 this.state = IteratorState.HaveCurrent;
318 return SetIteratorResult.HaveCurrentNode;
322 /// Return the current result navigator. This is only defined after MoveNext() has returned -1.
324 public XPathNavigator Current {
325 get { return this.navLeft; }