Commit ba49e9eb by Patrick Palka

libstdc++: Add missing friend declarations in some range adaptors

Some of the range adaptors have distinct constant and non-constant
iterator/sentinel types, along with converting constructors that can convert a
non-constant iterator/sentinel to a constant iterator/sentinel.  This patch adds
the missing appropriate friend declarations in order to make these converting
constructors well formed.

Strictly speaking it seems the friendship relations don't need to go both ways
-- we could get away with declaring e.g. friend _Iterator<false>; instead of
friend _Iterator<!_Const>; but both reference implementations seem to use the
latter symmetric form anyway.

libstdc++-v3/ChangeLog:

	* include/std/ranges (transform_view::_Iterator<_Const>): Befriend
	_Iterator<!_Const>.
	(transform_view::_Sentinel<_Const>): Befriend _Sentinel<!_Const>.
	(take_view::_Sentinel<_Const>): Likewise.
	(take_while_view::_Sentinel<_Const>): Likewise.
	(split_view::_OuterIter<_Const>): Befriend _OuterIter<!_Const>.
	* testsuite/std/ranges/adaptors/split.cc: Augment test.
	* testsuite/std/ranges/adaptors/take.cc: Augment test.
	* testsuite/std/ranges/adaptors/take_while.cc: Augment test.
	* testsuite/std/ranges/adaptors/transform.cc: Augment test.
