Report a bug
If you spot a problem with this page, click here to create a Github issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

mir.ndslice.slice

This is a submodule of mir.ndslice.
Authors:
Ilya Yaroshenko

Definitions

Name Description
Slice N-dimensional slice.
SliceKind Kind of Slice enumeration.
Universal Alias for .SliceKind.universal.
Canonical Alias for .SliceKind.canonical.
Contiguous Alias for .SliceKind.contiguous.
sliced Creates a slice on top of an iterator, a pointer, or an array's pointer.
slicedField Creates a slice on top of a field, a random access range, or an array.
slicedNdField Creates a slice on top of an ndField.
kindOf Extracts SliceKind.
isSlice Extracts dimension packs from a type. Extracts null if the template argument is not a Slice.
DeepElementType Extracts the element type of a Slice.
Structure A tuple of lengths and strides.
template isSlice(T)
Examples:
alias A = uint[];
alias S = Slice!(Universal, [2, 3], int*);

static assert(isSlice!S);
static assert(!isSlice!A);

static assert(isSlice!S == [2, 3]);
static assert(isSlice!A == null);
enum SliceKind: int;
Kind of Slice.
universal
A slice has strides for all dimensions.
canonical
A slice has >=2 dimensions and row dimension is contiguous.
contiguous
A slice is a flat contiguous data without strides.
alias Universal = SliceKind.universal;
alias Canonical = SliceKind.canonical;
alias Contiguous = SliceKind.contiguous;
enum auto kindOf(T : Slice!(kind, packs, Iterator), SliceKind kind, size_t[] packs, Iterator);
Extracts SliceKind.
Examples:
static assert(kindOf!(Slice!(Canonical, [1], int*)) == Canonical);
auto sliced(size_t N, Iterator)(Iterator iterator, size_t[N] lengths...)
if (!isStaticArray!Iterator && !isNarrowString!Iterator && N && !is(Iterator : Slice!(kind, packs, _Iterator), SliceKind kind, size_t[] packs, _Iterator));
Creates an n-dimensional slice-shell over an iterator.
Parameters:
Iterator iterator An iterator, a pointer, or an array.
size_t[N] lengths A list of lengths for each dimension
Returns:
n-dimensional slice
Examples:
Vandermonde matrix
auto vandermondeMatrix(Slice!(Universal, [1], double*) x)
{
    import mir.ndslice.allocation: slice;
    auto ret = slice!double(x.length, x.length);
    foreach (i; 0 .. x.length)
    foreach (j; 0 .. x.length)
        ret[i, j] = x[i] ^^ j;
    return ret;
}

import mir.ndslice.topology: universal;
auto x = [1.0, 2, 3, 4, 5].sliced.universal;
auto v = vandermondeMatrix(x);
assert(v ==
    [[  1.0,   1,   1,   1,   1],
     [  1.0,   2,   4,   8,  16],
     [  1.0,   3,   9,  27,  81],
     [  1.0,   4,  16,  64, 256],
     [  1.0,   5,  25, 125, 625]]);
Examples:
Random access range primitives for slices over user defined types
struct MyIota
{
    //`[index]` operator overloading
    auto opIndex(size_t index)
    {
        return index;
    }
}
import mir.ndslice.iterator: FieldIterator;
alias Iterator = FieldIterator!MyIota;
alias S = Slice!(Contiguous, [2], Iterator);
import std.range.primitives;
static assert(hasLength!S);
static assert(hasSlicing!S);
static assert(isRandomAccessRange!S);

auto slice = Iterator().sliced(20, 10);
assert(slice[1, 2] == 12);
auto sCopy = slice.save;
assert(slice[1, 2] == 12);
auto sliced(T)(T[] array);
Creates an 1-dimensional slice-shell over an array.
Parameters:
T[] array An array.
Returns:
1-dimensional slice
Examples:
Creates a slice from an array.
auto slice = new int[10].sliced;
assert(slice.length == 10);
static assert(is(typeof(slice) == Slice!(Contiguous, [1], int*)));
Slice!(kind, N ~ (packs[0] == 1 ? [] : [packs[0] - 1]) ~ packs[1..$], Iterator) sliced(SliceKind kind, size_t[] packs, Iterator, size_t N)(Slice!(kind, packs, Iterator) slice, size_t[N] lengths...)
if (N);
Creates an n-dimensional slice-shell over an iterator.
Parameters:
Slice!(kind, packs, Iterator) slice A slice, a pointer, or an array.
size_t[N] lengths A list of lengths for each dimension.
Returns:
n-dimensional slice
Examples:
import mir.ndslice.topology : iota;
auto data = new int[24];
foreach (int i,ref e; data)
    e = i;
