1 module sbin.util.stack; 2 3 package(sbin): 4 5 struct Stack(T, size_t N=0) 6 { 7 //private 8 public 9 { 10 ptrdiff_t topI = 0; 11 static if (N) T[N] sdata; 12 T[] data; 13 } 14 15 private void pushDynamic(T val) 16 { 17 if (cast(ptrdiff_t)data.length < topI-N) data ~= val; 18 else top = val; 19 } 20 21 void push(T val) 22 { 23 topI++; 24 static if (N) 25 { 26 if (topI <= cast(ptrdiff_t)N) top = val; 27 else pushDynamic(val); 28 } 29 else pushDynamic(val); 30 } 31 32 const(T[]) getData() const 33 { 34 static if (N) 35 { 36 if (topI <= cast(ptrdiff_t)N) return sdata[0..topI]; 37 else return (sdata[] ~ data)[0..topI]; 38 } 39 else return data[0..topI]; 40 } 41 42 void reserve(ptrdiff_t k) 43 { 44 k -= N; 45 if ((cast(ptrdiff_t)data.length) < k) data.length = k; 46 } 47 48 ref inout(T) top() inout @property 49 { 50 static if (N) 51 return (topI <= (cast(ptrdiff_t)N)) ? sdata[topI-1] : data[topI-N-1]; 52 else 53 return data[topI-1]; 54 } 55 T pop() 56 { 57 if (empty) assert(0, "stack empty"); 58 T ret = top; 59 topI--; 60 return ret; 61 } 62 bool empty() const @property { return topI == 0; } 63 void clear() { data.length = 0; topI = 0; } 64 } 65 66 version (unittest) void testStack(size_t N)() 67 { 68 Stack!(int, N) s; 69 assert (s.empty); 70 s.reserve(5); 71 assert (s.empty); 72 s.push(1); 73 assert (!s.empty); 74 s.push(2); 75 assert (!s.empty); 76 assert (s.top == 2); 77 s.pop(); 78 assert (s.top == 1); 79 s.pop(); 80 assert (s.empty); 81 82 import std.exception : assertThrown; 83 import core.exception : RangeError, AssertError; 84 import std.algorithm : equal, map; 85 import std.range : iota, chain; 86 87 assertThrown!RangeError(s.top); 88 assertThrown!AssertError(s.pop()); 89 90 foreach (i; 1..10) s.push(i*10); 91 assert (equal(s.getData(), iota(1,10).map!"a*10")); 92 foreach_reverse (i; 1..10) assert (s.pop() == i*10); 93 94 foreach (i; 1..100) s.push(i*3); 95 assert (equal(s.getData(), iota(1,100).map!"a*3")); 96 assert(s.pop() == 99*3); 97 foreach (i; 1..10) s.push(i*2); 98 assert (equal(s.getData(), chain(iota(1,99).map!"a*3", iota(1,10).map!"a*2"))); 99 foreach_reverse (i; 1..10) assert (s.pop() == i*2); 100 foreach_reverse (i; 1..99) assert (s.pop() == i*3); 101 102 assert (s.empty); 103 s.push(100); 104 assert (!s.empty); 105 s.clear(); 106 assert (s.empty); 107 } 108 109 unittest 110 { 111 static foreach (N; [0,1,5,8,9,10,11,12,99,100,101,196]) 112 testStack!N; 113 }