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