auto a = data[0..10].sliced(10)[0..6].sliced(2, 3);
auto b = iota!int(10)[0..6].sliced(2, 3);
assert(a == b);
a[] += b;
foreach (int i, e; data[0..6])
    assert(e == 2*i);
foreach (int i, e; data[6..$])
    assert(e == i+6);
auto c  = data.sliced(12, 2)[0..6].sliced(2, 3);
auto d  = iota(12, 2)[0..6].sliced(2, 3);
auto cc = data[0..12].sliced(2, 3, 2);
auto dc = iota(2, 3, 2);
assert(c._lengths == cc._lengths);
assert(c._strides == cc._strides);
assert(d._lengths == dc._lengths);
assert(d._strides == dc._strides);
assert(cc == c);
assert(dc == d);
auto e = data.sliced(8, 3)[0..5].sliced(5);
auto f = iota(8, 3)[0..5].sliced(5);
assert(e == data[0..15].sliced(5, 3));
assert(f == iota(5, 3));
Slice!(Contiguous, [N], FieldIterator!Field) slicedField(Field, size_t N)(Field field, size_t[N] lengths...)
if (N);

auto slicedField(Field)(Field field)
if (hasLength!Field);
Creates an n-dimensional slice-shell over a field.
Parameters:
Field field A field. The length of the array should be equal to or less then the product of lengths.
size_t[N] lengths A list of lengths for each dimension.
Returns:
n-dimensional slice
Examples:
Creates an 1-dimensional slice over a field, array, or random access range.
import mir.ndslice.topology : iota;
auto slice = 10.iota.slicedField;
assert(slice.length == 10);
Slice!(Contiguous, [N], IndexIterator!(FieldIterator!(ndIotaField!N), ndField)) slicedNdField(ndField, size_t N)(ndField field, size_t[N] lengths...)
if (N);

auto slicedNdField(ndField)(ndField field)
if (hasShape!ndField);
Creates an n-dimensional slice-shell over an ndField.
Parameters:
ndField field A ndField. Lengths should fit into field's shape.
size_t[N] lengths A list of lengths for each dimension.
Returns:
n-dimensional slice
See Also:
stack  examples.
template DeepElementType(S : Slice!(kind, packs, Iterator), SliceKind kind, size_t[] packs, Iterator)

template DeepElementType(S : Stack!(dim, Slices), size_t dim, Slices...)
Returns the element type of a Slice.
Examples:
import mir.ndslice.topology : iota;
static assert(is(DeepElementType!(Slice!(Universal, [4], const(int)[]))     == const(int)));
static assert(is(DeepElementType!(Slice!(Universal, [4], immutable(int)*))  == immutable(int)));
struct Structure(size_t N);
size_t[N] lengths;
sizediff_t[N] strides;
struct Slice(SliceKind kind, size_t[] packs, Iterator) if (packs.sum < 255);
Presents an n-dimensional view over a range.

Definitions

In order to change data in a slice using overloaded operators such as =, +=, ++, a syntactic structure of type <slice to change>[<index and interval sequence...>] must be used. It is worth noting that just like for regular arrays, operations a = b and a[] = b have different meanings. In the first case, after the operation is carried out, a simply points at the same data as b does, and the data which a previously pointed at remains unmodified. Here, а and b must be of the same type. In the second case, a points at the same data as before, but the data itself will be changed. In this instance, the number of dimensions of b may be less than the number of dimensions of а; and b can be a Slice, a regular multidimensional array, or simply a value (e.g. a number).
In the following table you will find the definitions you might come across in comments on operator overloading.
Definition Examples at N == 3
An interval is a part of a sequence of type i .. j. 2..$-3, 0..4
An index is a part of a sequence of type i. 3, $-1
A partially defined slice is a sequence composed of intervals and indexes with an overall length strictly less than N. [3], [0..$], [3, 3], [0..$,0..3], [0..$,2]
A fully defined index is a sequence composed only of indexes with an overall length equal to N. [2,3,1]
A fully defined slice is an empty sequence or a sequence composed of indexes and at least one interval with an overall length equal to N. [], [3..$,0..3,0..$-1], [2,0..$,1]

