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

<xstring>: constexpr string element lifetime #3334

Merged
merged 3 commits into from
Jan 12, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
77 changes: 28 additions & 49 deletions stl/inc/xstring
Original file line number Diff line number Diff line change
Expand Up @@ -2286,7 +2286,7 @@ public:
}

constexpr void _Activate_SSO_buffer() noexcept {
// begin the lifetime of the array elements (e.g., before copying into them)
// start the lifetime of the array elements
#if _HAS_CXX20
if (_STD is_constant_evaluated()) {
for (size_type _Idx = 0; _Idx < _BUF_SIZE; ++_Idx) {
Expand Down Expand Up @@ -2629,6 +2629,21 @@ public:
}

private:
static constexpr void _Start_element_lifetimes(_Elem* const _Ptr, const size_type _Size) {
// Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer,
// but likely more impactful to throughput.
#if _HAS_CXX20
if (_STD is_constant_evaluated()) {
for (size_type _Idx = 0; _Idx < _Size; ++_Idx) {
_STD construct_at(_Ptr + _Idx);
}
}
#else // ^^^ C++20-or-later / pre-C++20 vvv
(void) _Ptr;
(void) _Size;
#endif // _HAS_CXX20
}

enum class _Construct_strategy : uint8_t { _From_char, _From_ptr, _From_string };

template <_Construct_strategy _Strat, class _Char_or_ptr>
Expand Down Expand Up @@ -2658,13 +2673,13 @@ private:
_Traits::assign(_My_data._Bx._Buf, _Count, _Arg);
_Traits::assign(_My_data._Bx._Buf[_Count], _Elem());
} else if constexpr (_Strat == _Construct_strategy::_From_ptr) {
_Traits::move(_My_data._Bx._Buf, _Arg, _Count);
_Traits::copy(_My_data._Bx._Buf, _Arg, _Count);
_Traits::assign(_My_data._Bx._Buf[_Count], _Elem());
} else { // _Strat == _Construct_strategy::_From_string
#ifdef _INSERT_STRING_ANNOTATION
_Traits::move(_My_data._Bx._Buf, _Arg, _Count + 1);
_Traits::copy(_My_data._Bx._Buf, _Arg, _Count + 1);
#else // ^^^ _INSERT_STRING_ANNOTATION / !_INSERT_STRING_ANNOTATION vvv
_Traits::move(_My_data._Bx._Buf, _Arg, _BUF_SIZE);
_Traits::copy(_My_data._Bx._Buf, _Arg, _BUF_SIZE);
#endif // !_INSERT_STRING_ANNOTATION
}

Expand All @@ -2677,11 +2692,7 @@ private:
const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws
_Construct_in_place(_My_data._Bx._Ptr, _New_ptr);

#if _HAS_CXX20
if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB
_Traits::assign(_Unfancy(_New_ptr), _New_capacity + 1, _Elem());
}
#endif // _HAS_CXX20
_Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1);

_My_data._Mysize = _Count;
_My_data._Myres = _New_capacity;
Expand Down Expand Up @@ -2725,11 +2736,7 @@ private:
_Construct_in_place(_My_data._Bx._Ptr, _New_ptr);
_My_data._Myres = _New_capacity;

#if _HAS_CXX20
if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB
_Traits::assign(_Unfancy(_New_ptr), _New_capacity + 1, _Elem());
}
#endif // _HAS_CXX20
_Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1);
}
}

Expand All @@ -2745,11 +2752,7 @@ private:
const size_type _New_capacity = _Calculate_growth(_My_data._Mysize);
const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws

#if _HAS_CXX20
if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB
_Traits::assign(_Unfancy(_New_ptr), _New_capacity + 1, _Elem());
}
#endif // _HAS_CXX20
_Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1);
_Traits::copy(_Unfancy(_New_ptr), _Old_ptr, _My_data._Mysize);
if (_My_data._Myres >= _BUF_SIZE) { // Need to deallocate old storage
_Al.deallocate(_My_data._Bx._Ptr, _My_data._Myres + 1);
Expand Down Expand Up @@ -2834,11 +2837,7 @@ public:
_Ptr = _Unfancy(_Fancyptr);
_Construct_in_place(_My_data._Bx._Ptr, _Fancyptr);

#if _HAS_CXX20
if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB
_Traits::assign(_Ptr, _New_capacity + 1, _Elem());
}
#endif // _HAS_CXX20
_Start_element_lifetimes(_Ptr, _New_capacity + 1);
}

_My_data._Mysize = _New_size;
Expand Down Expand Up @@ -2909,11 +2908,7 @@ public:
_Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws
const pointer _Fancyptr = _Getal().allocate(_New_capacity + 1); // throws
// nothrow hereafter
#if _HAS_CXX20
if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB
_Traits::assign(_Unfancy(_Fancyptr), _New_capacity + 1, _Elem());
}
#endif // _HAS_CXX20
_Start_element_lifetimes(_Unfancy(_Fancyptr), _New_capacity + 1);
_Construct_in_place(_My_data._Bx._Ptr, _Fancyptr);
_My_data._Mysize = _New_size;
_My_data._Myres = _New_capacity;
Expand Down Expand Up @@ -3217,11 +3212,7 @@ public:
auto _Right_al_non_const = _Right_al;
const auto _New_ptr = _Right_al_non_const.allocate(_New_capacity + 1); // throws

#if _HAS_CXX20
if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB
_Traits::assign(_Unfancy(_New_ptr), _New_size + 1, _Elem());
}
#endif // _HAS_CXX20
_Start_element_lifetimes(_Unfancy(_New_ptr), _New_size + 1);

