PageRenderTime 47ms CodeModel.GetById 13ms app.highlight 13ms RepoModel.GetById 17ms app.codeStats 0ms

/Utilities/Collections/StackList.cs

#
C# | 362 lines | 220 code | 40 blank | 102 comment | 6 complexity | 278f0d8856169970fe2f417cec247cf9 MD5 | raw file
  1using System;
  2using System.Collections;
  3using System.Collections.Generic;
  4using NUnit.Framework;
  5
  6namespace Delta.Utilities.Collections
  7{
  8	/// <summary>
  9	/// This class defines a list with a "stack behavior". Note:
 10	/// Iterating items in a loop will always go from top to bottom, which means
 11	/// in a "for" is the item with index '0' the "TopMost" one and the same in
 12	/// a foreach loop where the first item the "TopMost" one is.
 13	/// </summary>
 14	/// <typeparam name="T">T</typeparam>
 15	public class StackList<T> : IEnumerable<T>
 16	{
 17		#region Count (Public)
 18		/// <summary>
 19		/// The number of the elements which are currently in the stack.
 20		/// </summary>
 21		/// <typeparam name="T">T</typeparam>
 22		public int Count
 23		{
 24			get
 25			{
 26				return dataList.Count;
 27			}
 28		}
 29		#endregion
 30
 31		#region TopMost (Public)
 32		/// <summary>
 33		/// Returns the top most element of the stack (without removing).
 34		/// </summary>
 35		/// <typeparam name="T">T</typeparam>
 36		public T TopMost
 37		{
 38			get
 39			{
 40				if (Count == 0)
 41				{
 42					throw new InvalidOperationException("Can't access the 'TopMost'" +
 43					                                    " element, because the stack is empty.");
 44				} // if
 45
 46				return dataList[dataList.Count - 1];
 47			} // get
 48		}
 49		#endregion
 50
 51		#region Item (Public)
 52		/// <summary>
 53		/// Item
 54		/// </summary>
 55		/// <param name="elementIndex">Element Index</param>
 56		/// <returns>Item</returns>
 57		public T this[int elementIndex]
 58		{
 59			get
 60			{
 61				return dataList[(dataList.Count - 1) - elementIndex];
 62			} // get
 63			set
 64			{
 65				dataList[(dataList.Count - 1) - elementIndex] = value;
 66			}
 67		}
 68		#endregion
 69
 70		#region Private
 71
 72		#region dataList (Private)
 73		/// <summary>
 74		/// Internal data list which stores all the stack data.
 75		/// -> The first element represents the "BottomMost" one and the last
 76		///			element represents the "TopMost" one.
 77		/// </summary>
 78		/// <typeparam name="T">T</typeparam>
 79		private readonly List<T> dataList;
 80		#endregion
 81
 82		#endregion
 83
 84		#region Constructors
 85		/// <summary>
 86		/// Stack list
 87		/// </summary>
 88		public StackList()
 89		{
 90			dataList = new List<T>();
 91		}
 92		#endregion
 93
 94		#region IEnumerable Members
 95		/// <summary>
 96		/// IEnumerable. get enumerator
 97		/// </summary>
 98		/// <returns>enumerator</returns>
 99		IEnumerator IEnumerable.GetEnumerator()
100		{
101			return GetEnumerator();
102		}
103		#endregion
104
105		#region IEnumerable<T> Members
106		/// <summary>
107		/// Get enumerator
108		/// </summary>
109		/// <returns>enumerator</returns>
110		public IEnumerator<T> GetEnumerator()
111		{
112			// Reference:
113			// -> http://shiman.wordpress.com/2008/08/01/c-net-iterator-example-reverse-iteration/
114			for (int index = dataList.Count - 1; index >= 0; --index)
115			{
116				yield return dataList[index];
117			}
118		}
119		#endregion
120
121		#region IndexOf (Public)
122		/// <summary>
123		/// Return the index of the item  if it's in the stack list else the
124		/// "MathHelper.InvalidIndex".
125		/// </summary>
126		/// <param name="item">Item</param>
127		/// <returns>Index of the item</returns>
128		public int IndexOf(T item)
129		{
130			return dataList.IndexOf(item);
131		}
132		#endregion
133
134		#region Contains (Public)
135		/// <summary>
136		/// Contains
137		/// </summary>
138		/// <param name="item">Item</param>
139		/// <returns>Contains</returns>
140		public bool Contains(T item)
141		{
142			return dataList.Contains(item);
143		}
144		#endregion
145
146		#region Push (Public)
147		/// <summary>
148		/// Puts the new item as the new "TopMost" item of the stack.
149		/// </summary>
150		/// <param name="newTopMostItem">New top most item</param>
151		public void Push(T newTopMostItem)
152		{
153			// Just add to the list
154			dataList.Add(newTopMostItem);
155		}
156		#endregion
157
158		#region Remove (Public)
159		/// <summary>
160		/// Removes a specific item from the list.
161		/// </summary>
162		/// <param name="itemToRemove">Item to remove</param>
163		/// <returns>True if the removal was successful, false otherwise.</returns>
164		public bool Remove(T itemToRemove)
165		{
166			return dataList.Remove(itemToRemove);
167		}
168		#endregion
169
170		#region Pop (Public)
171		/// <summary>
172		/// Returns the top most element and removes it from the stack.
173		/// </summary>
174		/// <returns>the top most element</returns>
175		public T Pop()
176		{
177			// At fist we have to "remember" the item
178			T topMostItem = TopMost;
179			// then remove it (TopMost <-> last)
180			dataList.RemoveAt(dataList.Count - 1);
181
182			return topMostItem;
183		}
184
185		// Pop()
186
187		/// <summary>
188		/// Pop
189		/// </summary>
190		/// <param name="indexToPop">Index to pop</param>
191		/// <returns>Pop</returns>
192		public T Pop(int indexToPop)
193		{
194			T itemToRemove = this[indexToPop];
195			dataList.RemoveAt(indexToPop);
196
197			return itemToRemove;
198		}
199		#endregion
200
201		#region PopTo (Public)
202		/// <summary>
203		/// Pop to
204		/// </summary>
205		/// <param name="index">index</param>
206		/// <returns>Pop to</returns>
207		public bool PopTo(int index)
208		{
209			int removeCount = Count - index;
210
211			#region Validation
212			if (removeCount > Count)
213			{
214				Log.Warning("PopTo() - The index mayn't be negative.");
215				return false;
216			} // if
217
218			if (removeCount < 1)
219			{
220				Log.Warning("PopTo() - The index can be max. '" + (Count - 1) + "'");
221				return false;
222			} // if
223			#endregion
224
225			// Compute the index from where we want to start to skip/remove all
226			// containing items
227			int removeStartIndex = Count - removeCount;
228			dataList.RemoveRange(removeStartIndex, removeCount);
229
230			return true;
231		}
232		#endregion
233
234		#region GetItems (Public)
235		/// <summary>
236		/// Returns all items that are currently in the StackList without modifying
237		/// or removing them.
238		/// </summary>
239		/// <returns>all items that are currently in the StackList</returns>
240		public T[] GetItems()
241		{
242			return dataList.ToArray();
243		}
244		#endregion
245	}
246
247	/// <summary>
248	/// StackList tests (must be here because StackList is a generic class)
249	/// </summary>
250	internal class StackListTests : StackList<String>
251	{
252		#region TestPush
253		/// <summary>
254		/// Test Push
255		/// </summary>
256		[Test]
257		public void TestPush()
258		{
259			StackListTests stack = new StackListTests();
260			Assert.Equal(0, stack.Count);
261			stack.Push("ch");
262			Assert.Equal(1, stack.Count);
263			Assert.Equal(stack.TopMost, stack[0]);
264			stack.Push("ars");
265			Assert.Equal(2, stack.Count);
266			Assert.Equal(stack.TopMost, stack[0]);
267			Assert.Equal("ars", stack[0]);
268		}
269		#endregion
270
271		#region TestPop
272		/// <summary>
273		/// Test Pop
274		/// </summary>
275		[Test]
276		public void TestPop()
277		{
278			StackListTests stack = new StackListTests();
279
280			Assert.Equal(0, stack.Count);
281
282			stack.Push("ch");
283			stack.Push("ars");
284			Assert.Equal(2, stack.Count);
285			Assert.Equal("ars", stack.TopMost);
286
287			stack.Pop();
288			Assert.Equal(1, stack.Count);
289			Assert.Equal("ch", stack.TopMost);
290
291			stack.Pop();
292			Assert.Equal(0, stack.Count);
293		}
294		#endregion
295		
296		#region TestContains
297		/// <summary>
298		/// Test Contains
299		/// </summary>
300		[Test]
301		public void TestContains()
302		{
303			String firstEntry = new String(new[]
304			{
305				'c', 'h'
306			});
307
308			StackListTests stackList = new StackListTests();
309			stackList.Push(firstEntry);
310
311			Assert.True(stackList.Contains(firstEntry));
312			Assert.True(stackList.Contains("ch"));
313		}
314		#endregion
315
316		#region TestIterating
317		/// <summary>
318		/// Test Iterating
319		/// </summary>
320		[Test]
321		public void TestIterating()
322		{
323			StackListTests stack = new StackListTests();
324
325			stack.Push("1");
326			stack.Push("2");
327			stack.Push("3");
328			stack.Push("4");
329			stack.Push("5");
330
331			Assert.Equal(stack.TopMost, "5");
332
333			// Test a first "foreach" run
334			int num = 5;
335			foreach (string item in stack)
336			{
337				Assert.Equal(item, num.ToString());
338				num--;
339			}
340			Assert.Equal(num, 0);
341
342			// and test if a second run would have the same result
343			num = 5;
344			foreach (string item in stack)
345			{
346				Assert.Equal(item, num.ToString());
347				num--;
348			}
349			Assert.Equal(num, 0);
350
351			// finally just test a normal "for" loop
352			num = 5;
353			for (int index = 0; index < stack.Count; index++)
354			{
355				string item = stack[index];
356				Assert.Equal(item, num.ToString());
357				num--;
358			}
359		}
360		#endregion
361	}
362}