17f7d6b5619c7086ce62310eae1ee8c92b02bf6f
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Common / Utils / ModifiableIteratorCollection.cs
1 //---------------------------------------------------------------------
2 // <copyright file="ModifiableIteratorCollection.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10
11 using System;
12 using System.Collections;
13 using System.Collections.Generic;
14 using System.Text;
15 using System.Diagnostics;
16
17 namespace System.Data.Common.Utils {
18
19     // A collection abstraction that allows elements to be removed during
20     // iteration without resulting in missed or duplicate elements in the
21     // iteration process. Also, allows the iterator to be restarted
22     // midway. It is recommended that this abstractions be used for small
23     // sets since Contains is an O(n) algorithm
24     // Restriction: There can be at most ONE iterator on the object at any
25     // given time.
26
27     internal class ModifiableIteratorCollection<TElement> : InternalBase {
28
29         #region Constructors
30         // effects: Generates a set based on values
31         internal ModifiableIteratorCollection(IEnumerable<TElement> elements) {
32             m_elements = new List<TElement>(elements);
33             m_currentIteratorIndex = -1;
34         }
35         #endregion
36
37         #region Fields
38         // A constant to denote the fact that iterator is not running currently
39         // The collection is simply a list
40         private List<TElement> m_elements;
41         // The index where the iterator is currently at
42         private int m_currentIteratorIndex;
43         #endregion
44
45         #region Properties
46         // effects: Returns true if the collection has no elements
47         internal bool IsEmpty {
48             get {
49                 return m_elements.Count == 0;
50             }
51         }
52         #endregion
53
54         #region Available Methods
55         // requires: IsEmpty is false
56         // effects: Removes some element from this and returns it
57         internal TElement RemoveOneElement() {
58             Debug.Assert(false == IsEmpty, "Empty set - cannot remove any element");
59             // Remove the last element
60             return Remove(m_elements.Count - 1);
61         }
62         
63         // requires; An iterator is currently under progress
64         // effects: Resets the current iterator so that it starts from the beginning
65         internal void ResetIterator() {
66             m_currentIteratorIndex = -1;
67             // This will be incremented after the yield statement if the
68             // iterator is on
69         }
70         
71         
72         // requires; An iterator is currently under progress
73         // effects: Removes the current element being yielded while Ensuring
74         // that no element is missed or repeated even after removal
75         internal void RemoveCurrentOfIterator() {
76             Debug.Assert(m_currentIteratorIndex >= 0, "Iterator not started yet");
77             Remove(m_currentIteratorIndex);
78             // We removed an element at m_currentIteratorIndex by placing the
79             // last element at m_currentIteratorIndex. We need to make
80             // sure that this element is not missed. We reduce
81             // m_currentIteratorIndex by 1 so that when it is incremented
82             // in Elements. So this could even set it to -1
83             m_currentIteratorIndex--;
84         }
85         
86         // requires; An iterator is not currently under progress
87         // effects: Yields the elements in this
88         internal IEnumerable<TElement> Elements() {
89             // We cannnot check that an iterator is under progress because
90             // the last time around, the caller may have called a "break" in
91             // their foreach
92
93             // Yield the elements -- any removal method ensures that
94             // m_currentIteratorIndex is set correctly so that the ++ does
95             // the right thing
96             
97             m_currentIteratorIndex = 0;
98             while (m_currentIteratorIndex < m_elements.Count) {
99                 yield return m_elements[m_currentIteratorIndex];
100                 m_currentIteratorIndex++;
101             }
102         }
103
104         internal override void ToCompactString(StringBuilder builder) {
105             StringUtil.ToCommaSeparatedString(builder, m_elements);
106         }
107         #endregion
108
109         #region Private Methods
110         // requires: The array is at least of size index+1
111         // effects: Removes the element at index
112         private TElement Remove(int index) {
113             Debug.Assert(index < m_elements.Count, "Removing an entry with too high an index");
114             // Place the last element at "index" and remove the last element
115             TElement element = m_elements[index];
116             int lastIndex = m_elements.Count - 1;
117             m_elements[index] = m_elements[lastIndex];
118             m_elements.RemoveAt(lastIndex);
119             return element;
120         }
121         #endregion
122     }
123 }