| File: System\Xml\Xsl\Runtime\SetIterators.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Xml; using System.Xml.Schema; using System.Xml.XPath; 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) { _runtime = runtime; _state = IteratorState.InitLeft; } /// <summary> /// Position this iterator to the next node in the union. /// </summary> public SetIteratorResult MoveNext(XPathNavigator nestedNavigator) { switch (_state) { case IteratorState.InitLeft: // Fetched node from left iterator, now get initial node from right iterator _navOther = nestedNavigator; _state = IteratorState.NeedRight; return SetIteratorResult.InitRightIterator; case IteratorState.NeedLeft: _navCurr = nestedNavigator; _state = IteratorState.LeftIsCurrent; break; case IteratorState.NeedRight: _navCurr = nestedNavigator; _state = IteratorState.RightIsCurrent; break; case IteratorState.LeftIsCurrent: // Just returned left node as current, so get new left _state = IteratorState.NeedLeft; return SetIteratorResult.NeedLeftNode; case IteratorState.RightIsCurrent: // Just returned right node as current, so get new right _state = IteratorState.NeedRight; return SetIteratorResult.NeedRightNode; } // Merge left and right nodes if (_navCurr == null) { // If both navCurr and navOther are null, then iteration is complete if (_navOther == null) return SetIteratorResult.NoMoreNodes; Swap(); } else if (_navOther != null) { int order = _runtime.ComparePosition(_navOther, _navCurr); // If navCurr is positioned to same node as navOther, if (order == 0) { // Skip navCurr, since it is a duplicate if (_state == IteratorState.LeftIsCurrent) { _state = IteratorState.NeedLeft; return SetIteratorResult.NeedLeftNode; } _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 _navCurr; } } /// <summary> /// Swap navCurr with navOther and invert state to reflect the change. /// </summary> private void Swap() { XPathNavigator navTemp = _navCurr; _navCurr = _navOther; _navOther = navTemp; if (_state == IteratorState.LeftIsCurrent) _state = IteratorState.RightIsCurrent; else _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) { _runtime = runtime; _state = IteratorState.InitLeft; } /// <summary> /// Position this iterator to the next node in the union. /// </summary> public SetIteratorResult MoveNext(XPathNavigator nestedNavigator) { int order; switch (_state) { case IteratorState.InitLeft: // Fetched node from left iterator, now get initial node from right iterator _navLeft = nestedNavigator; _state = IteratorState.NeedRight; return SetIteratorResult.InitRightIterator; case IteratorState.NeedLeft: _navLeft = nestedNavigator; break; case IteratorState.NeedRight: _navRight = nestedNavigator; break; case IteratorState.NeedLeftAndRight: // After fetching left node, still need right node _navLeft = nestedNavigator; _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."); _state = IteratorState.NeedLeftAndRight; return SetIteratorResult.NeedLeftNode; } if (_navLeft == null || _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 = _runtime.ComparePosition(_navLeft, _navRight); if (order < 0) { // If navLeft is positioned to a node that is before navRight, skip left node _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 _state = IteratorState.NeedRight; return SetIteratorResult.NeedRightNode; } // Otherwise, navLeft is positioned to the same node as navRight, so found one item in the intersection _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 _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) { _runtime = runtime; _state = IteratorState.InitLeft; } /// <summary> /// Position this iterator to the next node in the union. /// </summary> public SetIteratorResult MoveNext(XPathNavigator nestedNavigator) { switch (_state) { case IteratorState.InitLeft: // Fetched node from left iterator, now get initial node from right iterator _navLeft = nestedNavigator; _state = IteratorState.NeedRight; return SetIteratorResult.InitRightIterator; case IteratorState.NeedLeft: _navLeft = nestedNavigator; break; case IteratorState.NeedRight: _navRight = nestedNavigator; break; case IteratorState.NeedLeftAndRight: // After fetching left node, still need right node _navLeft = nestedNavigator; _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."); _state = IteratorState.NeedLeft; return SetIteratorResult.NeedLeftNode; } if (_navLeft == null) { // If navLeft is null, then difference operation is complete return SetIteratorResult.NoMoreNodes; } else if (_navRight != null) { int order = _runtime.ComparePosition(_navLeft, _navRight); // If navLeft is positioned to same node as navRight, if (order == 0) { // Skip navLeft and navRight _state = IteratorState.NeedLeftAndRight; return SetIteratorResult.NeedLeftNode; } // If navLeft is after navRight in document order, then skip navRight if (order > 0) { _state = IteratorState.NeedRight; return SetIteratorResult.NeedRightNode; } } // Return navLeft _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 _navLeft; } } } }