Static Length Propagation of Ranges

ZombineDev via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Oct 20 17:14:51 PDT 2016


On Thursday, 20 October 2016 at 12:38:40 UTC, Nordlöw wrote:
> On Wednesday, 19 October 2016 at 19:39:46 UTC, Nordlöw wrote:
>> On Wednesday, 19 October 2016 at 19:01:50 UTC, Meta wrote:
>>> https://goo.gl/t9m3YK
>>>
>>> I'm actually pretty impressed that this kind of code can be 
>>> written in D.
>>
>> Thanks! Add at
>>
>> https://github.com/nordlow/phobos-next/blob/master/src/algorithm_ex.d#L2234
>
> Made it even modular by factoring out arrayN at
>
> https://github.com/nordlow/phobos-next/blob/master/src/algorithm_ex.d#L2200
>
> and used at
>
> https://github.com/nordlow/phobos-next/blob/master/src/algorithm_ex.d#L2215
>
> Code:
>
>
> ElementType!R[n] arrayN(size_t n, R)(R r)
> {
>     assert(r.length == n);
>     typeof(return) dst;
>     import std.algorithm.mutation : copy;
>     r.copy(dst[]);
>     return dst;
> }
>
> typeof(fun(E.init))[n] map(alias fun, E, size_t n)(const E[n] 
> src)
> {
>     import std.algorithm.iteration : map;
>     return src[].map!fun.arrayN!n;
> }
>
> @safe pure nothrow unittest
> {
>     import std.meta : AliasSeq;
>     foreach (E; AliasSeq!(int, double))
>     {
>         enum n = 42;
>         E[n] c;
>         const result = map!(_ => _^^2)(c);
>         static assert(c.length == result.length);
>         static assert(is(typeof(result) == const(E)[n]));
>     }
> }

Here's my variation on the theme. The main difference being that 
instead of eagerly evaluating the range I wrap it with additional 
static information. Unfortunately, (AFAIK) Phobos does not take 
advantage of ranges with statically known length, similarly to 
how it handles ranges with `enum bool empty = false`.

void main()
{
     import std.stdio;

     int[3] sarr = [1, 2, 3];
     auto r1 = sarr.staticLengthRange;
     static assert (isInputRange!(typeof(r1)));
     static assert (r1.length == 3);
     writeln(r1);

     auto arr = [1, 2, 3, 4];
     auto r2 = arr.map!(a => a * 2).staticLengthRange!4;
     static assert (r2.length == 4);
     writeln(r2);
}

import std.algorithm.iteration : map;
import std.range.primitives : hasLength, isInputRange;

// Note: this overload has questionable memory safety :(
// Would be quite cool if DIP1000 could support this use case
auto staticLengthRange(T, size_t n)(ref T[n] arr)
{
     return .staticLengthRange!(n, T[])(arr[]);
}

auto staticLengthRange(size_t n, R)(R range)
     if (isInputRange!R && hasLength!R)
{
     struct Result
     {
         enum size_t length = n;

         R _range;

         alias _range this;
     }

     assert (range.length == n);
     return Result(range);
}


auto staticLengthRange(size_t n, R)(R range)
     if (isInputRange!R && hasLength!R)
{
     struct Result
     {
         enum size_t length = n;

         R _range;

         alias _range this;
     }

     assert (range.length == n);
     return Result(range);
}




More information about the Digitalmars-d-learn mailing list