problem with opIndex
Joseph
JE342 at gmail.com
Fri Sep 29 19:31:14 UTC 2017
I am trying to have a multi-dimensional array and opIndex has to
have both an arbitrary number of parameters and allow for slicing.
The problem is if I create opIndex for non-slicing, it looks like
ref auto opIndex(T...)(T index)
and this one catches all templates. But slices do not return the
same value. I need to somehow have two opIndex's, one for slice
handling and one for non-slices.
Trying to accomplish
arr[1..4, 5..8, 3, 3..4]
I already have the single index case arr[3, 4, 3, 1]
and the only difference is that for a slice, the indices are
int[2]'s.
To make this work, I need to somehow know if any of the
parameters is a slice or not.
Heres what I've got so far:
struct sMArray(F)
{
import std.traits, std.meta, core.stdc.stdlib;
size_t[] dimensions; // The dimensions of the multi-array
size_t[] offset; // The offset of the multi-array(for slices)
void[] data; // An array of the actual element data in bytes
void[] parent; // The parent array or slice, if null, no
parent.
this(T...)(T args) // Give the dimensions with one
element(first or last) being a flag array to initialize with
{
static if (isArray!(T[0]))
{
auto dat = T[0];
dimensions = args[1..$];
enum start = 1;
enum end = T.length;
} else
{
static if (isArray!(T[$-1]))
{
auto dat = T[$-1];
enum start = 0;
enum end = T.length-1;
} else
{
int[] dat = null;
enum start = 0;
enum end = T.length;
}
}
foreach(a; args[start..end])
dimensions ~= a;
int totalSize = 1;
foreach(d; dimensions)
totalSize *= d;
data = malloc(totalSize*F.sizeof)[0..totalSize*F.sizeof];
if (dat != null)
for(int i = 0; i < dat.length; i++)
(cast(typeof(dat))data)[i] = dat[i];
}
ref auto opIndex()
{
return data;
}
// Index a single element, e.g., data[0, 1] or takes a
slice/view of the array and returns that as another sMArray
ref auto opIndex(T...)(T idx)
{
if (T.length != dimensions.length) assert(0, "sMArray invalid
indexing!");
size_t i = 0;
static foreach(k, t; T)
{
static if (k == 0)
i = idx[0];
else
i += idx[k]*dimensions[k-1];
}
debug { if (i >= data.length) assert(0, "sMArray invalid index!
Too Large."); }
return (cast(F[])data)[i];
}
// Support for `x..y` notation in slicing operator for the given
dimension.
size_t opSlice(size_t dim)(size_t start, size_t end)
in { assert(start >= 0 && end <= this.opDollar!dim); }
body
{
return [start, end];
}
size_t GetDim(int i)
{
return dimensions[i];
}
// Support `$` in slicing notation, e.g., arr[1..$, 0..$-1].
@property size_t opDollar(size_t dim)() { return
dimensions[dim]; }
~this()
{
free(data.ptr);
}
}
More information about the Digitalmars-d-learn
mailing list