diff --git a/libcxx/include/string b/libcxx/include/string index c450ddcb41914..9476c3df3b8e7 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 subview(size_type pos = 0, + size_type n = npos) const; // since C++26 void swap(basic_string& str) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value); // C++17, constexpr since C++20 @@ -1745,6 +1747,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 861187c0640e1..ad036882e1630 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 + +// + +// constexpr basic_string_view<_CharT, _Traits> subview(size_type __pos = 0, size_type __n = npos) const; + +#include +#include + +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 index 62b0259c175f8..02755985ead70 100644 --- 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 @@ -11,6 +11,10 @@ // // 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. @@ -25,15 +29,21 @@ #include "test_macros.h" template -void test1(std::basic_string_view sv, std::size_t n, size_t pos) { +struct Test { + typedef std::basic_string_view (std::basic_string_view::*Sub)( + typename std::basic_string_view::size_type, typename std::basic_string_view::size_type) const; +}; + +template ::Sub TestSub> +void testDetail(std::basic_string_view sv, std::size_t n, size_t pos) { std::basic_string_view sv1; #ifdef TEST_HAS_NO_EXCEPTIONS if (pos > sv.size()) return; // would throw if exceptions were enabled - sv1 = sv.substr(pos, n); + sv1 = (sv.*TestSub)(pos, n); #else try { - sv1 = sv.substr(pos, n); + sv1 = (sv.*TestSub)(pos, n); assert(pos <= sv.size()); } catch (const std::out_of_range&) { assert(pos > sv.size()); @@ -46,79 +56,101 @@ void test1(std::basic_string_view sv, std::size_t n, size_t pos) { assert(sv[pos + i] == sv1[i]); } -template -void test(const CharT* s) { - typedef std::basic_string_view string_view_t; +template ::Sub TestSub> +void testCases(const CharT* s) { + std::basic_string_view sv(s); - string_view_t sv1(s); + testDetail(sv, 0, 0); + testDetail(sv, 1, 0); + testDetail(sv, 20, 0); + testDetail(sv, sv.size(), 0); - test1(sv1, 0, 0); - test1(sv1, 1, 0); - test1(sv1, 20, 0); - test1(sv1, sv1.size(), 0); + testDetail(sv, 100, 3); - test1(sv1, 0, 3); - test1(sv1, 2, 3); - test1(sv1, 100, 3); + testDetail(sv, 0, std::basic_string_view::npos); + testDetail(sv, 2, std::basic_string_view::npos); + testDetail(sv, sv.size(), std::basic_string_view::npos); - test1(sv1, 0, string_view_t::npos); - test1(sv1, 2, string_view_t::npos); - test1(sv1, sv1.size(), string_view_t::npos); + testDetail(sv, sv.size() + 1, 0); + testDetail(sv, sv.size() + 1, 1); + testDetail(sv, sv.size() + 1, std::basic_string_view::npos); +} - test1(sv1, sv1.size() + 1, 0); - test1(sv1, sv1.size() + 1, 1); - test1(sv1, sv1.size() + 1, string_view_t::npos); +template +void testSubs(const CharT* s) { + testCases::substr>(s); +#if TEST_STD_VER >= 26 + testCases::subview>(s); +#endif // TEST_STD_VER >= 26 } -int main(int, char**) { - test("ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE"); - test("ABCDE"); - test("a"); - test(""); +void test() { + testSubs("ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE"); + testSubs("ABCDE"); + testSubs("a"); + testSubs(""); #ifndef TEST_HAS_NO_WIDE_CHARACTERS - test(L"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE"); - test(L"ABCDE"); - test(L"a"); - test(L""); + testSubs( + L"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE"); + testSubs(L"ABCDE"); + testSubs(L"a"); + testSubs(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""); + 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 ::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', ""); + } -#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', ""); - } + 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; 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 + +// + +// 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; +}