https://gcc.gnu.org/g:cfb20f17bd17e1cd98ccd8a4517ff3e925cf731c

commit r15-8010-gcfb20f17bd17e1cd98ccd8a4517ff3e925cf731c
Author: Patrick Palka <ppa...@redhat.com>
Date:   Wed Mar 12 16:09:42 2025 -0400

    libstdc++: Implement P3137R3 views::to_input for C++26
    
    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 <tkami...@redhat.com>
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/version.def              |   8 +
 libstdc++-v3/include/bits/version.h                |  10 ++
 libstdc++-v3/include/std/ranges                    | 170 +++++++++++++++++++++
 .../testsuite/std/ranges/adaptors/to_input/1.cc    |  59 +++++++
 4 files changed, 247 insertions(+)

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 56638759539b..1468c0491b71 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 29e1535298cb..f7c9849893da 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 e21f5284b46d..c2a2d6f4e05e 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 <bits/version.h>
 
@@ -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<input_range _Vp>
+    requires view<_Vp>
+  class to_input_view : public view_interface<to_input_view<_Vp>>
+  {
+    _Vp _M_base = _Vp();
+
+    template<bool _Const>
+    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<false>(ranges::begin(_M_base)); }
+
+    constexpr auto
+    begin() const requires range<const _Vp>
+    { return _Iterator<true>(ranges::begin(_M_base)); }
+
+    constexpr auto
+    end() requires (!__detail::__simple_view<_Vp>)
+    { return ranges::end(_M_base); }
+
+    constexpr auto
+    end() const requires range<const _Vp>
+    { return ranges::end(_M_base); }
+
+    constexpr auto
+    size() requires sized_range<_Vp>
+    { return ranges::size(_M_base); }
+
+    constexpr auto
+    size() const requires sized_range<const _Vp>
+    { return ranges::size(_M_base); }
+  };
+
+  template<typename _Range>
+    to_input_view(_Range&&) -> to_input_view<views::all_t<_Range>>;
+
+  template<input_range _Vp>
+    requires view<_Vp>
+  template<bool _Const>
+  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<!_Const>;
+
+  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<iterator_t<_Base>> = default;
+
+    _Iterator(_Iterator&&) = default;
+    _Iterator& operator=(_Iterator&&) = default;
+
+    constexpr
+    _Iterator(_Iterator<!_Const> __i)
+      requires _Const && convertible_to<iterator_t<_Vp>, 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<sentinel_t<_Base>, 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<sentinel_t<_Base>, 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<iterator_t<_Base>>
+    { ranges::iter_swap(__x._M_current, __y._M_current); }
+  };
+
+  namespace views
+  {
+    namespace __detail
+    {
+      template<typename _Tp>
+       concept __can_to_input = requires { to_input_view(std::declval<_Tp>()); 
};
+    }
+
+    struct _ToInput : __adaptor::_RangeAdaptorClosure<_ToInput>
+    {
+      template<viewable_range _Range>
+       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 000000000000..cde368a2f64d
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc
@@ -0,0 +1,59 @@
+// { dg-do run { target c++26 } }
+
+#include <ranges>
+
+#if __cpp_lib_ranges_to_input != 202502L
+# error "Feature-test macro __cpp_lib_ranges_to_input has wrong value in 
<ranges>"
+#endif
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+namespace ranges = std::ranges;
+namespace views = std::views;
+
+void
+test01()
+{
+  std::vector<int> r{1,2,3};
+  auto v = r | views::to_input;
+  using type = decltype(v);
+  static_assert( ranges::input_range<type> && !ranges::forward_range<type> );
+
+  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<int> rx(x);
+  static_assert( !ranges::common_range<decltype(rx)> );
+  auto v = rx | views::to_input;
+  static_assert( std::same_as<decltype(v), decltype(views::all(rx))> );
+  static_assert( std::same_as<decltype(x | views::to_input),
+                             decltype(x | views::to_input | views::to_input)> 
);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}

Reply via email to