parent 10a32d47
2020-02-27 Patrick Palka <ppalka@redhat.com> 2020-02-27 Patrick Palka <ppalka@redhat.com>
* include/std/ranges (transform_view::_Iterator<_Const>): Befriend
_Iterator<!_Const>.
(transform_view::_Sentinel<_Const>): Befriend _Sentinel<!_Const>.
(take_view::_Sentinel<_Const>): Likewise.
(take_while_view::_Sentinel<_Const>): Likewise.
(split_view::_OuterIter<_Const>): Befriend _OuterIter<!_Const>.
* testsuite/std/ranges/adaptors/split.cc: Augment test.
* testsuite/std/ranges/adaptors/take.cc: Augment test.
* testsuite/std/ranges/adaptors/take_while.cc: Augment test.
* testsuite/std/ranges/adaptors/transform.cc: Augment test.
* testsuite/25_algorithms/copy/constrained.cc: Don't assume that the * testsuite/25_algorithms/copy/constrained.cc: Don't assume that the
base() of a vector<>::iterator is a pointer. base() of a vector<>::iterator is a pointer.
* testsuite/25_algorithms/copy_backward/constrained.cc: Likewise. * testsuite/25_algorithms/copy_backward/constrained.cc: Likewise.
......
...@@ -1759,6 +1759,7 @@ namespace views ...@@ -1759,6 +1759,7 @@ namespace views
requires indirectly_swappable<_Base_iter> requires indirectly_swappable<_Base_iter>
{ return ranges::iter_swap(__x._M_current, __y._M_current); } { return ranges::iter_swap(__x._M_current, __y._M_current); }
friend _Iterator<!_Const>;
friend _Sentinel<_Const>; friend _Sentinel<_Const>;
}; };
...@@ -1811,6 +1812,8 @@ namespace views ...@@ -1811,6 +1812,8 @@ namespace views
operator-(const _Sentinel& __y, const _Iterator<_Const>& __x) operator-(const _Sentinel& __y, const _Iterator<_Const>& __x)
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>> requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
{ return __y.__distance_from(__x); } { return __y.__distance_from(__x); }
friend _Sentinel<!_Const>;
}; };
_Vp _M_base = _Vp(); _Vp _M_base = _Vp();
...@@ -1916,6 +1919,8 @@ namespace views ...@@ -1916,6 +1919,8 @@ namespace views
friend constexpr bool operator==(const _CI& __y, const _Sentinel& __x) friend constexpr bool operator==(const _CI& __y, const _Sentinel& __x)
{ return __y.count() == 0 || __y.base() == __x._M_end; } { return __y.count() == 0 || __y.base() == __x._M_end; }
friend _Sentinel<!_Const>;
}; };
_Vp _M_base = _Vp(); _Vp _M_base = _Vp();
...@@ -2055,6 +2060,8 @@ namespace views ...@@ -2055,6 +2060,8 @@ namespace views
friend constexpr bool friend constexpr bool
operator==(const iterator_t<_Base>& __x, const _Sentinel& __y) operator==(const iterator_t<_Base>& __x, const _Sentinel& __y)
{ return __y._M_end == __x || !std::__invoke(*__y._M_pred, *__x); } { return __y._M_end == __x || !std::__invoke(*__y._M_pred, *__x); }
friend _Sentinel<!_Const>;
}; };
_Vp _M_base = _Vp(); _Vp _M_base = _Vp();
...@@ -2730,6 +2737,7 @@ namespace views ...@@ -2730,6 +2737,7 @@ namespace views
operator==(const _OuterIter& __x, default_sentinel_t) operator==(const _OuterIter& __x, default_sentinel_t)
{ return __x.__at_end(); }; { return __x.__at_end(); };
friend _OuterIter<!_Const>;
friend _InnerIter<_Const>; friend _InnerIter<_Const>;
}; };
......
...@@ -108,6 +108,19 @@ test05() ...@@ -108,6 +108,19 @@ test05()
str | views::filter(not_space_p)) ); str | views::filter(not_space_p)) );
} }
void
test06()
{
std::string str = "hello world";
auto v = str | views::transform(std::identity{}) | views::split(' ');
// Verify that _Iterator<false> is implicitly convertible to _Iterator<true>.
static_assert(!std::same_as<decltype(ranges::begin(v)),
decltype(ranges::cbegin(v))>);
auto b = ranges::cbegin(v);
b = ranges::begin(v);
}
int int
main() main()
{ {
...@@ -116,4 +129,5 @@ main() ...@@ -116,4 +129,5 @@ main()
test03(); test03();
test04(); test04();
test05(); test05();
test06();
} }
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
// { dg-do run { target c++2a } } // { dg-do run { target c++2a } }
#include <algorithm> #include <algorithm>
#include <forward_list>
#include <ranges> #include <ranges>
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
#include <testsuite_iterators.h> #include <testsuite_iterators.h>
...@@ -85,6 +86,20 @@ test04() ...@@ -85,6 +86,20 @@ test04()
VERIFY( ranges::equal(v | views::take(5), (int[]){1,2,3}) ); VERIFY( ranges::equal(v | views::take(5), (int[]){1,2,3}) );
} }
void
test05()
{
std::forward_list<int> x = {1,2,3,4,5};
auto v = x | views::transform(std::negate{}) | views::take(4);
// Verify that _Sentinel<false> is implicitly convertible to _Sentinel<true>.
static_assert(!ranges::common_range<decltype(v)>);
static_assert(!std::same_as<decltype(ranges::end(v)),
decltype(ranges::cend(v))>);
auto b = ranges::cend(v);
b = ranges::end(v);
}
int int
main() main()
{ {
...@@ -92,4 +107,5 @@ main() ...@@ -92,4 +107,5 @@ main()
test02(); test02();
test03(); test03();
test04(); test04();
test05();
} }
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
// { dg-do run { target c++2a } } // { dg-do run { target c++2a } }
#include <algorithm> #include <algorithm>
#include <forward_list>
#include <ranges> #include <ranges>
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
#include <testsuite_iterators.h> #include <testsuite_iterators.h>
...@@ -54,9 +55,25 @@ test02() ...@@ -54,9 +55,25 @@ test02()
static_assert(ranges::forward_range<R>); static_assert(ranges::forward_range<R>);
} }
void
test03()
{
std::forward_list<int> x = {1,2,3,4,5};
auto v
= x | views::transform(std::negate{}) | views::take_while(std::identity{});
// Verify that _Sentinel<false> is implicitly convertible to _Sentinel<true>.
static_assert(!ranges::common_range<decltype(v)>);
static_assert(!std::same_as<decltype(ranges::end(v)),
decltype(ranges::cend(v))>);
auto b = ranges::cend(v);
b = ranges::end(v);
}
int int
main() main()
{ {
test01(); test01();
test02(); test02();
test03();
} }
...@@ -100,6 +100,28 @@ test04() ...@@ -100,6 +100,28 @@ test04()
} }
} }
void
test05()
{
int x[] = {1,2,3,4,5};
auto i = std::counted_iterator(x, 5);
auto r = ranges::subrange{i, std::default_sentinel};
auto v = r | views::transform(std::negate{});
// Verify that _Iterator<false> is implicitly convertible to _Iterator<true>.
static_assert(!std::same_as<decltype(ranges::begin(v)),
decltype(ranges::cbegin(v))>);
auto a = ranges::cbegin(v);
a = ranges::begin(v);
// Verify that _Sentinel<false> is implicitly convertible to _Sentinel<true>.
static_assert(!ranges::common_range<decltype(v)>);
static_assert(!std::same_as<decltype(ranges::end(v)),
decltype(ranges::cend(v))>);
auto b = ranges::cend(v);
b = ranges::end(v);
}
int int
main() main()
{ {
...@@ -107,4 +129,5 @@ main() ...@@ -107,4 +129,5 @@ main()
test02(); test02();
test03(); test03();
test04(); test04();
test05();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment