From 40c1cea06d27187066d0ef78700a7db12060f33c Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 8 Aug 2022 13:29:14 +0200 Subject: [PATCH] Implement `views::as_rvalue` --- stl/inc/ranges | 118 ++++++++++++++++++ stl/inc/yvals_core.h | 2 + .../test.compile.pass.cpp | 14 +++ 3 files changed, 134 insertions(+) diff --git a/stl/inc/ranges b/stl/inc/ranges index 1042b83e085..2dfe880572b 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -1627,6 +1627,124 @@ namespace ranges { using all_t = decltype(all(_STD declval<_Rng>())); } // namespace views +#if _HAS_CXX23 + template + requires view<_Vw> + class as_rvalue_view : public view_interface> { + private: + /* [[no_unique_address]] */ _Vw _Range{}; + + template + static constexpr bool _Is_end_nothrow_v = noexcept(move_sentinel{_RANGES end(_STD declval<_Rng>())}); + + template + static constexpr bool _Is_end_nothrow_v<_Rng> = noexcept(move_iterator{_RANGES end(_STD declval<_Rng>())}); + + public: + // clang-format off + as_rvalue_view() requires default_initializable<_Vw> = default; + // clang-format on + + constexpr explicit as_rvalue_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened + : _Range(_STD move(_Range_)) {} + + _NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened + requires copy_constructible<_Vw> { + return _Range; + } + + _NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ { + return _STD move(_Range); + } + + _NODISCARD constexpr auto begin() noexcept(noexcept(move_iterator{_RANGES begin(_Range)})) // strengthened + requires(!_Simple_view<_Vw>) { + return move_iterator{_RANGES begin(_Range)}; + } + + _NODISCARD constexpr auto begin() const noexcept(noexcept(move_iterator{_RANGES begin(_Range)})) // strengthened + requires range { + return move_iterator{_RANGES begin(_Range)}; + } + + _NODISCARD constexpr auto end() noexcept(_Is_end_nothrow_v<_Vw>) // strengthened + requires(!_Simple_view<_Vw>) { + if constexpr (common_range<_Vw>) { + return move_iterator{_RANGES end(_Range)}; + } else { + return move_sentinel{_RANGES end(_Range)}; + } + } + + _NODISCARD constexpr auto end() const noexcept(_Is_end_nothrow_v) // strengthened + requires range { + if constexpr (common_range) { + return move_iterator{_RANGES end(_Range)}; + } else { + return move_sentinel{_RANGES end(_Range)}; + } + } + + _NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) // strengthened + requires sized_range<_Vw> { + return _RANGES size(_Range); + } + + _NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) // strengthened + requires sized_range { + return _RANGES size(_Range); + } + }; + + template + as_rvalue_view(_Rng&&) -> as_rvalue_view>; + + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; + + namespace views { + template + concept _Can_as_rvalue = requires(_Rng&& __r) { + as_rvalue_view{static_cast<_Rng&&>(__r)}; + }; + + struct _As_rvalue_fn : _Pipe::_Base<_As_rvalue_fn> { + private: + enum class _St { _None, _All, _As_rvalue }; + + template + _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + if constexpr (same_as, range_reference_t<_Rng>>) { + return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))}; + } else if constexpr (_Can_as_rvalue<_Rng>) { + return {_St::_As_rvalue, noexcept(as_rvalue_view{_STD declval<_Rng>()})}; + } else { + return {_St::_None}; + } + } + + template + static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>(); + + public: + template + requires(_Choice<_Rng>._Strategy != _St::_None) + _NODISCARD constexpr auto operator()(_Rng&& _Range) const noexcept(_Choice<_Rng>._No_throw) { + constexpr _St _Strat = _Choice<_Rng>._Strategy; + if constexpr (_Strat == _St::_All) { + return views::all(_STD forward<_Rng>(_Range)); + } else if constexpr (_Strat == _St::_As_rvalue) { + return as_rvalue_view{_STD forward<_Rng>(_Range)}; + } else { + static_assert(_Always_false<_Rng>, "Should be unreachable"); + } + } + }; + + inline constexpr _As_rvalue_fn as_rvalue; + } // namespace views +#endif // _HAS_CXX23 + template > _Pr> requires view<_Vw> && is_object_v<_Pr> class filter_view : public _Cached_position_t, _Vw, filter_view<_Vw, _Pr>> { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 7999917eb91..bd4b98f5069 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -328,6 +328,7 @@ // P2442R1 Windowing Range Adaptors: views::chunk, views::slide // P2443R1 views::chunk_by // P2445R1 forward_like() +// P2446R2 views::as_rvalue // P2499R0 string_view Range Constructor Should Be explicit // P2549R0 unexpected::error() @@ -1509,6 +1510,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #ifdef __cpp_lib_concepts #define __cpp_lib_out_ptr 202106L +#define __cpp_lib_ranges_as_rvalue 202207L #define __cpp_lib_ranges_chunk 202202L #define __cpp_lib_ranges_chunk_by 202202L #define __cpp_lib_ranges_contains 202207L diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 2a5739948f7..480725af8da 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -1440,6 +1440,20 @@ STATIC_ASSERT(__cpp_lib_ranges == 202110L); #endif #endif +#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 +#ifndef __cpp_lib_ranges_as_rvalue +#error __cpp_lib_ranges_as_rvalue is not defined +#elif __cpp_lib_ranges_as_rvalue != 202207L +#error __cpp_lib_ranges_as_rvalue is not 202207L +#else +STATIC_ASSERT(__cpp_lib_ranges_as_rvalue == 202207L); +#endif +#else +#ifdef __cpp_lib_ranges_as_rvalue +#error __cpp_lib_ranges_as_rvalue is defined +#endif +#endif + #if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 #ifndef __cpp_lib_ranges_chunk #error __cpp_lib_ranges_chunk is not defined