source: branches/AlphaChannel/AI Template/Project/Lib/ToughSet.cs

Last change on this file was 191, checked in by chronos, 5 years ago
  • Added: AI Template directory with manual for development of custom AI from original game.
File size: 4.7 KB
Line 
1using System;
2using System.Collections.Generic;
3
4// collection class with the following operations:
5// * add object
6// * iterate collection using foreach statement
7// * remove current object from within iteration
8
9// when removing objects while iterating, the following conditions are assured:
10// * no elements that are still in the collection are left out
11// * no elements that are no longer in the collection are iterated
12// * no element is iterated twice
13// * in case of nested iterations of the collection, all this is true for each of them
14
15// calling GetEnumerator explicitely is not recommended
16// never iterate from multiple threads at the same time
17
18namespace Common
19{
20 /// <summary>
21 /// Simple collection class which can be changed from within iteration.
22 /// </summary>
23 /// <typeparam name="T">type of collected objects</typeparam>
24 class ToughSet<T> : IEnumerable<T>
25 {
26 List<T> list = new List<T>();
27 List<Enumerator<T>> enumerators = new List<Enumerator<T>>(4); // list will rarely have more than 1 element
28
29 /// <summary>
30 /// Creates an empty collection.
31 /// </summary>
32 public ToughSet() { }
33
34 /// <summary>
35 /// Number of elements contained in the collection.
36 /// </summary>
37 public int Count { get { return list.Count; } }
38
39 /// <summary>
40 /// Adds an object to the collection.
41 /// </summary>
42 /// <param name="item">The object to be added.</param>
43 public void Add(T item) { list.Add(item); }
44
45 /// <summary>
46 /// Removes the current object of an iteration from the collection. Can only be called from within foreach loop.
47 /// </summary>
48 public void RemoveCurrent()
49 {
50 if (enumerators.Count == 0)
51 throw new Exception("ToughSet.Remove() can only be called from within foreach loop!");
52 Enumerator<T> innerEnumerator = enumerators[enumerators.Count - 1];
53 if (!innerEnumerator.currentWasRemoved)
54 {
55 int removeIndex = innerEnumerator.index;
56 if (removeIndex >= 0 && removeIndex < list.Count)
57 {
58 list.RemoveAt(removeIndex);
59 foreach (Enumerator<T> enumerator in enumerators)
60 enumerator.RemoveAt(removeIndex);
61 }
62 }
63 }
64
65 void EnumerationEnded(Enumerator<T> enumerator) // parameter is only for proof of correctness
66 {
67 if (enumerators.Count == 0)
68 throw new Exception("Error in ToughSet: Only started foreach loop can end!");
69 Enumerator<T> innerEnumerator = enumerators[enumerators.Count - 1];
70 if (enumerator != innerEnumerator)
71 throw new Exception("Error in ToughSet: Only most inner foreach loop can end!");
72 enumerator.DisposeEvent -= EnumerationEnded;
73 enumerators.RemoveAt(enumerators.Count - 1);
74 }
75
76 #region IEnumerable members
77 class Enumerator<TEn> : IEnumerator<TEn>
78 {
79 ToughSet<TEn> parent;
80 public int index;
81 public bool currentWasRemoved = false;
82 TEn current;
83
84 public Enumerator(ToughSet<TEn> parent)
85 {
86 this.parent = parent;
87 index = -1;
88 }
89
90 public void RemoveAt(int removeIndex)
91 {
92 if (removeIndex == index)
93 currentWasRemoved = true;
94 if (removeIndex <= index)
95 index--;
96 }
97
98 public delegate void DisposeEventHandler(Enumerator<TEn> enumerator);
99 public event DisposeEventHandler DisposeEvent;
100
101 #region IEnumerator Members
102 public void Reset() { index = -1; }
103 public TEn Current { get { return current; } }
104 object System.Collections.IEnumerator.Current { get { return current; } }
105 public void Dispose() { DisposeEvent(this); }
106
107 public bool MoveNext()
108 {
109 index++;
110 if (index < parent.list.Count)
111 {
112 current = parent.list[index];
113 currentWasRemoved = false;
114 return true;
115 }
116 else
117 return false;
118 }
119 #endregion
120 }
121
122 public IEnumerator<T> GetEnumerator()
123 {
124 Enumerator<T> enumerator = new Enumerator<T>(this);
125 enumerators.Add(enumerator);
126 enumerator.DisposeEvent += EnumerationEnded;
127 return enumerator;
128 }
129 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
130 #endregion
131 }
132}
133
134/*
135class was tested with the following code:
136
137ToughSet<int> ts = new ToughSet<int>();
138for (int i = 0; i < 20; i++)
139 ts.Add(i);
140
141foreach (int i in ts)
142{ // should iterate 0-1-2-3-5-6-7-8-9-11-13-14-15-16-17
143 if (i == 3)
144 {
145 foreach (int j in ts)
146 {
147 if (j == 1 || j == 4 || j ==12)
148 ts.Remove();
149 if (j == 14)
150 break;
151 }
152 }
153 if (i == 9)
154 {
155 foreach (int j in ts)
156 {
157 if (j == 0 || j == 9 || j == 10)
158 ts.Remove();
159 if (j == 16)
160 break;
161 }
162 }
163 if (i == 8 || i == 9 || i == 16)
164 ts.Remove();
165 if (i == 17)
166 break;
167}
168foreach (int i in ts)
169{ // should iterate 2-3-5-6-7-11-13-14-15-17-18-19
170}
171ts.Remove(); // should throw exception
172*/
Note: See TracBrowser for help on using the repository browser.