Jump to page: 1 2
Thread overview
parameter pack to inputRange
May 06, 2016
Erik Smith
May 06, 2016
Ali Çehreli
May 06, 2016
Erik Smith
May 06, 2016
Dicebot
May 06, 2016
Dicebot
May 08, 2016
Ali Çehreli
May 08, 2016
Erik Smith
May 08, 2016
Dicebot
May 08, 2016
Dicebot
May 08, 2016
Erik Smith
May 08, 2016
Ali Çehreli
May 09, 2016
Erik Smith
May 09, 2016
Dicebot
May 09, 2016
Ali Çehreli
May 09, 2016
Dicebot
May 09, 2016
Alex Parrill
May 06, 2016
Ali Çehreli
May 06, 2016
Alex Parrill
May 06, 2016
Is there an existing way to adapt a parameter pack to an input range? I would like to construct an array with it.  Example:

void run(A...) (A args) {
     Array!int a(toInputRange(args));
}

May 05, 2016
On 05/05/2016 10:00 PM, Erik Smith wrote:
> Is there an existing way to adapt a parameter pack to an input range? I
> would like to construct an array with it.  Example:
>
> void run(A...) (A args) {
>       Array!int a(toInputRange(args));
> }
>

Just initialize an array with the arguments:

void run(A...) (A args) {
    writeln([args]);
}

Ali

May 05, 2016
On 05/05/2016 10:00 PM, Erik Smith wrote:
> Is there an existing way to adapt a parameter pack to an input range? I
> would like to construct an array with it.  Example:
>
> void run(A...) (A args) {
>       Array!int a(toInputRange(args));
> }
>

Inspired by my DConf 2016 talk ;) here is a fiber-based InputRange solution:

import std.stdio;
import std.concurrency;
import std.container;

alias GeneratorFiber = std.concurrency.Generator;

void run(A...) (A args) {
    void asInputRange() {
        /* static */ foreach (arg; args) {
            yield(arg);
        }
    }

    auto range =  new GeneratorFiber!int(&asInputRange);
    auto a = Array!int(range);
    writeln(a[]);
}

void main() {
    run(1, 2, 3);
}

Ali

May 06, 2016
On Friday, 6 May 2016 at 05:20:50 UTC, Ali Çehreli wrote:
> On 05/05/2016 10:00 PM, Erik Smith wrote:
>> Is there an existing way to adapt a parameter pack to an input range? I
>> would like to construct an array with it.  Example:
>>
>> void run(A...) (A args) {
>>       Array!int a(toInputRange(args));
>> }
>>
>
> Just initialize an array with the arguments:
>
> void run(A...) (A args) {
>     writeln([args]);
> }
>
> Ali

That's allocating a dynamic array though, right?  It seems like there should be a non-GC adaptor for this purpose (especially since I'm using std.container.array).

erik

May 06, 2016
Unless parameter list is very (very!) long, I'd suggest to simply copy it into a stack struct. Something like this:

auto toInputRange (T...) (T args)
{
    struct Range
    {
        T args;
        size_t index;

        T[0] front () { return args[index]; }
        void popFront () { ++index; }
        bool empty () { return index >= args.length; }
    }

    return Range(args, 0);
}
May 06, 2016
On Friday, 6 May 2016 at 06:08:24 UTC, Dicebot wrote:
> Unless parameter list is very (very!) long, I'd suggest to simply copy it into a stack struct. Something like this:
>
> auto toInputRange (T...) (T args)
> {
>     struct Range
>     {
>         T args;
>         size_t index;
>
>         T[0] front () { return args[index]; }
>         void popFront () { ++index; }
>         bool empty () { return index >= args.length; }
>     }
>
>     return Range(args, 0);
> }

(note that you can actually make it random access range and not just input range, I simply have not defined required methods)
May 06, 2016
On Friday, 6 May 2016 at 05:00:48 UTC, Erik Smith wrote:
> Is there an existing way to adapt a parameter pack to an input range? I would like to construct an array with it.  Example:
>
> void run(A...) (A args) {
>      Array!int a(toInputRange(args));
> }

Use std.range.only: http://dlang.org/phobos/std_range.html#only

void run(A...)(A args) {
    auto rng = only(args);
    // ...
}
May 08, 2016
On 05/05/2016 11:08 PM, Dicebot wrote:
> Unless parameter list is very (very!) long, I'd suggest to simply copy
> it into a stack struct. Something like this:
>
> auto toInputRange (T...) (T args)
> {
>      struct Range
>      {
>          T args;
>          size_t index;
>
>          T[0] front () { return args[index]; }
>          void popFront () { ++index; }
>          bool empty () { return index >= args.length; }
>      }
>
>      return Range(args, 0);
> }

I wanted this syntax to work but when I tested I saw that T does not expand to struct members.

