[libcxx-commits] [libcxx] [libc++][string] P3044R2: sub-`string_view` from `string` (PR #147095)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 22 23:03:37 PDT 2025
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/147095
>From 0510c784394a21e0a1ec06e15588848912dc568b Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 4 Jul 2025 18:22:03 +0300
Subject: [PATCH 1/5] WIP [libc++][string] P3044R2: sub-`string_view` from
`string`
Implements [P3044R2](https://wg21.link/P3044R2)
- https://github.com/cplusplus/draft/pull/7975
---
libcxx/include/string | 9 +
libcxx/include/string_view | 8 +
.../string.ops/string_substr/subview.pass.cpp | 33 ++++
.../string.view.ops/substr.pass.cpp | 125 --------------
.../string.view.ops/substr_subview.pass.cpp | 158 ++++++++++++++++++
5 files changed, 208 insertions(+), 125 deletions(-)
create mode 100644 libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp
delete mode 100644 libcxx/test/std/strings/string.view/string.view.ops/substr.pass.cpp
create mode 100644 libcxx/test/std/strings/string.view/string.view.ops/substr_subview.pass.cpp
diff --git a/libcxx/include/string b/libcxx/include/string
index 98297d04d0c61..7e8d8fac9f753 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -280,6 +280,8 @@ public:
basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr in C++20, removed in C++23
basic_string substr(size_type pos = 0, size_type n = npos) const&; // since C++23
constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; // since C++23
+ constexpr basic_string_view<charT, traits> subview(size_type pos = 0,
+ size_type n = npos) const; // since C++26
void swap(basic_string& str)
noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
allocator_traits<allocator_type>::is_always_equal::value); // C++17, constexpr since C++20
@@ -1752,6 +1754,13 @@ public:
}
# endif
+# if _LIBCPP_STD_VER >= 26
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT, _Traits>
+ subview(size_type __pos = 0, size_type __n = npos) const {
+ return basic_string_view<_CharT, _Traits>(*this).subview(__pos, __n);
+ }
+# endif
+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(basic_string& __str)
# if _LIBCPP_STD_VER >= 14
_NOEXCEPT;
diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index f86b2722aca6c..952d44123622b 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -130,6 +130,8 @@ namespace std {
size_type copy(charT* s, size_type n, size_type pos = 0) const; // constexpr in C++20
constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const;
+ constexpr basic_string_view subview(size_type pos = 0,
+ size_type n = npos) const; // freestanding-deleted, since C++26
constexpr int compare(basic_string_view s) const noexcept;
constexpr int compare(size_type pos1, size_type n1, basic_string_view s) const;
constexpr int compare(size_type pos1, size_type n1,
@@ -465,6 +467,12 @@ public:
: basic_string_view(__assume_valid(), data() + __pos, std::min(__n, size() - __pos));
}
+# if _LIBCPP_STD_VER >= 26
+ _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view subview(size_type __pos = 0, size_type __n = npos) const {
+ return this->substr(__pos, __n);
+ }
+# endif
+
_LIBCPP_CONSTEXPR_SINCE_CXX14 int compare(basic_string_view __sv) const _NOEXCEPT {
size_type __rlen = std::min(size(), __sv.size());
int __retval = _Traits::compare(data(), __sv.data(), __rlen);
diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp
new file mode 100644
index 0000000000000..65418dcb4d7be
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <string>
+
+// constexpr basic_string_view<_CharT, _Traits> subview(size_type __pos = 0, size_type __n = npos) const;
+
+#include <cassert>
+#include <string>
+
+constexpr bool test() {
+ std::string s{"Hello cruel world!"};
+ auto sub = s.subview(6);
+ assert(sub == "cruel world!");
+ auto subsub = sub.subview(0, 5);
+ assert(subsub == "cruel");
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/strings/string.view/string.view.ops/substr.pass.cpp b/libcxx/test/std/strings/string.view/string.view.ops/substr.pass.cpp
deleted file mode 100644
index 62b0259c175f8..0000000000000
--- a/libcxx/test/std/strings/string.view/string.view.ops/substr.pass.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: !stdlib=libc++ && (c++03 || c++11 || c++14)
-
-// <string_view>
-
-// constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const;
-
-// Throws: out_of_range if pos > size().
-// Effects: Determines the effective length rlen of the string to reference as the smaller of n and size() - pos.
-// Returns: basic_string_view(data()+pos, rlen).
-
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <stdexcept>
-#include <string_view>
-
-#include "test_macros.h"
-
-template <typename CharT>
-void test1(std::basic_string_view<CharT> sv, std::size_t n, size_t pos) {
- std::basic_string_view<CharT> sv1;
-#ifdef TEST_HAS_NO_EXCEPTIONS
- if (pos > sv.size())
- return; // would throw if exceptions were enabled
- sv1 = sv.substr(pos, n);
-#else
- try {
- sv1 = sv.substr(pos, n);
- assert(pos <= sv.size());
- } catch (const std::out_of_range&) {
- assert(pos > sv.size());
- return;
- }
-#endif
- const std::size_t rlen = std::min(n, sv.size() - pos);
- assert(sv1.size() == rlen);
- for (std::size_t i = 0; i < rlen; ++i)
- assert(sv[pos + i] == sv1[i]);
-}
-
-template <typename CharT>
-void test(const CharT* s) {
- typedef std::basic_string_view<CharT> string_view_t;
-
- string_view_t sv1(s);
-
- test1(sv1, 0, 0);
- test1(sv1, 1, 0);
- test1(sv1, 20, 0);
- test1(sv1, sv1.size(), 0);
-
- test1(sv1, 0, 3);
- test1(sv1, 2, 3);
- test1(sv1, 100, 3);
-
- test1(sv1, 0, string_view_t::npos);
- test1(sv1, 2, string_view_t::npos);
- test1(sv1, sv1.size(), string_view_t::npos);
-
- test1(sv1, sv1.size() + 1, 0);
- test1(sv1, sv1.size() + 1, 1);
- test1(sv1, sv1.size() + 1, string_view_t::npos);
-}
-
-int main(int, char**) {
- test("ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
- test("ABCDE");
- test("a");
- test("");
-
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- test(L"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
- test(L"ABCDE");
- test(L"a");
- test(L"");
-#endif
-
-#if TEST_STD_VER >= 11
- test(u"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
- test(u"ABCDE");
- test(u"a");
- test(u"");
-
- test(U"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
- test(U"ABCDE");
- test(U"a");
- test(U"");
-#endif
-
-#if TEST_STD_VER > 11
- {
- constexpr std::string_view sv1{"ABCDE", 5};
-
- {
- constexpr std::string_view sv2 = sv1.substr(0, 3);
- static_assert(sv2.size() == 3, "");
- static_assert(sv2[0] == 'A', "");
- static_assert(sv2[1] == 'B', "");
- static_assert(sv2[2] == 'C', "");
- }
-
- {
- constexpr std::string_view sv2 = sv1.substr(3, 0);
- static_assert(sv2.size() == 0, "");
- }
-
- {
- constexpr std::string_view sv2 = sv1.substr(3, 3);
- static_assert(sv2.size() == 2, "");
- static_assert(sv2[0] == 'D', "");
- static_assert(sv2[1] == 'E', "");
- }
- }
-#endif
-
- return 0;
-}
diff --git a/libcxx/test/std/strings/string.view/string.view.ops/substr_subview.pass.cpp b/libcxx/test/std/strings/string.view/string.view.ops/substr_subview.pass.cpp
new file mode 100644
index 0000000000000..c40c771db4bae
--- /dev/null
+++ b/libcxx/test/std/strings/string.view/string.view.ops/substr_subview.pass.cpp
@@ -0,0 +1,158 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: !stdlib=libc++ && (c++03 || c++11 || c++14)
+
+// <string_view>
+
+// constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const;
+// constexpr basic_string_view subview(size_type pos = 0,
+// size_type n = npos) const; // freestanding-deleted
+
+// subview is alternative name of substr
+
+// Throws: out_of_range if pos > size().
+// Effects: Determines the effective length rlen of the string to reference as the smaller of n and size() - pos.
+// Returns: basic_string_view(data()+pos, rlen).
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <stdexcept>
+#include <string_view>
+
+#include "test_macros.h"
+
+template <typename CharT>
+struct Test {
+ typedef std::basic_string_view<CharT> (std::basic_string_view<CharT>::*Sub)(
+ typename std::basic_string_view<CharT>::size_type, typename std::basic_string_view<CharT>::size_type) const;
+};
+
+template <typename CharT>
+void testDetail(std::basic_string_view<CharT> sv, typename Test<CharT>::Sub testSub, std::size_t n, size_t pos) {
+ (void)testSub; // Avoid unused parameter warning
+ std::basic_string_view<CharT> sv1;
+#ifdef TEST_HAS_NO_EXCEPTIONS
+ if (pos > sv.size())
+ return; // would throw if exceptions were enabled
+ sv1 = (sv.*testSub)(pos, n);
+#else
+ try {
+ sv1 = (sv.*testSub)(pos, n);
+ assert(pos <= sv.size());
+ } catch (const std::out_of_range&) {
+ assert(pos > sv.size());
+ return;
+ }
+#endif
+ const std::size_t rlen = std::min(n, sv.size() - pos);
+ assert(sv1.size() == rlen);
+ for (std::size_t i = 0; i < rlen; ++i)
+ assert(sv[pos + i] == sv1[i]);
+}
+
+template <typename CharT>
+void testCases(std::basic_string_view<CharT> sv, typename Test<CharT>::Sub testSub) {
+ testDetail(sv, testSub, 0, 0);
+ testDetail(sv, testSub, 1, 0);
+ testDetail(sv, testSub, 20, 0);
+ testDetail(sv, testSub, sv.size(), 0);
+
+ testDetail(sv, testSub, 100, 3);
+
+ testDetail(sv, testSub, 0, std::basic_string_view<CharT>::npos);
+ testDetail(sv, testSub, 2, std::basic_string_view<CharT>::npos);
+ testDetail(sv, testSub, sv.size(), std::basic_string_view<CharT>::npos);
+
+ testDetail(sv, testSub, sv.size() + 1, 0);
+ testDetail(sv, testSub, sv.size() + 1, 1);
+ testDetail(sv, testSub, sv.size() + 1, std::basic_string_view<CharT>::npos);
+}
+
+template <typename CharT>
+void testSubs(const CharT* s) {
+ std::basic_string_view<CharT> sv(s);
+
+ testCases(sv, &std::basic_string_view<CharT>::substr);
+#if TEST_STD_VER >= 26
+ testCases(sv, &std::basic_string_view<CharT>::subview);
+#endif // TEST_STD_VER >= 26
+}
+
+void test() {
+ testSubs("ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
+ testSubs("ABCDE");
+ testSubs("a");
+ testSubs("");
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ testSubs(
+ L"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
+ testSubs(L"ABCDE");
+ testSubs(L"a");
+ testSubs(L"");
+#endif
+
+#if TEST_STD_VER >= 11
+ testSubs(
+ u"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
+ testSubs(u"ABCDE");
+ testSubs(u"a");
+ testSubs(u"");
+
+ testSubs(
+ U"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
+ testSubs(U"ABCDE");
+ testSubs(U"a");
+ testSubs(U"");
+#endif
+}
+
+#if TEST_STD_VER >= 14
+template <typename Test<char>::Sub TestSub>
+constexpr void testConstexprDetail() {
+ constexpr std::string_view sv{"ABCDE", 5};
+ {
+ constexpr std::string_view sv2 = (sv.*TestSub)(0, 3);
+
+ static_assert(sv2.size() == 3, "");
+ static_assert(sv2[0] == 'A', "");
+ static_assert(sv2[1] == 'B', "");
+ static_assert(sv2[2] == 'C', "");
+ }
+
+ {
+ constexpr std::string_view sv2 = (sv.*TestSub)(3, 0);
+ static_assert(sv2.size() == 0, "");
+ }
+
+ {
+ constexpr std::string_view sv2 = (sv.*TestSub)(3, 3);
+ static_assert(sv2.size() == 2, "");
+ static_assert(sv2[0] == 'D', "");
+ static_assert(sv2[1] == 'E', "");
+ }
+}
+
+void test_constexpr() {
+ testConstexprDetail<&std::string_view::substr>();
+# if TEST_STD_VER >= 26
+ testConstexprDetail<&std::string_view::subview>();
+# endif
+}
+#endif
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 14
+ test_constexpr();
+#endif
+
+ return 0;
+}
>From ad5e4107304b3169b54d2cc6904b66734b8512e1 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 4 Jul 2025 21:26:04 +0300
Subject: [PATCH 2/5] Renamed test
---
...ubstr_subview.pass.cpp => substr.pass.cpp} | 43 +++++++++----------
.../string.view.ops/subview.pass.cpp | 20 +++++++++
2 files changed, 41 insertions(+), 22 deletions(-)
rename libcxx/test/std/strings/string.view/string.view.ops/{substr_subview.pass.cpp => substr.pass.cpp} (77%)
create mode 100644 libcxx/test/std/strings/string.view/string.view.ops/subview.pass.cpp
diff --git a/libcxx/test/std/strings/string.view/string.view.ops/substr_subview.pass.cpp b/libcxx/test/std/strings/string.view/string.view.ops/substr.pass.cpp
similarity index 77%
rename from libcxx/test/std/strings/string.view/string.view.ops/substr_subview.pass.cpp
rename to libcxx/test/std/strings/string.view/string.view.ops/substr.pass.cpp
index c40c771db4bae..02755985ead70 100644
--- a/libcxx/test/std/strings/string.view/string.view.ops/substr_subview.pass.cpp
+++ b/libcxx/test/std/strings/string.view/string.view.ops/substr.pass.cpp
@@ -34,17 +34,16 @@ struct Test {
typename std::basic_string_view<CharT>::size_type, typename std::basic_string_view<CharT>::size_type) const;
};
-template <typename CharT>
-void testDetail(std::basic_string_view<CharT> sv, typename Test<CharT>::Sub testSub, std::size_t n, size_t pos) {
- (void)testSub; // Avoid unused parameter warning
+template <typename CharT, typename Test<CharT>::Sub TestSub>
+void testDetail(std::basic_string_view<CharT> sv, std::size_t n, size_t pos) {
std::basic_string_view<CharT> sv1;
#ifdef TEST_HAS_NO_EXCEPTIONS
if (pos > sv.size())
return; // would throw if exceptions were enabled
- sv1 = (sv.*testSub)(pos, n);
+ sv1 = (sv.*TestSub)(pos, n);
#else
try {
- sv1 = (sv.*testSub)(pos, n);
+ sv1 = (sv.*TestSub)(pos, n);
assert(pos <= sv.size());
} catch (const std::out_of_range&) {
assert(pos > sv.size());
@@ -57,31 +56,31 @@ void testDetail(std::basic_string_view<CharT> sv, typename Test<CharT>::Sub test
assert(sv[pos + i] == sv1[i]);
}
-template <typename CharT>
-void testCases(std::basic_string_view<CharT> sv, typename Test<CharT>::Sub testSub) {
- testDetail(sv, testSub, 0, 0);
- testDetail(sv, testSub, 1, 0);
- testDetail(sv, testSub, 20, 0);
- testDetail(sv, testSub, sv.size(), 0);
+template <typename CharT, typename Test<CharT>::Sub TestSub>
+void testCases(const CharT* s) {
+ std::basic_string_view<CharT> sv(s);
- testDetail(sv, testSub, 100, 3);
+ testDetail<CharT, TestSub>(sv, 0, 0);
+ testDetail<CharT, TestSub>(sv, 1, 0);
+ testDetail<CharT, TestSub>(sv, 20, 0);
+ testDetail<CharT, TestSub>(sv, sv.size(), 0);
- testDetail(sv, testSub, 0, std::basic_string_view<CharT>::npos);
- testDetail(sv, testSub, 2, std::basic_string_view<CharT>::npos);
- testDetail(sv, testSub, sv.size(), std::basic_string_view<CharT>::npos);
+ testDetail<CharT, TestSub>(sv, 100, 3);
- testDetail(sv, testSub, sv.size() + 1, 0);
- testDetail(sv, testSub, sv.size() + 1, 1);
- testDetail(sv, testSub, sv.size() + 1, std::basic_string_view<CharT>::npos);
+ testDetail<CharT, TestSub>(sv, 0, std::basic_string_view<CharT>::npos);
+ testDetail<CharT, TestSub>(sv, 2, std::basic_string_view<CharT>::npos);
+ testDetail<CharT, TestSub>(sv, sv.size(), std::basic_string_view<CharT>::npos);
+
+ testDetail<CharT, TestSub>(sv, sv.size() + 1, 0);
+ testDetail<CharT, TestSub>(sv, sv.size() + 1, 1);
+ testDetail<CharT, TestSub>(sv, sv.size() + 1, std::basic_string_view<CharT>::npos);
}
template <typename CharT>
void testSubs(const CharT* s) {
- std::basic_string_view<CharT> sv(s);
-
- testCases(sv, &std::basic_string_view<CharT>::substr);
+ testCases<CharT, &std::basic_string_view<CharT>::substr>(s);
#if TEST_STD_VER >= 26
- testCases(sv, &std::basic_string_view<CharT>::subview);
+ testCases<CharT, &std::basic_string_view<CharT>::subview>(s);
#endif // TEST_STD_VER >= 26
}
diff --git a/libcxx/test/std/strings/string.view/string.view.ops/subview.pass.cpp b/libcxx/test/std/strings/string.view/string.view.ops/subview.pass.cpp
new file mode 100644
index 0000000000000..fec258eef4546
--- /dev/null
+++ b/libcxx/test/std/strings/string.view/string.view.ops/subview.pass.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <string_view>
+
+// constexpr basic_string_view subview(size_type pos = 0,
+// size_type n = npos) const; // freestanding-deleted
+
+int main(int, char**) {
+ // This test is intentionally empty because subview is an alias for substr
+ // and is tested in substr.pass.cpp.
+ return 0;
+}
>From 14162bf3567254c5f4dd8088cd8f8cfeadbf2fe6 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 22 Jul 2025 22:01:54 +0300
Subject: [PATCH 3/5] LLVM22
---
libcxx/docs/FeatureTestMacroTable.rst | 2 ++
libcxx/docs/ReleaseNotes/22.rst | 1 +
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
libcxx/include/version | 2 ++
.../string.version.compile.pass.cpp | 30 +++++++++++++++++++
.../string_view.version.compile.pass.cpp | 30 +++++++++++++++++++
.../version.version.compile.pass.cpp | 30 +++++++++++++++++++
.../generate_feature_test_macro_components.py | 5 ++++
8 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 61805726a4ff0..63af1ffd77ca4 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -404,6 +404,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_string_resize_and_overwrite`` ``202110L``
---------------------------------------------------------- -----------------
+ ``__cpp_lib_string_subview`` ``202506L``
+ ---------------------------------------------------------- -----------------
``__cpp_lib_to_underlying`` ``202102L``
---------------------------------------------------------- -----------------
``__cpp_lib_tuple_like`` *unimplemented*
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 15bf46d44b07f..9361dc0ee8753 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -39,6 +39,7 @@ Implemented Papers
------------------
- P2321R2: ``zip`` (`Github <https://github.com/llvm/llvm-project/issues/105169>`__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release)
+- P3044R2: sub-``string_view`` from ``string`` (`Github <https://github.com/llvm/llvm-project/issues/148140>`__)
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index febb0c176f9c4..d954c4b9bbdec 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -129,7 +129,7 @@
"`P3179R9 <https://wg21.link/P3179R9>`__","Parallel Range Algorithms","2025-06 (Sofia)","","",""
"`P3709R2 <https://wg21.link/P3709R2>`__","Reconsider parallel ``ranges::rotate_copy`` and ``ranges::reverse_copy``","2025-06 (Sofia)","","",""
"`P3641R0 <https://wg21.link/P3641R0>`__","Rename ``std::observable`` to ``std::observable_checkpoint``, and add a feature-test macro","2025-06 (Sofia)","","",""
-"`P3044R2 <https://wg21.link/P3044R2>`__","sub-``string_view`` from ``string``","2025-06 (Sofia)","","",""
+"`P3044R2 <https://wg21.link/P3044R2>`__","sub-``string_view`` from ``string``","2025-06 (Sofia)","|Complete|","22",""
"`P2876R3 <https://wg21.link/P2876R3>`__","Proposal to extend ``std::simd`` with more constructors and accessors","2025-06 (Sofia)","","",""
"`P3480R6 <https://wg21.link/P3480R6>`__","``std::simd`` is a range","2025-06 (Sofia)","","",""
"`P2664R11 <https://wg21.link/P2664R11>`__","Extend ``std::simd`` with permutation API","2025-06 (Sofia)","","",""
diff --git a/libcxx/include/version b/libcxx/include/version
index d98049bd57046..dd874c7d50c74 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -245,6 +245,7 @@ __cpp_lib_starts_ends_with 201711L <string> <string
__cpp_lib_stdatomic_h 202011L <stdatomic.h>
__cpp_lib_string_contains 202011L <string> <string_view>
__cpp_lib_string_resize_and_overwrite 202110L <string>
+__cpp_lib_string_subview 202506L <string> <string_view>
__cpp_lib_string_udls 201304L <string>
__cpp_lib_string_view 202403L <string> <string_view>
201803L // C++20
@@ -535,6 +536,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_stdatomic_h 202011L
# define __cpp_lib_string_contains 202011L
# define __cpp_lib_string_resize_and_overwrite 202110L
+# define __cpp_lib_string_subview 202506L
# define __cpp_lib_to_underlying 202102L
// # define __cpp_lib_tuple_like 202207L
# define __cpp_lib_unreachable 202202L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
index 7236d5d7f2aca..c69c8ed59fb61 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
@@ -60,6 +60,10 @@
# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should not be defined before c++14"
# endif
@@ -114,6 +118,10 @@
# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++14"
# endif
@@ -177,6 +185,10 @@
# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++17"
# endif
@@ -261,6 +273,10 @@
# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++20"
# endif
@@ -354,6 +370,13 @@
# error "__cpp_lib_string_resize_and_overwrite should have the value 202110L in c++23"
# endif
+# ifndef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should be defined in c++23"
+# endif
+# if __cpp_lib_string_subview != 202506L
+# error "__cpp_lib_string_subview should have the value 202506L in c++23"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++23"
# endif
@@ -456,6 +479,13 @@
# error "__cpp_lib_string_resize_and_overwrite should have the value 202110L in c++26"
# endif
+# ifndef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should be defined in c++26"
+# endif
+# if __cpp_lib_string_subview != 202506L
+# error "__cpp_lib_string_subview should have the value 202506L in c++26"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++26"
# endif
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp
index c7bafb0bf059c..ed13f392b1b7f 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp
@@ -40,6 +40,10 @@
# error "__cpp_lib_string_contains should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_string_view
# error "__cpp_lib_string_view should not be defined before c++17"
# endif
@@ -66,6 +70,10 @@
# error "__cpp_lib_string_contains should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_string_view
# error "__cpp_lib_string_view should not be defined before c++17"
# endif
@@ -92,6 +100,10 @@
# error "__cpp_lib_string_contains should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifndef __cpp_lib_string_view
# error "__cpp_lib_string_view should be defined in c++17"
# endif
@@ -136,6 +148,10 @@
# error "__cpp_lib_string_contains should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifndef __cpp_lib_string_view
# error "__cpp_lib_string_view should be defined in c++20"
# endif
@@ -183,6 +199,13 @@
# error "__cpp_lib_string_contains should have the value 202011L in c++23"
# endif
+# ifndef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should be defined in c++23"
+# endif
+# if __cpp_lib_string_subview != 202506L
+# error "__cpp_lib_string_subview should have the value 202506L in c++23"
+# endif
+
# ifndef __cpp_lib_string_view
# error "__cpp_lib_string_view should be defined in c++23"
# endif
@@ -239,6 +262,13 @@
# error "__cpp_lib_string_contains should have the value 202011L in c++26"
# endif
+# ifndef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should be defined in c++26"
+# endif
+# if __cpp_lib_string_subview != 202506L
+# error "__cpp_lib_string_subview should have the value 202506L in c++26"
+# endif
+
# ifndef __cpp_lib_string_view
# error "__cpp_lib_string_view should be defined in c++26"
# endif
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 962688e06188a..0df86fbb825e4 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -820,6 +820,10 @@
# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should not be defined before c++14"
# endif
@@ -1775,6 +1779,10 @@
# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++14"
# endif
@@ -2916,6 +2924,10 @@
# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++17"
# endif
@@ -4330,6 +4342,10 @@
# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++23"
# endif
+# ifdef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should not be defined before c++23"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++20"
# endif
@@ -5978,6 +5994,13 @@
# error "__cpp_lib_string_resize_and_overwrite should have the value 202110L in c++23"
# endif
+# ifndef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should be defined in c++23"
+# endif
+# if __cpp_lib_string_subview != 202506L
+# error "__cpp_lib_string_subview should have the value 202506L in c++23"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++23"
# endif
@@ -7947,6 +7970,13 @@
# error "__cpp_lib_string_resize_and_overwrite should have the value 202110L in c++26"
# endif
+# ifndef __cpp_lib_string_subview
+# error "__cpp_lib_string_subview should be defined in c++26"
+# endif
+# if __cpp_lib_string_subview != 202506L
+# error "__cpp_lib_string_subview should have the value 202506L in c++26"
+# endif
+
# ifndef __cpp_lib_string_udls
# error "__cpp_lib_string_udls should be defined in c++26"
# endif
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index fe175fd758726..75cc8705ecffb 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1337,6 +1337,11 @@ def add_version_header(tc):
"values": {"c++23": 202110},
"headers": ["string"],
},
+ {
+ "name": "__cpp_lib_string_subview",
+ "values": {"c++23": 202506},
+ "headers": ["string", "string_view"],
+ },
{
"name": "__cpp_lib_string_udls",
"values": {"c++14": 201304},
>From f9efc16976cf10bdd2941e0d5061db5caa793005 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 23 Jul 2025 01:21:11 +0300
Subject: [PATCH 4/5] Updated test
---
.../string.ops/string_substr/subview.pass.cpp | 47 +++++++++++++++++--
1 file changed, 42 insertions(+), 5 deletions(-)
diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp
index 65418dcb4d7be..4fd2a4ceb5f7a 100644
--- a/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp
@@ -15,12 +15,49 @@
#include <cassert>
#include <string>
+#include "asan_testing.h"
+#include "constexpr_char_traits.h"
+#include "make_string.h"
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+#define CS(S) MAKE_CSTRING(CharT, S)
+
+template <typename CharT, typename TraitsT, typename AllocT>
+constexpr void test() {
+ std::basic_string<CharT, TraitsT, AllocT> s{CS("Hello cruel world!"), AllocT{}};
+
+ std::same_as<std::basic_string_view<CharT, TraitsT>> decltype(auto) sv = s.subview(6);
+ assert(sv == CS("cruel world!"));
+
+ std::same_as<std::basic_string_view<CharT, TraitsT>> decltype(auto) subsv = sv.subview(0, 5);
+ assert(subsv == CS("cruel"));
+}
+
+template <typename CharT>
+constexpr void test() {
+ test<CharT, std::char_traits<CharT>, std::allocator<CharT>>();
+ test<CharT, std::char_traits<CharT>, min_allocator<CharT>>();
+ test<CharT, std::char_traits<CharT>, safe_allocator<CharT>>();
+ test<CharT, std::char_traits<CharT>, test_allocator<CharT>>();
+
+ test<CharT, constexpr_char_traits<CharT>, std::allocator<CharT>>();
+ test<CharT, constexpr_char_traits<CharT>, min_allocator<CharT>>();
+ test<CharT, constexpr_char_traits<CharT>, safe_allocator<CharT>>();
+ test<CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>();
+}
+
constexpr bool test() {
- std::string s{"Hello cruel world!"};
- auto sub = s.subview(6);
- assert(sub == "cruel world!");
- auto subsub = sub.subview(0, 5);
- assert(subsub == "cruel");
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
+ test<char8_t>();
+#endif
+ test<char16_t>();
+ test<char32_t>();
return true;
}
>From 3dbebaee031930e6658b8748cd670f566a4ccabd Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 23 Jul 2025 09:03:19 +0300
Subject: [PATCH 5/5] Fix the test!!!
---
.../string.ops/string_substr/subview.pass.cpp | 28 +++++++++++++++----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp
index 4fd2a4ceb5f7a..63beedf829039 100644
--- a/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/subview.pass.cpp
@@ -15,7 +15,6 @@
#include <cassert>
#include <string>
-#include "asan_testing.h"
#include "constexpr_char_traits.h"
#include "make_string.h"
#include "min_allocator.h"
@@ -28,11 +27,30 @@ template <typename CharT, typename TraitsT, typename AllocT>
constexpr void test() {
std::basic_string<CharT, TraitsT, AllocT> s{CS("Hello cruel world!"), AllocT{}};
- std::same_as<std::basic_string_view<CharT, TraitsT>> decltype(auto) sv = s.subview(6);
- assert(sv == CS("cruel world!"));
+ { // With a default position and a character length.
+ std::same_as<std::basic_string_view<CharT, TraitsT>> decltype(auto) sv = s.subview();
+ assert(sv == CS("Hello cruel world!"));
+ }
- std::same_as<std::basic_string_view<CharT, TraitsT>> decltype(auto) subsv = sv.subview(0, 5);
- assert(subsv == CS("cruel"));
+ { // With a explict position and a character length.
+ std::same_as<std::basic_string_view<CharT, TraitsT>> decltype(auto) sv = s.subview(6, 5);
+ assert(sv == CS("cruel"));
+ }
+
+ { // From the beginning of the string with a explicit character length.
+ std::same_as<std::basic_string_view<CharT, TraitsT>> decltype(auto) sv = s.subview(0, 5);
+ assert(sv == CS("Hello"));
+ }
+
+ { // To the end of string with the default character length.
+ std::same_as<std::basic_string_view<CharT, TraitsT>> decltype(auto) sv = s.subview(12);
+ assert(sv == CS("world!"));
+ }
+
+ { // From the beginning to the end of the string with explicit values.
+ std::same_as<std::basic_string_view<CharT, TraitsT>> decltype(auto) sv = s.subview(0, s.size());
+ assert(sv == CS("Hello cruel world!"));
+ }
}
template <typename CharT>
More information about the libcxx-commits
mailing list