RFC on SlidingSplitter Range

monarch_dodra via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri Oct 3 10:46:16 PDT 2014


On Friday, 3 October 2014 at 17:06:41 UTC, Nordlöw wrote:
> On Friday, 3 October 2014 at 16:32:24 UTC, monarch_dodra wrote:
>> If anything, I'd have expected you to provide something 
>> returns the popped element. What you do pops an element, and 
>> then returns the *next* one. What good is that?
>
> My mistake. It's fixed now.

Well, yes and no. You are still providing a moveFront that does 
not conform to what the range interface expects. EG:

auto app = appender();
auto myRange = slidingSplitter([1, 2, 3]);
for ( ; !myRange.empty ; myRange.popFront() )
   app.put(myRange.moveFront());

As you can see from this code snippet, moveFront is not expected 
to pop. At all. As a matter of fact, this will error out during 
runtime, as the loop will attempt a pop on an empty range.

IMO, you should just leave it out.

>> Also, what you want to check is "hasSlicing", which is more 
>> powerful than "isRA". Speaking of which, if you don't have 
>> "isRA", it looks like your range errors out (no "front").
>
> Ok. Fixed know.

There's still the issue that if you don't have slicing, then your 
range doesn't have "front" at all. You might as well just make it 
a general template restriction.

>> Your sliding splitter does not handle narrow strings. I'd have 
>> thought that was the original goal. Well, it is better to not 
>> support it at all of course, rather than doing it wrong :)
>
> That's part of episode 2, for now ;)

Cool.

More things I saw:
Don't make opIndex const. You have no guarantee R.opindex is 
const.
Also, "opSlice()" is not a range primitive. You can implement it, 
it's basically just a no-op. The one that's important is 
"opSlice(lhs, rhs)".

Also, no point in returning an "auto ref" from "slidingSplitter", 
you *know* it's an rvalue.

If your implementation use two ranges that you slice "on the 
fly", then you can trivially support strings, thanks to popFront.

I threw this together. I left out checks for infinity in favor of 
brevity:

//----
import std.range, std.stdio;
import std.typecons: Tuple, tuple;

struct SlidingSplitter(R)
if (hasSlicing!R || isSomeString!R)
{
     this(R)(R data)
     {
         _original = data;
         _right = data.save;
     }

     auto front() @property
     {
         return tuple(_original[0 .. $ - _right.length], _right);
     }

     void popFront()
     {
         if (_right.empty)
             _original = _right;
         else
             _right.popFront();
     }

     bool empty() const { return _original.empty; }

     static if (hasSlicing!R)
     {
         auto opIndex(size_t i)
         {
             return tuple(
                 _original[0 .. i + $ - _right.length],
                 _right[i .. $]);
         }

         size_t length() { return _right.length + 1; }
     }

     private R _original;
     private R _right;
}

auto slidingSplitter(R)(R data)
{
     return SlidingSplitter!R(data);
}

void main()
{
     {
         auto r = slidingSplitter([1, 2, 3]);
         writefln("r.length: %s", r.length);
         writefln("r[1]: %s", r[1]);
         writefln("r[2]: %s", r[2]);
     }
     {
         writefln("%(%s\n%)", slidingSplitter("Nordlöw"));
     }
}
//----

Output:

r.length: 4
r[1]: Tuple!(int[], int[])([1], [2, 3])
r[2]: Tuple!(int[], int[])([1, 2], [3])
Tuple!(string, string)("", "Nordlöw")
Tuple!(string, string)("N", "ordlöw")
Tuple!(string, string)("No", "rdlöw")
Tuple!(string, string)("Nor", "dlöw")
Tuple!(string, string)("Nord", "löw")
Tuple!(string, string)("Nordl", "öw")
Tuple!(string, string)("Nordlö", "w")
Tuple!(string, string)("Nordlöw", "")


More information about the Digitalmars-d-learn mailing list