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", "")