[Issue 12564] New: std.range.backWalk, std.range.backWalkMaybe

d-bugmail at puremagic.com d-bugmail at puremagic.com
Sat Apr 12 03:25:59 PDT 2014


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

          Issue ID: 12564
           Summary: std.range.backWalk, std.range.backWalkMaybe
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: Phobos
          Assignee: nobody at puremagic.com
          Reporter: bearophile_hugs at eml.cc

If I have a range like this, how do you find its last item using Phobos? This
is a problem I have had to solve few times. A simple way is to use
seq.array.back, but this wastes memory. Another simple way is to use a foreach
loop keeping the last seen:

void main() {
    import std.stdio, std.algorithm, std.range;

    int m = 75;
    auto seq = recurrence!q{ a[n - 1] + a[n - 2] }(1, 1)
               .until!(x => x > m)(OpenRight.no);

    seq.array.back.writeln; // 89
    //seq.back.writeln;

    auto last = -1;
    foreach (immutable x; seq)
        last = x;
    last.writeln;
}



But I'd like a function to do it nicely in UFCS chains too. So I suggest to add
functions like this (the code here is illustrative, it doesn't work in all
cases):


import std.stdio, std.algorithm, std.range, std.traits,
       std.typecons;

// Throws when sequence is empty.
ElementType!R backWalk(R)(R sequence)
if (isForwardRange!R) {
    if (sequence.empty)
        throw new Exception("backWalk: empty imput");

    static if (__traits(compiles, { sequence.back; })) {
        return sequence.back;
    } else {
        ElementType!R last;
        foreach (x; sequence)
            last = x;
        return last;
    }
}

// Returns a given default element when sequence is empty,
// and can be nothrow.
ElementType!R backWalk(R, T)(R sequence, T defaultResult)
if (isForwardRange!R && is(T == ElementType!R)) {
    if (sequence.empty)
        return defaultResult;

    static if (__traits(compiles, { sequence.back; })) {
        return sequence.back;
    } else {
        ElementType!R last;
        foreach (x; sequence)
            last = x;
        return last;
    }
}

// Returns a Nullable when sequence is empty,
// and can be nothrow.
Nullable!(ElementType!R) backWalkMaybe(R)(R sequence)
if (isForwardRange!R) {
    if (sequence.empty)
        return typeof(return)();

    static if (__traits(compiles, { sequence.back; })) {
        return typeof(return)(sequence.back);
    } else {
        typeof(return) last;
        foreach (x; sequence)
            last = typeof(return)(x);
        return last;
    }
}

void main() { // Some tests and examples.
    int m = 75;
    auto seq = recurrence!q{ a[n - 1] + a[n - 2] }(1, 1)
               .until!(x => x > m)(OpenRight.no);

    seq.array.back.writeln; // 89
    //seq.back.writeln; // Not possible.

    seq.backWalk.writeln;
    [1, 2].backWalk.writeln;

    seq.backWalkMaybe.writeln;
    [1, 2].backWalkMaybe.writeln;

    "ABC".backWalk.writeln;
    "ABC".backWalkMaybe.writeln;

    "".backWalk(dchar('a')).writeln;
    const c = 'a';
    //"".backWalk(c).writeln; // This too should work.
}

--


More information about the Digitalmars-d-bugs mailing list