immutable range
kenji hara
k.hara.pg at gmail.com
Sun Oct 16 04:37:03 PDT 2011
I got an idea.
import std.range;
template isImmutableInputRange(R)
{
enum bool isImmutableInputRange = is(typeof(
{
R r; // can define a range object
if (r.empty) {} // can test for empty
auto r2 = r.nextFront(); // can invoke nextFront()
auto h = r2.front; // can get the front of the range
}));
}
template isImmutableForwardRange(R)
{
enum bool isImmutableForwardRange = isImmutableInputRange!R && is(typeof(
{
R r1;
R r2 = r1.save; // can call "save" against a range object
}));
}
template isImmutableBidirectionalRange(R)
{
enum bool isImmutableBidirectionalRange = isImmutableForwardRange!R
&& is(typeof(R.init.back()) == typeof(R.init.front()))
&& is(typeof({ R r; auto r2 = r.nextBack(); }));
}
void immutableForeach(R, E)(R r, scope void delegate(E) dg)
if (isImmutableInputRange!R && is(ElementType!R : E))
{
if (r.empty)
return;
dg(r.front);
immutableForeach(r.nextFront(), dg); // tail recursion
}
void immutableForeachReverse(R, E)(R r, scope void delegate(E) dg)
if (isImmutableBidirectionalRange!R && is(ElementType!R : E))
{
if (r.empty)
return;
dg(r.back);
immutableForeachReverse(r.nextBack(), dg); // tail recursion
}
const struct Range
{
int[] arr;
@property int front() const { return arr[0]; }
@property bool empty() const { return arr.length > 0; }
const(Range) nextFront() const { return Range(arr[1..$]); }
const(Range) save() const { return this; }
@property int back() const { return arr[$-1]; }
const(Range) nextBack() { return Range(arr[0..$-1]); }
}
static assert(isImmutableInputRange!Range);
static assert(isImmutableForwardRange!Range);
static assert(isImmutableBidirectionalRange!Range);
void main()
{
const r = Range([1,2,3]);
int i = 0;
immutableForeach(r, (int v)
{
assert(v == ++i);
});
int j = 3;
immutableForeachReverse(r, (int v)
{
assert(v == j--);
});
}
Kenji Hara
More information about the Digitalmars-d
mailing list