Internal Binary Representation

Multidimensional Slice is a structure that consists of lengths, strides, and a pointer. For ranges, a shell is used instead of a pointer. This shell contains a shift of the current initial element of a multidimensional slice and the range itself. With the exception of overloaded operators, no functions in this package change or copy data. The operations are only carried out on lengths, strides, and pointers. If a slice is defined over a range, only the shift of the initial element changes instead of the pointer.

Internal Representation for Universal Slices

Type definition
Slice!(Universal, [N], Iterator)
Schema
Slice!(Universal, [N], Iterator)
    size_t[N]     _lengths
    sizediff_t[N] _strides
    Iterator      _iterator

Example: Definitions

import mir.ndslice;
auto a = new double[24];
Slice!(Universal, [3], double*) s = a.sliced(2, 3, 4).universal;
Slice!(Universal, [3], double*) t = s.transposed!(1, 2, 0);
Slice!(Universal, [3], double*) r = t.reversed!1;
Representation
s________________________
    lengths[0] ::=  2
    lengths[1] ::=  3
    lengths[2] ::=  4

    strides[0] ::= 12
    strides[1] ::=  4
    strides[2] ::=  1

    iterator        ::= &a[0]

t____transposed!(1, 2, 0)
    lengths[0] ::=  3
    lengths[1] ::=  4
    lengths[2] ::=  2

    strides[0] ::=  4
    strides[1] ::=  1
    strides[2] ::= 12

    iterator        ::= &a[0]

r______________reversed!1
    lengths[0] ::=  2
    lengths[1] ::=  3
    lengths[2] ::=  4

    strides[0] ::= 12
    strides[1] ::= -4
    strides[2] ::=  1

    iterator        ::= &a[8] // (old_strides[1] * (lengths[1] - 1)) = 8

Internal Representation for Canonical Slices

Type definition
Slice!(Canonical, [N], Iterator)
Schema
Slice!(Universal, [N], Iterator)
    size_t[N]       _lengths
    sizediff_t[N-1] _strides
    Iterator        _iterator

Internal Representation for Contiguous Slices

Type definition
Slice!(Contiguous, [N], Iterator)
Schema
Slice!(Universal, [N], Iterator)
    size_t[N]     _lengths
    sizediff_t[0] _strides
    Iterator      _iterator

Examples:
Slicing, indexing, and arithmetic operations.
import mir.ndslice.allocation;
import mir.ndslice.dynamic : transposed;
import mir.ndslice.topology : iota, universal;
auto tensor = iota(3, 4, 5).slice;

assert(tensor[1, 2] == tensor[1][2]);
assert(tensor[1, 2, 3] == tensor[1][2][3]);

assert( tensor[0..$, 0..$, 4] == tensor.universal.transposed!2[4]);
assert(&tensor[0..$, 0..$, 4][1, 2] is &tensor[1, 2, 4]);

tensor[1, 2, 3]++; //`opIndex` returns value by reference.
--tensor[1, 2, 3]; //`opUnary`

++tensor[];
tensor[] -= 1;

// `opIndexAssing` accepts only fully defined indexes and slices.
// Use an additional empty slice `[]`.
static assert(!__traits(compiles, tensor[0 .. 2] *= 2));

tensor[0 .. 2][] *= 2;          //OK, empty slice
tensor[0 .. 2, 3, 0..$] /= 2; //OK, 3 index or slice positions are defined.

//fully defined index may be replaced by a static array
size_t[3] index = [1, 2, 3];
assert(tensor[index] == tensor[1, 2, 3]);
Examples:
Operations with rvalue slices.
import mir.ndslice.allocation;
import mir.ndslice.topology: universal;
import mir.ndslice.dynamic: transposed, everted;

auto tensor = slice!int(3, 4, 5).universal;
auto matrix = slice!int(3, 4).universal;
auto vector = slice!int(3);

foreach (i; 0..3)
    vector[i] = i;

// fills matrix columns
matrix.transposed[] = vector;

// fills tensor with vector
// transposed tensor shape is (4, 5, 3)
//            vector shape is (      3)
tensor.transposed!(1, 2)[] = vector;


// transposed tensor shape is (5, 3, 4)
//            matrix shape is (   3, 4)
tensor.transposed!2[] += matrix;

