Showing with 154 additions and 3 deletions.
  1. +1 −1 std/experimental/ndslice/internal.d
  2. +1 −0 std/experimental/ndslice/package.d
  3. +152 −0 std/experimental/ndslice/selection.d
  4. +0 −2 std/experimental/ndslice/slice.d
2 changes: 1 addition & 1 deletion std/experimental/ndslice/internal.d
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module std.experimental.ndslice.internal;
import std.traits;
import std.meta; //: AliasSeq, anySatisfy, Filter, Reverse;

package:
struct LikePtr {}

alias isMemory = isPointer;

Expand Down
1 change: 1 addition & 0 deletions std/experimental/ndslice/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ $(TR $(TDNW Advanced Level $(BR)
$(SUBREF selection, byElementInStandardSimplex)
$(SUBREF selection, indexSlice)
$(SUBREF selection, iotaSlice)
$(SUBREF selection, repeatSlice)
$(SUBREF selection, pack)
$(SUBREF selection, evertPack)
$(SUBREF selection, unpack)
Expand Down
152 changes: 152 additions & 0 deletions std/experimental/ndslice/selection.d
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ $(T2 byElementInStandardSimplex, an input range of all elements in standard simp
If the slice has two dimensions, it is a range of all elements of upper left triangular matrix.)
$(T2 indexSlice, lazy slice with initial multidimensional index)
$(T2 iotaSlice, lazy slice with initial flattened (continuous) index)
$(T2 repeatSlice, slice with identical values)
$(T2 reshape, new slice with changed dimensions for the same data)
$(T2 diagonal, 1-dimensional slice composed of diagonal elements)
$(T2 blocks, n-dimensional slice composed of n-dimensional non-overlapping blocks.
Expand Down Expand Up @@ -1791,3 +1792,154 @@ struct IotaMap()
return index;
}
}

/++
Returns a slice with identical elements.
`RepeatSlice` stores only single value.
Params:
lengths = list of dimension lengths
Returns:
`n`-dimensional slice composed of identical values, where `n` is dimension count.
See_also: $(REF repeat, std,range)
+/
RepeatSlice!(Lengths.length, T) repeatSlice(T, Lengths...)(T value, Lengths lengths)
if (allSatisfy!(isIndex, Lengths) && !is(T : Slice!(N, Range), size_t N, Range))
{
typeof(return) ret;
foreach (i; Iota!(0, ret.N))
ret._lengths[i] = lengths[i];
ret._ptr = RepeatPtr!T(value);
return ret;
}

/// ditto
Slice!(Lengths.length, Slice!(N + 1, Range)) repeatSlice(size_t N, Range, Lengths...)(auto ref Slice!(N, Range) slice, Lengths lengths)
if (allSatisfy!(isIndex, Lengths) && Lengths.length)
{
enum M = Lengths.length;
typeof(return) ret;
ret._ptr = slice._ptr;
foreach (i; Iota!(0, M))
ret._lengths[i] = lengths[i];
foreach (i; Iota!(0, N))
{
ret._lengths[M + i] = slice._lengths[i];
ret._strides[M + i] = slice._strides[i];
}
return ret;
}

///
@safe pure nothrow unittest
{
auto sl = iotaSlice(3)
.repeatSlice(4);
assert(sl == [[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2]]);
}

///
@safe pure nothrow unittest
{
import std.experimental.ndslice.iteration : transposed;

auto sl = iotaSlice(3)
.repeatSlice(4)
.unpack
.transposed;

assert(sl == [[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2]]);
}

///
pure nothrow unittest
{
import std.experimental.ndslice.slice : slice;

auto sl = iotaSlice([3], 6).slice;
auto slC = sl.repeatSlice(2, 3);
sl[1] = 4;
assert(slC == [[[6, 4, 8],
[6, 4, 8],
[6, 4, 8]],
[[6, 4, 8],
[6, 4, 8],
[6, 4, 8]]]);
}

///
@safe pure nothrow unittest
{
auto sl = repeatSlice(4.0, 2, 3);
assert(sl == [[4.0, 4.0, 4.0],
[4.0, 4.0, 4.0]]);

static assert(is(DeepElementType!(typeof(sl)) == double));

sl[1, 1] = 3;
assert(sl == [[3.0, 3.0, 3.0],
[3.0, 3.0, 3.0]]);
}

/++
Slice composed of identical values.
+/
template RepeatSlice(size_t N, T)
if (N)
{
alias RepeatSlice = Slice!(N, RepeatPtr!T);
}

// undocumented
// zero cost variant of `std.range.repeat`
// in addition, the internal value is mutable
@LikePtr struct RepeatPtr(T)
{
// UT definition is from std.range
// Store a non-qualified T when possible: This is to make RepeatPtr assignable
static if ((is(T == class) || is(T == interface)) && (is(T == const) || is(T == immutable)))
{
import std.typecons : Rebindable;
private alias UT = Rebindable!T;
}
else static if (is(T : Unqual!T) && is(Unqual!T : T))
private alias UT = Unqual!T;
else
private alias UT = T;
private UT _value;

ref T opIndex(sizediff_t)
{
return _value;
}

void opOpAssign(string op)(sizediff_t)
if (op == `+` || op == `-`)
{
}

auto opBinary(string op)(sizediff_t)
if (op == `+` || op == `-`)
{
return this;
}

auto ref opUnary(string op)()
if (op == `++` || op == `--`)
{
return this;
}
}

@safe pure nothrow @nogc unittest
{
RepeatPtr!double val;
val._value = 3;
assert((++val)._value == 3);
val += 2;
assert((val + 3)._value == 3);
}
2 changes: 0 additions & 2 deletions std/experimental/ndslice/slice.d
Original file line number Diff line number Diff line change
Expand Up @@ -3301,8 +3301,6 @@ unittest

private enum isSlicePointer(T) = isPointer!T || is(T : PtrShell!R, R);

private struct LikePtr {}

package template hasPtrBehavior(T)
{
static if (isPointer!T)
Expand Down