/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
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using NUnit.Framework;
-
- namespace Delta.Utilities.Collections
- {
- /// <summary>
- /// This class defines a list with a "stack behavior". Note:
- /// Iterating items in a loop will always go from top to bottom, which means
- /// in a "for" is the item with index '0' the "TopMost" one and the same in
- /// a foreach loop where the first item the "TopMost" one is.
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- public class StackList<T> : IEnumerable<T>
- {
- #region Count (Public)
- /// <summary>
- /// The number of the elements which are currently in the stack.
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- public int Count
- {
- get
- {
- return dataList.Count;
- }
- }
- #endregion
-
- #region TopMost (Public)
- /// <summary>
- /// Returns the top most element of the stack (without removing).
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- public T TopMost
- {
- get
- {
- if (Count == 0)
- {
- throw new InvalidOperationException("Can't access the 'TopMost'" +
- " element, because the stack is empty.");
- } // if
-
- return dataList[dataList.Count - 1];
- } // get
- }
- #endregion
-
- #region Item (Public)
- /// <summary>
- /// Item
- /// </summary>
- /// <param name="elementIndex">Element Index</param>
- /// <returns>Item</returns>
- public T this[int elementIndex]
- {
- get
- {
- return dataList[(dataList.Count - 1) - elementIndex];
- } // get
- set
- {
- dataList[(dataList.Count - 1) - elementIndex] = value;
- }
- }
- #endregion
-
- #region Private
-
- #region dataList (Private)
- /// <summary>
- /// Internal data list which stores all the stack data.
- /// -> The first element represents the "BottomMost" one and the last
- /// element represents the "TopMost" one.
- /// </summary>
- /// <typeparam name="T">T</typeparam>
- private readonly List<T> dataList;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Stack list
- /// </summary>
- public StackList()
- {
- dataList = new List<T>();
- }
- #endregion
-
- #region IEnumerable Members
- /// <summary>
- /// IEnumerable. get enumerator
- /// </summary>
- /// <returns>enumerator</returns>
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- #endregion
-
- #region IEnumerable<T> Members
- /// <summary>
- /// Get enumerator
- /// </summary>
- /// <returns>enumerator</returns>
- public IEnumerator<T> GetEnumerator()
- {
- // Reference:
- // -> http://shiman.wordpress.com/2008/08/01/c-net-iterator-example-reverse-iteration/
- for (int index = dataList.Count - 1; index >= 0; --index)
- {
- yield return dataList[index];
- }
- }
- #endregion
-
- #region IndexOf (Public)
- /// <summary>
- /// Return the index of the item if it's in the stack list else the
- /// "MathHelper.InvalidIndex".
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>Index of the item</returns>
- public int IndexOf(T item)
- {
- return dataList.IndexOf(item);
- }
- #endregion
-
- #region Contains (Public)
- /// <summary>
- /// Contains
- /// </summary>
- /// <param name="item">Item</param>
- /// <returns>Contains</returns>
- public bool Contains(T item)
- {
- return dataList.Contains(item);
- }
- #endregion
-
- #region Push (Public)
- /// <summary>
- /// Puts the new item as the new "TopMost" item of the stack.
- /// </summary>
- /// <param name="newTopMostItem">New top most item</param>
- public void Push(T newTopMostItem)
- {
- // Just add to the list
- dataList.Add(newTopMostItem);
- }
- #endregion
-
- #region Remove (Public)
- /// <summary>
- /// Removes a specific item from the list.
- /// </summary>
- /// <param name="itemToRemove">Item to remove</param>
- /// <returns>True if the removal was successful, false otherwise.</returns>
- public bool Remove(T itemToRemove)
- {
- return dataList.Remove(itemToRemove);
- }
- #endregion
-
- #region Pop (Public)
- /// <summary>
- /// Returns the top most element and removes it from the stack.
- /// </summary>
- /// <returns>the top most element</returns>
- public T Pop()
- {
- // At fist we have to "remember" the item
- T topMostItem = TopMost;
- // then remove it (TopMost <-> last)
- dataList.RemoveAt(dataList.Count - 1);
-
- return topMostItem;
- }
-
- // Pop()
-
- /// <summary>
- /// Pop
- /// </summary>
- /// <param name="indexToPop">Index to pop</param>
- /// <returns>Pop</returns>
- public T Pop(int indexToPop)
- {
- T itemToRemove = this[indexToPop];
- dataList.RemoveAt(indexToPop);
-
- return itemToRemove;
- }
- #endregion
-
- #region PopTo (Public)
- /// <summary>
- /// Pop to
- /// </summary>
- /// <param name="index">index</param>
- /// <returns>Pop to</returns>
- public bool PopTo(int index)
- {
- int removeCount = Count - index;
-
- #region Validation
- if (removeCount > Count)
- {
- Log.Warning("PopTo() - The index mayn't be negative.");
- return false;
- } // if
-
- if (removeCount < 1)
- {
- Log.Warning("PopTo() - The index can be max. '" + (Count - 1) + "'");
- return false;
- } // if
- #endregion
-
- // Compute the index from where we want to start to skip/remove all
- // containing items
- int removeStartIndex = Count - removeCount;
- dataList.RemoveRange(removeStartIndex, removeCount);
-
- return true;
- }
- #endregion
-
- #region GetItems (Public)
- /// <summary>
- /// Returns all items that are currently in the StackList without modifying
- /// or removing them.
- /// </summary>
- /// <returns>all items that are currently in the StackList</returns>
- public T[] GetItems()
- {
- return dataList.ToArray();
- }
- #endregion
- }
-
- /// <summary>
- /// StackList tests (must be here because StackList is a generic class)
- /// </summary>
- internal class StackListTests : StackList<String>
- {
- #region TestPush
- /// <summary>
- /// Test Push
- /// </summary>
- [Test]
- public void TestPush()
- {
- StackListTests stack = new StackListTests();
- Assert.Equal(0, stack.Count);
- stack.Push("ch");
- Assert.Equal(1, stack.Count);
- Assert.Equal(stack.TopMost, stack[0]);
- stack.Push("ars");
- Assert.Equal(2, stack.Count);
- Assert.Equal(stack.TopMost, stack[0]);
- Assert.Equal("ars", stack[0]);
- }
- #endregion
-
- #region TestPop
- /// <summary>
- /// Test Pop
- /// </summary>
- [Test]
- public void TestPop()
- {
- StackListTests stack = new StackListTests();
-
- Assert.Equal(0, stack.Count);
-
- stack.Push("ch");
- stack.Push("ars");
- Assert.Equal(2, stack.Count);
- Assert.Equal("ars", stack.TopMost);
-
- stack.Pop();
- Assert.Equal(1, stack.Count);
- Assert.Equal("ch", stack.TopMost);
-
- stack.Pop();
- Assert.Equal(0, stack.Count);
- }
- #endregion
-
- #region TestContains
- /// <summary>
- /// Test Contains
- /// </summary>
- [Test]
- public void TestContains()
- {
- String firstEntry = new String(new[]
- {
- 'c', 'h'
- });
-
- StackListTests stackList = new StackListTests();
- stackList.Push(firstEntry);
-
- Assert.True(stackList.Contains(firstEntry));
- Assert.True(stackList.Contains("ch"));
- }
- #endregion
-
- #region TestIterating
- /// <summary>
- /// Test Iterating
- /// </summary>
- [Test]
- public void TestIterating()
- {
- StackListTests stack = new StackListTests();
-
- stack.Push("1");
- stack.Push("2");
- stack.Push("3");
- stack.Push("4");
- stack.Push("5");
-
- Assert.Equal(stack.TopMost, "5");
-
- // Test a first "foreach" run
- int num = 5;
- foreach (string item in stack)
- {
- Assert.Equal(item, num.ToString());
- num--;
- }
- Assert.Equal(num, 0);
-
- // and test if a second run would have the same result
- num = 5;
- foreach (string item in stack)
- {
- Assert.Equal(item, num.ToString());
- num--;
- }
- Assert.Equal(num, 0);
-
- // finally just test a normal "for" loop
- num = 5;
- for (int index = 0; index < stack.Count; index++)
- {
- string item = stack[index];
- Assert.Equal(item, num.ToString());
- num--;
- }
- }
- #endregion
- }
- }