Add missing signature constraints for splitter.

As well as require bidirectional separator with length before assuming
retro(separator) and separator.length will work.

Without these additional constraints, splitter will cause unhelpful
compile errors about being unable instantiate find, when the separator
is a non-forward input range, or when it doesn't have length, or when
it's non-bidirectional. In the latter case, splitter should still work,
just that it won't export a bidirectional interface.
This commit is contained in:
H. S. Teoh 2013-08-07 14:37:25 -07:00
parent 9fab541993
commit cd9696a8e8

View file

@ -2412,7 +2412,9 @@ with string types.
*/
auto splitter(Range, Separator)(Range r, Separator s)
if (is(typeof(Range.init.front == Separator.init.front) : bool)
&& (hasSlicing!Range || isNarrowString!Range))
&& (hasSlicing!Range || isNarrowString!Range)
&& isForwardRange!Separator
&& (hasLength!Separator || isNarrowString!Separator))
{
static struct Result
{
@ -2444,7 +2446,7 @@ if (is(typeof(Range.init.front == Separator.init.front) : bool)
if (_backLength != _backLength.max) return;
assert(!_input.empty);
// compute back length
static if (isBidirectionalRange!Range)
static if (isBidirectionalRange!Range && isBidirectionalRange!Separator)
{
_backLength = _input.length -
find(retro(_input), retro(_separator)).source.length;
@ -2518,7 +2520,7 @@ if (is(typeof(Range.init.front == Separator.init.front) : bool)
}
// Bidirectional functionality as suggested by Brad Roberts.
static if (isBidirectionalRange!Range)
static if (isBidirectionalRange!Range && isBidirectionalRange!Separator)
{
@property Range back()
{
@ -2619,6 +2621,29 @@ unittest
}
}
unittest
{
// Test by-reference separator
class RefSep {
string _impl;
this(string s) { _impl = s; }
@property empty() { return _impl.empty; }
@property auto front() { return _impl.front; }
void popFront() { _impl = _impl[1..$]; }
@property RefSep save() { return new RefSep(_impl); }
@property auto length() { return _impl.length; }
}
auto sep = new RefSep("->");
auto data = "i->am->pointing";
auto words = splitter(data, sep);
auto expected = [ "i", "am", "pointing" ];
foreach (w; words) {
assert(w == expected.front);
expected.popFront();
}
assert(expected.empty);
}
auto splitter(alias isTerminator, Range)(Range input)
if (is(typeof(unaryFun!(isTerminator)(ElementType!(Range).init))))
{