[PATCH] libstdc++: implement P3044R2 - sub-string_view from string

Jonathan Wakely jwakely@redhat.com
Thu Nov 20 18:24:15 GMT 2025


On Fri, 21 Nov 2025 at 01:50 +0800, Yuao Ma wrote:
>Hi all,
>
>This patch implements P3044R2 by adding a subview function for string
>and string_view. The implementation delegates directly to substr.
>Tested on x86_64-linux.
>Also, could you please help review my other patch regarding P3223R2 at
>https://gcc.gnu.org/pipermail/libstdc++/2025-November/064369.html?
>
>Thanks,
>Yuao

>From 6cf50b0e5a2fc1ca6814dbc4555c543c690d300a Mon Sep 17 00:00:00 2001
>From: Yuao Ma <c8ef@outlook.com>
>Date: Fri, 21 Nov 2025 01:42:51 +0800
>Subject: [PATCH] libstdc++: implement P3044R2 - sub-string_view from string
>
>libstdc++-v3/ChangeLog:
>
>	* include/bits/basic_string.h: Add subview.
>	* include/bits/version.def: Add string_subview FTM.
>	* include/bits/version.h: Regenerate.
>	* include/std/string: Add FTM.
>	* include/std/string_view: Add subview.
>	* testsuite/21_strings/basic_string/operations/subview/char.cc: New test.
>	* testsuite/21_strings/basic_string/operations/subview/wchar_t.cc: New test.
>	* testsuite/21_strings/basic_string_view/operations/subview/char.cc: New test.
>	* testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc: New test.
>---
> libstdc++-v3/include/bits/basic_string.h      | 19 +++++++
> libstdc++-v3/include/bits/version.def         |  9 ++++
> libstdc++-v3/include/bits/version.h           | 10 ++++
> libstdc++-v3/include/std/string               |  1 +
> libstdc++-v3/include/std/string_view          | 10 +++-
> .../basic_string/operations/subview/char.cc   | 46 +++++++++++++++++
> .../operations/subview/wchar_t.cc             | 46 +++++++++++++++++
> .../operations/subview/char.cc                | 50 ++++++++++++++++++
> .../operations/subview/wchar_t.cc             | 51 +++++++++++++++++++
> 9 files changed, 241 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
> create mode 100644 libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
> create mode 100644 libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
> create mode 100644 libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
>
>diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
>index c4b6b1064a9..e87eb93e286 100644
>--- a/libstdc++-v3/include/bits/basic_string.h
>+++ b/libstdc++-v3/include/bits/basic_string.h
>@@ -3442,6 +3442,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
>       { return basic_string(*this,
> 			    _M_check(__pos, "basic_string::substr"), __n); }
>
>+#ifdef __glibcxx_string_subview // >= C++26
>+      /**
>+       *  @brief  Get a subview.
>+       *  @param __pos  Index of first character (default 0).
>+       *  @param __n  Number of characters in subview (default remainder).
>+       *  @return  The subview.
>+       *  @throw  std::out_of_range  If __pos > size().
>+       *
>+       *  Construct and return a subview using the @a __n characters starting

Also, we can use markdown formatting instead of Doxygen commands, so
`__pos` instead of @a __pos.

>+       *  at @a __pos.  If the string is too short, use the remainder of the
>+       *  characters.  If @a __pos is beyond the end of the string,
>+       *  out_of_range is thrown.
>+      */
>+      _GLIBCXX_NODISCARD constexpr
>+      basic_string_view<_CharT, _Traits>
>+      subview(size_type __pos = 0, size_type __n = npos) const
>+      { return __sv_type(*this).subview(__pos, __n); }
>+#endif
>+
>       /**
>        *  @brief  Compare to a string.
>        *  @param __str  String to compare against.
>diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
>index 29ecf15c7e3..b5575d2399f 100644
>--- a/libstdc++-v3/include/bits/version.def
>+++ b/libstdc++-v3/include/bits/version.def
>@@ -1934,6 +1934,15 @@ ftms = {
>   };
> };
>
>+ftms = {
>+  name = string_subview;
>+  values = {
>+    v = 202506;
>+    cxxmin = 26;
>+    hosted = yes;
>+  };
>+};
>+
> ftms = {
>   name = to_underlying;
>   values = {
>diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
>index 5901d27113d..413da56b088 100644
>--- a/libstdc++-v3/include/bits/version.h
>+++ b/libstdc++-v3/include/bits/version.h
>@@ -2161,6 +2161,16 @@
> #endif /* !defined(__cpp_lib_string_resize_and_overwrite) */
> #undef __glibcxx_want_string_resize_and_overwrite
>
>+#if !defined(__cpp_lib_string_subview)
>+# if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
>+#  define __glibcxx_string_subview 202506L
>+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_string_subview)
>+#   define __cpp_lib_string_subview 202506L
>+#  endif
>+# endif
>+#endif /* !defined(__cpp_lib_string_subview) */
>+#undef __glibcxx_want_string_subview
>+
> #if !defined(__cpp_lib_to_underlying)
> # if (__cplusplus >= 202100L)
> #  define __glibcxx_to_underlying 202102L
>diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string
>index 97ded057a87..918b4158b47 100644
>--- a/libstdc++-v3/include/std/string
>+++ b/libstdc++-v3/include/std/string
>@@ -63,6 +63,7 @@
> #define __glibcxx_want_erase_if
> #define __glibcxx_want_nonmember_container_access
> #define __glibcxx_want_string_resize_and_overwrite
>+#define __glibcxx_want_string_subview
> #define __glibcxx_want_string_udls
> #define __glibcxx_want_to_string
> #include <bits/version.h>
>diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
>index 842f6ad89af..b226544fa6f 100644
>--- a/libstdc++-v3/include/std/string_view
>+++ b/libstdc++-v3/include/std/string_view
>@@ -40,9 +40,10 @@
> #define __glibcxx_want_constexpr_char_traits
> #define __glibcxx_want_constexpr_string_view
> #define __glibcxx_want_freestanding_string_view
>-#define __glibcxx_want_string_view
> #define __glibcxx_want_starts_ends_with
> #define __glibcxx_want_string_contains
>+#define __glibcxx_want_string_subview
>+#define __glibcxx_want_string_view
> #include <bits/version.h>
>
> #if __cplusplus >= 201703L
>@@ -342,6 +343,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 	return basic_string_view{_M_str + __pos, __rlen};
>       }
>
>+#ifdef __glibcxx_string_subview // >= C++26
>+      [[nodiscard]]
>+      constexpr basic_string_view
>+      subview(size_type __pos = 0, size_type __n = npos) const
>+      { return substr(__pos, __n); }
>+#endif
>+
>       [[nodiscard]]
>       constexpr int
>       compare(basic_string_view __str) const noexcept
>diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
>new file mode 100644
>index 00000000000..c384948cc52
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
>@@ -0,0 +1,46 @@
>+// { dg-do run { target c++26 } }
>+
>+#include <stdexcept>
>+#include <string>
>+#include <string_view>
>+#include <testsuite_hooks.h>
>+
>+void test01(void) {
>+  typedef std::string::size_type csize_type;
>+  typedef std::string::const_reference cref;
>+  typedef std::string::reference ref;
>+  csize_type csz01;
>+
>+  const char str_lit01[] = "rockaway, pacifica";
>+  const std::string str01(str_lit01);
>+  std::string_view str02;
>+
>+  csz01 = str01.size();
>+  str02 = str01.subview(0, 1);
>+  VERIFY(str02 == "r");
>+  str02 = str01.subview(10);
>+  VERIFY(str02 == "pacifica");
>+
>+  try {
>+    str02 = str01.subview(csz01 + 1);
>+    VERIFY(false);
>+  } catch (std::out_of_range &fail) {
>+    VERIFY(true);
>+  } catch (...) {
>+    VERIFY(false);
>+  }
>+
>+  try {
>+    str02 = str01.subview(csz01);
>+    VERIFY(str02.size() == 0);
>+  } catch (std::out_of_range &fail) {
>+    VERIFY(false);
>+  } catch (...) {
>+    VERIFY(false);
>+  }
>+}
>+
>+int main() {
>+  test01();
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
>new file mode 100644
>index 00000000000..3b8e6a87fe6
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
>@@ -0,0 +1,46 @@
>+// { dg-do run { target c++26 } }
>+
>+#include <stdexcept>
>+#include <string>
>+#include <string_view>
>+#include <testsuite_hooks.h>
>+
>+void test01(void) {
>+  typedef std::wstring::size_type csize_type;
>+  typedef std::wstring::const_reference cref;
>+  typedef std::wstring::reference ref;
>+  csize_type csz01;
>+
>+  const wchar_t str_lit01[] = L"rockaway, pacifica";
>+  const std::wstring str01(str_lit01);
>+  std::wstring_view str02;
>+
>+  csz01 = str01.size();
>+  str02 = str01.subview(0, 1);
>+  VERIFY(str02 == L"r");
>+  str02 = str01.subview(10);
>+  VERIFY(str02 == L"pacifica");
>+
>+  try {
>+    str02 = str01.subview(csz01 + 1);
>+    VERIFY(false);
>+  } catch (std::out_of_range &fail) {
>+    VERIFY(true);
>+  } catch (...) {
>+    VERIFY(false);
>+  }
>+
>+  try {
>+    str02 = str01.subview(csz01);
>+    VERIFY(str02.size() == 0);
>+  } catch (std::out_of_range &fail) {
>+    VERIFY(false);
>+  } catch (...) {
>+    VERIFY(false);
>+  }
>+}
>+
>+int main() {
>+  test01();
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
>new file mode 100644
>index 00000000000..f0ce145b45b
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
>@@ -0,0 +1,50 @@
>+// { dg-do run { target c++26 } }
>+#include <string_view>
>+#include <testsuite_hooks.h>
>+
>+#if __STDC_HOSTED__
>+#include <stdexcept>
>+#endif
>+
>+void test01() {
>+  typedef std::string_view::size_type csize_type;
>+  typedef std::string_view::const_reference cref;
>+  typedef std::string_view::reference ref;
>+  csize_type csz01;
>+
>+  const char str_lit01[] = "rockaway, pacifica";
>+  const std::string_view str01(str_lit01);
>+  std::string_view str02;
>+
>+  csz01 = str01.size();
>+  str02 = str01.subview(0, 1);
>+  VERIFY(str02 == "r");
>+  str02 = str01.subview(10);
>+  VERIFY(str02 == "pacifica");
>+
>+#if __STDC_HOSTED__
>+  try {
>+    str02 = str01.subview(csz01 + 1);
>+    VERIFY(false);
>+  } catch (std::out_of_range &fail) {
>+    VERIFY(true);
>+  } catch (...) {
>+    VERIFY(false);
>+  }
>+
>+  try {
>+    str02 = str01.subview(csz01);
>+    VERIFY(str02.size() == 0);
>+    VERIFY(str02.begin() == str01.end());
>+    VERIFY(true);
>+  } catch (...) {
>+    VERIFY(false);
>+  }
>+#endif // HOSTED
>+}
>+
>+int main() {
>+  test01();
>+
>+  return 0;
>+}
>diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
>new file mode 100644
>index 00000000000..86b50959b5c
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
>@@ -0,0 +1,51 @@
>+// { dg-do run { target c++26 } }
>+
>+#include <string_view>
>+#include <testsuite_hooks.h>
>+
>+#if __STDC_HOSTED__
>+#include <stdexcept>
>+#endif
>+
>+void test01() {
>+  typedef std::wstring_view::size_type csize_type;
>+  typedef std::wstring_view::const_reference cref;
>+  typedef std::wstring_view::reference ref;
>+  csize_type csz01;
>+
>+  const wchar_t str_lit01[] = L"rockaway, pacifica";
>+  const std::wstring_view str01(str_lit01);
>+  std::wstring_view str02;
>+
>+  csz01 = str01.size();
>+  str02 = str01.subview(0, 1);
>+  VERIFY(str02 == L"r");
>+  str02 = str01.subview(10);
>+  VERIFY(str02 == L"pacifica");
>+
>+#if __STDC_HOSTED__
>+  try {
>+    str02 = str01.subview(csz01 + 1);
>+    VERIFY(false);
>+  } catch (std::out_of_range &fail) {
>+    VERIFY(true);
>+  } catch (...) {
>+    VERIFY(false);
>+  }
>+
>+  try {
>+    str02 = str01.subview(csz01);
>+    VERIFY(str02.size() == 0);
>+    VERIFY(str02.begin() == str01.end());
>+    VERIFY(true);
>+  } catch (...) {
>+    VERIFY(false);
>+  }
>+#endif // HOSTED
>+}
>+
>+int main() {
>+  test01();
>+
>+  return 0;
>+}
>-- 
>2.51.1
>



More information about the Libstdc++ mailing list