| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 | /******************************************************************************* copyright: Copyright (c) 2008 Kris Bell. All rights reserved license: BSD style: $(LICENSE) version: Initial release: April 2008 author: Kris Since: 0.99.7 *******************************************************************************/ module tango.util.container.more.Stack; private import tango.core.Exception : RangeError; /****************************************************************************** A stack of the given value-type V, with maximum depth Size. Note that this does no memory allocation of its own when Size != 0, and does heap allocation when Size == 0. Thus you can have a fixed-size low-overhead instance, or a heap oriented instance. ******************************************************************************/ struct Stack (V, int Size = 0) { alias nth opIndex; alias slice opSlice; Stack* opOpAssign(immutable(char)[] s : ">>")(uint d) { return rotateRight(d); } Stack* opOpAssign(immutable(char)[] s : "<<")(uint d) { return rotateLeft(d); } Stack* opOpAssign(immutable(char)[] s : "~")(V value) { return push(value); } static if (Size == 0) { private uint depth; private V[] stack; } else { private uint depth; private V[Size] stack; } /*********************************************************************** Clear the stack ***********************************************************************/ Stack* clear () { depth = 0; return &this; } /*********************************************************************** Return depth of the stack ***********************************************************************/ @property size_t size () { return depth; } /*********************************************************************** Return remaining unused slots ***********************************************************************/ size_t unused () { return stack.length - depth; } /*********************************************************************** Returns a (shallow) clone of this stack, on the stack ***********************************************************************/ Stack clone () { Stack s = void; static if (Size == 0) s.stack.length = stack.length; s.stack[] = stack; s.depth = depth; return s; } /*********************************************************************** Push and return a (shallow) copy of the topmost element ***********************************************************************/ @property V dup () { auto v = top; push (v); return v; } /********************************************************************** Push a value onto the stack. Throws an exception when the stack is full **********************************************************************/ Stack* push (V value) { static if (Size == 0) { if (depth >= stack.length) stack.length = stack.length + 64; stack[depth++] = value; } else { if (depth < stack.length) stack[depth++] = value; else error (__LINE__); } return &this; } /********************************************************************** Push a series of values onto the stack. Throws an exception when the stack is full **********************************************************************/ Stack* append (V[] value...) { foreach (v; value) push (v); return &this; } /********************************************************************** Remove and return the most recent addition to the stack. Throws an exception when the stack is empty **********************************************************************/ V pop () { if (depth) return stack[--depth]; return error (__LINE__); } /********************************************************************** Return the most recent addition to the stack. Throws an exception when the stack is empty **********************************************************************/ @property V top () { if (depth) return stack[depth-1]; return error (__LINE__); } /********************************************************************** Swaps the top two entries, and return the top Throws an exception when the stack has insufficient entries **********************************************************************/ V swap () { auto p = stack.ptr + depth; if ((p -= 2) >= stack.ptr) { auto v = p[0]; p[0] = p[1]; return p[1] = v; } return error (__LINE__); } /********************************************************************** Index stack entries, where a zero index represents the newest stack entry (the top). Throws an exception when the given index is out of range **********************************************************************/ V nth (size_t i) { if (i < depth) return stack [depth-i-1]; return error (__LINE__); } /********************************************************************** Rotate the given number of stack entries Throws an exception when the number is out of range **********************************************************************/ Stack* rotateLeft (size_t d) { if (d <= depth) { auto p = &stack[depth-d]; auto t = *p; while (--d) *p++ = *(p+1); *p = t; } else error (__LINE__); return &this; } /********************************************************************** Rotate the given number of stack entries Throws an exception when the number is out of range **********************************************************************/ Stack* rotateRight (size_t d) { if (d <= depth) { auto p = &stack[depth-1]; auto t = *p; while (--d) *p-- = *(p-1); *p = t; } else error (__LINE__); return &this; } /********************************************************************** Return the stack as an array of values, where the first array entry represents the oldest value. Doing a foreach() on the returned array will traverse in the opposite direction of foreach() upon a stack **********************************************************************/ V[] slice () { return stack [0 .. depth]; } /********************************************************************** Throw an exception **********************************************************************/ private V error (size_t line) { throw new RangeError (__FILE__, line); } /*********************************************************************** Iterate from the most recent to the oldest stack entries ***********************************************************************/ int opApply (scope int delegate(ref V value) dg) { int result; for (int i=depth; i-- && result is 0;) result = dg (stack[i]); return result; } } /******************************************************************************* *******************************************************************************/ debug (Stack) { import tango.io.Stdout; void main() { Stack!(int) v; v.push(1); Stack!(int, 10) s; Stdout.formatln ("push four"); s.push (1); s.push (2); s.push (3); s.push (4); foreach (v; s) Stdout.formatln ("{}", v); s <<= 4; s >>= 4; foreach (v; s) Stdout.formatln ("{}", v); s = s.clone; Stdout.formatln ("pop one: {}", s.pop); foreach (v; s) Stdout.formatln ("{}", v); Stdout.formatln ("top: {}", s.top); Stdout.formatln ("pop three"); s.pop; s.pop; s.pop; foreach (v; s) Stdout.formatln ("> {}", v); } } |