diff mbox series

libstdc++: Define std::ranges::to for C++23 (P1206R7) [PR111055]

Message ID 20231117155300.1513586-1-jwakely@redhat.com
State New
Headers show
Series libstdc++: Define std::ranges::to for C++23 (P1206R7) [PR111055] | expand

Commit Message

Jonathan Wakely Nov. 17, 2023, 3:49 p.m. UTC
This needs tests, and doesn't include the changes to the standard
containers to add insert_range etc. (but they work with ranges::to
anyway, using the existing member functions).

I plan to write the tests and push this tomorrow.

I've trimmed the boring bits of the version.h changes, that are caused
just by reordering some existing entries to be in alphabetical order.

-- >8 --

libstdc++-v3/ChangeLog:

	PR libstdc++/111055
	* include/bits/ranges_base.h (from_range_t): Define new tag
	type.
	(from_range): Define new tag object.
	* include/bits/version.def (ranges_to_container): Define.
	* include/bits/version.h: Regenerate.
	* include/std/ranges (ranges::to): Define.
---
 libstdc++-v3/include/bits/ranges_base.h |   6 +
 libstdc++-v3/include/bits/version.def   |  34 ++-
 libstdc++-v3/include/bits/version.h     | 111 +++++-----
 libstdc++-v3/include/std/ranges         | 279 +++++++++++++++++++++++-
 4 files changed, 371 insertions(+), 59 deletions(-)
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
index 7fa43d1965a..555065b4ed7 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -37,6 +37,7 @@ 
 #include <bits/stl_iterator.h>
 #include <ext/numeric_traits.h>
 #include <bits/max_size_type.h>
+#include <bits/version.h>
 
 #ifdef __cpp_lib_concepts
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -1057,6 +1058,11 @@  namespace ranges
 						iterator_t<_Range>,
 						dangling>;
 
+#if __glibcxx_ranges_to_container // C++ >= 23
+  struct from_range_t { explicit from_range_t() = default; };
+  inline constexpr from_range_t from_range{};
+#endif
+
 } // namespace ranges
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 447fdeb9519..15bd502f52c 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1370,19 +1370,21 @@  ftms = {
   };
 };
 
-ftms = {
-  name = to_underlying;
-  values = {
-    v = 202102;
-    cxxmin = 23;
-  };
-};
+//ftms = {
+//  name = container_ranges;
+//  values = {
+//    v = 202202;
+//    cxxmin = 23;
+//    hosted = yes;
+//  };
+//};
 
 ftms = {
-  name = unreachable;
+  name = ranges_to_container;
   values = {
     v = 202202;
     cxxmin = 23;
+    hosted = yes;
   };
 };
 
@@ -1614,6 +1616,22 @@  ftms = {
   };
 };
 
