PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Utilities/Collections/StackList.cs

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