I like Alex Parrill's only() solution but it allocates a dynamic array as well by doing the equivalent of [args] in the guts of its implementation.

As Dicebot said, unless there are tons of arguments, I think the following is the best as it is @nogc. It executes a switch statement for each front() call though. And I like the CommonType!T idea there.

import std.stdio;
import std.string;

/* Support empty Args? */
@nogc pure nothrow
auto toInputRange(Args...)() {
    struct Range {
        size_t index;

        bool empty() {
            return index >= Args.length;
        }

        void popFront() {
            ++index;
        }

        import std.traits : CommonType;
        alias E = CommonType!Args;

        E front() {
            final switch (index) {
                /* static */ foreach (i, arg; Args) {
                    case i:
                        return arg;
                }
            }
        }
    }

    return Range();
}

unittest {
    import std.traits;
    import std.range;

    static assert(isInputRange!(ReturnType!(toInputRange!(1))));
}

void main() {
    auto r = toInputRange!(1, 2.5, 3);
    writeln(r);
}

Ali

May 08, 2016
On Sunday, 8 May 2016 at 14:11:31 UTC, Ali Çehreli wrote:
> On 05/05/2016 11:08 PM, Dicebot wrote:
> > Unless parameter list is very (very!) long, I'd suggest to
> simply copy
> > it into a stack struct. Something like this:
> >
> > auto toInputRange (T...) (T args)
> > {
> >      struct Range
> >      {
> >          T args;
> >          size_t index;
> >
> >          T[0] front () { return args[index]; }
> >          void popFront () { ++index; }
> >          bool empty () { return index >= args.length; }
> >      }
> >
> >      return Range(args, 0);
> > }
>
> I wanted this syntax to work but when I tested I saw that T does not expand to struct members.
>
> I like Alex Parrill's only() solution but it allocates a dynamic array as well by doing the equivalent of [args] in the guts of its implementation.
>
> As Dicebot said, unless there are tons of arguments, I think the following is the best as it is @nogc. It executes a switch statement for each front() call though. And I like the CommonType!T idea there.
>
> import std.stdio;
> import std.string;
>
> /* Support empty Args? */
> @nogc pure nothrow
> auto toInputRange(Args...)() {
>     struct Range {
>         size_t index;
>
>         bool empty() {
>             return index >= Args.length;
>         }
>
>         void popFront() {
>             ++index;
>         }
>
>         import std.traits : CommonType;
>         alias E = CommonType!Args;
>
>         E front() {
>             final switch (index) {
>                 /* static */ foreach (i, arg; Args) {
>                     case i:
>                         return arg;
>                 }
>             }
>         }
>     }
>
>     return Range();
> }
>
> unittest {
>     import std.traits;
>     import std.range;
>
>     static assert(isInputRange!(ReturnType!(toInputRange!(1))));
> }
>
> void main() {
>     auto r = toInputRange!(1, 2.5, 3);
>     writeln(r);
> }
>
> Ali

I like this solution and it's exactly what I was looking for.   However, I'm having an issue when I try to apply it with an actual variadic function.  This seems like a DMD bug.

static void foo(Args...)(Args args) {
    import std.container.array;
    auto array = Array!int(toInputRange!(args));

    foreach(a; array) {
        writeln("e: ", a);
    }
}

foo(1,2,3);

e:1431827808
e:32767
e:1254116144



May 08, 2016
On Sunday, 8 May 2016 at 14:11:31 UTC, Ali Çehreli wrote:
> On 05/05/2016 11:08 PM, Dicebot wrote:
> > Unless parameter list is very (very!) long, I'd suggest to
> simply copy
> > it into a stack struct. Something like this:
> >
> > auto toInputRange (T...) (T args)
> > {
> >      struct Range
> >      {
> >          T args;
> >          size_t index;
> >
> >          T[0] front () { return args[index]; }
> >          void popFront () { ++index; }
> >          bool empty () { return index >= args.length; }
> >      }
> >
> >      return Range(args, 0);
> > }
>
> I wanted this syntax to work but when I tested I saw that T

It does (and it must). I have just tested it and noticed another issue though, one I have not foreseen initially. When accessing variadic variable list, one must use compile-time known index because variables are not guaranteed to be of same size. It can be fixed by using static array (and CommonType is a right call of course):

auto toInputRange (T...) (T args) @nogc
{
    import std.traits : CommonType;
    alias E = CommonType!T;

    struct Range
    {
        E[T.length] args;
        size_t index;

        E front () { return args[index]; }
        void popFront () { ++index; }
        bool empty () { return index >= args.length; }
    }

    Range range;
    foreach (i, ref arg; args)
        range.args[i] = arg;
    return range;
}

void main ( )
{
    import std.stdio;
    writeln(toInputRange(1, 2, 3));
}

This version is checked to work on my machine.

« First   ‹ Prev
1 2