Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement SSO for constexpr string #1735

Merged
merged 5 commits into from
Jun 19, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 18 additions & 77 deletions stl/inc/xstring
Original file line number Diff line number Diff line change
Expand Up @@ -2279,11 +2279,6 @@ public:
}

_CONSTEXPR20 bool _Large_string_engaged() const noexcept {
#if _HAS_CXX20
if (_STD is_constant_evaluated()) {
return true;
}
#endif // _HAS_CXX20
return _BUF_SIZE <= _Myres;
}

Expand Down Expand Up @@ -2311,7 +2306,7 @@ public:
}

union _Bxty { // storage for small buffer or pointer to larger one
_CONSTEXPR20 _Bxty() noexcept : _Ptr() {} // user-provided, for fancy pointers
_CONSTEXPR20 _Bxty() noexcept : _Buf() {} // user-provided, for fancy pointers
miscco marked this conversation as resolved.
Show resolved Hide resolved

_CONSTEXPR20 ~_Bxty() noexcept {} // user-provided, for fancy pointers

Expand Down Expand Up @@ -2689,19 +2684,8 @@ private:
auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Al);
_Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data);

if (_Count < _BUF_SIZE) {
#if _HAS_CXX20
if (_STD is_constant_evaluated()) {
_My_data._Myres = _BUF_SIZE; // TRANSITION: constexpr SSO
}

const bool _Stay_small = _Count < _BUF_SIZE && !_STD is_constant_evaluated();
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
const bool _Stay_small = _Count < _BUF_SIZE;
#endif // _HAS_CXX20

if (_Stay_small) {
#if _HAS_CXX20
// TRANSITION: This is currently unused until SSO support is merged
if (_STD is_constant_evaluated()) {
_Construct_in_place(_My_data._Bx);
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
}
Expand Down Expand Up @@ -2767,7 +2751,6 @@ private:
#if _HAS_CXX20
if (_STD is_constant_evaluated()) {
_Construct_in_place(_My_data._Bx);
_My_data._Myres = _BUF_SIZE; // TRANSITION: constexpr SSO
}
#endif // _HAS_CXX20

Expand All @@ -2777,12 +2760,7 @@ private:
_Xlen_string(); // result too long
}

#if _HAS_CXX20
const bool _Become_large = _Count >= _BUF_SIZE || _STD is_constant_evaluated();
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
const bool _Become_large = _Count >= _BUF_SIZE;
#endif // _HAS_CXX20
if (_Become_large) {
if (_Count >= _BUF_SIZE) {
const size_type _New_capacity = _Calculate_growth(_Count);
const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws
_Construct_in_place(_My_data._Bx._Ptr, _New_ptr);
Expand Down Expand Up @@ -2873,18 +2851,10 @@ public:
auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
_Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws

#if _HAS_CXX20
const bool _Activate_large_mode = _New_capacity < _New_size || _STD is_constant_evaluated();
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
const bool _Activate_large_mode = _New_capacity < _New_size;
#endif // _HAS_CXX20

if (_Activate_large_mode) {
// we should never allocate less than _BUF_SIZE space (_New_size could be small if constant evaluated)
const size_type _Requested_size = (_STD max)(_New_size, _BUF_SIZE);
_New_capacity = _Calculate_growth(_Requested_size, _BUF_SIZE - 1, max_size());
const pointer _Fancyptr = _Getal().allocate(_New_capacity + 1); // throws
_Ptr = _Unfancy(_Fancyptr);
if (_New_capacity < _New_size) {
_New_capacity = _Calculate_growth(_New_size, _BUF_SIZE - 1, max_size());
const pointer _Fancyptr = _Getal().allocate(_New_capacity + 1); // throws
_Ptr = _Unfancy(_Fancyptr);
_Construct_in_place(_My_data._Bx._Ptr, _Fancyptr);

#if _HAS_CXX20
Expand Down Expand Up @@ -3222,9 +3192,6 @@ public:
private:
_CONSTEXPR20 void _Copy_assign_val_from_small(const basic_string& _Right) {
// TRANSITION, VSO-761321; inline into only caller when that's fixed
#if _HAS_CXX20
_STL_ASSERT(!_STD is_constant_evaluated(), "SSO should be disabled in a constexpr context");
#endif // _HAS_CXX20
_Tidy_deallocate();
if constexpr (_Can_memcpy_val) {
#if _HAS_CXX20
Expand Down Expand Up @@ -4007,22 +3974,12 @@ public:
return;
}

#if _HAS_CXX20
const bool _Do_become_small = _My_data._Mysize < _BUF_SIZE && !_STD is_constant_evaluated();
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
const bool _Do_become_small = _My_data._Mysize < _BUF_SIZE;
#endif // _HAS_CXX20
if (_Do_become_small) {
if (_My_data._Mysize < _BUF_SIZE) {
_Become_small();
return;
}

size_type _Target_capacity = (_STD min)(_My_data._Mysize | _ALLOC_MASK, max_size());
#if _HAS_CXX20
// must allocate at least _BUF_SIZE space
_Target_capacity = (_STD max)(_Target_capacity, _BUF_SIZE);
#endif // _HAS_CXX20

const size_type _Target_capacity = (_STD min)(_My_data._Mysize | _ALLOC_MASK, max_size());
if (_Target_capacity < _My_data._Myres) { // worth shrinking, do it
auto& _Al = _Getal();
const pointer _New_ptr = _Al.allocate(_Target_capacity + 1); // throws
Expand Down Expand Up @@ -4872,24 +4829,15 @@ private:
_CONSTEXPR20 void _Tidy_init() noexcept { // initialize basic_string data members
auto& _My_data = _Mypair._Myval2;
_My_data._Mysize = 0;

_My_data._Myres = _BUF_SIZE - 1;
#if _HAS_CXX20
if (_STD is_constant_evaluated()) {
_My_data._Myres = _BUF_SIZE; // SSO disabled in constexpr context
auto& _Al = _Getal();
const pointer _New_ptr = _Al.allocate(_BUF_SIZE + 1); // throws
_My_data._Bx._Ptr = _New_ptr;

_Elem* const _Raw_new = _Unfancy(_New_ptr);
_Traits::assign(_Raw_new, _BUF_SIZE + 1, _Elem());
} else
#endif // _HAS_CXX20
{
_My_data._Myres = _BUF_SIZE - 1;
// the _Traits::assign is last so the codegen doesn't think the char write can alias this
_Traits::assign(_My_data._Bx._Buf[0], _Elem());
if (_STD is_constant_evaluated()) { // begin the lifetime of the array elements before copying into them
_Construct_in_place(_My_data._Bx);
}
#endif // _HAS_CXX20

// the _Traits::assign is last so the codegen doesn't think the char write can alias this
_Traits::assign(_My_data._Bx._Buf[0], _Elem());
_ASAN_STRING_CREATE(*this);
}

Expand All @@ -4910,16 +4858,9 @@ private:
}

_My_data._Mysize = 0;
#if _HAS_CXX20
if (_STD is_constant_evaluated()) {
_My_data._Myres = 0;
} else
#endif // _HAS_CXX20
{
_My_data._Myres = _BUF_SIZE - 1;
// the _Traits::assign is last so the codegen doesn't think the char write can alias this
_Traits::assign(_My_data._Bx._Buf[0], _Elem());
}
_My_data._Myres = _BUF_SIZE - 1;
// the _Traits::assign is last so the codegen doesn't think the char write can alias this
_Traits::assign(_My_data._Bx._Buf[0], _Elem());
}

public:
Expand Down
14 changes: 5 additions & 9 deletions tests/std/tests/P0980R1_constexpr_strings/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,16 +613,12 @@ constexpr bool test_interface() {
literal_constructed.shrink_to_fit();
miscco marked this conversation as resolved.
Show resolved Hide resolved

const auto c4 = literal_constructed.capacity();
if (is_constant_evaluated()) { // check minimum allocation of _BUF_SIZE when constant evaluated
assert(c4 == 16 / sizeof(CharType));
if constexpr (is_same_v<CharType, char16_t> || is_same_v<CharType, wchar_t>) {
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
assert(c4 == 7);
} else if constexpr (is_same_v<CharType, char32_t>) {
assert(c4 == 3);
} else {
if constexpr (is_same_v<CharType, char16_t> || is_same_v<CharType, wchar_t>) {
assert(c4 == 7);
} else if constexpr (is_same_v<CharType, char32_t>) {
assert(c4 == 3);
} else {
assert(c4 == 15);
}
assert(c4 == 15);
}
}

Expand Down