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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
|
//------------------------------------------------------------------------------
// <copyright file="SetIterators.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
using System;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Schema;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
namespace System.Xml.Xsl.Runtime {
/// <summary>
/// Set iterators (Union, Intersection, Difference) that use containment to control two nested iterators return
/// one of the following values from MoveNext().
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public enum SetIteratorResult {
NoMoreNodes, // Iteration is complete; there are no more nodes
InitRightIterator, // Initialize right nested iterator
NeedLeftNode, // The next node needs to be fetched from the left nested iterator
NeedRightNode, // The next node needs to be fetched from the right nested iterator
HaveCurrentNode, // This iterator's Current property is set to the next node in the iteration
};
/// <summary>
/// This iterator manages two sets of nodes that are already in document order with no duplicates.
/// Using a merge sort, this operator returns the union of these sets in document order with no duplicates.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public struct UnionIterator {
private XmlQueryRuntime runtime;
private XPathNavigator navCurr, navOther;
private IteratorState state;
private enum IteratorState {
InitLeft = 0,
NeedLeft,
NeedRight,
LeftIsCurrent,
RightIsCurrent,
};
/// <summary>
/// Create SetIterator.
/// </summary>
public void Create(XmlQueryRuntime runtime) {
this.runtime = runtime;
this.state = IteratorState.InitLeft;
}
/// <summary>
/// Position this iterator to the next node in the union.
/// </summary>
public SetIteratorResult MoveNext(XPathNavigator nestedNavigator) {
switch (this.state) {
case IteratorState.InitLeft:
// Fetched node from left iterator, now get initial node from right iterator
this.navOther = nestedNavigator;
this.state = IteratorState.NeedRight;
return SetIteratorResult.InitRightIterator;
case IteratorState.NeedLeft:
this.navCurr = nestedNavigator;
this.state = IteratorState.LeftIsCurrent;
break;
case IteratorState.NeedRight:
this.navCurr = nestedNavigator;
this.state = IteratorState.RightIsCurrent;
break;
case IteratorState.LeftIsCurrent:
// Just returned left node as current, so get new left
this.state = IteratorState.NeedLeft;
return SetIteratorResult.NeedLeftNode;
case IteratorState.RightIsCurrent:
// Just returned right node as current, so get new right
this.state = IteratorState.NeedRight;
return SetIteratorResult.NeedRightNode;
}
// Merge left and right nodes
if (this.navCurr == null) {
// If both navCurr and navOther are null, then iteration is complete
if (this.navOther == null)
return SetIteratorResult.NoMoreNodes;
Swap();
}
else if (this.navOther != null) {
int order = this.runtime.ComparePosition(this.navOther, this.navCurr);
// If navCurr is positioned to same node as navOther,
if (order == 0) {
// Skip navCurr, since it is a duplicate
if (this.state == IteratorState.LeftIsCurrent) {
this.state = IteratorState.NeedLeft;
return SetIteratorResult.NeedLeftNode;
}
this.state = IteratorState.NeedRight;
return SetIteratorResult.NeedRightNode;
}
// If navOther is before navCurr in document order, then swap navCurr with navOther
if (order < 0)
Swap();
}
// Return navCurr
return SetIteratorResult.HaveCurrentNode;
}
/// <summary>
/// Return the current result navigator. This is only defined after MoveNext() has returned -1.
/// </summary>
public XPathNavigator Current {
get { return this.navCurr; }
}
/// <summary>
/// Swap navCurr with navOther and invert state to reflect the change.
/// </summary>
private void Swap() {
XPathNavigator navTemp = this.navCurr;
this.navCurr = this.navOther;
this.navOther = navTemp;
if (this.state == IteratorState.LeftIsCurrent)
this.state = IteratorState.RightIsCurrent;
else
this.state = IteratorState.LeftIsCurrent;
}
}
/// <summary>
/// This iterator manages two sets of nodes that are already in document order with no duplicates.
/// This iterator returns the intersection of these sets in document order with no duplicates.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public struct IntersectIterator {
private XmlQueryRuntime runtime;
private XPathNavigator navLeft, navRight;
private IteratorState state;
private enum IteratorState {
InitLeft = 0,
NeedLeft,
NeedRight,
NeedLeftAndRight,
HaveCurrent,
};
/// <summary>
/// Create IntersectIterator.
/// </summary>
public void Create(XmlQueryRuntime runtime) {
this.runtime = runtime;
this.state = IteratorState.InitLeft;
}
/// <summary>
/// Position this iterator to the next node in the union.
/// </summary>
public SetIteratorResult MoveNext(XPathNavigator nestedNavigator) {
int order;
switch (this.state) {
case IteratorState.InitLeft:
// Fetched node from left iterator, now get initial node from right iterator
this.navLeft = nestedNavigator;
this.state = IteratorState.NeedRight;
return SetIteratorResult.InitRightIterator;
case IteratorState.NeedLeft:
this.navLeft = nestedNavigator;
break;
case IteratorState.NeedRight:
this.navRight = nestedNavigator;
break;
case IteratorState.NeedLeftAndRight:
// After fetching left node, still need right node
this.navLeft = nestedNavigator;
this.state = IteratorState.NeedRight;
return SetIteratorResult.NeedRightNode;
case IteratorState.HaveCurrent:
// Just returned left node as current, so fetch new left and right nodes
Debug.Assert(nestedNavigator == null, "null is passed to MoveNext after IteratorState.HaveCurrent has been returned.");
this.state = IteratorState.NeedLeftAndRight;
return SetIteratorResult.NeedLeftNode;
}
if (this.navLeft == null || this.navRight == null) {
// No more nodes from either left or right iterator (or both), so iteration is complete
return SetIteratorResult.NoMoreNodes;
}
// Intersect left and right sets
order = this.runtime.ComparePosition(this.navLeft, this.navRight);
if (order < 0) {
// If navLeft is positioned to a node that is before navRight, skip left node
this.state = IteratorState.NeedLeft;
return SetIteratorResult.NeedLeftNode;
}
else if (order > 0) {
// If navLeft is positioned to a node that is after navRight, so skip right node
this.state = IteratorState.NeedRight;
return SetIteratorResult.NeedRightNode;
}
// Otherwise, navLeft is positioned to the same node as navRight, so found one item in the intersection
this.state = IteratorState.HaveCurrent;
return SetIteratorResult.HaveCurrentNode;
}
/// <summary>
/// Return the current result navigator. This is only defined after MoveNext() has returned -1.
/// </summary>
public XPathNavigator Current {
get { return this.navLeft; }
}
}
/// <summary>
/// This iterator manages two sets of nodes that are already in document order with no duplicates.
/// This iterator returns the difference of these sets (Left - Right) in document order with no duplicates.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public struct DifferenceIterator {
private XmlQueryRuntime runtime;
private XPathNavigator navLeft, navRight;
private IteratorState state;
private enum IteratorState {
InitLeft = 0,
NeedLeft,
NeedRight,
NeedLeftAndRight,
HaveCurrent,
};
/// <summary>
/// Create DifferenceIterator.
/// </summary>
public void Create(XmlQueryRuntime runtime) {
this.runtime = runtime;
this.state = IteratorState.InitLeft;
}
/// <summary>
/// Position this iterator to the next node in the union.
/// </summary>
public SetIteratorResult MoveNext(XPathNavigator nestedNavigator) {
switch (this.state) {
case IteratorState.InitLeft:
// Fetched node from left iterator, now get initial node from right iterator
this.navLeft = nestedNavigator;
this.state = IteratorState.NeedRight;
return SetIteratorResult.InitRightIterator;
case IteratorState.NeedLeft:
this.navLeft = nestedNavigator;
break;
case IteratorState.NeedRight:
this.navRight = nestedNavigator;
break;
case IteratorState.NeedLeftAndRight:
// After fetching left node, still need right node
this.navLeft = nestedNavigator;
this.state = IteratorState.NeedRight;
return SetIteratorResult.NeedRightNode;
case IteratorState.HaveCurrent:
// Just returned left node as current, so fetch new left node
Debug.Assert(nestedNavigator == null, "null is passed to MoveNext after IteratorState.HaveCurrent has been returned.");
this.state = IteratorState.NeedLeft;
return SetIteratorResult.NeedLeftNode;
}
if (this.navLeft == null) {
// If navLeft is null, then difference operation is complete
return SetIteratorResult.NoMoreNodes;
}
else if (this.navRight != null) {
int order = this.runtime.ComparePosition(this.navLeft, this.navRight);
// If navLeft is positioned to same node as navRight,
if (order == 0) {
// Skip navLeft and navRight
this.state = IteratorState.NeedLeftAndRight;
return SetIteratorResult.NeedLeftNode;
}
// If navLeft is after navRight in document order, then skip navRight
if (order > 0) {
this.state = IteratorState.NeedRight;
return SetIteratorResult.NeedRightNode;
}
}
// Return navLeft
this.state = IteratorState.HaveCurrent;
return SetIteratorResult.HaveCurrentNode;
}
/// <summary>
/// Return the current result navigator. This is only defined after MoveNext() has returned -1.
/// </summary>
public XPathNavigator Current {
get { return this.navLeft; }
}
}
}
|