// transposed tensor shape is (5, 4, 3)
// transposed matrix shape is (   4, 3)
tensor.everted[] ^= matrix.transposed; // XOR
Examples:
Creating a slice from text. See also std.format.
import mir.ndslice.allocation;
import std.algorithm,  std.conv, std.exception, std.format,
    std.functional, std.string, std.range;

Slice!(Contiguous, [2], int*) toMatrix(string str)
{
    string[][] data = str.lineSplitter.filter!(not!empty).map!split.array;

    size_t rows    = data   .length.enforce("empty input");
    size_t columns = data[0].length.enforce("empty first row");

    data.each!(a => enforce(a.length == columns, "rows have different lengths"));
    auto slice = slice!int(rows, columns);
    foreach (i, line; data)
        foreach (j, num; line)
            slice[i, j] = num.to!int;
    return slice;
}

auto input = "\r1 2  3\r\n 4 5 6\n";

auto matrix = toMatrix(input);
assert(matrix == [[1, 2, 3], [4, 5, 6]]);

// back to text
auto text2 = format("%(%(%s %)\n%)\n", matrix);
assert(text2 == "1 2 3\n4 5 6\n");
enum auto N;
enum auto S;
alias This = Slice!(kind, packs, Iterator);
alias PureThis = Slice!(kind, [N], Iterator);
size_t[N] _lengths;
ptrdiff_t[S] _strides;
Iterator _iterator;
this()(in size_t[N] lengths, in sizediff_t[S] strides, Iterator iterator);
This constructor should be used only for integration with other languages or libraries such as Julia and numpy.
Parameters:
size_t[N] lengths lengths
sizediff_t[S] strides strides
Iterator iterator an iterator or a pointer to iterate on
Examples:
Creates a 2-dimentional slice with custom strides.
uint[8] array = [1, 2, 3, 4, 5, 6, 7, 8];
auto slice = Slice!(Universal, [2], uint*)([2, 2], [4, 1], array.ptr);

assert(&slice[0, 0] == &array[0]);
assert(&slice[0, 1] == &array[1]);
assert(&slice[1, 0] == &array[4]);
assert(&slice[1, 1] == &array[5]);
assert(slice == [[1, 2], [5, 6]]);

array[2] = 42;
assert(slice == [[1, 2], [5, 6]]);

array[1] = 99;
assert(slice == [[1, 99], [5, 6]]);
const pure nothrow @nogc ref @trusted ConstThis toConst();
Implicit cast to const slices in case of underlaying range is a pointer.
@property auto iterator()();
Returns:
Pointer to the first element of a slice if slice is defined as Slice!(N, T*) or plain structure with two fields shift and range otherwise. In second case the expression range[shift] refers to the first element. For slices with named elements the type of a return value has the same behavior like a pointer.

Note: iterator is defined only for non-packed slices.

Attention: iterator refers to the first element in the memory representation if and only if all strides are positive.

const @property size_t[packs[0]] shape()();
Returns:
static array of lengths
Examples:
Regular slice
import mir.ndslice.topology : iota;
assert(iota(3, 4, 5).shape == cast(size_t[3])[3, 4, 5]);
Examples:
Packed slice
import mir.ndslice.topology : pack, iota;
size_t[3] s = [3, 4, 5];
assert(iota(3, 4, 5, 6, 7).pack!2.shape == s);
const @property ptrdiff_t[packs[0]] strides()();
Returns:
static array of lengths
Examples:
Regular slice
import mir.ndslice.topology : iota;
size_t[3] s = [20, 5, 1];
assert(iota(3, 4, 5).strides == s);
Examples:
Modified regular slice
import mir.ndslice.topology : pack, iota, universal;
import mir.ndslice.dynamic : reversed, strided, transposed;
assert(iota(3, 4, 50)
    .universal
    .reversed!2      //makes stride negative
    .strided!2(6)    //multiplies stride by 6 and changes corresponding length
    .transposed!2    //brings dimension `2` to the first position
    .strides == cast(ptrdiff_t[3])[-6, 200, 50]);
Examples:
Packed slice
import mir.ndslice.topology : pack, iota;
size_t[3] s = [20 * 42, 5 * 42, 1 * 42];
assert(iota(3, 4, 5, 6, 7)
    .pack!2
    .strides == s);
