1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2008 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6         
7         version:        Initial release: April 2008      
8         
9         author:         Kris
10 
11         Since:          0.99.7
12 
13 *******************************************************************************/
14 
15 module tango.util.container.more.Stack;
16 
17 private import tango.core.Exception : RangeError;
18 
19 /******************************************************************************
20 
21         A stack of the given value-type V, with maximum depth Size. Note
22         that this does no memory allocation of its own when Size != 0, and
23         does heap allocation when Size == 0. Thus you can have a fixed-size
24         low-overhead instance, or a heap oriented instance.
25 
26 ******************************************************************************/
27 
28 struct Stack (V, int Size = 0) 
29 {
30         alias nth              opIndex;
31         alias slice            opSlice;
32         
33         Stack* opOpAssign(immutable(char)[] s : ">>")(uint d)
34         {
35             return rotateRight(d);
36         }
37         
38         Stack* opOpAssign(immutable(char)[] s : "<<")(uint d)
39         {
40             return rotateLeft(d);
41         }
42         
43         Stack* opOpAssign(immutable(char)[] s : "~")(V value)
44         {
45             return push(value);
46         }
47         
48         static if (Size == 0)
49                   {
50                   private uint depth;
51                   private V[]  stack;
52                   }
53                else
54                   {
55                   private uint     depth;
56                   private V[Size]  stack;
57                   }
58 
59         /***********************************************************************
60 
61                 Clear the stack
62 
63         ***********************************************************************/
64 
65         Stack* clear ()
66         {
67                 depth = 0;
68                 return &this;
69         }
70 
71         /***********************************************************************
72                 
73                 Return depth of the stack
74 
75         ***********************************************************************/
76 
77         @property size_t size ()
78         {
79                 return depth;
80         }
81 
82         /***********************************************************************
83                 
84                 Return remaining unused slots
85 
86         ***********************************************************************/
87 
88         size_t unused ()
89         {
90                 return stack.length - depth;
91         }
92 
93         /***********************************************************************
94                 
95                 Returns a (shallow) clone of this stack, on the stack
96 
97         ***********************************************************************/
98 
99         Stack clone ()
100         {       
101                 Stack s = void;
102                 static if (Size == 0)
103                            s.stack.length = stack.length;
104                 s.stack[] = stack[];
105                 s.depth = depth;
106                 return s;
107         }
108 
109         /***********************************************************************
110                 
111                 Push and return a (shallow) copy of the topmost element
112 
113         ***********************************************************************/
114 
115         @property V dup ()
116         {
117                 auto v = top;
118                 push (v);       
119                 return v;
120         }
121 
122         /**********************************************************************
123 
124                 Push a value onto the stack.
125 
126                 Throws an exception when the stack is full
127 
128         **********************************************************************/
129 
130         Stack* push (V value)
131         {
132                 static if (Size == 0)
133                           {
134                           if (depth >= stack.length)
135                               stack.length = stack.length + 64;
136                           stack[depth++] = value;
137                           }
138                        else
139                           {                         
140                           if (depth < stack.length)
141                               stack[depth++] = value;
142                           else
143                              error (__LINE__);
144                           }
145                 return &this;
146         }
147 
148         /**********************************************************************
149 
150                 Push a series of values onto the stack.
151 
152                 Throws an exception when the stack is full
153 
154         **********************************************************************/
155 
156         Stack* append (V[] value...)
157         {
158                 foreach (v; value)
159                          push (v);
160                 return &this;
161         }
162 
163         /**********************************************************************
164 
165                 Remove and return the most recent addition to the stack.
166 
167                 Throws an exception when the stack is empty
168 
169         **********************************************************************/
170 
171         V pop ()
172         {
173                 if (depth)
174                     return stack[--depth];
175 
176                 return error (__LINE__);
177         }
178 
179         /**********************************************************************
180 
181                 Return the most recent addition to the stack.
182 
183                 Throws an exception when the stack is empty
184 
185         **********************************************************************/
186 
187         @property V top ()
188         {
189                 if (depth)
190                     return stack[depth-1];
191 
192                 return error (__LINE__);
193         }
194 
195         /**********************************************************************
196 
197                 Swaps the top two entries, and return the top
198 
199                 Throws an exception when the stack has insufficient entries
200 
201         **********************************************************************/
202 
203         V swap ()
204         {
205                 auto p = stack.ptr + depth;
206                 if ((p -= 2) >= stack.ptr)
207                    {
208                    auto v = p[0];
209                    p[0] = p[1];
210                    return p[1] = v; 
211                    }
212 
213                 return error (__LINE__);                
214         }
215 
216         /**********************************************************************
217 
218                 Index stack entries, where a zero index represents the
219                 newest stack entry (the top).
220 
221                 Throws an exception when the given index is out of range
222 
223         **********************************************************************/
224 
225         V nth (size_t i)
226         {
227                 if (i < depth)
228                     return stack [depth-i-1];
229 
230                 return error (__LINE__);
231         }
232 
233         /**********************************************************************
234 
235                 Rotate the given number of stack entries 
236 
237                 Throws an exception when the number is out of range
238 
239         **********************************************************************/
240 
241         Stack* rotateLeft (size_t d)
242         {
243                 if (d <= depth)
244                    {
245                    auto p = &stack[depth-d];
246                    auto t = *p;
247                    while (--d)
248                           *p++ = *(p+1);
249                    *p = t;
250                    }
251                 else
252                    error (__LINE__);
253                 return &this;
254         }
255 
256         /**********************************************************************
257 
258                 Rotate the given number of stack entries 
259 
260                 Throws an exception when the number is out of range
261 
262         **********************************************************************/
263 
264         Stack* rotateRight (size_t d)
265         {
266                 if (d <= depth)
267                    {
268                    auto p = &stack[depth-1];
269                    auto t = *p;
270                    while (--d)
271                           *p-- = *(p-1);
272                    *p = t;
273                    }
274                 else
275                    error (__LINE__);
276                 return &this;
277         }
278 
279         /**********************************************************************
280 
281                 Return the stack as an array of values, where the first
282                 array entry represents the oldest value. 
283                 
284                 Doing a foreach() on the returned array will traverse in
285                 the opposite direction of foreach() upon a stack
286                  
287         **********************************************************************/
288 
289         V[] slice ()
290         {
291                 return stack [0 .. depth];
292         }
293 
294         /**********************************************************************
295 
296                 Throw an exception 
297 
298         **********************************************************************/
299 
300         private V error (size_t line)
301         {
302                 throw new RangeError (__FILE__, line);
303         }
304 
305         /***********************************************************************
306 
307                 Iterate from the most recent to the oldest stack entries
308 
309         ***********************************************************************/
310 
311         int opApply (scope int delegate(ref V value) dg)
312         {
313                         int result;
314 
315                         for (int i=depth; i-- && result is 0;)
316                              result = dg (stack[i]);
317                         return result;
318         }
319 }
320 
321 
322 /*******************************************************************************
323 
324 *******************************************************************************/
325 
326 debug (Stack)
327 {
328         import tango.io.Stdout;
329 
330         void main()
331         {
332                 Stack!(int) v;
333                 v.push(1);
334                 
335                 Stack!(int, 10) s;
336 
337                 Stdout.formatln ("push four");
338                 s.push (1);
339                 s.push (2);
340                 s.push (3);
341                 s.push (4);
342                 foreach (v; s)
343                          Stdout.formatln ("{}", v);
344                 s <<= 4;
345                 s >>= 4;
346                 foreach (v; s)
347                          Stdout.formatln ("{}", v);
348 
349                 s = s.clone;
350                 Stdout.formatln ("pop one: {}", s.pop);
351                 foreach (v; s)
352                          Stdout.formatln ("{}", v);
353                 Stdout.formatln ("top: {}", s.top);
354 
355                 Stdout.formatln ("pop three");
356                 s.pop;
357                 s.pop;
358                 s.pop;
359                 foreach (v; s)
360                          Stdout.formatln ("> {}", v);
361         }
362 }
363