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