namespace TestPooling.DirtyList { using System; using System.Collections.Generic; using System.Linq; /// /// While Push's stacks are generally treated as genuine stacks---that is, inclassions take their arguments from the /// tops of /// the stacks and push their results onto the tops of the stacks---a few inclassions (like YANK and SHOVE) do allow /// direct access /// to "deep" stack elements by means of integer indices. To this extent the stacks can be used as general, random /// access memory /// classures. This is one of the features that ensures the Turing-completeness of Push (another being the arbitrary /// name/value /// bindings supported by the NAME data type and DEFINE methods; see below). /// /// The item type of the collection. public class PushStack3 { private const string Delimiter = " "; private readonly LinkedList data; public PushStack3() { data = new LinkedList(); IsEnabled = true; } public bool IsEnabled { get; set; } public T Top { get { return data.Last.Value; } } public T TopOrDefault { get { return Count > 0 ? Top : default(T); } } public T Bottom { get { return data.First.Value; } } public T BottomOrDefault { get { return Count > 0 ? Bottom : default(T); } } public int Count { get { return data.Count; } } public bool IsEmpty { get { return Count == 0; } } public bool IsReadOnly { get { return false; } } public void Add(T item) { Push(item); } public void Clear() { data.Clear(); } public bool Contains(T item) { return data.Contains(item); } public void CopyTo(T[] array, int arrayIndex) { data.CopyTo(array, arrayIndex); } public IEnumerator GetEnumerator() { return data.GetEnumerator(); } public T ElementAt(int index) { return data.ElementAt(index); } public T ReverseElementAt(int offset) { return ElementAt(Count - 1 - offset); } public void SetTop(T value) { data.Last.Value = value; } private LinkedListNode GetByIndex(int index) { var current = data.First; for (var i = 0; i <= index; i++) { current = current.Next; } return current; } public T this[int key] { get { return ElementAt(key); } set { GetByIndex(key).Value = value; } } public void Swap(int count) { var topValue = Top; var current = data.Last; var bottomIndex = Count - count; for (var i = Count - 1; i > bottomIndex; i--) { current.Value = current.Previous.Value; current = current.Previous; } data.Last.Value = topValue; } public void Yank(int index) { if (index == Count - 1) return; var item = GetByIndex(index); data.Remove(item); data.AddLast(item); } public T Pop() { var value = Top; data.RemoveLast(); return value; } public T[] Pop(int count) { var items = new T[count]; for (var i = 0; i < count; i++) { items[count - i] = Top; data.RemoveLast(); } return items; } public T Peek() { return Top; } public T[] Peek(int count) { var items = new T[count]; var current = data.Last; for (var i = 0; i < count; i++) { items[count - i] = current.Value; current = current.Previous; } return items; } public void Push(T item) { if (!IsEnabled) return; data.AddLast(item); } public void Push(T item1, T item2) { if (!IsEnabled) return; data.AddLast(item1); data.AddLast(item2); } public void Push(T item1, T item2, T item3) { if (!IsEnabled) return; data.AddLast(item1); data.AddLast(item2); data.AddLast(item3); } public void Push(T item1, T item2, T item3, T item4) { if (!IsEnabled) return; data.AddLast(item1); data.AddLast(item2); data.AddLast(item3); data.AddLast(item4); } public void PushResult(int count, Func templateFunc) { if (!IsEnabled) return; Push(templateFunc(Pop(count))); } public void PushRange(IReadOnlyList items) { if (!IsEnabled) return; for (var i = 0; i < items.Count; i++) data.AddLast(items[i]); } public void Insert(int index, T value) { if (!IsEnabled) return; var node = GetByIndex(index); data.AddBefore(node, value); } public bool Remove(T item) { return data.Remove(item); } public void RemoveTop() { data.RemoveLast(); } public void Remove(int count) { for (var i = 0; i < count; i++) data.RemoveLast(); } public void RemoveAt(int index) { var node = GetByIndex(index); data.Remove(node); } public void RemoveAt(int index, int count) { var node = GetByIndex(index); for (var i = 0; i < count; i++) { data.Remove(node); node = node.Next; } } public bool TryPop(out T item) { if (Count > 0) { item = Pop(); return true; } item = default(T); return false; } public override string ToString() { var data = this.data as IEnumerable; return string.Join(Delimiter, data.Reverse()); } } }