RFC on range design for D2
Bill Baxter
wbaxter at gmail.com
Wed Sep 10 17:32:28 PDT 2008
On Thu, Sep 11, 2008 at 8:17 AM, Steven Schveighoffer
<schveiguy at yahoo.com> wrote:
> "Sergey Gromov" wrote
>> You don't mention here which iterator usage pattern you are trying to
>> model with ranges. I can think of at least two.
>>
>> 1. You use a single bidirectional 'center' iterator, center == 5. As
>> one would naturally do with iterators. Note then that whenever you use
>> your center for, say, backward iteration, you reconstruct the actual
>> range by calling list.begin. You do it on each iteration. No wonder it
>> stays valid even if you remove the first element in the meantime: you're
>> constructing your range from scratch anyway. If you want to model this
>> pattern with ranges---no problem, keep an empty 'center' range, center
>> == (5,5), and reconstruct backward iteration range,
>>
>> reverse = all.before(center);
>>
>> whenever you need to iterate, then
>>
>> center = reverse.end;
>>
>> This 'center' range, being slightly less efficient, stays valid and
>> becomes invalid in exactly the same conditions as your classical
>> iterator.
>
> This is exactly the pattern I use. I agree that your example would solve
> the problem, I hadn't thought of an empty range to be a cursor, that is
> clever!
>
> The only missing piece to your solution is that I must construct the range
> after the center range in order to access the value to see where I need to
> go.
>
> What I see as the biggest downside is the cumbersome and verbose code of
> moving the 'iterator' around, as every time I want to move forward, I
> construct a new range, and every time I want to move backwards I construct a
> new range (and construct a new 'center' afterwards). So a 'move back one'
> looks like:
>
> auto before = all.before(center);
> if(!before.isEmpty)
> center = before.pop.end;
>
> And to move forward it's:
> auto after = all.after(center);
> if(!after.isEmpty)
> center = after.next.begin;
Maybe all we need to neatly support this sliding cursor idiom is just
some functions in the std lib:
bool cursorRetreat(R)(R all, ref R center)
{
auto before = all.before(center);
if(!before.isEmpty) {
center = before.pop.end;
return true;
}
return false;
}
bool cursorAdvance(R)(R all, ref R center)
{
auto after = all.after(center);
if(!after.isEmpty) {
center = after.next.begin;
return true;
}
return false
}
> To get the value there, I have to do:
> all.after(center).left // or whatever gets decided as the 'get first value
> of range' member
> or if opStar is used:
>
> *all.after(center);
Why is all that necessary? Can't you just do a *center?
>
> I much prefer:
>
> forward:
> if(center != list.end)
> ++center;
>
> reverse:
> if(center != list.begin)
> --center;
>
> get value:
> *center;
With the functions it becomes
forward:
cursorAdance(list,center);
reverse:
cursorRetreat(list,center);
get value:
*center -- this works doesn't it?
> Especially without all the extra overhead
Since we haven't really come up with any examples where the speed with
which you can slide back and forth would make a whit of difference,
perhaps the extra overhead is a non-issue.
> I see both methods as being just as open to mistakes, the first more-so, and
> more difficult to comprehend (at least for me).
I'm optimistic that this use case can also be covered by some well
chosen std library functions, similar to the above.
--bb
More information about the Digitalmars-d-announce
mailing list