For my latest project in X++ I needed to use a Stack. .NET does already provide a Stack class however MS recommends using the Generics version as it is faster because it is typed. See Non-generic collections shouldn’t be used on GitHub. I had initially tried creating a Stack class using a container, but it was painfully slow – it took several minutes to push and pop 100,000 elements onto and off of the stack.
Here is my implementation:
class Stack extends List
{
private Types dataType;
public void push(anytype _value)
{
// double check that we have received a variable of the correct type
if (typeOf(_value) != dataType)
{
throw error("Incorrect data type");
}
this.addStart(_value);
}
public void new(Types _type)
{
dataType = _type;
super(_type);
}
public anytype pop()
{
ListIterator iterator;
anytype topValue;
// double check that there is an element on the stack
if (!this.elements())
{
return null;
}
iterator = new ListIterator(this);
// position the iterator to the top
iterator.more();
// retreive the value
topValue = iterator.value();
// remove the element from the stack
iterator.delete();
// return the value
return topValue;
}
}
Here is a job to demonstrate how to use the class and to test the speed of pushing and popping 100,000 elements on to and off of the stack:
class StackTest
{
/// <summary>
/// Runs the class with the specified arguments.
/// </summary>
/// <param name = "_args">The specified arguments.</param>
public static void main(Args _args)
{
System.Random random;
System.Diagnostics.Stopwatch stopwatch;
System.TimeSpan timeSpan;
Stack numberStack;
str elapsedTime;
random = new System.Random();
numberStack = new GWStack(Types::Integer);
stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
// push 100,000 random numbers onto the stack
for (int i = 0 ; i <= 100000 ; i++)
{
numberStack.push(random.Next(1, 1000));
}
// pop everything off of the stack one by one
for (int i = 0 ; i <= 100000 ; i++)
{
numberStack.pop();
}
stopwatch.Stop();
timeSpan = stopwatch.Elapsed;
elapsedTime = System.String::Format("{0:00}:{1:00}:{2:00}.{3:0000}",
timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds,
timeSpan.Milliseconds);
info(strFmt("elapsed time for list based stack: %1", elapsedTime));
}
}
The results show that pushing and popping 100,000 elements is well under 1 second.
Let me know if you use it or if you found this helpful.