+ftms = {
+  name = to_underlying;
+  values = {
+    v = 202102;
+    cxxmin = 23;
+  };
+};
+
+ftms = {
+  name = unreachable;
+  values = {
+    v = 202202;
+    cxxmin = 23;
+  };
+};
+
 ftms = {
   name = fstream_native_handle;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 97c6d8508f4..9563b6cd2f7 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1658,29 +1658,18 @@ 
 #endif /* !defined(__cpp_lib_reference_from_temporary) && defined(__glibcxx_want_reference_from_temporary) */
 #undef __glibcxx_want_reference_from_temporary
 
-// from version.def line 1374
-#if !defined(__cpp_lib_to_underlying)
-# if (__cplusplus >= 202100L)
-#  define __glibcxx_to_underlying 202102L
-#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_underlying)
-#   define __cpp_lib_to_underlying 202102L
+// from version.def line 1383
+#if !defined(__cpp_lib_ranges_to_container)
+# if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
+#  define __glibcxx_ranges_to_container 202202L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_to_container)
+#   define __cpp_lib_ranges_to_container 202202L
 #  endif
 # endif
-#endif /* !defined(__cpp_lib_to_underlying) && defined(__glibcxx_want_to_underlying) */
-#undef __glibcxx_want_to_underlying
+#endif /* !defined(__cpp_lib_ranges_to_container) && defined(__glibcxx_want_ranges_to_container) */
+#undef __glibcxx_want_ranges_to_container
 
-// from version.def line 1382
-#if !defined(__cpp_lib_unreachable)
-# if (__cplusplus >= 202100L)
-#  define __glibcxx_unreachable 202202L
-#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_unreachable)
-#   define __cpp_lib_unreachable 202202L
-#  endif
-# endif
-#endif /* !defined(__cpp_lib_unreachable) && defined(__glibcxx_want_unreachable) */
-#undef __glibcxx_want_unreachable
-
-// from version.def line 1390
+// from version.def line 1392
 #if !defined(__cpp_lib_ranges_zip)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_zip 202110L
@@ -1977,7 +1966,29 @@ 
 #endif /* !defined(__cpp_lib_string_resize_and_overwrite) && defined(__glibcxx_want_string_resize_and_overwrite) */
 #undef __glibcxx_want_string_resize_and_overwrite
 
-// from version.def line 1618
+// from version.def line 1620
+#if !defined(__cpp_lib_to_underlying)
+# if (__cplusplus >= 202100L)
+#  define __glibcxx_to_underlying 202102L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_underlying)
+#   define __cpp_lib_to_underlying 202102L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_to_underlying) && defined(__glibcxx_want_to_underlying) */
+#undef __glibcxx_want_to_underlying
+
+// from version.def line 1628
+#if !defined(__cpp_lib_unreachable)
+# if (__cplusplus >= 202100L)
+#  define __glibcxx_unreachable 202202L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_unreachable)
+#   define __cpp_lib_unreachable 202202L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_unreachable) && defined(__glibcxx_want_unreachable) */
+#undef __glibcxx_want_unreachable
+
+// from version.def line 1636
 #if !defined(__cpp_lib_fstream_native_handle)
 # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
 #  define __glibcxx_fstream_native_handle 202306L
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 26d6c013ad0..fcc0a786091 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -64,6 +64,7 @@ 
 #define __glibcxx_want_ranges_repeat
 #define __glibcxx_want_ranges_slide
 #define __glibcxx_want_ranges_stride
+#define __glibcxx_want_ranges_to_container
 #define __glibcxx_want_ranges_zip
 #include <bits/version.h>
 
@@ -9213,8 +9214,284 @@  namespace views::__adaptor
 
   namespace views = ranges::views;
 
+#if __cpp_lib_ranges_to_container // C++ >= 23
+namespace ranges
+{
+namespace __detail
+{
+  template<typename _Container>
+    constexpr bool __reservable_container
+      = sized_range<_Container>
+      && requires(_Container& __c, range_size_t<_Container> __n) {
+	__c.reserve(__n);
+	{ __c.capacity() } -> same_as<decltype(__n)>;
+	{ __c.max_size() } -> same_as<decltype(__n)>;
+      };
+
+  template<typename _Container, typename _Ref>
+    constexpr bool __container_insertable
+      = requires(_Container& __c, _Ref&& __ref) {
+	requires (requires { __c.push_back(std::forward<_Ref>(__ref)); }
+	    || requires { __c.insert(__c.end(), std::forward<_Ref>(__ref)); });
+      };
+
+  template<typename _Ref, typename _Container>
+    constexpr auto
+    __container_inserter(_Container& __c)
+    {
+      if constexpr (requires { __c.push_back(std::declval<_Ref>()); })
+	return back_inserter(__c);
+      else
+	return inserter(__c, __c.end());
+    }
+
+  template<typename _Rg>
+    struct _InputIter
+    {
+      using iterator_category = input_iterator_tag;
+      using value_type = range_value_t<_Rg>;
+      using difference_type = ptrdiff_t;
+      using pointer = add_pointer_t<range_reference_t<_Rg>>;
+      using reference = range_reference_t<_Rg>;
+      reference operator*() const;
+      pointer operator->() const;
+      _InputIter& operator++();
+      _InputIter operator++(int);
+      bool operator==(const _InputIter&) const;
+    };
+
+  template<template<typename...> typename _Cont, typename _Rg,
+	   typename... _Args>
+    concept __deduce_expr_1 = requires {
+      _Cont(std::declval<_Rg>(), std::declval<_Args>()...);
+    };
+
+  template<template<typename...> typename _Cont, typename _Rg,
+	   typename... _Args>
+    concept __deduce_expr_2 = requires {
+      _Cont(from_range, std::declval<_Rg>(), std::declval<_Args>()...);
+    };
+
+  template<template<typename...> typename _Cont, typename _Rg,
+	   typename... _Args>
+    concept __deduce_expr_3 = requires(_InputIter<_Rg> __i) {
+      _Cont(std::move(__i), std::move(__i), std::declval<_Args>()...);
+    };
+
+  template<template<typename...> typename _Cont, input_range _Rg,
+	   typename... _Args>
+    using _DeduceExpr1
+      = decltype(_Cont(std::declval<_Rg>(), std::declval<_Args>()...));
+
+  template<template<typename...> typename _Cont, input_range _Rg,
+	   typename... _Args>
+    using _DeduceExpr2
+      = decltype(_Cont(from_range, std::declval<_Rg>(),
+		       std::declval<_Args>()...));
+
+  template<template<typename...> typename _Cont, input_range _Rg,
+	   typename... _Args>
+    using _DeduceExpr3
+      = decltype(_Cont(std::declval<_InputIter<_Rg>>(),
+		       std::declval<_InputIter<_Rg>>(),
+		       std::declval<_Args>()...));
+
+} // namespace __detail
+
+  template<typename _Cont, input_range _Rg, typename... _Args>
+    requires (!view<_Cont>)
+    constexpr _Cont
+    to(_Rg&& __r, _Args&&... __args)
+    {
+      static_assert(!is_const_v<_Cont> && !is_volatile_v<_Cont>);
+      static_assert(is_class_v<_Cont>);
+      if constexpr (!input_range<_Cont>
+	  || convertible_to<range_reference_t<_Rg>, range_value_t<_Cont>>)
+	{
+	  if constexpr (constructible_from<_Cont, _Rg, _Args...>)
+	    return _Cont(std::forward<_Rg>(__r),
+			 std::forward<_Args>(__args)...);
+	  else if constexpr (constructible_from<_Cont, from_range_t, _Rg, _Args...>)
+	    return _Cont(from_range, std::forward<_Rg>(__r),
+			 std::forward<_Args>(__args)...);
+	  else if constexpr (common_range<_Rg>
+	      && derived_from<__iter_category_t<iterator_t<_Rg>>,
+			      input_iterator_tag>
+	      && constructible_from<_Cont, iterator_t<_Rg>, sentinel_t<_Rg>,
+				    _Args...>)
+	    return _Cont(ranges::begin(__r), ranges::end(__r),
+			 std::forward<_Args>(__args)...);
+	  else
+	    {
+	      using __detail::__container_insertable;
+	      using __detail::__reservable_container;
+	      using _RefT = range_reference_t<_Rg>;
+	      static_assert(constructible_from<_Cont, _Args...>);
+	      static_assert(__container_insertable<_Cont, _RefT>);
+	      _Cont __c(std::forward<_Args>(__args)...);
+	      if constexpr (sized_range<_Rg> && __reservable_container<_Cont>)
+		__c.reserve(static_cast<range_size_t<_Cont>>(ranges::size(__r)));
+	      auto __ins = __detail::__container_inserter<_RefT>(__c);
+	      for (auto&& __e : __r)
+		*__ins++ = std::forward<decltype(__e)>(__e);
+	      return __c;
+	    }
+	}
+      else
+	{
+	  static_assert(input_range<range_reference_t<_Rg>>);
+	  return ranges::to<_Cont>(__r | views::transform( // XXX not in scope
+		[]<typename _Elt>(_Elt&& __elem) {
+		  using _ValT = range_value_t<_Cont>;
+		  return ranges::to<_ValT>(std::forward<_Elt>(__elem));
+		}), std::forward<_Args>(__args)...);
+	}
+    }
+
+  template<template<typename...> typename _Cont, input_range _Rg,
+	   typename... _Args>
+    constexpr auto
+    to(_Rg&& __r, _Args&&... __args)
+    {
+      using __detail::_DeduceExpr1;
+      using __detail::_DeduceExpr2;
+      using __detail::_DeduceExpr3;
+      if constexpr (requires { typename _DeduceExpr1<_Cont, _Rg, _Args...>; })
+	return ranges::to<_DeduceExpr1<_Cont, _Rg, _Args...>>(
+	    std::forward<_Rg>(__r), std::forward<_Args>(__args)...);
+      else if constexpr (requires { typename _DeduceExpr2<_Cont, _Rg, _Args...>; })
+	return ranges::to<_DeduceExpr2<_Cont, _Rg, _Args...>>(
+	    std::forward<_Rg>(__r), std::forward<_Args>(__args)...);
+      else if constexpr (requires { typename _DeduceExpr3<_Cont, _Rg, _Args...>; })
+	return ranges::to<_DeduceExpr3<_Cont, _Rg, _Args...>>(
+	    std::forward<_Rg>(__r), std::forward<_Args>(__args)...);
+      else
+	static_assert(false); // Cannot deduce container specialization.
+    }
+
+  template<typename _Cont, typename... _Args>
+    class _ToClosure
+    : public views::__adaptor::_RangeAdaptorClosure<_ToClosure<_Cont, _Args...>>
+    {
+      tuple<decay_t<_Args>...> _M_bound_args;
+
+    public:
+      _ToClosure(_Args&&... __args)
+      : _M_bound_args(std::forward<_Args>(__args)...)
+      { }
+
+      // TODO: use explicit object functions ("deducing this").
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) &
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, _M_bound_args);
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) const &
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, _M_bound_args);
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) &&
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, std::move(_M_bound_args));
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) const &&
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, std::move(_M_bound_args));
+	}
+    };
+
+  template<typename _Cont, typename... _Args>
+    requires (!view<_Cont>)
+    constexpr _ToClosure<_Cont, _Args...>
+    to(_Args&&... __args)
+    { return {std::forward<_Args>(__args)...}; }
+
+  template<template<typename...> typename _Cont, typename... _Args>
+    class _ToClosure2
+    : public views::__adaptor::_RangeAdaptorClosure<_ToClosure2<_Cont, _Args...>>
+    {
+      tuple<decay_t<_Args>...> _M_bound_args;
+
+    public:
+      _ToClosure2(_Args&&... __args)
+      : _M_bound_args(std::forward<_Args>(__args)...)
+      { }
+
+      // TODO: use explicit object functions ("deducing this").
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) &
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, _M_bound_args);
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) const &
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, _M_bound_args);
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) &&
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, std::move(_M_bound_args));
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) const &&
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, std::move(_M_bound_args));
+	}
+    };
+
+  template<template<typename...> typename _Cont, typename... _Args>
+    constexpr _ToClosure2<_Cont, _Args...>
+    to(_Args&&... __args)
+    { return {std::forward<_Args>(__args)...}; }
+} // namespace ranges
+#endif // __cpp_lib_ranges_to_container
+
 _GLIBCXX_END_NAMESPACE_VERSION
-} // namespace
+} // namespace std
 #endif // library concepts
 #endif // C++2a
 #endif /* _GLIBCXX_RANGES */