diff mbox series

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

Message ID 20200227162728.1560094-1-ppalka@redhat.com
State New
Headers show
Series libstdc++: Add missing friend declarations in some range adaptors | expand

Commit Message

Patrick Palka Feb. 27, 2020, 4:27 p.m. UTC
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 relation doesn't need to go both ways
-- we could get away with declaring e.g. friend _Iterator<false>; instead of
friend _Iterator<!_Const>; but the spec and the reference implementations all
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>.
	* std/ranges/adaptors/split.cc: Augment test.
	* std/ranges/adaptors/take.cc: Augment test.
	* std/ranges/adaptors/take_while.cc: Augment test.
	* std/ranges/adaptors/transform.cc: Augment test.
---
 libstdc++-v3/include/std/ranges               |  8 +++++++
 .../testsuite/std/ranges/adaptors/split.cc    | 14 +++++++++++
 .../testsuite/std/ranges/adaptors/take.cc     | 16 +++++++++++++
 .../std/ranges/adaptors/take_while.cc         | 17 ++++++++++++++
 .../std/ranges/adaptors/transform.cc          | 23 +++++++++++++++++++
 5 files changed, 78 insertions(+)

Comments

Jonathan Wakely Feb. 27, 2020, 5:25 p.m. UTC | #1
On 27/02/20 11:27 -0500, Patrick Palka wrote:
>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 relation doesn't need to go both ways
>-- we could get away with declaring e.g. friend _Iterator<false>; instead of
>friend _Iterator<!_Const>; but the spec and the reference implementations all
>seem to use the latter symmetric form anyway.

I think at least one of those friend declarations in the spec was
recently removed, because the class it was in is presented for
exposition only, so doesn't actually need to declare other
non-existent classes as friends. But it's certainly not a problem to
use _Iterator<!_Const> rather than _Iterator<false>.

OK for master, thanks.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 2e3e298adcc..2f08cfd7f16 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1844,6 +1844,7 @@  namespace views
 	    requires indirectly_swappable<_Base_iter>
 	  { return ranges::iter_swap(__x._M_current, __y._M_current); }
 
+	  friend _Iterator<!_Const>;
 	  friend _Sentinel<_Const>;
 	};
 
@@ -1896,6 +1897,8 @@  namespace views
 	  operator-(const _Sentinel& __y, const _Iterator<_Const>& __x)
 	    requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
 	  { return __y.__distance_from(__x); }
+
+	  friend _Sentinel<!_Const>;
 	};
 
       _Vp _M_base = _Vp();
@@ -2001,6 +2004,8 @@  namespace views
 
 	  friend constexpr bool operator==(const _CI& __y, const _Sentinel& __x)
 	  { return __y.count() == 0 || __y.base() == __x._M_end; }
+
+	  friend _Sentinel<!_Const>;
 	};
 
       _Vp _M_base = _Vp();
@@ -2140,6 +2145,8 @@  namespace views
 	  friend constexpr bool
 	  operator==(const iterator_t<_Base>& __x, const _Sentinel& __y)
 	  { return __y._M_end == __x || !std::__invoke(*__y._M_pred, *__x); }
+
+	  friend _Sentinel<!_Const>;
 	};
 
       _Vp _M_base = _Vp();
@@ -2831,6 +2838,7 @@  namespace views
 	  operator==(const _OuterIter& __x, default_sentinel_t)
 	  { return __x.__at_end(); };
 
+	  friend _OuterIter<!_Const>;
 	  friend _InnerIter<_Const>;
 	};
 
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
index 52b015cf0c6..e7556725e4f 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
@@ -108,6 +108,19 @@  test05()
 			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
 main()
 {
@@ -116,4 +129,5 @@  main()
   test03();
   test04();
   test05();
+  test06();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
index e2d2edbe0a8..c42505b44cb 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
@@ -19,6 +19,7 @@ 
 // { dg-do run { target c++2a } }
 
 #include <algorithm>
+#include <forward_list>
 #include <ranges>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
@@ -85,6 +86,20 @@  test04()
   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
 main()
 {
@@ -92,4 +107,5 @@  main()
   test02();
   test03();
   test04();
+  test05();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
index b261ffd1aae..d587127b97e 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
@@ -19,6 +19,7 @@ 
 // { dg-do run { target c++2a } }
 
 #include <algorithm>
+#include <forward_list>
 #include <ranges>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
@@ -54,9 +55,25 @@  test02()
   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
 main()
 {
   test01();
   test02();
+  test03();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
index 178544d6378..c14e36e0cef 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
@@ -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
 main()
 {
@@ -107,4 +129,5 @@  main()
   test02();
   test03();
   test04();
+  test05();
 }