const @property Structure!(packs[0]) structure()();
Returns:
static array of lengths and static array of strides
See Also:
Examples:
Regular slice
import mir.ndslice.topology : iota;
assert(iota(3, 4, 5)
    .structure == Structure!3([3, 4, 5], [20, 5, 1]));
Examples:
Modified regular slice
import mir.ndslice.topology : pack, iota, universal;
import mir.ndslice.dynamic : reversed, strided, transposed;
assert(iota(3, 4, 50)
    .universal
    .reversed!2      //makes stride negative
    .strided!2(6)    //multiplies stride by 6 and changes corresponding length
    .transposed!2    //brings dimension `2` to the first position
    .structure == Structure!3([9, 3, 4], [-6, 200, 50]));
Examples:
Packed slice
import mir.ndslice.topology : pack, iota;
assert(iota(3, 4, 5, 6, 7)
    .pack!2
    .structure == Structure!3([3, 4, 5], [20 * 42, 5 * 42, 1 * 42]));
@property auto save()();
Save primitive.
Examples:
Save range
import mir.ndslice.topology : iota;
auto slice = iota(2, 3).save;
Examples:
Pointer type.
import mir.ndslice.allocation;
//sl type is `Slice!(2, int*)`
auto sl = slice!int(2, 3).save;
const @property size_t length(size_t dimension = 0)()
if (dimension < packs[0]);
Multidimensional length property.
Returns:
length of the corresponding dimension
Examples:
import mir.ndslice.topology : iota;
auto slice = iota(3, 4, 5);
assert(slice.length   == 3);
assert(slice.length!0 == 3);
assert(slice.length!1 == 4);
assert(slice.length!2 == 5);
const @property sizediff_t _stride(size_t dimension = 0)()
if (dimension < packs[0]);
Multidimensional stride property.
Returns:
stride of the corresponding dimension
Examples:
Regular slice
import mir.ndslice.topology : iota;
auto slice = iota(3, 4, 5);
assert(slice._stride   == 20);
assert(slice._stride!0 == 20);
assert(slice._stride!1 == 5);
assert(slice._stride!2 == 1);
Examples:
Modified regular slice
import mir.ndslice.dynamic : reversed, strided, swapped;
import mir.ndslice.topology : universal, iota;
assert(iota(3, 4, 50)
    .universal
    .reversed!2      //makes stride negative
    .strided!2(6)    //multiplies stride by 6 and changes the corresponding length
    .swapped!(1, 2)  //swaps dimensions `1` and `2`
    ._stride!1 == -6);
const @property bool empty(size_t dimension = 0)()
if (dimension < packs[0]);

@property ref auto front(size_t dimension = 0)()
if (dimension < packs[0]);

@property auto front(size_t dimension = 0, T)(T value)
if (dimension == 0);

@property ref auto back(size_t dimension = 0)()
if (dimension < packs[0]);

@property auto back(size_t dimension = 0, T)(T value)
if (dimension == 0);

void popFront(size_t dimension = 0)()
if (dimension < packs[0] && (dimension == 0 || kind != Contiguous));

void popBack(size_t dimension = 0)()
if (dimension < packs[0] && (dimension == 0 || kind != Contiguous));

void popFrontExactly(size_t dimension = 0)(size_t n)
if (dimension < packs[0] && (dimension == 0 || kind != Contiguous));

void popBackExactly(size_t dimension = 0)(size_t n)
if (dimension < packs[0] && (dimension == 0 || kind != Contiguous));

void popFrontN(size_t dimension = 0)(size_t n)
if (dimension < packs[0] && (dimension == 0 || kind != Contiguous));

void popBackN(size_t dimension = 0)(size_t n)
if (dimension < packs[0] && (dimension == 0 || kind != Contiguous));
Multidimensional input range primitive.
Examples:
import std.range.primitives;
import mir.ndslice.topology : iota, canonical;
auto slice = iota(10, 20, 30).canonical;

static assert(isRandomAccessRange!(typeof(slice)));
static assert(hasSlicing!(typeof(slice)));
static assert(hasLength!(typeof(slice)));

assert(slice.shape == cast(size_t[3])[10, 20, 30]);
slice.popFront;
slice.popFront!1;
slice.popBackExactly!2(4);
assert(slice.shape == cast(size_t[3])[9, 19, 26]);