_Traits::copy(_Unfancy(_New_ptr), _Unfancy(_Right._Mypair._Myval2._Bx._Ptr), _New_size + 1);
_Tidy_deallocate();
Expand Down Expand Up @@ -4049,11 +4040,7 @@ public:
const pointer _New_ptr = _Al.allocate(_Target_capacity + 1); // throws
_ASAN_STRING_REMOVE(*this);

#if _HAS_CXX20
if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB
_Traits::assign(_Unfancy(_New_ptr), _Target_capacity + 1, _Elem());
}
#endif // _HAS_CXX20
_Start_element_lifetimes(_Unfancy(_New_ptr), _Target_capacity + 1);

_My_data._Orphan_all();
_Traits::copy(_Unfancy(_New_ptr), _Unfancy(_My_data._Bx._Ptr), _My_data._Mysize + 1);
Expand Down Expand Up @@ -4792,11 +4779,7 @@ private:
auto& _Al = _Getal();
const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws

#if _HAS_CXX20
if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB
_Traits::assign(_Unfancy(_New_ptr), _New_capacity + 1, _Elem());
}
#endif // _HAS_CXX20
_Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1);
_Mypair._Myval2._Orphan_all();
_ASAN_STRING_REMOVE(*this);
_Mypair._Myval2._Mysize = _New_size;
Expand Down Expand Up @@ -4829,11 +4812,7 @@ private:
auto& _Al = _Getal();
const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws

#if _HAS_CXX20
if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB
_Traits::assign(_Unfancy(_New_ptr), _New_capacity + 1, _Elem());
}
#endif // _HAS_CXX20
_Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1);
_My_data._Orphan_all();
_ASAN_STRING_REMOVE(*this);
_My_data._Mysize = _New_size;
Expand Down
7 changes: 0 additions & 7 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,6 @@ std/ranges/range.adaptors/range.lazy.split/view_interface.pass.cpp FAIL
std/ranges/range.adaptors/range.take/adaptor.pass.cpp FAIL
std/ranges/range.factories/range.single.view/cpo.pass.cpp FAIL
std/strings/basic.string/string.cons/dtor.pass.cpp FAIL
std/strings/basic.string/string.cons/implicit_deduction_guides.pass.cpp FAIL
std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp:0 FAIL
std/strings/basic.string/string.modifiers/string_erase/iter_iter.pass.cpp:0 FAIL
std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp:0 FAIL
Expand All @@ -1020,12 +1019,6 @@ std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer_size.
std/strings/basic.string/string.modifiers/string_replace/iter_iter_size_char.pass.cpp:0 FAIL
std/strings/basic.string/string.modifiers/string_replace/iter_iter_string.pass.cpp:0 FAIL
std/strings/basic.string/string.modifiers/string_replace/iter_iter_string_view.pass.cpp:0 FAIL
std/strings/string.view/string.view.comparison/equal.pass.cpp FAIL
std/strings/string.view/string.view.comparison/greater.pass.cpp FAIL
std/strings/string.view/string.view.comparison/greater_equal.pass.cpp FAIL
std/strings/string.view/string.view.comparison/less.pass.cpp FAIL
std/strings/string.view/string.view.comparison/less_equal.pass.cpp FAIL
std/strings/string.view/string.view.comparison/not_equal.pass.cpp FAIL
std/thread/futures/futures.task/futures.task.members/ctor2.compile.pass.cpp FAIL
std/utilities/function.objects/func.wrap/func.wrap.func/addressof.pass.cpp:0 FAIL
std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.alg/swap.pass.cpp:0 FAIL
Expand Down
7 changes: 0 additions & 7 deletions tests/libcxx/skipped_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,6 @@ ranges\range.adaptors\range.lazy.split\view_interface.pass.cpp
ranges\range.adaptors\range.take\adaptor.pass.cpp
ranges\range.factories\range.single.view\cpo.pass.cpp
strings\basic.string\string.cons\dtor.pass.cpp
strings\basic.string\string.cons\implicit_deduction_guides.pass.cpp
strings\basic.string\string.modifiers\string_erase\iter.pass.cpp
strings\basic.string\string.modifiers\string_erase\iter_iter.pass.cpp
strings\basic.string\string.modifiers\string_insert\iter_iter_iter.pass.cpp
Expand All @@ -1020,12 +1019,6 @@ strings\basic.string\string.modifiers\string_replace\iter_iter_pointer_size.pass
strings\basic.string\string.modifiers\string_replace\iter_iter_size_char.pass.cpp
strings\basic.string\string.modifiers\string_replace\iter_iter_string.pass.cpp
strings\basic.string\string.modifiers\string_replace\iter_iter_string_view.pass.cpp
strings\string.view\string.view.comparison\equal.pass.cpp
strings\string.view\string.view.comparison\greater.pass.cpp
strings\string.view\string.view.comparison\greater_equal.pass.cpp
strings\string.view\string.view.comparison\less.pass.cpp
strings\string.view\string.view.comparison\less_equal.pass.cpp
strings\string.view\string.view.comparison\not_equal.pass.cpp
thread\futures\futures.task\futures.task.members\ctor2.compile.pass.cpp
utilities\function.objects\func.wrap\func.wrap.func\addressof.pass.cpp
utilities\function.objects\func.wrap\func.wrap.func\func.wrap.func.alg\swap.pass.cpp
Expand Down