diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -39,6 +39,7 @@ ------------------ - P2499R0 - ``string_view`` range constructor should be ``explicit`` - P2417R2 - A more constexpr bitset +- P2438R2 - ``std::string::substr() &&`` Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -71,7 +71,7 @@ "`P2408R5 `__","LWG","Ranges iterators as inputs to non-Ranges algorithms","July 2022","","" "`P2417R2 `__","LWG","A more ``constexpr`` ``bitset``","July 2022","|Complete|","16.0" "`P2419R2 `__","LWG","Clarify handling of encodings in localized formatting of chrono types","July 2022","","" -"`P2438R2 `__","LWG","``std::string::substr() &&``","July 2022","","" +"`P2438R2 `__","LWG","``std::string::substr() &&``","July 2022","|Complete|","16.0" "`P2445R1 `__","LWG","``forward_like``","July 2022","","" "`P2446R2 `__","LWG","``views::as_rvalue``","July 2022","","" "`P2460R2 `__","LWG","Relax requirements on ``wchar_t`` to match existing practices","July 2022","","" diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -109,6 +109,10 @@ const allocator_type& a = allocator_type()); // constexpr since C++20 basic_string(const basic_string& str, size_type pos, size_type n, const Allocator& a = Allocator()); // constexpr since C++20 + constexpr basic_string( + basic_string&& str, size_type pos, const Allocator& a = Allocator()); // since C++23 + constexpr basic_string( + basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); // since C++23 template basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); // C++17, constexpr since C++20 template @@ -261,8 +265,9 @@ basic_string& replace(const_iterator i1, const_iterator i2, initializer_list); // constexpr since C++20 size_type copy(value_type* s, size_type n, size_type pos = 0) const; // constexpr since C++20 - basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr since C++20 - + 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 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 @@ -877,11 +882,38 @@ basic_string(size_type __n, _CharT __c, const _Allocator& __a); _LIBCPP_CONSTEXPR_AFTER_CXX17 - basic_string(const basic_string& __str, size_type __pos, size_type __n, - const _Allocator& __a = _Allocator()); + basic_string(const basic_string& __str, size_type __pos, size_type __n, const _Allocator& __a = _Allocator()); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 - basic_string(const basic_string& __str, size_type __pos, - const _Allocator& __a = _Allocator()); + basic_string(const basic_string& __str, size_type __pos, const _Allocator& __a = _Allocator()); + +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + basic_string(basic_string&& __str, size_type __pos, const _Allocator& __alloc = _Allocator()) + : basic_string(std::move(__str), __pos, npos, __alloc) {} + + _LIBCPP_HIDE_FROM_ABI constexpr + basic_string(basic_string&& __str, size_type __pos, size_type __n, const _Allocator& __alloc = _Allocator()) + : __r_(__default_init_tag(), __alloc) { + if (__pos > __str.size()) + __throw_out_of_range(); + + auto __len = std::min(__n, __str.size() - __pos); + if (__alloc_traits::is_always_equal::value || __alloc == __str.__alloc()) { + __r_.first() = __str.__r_.first(); + __str.__default_init(); + + _Traits::move(data(), data() + __pos, __len); + __set_size(__len); + _Traits::assign(data()[__len], value_type()); + } else { + __init(__str.data() + __pos, __len); + } + + std::__debug_db_insert_c(this); + if (__is_long()) + std::__debug_db_swap(this, &__str); + } +#endif template::value && !__is_same_uncvref<_Tp, basic_string>::value> > _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -1274,8 +1306,24 @@ #endif // _LIBCPP_CXX03_LANG _LIBCPP_CONSTEXPR_AFTER_CXX17 size_type copy(value_type* __s, size_type __n, size_type __pos = 0) const; + + // TODO: Maybe don't pass in the allocator. See https://llvm.org/PR57190 +#if _LIBCPP_STD_VER <= 20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 - basic_string substr(size_type __pos = 0, size_type __n = npos) const; + basic_string substr(size_type __pos = 0, size_type __n = npos) const { + return basic_string(*this, __pos, __n, __alloc()); + } +#else + _LIBCPP_HIDE_FROM_ABI constexpr + basic_string substr(size_type __pos = 0, size_type __n = npos) const& { + return basic_string(*this, __pos, __n, __alloc()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr + basic_string substr(size_type __pos = 0, size_type __n = npos) && { + return basic_string(std::move(*this), __pos, __n, __alloc()); + } +#endif _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(basic_string& __str) @@ -3578,14 +3626,6 @@ return __rlen; } -template -inline _LIBCPP_CONSTEXPR_AFTER_CXX17 -basic_string<_CharT, _Traits, _Allocator> -basic_string<_CharT, _Traits, _Allocator>::substr(size_type __pos, size_type __n) const -{ - return basic_string(*this, __pos, __n, __alloc()); -} - template inline _LIBCPP_CONSTEXPR_AFTER_CXX17 void diff --git a/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp @@ -0,0 +1,204 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14, c++17, c++20 + +// + +// constexpr basic_string(basic_string&& str, size_type pos, const Allocator& a = Allocator()); +// constexpr basic_string(basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); + +#include +#include + +#include "constexpr_char_traits.h" +#include "count_new.h" +#include "make_string.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_macros.h" + +#define STR(string) MAKE_CSTRING(typename S::value_type, string) + +template +constexpr void test_string_pos(S orig, typename S::size_type pos, S expected) { + if (pos <= orig.size()) { +#ifdef _LIBCPP_VERSION + DisableAllocationGuard g; +#endif + S substr(std::move(orig), pos); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(orig.empty()); + LIBCPP_ASSERT(substr.__invariants()); + assert(substr == expected); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + else if (!std::is_constant_evaluated()) { + try { + [[maybe_unused]] S substr = S(std::move(orig), pos); + assert(false); + } catch (const std::out_of_range&) { + assert(expected == STR("exception")); + } + } +#endif +} + +template +constexpr void +test_string_pos_alloc(S orig, typename S::size_type pos, const typename S::allocator_type& alloc, S expected) { + if (pos <= orig.size()) { + S substr(std::move(orig), pos, alloc); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(substr.__invariants()); + assert(substr == expected); + assert(substr.get_allocator() == alloc); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + else if (!std::is_constant_evaluated()) { + try { + [[maybe_unused]] S substr = S(std::move(orig), pos, alloc); + assert(false); + } catch (const std::out_of_range&) { + assert(expected == STR("exception")); + } + } +#endif +} + +template +constexpr void test_string_pos_n(S orig, typename S::size_type pos, typename S::size_type n, S expected) { + if (pos <= orig.size()) { +#ifdef _LIBCPP_VERSION + DisableAllocationGuard g; +#endif + S substr(std::move(orig), pos, n); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(orig.empty()); + LIBCPP_ASSERT(substr.__invariants()); + assert(substr == expected); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + else if (!std::is_constant_evaluated()) { + try { + [[maybe_unused]] S substr = S(std::move(orig), pos, n); + assert(false); + } catch (const std::out_of_range&) { + assert(expected == STR("exception")); + } + } +#endif +} + +template +constexpr void test_string_pos_n_alloc( + S orig, typename S::size_type pos, typename S::size_type n, const typename S::allocator_type& alloc, S expected) { + if (pos <= orig.size()) { + S substr(std::move(orig), pos, n, alloc); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(substr.__invariants()); + assert(substr == expected); + assert(substr.get_allocator() == alloc); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + else if (!std::is_constant_evaluated()) { + try { + [[maybe_unused]] S substr = S(std::move(orig), pos, n, alloc); + assert(false); + } catch (const std::out_of_range&) { + assert(expected == STR("exception")); + } + } +#endif +} + +template +constexpr void test_string(const typename S::allocator_type& alloc) { + test_string_pos(STR(""), 0, STR("")); + test_string_pos(STR(""), 1, STR("exception")); + test_string_pos(STR("Banane"), 1, STR("anane")); + test_string_pos(STR("Banane"), 6, STR("")); + test_string_pos(STR("Banane"), 7, STR("exception")); + test_string_pos(STR("long long string so no SSO"), 0, STR("long long string so no SSO")); + test_string_pos(STR("long long string so no SSO"), 10, STR("string so no SSO")); + test_string_pos(STR("long long string so no SSO"), 26, STR("")); + test_string_pos(STR("long long string so no SSO"), 27, STR("exception")); + + test_string_pos_alloc(STR(""), 0, alloc, STR("")); + test_string_pos_alloc(STR(""), 1, alloc, STR("exception")); + test_string_pos_alloc(STR("Banane"), 1, alloc, STR("anane")); + test_string_pos_alloc(STR("Banane"), 6, alloc, STR("")); + test_string_pos_alloc(STR("Banane"), 7, alloc, STR("exception")); + test_string_pos_alloc(STR("long long string so no SSO"), 0, alloc, STR("long long string so no SSO")); + test_string_pos_alloc(STR("long long string so no SSO"), 10, alloc, STR("string so no SSO")); + test_string_pos_alloc(STR("long long string so no SSO"), 26, alloc, STR("")); + test_string_pos_alloc(STR("long long string so no SSO"), 27, alloc, STR("exception")); + + test_string_pos_n(STR(""), 0, 0, STR("")); + test_string_pos_n(STR(""), 0, 1, STR("")); + test_string_pos_n(STR(""), 1, 0, STR("exception")); + test_string_pos_n(STR(""), 1, 1, STR("exception")); + test_string_pos_n(STR("Banane"), 1, 10, STR("anane")); + test_string_pos_n(STR("Banane"), 6, 0, STR("")); + test_string_pos_n(STR("Banane"), 6, 5, STR("")); + test_string_pos_n(STR("Banane"), 7, 10, STR("exception")); + test_string_pos_n(STR("long long string so no SSO"), 0, 10, STR("long long ")); + test_string_pos_n(STR("long long string so no SSO"), 10, 8, STR("string s")); + test_string_pos_n(STR("long long string so no SSO"), 20, 10, STR("no SSO")); + test_string_pos_n(STR("long long string so no SSO"), 26, 10, STR("")); + test_string_pos_n(STR("long long string so no SSO"), 27, 10, STR("exception")); + + test_string_pos_n_alloc(STR(""), 0, 0, alloc, STR("")); + test_string_pos_n_alloc(STR(""), 0, 1, alloc, STR("")); + test_string_pos_n_alloc(STR(""), 1, 0, alloc, STR("exception")); + test_string_pos_n_alloc(STR(""), 1, 1, alloc, STR("exception")); + test_string_pos_n_alloc(STR("Banane"), 1, 10, alloc, STR("anane")); + test_string_pos_n_alloc(STR("Banane"), 6, 0, alloc, STR("")); + test_string_pos_n_alloc(STR("Banane"), 6, 5, alloc, STR("")); + test_string_pos_n_alloc(STR("Banane"), 7, 10, alloc, STR("exception")); + test_string_pos_n_alloc(STR("long long string so no SSO"), 0, 10, alloc, STR("long long ")); + test_string_pos_n_alloc(STR("long long string so no SSO"), 10, 8, alloc, STR("string s")); + test_string_pos_n_alloc(STR("long long string so no SSO"), 20, 10, alloc, STR("no SSO")); + test_string_pos_n_alloc(STR("long long string so no SSO"), 26, 10, alloc, STR("")); + test_string_pos_n_alloc(STR("long long string so no SSO"), 27, 10, alloc, STR("exception")); +} + +template +constexpr void test_allocators() { + test_string>>(std::allocator{}); + test_string>>(min_allocator{}); + test_string>>(test_allocator{42}); +} + +template +constexpr bool test_char_traits() { + test_allocators>(); + test_allocators>(); + + return true; +} + +int main(int, char**) { + // TODO: put these into a single function when we increase the constexpr step limit + test_char_traits(); + static_assert(test_char_traits()); + test_char_traits(); + static_assert(test_char_traits()); + test_char_traits(); + static_assert(test_char_traits()); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_char_traits(); + static_assert(test_char_traits()); +#endif +#ifndef TEST_HAS_NO_CHAR8_T + test_char_traits(); + static_assert(test_char_traits()); +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp @@ -8,7 +8,8 @@ // -// basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr since C++20 +// basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr since C++20, removed in C++23 +// basic_string substr(size_type pos = 0, size_type n = npos) const&; // since in C++23 #include #include @@ -47,130 +48,72 @@ #endif } +template +TEST_CONSTEXPR_CXX20 void test_string() { + test(S(""), 0, 0); + test(S(""), 1, 0); + test(S("pniot"), 0, 0); + test(S("htaob"), 0, 1); + test(S("fodgq"), 0, 2); + test(S("hpqia"), 0, 4); + test(S("qanej"), 0, 5); + test(S("dfkap"), 1, 0); + test(S("clbao"), 1, 1); + test(S("ihqrf"), 1, 2); + test(S("mekdn"), 1, 3); + test(S("ngtjf"), 1, 4); + test(S("srdfq"), 2, 0); + test(S("qkdrs"), 2, 1); + test(S("ikcrq"), 2, 2); + test(S("cdaih"), 2, 3); + test(S("dmajb"), 4, 0); + test(S("karth"), 4, 1); + test(S("lhcdo"), 5, 0); + test(S("acbsj"), 6, 0); + test(S("pbsjikaole"), 0, 0); + test(S("pcbahntsje"), 0, 1); + test(S("mprdjbeiak"), 0, 5); + test(S("fhepcrntko"), 0, 9); + test(S("eqmpaidtls"), 0, 10); + test(S("joidhalcmq"), 1, 0); + test(S("omigsphflj"), 1, 1); + test(S("kocgbphfji"), 1, 4); + test(S("onmjekafbi"), 1, 8); + test(S("fbslrjiqkm"), 1, 9); + test(S("oqmrjahnkg"), 5, 0); + test(S("jeidpcmalh"), 5, 1); + test(S("schfalibje"), 5, 2); + test(S("crliponbqe"), 5, 4); + test(S("igdscopqtm"), 5, 5); + test(S("qngpdkimlc"), 9, 0); + test(S("thdjgafrlb"), 9, 1); + test(S("hcjitbfapl"), 10, 0); + test(S("mgojkldsqh"), 11, 0); + test(S("gfshlcmdjreqipbontak"), 0, 0); + test(S("nadkhpfemgclosibtjrq"), 0, 1); + test(S("nkodajteqplrbifhmcgs"), 0, 10); + test(S("ofdrqmkeblthacpgijsn"), 0, 19); + test(S("gbmetiprqdoasckjfhln"), 0, 20); + test(S("bdfjqgatlksriohemnpc"), 1, 0); + test(S("crnklpmegdqfiashtojb"), 1, 1); + test(S("ejqcnahdrkfsmptilgbo"), 1, 9); + test(S("jsbtafedocnirgpmkhql"), 1, 18); + test(S("prqgnlbaejsmkhdctoif"), 1, 19); + test(S("qnmodrtkebhpasifgcjl"), 10, 0); + test(S("pejafmnokrqhtisbcdgl"), 10, 1); + test(S("cpebqsfmnjdolhkratgi"), 10, 5); + test(S("odnqkgijrhabfmcestlp"), 10, 9); + test(S("lmofqdhpkibagnrcjste"), 10, 10); + test(S("lgjqketopbfahrmnsicd"), 19, 0); + test(S("ktsrmnqagdecfhijpobl"), 19, 1); + test(S("lsaijeqhtrbgcdmpfkno"), 20, 0); + test(S("dplqartnfgejichmoskb"), 21, 0); +} + TEST_CONSTEXPR_CXX20 bool test() { - { - typedef std::string S; - test(S(""), 0, 0); - test(S(""), 1, 0); - test(S("pniot"), 0, 0); - test(S("htaob"), 0, 1); - test(S("fodgq"), 0, 2); - test(S("hpqia"), 0, 4); - test(S("qanej"), 0, 5); - test(S("dfkap"), 1, 0); - test(S("clbao"), 1, 1); - test(S("ihqrf"), 1, 2); - test(S("mekdn"), 1, 3); - test(S("ngtjf"), 1, 4); - test(S("srdfq"), 2, 0); - test(S("qkdrs"), 2, 1); - test(S("ikcrq"), 2, 2); - test(S("cdaih"), 2, 3); - test(S("dmajb"), 4, 0); - test(S("karth"), 4, 1); - test(S("lhcdo"), 5, 0); - test(S("acbsj"), 6, 0); - test(S("pbsjikaole"), 0, 0); - test(S("pcbahntsje"), 0, 1); - test(S("mprdjbeiak"), 0, 5); - test(S("fhepcrntko"), 0, 9); - test(S("eqmpaidtls"), 0, 10); - test(S("joidhalcmq"), 1, 0); - test(S("omigsphflj"), 1, 1); - test(S("kocgbphfji"), 1, 4); - test(S("onmjekafbi"), 1, 8); - test(S("fbslrjiqkm"), 1, 9); - test(S("oqmrjahnkg"), 5, 0); - test(S("jeidpcmalh"), 5, 1); - test(S("schfalibje"), 5, 2); - test(S("crliponbqe"), 5, 4); - test(S("igdscopqtm"), 5, 5); - test(S("qngpdkimlc"), 9, 0); - test(S("thdjgafrlb"), 9, 1); - test(S("hcjitbfapl"), 10, 0); - test(S("mgojkldsqh"), 11, 0); - test(S("gfshlcmdjreqipbontak"), 0, 0); - test(S("nadkhpfemgclosibtjrq"), 0, 1); - test(S("nkodajteqplrbifhmcgs"), 0, 10); - test(S("ofdrqmkeblthacpgijsn"), 0, 19); - test(S("gbmetiprqdoasckjfhln"), 0, 20); - test(S("bdfjqgatlksriohemnpc"), 1, 0); - test(S("crnklpmegdqfiashtojb"), 1, 1); - test(S("ejqcnahdrkfsmptilgbo"), 1, 9); - test(S("jsbtafedocnirgpmkhql"), 1, 18); - test(S("prqgnlbaejsmkhdctoif"), 1, 19); - test(S("qnmodrtkebhpasifgcjl"), 10, 0); - test(S("pejafmnokrqhtisbcdgl"), 10, 1); - test(S("cpebqsfmnjdolhkratgi"), 10, 5); - test(S("odnqkgijrhabfmcestlp"), 10, 9); - test(S("lmofqdhpkibagnrcjste"), 10, 10); - test(S("lgjqketopbfahrmnsicd"), 19, 0); - test(S("ktsrmnqagdecfhijpobl"), 19, 1); - test(S("lsaijeqhtrbgcdmpfkno"), 20, 0); - test(S("dplqartnfgejichmoskb"), 21, 0); - } + test_string(); #if TEST_STD_VER >= 11 - { - typedef std::basic_string, min_allocator> S; - test(S(""), 0, 0); - test(S(""), 1, 0); - test(S("pniot"), 0, 0); - test(S("htaob"), 0, 1); - test(S("fodgq"), 0, 2); - test(S("hpqia"), 0, 4); - test(S("qanej"), 0, 5); - test(S("dfkap"), 1, 0); - test(S("clbao"), 1, 1); - test(S("ihqrf"), 1, 2); - test(S("mekdn"), 1, 3); - test(S("ngtjf"), 1, 4); - test(S("srdfq"), 2, 0); - test(S("qkdrs"), 2, 1); - test(S("ikcrq"), 2, 2); - test(S("cdaih"), 2, 3); - test(S("dmajb"), 4, 0); - test(S("karth"), 4, 1); - test(S("lhcdo"), 5, 0); - test(S("acbsj"), 6, 0); - test(S("pbsjikaole"), 0, 0); - test(S("pcbahntsje"), 0, 1); - test(S("mprdjbeiak"), 0, 5); - test(S("fhepcrntko"), 0, 9); - test(S("eqmpaidtls"), 0, 10); - test(S("joidhalcmq"), 1, 0); - test(S("omigsphflj"), 1, 1); - test(S("kocgbphfji"), 1, 4); - test(S("onmjekafbi"), 1, 8); - test(S("fbslrjiqkm"), 1, 9); - test(S("oqmrjahnkg"), 5, 0); - test(S("jeidpcmalh"), 5, 1); - test(S("schfalibje"), 5, 2); - test(S("crliponbqe"), 5, 4); - test(S("igdscopqtm"), 5, 5); - test(S("qngpdkimlc"), 9, 0); - test(S("thdjgafrlb"), 9, 1); - test(S("hcjitbfapl"), 10, 0); - test(S("mgojkldsqh"), 11, 0); - test(S("gfshlcmdjreqipbontak"), 0, 0); - test(S("nadkhpfemgclosibtjrq"), 0, 1); - test(S("nkodajteqplrbifhmcgs"), 0, 10); - test(S("ofdrqmkeblthacpgijsn"), 0, 19); - test(S("gbmetiprqdoasckjfhln"), 0, 20); - test(S("bdfjqgatlksriohemnpc"), 1, 0); - test(S("crnklpmegdqfiashtojb"), 1, 1); - test(S("ejqcnahdrkfsmptilgbo"), 1, 9); - test(S("jsbtafedocnirgpmkhql"), 1, 18); - test(S("prqgnlbaejsmkhdctoif"), 1, 19); - test(S("qnmodrtkebhpasifgcjl"), 10, 0); - test(S("pejafmnokrqhtisbcdgl"), 10, 1); - test(S("cpebqsfmnjdolhkratgi"), 10, 5); - test(S("odnqkgijrhabfmcestlp"), 10, 9); - test(S("lmofqdhpkibagnrcjste"), 10, 10); - test(S("lgjqketopbfahrmnsicd"), 19, 0); - test(S("ktsrmnqagdecfhijpobl"), 19, 1); - test(S("lsaijeqhtrbgcdmpfkno"), 20, 0); - test(S("dplqartnfgejichmoskb"), 21, 0); - } + test_string, min_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// 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: c++03, c++11, c++14, c++17, c++20 + +// + +// constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; + +#include +#include + +#include "constexpr_char_traits.h" +#include "make_string.h" +#include "min_allocator.h" +#include "test_allocator.h" + +#define STR(string) MAKE_CSTRING(typename S::value_type, string) + +template +constexpr void test(S orig, size_t pos, ptrdiff_t n, S expected) { + if (pos <= orig.size()) { + S str = std::move(orig).substr(pos, n); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(str.__invariants()); + assert(str == expected); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + else if (!std::is_constant_evaluated()) { + try { + S str = std::move(orig).substr(pos, n); + assert(false); + } catch (const std::out_of_range&) { + assert(expected == STR("exception")); + } + } +#endif +} + +template +constexpr void test_string() { + test(STR(""), 0, 0, STR("")); + test(STR(""), 0, 1, STR("")); + test(STR(""), 1, 0, STR("exception")); + test(STR(""), 1, 1, STR("exception")); + test(STR("short string"), 0, 1, STR("s")); + test(STR("short string"), 5, 5, STR(" stri")); + test(STR("short string"), 12, 5, STR("")); + test(STR("short string"), 13, 5, STR("exception")); + test(STR("long long string so no SSO"), 0, 0, STR("")); + test(STR("long long string so no SSO"), 0, 10, STR("long long ")); + test(STR("long long string so no SSO"), 10, 10, STR("string so ")); + test(STR("long long string so no SSO"), 20, 10, STR("no SSO")); + test(STR("long long string so no SSO"), 26, 10, STR("")); + test(STR("long long string so no SSO"), 27, 0, STR("exception")); +} + +template +constexpr void test_allocators() { + test_string>>(); + test_string>>(); + test_string>>(); +} + +template +constexpr void test_char_traits() { + test_allocators>(); + test_allocators>(); +} + +constexpr bool test() { + test_char_traits(); + test_char_traits(); + test_char_traits(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_char_traits(); +#endif +#ifndef TEST_HAS_NO_CHAR8_T + test_char_traits(); +#endif + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/support/count_new.h b/libcxx/test/support/count_new.h --- a/libcxx/test/support/count_new.h +++ b/libcxx/test/support/count_new.h @@ -434,19 +434,23 @@ #endif // DISABLE_NEW_COUNT struct DisableAllocationGuard { - explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable) + TEST_CONSTEXPR_CXX14 explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable) { - // Don't re-disable if already disabled. - if (globalMemCounter.disable_allocations == true) m_disabled = false; - if (m_disabled) globalMemCounter.disableAllocations(); + if (!TEST_IS_CONSTANT_EVALUATED) { + // Don't re-disable if already disabled. + if (globalMemCounter.disable_allocations == true) m_disabled = false; + if (m_disabled) globalMemCounter.disableAllocations(); + } } - void release() { - if (m_disabled) globalMemCounter.enableAllocations(); - m_disabled = false; + TEST_CONSTEXPR_CXX14 void release() { + if (!TEST_IS_CONSTANT_EVALUATED) { + if (m_disabled) globalMemCounter.enableAllocations(); + m_disabled = false; + } } - ~DisableAllocationGuard() { + TEST_CONSTEXPR_CXX20 ~DisableAllocationGuard() { release(); } diff --git a/libcxx/test/support/make_string.h b/libcxx/test/support/make_string.h --- a/libcxx/test/support/make_string.h +++ b/libcxx/test/support/make_string.h @@ -89,7 +89,7 @@ // This helper is used in unit tests to make them generic. The input should be // valid ASCII which means the input is also valid UTF-8. #define MAKE_CSTRING(CharT, Str) \ - MKSTR(Str).as_ptr((const CharT*)0) + MKSTR(Str).as_ptr(static_cast(nullptr)) // Like MAKE_CSTRING but makes a basic_string. Embedded nulls are OK. #define MAKE_STRING(CharT, Str) \