1 //---------------------------------------------------------------------
2 // <copyright file="ModifiableIteratorCollection.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
12 using System.Collections;
13 using System.Collections.Generic;
15 using System.Diagnostics;
17 namespace System.Data.Common.Utils {
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
27 internal class ModifiableIteratorCollection<TElement> : InternalBase {
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;
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;
46 // effects: Returns true if the collection has no elements
47 internal bool IsEmpty {
49 return m_elements.Count == 0;
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);
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
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--;
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
93 // Yield the elements -- any removal method ensures that
94 // m_currentIteratorIndex is set correctly so that the ++ does
97 m_currentIteratorIndex = 0;
98 while (m_currentIteratorIndex < m_elements.Count) {
99 yield return m_elements[m_currentIteratorIndex];
100 m_currentIteratorIndex++;
104 internal override void ToCompactString(StringBuilder builder) {
105 StringUtil.ToCommaSeparatedString(builder, m_elements);
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);