From cfb20f17bd17e1cd98ccd8a4517ff3e925cf731c Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 12 Mar 2025 16:09:42 -0400 Subject: [PATCH] libstdc++: Implement P3137R3 views::to_input for C++26 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit libstdc++-v3/ChangeLog: * include/bits/version.def (ranges_to_input): Define. * include/bits/version.h: Regenerate. * include/std/ranges (ranges::to_input_view): Define for C++26. (views::__detail::__can_to_input): Likewise. (views::_ToInput, views::to_input): Likewise. * testsuite/std/ranges/adaptors/to_input/1.cc: New test. Reviewed-by: Tomasz Kamiński Reviewed-by: Jonathan Wakely --- libstdc++-v3/include/bits/version.def | 8 + libstdc++-v3/include/bits/version.h | 10 ++ libstdc++-v3/include/std/ranges | 170 ++++++++++++++++++ .../std/ranges/adaptors/to_input/1.cc | 59 ++++++ 4 files changed, 247 insertions(+) create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 56638759539..1468c0491b7 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1911,6 +1911,14 @@ ftms = { }; }; +ftms = { + name = ranges_to_input; + values = { + v = 202502; + cxxmin = 26; + }; +}; + ftms = { name = to_string; values = { diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 29e1535298c..f7c9849893d 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -2120,6 +2120,16 @@ #endif /* !defined(__cpp_lib_text_encoding) && defined(__glibcxx_want_text_encoding) */ #undef __glibcxx_want_text_encoding +#if !defined(__cpp_lib_ranges_to_input) +# if (__cplusplus > 202302L) +# define __glibcxx_ranges_to_input 202502L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_to_input) +# define __cpp_lib_ranges_to_input 202502L +# endif +# endif +#endif /* !defined(__cpp_lib_ranges_to_input) && defined(__glibcxx_want_ranges_to_input) */ +#undef __glibcxx_want_ranges_to_input + #if !defined(__cpp_lib_to_string) # if (__cplusplus > 202302L) && _GLIBCXX_HOSTED && (__glibcxx_to_chars) # define __glibcxx_to_string 202306L diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index e21f5284b46..c2a2d6f4e05 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -69,6 +69,7 @@ #define __glibcxx_want_ranges_slide #define __glibcxx_want_ranges_stride #define __glibcxx_want_ranges_to_container +#define __glibcxx_want_ranges_to_input #define __glibcxx_want_ranges_zip #include @@ -10390,6 +10391,175 @@ namespace ranges } // namespace ranges #endif // __cpp_lib_ranges_cache_latest +#if __cpp_lib_ranges_to_input // C++ >= 26 +namespace ranges +{ + template + requires view<_Vp> + class to_input_view : public view_interface> + { + _Vp _M_base = _Vp(); + + template + class _Iterator; + + public: + to_input_view() requires default_initializable<_Vp> = default; + + constexpr explicit + to_input_view(_Vp __base) + : _M_base(std::move(__base)) + { } + + constexpr _Vp + base() const & requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr auto + begin() requires (!__detail::__simple_view<_Vp>) + { return _Iterator(ranges::begin(_M_base)); } + + constexpr auto + begin() const requires range + { return _Iterator(ranges::begin(_M_base)); } + + constexpr auto + end() requires (!__detail::__simple_view<_Vp>) + { return ranges::end(_M_base); } + + constexpr auto + end() const requires range + { return ranges::end(_M_base); } + + constexpr auto + size() requires sized_range<_Vp> + { return ranges::size(_M_base); } + + constexpr auto + size() const requires sized_range + { return ranges::size(_M_base); } + }; + + template + to_input_view(_Range&&) -> to_input_view>; + + template + requires view<_Vp> + template + class to_input_view<_Vp>::_Iterator + { + using _Base = __maybe_const_t<_Const, _Vp>; + + iterator_t<_Base> _M_current = iterator_t<_Base>(); + + constexpr explicit + _Iterator(iterator_t<_Base> __current) + : _M_current(std::move(__current)) + { } + + friend to_input_view; + friend _Iterator; + + public: + using difference_type = range_difference_t<_Base>; + using value_type = range_value_t<_Base>; + using iterator_concept = input_iterator_tag; + + _Iterator() requires default_initializable> = default; + + _Iterator(_Iterator&&) = default; + _Iterator& operator=(_Iterator&&) = default; + + constexpr + _Iterator(_Iterator __i) + requires _Const && convertible_to, iterator_t<_Base>> + : _M_current(std::move(__i._M_current)) + { } + + constexpr iterator_t<_Base> + base() && + { return std::move(_M_current); } + + constexpr const iterator_t<_Base>& + base() const & noexcept + { return _M_current; } + + constexpr decltype(auto) + operator*() const + { return *_M_current; } + + constexpr _Iterator& + operator++() + { + ++_M_current; + return *this; + } + + constexpr void + operator++(int) + { ++*this; } + + friend constexpr bool + operator==(const _Iterator& __x, const sentinel_t<_Base>& __y) + { return __x._M_current == __y; } + + friend constexpr difference_type + operator-(const sentinel_t<_Base>& __y, const _Iterator& __x) + requires sized_sentinel_for, iterator_t<_Base>> + { return __y - __x._M_current; } + + friend constexpr difference_type + operator-(const _Iterator& __x, const sentinel_t<_Base>& __y) + requires sized_sentinel_for, iterator_t<_Base>> + { return __x._M_current - __y; } + + friend constexpr range_rvalue_reference_t<_Base> + iter_move(const _Iterator& __i) + noexcept(noexcept(ranges::iter_move(__i._M_current))) + { return ranges::iter_move(__i._M_current); } + + friend constexpr void + iter_swap(const _Iterator& __x, const _Iterator& __y) + noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current))) + requires indirectly_swappable> + { ranges::iter_swap(__x._M_current, __y._M_current); } + }; + + namespace views + { + namespace __detail + { + template + concept __can_to_input = requires { to_input_view(std::declval<_Tp>()); }; + } + + struct _ToInput : __adaptor::_RangeAdaptorClosure<_ToInput> + { + template + requires __detail::__can_to_input<_Range> + constexpr auto + operator() [[nodiscard]] (_Range&& __r) const + { + if constexpr (input_range<_Range> + && !common_range<_Range> + && !forward_range<_Range>) + return views::all(std::forward<_Range>(__r)); + else + return to_input_view(std::forward<_Range>(__r)); + } + + static constexpr bool _S_has_simple_call_op = true; + }; + + inline constexpr _ToInput to_input; + } +} // namespace ranges +#endif // __cpp_lib_ranges_to_input + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // library concepts diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc new file mode 100644 index 00000000000..cde368a2f64 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc @@ -0,0 +1,59 @@ +// { dg-do run { target c++26 } } + +#include + +#if __cpp_lib_ranges_to_input != 202502L +# error "Feature-test macro __cpp_lib_ranges_to_input has wrong value in " +#endif + +#include +#include +#include +#include + +namespace ranges = std::ranges; +namespace views = std::views; + +void +test01() +{ + std::vector r{1,2,3}; + auto v = r | views::to_input; + using type = decltype(v); + static_assert( ranges::input_range && !ranges::forward_range ); + + VERIFY( ranges::equal(v.base(), r) ); + VERIFY( v.size() == r.size() ); + VERIFY( v.end() == r.end() ); + auto it = v.begin(); + VERIFY( it != r.end() ); + *it = 42; + ++it; + *it = 43; + it++; + ranges::iter_swap(v.begin(), it); + VERIFY( ranges::equal(r, (int[]){3,43,42}) ); + *it = ranges::iter_move(it); + VERIFY( it == r.begin() + 2 ); + VERIFY( r.end() - it == 1 ); + VERIFY( it - r.end() == -1 ); +} + +void +test02() +{ + int x[] = {1,2,3}; + __gnu_test::test_input_range rx(x); + static_assert( !ranges::common_range ); + auto v = rx | views::to_input; + static_assert( std::same_as ); + static_assert( std::same_as ); +} + +int +main() +{ + test01(); + test02(); +} -- 2.47.2