[PATCH] libstdc++: implement P3052R2 view_interface::at()
Yuao Ma
addr2line@gmail.com
Fri Sep 18 13:15:19 GMT 2026
On Fri, Sep 18, 2026 at 12:33 AM Jonathan Wakely <jwakely@redhat.com> wrote:
>
> >From 7c8c3330f775b98949705fa33ee0605989254b65 Mon Sep 17 00:00:00 2001
> >From: Yuao Ma <c8ef@outlook.com>
> >Date: Thu, 17 Sep 2026 23:10:13 +0800
> >Subject: [PATCH] libstdc++: implement P3052R2 view_interface::at()
> >
> >libstdc++-v3/ChangeLog:
> >
> > * include/bits/ranges_util.h (view_interface::at): Define.
> > * include/bits/version.def: Define view_interface.
> > * include/bits/version.h: Regenerate.
> > * include/std/ranges: Define __glibcxx_want_view_interface.
> > * testsuite/std/ranges/p3052.cc: New test.
>
> OK for trunk, thanks.
>
> >---
> > libstdc++-v3/include/bits/ranges_util.h | 23 +++++++++
> > libstdc++-v3/include/bits/version.def | 8 ++++
> > libstdc++-v3/include/bits/version.h | 10 ++++
> > libstdc++-v3/include/std/ranges | 1 +
> > libstdc++-v3/testsuite/std/ranges/p3052.cc | 55 ++++++++++++++++++++++
> > 5 files changed, 97 insertions(+)
> > create mode 100644 libstdc++-v3/testsuite/std/ranges/p3052.cc
> >
> >diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h
> >index 423767f00fc..c14cdd7bd1e 100644
> >--- a/libstdc++-v3/include/bits/ranges_util.h
> >+++ b/libstdc++-v3/include/bits/ranges_util.h
> >@@ -38,6 +38,9 @@
> > #if __glibcxx_tuple_like // >= C++23
> > # include <bits/stl_pair.h> // __pair_like, __is_tuple_like_v
> > #endif
> >+#if __glibcxx_view_interface // >= C++29
> >+# include <bits/stdexcept_throw.h>
Well this is a bit subtler than my original thought. This will cause a
include cycle: <tuple> -> ranges_util.h -> stdexcept_throw.h ->
<string> -> memory_resource.h -> uses_allocator_args.h -> <tuple>.
Includes # include <bits/stdexcept_throwfwd.h> can make the CI green,
but not sure whether it is ideal.
see also: https://patchwork.sourceware.org/patch/144067
> >+#endif
> >
> > #ifdef __glibcxx_ranges
> > namespace std _GLIBCXX_VISIBILITY(default)
> >@@ -199,6 +202,26 @@ namespace ranges
> > operator[](range_difference_t<_Range> __n) const
> > { return ranges::begin(_M_derived())[__n]; }
> >
> >+#if __glibcxx_view_interface // >= C++29
> >+ template<random_access_range _Range = _Derived>
> >+ [[nodiscard]] constexpr decltype(auto)
> >+ at(range_difference_t<_Range> __n) requires sized_range<_Range>
> >+ {
> >+ if (__n < 0 || __n >= ranges::distance(_M_derived()))
> >+ std::__throw_out_of_range("view_interface::at");
> >+ return (*this)[__n];
> >+ }
> >+
> >+ template<random_access_range _Range = const _Derived>
> >+ [[nodiscard]] constexpr decltype(auto)
> >+ at(range_difference_t<_Range> __n) const requires sized_range<_Range>
> >+ {
> >+ if (__n < 0 || __n >= ranges::distance(_M_derived()))
> >+ std::__throw_out_of_range("view_interface::at");
> >+ return (*this)[__n];
> >+ }
> >+#endif
> >+
> > #if __cplusplus > 202002L
> > constexpr auto
> > cbegin() requires input_range<_Derived>
> >diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
> >index 9c523581c65..17589685f90 100644
> >--- a/libstdc++-v3/include/bits/version.def
> >+++ b/libstdc++-v3/include/bits/version.def
> >@@ -2164,6 +2164,14 @@ ftms = {
> > };
> > };
> >
> >+ftms = {
> >+ name = view_interface;
> >+ values = {
> >+ v = 202606;
> >+ cxxmin = 29;
> >+ };
> >+};
> >+
> > ftms = {
> > name = observable_checkpoint;
> > values = {
> >diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
> >index e0003054af6..4df6a648323 100644
> >--- a/libstdc++-v3/include/bits/version.h
> >+++ b/libstdc++-v3/include/bits/version.h
> >@@ -2391,6 +2391,16 @@
> > #endif /* !defined(__cpp_lib_unreachable) */
> > #undef __glibcxx_want_unreachable
> >
> >+#if !defined(__cpp_lib_view_interface)
> >+# if (__cplusplus > 202603L)
> >+# define __glibcxx_view_interface 202606L
> >+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_view_interface)
> >+# define __cpp_lib_view_interface 202606L
> >+# endif
> >+# endif
> >+#endif /* !defined(__cpp_lib_view_interface) */
> >+#undef __glibcxx_want_view_interface
> >+
> > #if !defined(__cpp_lib_observable_checkpoint)
> > # if (__cplusplus > 202302L) && (__has_builtin(__builtin_observable_checkpoint))
> > # define __glibcxx_observable_checkpoint 202506L
> >diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> >index a7fb2312fe8..f67ea82a0a2 100644
> >--- a/libstdc++-v3/include/std/ranges
> >+++ b/libstdc++-v3/include/std/ranges
> >@@ -75,6 +75,7 @@
> > #define __glibcxx_want_ranges_to_container
> > #define __glibcxx_want_ranges_as_input
> > #define __glibcxx_want_ranges_zip
> >+#define __glibcxx_want_view_interface
> > #include <bits/version.h>
> >
> > #ifdef __glibcxx_generator // C++ >= 23 && __glibcxx_coroutine
> >diff --git a/libstdc++-v3/testsuite/std/ranges/p3052.cc b/libstdc++-v3/testsuite/std/ranges/p3052.cc
> >new file mode 100644
> >index 00000000000..d68d39df50c
> >--- /dev/null
> >+++ b/libstdc++-v3/testsuite/std/ranges/p3052.cc
> >@@ -0,0 +1,55 @@
> >+// { dg-do run { target c++29 } }
> >+
> >+#include <ranges>
> >+
> >+#if __cpp_lib_view_interface != 202606L
> >+#error "Feature-test macro __cpp_lib_view_interface has wrong value in <ranges>"
> >+#endif
> >+
> >+#include <stdexcept>
> >+
> >+#include <testsuite_hooks.h>
> >+
> >+struct v1 : std::ranges::view_interface<v1> {
> >+ int *ptr;
> >+ std::size_t sz;
> >+
> >+ constexpr v1(int *p, std::size_t n) : ptr(p), sz(n) {}
> >+
> >+ constexpr int *begin() const noexcept { return ptr; }
> >+ constexpr int *end() const noexcept { return ptr + sz; }
> >+};
> >+
> >+void test01() {
> >+ int x[2]{0, 1};
> >+ v1 v(x, 2);
> >+ VERIFY(v.at(1) == 1);
> >+ v.at(1) = 3;
> >+ VERIFY(v.at(1) == 3);
> >+ VERIFY(static_cast<const v1 &>(v).at(1) == 3);
> >+
> >+#if __cpp_exceptions
> >+ try {
> >+ static_cast<void>(v.at(-1));
> >+ VERIFY(false);
> >+ } catch (const std::out_of_range &) {
> >+ VERIFY(true);
> >+ } catch (...) {
> >+ VERIFY(false);
> >+ }
> >+
> >+ try {
> >+ static_cast<void>(v.at(2));
> >+ VERIFY(false);
> >+ } catch (const std::out_of_range &) {
> >+ VERIFY(true);
> >+ } catch (...) {
> >+ VERIFY(false);
> >+ }
> >+#endif
> >+}
> >+
> >+int main() {
> >+ test01();
> >+ return 0;
> >+}
> >--
> >2.54.0
> >
>
More information about the Libstdc++
mailing list