libstdc++: Implement constexpr std::basic_string for C++20

This is only supported for the cxx11 ABI, not for COW strings.

libstdc++-v3/ChangeLog:

	* include/bits/basic_string.h (basic_string, operator""s): Add
	constexpr for C++20.
	(basic_string::basic_string(basic_string&&)): Only copy
	initialized portion of the buffer.
	(basic_string::basic_string(basic_string&&, const Alloc&)):
	Likewise.
	* include/bits/basic_string.tcc (basic_string): Add constexpr
	for C++20.
	(basic_string::swap(basic_string&)): Only copy initialized
	portions of the buffers.
	(basic_string::_M_replace): Add constexpr implementation that
	doesn't depend on pointer comparisons.
	* include/bits/cow_string.h: Adjust comment.
	* include/ext/type_traits.h (__is_null_pointer): Add constexpr.
	* include/std/string (erase, erase_if): Add constexpr.
	* include/std/version (__cpp_lib_constexpr_string): Update
	value.
	* testsuite/21_strings/basic_string/cons/char/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/literals/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/modifiers/constexpr.cc: New test.
	* testsuite/21_strings/basic_string/modifiers/swap/char/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/modifiers/swap/wchar_t/constexpr.cc:
	New test.
	* testsuite/21_strings/basic_string/version.cc: New test.
