Thread overview
Automatic range creation for class or struct?
Feb 10, 2016
Peka
Feb 10, 2016
cym13
Feb 10, 2016
Peka
Feb 10, 2016
Peka
Feb 10, 2016
cym13
Feb 10, 2016
Ali Çehreli
Feb 10, 2016
Jesse Phillips
February 10, 2016
Hi!

I have class (or struct) which realises .length() and .opIndex(size_t) methods.

It is possible to create from this class some sort of range using template from std? (I mean that internal counter, .popFront(), .empty() etc methods should be added by template.)

February 10, 2016
On Wednesday, 10 February 2016 at 00:05:36 UTC, Peka wrote:
> Hi!
>
> I have class (or struct) which realises .length() and .opIndex(size_t) methods.
>
> It is possible to create from this class some sort of range using template from std? (I mean that internal counter, .popFront(), .empty() etc methods should be added by template.)

I don't think anything like that exists in phobos but it's not hard to pull it out using mixin templates:


mixin template Rangify(T)
if (__traits(hasMember, T, "length")
 && __traits(hasMember, T, "opIndex")) {

    ulong _counter;

    bool empty() {
        return _counter == this.length;
    }

    auto front() {
        return this[_counter];
    }

    auto popFront() {
        _counter++;
    }
}

struct S {
    int[] arr;

    mixin Rangify!S;

    auto length() {
        return arr.length;
    }

    int opIndex(size_t i) {
        return arr[i];
    }
}

void main(string[] args) {
    import std.stdio: writeln;

    auto s = S();
    s.arr = [1, 2, 3];

    foreach (x ; s)
        writeln(x);
}

February 10, 2016
On Wednesday, 10 February 2016 at 00:22:46 UTC, cym13 wrote:
> On Wednesday, 10 February 2016 at 00:05:36 UTC, Peka wrote:
>> Hi!
>>
>> I have class (or struct) which realises .length() and .opIndex(size_t) methods.
>>
>> It is possible to create from this class some sort of range using template from std? (I mean that internal counter, .popFront(), .empty() etc methods should be added by template.)
>
> I don't think anything like that exists in phobos

I need definitive answer.

> but it's not hard to pull it out using mixin templates:

Sure! Thanks a lot, but I want to use std lib as much as possible
February 10, 2016
>> I don't think anything like that exists in phobos
>
> I need definitive answer.

I need a precise answer.

(sorry, google translator :з)

February 10, 2016
On Wednesday, 10 February 2016 at 00:27:54 UTC, Peka wrote:
>>> I don't think anything like that exists in phobos
>>
>> I need definitive answer.
>
> I need a precise answer.
>
> (sorry, google translator :з)

"Definitive" is good, maybe even better in the context.

I should have been clearer, sorry. When I said "I don't think" I actually meant "I've searched the docs and sources and haven't found anything even remotely similar". I'll never be 100% percent sure that it isn't there though, you're free to read phobos to confirm it.
February 09, 2016
On 02/09/2016 04:22 PM, cym13 wrote:
> On Wednesday, 10 February 2016 at 00:05:36 UTC, Peka wrote:
>> Hi!
>>
>> I have class (or struct) which realises .length() and .opIndex(size_t)
>> methods.
>>
>> It is possible to create from this class some sort of range using
>> template from std? (I mean that internal counter, .popFront(),
>> .empty() etc methods should be added by template.)
>
> I don't think anything like that exists in phobos but it's not hard to
> pull it out using mixin templates:
>
>
> mixin template Rangify(T)
> if (__traits(hasMember, T, "length")
>   && __traits(hasMember, T, "opIndex")) {
>
>      ulong _counter;
>
>      bool empty() {
>          return _counter == this.length;
>      }
>
>      auto front() {
>          return this[_counter];
>      }
>
>      auto popFront() {
>          _counter++;
>      }
> }
>
> struct S {
>      int[] arr;
>
>      mixin Rangify!S;
>
>      auto length() {
>          return arr.length;
>      }
>
>      int opIndex(size_t i) {
>          return arr[i];
>      }
> }
>
> void main(string[] args) {
>      import std.stdio: writeln;
>
>      auto s = S();
>      s.arr = [1, 2, 3];
>
>      foreach (x ; s)
>          writeln(x);
> }
>

Actually, your method can work non-intrusively if the template is a function that returns a range (typically Voldemort):

auto rangify(T)(T range)
if (__traits(hasMember, T, "length")
 && __traits(hasMember, T, "opIndex")) {

    struct Range {
        T range;
        ulong _counter;

        bool empty() {
            return _counter == range.length;
        }

        auto front() {
            return range[_counter];
        }

        auto popFront() {
            _counter++;
        }
    }

    return Range(range);    // <-- Now returns a Voldemort object
}

struct S {         // <-- No mixin needed
    int[] arr;

    auto length() {
        return arr.length;
    }

    int opIndex(size_t i) {
        return arr[i];
    }
}

void main(string[] args) {
    import std.stdio: writeln;

    auto s = S();
    s.arr = [1, 2, 3];

    foreach (x ; s.rangify)    // <-- CHANGED
        writeln(x);
}

Ali

February 10, 2016
On Wednesday, 10 February 2016 at 00:05:36 UTC, Peka wrote:
> Hi!
>
> I have class (or struct) which realises .length() and .opIndex(size_t) methods.
>
> It is possible to create from this class some sort of range using template from std? (I mean that internal counter, .popFront(), .empty() etc methods should be added by template.)

See: https://issues.dlang.org/show_bug.cgi?id=5351