auto matrix = slice.front!1;
assert(matrix.shape == cast(size_t[2])[9, 26]);

auto column = matrix.back!1;
assert(column.shape == cast(size_t[1])[9]);

slice.popFrontExactly!1(slice.length!1);
assert(slice.empty   == false);
assert(slice.empty!1 == true);
assert(slice.empty!2 == false);
assert(slice.shape == cast(size_t[3])[9, 0, 26]);

assert(slice.back.front!1.empty);

slice.popFrontN!0(40);
slice.popFrontN!2(40);
assert(slice.shape == cast(size_t[3])[0, 0, 0]);
const bool anyEmpty()();
Returns:
true if for any dimension the length equals to 0, and false otherwise.
Examples:
import mir.ndslice.topology : iota, canonical;
auto s = iota(2, 3).canonical;
assert(!s.anyEmpty);
s.popFrontExactly!1(3);
assert(s.anyEmpty);
ref auto backward()(size_t[packs[0]] index);
Convenience function for backward indexing.
Returns:
this[$-index[0], $-index[1], ..., $-index[N-1]]
Examples:
import mir.ndslice.topology : iota;
auto s = iota(2, 3);
assert(s[$ - 1, $ - 2] == s.backward([1, 2]));
const size_t elementsCount();
Returns:
Total number of elements in a slice
Examples:
Regular slice
import mir.ndslice.topology : iota;
assert(iota(3, 4, 5).elementsCount == 60);
Examples:
Packed slice
import mir.ndslice.topology : pack, evertPack, iota;
auto slice = iota(3, 4, 5, 6, 7, 8);
auto p = slice.pack!2;
assert(p.elementsCount == 360);
assert(p[0, 0, 0, 0].elementsCount == 56);
assert(p.evertPack.elementsCount == 56);
const bool opEquals(SliceKind rkind, size_t[] rpacks, IteratorR)(const Slice!(rkind, rpacks, IteratorR) rslice)
if (rpacks.sum == N);

const bool opEquals(T)(T[] arr);
Overloading == and !=
Examples:
auto a = [1, 2, 3, 4].sliced(2, 2);

assert(a != [1, 2, 3, 4, 5, 6].sliced(2, 3));
assert(a != [[1, 2, 3], [4, 5, 6]]);

assert(a == [1, 2, 3, 4].sliced(2, 2));
assert(a == [[1, 2], [3, 4]]);

assert(a != [9, 2, 3, 4].sliced(2, 2));
assert(a != [[9, 2], [3, 4]]);
ref auto opIndex(size_t I)(size_t[I] _indexes...)
if (I && I <= packs[0]);
auto opIndex(Slices...)(Slices slices)
if (isPureSlice!Slices);
ditto
Examples:
import mir.ndslice.allocation;
auto slice = slice!int(5, 3);

/// Fully defined slice
assert(slice[] == slice);
auto sublice = slice[0..$-2, 1..$];

/// Partially defined slice
auto row = slice[3];
auto col = slice[0..$, 1];
void opIndexAssign(SliceKind rkind, size_t[] rpacks, RIterator, Slices...)(Slice!(rkind, rpacks, RIterator) value, Slices slices)
if (isFullPureSlice!Slices);
Assignment of a value of Slice type to a fully defined slice.

Optimization: SIMD instructions may be used if both slices have the last stride equals to 1.

Examples:
import mir.ndslice.allocation;
auto a = slice!int(2, 3);
auto b = [1, 2, 3, 4].sliced(2, 2);

a[0..$, 0..$-1] = b;
assert(a == [[1, 2, 0], [3, 4, 0]]);

// fills both rows with b[0]
a[0..$, 0..$-1] = b[0];
assert(a == [[1, 2, 0], [1, 2, 0]]);

a[1, 0..$-1] = b[1];
assert(a[1] == [3, 4, 0]);

a[1, 0..$-1][] = b[0];
assert(a[1] == [1, 2, 0]);
Examples:
Left slice is packed
import mir.ndslice.topology : blocks, iota;
import mir.ndslice.allocation : slice;
auto a = slice!int(4, 4);
a.blocks(2, 2)[] = iota!int(2, 2);

assert(a ==
        [[0, 0, 1, 1],
         [0, 0, 1, 1],
         [2, 2, 3, 3],
         [2, 2, 3, 3]]);
