Functions and types that manipulate multidimensional rectangular arrays.

Authors
Denis Shelomovskij

### struct MultidimArray(T, size_t n) if (n >= 1);

Implements multidimensional rectangular arrays.

Something like FORTRAN's one.

Examples
```// Let's creates an GC allocated three-dimensional rectangular array from 2 matrices 3x4
auto matrices = multidimArray!int(2, 3, 4); // matrices has a type MultidimArray!(int, 3)

// Setting an element at intersection of the first column and
// the third row of the secon matrix to seven:
matrices[1, 0, 2] = 7;

// Filling the whole first column of the secon matrix with sixes:
matrices[1, 0, 0..\$][] = 6;

// Filling the whole array with fives:
matrices[] = 5;

// Iterating the array
foreach(z, y, x, ref el; matrices) // using opApply
el = cast(int) (z * 100 + y * 10 + x);

int c = 0;
foreach(ref el; matrices.byElementForward)
el = c++;

c = 0;
foreach(i; 0 .. matrices.elements)
matrices.byElementRandomAccess[i] = c++;

c = 0;
foreach(matrix; matrices.byTopDimension)       // for each of two matrices
foreach(row; matrix.byTopDimension)        // for each row
foreach(ref el; row.byTopDimension) // for each element
el = c++;

c = 0;
foreach_reverse(ref el; matrices.byElementRandomAccess)
el = c++;

c = 0;
foreach_reverse(i; 0 .. matrices.elements)
matrices.byElementRandomAccess[i] = c++;

// Inexing/slicing
// * use <integer> to select a position
// * use <integer> .. <integer> to select a range
// E.g. use 0..\$  to select the whole range
matrices = matrices[0..\$, 0..\$, 0..\$];  // the entire array, same as [0..2, 0..3, 0..4]
auto array2d = matrices[0, 0..\$, 0..\$]; // the first matrix
auto array1d = matrices[0, 1, 0..\$];  // the second row of the first matrix
array1d = matrices[0, 0..\$, 1];       // the second column of the first matrix
matrices[0, 1, 1] = 9;                // setting an element at a crossing of the row an the column

// first two rows and three columns of the secon matrix
array2d = matrices[1, 0 .. 2, 0 .. 3];
```

### alias dimensions = n;

Dimensions of this array.

### const pure nothrow @safe const(size_t)[n] lengths();

Returns the read only view at its  lengths array.

### const pure nothrow @safe size_t elements();

Returns the  elements count of the array.

### const pure nothrow @safe size_t packedDimensions();

Returns the maximum number of tail dimensions without pading. Note, that there can be no such dimensions.

### pure nothrow @property @safe auto byElementForward();

Returns a forward range which has mutable elements and a length for iteration by an element.

### pure nothrow @property @safe auto byElementRandomAccess();

Returns a finite random-access range which has mutable elements and a length for iteration by an element.

### pure nothrow @property @safe auto byTopDimension();

Returns a finite random-access range for iteration over the top dimension.

It has mutable elements iff dimensions is 1.

### @property auto byFunction(string pred)();

Returns a forward range which has mutable elements for iteration using indices defined by pred starting from a = 0 and incrementing it while indices are in valid range.

Example:
```auto matrix = multidimArray!char(30, 20);
matrix[] = ' ';

foreach(ref el; matrix.byFunction!`a, a`) // fills a diagonal
el = 'X';

foreach(ref el; matrix.byFunction!`a^^2 / 5, a`()) // fills a parabola points
el = 'Y';

import std.stdio;
writeln(matrix);
```

### int opApply(int delegate(RepeatTuple!(n, size_t), ref T) dg);

Implements by-element iteration with inidces starting from the top dimension.

Example:
```auto matrix = multidimArray!int(2, 3, 4);
foreach(z, y, x, ref el; matrices)
el = z * 100 + y * 10 + x;
```

### MultidimArray opSliceAssign(T value); MultidimArray opSliceAssign(Range)(Range value) if (isInputRange!Range && isAssignable!(T, ElementType!Range)); MultidimArray opSliceAssign(U)(MultidimArray!(U, n) value) if (isAssignable!(T, U));

Implements elements initialisation with a value, where value can be of type T or an input range which front can be assigned to an element. The range should contain exectly elements elements, otherwise an Exception will be thrown.

