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 <[email protected]> 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 + * 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
