The rfind challenge
Phil Lavoie
maidenphil at hotmail.com
Tue Jan 15 09:03:06 PST 2013
On Tuesday, 15 January 2013 at 05:51:16 UTC, Andrei Alexandrescu
wrote:
> (Warning: this assumes a fair bit of background with ranges and
> the STL.)
>
> We've had a long-standing weakness of ranges when compared with
> STL iterators: in a find() call we get to access the balance of
> the range from the found position (if any) through the end of
> the initial range. In contrast, STL's find returns an iterator
> that can be combined with the beginning of the initial range or
> the end of the initial range, thus offering two ranges instead
> of one.
>
> D offers the findSplit family which partially deals with this,
> but in an arguably imperfect way because the range from the
> beginning of the initial range to the found element has a
> different type than the initial range.
>
> In spite of that, things have worked out well.
>
> Nowadays I've been thinking (inspired by an exchange on a C=+
> mailing list) that STL's rfind (http://goo.gl/Btg8s) is a real
> challenge for D's ranges.
>
> In D, r.rfind(e) should return a range starting with the last
> occurrence of e in r and spanning through the rest of r.
>
> If r is a forward range but not better, this is rather simple:
>
> R rfind(R, E)(R range, E element)
> {
> for (;;)
> {
> auto ahead = range.save.find(element);
> if (ahead.empty) return range;
> range = ahead;
> }
> }
>
> If the range is random-access, the algorithm is easy to
> implement efficiently by scanning from the end and using
> indexing.
>
> The tricky case is with bidirectional range. I was unable to
> define an algorithm using the current primitives that: (a)
> scans the range from the end, and (b) returns a range from the
> found position through the end.
>
> Looks like rfind() would need one extra primitive for
> bidirectional ranges. What would be a good one? I have a few
> starters, but don't want to bias anyone. Please chime in!
>
>
> Thanks,
>
> Andrei
Interesting problem. One possibility would be to add a CLASS
primitive like this: Range.merge( Range start, Range end )
//Takes the start of the start and the end of end.
Pseudo:
original = range.save
resPos = range.retro.find
return Range.merge( resPos, original ) //DOES NOT WORK
The problem with this solution is that:
Retro returns a different range type and it would be more
complicated to
have the merge function work with this type.
An addition to this solution could be another new primitive:
reverse:
Pseudo:
original = range.save
reversed = range.reverse //Permanently invert start an end. I
think this is feasible for all bidirectional ranges. Still a
bidirectional range.
reversed.find( needle ) //In haystack :)
return Range.merge( reversed, original ) //Ok, start of
reversed is on needle and end of original hasn't moved. The order
of the range returned is the same as the one received.
This is just a suggestion and any primitive could be renamed.
However, I think reverse is a good place to start.
Phil
More information about the Digitalmars-d
mailing list