Returns
If value is of type T or a forward range, returns value. Otherwise (value is an input range but not a forward range) returns void.
Example:
```auto a23 = multidimArray!int(2, 3);
auto a46 = multidimArray!int(4, 6);
auto a234 = multidimArray!int(2, 3, 4);

a23[] = a234[] = 7;
a23[] = take(a46[] = a234[] = iota(24), 6);
```

### @property auto dup(); @property auto idup();

Support for and idup properties for MultidimArray.

### inout pure nothrow ref @safe auto opIndex(in size_t[n] indices...); inout pure nothrow @trusted auto opIndex(A...)(A args) if (args.length == n && allTuple!(isROrSize, A) && RCount!A); auto opIndexAssign(U, A...)(U value, A args) if (args.length == n && allTuple!(isROrSize, A));

Inexing/slicing.

A parameter can be:

type meaning effect on a resulting dimensions
n a position -1
m .. n a range 0

Examples
See MultidimArray examples.
Known Bugs
A bit ugly syntax is used because dmd hasn't support for a better one yet (see D Bugzilla 6798).

### pure @safe auto reorderIndices(in size_t[n] newOrder...);

Creates a slice of this entire array with reordered indices. newOrder[i] = n means that i-th index of a resulting array will behave like n-th index of the original array. Every index sould be used once, otherwise an Exception will be thrown.

Example:
```auto matrix3x4 = multidimArray!int(3, 4);
auto transposed = matrix3x4.reorderIndices(1, 0);
assert(transposed.lengths == [4, 3]);
assert(&matrix3x4[2, 3] == &transposed[3, 2]);
```
Example:
```auto a = multidimArray!int(2, 3, 4);
auto b = a.reorderIndices(2, 0, 1);
assert(b.lengths == [4, 2, 3]);
assert(&a[1, 2, 3] == &b[3, 1, 2]);
```

### string toString();

Conversion to string function for debugging purposes.

Implemented for dimensions <= 3.

### pure nothrow @safe auto multidimArray(T, size_t n)(size_t[n] lengths...) if (n > 0); pure nothrow @safe auto multidimArray(size_t n, T)(T[] data, size_t[n] lengths...) if (n > 0); pure nothrow auto multidimArray(size_t n, A)(ref A array) if (n > 0 && n <= staticArrayDims!A); pure nothrow auto multidimArray(A)(ref A array) if (isStaticArray!A); pure nothrow @safe auto multidimArray(size_t n, A)(A array) if (isDynamicArray!A && n > 0 && n - 1 <= staticArrayDims!(ElementType!A)); pure nothrow @safe auto multidimArray(A)(A array) if (isDynamicArray!A);

Convenience function that returns an MultidimArray!(T, n) object.

Returns
The first overload returns a MultidimArray with a newly allocated data Others use an existing storage.
Parameters
 data A memory storage for a resulting array of type T[]. array An array to wrap. It can be a multidimensional static array or a slice of it (has a dynamic top dimension). size_t[n] lengths Lengths of a resulting array.
Template parameters:
T Element type of a resulting array. Should be explicitly defined only for the first overload which has no memory storage.

n Dimensions of a resulting array. Can be explicitly defined to use only first n of array dimensions.

A Type of a wrapping array. It is inferred from the array argument and should not be explicitly defined.
MultidimArray
Throws
The first overload throws an RangeError in debug build if data length isn't equal to lengths prouct.
Examples
```// Let's create an GC allocated three-dimensional rectangular array from 2 matrices 3x4
auto matrix1 = multidimArray!int(2, 3, 4);

// Let's create the same array using an existing storage
auto darr2 = new int[24]; // At least 24 elements are needed
auto matrix2 = multidimArray(darr2, 2, 3, 4); // No need for explicit element type declaration

// Let's create the same array using an existing static array as data storage
int[4][3][2] sarr3; // or in a postfix form: int sarr[2][3][4];
auto matrix3 = multidimArray(sarr3); // No need for any explicit template declarations

// The head array can be dynamic
int[4][3][] darr3 = sarr3[];
auto matrix31 = multidimArray(darr3); // Works like previous one

// Let's create an array of static arrays
ubyte[4][4][3][2] sarr4; // a postfix form: ubyte[4] sarr[2][3][4];
auto matrix4 = multidimArray!3(sarr4); // Only 3 major of 4 dimensions are indeces

// The head array can also be dynamic
auto matrix41 = multidimArray!3(sarr4[]); // Works like previous one
```