public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-3768] libstdc++: Relax range adaptors for move-only types (P2494R2)
@ 2023-09-07 7:11 Jonathan Wakely
0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2023-09-07 7:11 UTC (permalink / raw)
To: gcc-cvs, libstdc++-cvs
https://gcc.gnu.org/g:9f41791eff82d5f41f16204cf092b7888b6c7a8d
commit r14-3768-g9f41791eff82d5f41f16204cf092b7888b6c7a8d
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue Sep 5 22:07:22 2023 +0100
libstdc++: Relax range adaptors for move-only types (P2494R2)
This is a C++23 feature that relaxes the constraints on some range
adaptors, to support move-only types.
libstdc++-v3/ChangeLog:
* include/bits/version.def (ranges): Update value.
* include/bits/version.h: Regenerate.
* include/std/ranges (__detail::__boxable): Use
move_constructible instead of copy_constructible for C++23.
(__detail::__box<T>): Adjust constraints for partial
specialization.
(single_view, transform_view): Use __box_constructible instead
of copy_constructible in constraints.
(zip_transform_view, adjacent_transform_view, repeat_view): Use
move_constructible instead of copy_constructible in constraints.
* testsuite/std/ranges/adaptors/adjacent_transform/1.cc: Check
construction from move-only argument.
* testsuite/std/ranges/adaptors/transform.cc: Likewise.
* testsuite/std/ranges/repeat/1.cc: Likewise.
* testsuite/std/ranges/single_view.cc: Likewise.
* testsuite/std/ranges/zip_transform/1.cc: Likewise.
* testsuite/std/ranges/version_c++23.cc: Adjust expected value
of __cpp_lib_ranges.
Diff:
---
libstdc++-v3/include/bits/version.def | 2 +-
libstdc++-v3/include/bits/version.h | 4 +-
libstdc++-v3/include/std/ranges | 72 +++++++++++++++-------
.../std/ranges/adaptors/adjacent_transform/1.cc | 14 +++++
.../testsuite/std/ranges/adaptors/transform.cc | 19 ++++++
libstdc++-v3/testsuite/std/ranges/repeat/1.cc | 12 ++++
libstdc++-v3/testsuite/std/ranges/single_view.cc | 17 +++++
libstdc++-v3/testsuite/std/ranges/version_c++23.cc | 2 +-
.../testsuite/std/ranges/zip_transform/1.cc | 14 +++++
9 files changed, 131 insertions(+), 25 deletions(-)
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 80c13d4a447e..44b916e38974 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1045,7 +1045,7 @@ ftms = {
ftms = {
name = ranges;
values = {
- v = 202202;
+ v = 202207;
cxxmin = 23;
extra_cond = "__glibcxx_concepts";
};
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 5bddb4b8adc6..9fada98eee3f 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1290,9 +1290,9 @@
// from version.def line 1046
#if !defined(__cpp_lib_ranges)
# if (__cplusplus >= 202302L) && (__glibcxx_concepts)
-# define __glibcxx_ranges 202202L
+# define __glibcxx_ranges 202207L
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges)
-# define __cpp_lib_ranges 202202L
+# define __cpp_lib_ranges 202207L
# endif
# elif (__cplusplus >= 202002L) && (__glibcxx_concepts)
# define __glibcxx_ranges 202110L
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 3477323d8711..1d529a886bec 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -106,8 +106,14 @@ namespace ranges
namespace __detail
{
+#if __cpp_lib_ranges >= 202207L // C++ >= 23
+ // P2494R2 Relaxing range adaptors to allow for move only types
+ template<typename _Tp>
+ concept __boxable = move_constructible<_Tp> && is_object_v<_Tp>;
+#else
template<typename _Tp>
concept __boxable = copy_constructible<_Tp> && is_object_v<_Tp>;
+#endif
template<__boxable _Tp>
struct __box : std::optional<_Tp>
@@ -132,7 +138,7 @@ namespace ranges
constexpr __box&
operator=(const __box& __that)
noexcept(is_nothrow_copy_constructible_v<_Tp>)
- requires (!copyable<_Tp>)
+ requires (!copyable<_Tp>) && copy_constructible<_Tp>
{
if (this != std::__addressof(__that))
{
@@ -160,13 +166,22 @@ namespace ranges
}
};
- // For types which are already copyable, this specialization of the
- // copyable wrapper stores the object directly without going through
- // std::optional. It provides just the subset of the primary template's
- // API that we currently use.
+ template<typename _Tp>
+ concept __boxable_copyable
+ = copy_constructible<_Tp>
+ && (copyable<_Tp> || (is_nothrow_move_constructible_v<_Tp>
+ && is_nothrow_copy_constructible_v<_Tp>));
+ template<typename _Tp>
+ concept __boxable_movable
+ = (!copy_constructible<_Tp>)
+ && (movable<_Tp> || is_nothrow_move_constructible_v<_Tp>);
+
+ // For types which are already copyable (or since C++23, movable)
+ // this specialization of the box wrapper stores the object directly
+ // without going through std::optional. It provides just the subset of
+ // the primary template's API that we currently use.
template<__boxable _Tp>
- requires copyable<_Tp> || (is_nothrow_move_constructible_v<_Tp>
- && is_nothrow_copy_constructible_v<_Tp>)
+ requires __boxable_copyable<_Tp> || __boxable_movable<_Tp>
struct __box<_Tp>
{
private:
@@ -178,6 +193,7 @@ namespace ranges
constexpr explicit
__box(const _Tp& __t)
noexcept(is_nothrow_copy_constructible_v<_Tp>)
+ requires copy_constructible<_Tp>
: _M_value(__t)
{ }
@@ -198,12 +214,13 @@ namespace ranges
__box(const __box&) = default;
__box(__box&&) = default;
__box& operator=(const __box&) requires copyable<_Tp> = default;
- __box& operator=(__box&&) requires copyable<_Tp> = default;
+ __box& operator=(__box&&) requires movable<_Tp> = default;
// When _Tp is nothrow_copy_constructible but not copy_assignable,
// copy assignment is implemented via destroy-then-copy-construct.
constexpr __box&
operator=(const __box& __that) noexcept
+ requires (!copyable<_Tp>) && copy_constructible<_Tp>
{
static_assert(is_nothrow_copy_constructible_v<_Tp>);
if (this != std::__addressof(__that))
@@ -217,6 +234,7 @@ namespace ranges
// Likewise for move assignment.
constexpr __box&
operator=(__box&& __that) noexcept
+ requires (!movable<_Tp>)
{
static_assert(is_nothrow_move_constructible_v<_Tp>);
if (this != std::__addressof(__that))
@@ -250,7 +268,12 @@ namespace ranges
} // namespace __detail
/// A view that contains exactly one element.
- template<copy_constructible _Tp> requires is_object_v<_Tp>
+#if __cpp_lib_ranges >= 202207L // C++ >= 23
+ template<move_constructible _Tp>
+#else
+ template<copy_constructible _Tp>
+#endif
+ requires is_object_v<_Tp>
class single_view : public view_interface<single_view<_Tp>>
{
public:
@@ -259,6 +282,7 @@ namespace ranges
constexpr explicit
single_view(const _Tp& __t)
noexcept(is_nothrow_copy_constructible_v<_Tp>)
+ requires copy_constructible<_Tp>
: _M_value(__t)
{ }
@@ -1147,7 +1171,8 @@ namespace views::__adaptor
};
} // namespace views::__adaptor
-#if __cplusplus > 202002L
+#if __cpp_lib_ranges >= 202202L
+ // P2387R3 Pipe support for user-defined range adaptors
template<typename _Derived>
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
class range_adaptor_closure
@@ -1751,7 +1776,11 @@ namespace views::__adaptor
inline constexpr _Filter filter;
} // namespace views
+#if __cpp_lib_ranges >= 202207L // C++ >= 23
+ template<input_range _Vp, move_constructible _Fp>
+#else
template<input_range _Vp, copy_constructible _Fp>
+#endif
requires view<_Vp> && is_object_v<_Fp>
&& regular_invocable<_Fp&, range_reference_t<_Vp>>
&& std::__detail::__can_reference<invoke_result_t<_Fp&,
@@ -4623,7 +4652,7 @@ namespace views::__adaptor
return input_iterator_tag{};
}
- template<copy_constructible _Fp, input_range... _Ws>
+ template<move_constructible _Fp, input_range... _Ws>
requires (view<_Ws> && ...) && (sizeof...(_Ws) > 0) && is_object_v<_Fp>
&& regular_invocable<_Fp&, range_reference_t<_Ws>...>
&& std::__detail::__can_reference<invoke_result_t<_Fp&, range_reference_t<_Ws>...>>
@@ -4894,7 +4923,7 @@ namespace views::__adaptor
= typename iterator_traits<iterator_t<__maybe_const_t<_Const, _Range>>>::iterator_category;
}
- template<copy_constructible _Fp, input_range... _Vs>
+ template<move_constructible _Fp, input_range... _Vs>
requires (view<_Vs> && ...) && (sizeof...(_Vs) > 0) && is_object_v<_Fp>
&& regular_invocable<_Fp&, range_reference_t<_Vs>...>
&& std::__detail::__can_reference<invoke_result_t<_Fp&, range_reference_t<_Vs>...>>
@@ -5001,7 +5030,7 @@ namespace views::__adaptor
template<class _Fp, class... Rs>
zip_transform_view(_Fp, Rs&&...) -> zip_transform_view<_Fp, views::all_t<Rs>...>;
- template<copy_constructible _Fp, input_range... _Vs>
+ template<move_constructible _Fp, input_range... _Vs>
requires (view<_Vs> && ...) && (sizeof...(_Vs) > 0) && is_object_v<_Fp>
&& regular_invocable<_Fp&, range_reference_t<_Vs>...>
&& std::__detail::__can_reference<invoke_result_t<_Fp&, range_reference_t<_Vs>...>>
@@ -5131,7 +5160,7 @@ namespace views::__adaptor
{ return __x._M_inner - __y._M_inner; }
};
- template<copy_constructible _Fp, input_range... _Vs>
+ template<move_constructible _Fp, input_range... _Vs>
requires (view<_Vs> && ...) && (sizeof...(_Vs) > 0) && is_object_v<_Fp>
&& regular_invocable<_Fp&, range_reference_t<_Vs>...>
&& std::__detail::__can_reference<invoke_result_t<_Fp&, range_reference_t<_Vs>...>>
@@ -5338,7 +5367,7 @@ namespace views::__adaptor
friend class adjacent_view;
- template<forward_range _Wp, copy_constructible _Fp, size_t _Mm>
+ template<forward_range _Wp, move_constructible _Fp, size_t _Mm>
requires view<_Wp> && (_Mm > 0) && is_object_v<_Fp>
&& regular_invocable<__detail::__unarize<_Fp&, _Mm>, range_reference_t<_Wp>>
&& std::__detail::__can_reference<invoke_result_t<__detail::__unarize<_Fp&, _Mm>,
@@ -5580,7 +5609,7 @@ namespace views::__adaptor
inline constexpr auto pairwise = adjacent<2>;
}
- template<forward_range _Vp, copy_constructible _Fp, size_t _Nm>
+ template<forward_range _Vp, move_constructible _Fp, size_t _Nm>
requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
&& regular_invocable<__detail::__unarize<_Fp&, _Nm>, range_reference_t<_Vp>>
&& std::__detail::__can_reference<invoke_result_t<__detail::__unarize<_Fp&, _Nm>,
@@ -5650,7 +5679,7 @@ namespace views::__adaptor
{ return _M_inner.size(); }
};
- template<forward_range _Vp, copy_constructible _Fp, size_t _Nm>
+ template<forward_range _Vp, move_constructible _Fp, size_t _Nm>
requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
&& regular_invocable<__detail::__unarize<_Fp&, _Nm>, range_reference_t<_Vp>>
&& std::__detail::__can_reference<invoke_result_t<__detail::__unarize<_Fp&, _Nm>,
@@ -5819,7 +5848,7 @@ namespace views::__adaptor
{ return __x._M_inner - __y._M_inner; }
};
- template<forward_range _Vp, copy_constructible _Fp, size_t _Nm>
+ template<forward_range _Vp, move_constructible _Fp, size_t _Nm>
requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
&& regular_invocable<__detail::__unarize<_Fp&, _Nm>, range_reference_t<_Vp>>
&& std::__detail::__can_reference<invoke_result_t<__detail::__unarize<_Fp&, _Nm>,
@@ -7528,8 +7557,8 @@ namespace views::__adaptor
} // namespace views
#endif // __cpp_lib_ranges_join_with
-#ifdef __cpp_lib_ranges_repeat // C++ >= 32
- template<copy_constructible _Tp, semiregular _Bound = unreachable_sentinel_t>
+#ifdef __cpp_lib_ranges_repeat // C++ >= 23
+ template<move_constructible _Tp, semiregular _Bound = unreachable_sentinel_t>
requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
&& (__detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t>)
class repeat_view : public view_interface<repeat_view<_Tp, _Bound>>
@@ -7552,6 +7581,7 @@ namespace views::__adaptor
constexpr explicit
repeat_view(const _Tp& __value, _Bound __bound = _Bound())
+ requires copy_constructible<_Tp>
: _M_value(__value), _M_bound(__bound)
{
if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
@@ -7594,7 +7624,7 @@ namespace views::__adaptor
template<typename _Tp, typename _Bound>
repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>;
- template<copy_constructible _Tp, semiregular _Bound>
+ template<move_constructible _Tp, semiregular _Bound>
requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
&& (__detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t>)
class repeat_view<_Tp, _Bound>::_Iterator
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
index 07f20b702dd2..c32c639e8154 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
@@ -97,10 +97,24 @@ test03()
return true;
}
+void
+test04()
+{
+ extern int x[5];
+ struct move_only {
+ move_only() { }
+ move_only(move_only&&) { }
+ int operator()(int i, int j) const { return i + j; }
+ };
+ // P2494R2 Relaxing range adaptors to allow for move only types
+ static_assert( requires { views::pairwise_transform(x, move_only{}); } );
+}
+
int
main()
{
static_assert(test01());
static_assert(test02());
static_assert(test03());
+ test04();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
index e89ae4f9f3f2..9d52cb01dadb 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
@@ -175,6 +175,24 @@ test08()
static_assert(!requires { views::all | transform; });
}
+template<auto transform = views::transform>
+void
+test09()
+{
+ extern int x[5];
+ struct move_only {
+ move_only() { }
+ move_only(move_only&&) { }
+ int operator()(int i) const { return i; }
+ };
+#if __cpp_lib_ranges >= 202207L
+ // P2494R2 Relaxing range adaptors to allow for move only types
+ static_assert( requires { transform(x, move_only{}); } );
+#else
+ static_assert( ! requires { transform(x, move_only{}); } );
+#endif
+}
+
int
main()
{
@@ -186,4 +204,5 @@ main()
test06();
test07();
test08();
+ test09();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
index 07b70891042c..c62122c078f3 100644
--- a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
@@ -127,6 +127,17 @@ test05()
ranges::repeat_view<int> r;
}
+void
+test06()
+{
+ struct move_only {
+ move_only() { }
+ move_only(move_only&&) { }
+ };
+ // P2494R2 Relaxing range adaptors to allow for move only types
+ static_assert( requires { views::repeat(move_only{}, 2); } );
+}
+
int
main()
{
@@ -135,4 +146,5 @@ main()
static_assert(test03());
static_assert(test04());
test05();
+ test06();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/single_view.cc b/libstdc++-v3/testsuite/std/ranges/single_view.cc
index 38a3946ca43c..8dfe6bb4bd1d 100644
--- a/libstdc++-v3/testsuite/std/ranges/single_view.cc
+++ b/libstdc++-v3/testsuite/std/ranges/single_view.cc
@@ -123,6 +123,22 @@ test07()
static_assert(!requires { single(uncopyable{}); });
}
+template<auto single = std::views::single>
+void
+test08()
+{
+ struct move_only {
+ move_only() { }
+ move_only(move_only&&) { }
+ };
+#if __cpp_lib_ranges >= 202207L
+ // P2494R2 Relaxing range adaptors to allow for move only types
+ static_assert( requires { single(move_only{}); } );
+#else
+ static_assert( ! requires { single(move_only{}); } );
+#endif
+}
+
int main()
{
test01();
@@ -132,4 +148,5 @@ int main()
test05();
test06();
test07();
+ test08();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/version_c++23.cc b/libstdc++-v3/testsuite/std/ranges/version_c++23.cc
index e8342fa986a8..8e4a8b466aab 100644
--- a/libstdc++-v3/testsuite/std/ranges/version_c++23.cc
+++ b/libstdc++-v3/testsuite/std/ranges/version_c++23.cc
@@ -4,7 +4,7 @@
#include <version>
#if __STDC_HOSTED__
-# if __cpp_lib_ranges != 202202L
+# if __cpp_lib_ranges != 202207L
# error "Feature-test macro __cpp_lib_ranges has wrong value in <version>"
# endif
#endif
diff --git a/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
index 5ea24c578a8b..d858b02f1999 100644
--- a/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/zip_transform/1.cc
@@ -99,10 +99,24 @@ test03()
return true;
}
+void
+test04()
+{
+ extern int x[5];
+ struct move_only {
+ move_only() { }
+ move_only(move_only&&) { }
+ int operator()(int i, int j) const { return i + j; }
+ };
+ // P2494R2 Relaxing range adaptors to allow for move only types
+ static_assert( requires { views::zip_transform(move_only{}, x, x); } );
+}
+
int
main()
{
static_assert(test01());
static_assert(test02());
static_assert(test03());
+ test04();
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2023-09-07 7:11 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-07 7:11 [gcc r14-3768] libstdc++: Relax range adaptors for move-only types (P2494R2) Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).