libstdc++: Implement P2210 changes to split_view resolving LWG 3478

This implements the part of P2210R2 "Superior String Splitting" that
resolves LWG 3478.

libstdc++-v3/ChangeLog:

	* include/std/ranges (split_view::_OuterIter::__at_end):
	Check _M_trailing_empty.
	(split_view::_OuterIter::_M_trailing_empty): Define this
	data member.
	(split_view::_OuterIter::operator++): Set _M_trailing_empty
	appropriately.
	(split_view::_OuterIter::operator==): Compare
	_M_trailing_empty.
	* testsuite/std/ranges/adaptors/100479.cc (test03): Expect two
	split parts instead of one.
	* testsuite/std/ranges/adaptors/split.cc (test11): New test.
This commit is contained in:
Patrick Palka 2021-06-20 12:38:43 -04:00
parent 85a594f7dc
commit 3f631671f1
3 changed files with 40 additions and 7 deletions

View File

@ -2879,7 +2879,7 @@ namespace views::__adaptor
constexpr bool
__at_end() const
{ return __current() == ranges::end(_M_parent->_M_base); }
{ return __current() == ranges::end(_M_parent->_M_base) && !_M_trailing_empty; }
// [range.split.outer] p1
// Many of the following specifications refer to the notional member
@ -2909,6 +2909,7 @@ namespace views::__adaptor
[[no_unique_address]]
__detail::__maybe_present_t<forward_range<_Vp>,
iterator_t<_Base>> _M_current;
bool _M_trailing_empty = false;
public:
using iterator_concept = conditional_t<forward_range<_Base>,
@ -2971,7 +2972,10 @@ namespace views::__adaptor
// 3505. split_view::outer-iterator::operator++ misspecified
const auto __end = ranges::end(_M_parent->_M_base);
if (__current() == __end)
return *this;
{
_M_trailing_empty = false;
return *this;
}
const auto [__pbegin, __pend] = subrange{_M_parent->_M_pattern};
if (__pbegin == __pend)
++__current();
@ -2980,7 +2984,11 @@ namespace views::__adaptor
__current() = ranges::find(std::move(__current()), __end,
*__pbegin);
if (__current() != __end)
++__current();
{
++__current();
if (__current() == __end)
_M_trailing_empty = true;
}
}
else
do
@ -2990,6 +2998,8 @@ namespace views::__adaptor
if (__p == __pend)
{
__current() = __b;
if (__current() == __end)
_M_trailing_empty = true;
break;
}
} while (++__current() != __end);
@ -3012,7 +3022,10 @@ namespace views::__adaptor
friend constexpr bool
operator==(const _OuterIter& __x, const _OuterIter& __y)
requires forward_range<_Base>
{ return __x._M_current == __y._M_current; }
{
return __x._M_current == __y._M_current
&& __x._M_trailing_empty == __y._M_trailing_empty;
}
friend constexpr bool
operator==(const _OuterIter& __x, default_sentinel_t)

View File

@ -95,11 +95,11 @@ test03()
| views::drop_while([](auto) { return false; })
| views::filter([](auto) { return true; });
static_assert(ranges::forward_range<decltype(v)>);
VERIFY( ranges::next(v.begin()) == v.end() );
VERIFY( ranges::distance(v) == 2 );
auto w = v;
VERIFY( ranges::next(w.begin()) == w.end() );
VERIFY( ranges::distance(v) == 2 );
auto z = std::move(w);
VERIFY( ranges::next(z.begin()) == z.end() );
VERIFY( ranges::distance(v) == 2 );
return true;
}

View File

@ -193,6 +193,25 @@ test10()
VERIFY( ranges::equal(v, (std::string_view[]){"x", "x"}) );
}
void
test11()
{
// LWG 3478
auto v = views::split("text"sv, "text"sv);
auto i = v.begin();
VERIFY( ranges::empty(*i++) );
VERIFY( ranges::empty(*i++) );
VERIFY( i == v.end() );
static_assert(ranges::distance(views::split(" text "sv, ' ')) == 3);
static_assert(ranges::distance(views::split(" t e x t "sv, ' ')) == 6);
static_assert(ranges::distance(views::split(" text "sv, " "sv)) == 3);
static_assert(ranges::distance(views::split(" text "sv, " "sv)) == 4);
static_assert(ranges::distance(views::split(" text "sv, " "sv)) == 4);
static_assert(ranges::distance(views::split("t"sv, 't')) == 2);
static_assert(ranges::distance(views::split("text"sv, ""sv)) == 4);
}
int
main()
{
@ -206,4 +225,5 @@ main()
test08();
test09();
test10();
test11();
}