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 }