streams to ranges adapters

Peter Neubauer peterneubauer2 at gmail.com
Wed Sep 1 11:54:22 PDT 2010


On 09/01/2010 12:19 PM, Diego Martinelli wrote:
 > Hi all!
 > I'm digging the documentation of phobos but I am still learning D and 
I can't help
 > myself.
 > I feel like there's a lack of adapters between streams and ranges 
(something like
 > istream_iterator/ostream_iterator in STL).

I've encountered a similar problem yesterday. It left me digging through 
the Phobos docs for an hour looking for an existing solution :-) Let's 
say I have a function (or any D expression,) and I want to turn 
consecutive calls to this function into range form. As an example, let's 
generate 10 random numbers between 30 and 50. My first attempt was 
something like this:

import std.range;
import std.random;

void main ()
{
	writeln(take(recurrence!("uniform(30, 50)")(), 10));
}

However, this doesn't work because recurrence refuses to take 0 
arguments. Your post prompted me to steal some boilerplate code from the 
Phobos source and write this:

struct Rangeof(T)
{
     T delegate() _dg;
     T _buffer;
     bool _called = false;

     this(T delegate() dg) { _dg = dg; }
     @property bool empty() { return false; }
     void popFront()
     {
		if (!_called) {
			_buffer = _dg();
		}
		_called = false;
     }
     @property ref T front()
     {
         if (!_called) {
			_buffer = _dg();
			_called = true;
		}
		return _buffer;
     }
}

auto rangeof(F)(F func) if (isCallable!F)
{
	return Rangeof!(ReturnType!(F))(func);
}

Rangeof!(T) rangeof(T)(lazy T exp) if (!isCallable!T)
{
	T callexp (){ return exp; }
	return rangeof(&callexp);
}

Now you can turn any expression or function into a proper input range, 
compatible with std.range stuff. Example:

writeln(take(rangeof(uniform(30, 50)), 10));

At the risk of overshooting my goal, here's an additional overload for 
std.range.take which can now also "take" from a function:

auto my_take(F)(F input, size_t n) if (!isInputRange!F && isCallable!F)
{
     return Take!(Rangeof!(ReturnType!(F)))(rangeof(input), n);
}

Which means one less step in usage:

writeln(my_take({ return uniform(30, 50); }, 10));


Oh, and I didn't test my code at all, apart from those examples. Feel 
free to use it if you like.

-Peter


More information about the Digitalmars-d-learn mailing list