mirror of
https://github.com/dlang/phobos.git
synced 2025-05-06 11:07:39 +03:00
Bug 2903: Splitter should be bi-dir if the input range is bi-dir (Single-character separator version, since range separator version was fixed a long time ago. Excluded terminator version b/c it's not documented/officially part of Phobos yet and there are issues w/ including an empty range if the last character is the terminator that need to be resolved first.)
This commit is contained in:
parent
75705bc9e7
commit
d316980220
1 changed files with 90 additions and 2 deletions
|
@ -1129,6 +1129,16 @@ private:
|
|||
Separator _separator;
|
||||
enum size_t _unComputed = size_t.max - 1, _atEnd = size_t.max;
|
||||
size_t _frontLength = _unComputed;
|
||||
size_t _backLength = _unComputed;
|
||||
|
||||
static if(isBidirectionalRange!Range)
|
||||
{
|
||||
static int lastIndexOf(Range haystack, Separator needle)
|
||||
{
|
||||
immutable index = indexOf(retro(haystack), needle);
|
||||
return (index == -1) ? -1 : haystack.length - 1 - index;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
this(Range input, Separator separator)
|
||||
|
@ -1174,6 +1184,9 @@ public:
|
|||
{
|
||||
// no more input and need to fetch => done
|
||||
_frontLength = _atEnd;
|
||||
|
||||
// Probably don't need this, but just for consistency:
|
||||
_backLength = _atEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1192,6 +1205,56 @@ public:
|
|||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static if(isBidirectionalRange!Range)
|
||||
{
|
||||
@property Range back()
|
||||
{
|
||||
assert(!empty);
|
||||
if (_backLength == _unComputed)
|
||||
{
|
||||
immutable lastIndex = lastIndexOf(_input, _separator);
|
||||
if(lastIndex == -1)
|
||||
{
|
||||
_backLength = _input.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
_backLength = _input.length - lastIndex - 1;
|
||||
}
|
||||
}
|
||||
return _input[_input.length - _backLength .. _input.length];
|
||||
}
|
||||
|
||||
void popBack()
|
||||
{
|
||||
assert(!empty);
|
||||
if (_backLength == _unComputed)
|
||||
{
|
||||
back;
|
||||
}
|
||||
assert(_backLength <= _input.length);
|
||||
if (_backLength == _input.length)
|
||||
{
|
||||
// no more input and need to fetch => done
|
||||
_frontLength = _atEnd;
|
||||
_backLength = _atEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
_input = _input[0 .. _input.length - _backLength];
|
||||
if(!_input.empty && _input.back == _separator)
|
||||
{
|
||||
_input.popBack();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
_backLength = _unComputed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
|
@ -1224,14 +1287,39 @@ unittest
|
|||
a = [ 0, 1 ];
|
||||
assert(equal(splitter(a, 0), [ [], [1] ][]));
|
||||
|
||||
// Thoroughly exercise the bidirectional stuff.
|
||||
auto str = "abc abcd abcde ab abcdefg abcdefghij ab ac ar an at ada";
|
||||
assert(equal(
|
||||
retro(splitter(str, 'a')),
|
||||
retro(array(splitter(str, 'a')))
|
||||
));
|
||||
|
||||
// Test interleaving front and back.
|
||||
auto split = splitter(str, 'a');
|
||||
assert(split.front == "");
|
||||
assert(split.back == "");
|
||||
split.popBack();
|
||||
assert(split.back == "d");
|
||||
split.popFront();
|
||||
assert(split.front == "bc ");
|
||||
assert(split.back == "d");
|
||||
split.popFront();
|
||||
split.popBack();
|
||||
assert(split.back == "t ");
|
||||
split.popBack();
|
||||
split.popBack();
|
||||
split.popFront();
|
||||
split.popFront();
|
||||
assert(split.front == "b ");
|
||||
assert(split.back == "r ");
|
||||
|
||||
foreach(DummyType; AllDummyRanges) { // Bug 4408
|
||||
static if(isRandomAccessRange!DummyType) {
|
||||
static assert(isBidirectionalRange!DummyType);
|
||||
DummyType d;
|
||||
auto s = splitter(d, 5);
|
||||
assert(equal(s.front, [1,2,3,4]));
|
||||
s.popFront();
|
||||
assert(equal(s.front, [6,7,8,9,10]));
|
||||
assert(equal(s.back, [6,7,8,9,10]));
|
||||
|
||||
|
||||
auto s2 = splitter(d, [4, 5]);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue