[libc++] Implement P2438R2 (std::string::substr() &&)

This doesn't affect our ABI because `std::string::substr()` isn't in the dylib and the mangling of `substr() const` and `substr() const&` are different.

Reviewed By: ldionne, Mordante, var-const, avogelsgesang, #libc

Spies: arphaman, huixie90, libcxx-commits

Differential Revision: https://reviews.llvm.org/D131668
This commit is contained in:
Nikolas Klauser 2022-08-09 13:17:30 +02:00
parent 001d18664f
commit 29378ab24b
10 changed files with 543 additions and 136 deletions

View File

@ -46,6 +46,7 @@ Implemented Papers
``from_chars`` for Integral Types in ``<charconv>`` 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
-----------------------------

View File

@ -71,7 +71,7 @@
"`P2408R5 <https://wg21.link/P2408R5>`__","LWG","Ranges iterators as inputs to non-Ranges algorithms","July 2022","",""
"`P2417R2 <https://wg21.link/P2417R2>`__","LWG","A more ``constexpr`` ``bitset``","July 2022","|Complete|","16.0"
"`P2419R2 <https://wg21.link/P2419R2>`__","LWG","Clarify handling of encodings in localized formatting of chrono types","July 2022","",""
"`P2438R2 <https://wg21.link/P2438R2>`__","LWG","``std::string::substr() &&``","July 2022","",""
"`P2438R2 <https://wg21.link/P2438R2>`__","LWG","``std::string::substr() &&``","July 2022","|Complete|","16.0"
"`P2445R1 <https://wg21.link/P2445R1>`__","LWG","``forward_like``","July 2022","|Complete|","16.0"
"`P2446R2 <https://wg21.link/P2446R2>`__","LWG","``views::as_rvalue``","July 2022","",""
"`P2460R2 <https://wg21.link/P2460R2>`__","LWG","Relax requirements on ``wchar_t`` to match existing practices","July 2022","",""

1 Paper # Group Paper Name Meeting Status First released version
71 `P2408R5 <https://wg21.link/P2408R5>`__ LWG Ranges iterators as inputs to non-Ranges algorithms July 2022
72 `P2417R2 <https://wg21.link/P2417R2>`__ LWG A more ``constexpr`` ``bitset`` July 2022 |Complete| 16.0
73 `P2419R2 <https://wg21.link/P2419R2>`__ LWG Clarify handling of encodings in localized formatting of chrono types July 2022
74 `P2438R2 <https://wg21.link/P2438R2>`__ LWG ``std::string::substr() &&`` July 2022 |Complete| 16.0
75 `P2445R1 <https://wg21.link/P2445R1>`__ LWG ``forward_like`` July 2022 |Complete| 16.0
76 `P2446R2 <https://wg21.link/P2446R2>`__ LWG ``views::as_rvalue`` July 2022
77 `P2460R2 <https://wg21.link/P2460R2>`__ LWG Relax requirements on ``wchar_t`` to match existing practices July 2022

View File

@ -109,6 +109,10 @@ public:
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<class T>
basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); // C++17, constexpr since C++20
template <class T>
@ -261,8 +265,9 @@ public:
basic_string& replace(const_iterator i1, const_iterator i2, initializer_list<value_type>); // 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<allocator_type>::propagate_on_container_swap::value ||
allocator_traits<allocator_type>::is_always_equal::value); // C++17, constexpr since C++20
@ -897,6 +902,36 @@ public:
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<size_type>(__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 <class = __enable_if_t<__is_allocator<_Allocator>::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 @@ public:
#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 @@ basic_string<_CharT, _Traits, _Allocator>::copy(value_type* __s, size_type __n,
return __rlen;
}
template <class _CharT, class _Traits, class _Allocator>
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 <class _CharT, class _Traits, class _Allocator>
inline _LIBCPP_CONSTEXPR_SINCE_CXX20
void

View File

@ -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
//
//===----------------------------------------------------------------------===//
// <string>
// 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 <cassert>
#include <string>
#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");
}
}

View File

@ -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');

View File

@ -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
// <string>
// 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 <cassert>
#include <string>
#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 <class S>
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 <class S>
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 <class S>
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 <class S>
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 <class S>
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 <class S>
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 <class S>
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 <class S>
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 <class S>
constexpr void test_string(const typename S::allocator_type& alloc) {
test_string_pos<S>(STR(""), 0, STR(""));
test_string_pos<S>(STR(""), 1, should_throw_exception);
test_string_pos<S>(STR("Banane"), 1, STR("anane"));
test_string_pos<S>(STR("Banane"), 6, STR(""));
test_string_pos<S>(STR("Banane"), 7, should_throw_exception);
test_string_pos<S>(STR("long long string so no SSO"), 0, STR("long long string so no SSO"));
test_string_pos<S>(STR("long long string so no SSO"), 10, STR("string so no SSO"));
test_string_pos<S>(STR("long long string so no SSO"), 26, STR(""));
test_string_pos<S>(STR("long long string so no SSO"), 27, should_throw_exception);
test_string_pos_alloc<S>(STR(""), 0, alloc, STR(""));
test_string_pos_alloc<S>(STR(""), 1, alloc, should_throw_exception);
test_string_pos_alloc<S>(STR("Banane"), 1, alloc, STR("anane"));
test_string_pos_alloc<S>(STR("Banane"), 6, alloc, STR(""));
test_string_pos_alloc<S>(STR("Banane"), 7, alloc, should_throw_exception);
test_string_pos_alloc<S>(STR("long long string so no SSO"), 0, alloc, STR("long long string so no SSO"));
test_string_pos_alloc<S>(STR("long long string so no SSO"), 10, alloc, STR("string so no SSO"));
test_string_pos_alloc<S>(STR("long long string so no SSO"), 26, alloc, STR(""));
test_string_pos_alloc<S>(STR("long long string so no SSO"), 27, alloc, should_throw_exception);
test_string_pos_n<S>(STR(""), 0, 0, STR(""));
test_string_pos_n<S>(STR(""), 0, 1, STR(""));
test_string_pos_n<S>(STR(""), 1, 0, should_throw_exception);
test_string_pos_n<S>(STR(""), 1, 1, should_throw_exception);
test_string_pos_n<S>(STR("Banane"), 1, 10, STR("anane"));
test_string_pos_n<S>(STR("Banane"), 6, 0, STR(""));
test_string_pos_n<S>(STR("Banane"), 6, 5, STR(""));
test_string_pos_n<S>(STR("Banane"), 7, 10, should_throw_exception);
test_string_pos_n<S>(STR("long long string so no SSO"), 0, 10, STR("long long "));
test_string_pos_n<S>(STR("long long string so no SSO"), 10, 8, STR("string s"));
test_string_pos_n<S>(STR("long long string so no SSO"), 20, 10, STR("no SSO"));
test_string_pos_n<S>(STR("long long string so no SSO"), 26, 10, STR(""));
test_string_pos_n<S>(STR("long long string so no SSO"), 27, 10, should_throw_exception);
test_string_pos_n_alloc<S>(STR(""), 0, 0, alloc, STR(""));
test_string_pos_n_alloc<S>(STR(""), 0, 1, alloc, STR(""));
test_string_pos_n_alloc<S>(STR(""), 1, 0, alloc, should_throw_exception);
test_string_pos_n_alloc<S>(STR(""), 1, 1, alloc, should_throw_exception);
test_string_pos_n_alloc<S>(STR("Banane"), 1, 10, alloc, STR("anane"));
test_string_pos_n_alloc<S>(STR("Banane"), 6, 0, alloc, STR(""));
test_string_pos_n_alloc<S>(STR("Banane"), 6, 5, alloc, STR(""));
test_string_pos_n_alloc<S>(STR("Banane"), 7, 10, alloc, should_throw_exception);
test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 0, 10, alloc, STR("long long "));
test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 10, 8, alloc, STR("string s"));
test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 20, 10, alloc, STR("no SSO"));
test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 26, 10, alloc, STR(""));
test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 27, 10, alloc, should_throw_exception);
}
template <class CharT, class CharTraits>
constexpr void test_allocators() {
test_string<std::basic_string<CharT, CharTraits, std::allocator<CharT>>>(std::allocator<CharT>{});
test_string<std::basic_string<CharT, CharTraits, min_allocator<CharT>>>(min_allocator<CharT>{});
test_string<std::basic_string<CharT, CharTraits, test_allocator<CharT>>>(test_allocator<CharT>{42});
}
template <class CharT>
constexpr bool test_char_traits() {
test_allocators<CharT, std::char_traits<CharT>>();
test_allocators<CharT, constexpr_char_traits<CharT>>();
return true;
}
int main(int, char**) {
// TODO: put these into a single function when we increase the constexpr step limit
test_char_traits<char>();
static_assert(test_char_traits<char>());
test_char_traits<char16_t>();
static_assert(test_char_traits<char16_t>());
test_char_traits<char32_t>();
static_assert(test_char_traits<char32_t>());
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test_char_traits<wchar_t>();
static_assert(test_char_traits<wchar_t>());
#endif
#ifndef TEST_HAS_NO_CHAR8_T
test_char_traits<char8_t>();
static_assert(test_char_traits<char8_t>());
#endif
return 0;
}

View File

@ -8,7 +8,8 @@
// <string>
// 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 <string>
#include <stdexcept>
@ -47,130 +48,72 @@ test(const S& s, typename S::size_type pos, typename S::size_type n)
#endif
}
template <class S>
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<std::string>();
#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> 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<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
#endif
return true;

View File

@ -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
// <string>
// constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&;
#include <algorithm>
#include <string>
#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 <class S>
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 <class S>
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 <class S>
constexpr void test_string() {
test<S>(STR(""), 0, 0, STR(""));
test<S>(STR(""), 0, 1, STR(""));
test<S>(STR(""), 1, 0, should_throw_exception);
test<S>(STR(""), 1, 1, should_throw_exception);
test<S>(STR("short string"), 0, 1, STR("s"));
test<S>(STR("short string"), 5, 5, STR(" stri"));
test<S>(STR("short string"), 12, 5, STR(""));
test<S>(STR("short string"), 13, 5, should_throw_exception);
test<S>(STR("long long string so no SSO"), 0, 0, STR(""));
test<S>(STR("long long string so no SSO"), 0, 10, STR("long long "));
test<S>(STR("long long string so no SSO"), 10, 10, STR("string so "));
test<S>(STR("long long string so no SSO"), 20, 10, STR("no SSO"));
test<S>(STR("long long string so no SSO"), 26, 10, STR(""));
test<S>(STR("long long string so no SSO"), 27, 0, should_throw_exception);
}
template <class CharT, class CharTraits>
constexpr void test_allocators() {
test_string<std::basic_string<CharT, CharTraits, std::allocator<CharT>>>();
test_string<std::basic_string<CharT, CharTraits, min_allocator<CharT>>>();
test_string<std::basic_string<CharT, CharTraits, test_allocator<CharT>>>();
}
template <class CharT>
constexpr void test_char_traits() {
test_allocators<CharT, std::char_traits<CharT>>();
test_allocators<CharT, constexpr_char_traits<CharT>>();
}
constexpr bool test() {
test_char_traits<char>();
test_char_traits<char16_t>();
test_char_traits<char32_t>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test_char_traits<wchar_t>();
#endif
#ifndef TEST_HAS_NO_CHAR8_T
test_char_traits<char8_t>();
#endif
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -472,6 +472,40 @@ private:
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),

View File

@ -89,7 +89,7 @@ struct MultiStringType {
// 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<const CharT*>(nullptr))
// Like MAKE_CSTRING but makes a basic_string<CharT>. Embedded nulls are OK.
#define MAKE_STRING(CharT, Str) \