From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 842283858D3C for ; Fri, 17 Nov 2023 15:53:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 842283858D3C Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 842283858D3C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700236386; cv=none; b=FIVIOvQ8uBKYXGcEsLGIXbcDAhq9Al1ZxQ7djS7u+ooRX7H+6OR8T/yKOBTlcU2MmJHasYmf/WWErFYhhfofMDdLp9RL9a77NRwHbSOFLQKyAUZ7U1r084qxtGIMbnkUDAMqRvAI3UfPaL+TFQHLXKYvg59BxewDtExEtcjHPhc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700236386; c=relaxed/simple; bh=gQXLl6x0nzKD56CXq55jaSrPCesnM8Q3zAnwJ90Oh/E=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=AIkjHGVpRTXRtXgyRzi2dr16StuFivW4Ni0siXCRshWoJ9ZTV3nWDo//oiwnVNBtxYozTnnGTdyZVWXiLPDb7sRFaVXfKcQ2FYUbXitQsAbq8BpfxUFX2Oz1fNpQhfWr9V8mYSWKwk8kXgkpyo6l/AS+sIEoKwmS/HaO2VcWwVc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700236384; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=AEeRFidqmtR8KRiF1NoW/2ERvU6jTB2Wu+r2LOU2m4Q=; b=jAy8AZf+oddqYveVRo8/jEoPi57j1A3W5cVCeloUn8ukttK+uAZ7JYcwjyE7CrUk3MvTuP ewkWZEGuXyooctf9eQAcsNJfRgtzX7p29nqaEjx9G51Z0byD69isOXi+1p9OaXcZU0fWbv cRnCceiff4ptvq0XLx985CD38R9pMfY= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-53-tG1Yh8jJOe-_DVuaC3Mz1A-1; Fri, 17 Nov 2023 10:53:01 -0500 X-MC-Unique: tG1Yh8jJOe-_DVuaC3Mz1A-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 5F8EE185A785; Fri, 17 Nov 2023 15:53:01 +0000 (UTC) Received: from localhost (unknown [10.42.28.9]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0FB6F492BFE; Fri, 17 Nov 2023 15:53:00 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] libstdc++: Define std::ranges::to for C++23 (P1206R7) [PR111055] Date: Fri, 17 Nov 2023 15:49:47 +0000 Message-ID: <20231117155300.1513586-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: 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 --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 #include #include +#include #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 @@ -9213,8 +9214,284 @@ namespace views::__adaptor namespace views = ranges::views; +#if __cpp_lib_ranges_to_container // C++ >= 23 +namespace ranges +{ +namespace __detail +{ + template + constexpr bool __reservable_container + = sized_range<_Container> + && requires(_Container& __c, range_size_t<_Container> __n) { + __c.reserve(__n); + { __c.capacity() } -> same_as; + { __c.max_size() } -> same_as; + }; + + template + 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 + 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 + 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>; + using reference = range_reference_t<_Rg>; + reference operator*() const; + pointer operator->() const; + _InputIter& operator++(); + _InputIter operator++(int); + bool operator==(const _InputIter&) const; + }; + + template typename _Cont, typename _Rg, + typename... _Args> + concept __deduce_expr_1 = requires { + _Cont(std::declval<_Rg>(), std::declval<_Args>()...); + }; + + template typename _Cont, typename _Rg, + typename... _Args> + concept __deduce_expr_2 = requires { + _Cont(from_range, std::declval<_Rg>(), std::declval<_Args>()...); + }; + + template 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 typename _Cont, input_range _Rg, + typename... _Args> + using _DeduceExpr1 + = decltype(_Cont(std::declval<_Rg>(), std::declval<_Args>()...)); + + template typename _Cont, input_range _Rg, + typename... _Args> + using _DeduceExpr2 + = decltype(_Cont(from_range, std::declval<_Rg>(), + std::declval<_Args>()...)); + + template 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 + 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_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>, + 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>(ranges::size(__r))); + auto __ins = __detail::__container_inserter<_RefT>(__c); + for (auto&& __e : __r) + *__ins++ = std::forward(__e); + return __c; + } + } + else + { + static_assert(input_range>); + return ranges::to<_Cont>(__r | views::transform( // XXX not in scope + [](_Elt&& __elem) { + using _ValT = range_value_t<_Cont>; + return ranges::to<_ValT>(std::forward<_Elt>(__elem)); + }), std::forward<_Args>(__args)...); + } + } + + template 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 + class _ToClosure + : public views::__adaptor::_RangeAdaptorClosure<_ToClosure<_Cont, _Args...>> + { + tuple...> _M_bound_args; + + public: + _ToClosure(_Args&&... __args) + : _M_bound_args(std::forward<_Args>(__args)...) + { } + + // TODO: use explicit object functions ("deducing this"). + + template + constexpr auto + operator()(_Rg&& __r) & + { + return std::apply([&__r](_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, _M_bound_args); + } + + template + constexpr auto + operator()(_Rg&& __r) const & + { + return std::apply([&__r](_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, _M_bound_args); + } + + template + constexpr auto + operator()(_Rg&& __r) && + { + return std::apply([&__r](_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, std::move(_M_bound_args)); + } + + template + constexpr auto + operator()(_Rg&& __r) const && + { + return std::apply([&__r](_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, std::move(_M_bound_args)); + } + }; + + template + requires (!view<_Cont>) + constexpr _ToClosure<_Cont, _Args...> + to(_Args&&... __args) + { return {std::forward<_Args>(__args)...}; } + + template typename _Cont, typename... _Args> + class _ToClosure2 + : public views::__adaptor::_RangeAdaptorClosure<_ToClosure2<_Cont, _Args...>> + { + tuple...> _M_bound_args; + + public: + _ToClosure2(_Args&&... __args) + : _M_bound_args(std::forward<_Args>(__args)...) + { } + + // TODO: use explicit object functions ("deducing this"). + + template + constexpr auto + operator()(_Rg&& __r) & + { + return std::apply([&__r](_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, _M_bound_args); + } + + template + constexpr auto + operator()(_Rg&& __r) const & + { + return std::apply([&__r](_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, _M_bound_args); + } + + template + constexpr auto + operator()(_Rg&& __r) && + { + return std::apply([&__r](_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, std::move(_M_bound_args)); + } + + template + constexpr auto + operator()(_Rg&& __r) const && + { + return std::apply([&__r](_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, std::move(_M_bound_args)); + } + }; + + template 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 */ -- 2.41.0