Examples:
Both slices are packed
import mir.ndslice.topology : blocks, iota, pack;
import mir.ndslice.allocation : slice;
auto a = slice!int(4, 4);
a.blocks(2, 2)[] = iota!int(2, 2, 2).pack!1;

assert(a ==
        [[0, 1, 2, 3],
         [0, 1, 2, 3],
         [4, 5, 6, 7],
         [4, 5, 6, 7]]);
void opIndexAssign(T, Slices...)(T[] value, Slices slices)
if (isFullPureSlice!Slices && !isDynamicArray!DeepElemType && DynamicArrayDimensionsCount!(T[]) <= ReturnType!(opIndex!Slices).N);
Assignment of a regular multidimensional array to a fully defined slice.

Optimization: SIMD instructions may be used if the slice has the last stride equals to 1.

Examples:
import mir.ndslice.allocation;
auto a = slice!int(2, 3);
auto b = [[1, 2], [3, 4]];

a[] = [[1, 2, 3], [4, 5, 6]];
assert(a == [[1, 2, 3], [4, 5, 6]]);

a[0..$, 0..$-1] = [[1, 2], [3, 4]];
assert(a == [[1, 2, 3], [3, 4, 6]]);

a[0..$, 0..$-1] = [1, 2];
assert(a == [[1, 2, 3], [1, 2, 6]]);

a[1, 0..$-1] = [3, 4];
assert(a[1] == [3, 4, 6]);

a[1, 0..$-1][] = [3, 4];
assert(a[1] == [3, 4, 6]);
Examples:
Packed slices
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : blocks;
auto a = slice!int(4, 4);
a.blocks(2, 2)[] = [[0, 1], [2, 3]];

assert(a ==
        [[0, 0, 1, 1],
         [0, 0, 1, 1],
         [2, 2, 3, 3],
         [2, 2, 3, 3]]);
void opIndexAssign(T, Slices...)(T stack, Slices slices)
if (isFullPureSlice!Slices && isStack!T);
void opIndexAssign(T, Slices...)(T value, Slices slices)
if (isFullPureSlice!Slices && (!isDynamicArray!T || isDynamicArray!DeepElemType) && !isSlice!T && !isStack!T);
Assignment of a value (e.g. a number) to a fully defined slice.

Optimization: SIMD instructions may be used if the slice has the last stride equals to 1.

Examples:
import mir.ndslice.allocation;
auto a = slice!int(2, 3);

a[] = 9;
assert(a == [[9, 9, 9], [9, 9, 9]]);

a[0..$, 0..$-1] = 1;
assert(a == [[1, 1, 9], [1, 1, 9]]);

a[0..$, 0..$-1] = 2;
assert(a == [[2, 2, 9], [2, 2, 9]]);

a[1, 0..$-1] = 3;
//assert(a[1] == [3, 3, 9]);

a[1, 0..$-1] = 4;
//assert(a[1] == [4, 4, 9]);

a[1, 0..$-1][] = 5;

assert(a[1] == [5, 5, 9]);
Examples:
Packed slices have the same behavior.
import mir.ndslice.allocation;
import mir.ndslice.topology : pack;
auto a = slice!int(2, 3).pack!1;

a[] = 9;
//assert(a == [[9, 9, 9], [9, 9, 9]]);
ref auto opIndexAssign(T)(T value, size_t[N] _indexes...);
Assignment of a value (e.g. a number) to a fully defined index.
Examples:
import mir.ndslice.allocation;
auto a = slice!int(2, 3);

a[1, 2] = 3;
assert(a[1, 2] == 3);
ref auto opIndexOpAssign(string op, T)(T value, size_t[N] _indexes...);
Op Assignment op= of a value (e.g. a number) to a fully defined index.
Examples:
import mir.ndslice.allocation;
auto a = slice!int(2, 3);

a[1, 2] += 3;
assert(a[1, 2] == 3);
void opIndexOpAssign(string op, SliceKind kind, size_t[] rpacks, RIterator, Slices...)(Slice!(kind, rpacks, RIterator) value, Slices slices)
if (isFullPureSlice!Slices);
Op Assignment op= of a value of Slice type to a fully defined slice.

Optimization: SIMD instructions may be used if both slices have the last stride equals to 1.

Examples:
import mir.ndslice.allocation;
auto a = slice!int(2, 3);
auto b = [1, 2, 3, 4].sliced(2, 2);

