Ranges

20.1 The Range Concept

A range is an abstraction for sequential data. It replaces iterators and powers Phobos.

empty, front, popFront() + save (copy the iteration state) + back, popBack() + opIndex, and length (or infinite) enum empty = false;

20.2 Writing a Custom Range

struct FibRange
{
    ulong a = 0, b = 1;
    enum empty = false;                     // infinite
    @property ulong front() const { return a; }
    void popFront() { auto t = a + b; a = b; b = t; }
    @property FibRange save() { return this; }
}

import std.range : take;
import std.stdio;
foreach (f; FibRange().take(10)) write(f, " ");

struct Countdown
{
    int n;
    bool empty() const { return n < 0; }
    int front() const { return n; }
    void popFront() { --n; }
}

20.3 Range Checks

import std.range.primitives;
static assert(isInputRange!FibRange);
static assert(isForwardRange!FibRange);
static assert(isInfinite!FibRange);
static assert(isRandomAccessRange!(int[]));
alias E = ElementType!(int[]);

20.4 Laziness and Eagerness

import std.algorithm, std.range, std.array;
auto lazyResult = iota(1, 1_000_000).filter!(x => x % 3 == 0).map!(x => x * 2);  // nothing computed yet
auto first5 = lazyResult.take(5).array;     // computes only what's needed

20.5 Generators and Range Interfaces

import std.concurrency : Generator, yield;
auto gen = new Generator!int({ foreach (i; 0 .. 5) yield(i * i); });
foreach (v; gen) write(v, " ");

import std.range.interfaces : InputRange, inputRangeObject;
InputRange!int r = inputRangeObject(iota(5));   // type-erased (runtime polymorphic) range