Fix for popBack/popFront

popBack/popFront works for RoRs starting and/or ending with empty items
This commit is contained in:
vladchicos 2021-08-05 21:53:30 +03:00
parent e32b635f05
commit 7a715fe687

View file

@ -2918,11 +2918,11 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)
{ {
private RoR _items; private RoR _items;
private ElementType!RoR _current; private ElementType!RoR _current;
bool startsWithEmpty = false; bool inputStartsWithEmpty = false;
static if (isBidirectional) static if (isBidirectional)
{ {
private ElementType!RoR _currentBack; private ElementType!RoR _currentBack;
bool endsWithEmpty = false; bool inputEndsWithEmpty = false;
} }
enum isBidirectional = isBidirectionalRange!RoR && enum isBidirectional = isBidirectionalRange!RoR &&
isBidirectionalRange!(ElementType!RoR); isBidirectionalRange!(ElementType!RoR);
@ -3064,14 +3064,14 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)
{ {
if (_currentBack.empty) if (_currentBack.empty)
{ {
endsWithEmpty = true; inputEndsWithEmpty = true;
} }
} }
if (_current.empty) if (_current.empty)
{ {
// No data in the current item - toggle to use the separator // No data in the current item - toggle to use the separator
startsWithEmpty = true; inputStartsWithEmpty = true;
//A range with a single element which is empty will always //A range with a single element which is empty will always
// return an empty Result // return an empty Result
@ -3102,13 +3102,18 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)
return _items.empty; return _items.empty;
} }
@property ElementType!(ElementType!RoR) front() //no data in the first item of the initial range - use the separator
{ private enum useSepIfFrontIsEmpty = q{
if (startsWithEmpty) if (inputStartsWithEmpty)
{ {
useSeparator(); useSeparator();
startsWithEmpty = false; inputStartsWithEmpty = false;
} }
};
@property ElementType!(ElementType!RoR) front()
{
mixin(useSepIfFrontIsEmpty);
if (!_currentSep.empty) return _currentSep.front; if (!_currentSep.empty) return _currentSep.front;
assert(!_current.empty, "Attempting to fetch the front of an empty joiner."); assert(!_current.empty, "Attempting to fetch the front of an empty joiner.");
return _current.front; return _current.front;
@ -3118,6 +3123,8 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)
{ {
assert(!_items.empty, "Attempting to popFront an empty joiner."); assert(!_items.empty, "Attempting to popFront an empty joiner.");
// Using separator? // Using separator?
mixin(useSepIfFrontIsEmpty);
if (!_currentSep.empty) if (!_currentSep.empty)
{ {
_currentSep.popFront(); _currentSep.popFront();
@ -3159,15 +3166,20 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)
static if (isBidirectional) static if (isBidirectional)
{ {
//no data in the last item of the initial range - use the separator
private enum useSepIfBackIsEmpty = q{
if (inputEndsWithEmpty)
{
useBackSeparator;
inputEndsWithEmpty = false;
}
};
private void setBackItem() private void setBackItem()
{ {
if (!_items.empty) if (!_items.empty)
{ {
// If we're exporting .save, we must not consume any of the _currentBack = _items.back.save;
// subranges, since RoR.save does not guarantee that the states
// of the subranges are also saved.
_currentBack = _items.back.save;
} }
} }
@ -3202,11 +3214,8 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)
@property ElementType!(ElementType!RoR) back() @property ElementType!(ElementType!RoR) back()
{ {
if (endsWithEmpty) mixin(useSepIfBackIsEmpty);
{
useBackSeparator;
endsWithEmpty = false;
}
if (!_currentBackSep.empty) return _currentBackSep.front; if (!_currentBackSep.empty) return _currentBackSep.front;
assert(!_currentBack.empty, "Attempting to fetch the back of an empty joiner."); assert(!_currentBack.empty, "Attempting to fetch the back of an empty joiner.");
return _currentBack.back; return _currentBack.back;
@ -3215,6 +3224,9 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)
void popBack() void popBack()
{ {
assert(!_items.empty, "Attempting to popBack an empty joiner."); assert(!_items.empty, "Attempting to popBack an empty joiner.");
mixin(useSepIfBackIsEmpty);
if (!_currentBackSep.empty) if (!_currentBackSep.empty)
{ {
_currentBackSep.popFront(); _currentBackSep.popFront();
@ -3444,6 +3456,49 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)
assert(resFront.equal("../../../abc../")); assert(resFront.equal("../../../abc../"));
assert(resBack.equal("../cba../../../")); assert(resBack.equal("../cba../../../"));
} }
{
auto r = ["", "abc", ""].joiner("./");
auto rCopy = r.save;
r.popBack;
rCopy.popFront;
auto rRev = r.save;
auto rCopyRev = rCopy.save;
char[] r1, r2, r3, r4;
while (!r.empty)
{
r1 ~= r.back;
r.popBack;
}
while (!rCopy.empty)
{
r2 ~= rCopy.front;
rCopy.popFront;
}
while (!rRev.empty)
{
r3 ~= rRev.front;
rRev.popFront;
}
while (!rCopyRev.empty)
{
r4 ~= rCopyRev.back;
rCopyRev.popBack;
}
import std.algorithm.comparison : equal;
assert(r1.equal("/cba./"));
assert(r2.equal("/abc./"));
assert(r3.equal("./abc"));
assert(r4.equal("./cba"));
}
} }
@system unittest @system unittest