www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - immutable range

reply kenji hara <k.hara.pg gmail.com> writes:
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
Oct 16 2011
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 16 Oct 2011 07:37:03 -0400, kenji hara <k.hara.pg gmail.com> wrote:

 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
I don't think this scales well. Not only are you introducing a new type of range, you are introducing a new *class* of range. One which does not work with any existing algorithms. The solution must be compatible with all the existing range functions (which do not modify data), or it doesn't work. -Steve
Oct 17 2011