The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Runtime \ DifferenceIterator

  1. //------------------------------------------------------------------------------
  2. // <copyright file="SetIterators.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Xml;
  17. using System.Xml.XPath;
  18. using System.Xml.Schema;
  19. using System.Diagnostics;
  20. using System.Collections;
  21. using System.ComponentModel;
  22. namespace System.Xml.Xsl.Runtime
  23. {
  24.    
  25.     /// <summary>
  26.     /// Set iterators (Union, Intersection, Difference) that use containment to control two nested iterators return
  27.     /// one of the following values from MoveNext().
  28.     /// </summary>
  29.     [EditorBrowsable(EditorBrowsableState.Never)]
  30.     public enum SetIteratorResult
  31.     {
  32.         NoMoreNodes,
  33.         // Iteration is complete; there are no more nodes
  34.         InitRightIterator,
  35.         // Initialize right nested iterator
  36.         NeedLeftNode,
  37.         // The next node needs to be fetched from the left nested iterator
  38.         NeedRightNode,
  39.         // The next node needs to be fetched from the right nested iterator
  40.         HaveCurrentNode
  41.         // This iterator's Current property is set to the next node in the iteration
  42.     }
  43.    
  44.    
  45.     /// <summary>
  46.     /// This iterator manages two sets of nodes that are already in document order with no duplicates.
  47.     /// Using a merge sort, this operator returns the union of these sets in document order with no duplicates.
  48.     /// </summary>
  49.     [EditorBrowsable(EditorBrowsableState.Never)]
  50.     public struct UnionIterator
  51.     {
  52.         private XmlQueryRuntime runtime;
  53.         private XPathNavigator navCurr, navOther;
  54.         private IteratorState state;
  55.        
  56.         private enum IteratorState
  57.         {
  58.             InitLeft = 0,
  59.             NeedLeft,
  60.             NeedRight,
  61.             LeftIsCurrent,
  62.             RightIsCurrent
  63.         }
  64.        
  65.         /// <summary>
  66.         /// Create SetIterator.
  67.         /// </summary>
  68.         public void Create(XmlQueryRuntime runtime)
  69.         {
  70.             this.runtime = runtime;
  71.             this.state = IteratorState.InitLeft;
  72.         }
  73.        
  74.         /// <summary>
  75.         /// Position this iterator to the next node in the union.
  76.         /// </summary>
  77.         public SetIteratorResult MoveNext(XPathNavigator nestedNavigator)
  78.         {
  79.             switch (this.state) {
  80.                 case IteratorState.InitLeft:
  81.                     // Fetched node from left iterator, now get initial node from right iterator
  82.                     this.navOther = nestedNavigator;
  83.                     this.state = IteratorState.NeedRight;
  84.                     return SetIteratorResult.InitRightIterator;
  85.                 case IteratorState.NeedLeft:
  86.                    
  87.                     this.navCurr = nestedNavigator;
  88.                     this.state = IteratorState.LeftIsCurrent;
  89.                     break;
  90.                 case IteratorState.NeedRight:
  91.                    
  92.                     this.navCurr = nestedNavigator;
  93.                     this.state = IteratorState.RightIsCurrent;
  94.                     break;
  95.                 case IteratorState.LeftIsCurrent:
  96.                    
  97.                     // Just returned left node as current, so get new left
  98.                     this.state = IteratorState.NeedLeft;
  99.                     return SetIteratorResult.NeedLeftNode;
  100.                 case IteratorState.RightIsCurrent:
  101.                    
  102.                     // Just returned right node as current, so get new right
  103.                     this.state = IteratorState.NeedRight;
  104.                     return SetIteratorResult.NeedRightNode;
  105.             }
  106.            
  107.             // Merge left and right nodes
  108.             if (this.navCurr == null) {
  109.                 // If both navCurr and navOther are null, then iteration is complete
  110.                 if (this.navOther == null)
  111.                     return SetIteratorResult.NoMoreNodes;
  112.                
  113.                 Swap();
  114.             }
  115.             else if (this.navOther != null) {
  116.                 int order = this.runtime.ComparePosition(this.navOther, this.navCurr);
  117.                
  118.                 // If navCurr is positioned to same node as navOther,
  119.                 if (order == 0) {
  120.                     // Skip navCurr, since it is a duplicate
  121.                     if (this.state == IteratorState.LeftIsCurrent) {
  122.                         this.state = IteratorState.NeedLeft;
  123.                         return SetIteratorResult.NeedLeftNode;
  124.                     }
  125.                    
  126.                     this.state = IteratorState.NeedRight;
  127.                     return SetIteratorResult.NeedRightNode;
  128.                 }
  129.                
  130.                 // If navOther is before navCurr in document order, then swap navCurr with navOther
  131.                 if (order < 0)
  132.                     Swap();
  133.             }
  134.            
  135.             // Return navCurr
  136.             return SetIteratorResult.HaveCurrentNode;
  137.         }
  138.        
  139.         /// <summary>
  140.         /// Return the current result navigator. This is only defined after MoveNext() has returned -1.
  141.         /// </summary>
  142.         public XPathNavigator Current {
  143.             get { return this.navCurr; }
  144.         }
  145.        
  146.         /// <summary>
  147.         /// Swap navCurr with navOther and invert state to reflect the change.
  148.         /// </summary>
  149.         private void Swap()
  150.         {
  151.             XPathNavigator navTemp = this.navCurr;
  152.             this.navCurr = this.navOther;
  153.             this.navOther = navTemp;
  154.            
  155.             if (this.state == IteratorState.LeftIsCurrent)
  156.                 this.state = IteratorState.RightIsCurrent;
  157.             else
  158.                 this.state = IteratorState.LeftIsCurrent;
  159.         }
  160.     }
  161.    
  162.    
  163.     /// <summary>
  164.     /// This iterator manages two sets of nodes that are already in document order with no duplicates.
  165.     /// This iterator returns the intersection of these sets in document order with no duplicates.
  166.     /// </summary>
  167.     [EditorBrowsable(EditorBrowsableState.Never)]
  168.     public struct IntersectIterator
  169.     {
  170.         private XmlQueryRuntime runtime;
  171.         private XPathNavigator navLeft, navRight;
  172.         private IteratorState state;
  173.        
  174.         private enum IteratorState
  175.         {
  176.             InitLeft = 0,
  177.             NeedLeft,
  178.             NeedRight,
  179.             NeedLeftAndRight,
  180.             HaveCurrent
  181.         }
  182.        
  183.         /// <summary>
  184.         /// Create IntersectIterator.
  185.         /// </summary>
  186.         public void Create(XmlQueryRuntime runtime)
  187.         {
  188.             this.runtime = runtime;
  189.             this.state = IteratorState.InitLeft;
  190.         }
  191.        
  192.         /// <summary>
  193.         /// Position this iterator to the next node in the union.
  194.         /// </summary>
  195.         public SetIteratorResult MoveNext(XPathNavigator nestedNavigator)
  196.         {
  197.             int order;
  198.            
  199.             switch (this.state) {
  200.                 case IteratorState.InitLeft:
  201.                     // Fetched node from left iterator, now get initial node from right iterator
  202.                     this.navLeft = nestedNavigator;
  203.                     this.state = IteratorState.NeedRight;
  204.                     return SetIteratorResult.InitRightIterator;
  205.                 case IteratorState.NeedLeft:
  206.                    
  207.                     this.navLeft = nestedNavigator;
  208.                     break;
  209.                 case IteratorState.NeedRight:
  210.                    
  211.                     this.navRight = nestedNavigator;
  212.                     break;
  213.                 case IteratorState.NeedLeftAndRight:
  214.                    
  215.                     // After fetching left node, still need right node
  216.                     this.navLeft = nestedNavigator;
  217.                     this.state = IteratorState.NeedRight;
  218.                     return SetIteratorResult.NeedRightNode;
  219.                 case IteratorState.HaveCurrent:
  220.                    
  221.                     // Just returned left node as current, so fetch new left and right nodes
  222.                     Debug.Assert(nestedNavigator == null, "null is passed to MoveNext after IteratorState.HaveCurrent has been returned.");
  223.                     this.state = IteratorState.NeedLeftAndRight;
  224.                     return SetIteratorResult.NeedLeftNode;
  225.             }
  226.            
  227.             if (this.navLeft == null || this.navRight == null) {
  228.                 // No more nodes from either left or right iterator (or both), so iteration is complete
  229.                 return SetIteratorResult.NoMoreNodes;
  230.             }
  231.            
  232.             // Intersect left and right sets
  233.             order = this.runtime.ComparePosition(this.navLeft, this.navRight);
  234.            
  235.             if (order < 0) {
  236.                 // If navLeft is positioned to a node that is before navRight, skip left node
  237.                 this.state = IteratorState.NeedLeft;
  238.                 return SetIteratorResult.NeedLeftNode;
  239.             }
  240.             else if (order > 0) {
  241.                 // If navLeft is positioned to a node that is after navRight, so skip right node
  242.                 this.state = IteratorState.NeedRight;
  243.                 return SetIteratorResult.NeedRightNode;
  244.             }
  245.            
  246.             // Otherwise, navLeft is positioned to the same node as navRight, so found one item in the intersection
  247.             this.state = IteratorState.HaveCurrent;
  248.             return SetIteratorResult.HaveCurrentNode;
  249.         }
  250.        
  251.         /// <summary>
  252.         /// Return the current result navigator. This is only defined after MoveNext() has returned -1.
  253.         /// </summary>
  254.         public XPathNavigator Current {
  255.             get { return this.navLeft; }
  256.         }
  257.     }
  258.    
  259.    
  260.     /// <summary>
  261.     /// This iterator manages two sets of nodes that are already in document order with no duplicates.
  262.     /// This iterator returns the difference of these sets (Left - Right) in document order with no duplicates.
  263.     /// </summary>
  264.     [EditorBrowsable(EditorBrowsableState.Never)]
  265.     public struct DifferenceIterator
  266.     {
  267.         private XmlQueryRuntime runtime;
  268.         private XPathNavigator navLeft, navRight;
  269.         private IteratorState state;
  270.        
  271.         private enum IteratorState
  272.         {
  273.             InitLeft = 0,
  274.             NeedLeft,
  275.             NeedRight,
  276.             NeedLeftAndRight,
  277.             HaveCurrent
  278.         }
  279.        
  280.         /// <summary>
  281.         /// Create DifferenceIterator.
  282.         /// </summary>
  283.         public void Create(XmlQueryRuntime runtime)
  284.         {
  285.             this.runtime = runtime;
  286.             this.state = IteratorState.InitLeft;
  287.         }
  288.        
  289.         /// <summary>
  290.         /// Position this iterator to the next node in the union.
  291.         /// </summary>
  292.         public SetIteratorResult MoveNext(XPathNavigator nestedNavigator)
  293.         {
  294.             switch (this.state) {
  295.                 case IteratorState.InitLeft:
  296.                     // Fetched node from left iterator, now get initial node from right iterator
  297.                     this.navLeft = nestedNavigator;
  298.                     this.state = IteratorState.NeedRight;
  299.                     return SetIteratorResult.InitRightIterator;
  300.                 case IteratorState.NeedLeft:
  301.                    
  302.                     this.navLeft = nestedNavigator;
  303.                     break;
  304.                 case IteratorState.NeedRight:
  305.                    
  306.                     this.navRight = nestedNavigator;
  307.                     break;
  308.                 case IteratorState.NeedLeftAndRight:
  309.                    
  310.                     // After fetching left node, still need right node
  311.                     this.navLeft = nestedNavigator;
  312.                     this.state = IteratorState.NeedRight;
  313.                     return SetIteratorResult.NeedRightNode;
  314.                 case IteratorState.HaveCurrent:
  315.                    
  316.                     // Just returned left node as current, so fetch new left node
  317.                     Debug.Assert(nestedNavigator == null, "null is passed to MoveNext after IteratorState.HaveCurrent has been returned.");
  318.                     this.state = IteratorState.NeedLeft;
  319.                     return SetIteratorResult.NeedLeftNode;
  320.             }
  321.            
  322.             if (this.navLeft == null) {
  323.                 // If navLeft is null, then difference operation is complete
  324.                 return SetIteratorResult.NoMoreNodes;
  325.             }
  326.             else if (this.navRight != null) {
  327.                 int order = this.runtime.ComparePosition(this.navLeft, this.navRight);
  328.                
  329.                 // If navLeft is positioned to same node as navRight,
  330.                 if (order == 0) {
  331.                     // Skip navLeft and navRight
  332.                     this.state = IteratorState.NeedLeftAndRight;
  333.                     return SetIteratorResult.NeedLeftNode;
  334.                 }
  335.                
  336.                 // If navLeft is after navRight in document order, then skip navRight
  337.                 if (order > 0) {
  338.                     this.state = IteratorState.NeedRight;
  339.                     return SetIteratorResult.NeedRightNode;
  340.                 }
  341.             }
  342.            
  343.             // Return navLeft
  344.             this.state = IteratorState.HaveCurrent;
  345.             return SetIteratorResult.HaveCurrentNode;
  346.         }
  347.        
  348.         /// <summary>
  349.         /// Return the current result navigator. This is only defined after MoveNext() has returned -1.
  350.         /// </summary>
  351.         public XPathNavigator Current {
  352.             get { return this.navLeft; }
  353.         }
  354.     }
  355. }

Developer Fusion