Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / XPath / XPathNodeIterator.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XPathNodeIterator.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 using System.Collections;
9 using System.Diagnostics;
10 using System.Text;
11
12 namespace System.Xml.XPath {
13
14     [DebuggerDisplay("Position={CurrentPosition}, Current={debuggerDisplayProxy}")]
15     public abstract class XPathNodeIterator : ICloneable, IEnumerable {
16         internal int count = -1;
17
18         object ICloneable.Clone() { return this.Clone(); }
19
20         public abstract XPathNodeIterator Clone();
21         public abstract bool MoveNext();
22         public abstract XPathNavigator Current { get; }
23         public abstract int CurrentPosition { get; }
24         public virtual int Count {
25             get {
26                 if (count == -1) {
27                     XPathNodeIterator clone = this.Clone();
28                     while(clone.MoveNext()) ;
29                     count = clone.CurrentPosition;
30                 }
31                 return count;
32             }
33         }
34         public virtual IEnumerator GetEnumerator() {
35             return new Enumerator(this);
36         }
37
38         private object debuggerDisplayProxy { get { return Current == null ? null : (object)new XPathNavigator.DebuggerDisplayProxy(Current); } }
39
40         /// <summary>
41         /// Implementation of a resetable enumerator that is linked to the XPathNodeIterator used to create it.
42         /// </summary>
43         private class Enumerator : IEnumerator {
44             private XPathNodeIterator original;     // Keep original XPathNodeIterator in case Reset() is called
45             private XPathNodeIterator current;
46             private bool iterationStarted;
47
48             public Enumerator(XPathNodeIterator original) {
49                 this.original = original.Clone();
50             }
51
52             public virtual object Current {
53                 get {
54                     // 1. Do not reuse the XPathNavigator, as we do in XPathNodeIterator
55                     // 2. Throw exception if current position is before first node or after the last node
56                     if (this.iterationStarted) {
57                         // Current is null if iterator is positioned after the last node
58                         if (this.current == null)
59                             throw new InvalidOperationException(Res.GetString(Res.Sch_EnumFinished, string.Empty));
60
61                         return this.current.Current.Clone();
62                     }
63
64                     // User must call MoveNext before accessing Current property
65                     throw new InvalidOperationException(Res.GetString(Res.Sch_EnumNotStarted, string.Empty));
66                 }
67             }
68
69             public virtual bool MoveNext() {
70                 // Delegate to XPathNodeIterator
71                 if (!this.iterationStarted) {
72                     // Reset iteration to original position
73                     this.current = this.original.Clone();
74                     this.iterationStarted = true;
75                 }
76
77                 if (this.current == null || !this.current.MoveNext()) {
78                     // Iteration complete
79                     this.current = null;
80                     return false;
81                 }
82                 return true;
83             }
84
85             public virtual void Reset() {
86                 this.iterationStarted = false;
87             }
88         }
89
90         private struct DebuggerDisplayProxy {
91             private XPathNodeIterator nodeIterator;
92
93             public DebuggerDisplayProxy(XPathNodeIterator nodeIterator) {
94                 this.nodeIterator = nodeIterator;
95             }
96
97             public override string ToString() {
98                 // Position={CurrentPosition}, Current={Current == null ? null : (object) new XPathNavigator.DebuggerDisplayProxy(Current)}
99                 StringBuilder sb = new StringBuilder();
100                 sb.Append("Position=");
101                 sb.Append(nodeIterator.CurrentPosition);
102                 sb.Append(", Current=");
103                 if (nodeIterator.Current == null) {
104                     sb.Append("null");
105                 } else {
106                     sb.Append('{');
107                     sb.Append(new XPathNavigator.DebuggerDisplayProxy(nodeIterator.Current).ToString());
108                     sb.Append('}');
109                 }
110                 return sb.ToString();
111             }
112         }
113     }
114 }