This commit is contained in:
Michael de Lang 2020-02-26 23:43:45 +01:00 committed by Jonathan Wakely
parent 59434931fb
commit b96e2ff9d8
13 changed files with 869 additions and 33 deletions

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
basic_string<_CharT, _Traits, _Alloc>::npos;
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
swap(basic_string& __s) _GLIBCXX_NOEXCEPT
@ -70,16 +71,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
_CharT __tmp_data[_S_local_capacity + 1];
traits_type::copy(__tmp_data, __s._M_local_buf,
_S_local_capacity + 1);
__s.length() + 1);
traits_type::copy(__s._M_local_buf, _M_local_buf,
_S_local_capacity + 1);
length() + 1);
traits_type::copy(_M_local_buf, __tmp_data,
_S_local_capacity + 1);
__s.length() + 1);
}
else if (__s.length())
{
traits_type::copy(_M_local_buf, __s._M_local_buf,
_S_local_capacity + 1);
__s.length() + 1);
_M_length(__s.length());
__s._M_set_length(0);
return;
@ -87,7 +88,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
else if (length())
{
traits_type::copy(__s._M_local_buf, _M_local_buf,
_S_local_capacity + 1);
length() + 1);
__s._M_length(length());
_M_set_length(0);
return;
@ -97,7 +98,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
const size_type __tmp_capacity = __s._M_allocated_capacity;
traits_type::copy(__s._M_local_buf, _M_local_buf,
_S_local_capacity + 1);
length() + 1);
_M_data(__s._M_data());
__s._M_data(__s._M_local_buf);
_M_capacity(__tmp_capacity);
@ -108,7 +109,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__s._M_is_local())
{
traits_type::copy(_M_local_buf, __s._M_local_buf,
_S_local_capacity + 1);
__s.length() + 1);
__s._M_data(_M_data());
_M_data(_M_local_buf);
}
@ -128,6 +129,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::pointer
basic_string<_CharT, _Traits, _Alloc>::
_M_create(size_type& __capacity, size_type __old_capacity)
@ -159,6 +161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// pointers, calling for a different coding style.
template<typename _CharT, typename _Traits, typename _Alloc>
template<typename _InIterator>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
_M_construct(_InIterator __beg, _InIterator __end,
@ -202,6 +205,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits, typename _Alloc>
template<typename _InIterator>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
_M_construct(_InIterator __beg, _InIterator __end,
@ -233,6 +237,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
_M_construct(size_type __n, _CharT __c)
@ -250,6 +255,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
_M_assign(const basic_string& __str)
@ -276,6 +282,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
reserve(size_type __res)
@ -296,6 +303,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
_M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
@ -320,6 +328,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
_M_erase(size_type __pos, size_type __n)
@ -333,6 +342,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
reserve()
@ -368,6 +378,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
void
basic_string<_CharT, _Traits, _Alloc>::
resize(size_type __n, _CharT __c)
@ -380,6 +391,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
basic_string<_CharT, _Traits, _Alloc>&
basic_string<_CharT, _Traits, _Alloc>::
_M_append(const _CharT* __s, size_type __n)
@ -400,6 +412,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits, typename _Alloc>
template<typename _InputIterator>
_GLIBCXX20_CONSTEXPR
basic_string<_CharT, _Traits, _Alloc>&
basic_string<_CharT, _Traits, _Alloc>::
_M_replace_dispatch(const_iterator __i1, const_iterator __i2,
@ -415,6 +428,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
basic_string<_CharT, _Traits, _Alloc>&
basic_string<_CharT, _Traits, _Alloc>::
_M_replace_aux(size_type __pos1, size_type __n1, size_type __n2,
@ -444,6 +458,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
basic_string<_CharT, _Traits, _Alloc>&
basic_string<_CharT, _Traits, _Alloc>::
_M_replace(size_type __pos, size_type __len1, const _CharT* __s,
@ -459,6 +474,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
pointer __p = this->_M_data() + __pos;
const size_type __how_much = __old_size - __pos - __len1;
#if __cpp_lib_is_constant_evaluated
if (__builtin_is_constant_evaluated())
{
auto __newp = this->_M_get_allocator().allocate(__new_size);
_S_copy(__newp, this->_M_data(), __pos);
_S_copy(__newp + __pos, __s, __len2);
_S_copy(__newp + __pos + __len2, __p + __len1, __how_much);
_S_copy(this->_M_data(), __newp, __new_size);
this->_M_get_allocator().deallocate(__newp, __new_size);
}
else
#endif
if (_M_disjunct(__s))
{
if (__how_much && __len1 != __len2)
@ -502,6 +529,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
copy(_CharT* __s, size_type __n, size_type __pos) const
@ -535,7 +563,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
else
__p = _M_data();
struct _Terminator {
~_Terminator() { _M_this->_M_set_length(_M_r); }
constexpr ~_Terminator() { _M_this->_M_set_length(_M_r); }
basic_string* _M_this;
size_type _M_r;
};
@ -548,7 +576,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif // _GLIBCXX_USE_CXX11_ABI
#if __cpp_lib_constexpr_string >= 201907L
# define _GLIBCXX_STRING_CONSTEXPR constexpr
#else
# define _GLIBCXX_STRING_CONSTEXPR
#endif
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
basic_string<_CharT, _Traits, _Alloc>
operator+(const _CharT* __lhs,
const basic_string<_CharT, _Traits, _Alloc>& __rhs)
@ -569,6 +604,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX20_CONSTEXPR
basic_string<_CharT, _Traits, _Alloc>
operator+(_CharT __lhs, const basic_string<_CharT, _Traits, _Alloc>& __rhs)
{
@ -587,6 +623,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
find(const _CharT* __s, size_type __pos, size_type __n) const
@ -623,6 +660,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
find(_CharT __c, size_type __pos) const _GLIBCXX_NOEXCEPT
@ -641,6 +679,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
rfind(const _CharT* __s, size_type __pos, size_type __n) const
@ -663,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
rfind(_CharT __c, size_type __pos) const _GLIBCXX_NOEXCEPT
@ -680,6 +720,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
find_first_of(const _CharT* __s, size_type __pos, size_type __n) const
@ -696,6 +737,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
find_last_of(const _CharT* __s, size_type __pos, size_type __n) const
@ -718,6 +760,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
find_first_not_of(const _CharT* __s, size_type __pos, size_type __n) const
@ -731,6 +774,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
find_first_not_of(_CharT __c, size_type __pos) const _GLIBCXX_NOEXCEPT
@ -742,6 +786,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
find_last_not_of(const _CharT* __s, size_type __pos, size_type __n) const
@ -764,6 +809,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
find_last_not_of(_CharT __c, size_type __pos) const _GLIBCXX_NOEXCEPT
@ -784,6 +830,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
int
basic_string<_CharT, _Traits, _Alloc>::
compare(size_type __pos, size_type __n, const basic_string& __str) const
@ -799,6 +846,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
int
basic_string<_CharT, _Traits, _Alloc>::
compare(size_type __pos1, size_type __n1, const basic_string& __str,
@ -817,6 +865,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
int
basic_string<_CharT, _Traits, _Alloc>::
compare(const _CharT* __s) const _GLIBCXX_NOEXCEPT
@ -832,6 +881,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
int
basic_string <_CharT, _Traits, _Alloc>::
compare(size_type __pos, size_type __n1, const _CharT* __s) const
@ -848,6 +898,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc>
_GLIBCXX_STRING_CONSTEXPR
int
basic_string <_CharT, _Traits, _Alloc>::
compare(size_type __pos, size_type __n1, const _CharT* __s,
@ -863,6 +914,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __r;
}
#undef _GLIBCXX_STRING_CONSTEXPR
// 21.3.7.9 basic_string::getline and operators
template<typename _CharT, typename _Traits, typename _Alloc>
basic_istream<_CharT, _Traits>&

View File

@ -35,7 +35,7 @@
#if ! _GLIBCXX_USE_CXX11_ABI
#ifdef __cpp_lib_is_constant_evaluated
// Support P1032R1 in C++20 (but not P0980R1 yet).
// Support P1032R1 in C++20 (but not P0980R1 for COW strings).
# define __cpp_lib_constexpr_string 201811L
#elif __cplusplus >= 201703L && _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED
// Support P0426R1 changes to char_traits in C++17.

View File

@ -148,17 +148,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// For use in string and vstring.
template<typename _Type>
_GLIBCXX_CONSTEXPR
inline bool
__is_null_pointer(_Type* __ptr)
{ return __ptr == 0; }
template<typename _Type>
_GLIBCXX_CONSTEXPR
inline bool
__is_null_pointer(_Type)
{ return false; }
#if __cplusplus >= 201103L
inline bool
constexpr bool
__is_null_pointer(std::nullptr_t)
{ return true; }
#endif

View File

@ -116,6 +116,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits, typename _Alloc,
typename _Predicate>
_GLIBCXX20_CONSTEXPR
inline typename basic_string<_CharT, _Traits, _Alloc>::size_type
erase_if(basic_string<_CharT, _Traits, _Alloc>& __cont, _Predicate __pred)
{
@ -129,6 +130,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _CharT, typename _Traits, typename _Alloc, typename _Up>
_GLIBCXX20_CONSTEXPR
inline typename basic_string<_CharT, _Traits, _Alloc>::size_type
erase(basic_string<_CharT, _Traits, _Alloc>& __cont, const _Up& __value)
{

View File

@ -232,7 +232,11 @@
#define __cpp_lib_constexpr_memory 201811L
#define __cpp_lib_constexpr_numeric 201911L
#ifdef __cpp_lib_is_constant_evaluated
# define __cpp_lib_constexpr_string 201811L
# if _GLIBCXX_USE_CXX11_ABI
# define __cpp_lib_constexpr_string 201907L
# else
# define __cpp_lib_constexpr_string 201811L
# endif
#endif
#define __cpp_lib_constexpr_string_view 201811L
#define __cpp_lib_constexpr_tuple 201811L

View File

@ -0,0 +1,174 @@
// { dg-options "-std=gnu++20" }
// { dg-do compile { target c++20 } }
// { dg-require-effective-target cxx11-abi }
#include <string>
#ifndef __cpp_lib_constexpr_string
# error "Feature-test macro for constexpr std::string missing in <string>"
#elif __cpp_lib_constexpr_string != 201907L
# error "Feature-test macro for constexpr std::string has wrong value in <string>"
#endif
#include <testsuite_hooks.h>
using C = char;
using T = std::char_traits<C>;
template<typename T>
struct Alloc : std::allocator<T>
{
using std::allocator<T>::allocator;
constexpr explicit Alloc(int p) : personality(p) { }
template<typename U>
constexpr Alloc(const Alloc<U>& a) : personality(a.personality) { }
int personality = 0;
constexpr Alloc select_on_container_copy_construction() const
{ return Alloc(-1); }
constexpr bool operator==(const Alloc& a) const noexcept
{ return personality == a.personality; }
};
constexpr bool
test_default_ctor()
{
std::basic_string<C> s0;
VERIFY( s0.empty() );
std::basic_string<C> s1(std::allocator<C>{});
VERIFY( s1.empty() );
std::basic_string<C, T, Alloc<C>> s2;
VERIFY( s2.empty() );
std::basic_string<C, T, Alloc<C>> s3(Alloc<C>(3));
VERIFY( s3.empty() );
VERIFY( s3.get_allocator().personality == 3 );
return true;
}
static_assert( test_default_ctor() );
constexpr bool
test_cstr()
{
const C cs[] = "This has an embedded \0 null";
const auto len = (sizeof(cs) - 1)/sizeof(C);
std::basic_string<C> s1(cs);
VERIFY( s1.length() == 21 );
std::basic_string<C> s2(cs, std::allocator<C>{});
VERIFY( s2 == s1 );
std::basic_string<C> s3(cs, len);
VERIFY( s3.length() == len );
VERIFY( s3[len] == '\0' );
std::basic_string<C> s4(cs, len, std::allocator<C>{});
VERIFY( s4 == s3 );
std::basic_string<C, T, Alloc<C>> s5(cs);
VERIFY( s5 == std::basic_string_view<C>(s1) );
std::basic_string<C, T, Alloc<C>> s6(cs, Alloc<C>(6));
VERIFY( s6 == std::basic_string_view<C>(s1) );
VERIFY( s6.get_allocator().personality == 6 );
std::basic_string<C, T, Alloc<C>> s7(cs, len, Alloc<C>(7));
VERIFY( s7 == std::basic_string_view<C>(s3) );
VERIFY( s7.get_allocator().personality == 7 );
return true;
}
static_assert( test_cstr() );
constexpr bool
test_copy()
{
const std::basic_string<C> short_string = "sh";
const std::basic_string<C> long_string = "string longer than the SSO buffer";
std::basic_string<C> s1 = short_string;
VERIFY( s1 == short_string );
std::basic_string<C> s2(short_string, s1.get_allocator());
VERIFY( s2 == short_string );
std::basic_string<C> s3 = long_string;
VERIFY( s3 == long_string );
std::basic_string<C> s4(long_string, s1.get_allocator());
VERIFY( s4 == long_string );
std::basic_string<C, T, Alloc<C>> a_short_string = short_string.c_str();
std::basic_string<C, T, Alloc<C>> a_long_string = long_string.c_str();
std::basic_string<C, T, Alloc<C>> s5(a_short_string);
VERIFY( s5 == a_short_string );
std::basic_string<C, T, Alloc<C>> s6(a_short_string, s5.get_allocator());
VERIFY( s6 == a_short_string );
std::basic_string<C, T, Alloc<C>> s7(a_short_string, Alloc<C>(7));
VERIFY( s7 == a_short_string );
VERIFY( s7.get_allocator().personality == 7 );
std::basic_string<C, T, Alloc<C>> s8 = a_long_string;
VERIFY( s8 == a_long_string );
std::basic_string<C, T, Alloc<C>> s9(a_long_string, s5.get_allocator());
VERIFY( s9 == a_long_string );
std::basic_string<C, T, Alloc<C>> s10(a_long_string, Alloc<C>(10));
VERIFY( s10 == a_long_string );
VERIFY( s10.get_allocator().personality == 10 );
return true;
}
static_assert( test_copy() );
constexpr bool
test_move()
{
const std::basic_string<C> short_string = "sh";
const std::basic_string<C> long_string = "string longer than the SSO buffer";
std::basic_string<C> s0 = short_string;
std::basic_string<C> s1 = std::move(s0);
VERIFY( s1 == short_string );
std::basic_string<C> s2(std::move(s1), std::allocator<C>());
VERIFY( s2 == short_string );
s0 = long_string;
std::basic_string<C> s3 = std::move(s0);
VERIFY( s3 == long_string );
std::basic_string<C> s4(std::move(s3), s1.get_allocator());
VERIFY( s4 == long_string );
std::basic_string<C, T, Alloc<C>> a_short_string = short_string.c_str();
std::basic_string<C, T, Alloc<C>> a_long_string = long_string.c_str();
auto sa0 = a_short_string;
std::basic_string<C, T, Alloc<C>> s5 = std::move(sa0);
VERIFY( s5 == a_short_string );
std::basic_string<C, T, Alloc<C>> s6(std::move(s5), sa0.get_allocator());
VERIFY( s6 == a_short_string );
std::basic_string<C, T, Alloc<C>> s7(std::move(s6), Alloc<C>(7));
VERIFY( s7 == a_short_string );
VERIFY( s7.get_allocator().personality == 7 );
sa0 = a_long_string;
std::basic_string<C, T, Alloc<C>> s8 = std::move(sa0);
VERIFY( s8 == a_long_string );
std::basic_string<C, T, Alloc<C>> s9(std::move(s8), s5.get_allocator());
VERIFY( s9 == a_long_string );
std::basic_string<C, T, Alloc<C>> s10(std::move(s9), Alloc<C>(10));
VERIFY( s10 == a_long_string );
VERIFY( s10.get_allocator().personality == 10 );
return true;
}
static_assert( test_move() );

View File

@ -0,0 +1,174 @@
// { dg-options "-std=gnu++20" }
// { dg-do compile { target c++20 } }
// { dg-require-effective-target cxx11-abi }
#include <string>
#ifndef __cpp_lib_constexpr_string
# error "Feature-test macro for constexpr std::string missing in <string>"
#elif __cpp_lib_constexpr_string != 201907L
# error "Feature-test macro for constexpr std::string has wrong value in <string>"
#endif
#include <testsuite_hooks.h>
using C = wchar_t;
using T = std::char_traits<C>;
template<typename T>
struct Alloc : std::allocator<T>
{
using std::allocator<T>::allocator;
constexpr explicit Alloc(int p) : personality(p) { }
template<typename U>
constexpr Alloc(const Alloc<U>& a) : personality(a.personality) { }
int personality = 0;
constexpr Alloc select_on_container_copy_construction() const
{ return Alloc(-1); }
constexpr bool operator==(const Alloc& a) const noexcept
{ return personality == a.personality; }
};
constexpr bool
test_default_ctor()
{
std::basic_string<C> s0;
VERIFY( s0.empty() );
std::basic_string<C> s1(std::allocator<C>{});
VERIFY( s1.empty() );
std::basic_string<C, T, Alloc<C>> s2;
VERIFY( s2.empty() );
std::basic_string<C, T, Alloc<C>> s3(Alloc<C>(3));
VERIFY( s3.empty() );
VERIFY( s3.get_allocator().personality == 3 );
return true;
}
static_assert( test_default_ctor() );
constexpr bool
test_cstr()
{
const C cs[] = L"This has an embedded \0 null";
const auto len = (sizeof(cs) - 1)/sizeof(C);
std::basic_string<C> s1(cs);
VERIFY( s1.length() == 21 );
std::basic_string<C> s2(cs, std::allocator<C>{});
VERIFY( s2 == s1 );
std::basic_string<C> s3(cs, len);
VERIFY( s3.length() == len );
VERIFY( s3[len] == L'\0' );
std::basic_string<C> s4(cs, len, std::allocator<C>{});
VERIFY( s4 == s3 );
std::basic_string<C, T, Alloc<C>> s5(cs);
VERIFY( s5 == std::basic_string_view<C>(s1) );
std::basic_string<C, T, Alloc<C>> s6(cs, Alloc<C>(6));
VERIFY( s6 == std::basic_string_view<C>(s1) );
VERIFY( s6.get_allocator().personality == 6 );
std::basic_string<C, T, Alloc<C>> s7(cs, len, Alloc<C>(7));
VERIFY( s7 == std::basic_string_view<C>(s3) );
VERIFY( s7.get_allocator().personality == 7 );
return true;
}
static_assert( test_cstr() );
constexpr bool
test_copy()
{
const std::basic_string<C> short_string = L"sh";
const std::basic_string<C> long_string = L"string longer than the SSO buffer";
std::basic_string<C> s1 = short_string;
VERIFY( s1 == short_string );
std::basic_string<C> s2(short_string, s1.get_allocator());
VERIFY( s2 == short_string );
std::basic_string<C> s3 = long_string;
VERIFY( s3 == long_string );
std::basic_string<C> s4(long_string, s1.get_allocator());
VERIFY( s4 == long_string );
std::basic_string<C, T, Alloc<C>> a_short_string = short_string.c_str();
std::basic_string<C, T, Alloc<C>> a_long_string = long_string.c_str();
std::basic_string<C, T, Alloc<C>> s5(a_short_string);
VERIFY( s5 == a_short_string );
std::basic_string<C, T, Alloc<C>> s6(a_short_string, s5.get_allocator());
VERIFY( s6 == a_short_string );
std::basic_string<C, T, Alloc<C>> s7(a_short_string, Alloc<C>(7));
VERIFY( s7 == a_short_string );
VERIFY( s7.get_allocator().personality == 7 );
std::basic_string<C, T, Alloc<C>> s8 = a_long_string;
VERIFY( s8 == a_long_string );
std::basic_string<C, T, Alloc<C>> s9(a_long_string, s5.get_allocator());
VERIFY( s9 == a_long_string );
std::basic_string<C, T, Alloc<C>> s10(a_long_string, Alloc<C>(10));
VERIFY( s10 == a_long_string );
VERIFY( s10.get_allocator().personality == 10 );
return true;
}
static_assert( test_copy() );
constexpr bool
test_move()
{
const std::basic_string<C> short_string = L"sh";
const std::basic_string<C> long_string = L"string longer than the SSO buffer";
std::basic_string<C> s0 = short_string;
std::basic_string<C> s1 = std::move(s0);
VERIFY( s1 == short_string );
std::basic_string<C> s2(std::move(s1), std::allocator<C>());
VERIFY( s2 == short_string );
s0 = long_string;
std::basic_string<C> s3 = std::move(s0);
VERIFY( s3 == long_string );
std::basic_string<C> s4(std::move(s3), s1.get_allocator());
VERIFY( s4 == long_string );
std::basic_string<C, T, Alloc<C>> a_short_string = short_string.c_str();
std::basic_string<C, T, Alloc<C>> a_long_string = long_string.c_str();
auto sa0 = a_short_string;
std::basic_string<C, T, Alloc<C>> s5 = std::move(sa0);
VERIFY( s5 == a_short_string );
std::basic_string<C, T, Alloc<C>> s6(std::move(s5), sa0.get_allocator());
VERIFY( s6 == a_short_string );
std::basic_string<C, T, Alloc<C>> s7(std::move(s6), Alloc<C>(7));
VERIFY( s7 == a_short_string );
VERIFY( s7.get_allocator().personality == 7 );
sa0 = a_long_string;
std::basic_string<C, T, Alloc<C>> s8 = std::move(sa0);
VERIFY( s8 == a_long_string );
std::basic_string<C, T, Alloc<C>> s9(std::move(s8), s5.get_allocator());
VERIFY( s9 == a_long_string );
std::basic_string<C, T, Alloc<C>> s10(std::move(s9), Alloc<C>(10));
VERIFY( s10 == a_long_string );
VERIFY( s10.get_allocator().personality == 10 );
return true;
}
static_assert( test_move() );

View File

@ -0,0 +1,22 @@
// { dg-options "-std=gnu++20" }
// { dg-do compile { target c++20 } }
// { dg-require-effective-target cxx11-abi }
#include <string>
#include <testsuite_hooks.h>
constexpr bool
test_literals()
{
using namespace std::literals;
auto s = "narrow string"s;
auto sw = L"wide string"s;
auto s8 = u8"UTF-8 string"s;
auto su = u"UTF-16 string"s;
auto sU = U"UTF-32 string"s;
return !s.empty() && !sw.empty() && !s8.empty() && !su.empty() && !sU.empty();
}
static_assert( test_literals() );

View File

@ -0,0 +1,52 @@
// { dg-options "-std=gnu++20" }
// { dg-do compile { target c++20 } }
#include <string>
#include <testsuite_hooks.h>
constexpr bool
test_insert()
{
std::string s;
s.insert(0, "one");
VERIFY( s == "one" );
s.insert(0, "eleventy-");
VERIFY( s == "eleventy-one" );
s.insert(6, "ses at ten thirteen", 15);
VERIFY( s == "elevenses at ten thirty-one" );
return true;
}
static_assert( test_insert() );
constexpr bool
test_replace()
{
std::string s = "abcdef";
s.replace(2, 1, s.c_str(), 3);
VERIFY( s == "ababcdef" );
s.replace(0, 2, "", 0);
VERIFY( s == "abcdef" );
s.replace(1, 4, "ardwol", 6);
VERIFY( s == "aardwolf" );
s.replace(4, 0, "vark not wolf");
return true;
}
static_assert( test_replace() );
constexpr bool
test_erasure()
{
std::string s = "Spiritualized Electric Mainline";
std::erase(s, 'i');
VERIFY( s == "Sprtualzed Electrc Manlne" );
std::erase_if(s, [](char c) { return c == 'l'; });
VERIFY( s == "Sprtuazed Eectrc Manne" );
return true;
}
static_assert( test_erasure() );

View File

@ -0,0 +1,49 @@
// { dg-options "-std=gnu++20" }
// { dg-do compile { target c++20 } }
// { dg-require-effective-target cxx11-abi }
#include <string>
#include <testsuite_hooks.h>
using C = char;
using T = std::char_traits<C>;
constexpr bool
test_swap()
{
std::basic_string<C> s0;
s0.swap(s0);
VERIFY( s0.empty() );
std::basic_string<C> s00;
s0.swap(s00);
VERIFY( s0.empty() );
VERIFY( s00.empty() );
std::basic_string<C> s1 = "s1";
s1.swap(s0);
VERIFY( s1.empty() );
VERIFY( ! s0.empty() );
s1.swap(s0);
VERIFY( s0.empty() );
VERIFY( ! s1.empty() );
std::basic_string<C> s2 = "quite a long string, but not very long";
s2.swap(s1);
VERIFY( s2.length() == 2 );
VERIFY( s1.length() == 38 );
s2.swap(s1);
VERIFY( s1.length() == 2 );
VERIFY( s2.length() == 38 );
swap(s2, s0);
VERIFY( s2.empty() );
VERIFY( s0.length() == 38 );
auto s3 = s0;
swap(s3, s0);
VERIFY( s3 == s0 );
return true;
}
static_assert( test_swap() );

View File

@ -0,0 +1,49 @@
// { dg-options "-std=gnu++20" }
// { dg-do compile { target c++20 } }
// { dg-require-effective-target cxx11-abi }
#include <string>
#include <testsuite_hooks.h>
using C = wchar_t;
using T = std::char_traits<C>;
constexpr bool
test_swap()
{
std::basic_string<C> s0;
s0.swap(s0);
VERIFY( s0.empty() );
std::basic_string<C> s00;
s0.swap(s00);
VERIFY( s0.empty() );
VERIFY( s00.empty() );
std::basic_string<C> s1 = L"s1";
s1.swap(s0);
VERIFY( s1.empty() );
VERIFY( ! s0.empty() );
s1.swap(s0);
VERIFY( s0.empty() );
VERIFY( ! s1.empty() );
std::basic_string<C> s2 = L"quite a long string, but not very long";
s2.swap(s1);
VERIFY( s2.length() == 2 );
VERIFY( s1.length() == 38 );
s2.swap(s1);
VERIFY( s1.length() == 2 );
VERIFY( s2.length() == 38 );
swap(s2, s0);
VERIFY( s2.empty() );
VERIFY( s0.length() == 38 );
auto s3 = s0;
swap(s3, s0);
VERIFY( s3 == s0 );
return true;
}
static_assert( test_swap() );

View File

@ -0,0 +1,25 @@
// { dg-do compile { target c++17 } }
#include <version>
#ifndef __cpp_lib_constexpr_string
# error "Feature-test macro for constexpr std::string missing in <version>"
#endif
#if __cplusplus == 201703L
# if __cpp_lib_constexpr_string != 201611L
# error "Feature-test macro for constexpr std::string has wrong value for C++17 in <version>"
# endif
#endif
#if __cplusplus == 202002L
# if _GLIBCXX_USE_CXX11_ABI
# if __cpp_lib_constexpr_string != 201907L
# error "Feature-test macro for constexpr std::string has wrong value for C++20 in <version>"
# endif
# else // COW strings
# if __cpp_lib_constexpr_string != 201811L
# error "Feature-test macro for constexpr std::string has wrong value for C++20 in <version>"
# endif
# endif
#endif