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 needed20.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