problem with opIndex

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Sep 29 20:16:35 UTC 2017


On Fri, Sep 29, 2017 at 07:31:14PM +0000, Joseph via Digitalmars-d-learn wrote:
> 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.
[...]

I've done this before.

Basically, there are a few things you need to do:

1) Determine the type of the result.  Presumably, you'll want to return
the same Matrix / Array type that you started with, only with a
different dimensionality, depending on how many slicing arguments you
get. To do that, you need to know:

	a) How many of your arguments are slices
	b) How many are single indices.

You can use a foreach loop with static if, or an analogous template, to
count the number of slices.  I'd go with the template solution, to
ensure you don't incur unnecessary runtime overhead if you have a poor
optimizer.  Something like this, perhaps:

	template numSlices(Args...)
		if (Args.length > 0)
	{
		static if (Args.length == 1) {
			enum numSlices = is(Args[0] == int[2]) ? 1 : 0;
		else
			enum numSlices = (is(Args[0] == int[2]) ? 1 : 0)
				+ numSlices!(Args[1 .. $]);
	}

Then you'd construct a type of the same dimensionality as numSlices!Args
as the receiving object.

2) Loop over the arguments and compute the stride information for each.
(Presumably, you're constructing a slice over the original data; if
you're copying the data then of course you'll do something else.)
Basically something like this:

	foreach (arg; args) {
		static if (is(typeof(arg == int[2]))) {
			... // compute stride corresponding to the range
		} else {
			... // compute start offset of subdimensional slice
		}
	}


T

-- 
Don't drink and derive. Alcohol and algebra don't mix.


More information about the Digitalmars-d-learn mailing list