www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to implement a range?

reply Jack <jckj33 gmail.com> writes:
In order to my array class work with filter, I went to implement 
an ``InputRange``. But I don't quite get how do that and didn't 
find much help on the docs. From below code, is ``moveFront()`` 
implemented correctly? I'm using a simple int i as index of 
current item and in popFront() just increment it. I must reset 
the i value once the loop is done, right? where am I supposed to 
do that? opApply()? not properly reseting it result in obvious 
bugs like subsequent calls doesn't work because the index is in 
the end of the array:

```d
auto arr = new MyArray!int;
arr.Add(1);
arr.Add(2);
arr.Add(3);
arr.Add(4);
auto r = arr.filter!(n => (n % 2) == 0);
auto r2 = arr.filter!(n => n >= 2);
writeln(r); // ok
writeln(r2); // empty
```

yeah, i'm a bit confused... here's the code:

```d
class MyArray(T) : InputRange!T
{
     private T[] arr;
     private int i = 0;

     void Add(T item)
     {
         arr ~= item;
     }

     void Add(T[] items)
     {
         foreach(item; items)
         {
             Add(item);
         }
     }

     size_t length() nothrow
     {
         return arr.length;
     }

     bool empty()
     {
     	return i == length;
     }

     T front()
     {
     	return arr[i];
     }

     void popFront()
     {
     	i++;
     }

     T moveFront()
     {
     	auto r = front;
     	popFront();
     	return r;
     }

     int opApply(scope int delegate(ref T) dg)
     {
         int result = 0;

         foreach (item; arr)
         {
             result = dg(item);
             if (result) {
                 break;
             }
         }

         return result;
     }

     int opApply(scope int delegate(T) dg)
     {
         int result = 0;

         foreach (item; arr)
         {
             result = dg(item);
             if (result) {
                 break;
             }
         }

         return result;
     }

     int opApply(scope int delegate(uint, T) dg)
     {
         int result = 0;
     	
         foreach (j, item; arr)
         {
             result = dg(j, item);
             if (result) {
                 break;
             }
         }

         return result;
     }
}
```
Apr 15 2021
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Friday, 16 April 2021 at 06:21:35 UTC, Jack wrote:
 In order to my array class work with filter, I went to 
 implement an ``InputRange``. But I don't quite get how do that 
 and didn't find much help on the docs. From below code, is 
 ``moveFront()`` implemented correctly? I'm using a simple int i 
 as index of current item and in popFront() just increment it. I 
 must reset the i value once the loop is done, right? where am I 
 supposed to do that? opApply()? not properly reseting it result 
 in obvious bugs like subsequent calls doesn't work because the 
 index is in the end of the array:
Generally, you don't want your containers to be ranges themselves. You want them to produce ranges, i.e., separate the duties of iteration from the duties of the container. Also, it's best to make your range types as structs rather than classes for an easier time. A basic input range doesn't need to worry about `moveFront`. So you can get away with `empty`, `front`, and `popFront` on a struct. ```d import std.stdio; class MyArray(T) { private T[] _a; this(T[] a) { _a = a; }; auto opIndex() { return Range(_a[]); } private static struct Range { T[] a; T front() { return a[0]; } void popFront() { a = a[1 .. $]; } bool empty() { return a.length == 0; } } } void main() { auto ma = new MyArray!int([10, 20, 30, 44, 55]); foreach(i; ma[]) { writeln(i); } } ``` I've overloaded the slice operator via the no-arg `opIndex` to provide the range so that you can do `ma[]` to get to it. You'd want to expand on that to handle start & end points for a slice. But anyway, the whole idea behind ranges is you want to keep your iteration separate from the data. Then ranges can be copied around and consumed without every changing the original data structure.
Apr 15 2021
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 4/15/21 11:21 PM, Jack wrote:

 didn't find much help on the docs.
In case it's useful to others as well, I have two chapters on ranges: http://ddili.org/ders/d.en/ranges.html http://ddili.org/ders/d.en/ranges_more.html Ali
Apr 16 2021