InputRanges that are not ForwardRanges seem to lack a possibly crucial operation. I want to start with an arbitrary range, take 1 from it, then process the rest. But there doesn't seem to be any way to do that, because there's no way to tell whether "take" will advance the range, or whether it will leave the range as-is.

When you know a range implements front, empty, and popFront, and you take from that range, there seems to be a secret requirement that the iterator supports save() via copy constructor. And if it doesn't... your program just breaks silently when you drop elements that haven't been processed yet.

Is there some way around that, that I'm not aware of?

struct CertainlyNotAForwardRange(A) {
        static int i = 0;
        A a;
        auto front() {
                return a[i];
        }
        auto empty() {
                return i == a.length;
        }
        auto popFront() {
                ++i;
        }
}

struct SecretlyForwardRange(A) {
        A a;
        int i = 0;
        auto front() {
                return a[i];
        }
        auto empty() {
                return i == a.length;
        }
        auto popFront() {
                ++i;
        }
}

auto failhard(T)(T iter) {
        import std.stdio;
        import std.range: take, drop;
        import std.array: array;

        writeln("We have some range:");
        writeln(typeid(T));
        writeln("We take 1 from it...");
        writeln(iter.take(1));
        writeln("The rest of the range has:");
        writeln(iter.drop(1).array);
        writeln("");
}       

void main() {
        auto arr = [0, 1, 2, 3];
        failhard(arr);
        failhard(SecretlyForwardRange!(typeof(arr))(arr));
        failhard(CertainlyNotAForwardRange!(typeof(arr))(arr));
}

Reply via email to