[PATCH] libstdc++: implement P3044R2 - sub-string_view from string
Yuao Ma
addr2line@gmail.com
Fri Nov 21 16:49:40 GMT 2025
On Sat, Nov 22, 2025 at 12:41 AM Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On Fri, 21 Nov 2025 at 16:32, Yuao Ma <addr2line@gmail.com> wrote:
> >
> > On Fri, Nov 21, 2025 at 7:52 PM Jonathan Wakely <jwakely@redhat.com> wrote:
> > >
> > > On Thu, 20 Nov 2025 at 17:51, Yuao Ma <addr2line@gmail.com> 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.
> > >
> > > The new basic_string::subview member needs to be added to
> > > include/bits/cow_string.h as well, or the new tests need to be
> > > disabled for the old COW std::string ABI.
> > >
> >
> > The nodiscard and Markdown symbols are fixed. I also added the
>
> Thanks!
>
> > cxx11_abi effective target to the tests, since we likely don't want to
> > use the COW ABI with C++26.
>
> You would be surprised, people still do use it!
>
> If the feature is absent for the COW string then bits/version.def
> needs to use cxx11abi = yes so that the new macro is not defined for
> the COW ABI.
>
Got it! Fixed in the new series.
-------------- next part --------------
From 668363e4dbf6db6d7cd40899a480256936dcd0ae Mon Sep 17 00:00:00 2001
From: Yuao Ma <c8ef@outlook.com>
Date: Sat, 22 Nov 2025 00:37:48 +0800
Subject: [PATCH 1/2] libstdc++: implement P3044R2 - sub-string_view from
string (string_view part)
libstdc++-v3/ChangeLog:
* include/bits/version.def: Add string_subview FTM.
* include/bits/version.h: Regenerate.
* include/std/string_view: Add subview.
* 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/version.def | 9 ++++
libstdc++-v3/include/bits/version.h | 10 ++++
libstdc++-v3/include/std/string_view | 10 +++-
.../operations/subview/char.cc | 52 +++++++++++++++++++
.../operations/subview/wchar_t.cc | 52 +++++++++++++++++++
5 files changed, 132 insertions(+), 1 deletion(-)
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/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_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_view/operations/subview/char.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
new file mode 100644
index 00000000000..296d85af69b
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/char.cc
@@ -0,0 +1,52 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target cxx11_abi }
+
+#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..461d1005c65
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/subview/wchar_t.cc
@@ -0,0 +1,52 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target cxx11_abi }
+
+#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
-------------- next part --------------
From 6aa79695876a6834d0a009a68df864998a3f7056 Mon Sep 17 00:00:00 2001
From: Yuao Ma <c8ef@outlook.com>
Date: Sat, 22 Nov 2025 00:38:54 +0800
Subject: [PATCH 2/2] libstdc++: implement P3044R2 - sub-string_view from
string (string part)
libstdc++-v3/ChangeLog:
* include/bits/basic_string.h: Add subview.
* include/std/string: Add FTM.
* testsuite/21_strings/basic_string/operations/subview/char.cc: New test.
* testsuite/21_strings/basic_string/operations/subview/wchar_t.cc: New test.
---
libstdc++-v3/include/bits/basic_string.h | 19 ++++++++
libstdc++-v3/include/std/string | 1 +
.../basic_string/operations/subview/char.cc | 47 +++++++++++++++++++
.../operations/subview/wchar_t.cc | 47 +++++++++++++++++++
4 files changed, 114 insertions(+)
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
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index c4b6b1064a9..b1db722402f 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 `__n` characters starting at
+ * `__pos`. If the string is too short, use the remainder of the
+ * characters. If `__pos` is beyond the end of the string, out_of_range
+ * is thrown.
+ */
+ [[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/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/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..da541f2c9f8
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/char.cc
@@ -0,0 +1,47 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target cxx11_abi }
+
+#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..06025a0b638
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/subview/wchar_t.cc
@@ -0,0 +1,47 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target cxx11_abi }
+
+#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;
+}
--
2.51.1
More information about the Libstdc++
mailing list