| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 | /******************************************************************************* 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.Vector; private import tango.core.Exception : RangeError; private import tango.stdc.string : memmove; /****************************************************************************** A vector 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 Vector (V, int Size = 0) { alias add push; alias slice opSlice; Vector* opOpAssign(immutable(char)[] s : "~")(V value) { return push(value); } static if (Size == 0) { private size_t depth; private V[] vector; } else { private size_t depth; private V[Size] vector; } /*********************************************************************** Clear the vector ***********************************************************************/ Vector* clear () { depth = 0; return &this; } /*********************************************************************** Return depth of the vector ***********************************************************************/ @property const size_t size () { return depth; } /*********************************************************************** Return remaining unused slots ***********************************************************************/ const size_t unused () { return vector.length - depth; } /*********************************************************************** Returns a (shallow) clone of this vector ***********************************************************************/ Vector clone () { Vector v; static if (Size == 0) v.vector.length = vector.length; v.vector[0..depth] = vector[0..depth]; v.depth = depth; return v; } /********************************************************************** Add a value to the vector. Throws an exception when the vector is full **********************************************************************/ V* add (V value) { static if (Size == 0) { if (depth >= vector.length) vector.length = vector.length + 64; vector[depth++] = value; } else { if (depth < vector.length) vector[depth++] = value; else error (__LINE__); } return &vector[depth-1]; } /********************************************************************** Add a value to the vector. Throws an exception when the vector is full **********************************************************************/ V* add () { static if (Size == 0) { if (depth >= vector.length) vector.length = vector.length + 64; } else if (depth >= vector.length) error (__LINE__); auto p = &vector[depth++]; *p = V.init; return p; } /********************************************************************** Add a series of values to the vector. Throws an exception when the vector is full **********************************************************************/ Vector* append (V[] value...) { foreach (v; value) add (v); return &this; } /********************************************************************** Remove and return the most recent addition to the vector. Throws an exception when the vector is empty **********************************************************************/ V remove () { if (depth) return vector[--depth]; return error (__LINE__); } /********************************************************************** Index vector entries, where a zero index represents the oldest vector entry. Throws an exception when the given index is out of range **********************************************************************/ V remove (size_t i) { if (i < depth) { if (i is depth-1) return remove; --depth; auto v = vector [i]; memmove (vector.ptr+i, vector.ptr+i+1, V.sizeof * (depth-i)); return v; } return error (__LINE__); } /********************************************************************** Index vector entries, as though it were an array Throws an exception when the given index is out of range **********************************************************************/ V opIndex (size_t i) { if (i < depth) return vector [i]; return error (__LINE__); } /********************************************************************** Assign vector entries as though it were an array. Throws an exception when the given index is out of range **********************************************************************/ V opIndexAssign (V value, size_t i) { if (i < depth) { vector[i] = value; return value; } return error (__LINE__); } /********************************************************************** Return the vector 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 vector **********************************************************************/ V[] slice () { return vector [0 .. depth]; } /********************************************************************** Throw an exception **********************************************************************/ private V error (size_t line) { throw new RangeError (__FILE__, line); } /*********************************************************************** Iterate from the most recent to the oldest vector entries ***********************************************************************/ int opApply (scope int delegate(ref V value) dg) { int result; for (int i=depth; i-- && result is 0;) result = dg (vector [i]); return result; } /*********************************************************************** Iterate from the most recent to the oldest vector entries ***********************************************************************/ int opApply (scope int delegate(ref V value, ref bool kill) dg) { int result; for (int i=depth; i-- && result is 0;) { auto kill = false; result = dg (vector[i], kill); if (kill) remove (i); } return result; } } /******************************************************************************* *******************************************************************************/ debug (Vector) { import tango.io.Stdout; void main() { Vector!(int, 0) v; v.add (1); Vector!(int, 10) s; Stdout.formatln ("add four"); s.add (1); s.add (2); s.add (3); s.add (4); foreach (v; s) Stdout.formatln ("{}", v); s = s.clone; Stdout.formatln ("pop one: {}", s.remove); foreach (v; s) Stdout.formatln ("{}", v); Stdout.formatln ("remove[1]: {}", s.remove(1)); foreach (v; s) Stdout.formatln ("{}", v); Stdout.formatln ("remove two"); s.remove; s.remove; foreach (v; s) Stdout.formatln ("> {}", v); s.add (1); s.add (2); s.add (3); s.add (4); foreach (v, ref k; s) k = true; Stdout.formatln ("size {}", s.size); } } |