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