a[0..$, 0..$-1] += b;
assert(a == [[1, 2, 0], [3, 4, 0]]);

a[0..$, 0..$-1] += b[0];
assert(a == [[2, 4, 0], [4, 6, 0]]);

a[1, 0..$-1] += b[1];
assert(a[1] == [7, 10, 0]);

a[1, 0..$-1][] += b[0];
assert(a[1] == [8, 12, 0]);
Examples:
Left slice is packed
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : blocks, iota;
auto a = slice!size_t(4, 4);
a.blocks(2, 2)[] += iota(2, 2);

assert(a ==
        [[0, 0, 1, 1],
         [0, 0, 1, 1],
         [2, 2, 3, 3],
         [2, 2, 3, 3]]);
Examples:
Both slices are packed
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : blocks, iota, pack;
auto a = slice!size_t(4, 4);
a.blocks(2, 2)[] += iota(2, 2, 2).pack!1;

assert(a ==
        [[0, 1, 2, 3],
         [0, 1, 2, 3],
         [4, 5, 6, 7],
         [4, 5, 6, 7]]);
void opIndexOpAssign(string op, T, Slices...)(T[] value, Slices slices)
if (isFullPureSlice!Slices && !isDynamicArray!DeepElemType && DynamicArrayDimensionsCount!(T[]) <= ReturnType!(opIndex!Slices).N);
Op Assignment op= of a regular multidimensional array to a fully defined slice.

Optimization: SIMD instructions may be used if the slice has the last stride equals to 1.

Examples:
import mir.ndslice.allocation : slice;
auto a = slice!int(2, 3);

a[0..$, 0..$-1] += [[1, 2], [3, 4]];
assert(a == [[1, 2, 0], [3, 4, 0]]);

a[0..$, 0..$-1] += [1, 2];
assert(a == [[2, 4, 0], [4, 6, 0]]);

a[1, 0..$-1] += [3, 4];
assert(a[1] == [7, 10, 0]);

a[1, 0..$-1][] += [1, 2];
assert(a[1] == [8, 12, 0]);
Examples:
Packed slices
import mir.ndslice.allocation : slice;
import mir.ndslice.topology : blocks;
auto a = slice!int(4, 4);
a.blocks(2, 2)[].opIndexOpAssign!"+"([[0, 1], [2, 3]]);

assert(a ==
        [[0, 0, 1, 1],
         [0, 0, 1, 1],
         [2, 2, 3, 3],
         [2, 2, 3, 3]]);
void opIndexOpAssign(string op, T, Slices...)(T value, Slices slices)
if (isFullPureSlice!Slices && (!isDynamicArray!T || isDynamicArray!DeepElemType) && !isSlice!T && !isStack!T);
Op Assignment op= of a value (e.g. a number) to a fully defined slice.

Optimization: SIMD instructions may be used if the slice has the last stride equals to 1.

Examples:
import mir.ndslice.allocation;
auto a = slice!int(2, 3);

a[] += 1;
assert(a == [[1, 1, 1], [1, 1, 1]]);

a[0..$, 0..$-1] += 2;
assert(a == [[3, 3, 1], [3, 3, 1]]);

a[1, 0..$-1] += 3;
assert(a[1] == [6, 6, 1]);
void opIndexOpAssign(string op, T, Slices...)(T stack, Slices slices)
if (isFullPureSlice!Slices && isStack!T);
Examples:
Packed slices have the same behavior.
import mir.ndslice.allocation;
import mir.ndslice.topology : pack;
auto a = slice!int(2, 3).pack!1;

a[] += 9;
assert(a == [[9, 9, 9], [9, 9, 9]]);
ref auto opIndexUnary(string op)(size_t[N] _indexes...);
Increment ++ and Decrement -- operators for a fully defined index.
Examples:
import mir.ndslice.allocation;
auto a = slice!int(2, 3);

++a[1, 2];
assert(a[1, 2] == 1);
void opIndexUnary(string op, Slices...)(Slices slices)
if (isFullPureSlice!Slices && (op == "++" || op == "--"));
Increment ++ and Decrement -- operators for a fully defined slice.
Examples:
import mir.ndslice.allocation;
auto a = slice!int(2, 3);

++a[];
assert(a == [[1, 1, 1], [1, 1, 1]]);

--a[1, 0..$-1];

assert(a[1] == [0, 0, 1]);