1 /// LCFS container 2 module sily.stack; 3 4 import std.array: popFront; 5 import std.conv: to; 6 7 /// LCFS container 8 struct Stack(T) { 9 /// First element 10 private Node!T* _root = null; 11 /// Last element 12 private Node!T* _end = null; 13 /// Length 14 private size_t _length = 0; 15 /// Length limit 16 private size_t _lengthLimit = -1; 17 18 /// Length of stack 19 @property public size_t length() { return _length; } 20 /// Is stack empty 21 @property public bool empty() { return _root == null; } 22 /// Returns first value without removing it from stack 23 @property public T front() { return (*_root).value; } 24 25 /// Creates stack filled with vals 26 public this(T[] vals...) { 27 push(vals); 28 } 29 30 /// opOpAssign x += y == x.push(y) 31 Stack!T opOpAssign(string op)( in T b ) if ( op == "+" ) { 32 push(b); 33 return this; 34 } 35 36 /++ 37 Limits length of stack, default is -1 which is limitless. 38 If length is limited and new element is attempted to be 39 pushed when stack is overfilled nothing will happen. 40 +/ 41 void limitLength(size_t len) { 42 _lengthLimit = len; 43 clearAfter(_lengthLimit); 44 } 45 46 /// Adds vals at end of stack 47 public void push(T[] vals...) { 48 if (vals.length == 0) return; 49 if (_length >= _lengthLimit) return; 50 51 52 if (_root == null && _length < _lengthLimit) { 53 _root = new Node!T(vals[0]); 54 _end = _root; 55 vals.popFront(); 56 ++_length; 57 } 58 59 foreach (val; vals) { 60 if (_length >= _lengthLimit) break; 61 Node!T* _last = new Node!T(val); 62 (*_last).next = _root; 63 _root = _last; 64 ++_length; 65 } 66 } 67 68 /// Returns first value and removes it from stack 69 public T pop() { 70 if (_root == null) { return T.init; } 71 T val = (*_root).value; 72 --_length; 73 if ((*_root).next != null) { 74 _root = (*_root).next; 75 } else { 76 _root = null; 77 _end = null; 78 } 79 return val; 80 } 81 82 /// Removes all elements before pos (used in limitLength) 83 private void clearAfter(size_t pos) { 84 if (_root == null) return; 85 if (pos >= _length) return; 86 Node!T* _node = _root; 87 for (int i = 0; i < pos; ++i) { 88 if (i != pos - 1) { 89 _node = (*_node).next; 90 } else { 91 (*_node).next = null; 92 _end = _node; 93 } 94 } 95 } 96 97 /// Removes all elements from stack 98 public void clear() { 99 _root = null; 100 _end = null; 101 _length = 0; 102 } 103 104 public string toString() const { 105 if (_root == null) return "[]"; 106 107 string _out = "["; 108 109 Node!T* last = cast(Node!T*) _root; 110 111 while(true) { 112 _out ~= (*last).value.to!string; 113 if ((*last).next == null) break; 114 last = (*last).next; 115 _out ~= ", "; 116 } 117 _out ~= "]"; 118 return _out; 119 } 120 121 public T[] toArray(){ 122 if (_root == null) return T[].init; 123 124 T[] arr = []; 125 126 Node!T* last = cast(Node!T*) _root; 127 128 while(true) { 129 arr ~= (*last).value; 130 if ((*last).next == null) break; 131 last = (*last).next; 132 } 133 return arr; 134 } 135 } 136 137 private struct Node(T) { 138 private T _value; 139 private Node!T* _next = null; 140 141 @property public void value(T value) { _value = value; } 142 @property public T value() { return _value; } 143 144 @property public void next(Node!T* next) { _next = next; } 145 @property public Node!T* next() { return _next; } 146 147 @disable this(); 148 149 public this(T value) { 150 _value = value; 151 } 152 }