namespace HeuristicLab.Problems.ProgramSynthesis.Push.Stack {
using System;
using System.Collections;
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 PushStack : IPushStack {
private const string Delimiter = " ";
private readonly List data;
public PushStack(int capacity = 0) {
data = new List(capacity);
IsEnabled = true;
}
public bool IsEnabled { get; set; }
public int Capacity
{
get
{
return data.Capacity;
}
}
public T Top
{
get
{
return data[Count - 1];
}
}
public T TopOrDefault
{
get
{
return Count > 0 ? Top : default(T);
}
}
public T Bottom
{
get
{
return data[0];
}
}
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[index];
}
public T ReverseElementAt(int offset) {
return data[offset];
}
public void SetTop(T value) {
data[Count - 1] = value;
}
public T this[int index]
{
get { return data[Count - 1 - index]; }
set { data[Count - 1 - index] = value; }
}
public void Swap(int count) {
var top = Top;
var bottomIndex = Count - count;
for (var i = Count - 1; i > bottomIndex; i--)
data[i] = data[i - 1];
data[bottomIndex] = top;
}
public void Yank(int index) {
if (index == Count - 1) return;
var item = ReverseElementAt(index);
data.RemoveAt(index);
data.Add(item);
}
public T Pop() {
var top = Top;
data.RemoveAt(Count - 1);
return top;
}
public T[] Pop(int count) {
var items = Peek(count);
Remove(count);
return items;
}
public T Peek() {
return Top;
}
public T[] Peek(int count) {
var startIndex = Count - count;
var items = new T[count];
data.CopyTo(startIndex, items, 0, count);
return items;
}
public void Push(T item) {
if (!IsEnabled) return;
data.Add(item);
}
public void Push(T item1, T item2) {
if (!IsEnabled) return;
data.Add(item1);
data.Add(item2);
}
public void Push(T item1, T item2, T item3) {
if (!IsEnabled) return;
data.Add(item1);
data.Add(item2);
data.Add(item3);
}
public void Push(T item1, T item2, T item3, T item4) {
if (!IsEnabled) return;
data.Add(item1);
data.Add(item2);
data.Add(item3);
data.Add(item4);
}
public void PushResult(int count, Func templateFunc) {
if (!IsEnabled) return;
var startIndex = Count - count;
var items = new T[count];
data.CopyTo(startIndex, items, 0, count);
Remove(count - 1);
data[Count - 1] = templateFunc(items);
}
public void Push(IReadOnlyList items, int startIndex) {
if (!IsEnabled) return;
for (var i = startIndex; i < items.Count; i++) data.Add(items[i]);
}
public void Push(IReadOnlyList items) {
if (!IsEnabled) return;
data.AddRange(items);
}
public void Insert(int index, T item) {
if (!IsEnabled) return;
data.Insert(Count - index, item);
}
public bool Remove(T item) {
return this.data.Remove(item);
}
public void RemoveTop() {
data.RemoveAt(Count - 1);
}
public void Remove(int count) {
this.data.RemoveRange(this.Count - count, count);
}
public void RemoveAt(int index) {
data.RemoveAt(index);
}
public void RemoveAt(int index, int count) {
data.RemoveRange(index, count);
}
public bool TryPop(out T item) {
if (Count > 0) {
item = Pop();
return true;
}
item = default(T);
return false;
}
IEnumerator IEnumerable.GetEnumerator() {
return data.GetEnumerator();
}
public override string ToString() {
var data = this.data as IEnumerable;
return string.Join(Delimiter, data.Reverse());
}
}
}