On 06/22/2013 09:08 PM, monarch_dodra wrote:
> Personally, I've found ranges to be a very useful and powerful *high level*
> abstraction. They lend themselves work very well for adapting and chaining
> (which iterators don't). However, they do come with *some* downsides (IMO):
> #1: Performance issues: No matter how I use them, it seems that I can never
> get
> the same raw performance I could get with raw iterator iteration.*
Do you think that's inevitable? I'd have thought that this ought to be possible
to improve with better compiler optimizations.
> *: #1 is subject to simple iteration: Once things scale in terms of adaptors,
> ranges win because of the "single item empty" mechanic
Could you explain that in a bit more depth, please?
> #2: Extremelly bad compatibility with simple no bidir/non-slicing ranges:
> There
> is no way to iterate over a specific part of a range, and making a range out
> of
> what was just iterated over. For example "Get the beggining of this range
> until
> the first x": not possible without slicing.
Not sure what you mean here -- doesn't the attached little code example do
roughly what you're looking for? (N.B. it has crap template constraints.
Typing this quickly I couldn't work out how to make sure that the second
constructor argument matches the type of input.front.)
import std.range;
struct UntilFirst(R, T)
if(isInputRange!R)
{
private R _input;
private T _x;
this(R input, T x)
{
_input = input;
_x = x;
}
bool empty() @property
{
return _input.empty || _input.front == _x;
}
auto front() @property
{
assert(!empty);
return _input.front;
}
void popFront()
{
assert(!empty);
_input.popFront();
}
}
auto untilFirst(R, T)(R input, T x)
if(isInputRange!R)
{
return UntilFirst!(R, T)(input, x);
}
unittest
{
import std.stdio;
writeln(untilFirst(iota(20), 13));
writeln(untilFirst("abcdefghijklmnopqrstuvwxyz", 'j'));
}