Skip to content

Commit 661f2d8

Browse files
authored
as and retro for ranges (#307)
* add `as` for ranges * add support for ranges
1 parent 32371ba commit 661f2d8

File tree

1 file changed

+107
-2
lines changed

1 file changed

+107
-2
lines changed

source/mir/ndslice/topology.d

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2124,9 +2124,9 @@ auto stride(T)(T withAsSlice, ptrdiff_t factor)
21242124
/++
21252125
Reverses order of iteration for all dimensions.
21262126
Params:
2127-
slice = Unpacked slice.
2127+
slice = slice, range, or array.
21282128
Returns:
2129-
Slice with reversed order of iteration for all dimensions.
2129+
Slice/range with reversed order of iteration for all dimensions.
21302130
See_also: $(SUBREF dynamic, reversed), $(SUBREF dynamic, allReversed).
21312131
+/
21322132
auto retro
@@ -2184,6 +2184,80 @@ auto retro(T)(T withAsSlice)
21842184
return retro(withAsSlice.asSlice);
21852185
}
21862186

2187+
2188+
/// ditto
2189+
auto retro(Range)(Range r)
2190+
if (!hasAsSlice!Range && !isSlice!Range && !is(Range : T[], T))
2191+
{
2192+
import std.traits: Unqual;
2193+
2194+
static if (is(Unqual!Range == Range))
2195+
{
2196+
import core.lifetime: move;
2197+
static if (is(Range : RetroRange!R, R))
2198+
{
2199+
return move(r._source);
2200+
}
2201+
else
2202+
{
2203+
return RetroRange!Range(move(r));
2204+
}
2205+
}
2206+
else
2207+
{
2208+
return .retro!(Unqual!Range)(r);
2209+
}
2210+
}
2211+
2212+
/// ditto
2213+
struct RetroRange(Range)
2214+
{
2215+
import mir.primitives: hasLength;
2216+
2217+
///
2218+
Range _source;
2219+
2220+
private enum hasAccessByRef = __traits(compiles, &_source.front);
2221+
2222+
@property
2223+
{
2224+
bool empty()() const { return _source.empty; }
2225+
static if (hasLength!Range)
2226+
auto length()() const { return _source.length; }
2227+
auto ref front()() { return _source.back; }
2228+
auto ref back()() { return _source.front; }
2229+
static if (__traits(hasMember, Range, "save"))
2230+
auto save()() { return RetroRange(_source.save); }
2231+
alias opDollar = length;
2232+
2233+
static if (!hasAccessByRef)
2234+
{
2235+
import std.traits: ForeachType;
2236+
2237+
void front()(ForeachType!R val)
2238+
{
2239+
import mir.functional: forward;
2240+
_source.back = forward!val;
2241+
}
2242+
2243+
void back()(ForeachType!R val)
2244+
{
2245+
import mir.functional: forward;
2246+
_source.front = forward!val;
2247+
}
2248+
}
2249+
}
2250+
2251+
void popFront()() { _source.popBack(); }
2252+
void popBack()() { _source.popFront(); }
2253+
2254+
static if (is(typeof(_source.moveBack())))
2255+
auto moveFront()() { return _source.moveBack(); }
2256+
2257+
static if (is(typeof(_source.moveFront())))
2258+
auto moveBack()() { return _source.moveFront(); }
2259+
}
2260+
21872261
///
21882262
@safe pure nothrow @nogc version(mir_test) unittest
21892263
{
@@ -2198,6 +2272,16 @@ auto retro(T)(T withAsSlice)
21982272
static assert(is(typeof(slice.universal.retro) == typeof(slice.universal)));
21992273
}
22002274

2275+
/// Ranges
2276+
@safe pure nothrow @nogc version(mir_test) unittest
2277+
{
2278+
import mir.algorithm.iteration: equal;
2279+
import std.range: std_iota = iota;
2280+
2281+
assert(std_iota(4).retro.equal(iota(4).retro));
2282+
static assert(is(typeof(std_iota(4).retro.retro) == typeof(std_iota(4))));
2283+
}
2284+
22012285
/++
22022286
Bitwise slice over an integral slice.
22032287
Params:
@@ -3308,6 +3392,20 @@ template as(T)
33083392
{
33093393
return as(withAsSlice.asSlice);
33103394
}
3395+
3396+
/// ditto
3397+
auto as(Range)(Range r)
3398+
if (!hasAsSlice!Range && !isSlice!Range && !is(Range : T[], T))
3399+
{
3400+
static if (is(ForeachType!Range == T))
3401+
return r;
3402+
else
3403+
{
3404+
import core.lifetime: move;
3405+
import mir.conv: to;
3406+
return map!(to!T)(r.move);
3407+
}
3408+
}
33113409
}
33123410

33133411
///
@@ -3341,6 +3439,13 @@ template as(T)
33413439
Slice!(const(double)*, 2) const_matrix = matrix.as!(const double);
33423440
}
33433441

3442+
/// Ranges
3443+
@safe pure nothrow version(mir_test) unittest
3444+
{
3445+
import mir.algorithm.iteration: filter, equal;
3446+
assert(5.iota.filter!"a % 2".as!double.map!"a / 2".equal([0.5, 1.5]));
3447+
}
3448+
33443449
/++
33453450
Takes a field `source` and a slice `indexes`, and creates a view of source as if its elements were reordered according to indexes.
33463451
`indexes` may include only a subset of the elements of `source` and may also repeat elements.

0 commit comments

Comments
 (0)