1 module anansi.container.stack; 2 3 import std.range, std.traits; 4 5 /** 6 * Implements a 7 */ 8 struct Stack(T) { 9 public this(Stuff)(Stuff stuff) 10 if (isInputRange!Stuff && 11 isImplicitlyConvertible!(ElementType!Stuff, T)) { 12 _payload = array(stuff); 13 } 14 15 this(this) { 16 _payload = _payload.dup; 17 } 18 19 void push(T value) { 20 _payload ~= value; 21 } 22 23 void pop() 24 in { 25 assert (_payload.length > 0, "Stack must not be empty to pop"); 26 } 27 body { 28 _payload = _payload[0 .. $-1]; 29 _payload.assumeSafeAppend(); 30 } 31 32 @property ref inout(T) front() inout 33 in { 34 assert (_payload.length > 0, "Stack must not be empty to read front"); 35 } 36 body { 37 return _payload[$-1]; 38 } 39 40 @property bool empty() const { 41 return _payload.empty; 42 } 43 44 @property size_t length() const { 45 return _payload.length; 46 } 47 48 private T[] _payload; 49 } 50 51 version (unittest) { 52 import std.conv, std.stdio; 53 } 54 55 unittest { 56 writeln("Stack: Default construction must yield an empty stack."); 57 auto s = Stack!int(); 58 assert(s.empty, "A default-constructed stack should be empty"); 59 assert(s.length == 0, "A default-constructed stack should have a length of 0"); 60 } 61 62 unittest { 63 writeln("Stack: Construction from a range should yield a non-empty stack."); 64 auto s = Stack!int([1, 2, 3, 4, 5, 6, 7, 8, 9]); 65 assert (!s.empty, "Range-constructed stack should not be empty"); 66 assert (s.length == 9, "Range-constructed stack should have length 9."); 67 } 68 69 unittest { 70 writeln("Stack: Enumerating a stack should yield items in reverse order."); 71 auto s = Stack!int([1, 2, 3, 4, 5, 6, 7, 8, 9]); 72 int expected = 9; 73 while (!s.empty) { 74 assert (s.front == expected, 75 "Expected " ~ to!string(expected) ~ 76 ", got " ~ to!string(s.front)); 77 s.pop(); 78 expected--; 79 } 80 } 81 82 unittest { 83 writeln("Stack: Adding an item to a stack should increase its length."); 84 auto s = Stack!int(); 85 s.push(42); 86 assert (!s.empty, "Stack should not be empty after push."); 87 assert (s.length == 1, "Stack should not be empty after push."); 88 } 89 90 unittest { 91 writeln("Stack: Popping an item from a stack should decrease its length."); 92 auto s = Stack!int([1, 2, 3, 4, 5]); 93 auto n = s.length; 94 s.pop(); 95 assert (s.length == (n-1), "Stack length should be reduced by 1 after a pop."); 96 97 }