diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -46,6 +46,7 @@ ``from_chars`` for Integral Types in ```` Header - P0220R1 - Adopt Library Fundamentals V1 TS Components for C++17 - P0482R6 - char8_t: A type for UTF-8 characters and strings +- 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","|Complete|","16.0" "`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 @@ -897,6 +902,36 @@ std::__debug_db_insert_c(this); } +#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 { + // Perform a copy because the allocators are not compatible. + __init(__str.data() + __pos, __len); + } + + std::__debug_db_insert_c(this); + if (__is_long()) + std::__debug_db_swap(this, &__str); + } +#endif + template ::value, nullptr_t> > _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(size_type __n, _CharT __c, const _Allocator& __a); @@ -1324,8 +1359,24 @@ #endif // _LIBCPP_CXX03_LANG _LIBCPP_CONSTEXPR_SINCE_CXX20 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_SINCE_CXX20 - 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_SINCE_CXX20 void swap(basic_string& __str) @@ -3472,14 +3523,6 @@ return __rlen; } -template -inline _LIBCPP_CONSTEXPR_SINCE_CXX20 -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_SINCE_CXX20 void diff --git a/libcxx/test/libcxx/strings/basic.string/string.cons/debug.iterator.substr.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.cons/debug.iterator.substr.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/strings/basic.string/string.cons/debug.iterator.substr.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// Check that basic_string(basic_string&&, size_type, Allocator) and +// basic_string(basic_string&&, size_type, size_type, Allocator) inserts the container into the debug database + +// REQUIRES: has-unix-headers +// UNSUPPORTED: !libcpp-has-debug-mode, c++03 + +#include +#include + +#include "check_assertion.h" + +int main(int, char**) { + using namespace std::string_literals; + + { + std::string s = {"Banane"s, 1}; + auto i = s.begin(); + assert(i[0] == 'a'); + TEST_LIBCPP_ASSERT_FAILURE(i[5], "Attempted to subscript an iterator outside its valid range"); + } + { + std::string s = {"Banane"s, 0, 5}; + auto i = s.begin(); + assert(i[0] == 'B'); + TEST_LIBCPP_ASSERT_FAILURE(i[5], "Attempted to subscript an iterator outside its valid range"); + } + { + std::string s = {"long long string so no SSO"s, 21}; + auto i = s.begin(); + assert(i[0] == 'o'); + TEST_LIBCPP_ASSERT_FAILURE(i[5], "Attempted to subscript an iterator outside its valid range"); + } + { + std::string s = {"long long string so no SSO"s, 0, 5}; + auto i = s.begin(); + assert(i[0] == 'l'); + TEST_LIBCPP_ASSERT_FAILURE(i[5], "Attempted to subscript an iterator outside its valid range"); + } +} diff --git a/libcxx/test/libcxx/strings/basic.string/string.iterators/debug.iterator.index.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.iterators/debug.iterator.index.pass.cpp --- a/libcxx/test/libcxx/strings/basic.string/string.iterators/debug.iterator.index.pass.cpp +++ b/libcxx/test/libcxx/strings/basic.string/string.iterators/debug.iterator.index.pass.cpp @@ -20,6 +20,7 @@ #include "min_allocator.h" int main(int, char**) { + using T = decltype(uint8_t() - uint8_t()); { typedef std::string C; C c(1, '\0'); 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,233 @@ +//===----------------------------------------------------------------------===// +// +// 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) + +constexpr struct should_throw_exception_t { +} should_throw_exception; + +template +constexpr void test_string_pos(S orig, typename S::size_type pos, S expected) { +#ifdef _LIBCPP_VERSION + ConstexprDisableAllocationGuard g; +#endif + S substr(std::move(orig), pos); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(orig.empty()); + LIBCPP_ASSERT(substr.__invariants()); + assert(substr == expected); +} + +template +constexpr void test_string_pos(S orig, typename S::size_type pos, should_throw_exception_t) { +#ifndef TEST_HAS_NO_EXCEPTIONS + if (!std::is_constant_evaluated()) { + try { + [[maybe_unused]] S substr = S(std::move(orig), pos); + assert(false); + } catch (const std::out_of_range&) { + } + } +#else + (void)orig; + (void)pos; +#endif +} + +template +constexpr void +test_string_pos_alloc(S orig, typename S::size_type pos, const typename S::allocator_type& alloc, S expected) { + S substr(std::move(orig), pos, alloc); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(substr.__invariants()); + assert(substr == expected); + assert(substr.get_allocator() == alloc); +} + +template +constexpr void test_string_pos_alloc( + S orig, typename S::size_type pos, const typename S::allocator_type& alloc, should_throw_exception_t) { +#ifndef TEST_HAS_NO_EXCEPTIONS + if (!std::is_constant_evaluated()) { + try { + [[maybe_unused]] S substr = S(std::move(orig), pos, alloc); + assert(false); + } catch (const std::out_of_range&) { + } + } +#else + (void)orig; + (void)pos; + (void)alloc; +#endif +} + +template +constexpr void test_string_pos_n(S orig, typename S::size_type pos, typename S::size_type n, S expected) { +#ifdef _LIBCPP_VERSION + ConstexprDisableAllocationGuard g; +#endif + S substr(std::move(orig), pos, n); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(orig.empty()); + LIBCPP_ASSERT(substr.__invariants()); + assert(substr == expected); +} + +template +constexpr void test_string_pos_n(S orig, typename S::size_type pos, typename S::size_type n, should_throw_exception_t) { +#ifndef TEST_HAS_NO_EXCEPTIONS + if (!std::is_constant_evaluated()) { + try { + [[maybe_unused]] S substr = S(std::move(orig), pos, n); + assert(false); + } catch (const std::out_of_range&) { + } + } +#else + (void)orig; + (void)pos; + (void)n; +#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) { + S substr(std::move(orig), pos, n, alloc); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(substr.__invariants()); + assert(substr == expected); + assert(substr.get_allocator() == alloc); +} + +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, + should_throw_exception_t) { +#ifndef TEST_HAS_NO_EXCEPTIONS + 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&) { + } + } +#else + (void)orig; + (void)pos; + (void)n; + (void)alloc; +#endif +} + +template +constexpr void test_string(const typename S::allocator_type& alloc) { + test_string_pos(STR(""), 0, STR("")); + test_string_pos(STR(""), 1, should_throw_exception); + test_string_pos(STR("Banane"), 1, STR("anane")); + test_string_pos(STR("Banane"), 6, STR("")); + test_string_pos(STR("Banane"), 7, should_throw_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, should_throw_exception); + + test_string_pos_alloc(STR(""), 0, alloc, STR("")); + test_string_pos_alloc(STR(""), 1, alloc, should_throw_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, should_throw_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, should_throw_exception); + + test_string_pos_n(STR(""), 0, 0, STR("")); + test_string_pos_n(STR(""), 0, 1, STR("")); + test_string_pos_n(STR(""), 1, 0, should_throw_exception); + test_string_pos_n(STR(""), 1, 1, should_throw_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, should_throw_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, should_throw_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, should_throw_exception); + test_string_pos_n_alloc(STR(""), 1, 1, alloc, should_throw_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, should_throw_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, should_throw_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,103 @@ +//===----------------------------------------------------------------------===// +// +// 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) + +constexpr struct should_throw_exception_t { +} should_throw_exception; + +template +constexpr void test(S orig, size_t pos, ptrdiff_t n, S expected) { + S str = std::move(orig).substr(pos, n); + LIBCPP_ASSERT(orig.__invariants()); + LIBCPP_ASSERT(str.__invariants()); + assert(str == expected); +} + +template +constexpr void test(S orig, size_t pos, ptrdiff_t n, should_throw_exception_t) { +#ifndef TEST_HAS_NO_EXCEPTIONS + if (!std::is_constant_evaluated()) { + try { + S str = std::move(orig).substr(pos, n); + assert(false); + } catch (const std::out_of_range&) { + } + } +#else + (void)orig; + (void)pos; + (void)n; +#endif +} + +template +constexpr void test_string() { + test(STR(""), 0, 0, STR("")); + test(STR(""), 0, 1, STR("")); + test(STR(""), 1, 0, should_throw_exception); + test(STR(""), 1, 1, should_throw_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, should_throw_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, should_throw_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 @@ -472,6 +472,40 @@ DisableAllocationGuard& operator=(DisableAllocationGuard const&); }; +#if TEST_STD_VER >= 20 + +struct ConstexprDisableAllocationGuard { + TEST_CONSTEXPR_CXX14 explicit ConstexprDisableAllocationGuard(bool disable = true) : m_disabled(disable) + { + 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(); + } else { + m_disabled = false; + } + } + + TEST_CONSTEXPR_CXX14 void release() { + if (!TEST_IS_CONSTANT_EVALUATED) { + if (m_disabled) globalMemCounter.enableAllocations(); + m_disabled = false; + } + } + + TEST_CONSTEXPR_CXX20 ~ConstexprDisableAllocationGuard() { + release(); + } + +private: + bool m_disabled; + + ConstexprDisableAllocationGuard(ConstexprDisableAllocationGuard const&); + ConstexprDisableAllocationGuard& operator=(ConstexprDisableAllocationGuard const&); +}; + +#endif + struct RequireAllocationGuard { explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1) : m_req_alloc(RequireAtLeast), 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) \