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);
}
}
|