From b03c70857f55a553b681c43850491fc45bad2f11 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 21 Dec 2020 13:37:57 +0100 Subject: [PATCH 01/74] Prepare the constexpr machinery needed for string and vector --- stl/inc/xmemory | 431 +++++++++++++++++++++++++++++------------------ stl/inc/xutility | 14 +- 2 files changed, 280 insertions(+), 165 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 38209d5c9cd..73ecb33edbb 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -27,7 +27,7 @@ _STD_BEGIN template struct _NODISCARD _Tidy_guard { // class with destructor that calls _Tidy _Ty* _Target; - ~_Tidy_guard() { + _CONSTEXPR20_DYNALLOC ~_Tidy_guard() { if (_Target) { _Target->_Tidy(); } @@ -38,7 +38,7 @@ struct _NODISCARD _Tidy_guard { // class with destructor that calls _Tidy template struct _NODISCARD _Tidy_deallocate_guard { // class with destructor that calls _Tidy_deallocate _Ty* _Target; - ~_Tidy_deallocate_guard() { + _CONSTEXPR20_DYNALLOC ~_Tidy_deallocate_guard() { if (_Target) { _Target->_Tidy_deallocate(); } @@ -265,10 +265,10 @@ _CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, size_t _Bytes) noexcept { // FUNCTION TEMPLATE _Global_new template -_Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection +_CONSTEXPR20_DYNALLOC _Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection struct _NODISCARD _Guard_type { void* _Result; - ~_Guard_type() { + _CONSTEXPR20_DYNALLOC ~_Guard_type() { if (_Result) { _Deallocate<_New_alignof<_Ty>>(_Result, sizeof(_Ty)); } @@ -286,12 +286,12 @@ using _Rebind_pointer_t = typename pointer_traits<_Ptr>::template rebind<_Ty>; // FUNCTION TEMPLATE _Refancy template , int> = 0> -_Pointer _Refancy(typename pointer_traits<_Pointer>::element_type* _Ptr) noexcept { +_CONSTEXPR20 _Pointer _Refancy(typename pointer_traits<_Pointer>::element_type* _Ptr) noexcept { return pointer_traits<_Pointer>::pointer_to(*_Ptr); } template , int> = 0> -_Pointer _Refancy(_Pointer _Ptr) noexcept { +_CONSTEXPR20 _Pointer _Refancy(_Pointer _Ptr) noexcept { return _Ptr; } @@ -837,7 +837,7 @@ public: template _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS void construct(_Objty* const _Ptr, _Types&&... _Args) { - ::new (const_cast(static_cast(_Ptr))) _Objty(_STD forward<_Types>(_Args)...); + ::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); } template @@ -897,7 +897,7 @@ using _Alloc_size_t = typename allocator_traits<_Alloc>::size_type; // FUNCTION TEMPLATE _Pocca template -void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { +_CONSTEXPR20 void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { if constexpr (allocator_traits<_Alloc>::propagate_on_container_copy_assignment::value) { _Left = _Right; } @@ -905,7 +905,7 @@ void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { // FUNCTION TEMPLATE _Pocma template -void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // (maybe) propagate on container move assignment +_CONSTEXPR20 void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // (maybe) propagate on container move assignment if constexpr (allocator_traits<_Alloc>::propagate_on_container_move_assignment::value) { _Left = _STD move(_Right); } @@ -913,7 +913,7 @@ void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // (maybe) propagate on co // FUNCTION TEMPLATE _Pocs template -void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { +_CONSTEXPR20 void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { if constexpr (allocator_traits<_Alloc>::propagate_on_container_swap::value) { _Swap_adl(_Left, _Right); } else { @@ -923,7 +923,8 @@ void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { // FUNCTION TEMPLATE _Destroy_range WITH ALLOC template -void _Destroy_range(_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept { +_CONSTEXPR20_DYNALLOC void _Destroy_range( + _Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept { // note that this is an optimization for debug mode codegen; in release mode the BE removes all of this using _Ty = typename _Alloc::value_type; if constexpr (!conjunction_v, _Uses_default_destroy<_Alloc, _Ty*>>) { @@ -963,7 +964,7 @@ _NODISCARD constexpr size_t _Convert_size(const size_t _Len) noexcept { // FUNCTION TEMPLATE _Deallocate_plain template -void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { +_CONSTEXPR20_DYNALLOC void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { // deallocate a plain pointer using an allocator using _Alloc_traits = allocator_traits<_Alloc>; if constexpr (is_same_v<_Alloc_ptr_t<_Alloc>, typename _Alloc::value_type*>) { @@ -976,7 +977,7 @@ void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noe // FUNCTION TEMPLATE _Delete_plain_internal template -void _Delete_plain_internal(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { +_CONSTEXPR20_DYNALLOC void _Delete_plain_internal(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { // destroy *_Ptr in place, then deallocate _Ptr using _Al; used for internal container types the user didn't name using _Ty = typename _Alloc::value_type; _Ptr->~_Ty(); @@ -992,16 +993,16 @@ struct _Alloc_construct_ptr { // pointer used to help construct 1 _Alloc::value_ explicit _Alloc_construct_ptr(_Alloc& _Al_) : _Al(_Al_), _Ptr(nullptr) {} - _NODISCARD pointer _Release() noexcept { // disengage *this and return contained pointer + _NODISCARD _CONSTEXPR20_DYNALLOC pointer _Release() noexcept { // disengage *this and return contained pointer return _STD exchange(_Ptr, nullptr); } - void _Allocate() { // disengage *this, then allocate a new memory block + _CONSTEXPR20_DYNALLOC void _Allocate() { // disengage *this, then allocate a new memory block _Ptr = nullptr; // if allocate throws, prevents double-free _Ptr = _Al.allocate(1); } - ~_Alloc_construct_ptr() { // if this instance is engaged, deallocate storage + _CONSTEXPR20_DYNALLOC ~_Alloc_construct_ptr() { // if this instance is engaged, deallocate storage if (_Ptr) { _Al.deallocate(_Ptr, 1); } @@ -1015,15 +1016,15 @@ struct _Alloc_construct_ptr { // pointer used to help construct 1 _Alloc::value_ struct _Fake_allocator {}; struct _Container_base0 { - void _Orphan_all() noexcept {} - void _Swap_proxy_and_iterators(_Container_base0&) noexcept {} - void _Alloc_proxy(const _Fake_allocator&) noexcept {} - void _Reload_proxy(const _Fake_allocator&, const _Fake_allocator&) noexcept {} + _CONSTEXPR20 void _Orphan_all() noexcept {} + _CONSTEXPR20 void _Swap_proxy_and_iterators(_Container_base0&) noexcept {} + _CONSTEXPR20 void _Alloc_proxy(const _Fake_allocator&) noexcept {} + _CONSTEXPR20 void _Reload_proxy(const _Fake_allocator&, const _Fake_allocator&) noexcept {} }; struct _Iterator_base0 { - void _Adopt(const void*) noexcept {} - const _Container_base0* _Getcont() const noexcept { + _CONSTEXPR20 void _Adopt(const void*) noexcept {} + _CONSTEXPR20 const _Container_base0* _Getcont() const noexcept { return nullptr; } @@ -1033,25 +1034,25 @@ struct _Iterator_base0 { // CLASS _Container_proxy struct _Container_base12; struct _Container_proxy { // store head of iterator chain and back pointer - _Container_proxy() noexcept : _Mycont(nullptr), _Myfirstiter(nullptr) {} - _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_), _Myfirstiter(nullptr) {} + _CONSTEXPR20 _Container_proxy() noexcept = default; + _CONSTEXPR20 _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_) {} const _Container_base12* _Mycont; - _Iterator_base12* _Myfirstiter; + mutable _Iterator_base12* _Myfirstiter; }; struct _Container_base12 { public: - _Container_base12() noexcept : _Myproxy(nullptr) {} + _CONSTEXPR20_DYNALLOC _Container_base12() noexcept = default; _Container_base12(const _Container_base12&) = delete; _Container_base12& operator=(const _Container_base12&) = delete; - void _Orphan_all() noexcept; - void _Swap_proxy_and_iterators(_Container_base12&) noexcept; + _CONSTEXPR20_DYNALLOC void _Orphan_all() noexcept; + _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators(_Container_base12&) noexcept; template - void _Alloc_proxy(_Alloc&& _Al) { + _CONSTEXPR20_DYNALLOC void _Alloc_proxy(_Alloc&& _Al) { _Container_proxy* const _New_proxy = _Unfancy(_Al.allocate(1)); _Construct_in_place(*_New_proxy, this); _Myproxy = _New_proxy; @@ -1059,7 +1060,7 @@ public: } template - void _Reload_proxy(_Alloc&& _Old_alloc, _Alloc&& _New_alloc) { + _CONSTEXPR20_DYNALLOC void _Reload_proxy(_Alloc&& _Old_alloc, _Alloc&& _New_alloc) { // pre: no iterators refer to the existing proxy _Container_proxy* const _New_proxy = _Unfancy(_New_alloc.allocate(1)); _Construct_in_place(*_New_proxy, this); @@ -1067,113 +1068,156 @@ public: _Delete_plain_internal(_Old_alloc, _STD exchange(_Myproxy, _New_proxy)); } - _Container_proxy* _Myproxy; + _Container_proxy* _Myproxy = nullptr; + +private: + _CONSTEXPR20_DYNALLOC void _Orphan_all_unlocked() noexcept; + inline void _Orphan_all_locked() noexcept; + _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators_unlocked(_Container_base12&) noexcept; + inline void _Swap_proxy_and_iterators_locked(_Container_base12&) noexcept; }; struct _Iterator_base12 { // store links to container proxy, next iterator - _Iterator_base12() noexcept : _Myproxy(nullptr), _Mynextiter(nullptr) {} // construct orphaned iterator +public: + _CONSTEXPR20_DYNALLOC _Iterator_base12() noexcept = default; // construct orphaned iterator - _Iterator_base12(const _Iterator_base12& _Right) noexcept : _Myproxy(nullptr), _Mynextiter(nullptr) { + _CONSTEXPR20_DYNALLOC _Iterator_base12(const _Iterator_base12& _Right) noexcept { *this = _Right; } - _Iterator_base12& operator=(const _Iterator_base12& _Right) noexcept { + _CONSTEXPR20_DYNALLOC _Iterator_base12& operator=(const _Iterator_base12& _Right) noexcept { if (_Myproxy != _Right._Myproxy) { if (_Right._Myproxy) { _Adopt(_Right._Myproxy->_Mycont); } else { // becoming invalid, disown current parent #if _ITERATOR_DEBUG_LEVEL == 2 - _Lockit _Lock(_LOCK_DEBUG); _Orphan_me(); #else // _ITERATOR_DEBUG_LEVEL == 2 _Myproxy = nullptr; #endif // _ITERATOR_DEBUG_LEVEL == 2 } } - return *this; } - ~_Iterator_base12() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 - _Lockit _Lock(_LOCK_DEBUG); + _CONSTEXPR20_DYNALLOC ~_Iterator_base12() noexcept { _Orphan_me(); -#endif // _ITERATOR_DEBUG_LEVEL == 2 } - void _Adopt(const _Container_base12* _Parent) noexcept { - if (_Parent) { - // have a parent, do adoption + _CONSTEXPR20_DYNALLOC void _Adopt(const _Container_base12* _Parent) noexcept { + if (_Parent) { // have a parent, do adoption _Container_proxy* _Parent_proxy = _Parent->_Myproxy; - -#if _ITERATOR_DEBUG_LEVEL == 2 if (_Myproxy != _Parent_proxy) { // change parentage - _Lockit _Lock(_LOCK_DEBUG); - _Orphan_me(); - _Mynextiter = _Parent_proxy->_Myfirstiter; - _Parent_proxy->_Myfirstiter = this; - _Myproxy = _Parent_proxy; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Adopt_unlocked(_Parent_proxy); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Adopt_locked(_Parent_proxy); + } } - -#else // _ITERATOR_DEBUG_LEVEL == 2 - _Myproxy = _Parent_proxy; -#endif // _ITERATOR_DEBUG_LEVEL == 2 - } else { - // no future parent, just disown current parent -#if _ITERATOR_DEBUG_LEVEL == 2 - _Lockit _Lock(_LOCK_DEBUG); + } else { // no future parent, just disown current parent _Orphan_me(); -#else // _ITERATOR_DEBUG_LEVEL == 2 - _Myproxy = nullptr; -#endif // _ITERATOR_DEBUG_LEVEL == 2 } } - const _Container_base12* _Getcont() const noexcept { - return _Myproxy ? _Myproxy->_Mycont : nullptr; - } - -#if _ITERATOR_DEBUG_LEVEL == 2 - void _Orphan_me() noexcept { + _CONSTEXPR20_DYNALLOC void _Orphan_me() noexcept { if (_Myproxy) { // adopted, remove self from list - _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; - while (*_Pnext && *_Pnext != this) { - _Pnext = &(*_Pnext)->_Mynextiter; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Orphan_me_unlocked(); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Orphan_me_locked(); } + } + } - _STL_VERIFY(*_Pnext, "ITERATOR LIST CORRUPTED!"); - *_Pnext = _Mynextiter; +#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL != 2 vvv + _CONSTEXPR20_DYNALLOC void _Adopt(const _Container_base12* _Parent) noexcept { + if (_Parent) { // have a parent, do adoption + _Myproxy = _Parent->_Myproxy; + } else { // no future parent, just disown current parent _Myproxy = nullptr; } } -#endif // _ITERATOR_DEBUG_LEVEL == 2 +#endif // _ITERATOR_DEBUG_LEVEL != 2 + + _CONSTEXPR20_DYNALLOC const _Container_base12* _Getcont() const noexcept { + return _Myproxy ? _Myproxy->_Mycont : nullptr; + } static constexpr bool _Unwrap_when_unverified = _ITERATOR_DEBUG_LEVEL == 0; - _Container_proxy* _Myproxy; - _Iterator_base12* _Mynextiter; -}; + _Container_proxy* _Myproxy = nullptr; + _Iterator_base12* _Mynextiter = nullptr; -// MEMBER FUNCTIONS FOR _Container_base12 -inline void _Container_base12::_Orphan_all() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 - if (_Myproxy) { // proxy allocated, drain it +private: + _CONSTEXPR20_DYNALLOC void _Adopt_unlocked(_Container_proxy* _Parent_proxy) noexcept { + if (_Myproxy) { // adopted, remove self from list + _Orphan_me_unlocked(); + } + _Mynextiter = _Parent_proxy->_Myfirstiter; + _Parent_proxy->_Myfirstiter = this; + _Myproxy = _Parent_proxy; + } + + void _Adopt_locked(_Container_proxy* _Parent_proxy) noexcept { _Lockit _Lock(_LOCK_DEBUG); + _Adopt_unlocked(_Parent_proxy); + } - for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) { - (*_Pnext)->_Myproxy = nullptr; + _CONSTEXPR20_DYNALLOC void _Orphan_me_unlocked() noexcept { + _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; + while (*_Pnext && *_Pnext != this) { + _Pnext = &(*_Pnext)->_Mynextiter; } - _Myproxy->_Myfirstiter = nullptr; + _STL_VERIFY(*_Pnext, "ITERATOR LIST CORRUPTED!"); + *_Pnext = _Mynextiter; + _Myproxy = nullptr; + } + + void _Orphan_me_locked() noexcept { + _Lockit _Lock(_LOCK_DEBUG); + _Orphan_me_unlocked(); } #endif // _ITERATOR_DEBUG_LEVEL == 2 +}; + +// MEMBER FUNCTIONS FOR _Container_base12 +_CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all_unlocked() noexcept { + for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) { + (*_Pnext)->_Myproxy = nullptr; + } + _Myproxy->_Myfirstiter = nullptr; } -inline void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { -#if _ITERATOR_DEBUG_LEVEL == 2 +inline void _Container_base12::_Orphan_all_locked() noexcept { _Lockit _Lock(_LOCK_DEBUG); + _Orphan_all_unlocked(); +} + +_CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all() noexcept { +#if _ITERATOR_DEBUG_LEVEL == 2 + if (_Myproxy) { // proxy allocated, drain it +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Orphan_all_unlocked(); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Orphan_all_locked(); + } + } #endif // _ITERATOR_DEBUG_LEVEL == 2 +} +_CONSTEXPR20_DYNALLOC void _Container_base12::_Swap_proxy_and_iterators_unlocked(_Container_base12& _Right) noexcept { _Container_proxy* _Temp = _Myproxy; _Myproxy = _Right._Myproxy; _Right._Myproxy = _Temp; @@ -1187,6 +1231,26 @@ inline void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Rig } } +inline void _Container_base12::_Swap_proxy_and_iterators_locked(_Container_base12& _Right) noexcept { + _Lockit _Lock(_LOCK_DEBUG); + _Swap_proxy_and_iterators_unlocked(_Right); +} + +_CONSTEXPR20_DYNALLOC void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { +#if _ITERATOR_DEBUG_LEVEL != 2 + _Swap_proxy_and_iterators_unlocked(_Right); +#else // ^^^ _ITERATOR_DEBUG_LEVEL != 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL == 2 vvv +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Swap_proxy_and_iterators_unlocked(_Right); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Swap_proxy_and_iterators_locked(_Right); + } +#endif // _ITERATOR_DEBUG_LEVEL == 2 +} + #if _ITERATOR_DEBUG_LEVEL == 0 using _Container_base = _Container_base0; using _Iterator_base = _Iterator_base0; @@ -1203,23 +1267,23 @@ struct _Leave_proxy_unbound { struct _Fake_proxy_ptr_impl { // fake replacement for a container proxy smart pointer when no container proxy is in use _Fake_proxy_ptr_impl(const _Fake_proxy_ptr_impl&) = delete; _Fake_proxy_ptr_impl& operator=(const _Fake_proxy_ptr_impl&) = delete; - _Fake_proxy_ptr_impl(const _Fake_allocator&, _Leave_proxy_unbound) noexcept {} - _Fake_proxy_ptr_impl(const _Fake_allocator&, const _Container_base0&) noexcept {} + _CONSTEXPR20_DYNALLOC _Fake_proxy_ptr_impl(const _Fake_allocator&, _Leave_proxy_unbound) noexcept {} + _CONSTEXPR20_DYNALLOC _Fake_proxy_ptr_impl(const _Fake_allocator&, const _Container_base0&) noexcept {} - void _Bind(const _Fake_allocator&, _Container_base0*) noexcept {} - void _Release() noexcept {} + _CONSTEXPR20_DYNALLOC void _Bind(const _Fake_allocator&, _Container_base0*) noexcept {} + _CONSTEXPR20_DYNALLOC void _Release() noexcept {} }; struct _Basic_container_proxy_ptr12 { // smart pointer components for a _Container_proxy * that don't depend on the allocator _Container_proxy* _Ptr; - void _Release() noexcept { // disengage this _Basic_container_proxy_ptr12 + constexpr void _Release() noexcept { // disengage this _Basic_container_proxy_ptr12 _Ptr = nullptr; } protected: - _Basic_container_proxy_ptr12() = default; + _CONSTEXPR20_DYNALLOC _Basic_container_proxy_ptr12() = default; _Basic_container_proxy_ptr12(const _Basic_container_proxy_ptr12&) = delete; _Basic_container_proxy_ptr12(_Basic_container_proxy_ptr12&&) = delete; }; @@ -1229,26 +1293,27 @@ struct _Container_proxy_ptr12 : _Basic_container_proxy_ptr12 { // smart pointer components for a _Container_proxy * for an allocator family _Alloc& _Al; - _Container_proxy_ptr12(_Alloc& _Al_, _Leave_proxy_unbound) : _Al(_Al_) { // create a new unbound _Container_proxy + _CONSTEXPR20_DYNALLOC _Container_proxy_ptr12(_Alloc& _Al_, _Leave_proxy_unbound) : _Al(_Al_) { + // create a new unbound _Container_proxy _Ptr = _Unfancy(_Al_.allocate(1)); _Construct_in_place(*_Ptr); } - _Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont) - : _Al(_Al_) { // create a new _Container_proxy pointing at _Mycont + _CONSTEXPR20_DYNALLOC _Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont) : _Al(_Al_) { + // create a new _Container_proxy pointing at _Mycont _Ptr = _Unfancy(_Al_.allocate(1)); _Construct_in_place(*_Ptr, _STD addressof(_Mycont)); _Mycont._Myproxy = _Ptr; } - void _Bind(_Alloc& _Old_alloc, _Container_base12* _Mycont) noexcept { + _CONSTEXPR20_DYNALLOC void _Bind(_Alloc& _Old_alloc, _Container_base12* _Mycont) noexcept { // Attach the proxy stored in *this to _Mycont, and destroy _Mycont's existing proxy // with _Old_alloc. Requires that no iterators are alive referring to _Mycont. _Ptr->_Mycont = _Mycont; _Delete_plain_internal(_Old_alloc, _STD exchange(_Mycont->_Myproxy, _STD exchange(_Ptr, nullptr))); } - ~_Container_proxy_ptr12() { + _CONSTEXPR20_DYNALLOC ~_Container_proxy_ptr12() { if (_Ptr) { _Delete_plain_internal(_Al, _Ptr); } @@ -1381,18 +1446,18 @@ struct _NODISCARD _Uninitialized_backout { _Uninitialized_backout(const _Uninitialized_backout&) = delete; _Uninitialized_backout& operator=(const _Uninitialized_backout&) = delete; - ~_Uninitialized_backout() { + _CONSTEXPR20_DYNALLOC ~_Uninitialized_backout() { _Destroy_range(_First, _Last); } template - void _Emplace_back(_Types&&... _Vals) { + _CONSTEXPR20_DYNALLOC void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment _Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...); ++_Last; } - _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last + constexpr _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last _First = _Last; return _Last; } @@ -1425,18 +1490,23 @@ namespace ranges { // FUNCTION TEMPLATE _Uninitialized_move_unchecked template -_NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { +_CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_move_unchecked( + _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // move [_First, _Last) to raw [_Dest, ...) if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { - return _Copy_memmove(_First, _Last, _Dest); - } else { - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; - for (; _First != _Last; ++_First) { - _Backout._Emplace_back(_STD move(*_First)); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + return _Copy_memmove(_First, _Last, _Dest); } - - return _Backout._Release(); } + _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; + for (; _First != _Last; ++_First) { + _Backout._Emplace_back(_STD move(*_First)); + } + + return _Backout._Release(); } // STRUCT TEMPLATE _Uninitialized_backout_al @@ -1446,22 +1516,23 @@ class _NODISCARD _Uninitialized_backout_al { using pointer = _Alloc_ptr_t<_Alloc>; public: - _Uninitialized_backout_al(pointer _Dest, _Alloc& _Al_) : _First(_Dest), _Last(_Dest), _Al(_Al_) {} + _CONSTEXPR20_DYNALLOC _Uninitialized_backout_al(pointer _Dest, _Alloc& _Al_) + : _First(_Dest), _Last(_Dest), _Al(_Al_) {} _Uninitialized_backout_al(const _Uninitialized_backout_al&) = delete; _Uninitialized_backout_al& operator=(const _Uninitialized_backout_al&) = delete; - ~_Uninitialized_backout_al() { + _CONSTEXPR20_DYNALLOC ~_Uninitialized_backout_al() { _Destroy_range(_First, _Last, _Al); } template - void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment + _CONSTEXPR20_DYNALLOC void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment allocator_traits<_Alloc>::construct(_Al, _Unfancy(_Last), _STD forward<_Types>(_Vals)...); ++_Last; } - pointer _Release() { // suppress any exception handling backout and return _Last + _CONSTEXPR20_DYNALLOC pointer _Release() { // suppress any exception handling backout and return _Last _First = _Last; return _Last; } @@ -1474,7 +1545,7 @@ private: // FUNCTION TEMPLATE _Uninitialized_copy WITH ALLOCATOR template -_Alloc_ptr_t<_Alloc> _Uninitialized_copy( +_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_copy( const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) { // copy [_First, _Last) to raw _Dest, using _Al // note: only called internally from elsewhere in the STL @@ -1485,21 +1556,48 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_copy( if constexpr (conjunction_v::_Really_trivial>, _Uses_default_construct<_Alloc, _Ptrval, decltype(*_UFirst)>>) { - _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); - _Dest += _ULast - _UFirst; - } else { - _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; - for (; _UFirst != _ULast; ++_UFirst) { - _Backout._Emplace_back(*_UFirst); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); + _Dest += _ULast - _UFirst; + return _Dest; } - - _Dest = _Backout._Release(); + } + _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; + for (; _UFirst != _ULast; ++_UFirst) { + _Backout._Emplace_back(*_UFirst); } + _Dest = _Backout._Release(); + return _Dest; } // FUNCTION TEMPLATE uninitialized_copy +template +_CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_copy_unchecked( + _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { + // copy [_First, _Last) to raw [_Dest, ...) + if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + return _Copy_memmove(_First, _Last, _Dest); + } + } + _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; + for (; _First != _Last; ++_First) { + _Backout._Emplace_back(*_First); + } + + _Dest = _Backout._Release(); + + return _Dest; +} + template _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // copy [_First, _Last) to raw [_Dest, ...) @@ -1507,24 +1605,13 @@ _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrow auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast)); - if constexpr (_Ptr_copy_cat::_Really_trivial) { - _UDest = _Copy_memmove(_UFirst, _ULast, _UDest); - } else { - _Uninitialized_backout _Backout{_UDest}; - for (; _UFirst != _ULast; ++_UFirst) { - _Backout._Emplace_back(*_UFirst); - } - - _UDest = _Backout._Release(); - } - - _Seek_wrapped(_Dest, _UDest); + _Seek_wrapped(_Dest, _Uninitialized_copy_unchecked(_UFirst, _ULast, _UDest)); return _Dest; } // FUNCTION TEMPLATE _Uninitialized_move WITH ALLOCATOR template -_Alloc_ptr_t<_Alloc> _Uninitialized_move( +_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_move( const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) { // move [_First, _Last) to raw _Dest, using _Al // note: only called internally from elsewhere in the STL @@ -1533,41 +1620,54 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_move( const auto _ULast = _Get_unwrapped(_Last); if constexpr (conjunction_v::_Really_trivial>, _Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>>) { - _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); - return _Dest + (_ULast - _UFirst); - } else { - _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; - for (; _UFirst != _ULast; ++_UFirst) { - _Backout._Emplace_back(_STD move(*_UFirst)); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); + return _Dest + (_ULast - _UFirst); } - - return _Backout._Release(); } + _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; + for (; _UFirst != _ULast; ++_UFirst) { + _Backout._Emplace_back(_STD move(*_UFirst)); + } + + return _Backout._Release(); } // FUNCTION TEMPLATE _Uninitialized_fill_n WITH ALLOCATOR template -_Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( +_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, const typename _Alloc::value_type& _Val, _Alloc& _Al) { // copy _Count copies of _Val to raw _First, using _Al using _Ty = typename _Alloc::value_type; if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { - _Fill_memset(_Unfancy(_First), _Val, static_cast(_Count)); - return _First + _Count; - } else { - if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Fill_memset(_Unfancy(_First), _Val, static_cast(_Count)); + return _First + _Count; + } + } else if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_Unfancy(_First), static_cast(_Count)); return _First + _Count; } } - _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(_Val); - } + } + _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; - return _Backout._Release(); + for (; 0 < _Count; --_Count) { + _Backout._Emplace_back(_Val); } + + return _Backout._Release(); } // FUNCTION TEMPLATE uninitialized_fill @@ -1610,22 +1710,26 @@ _Ptr _Zero_range(const _Ptr _First, const _Ptr _Last) { // fill [_First, _Last) } template -_Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( +_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, _Alloc& _Al) { // value-initialize _Count objects to raw _First, using _Al using _Ptrty = typename _Alloc::value_type*; if constexpr (_Use_memset_value_construct_v<_Ptrty> && _Uses_default_construct<_Alloc, _Ptrty>::value) { - auto _PFirst = _Unfancy(_First); - _Zero_range(_PFirst, _PFirst + _Count); - return _First + _Count; - } else { - _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + auto _PFirst = _Unfancy(_First); + _Zero_range(_PFirst, _PFirst + _Count); + return _First + _Count; } - - return _Backout._Release(); } + _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; + for (; 0 < _Count; --_Count) { + _Backout._Emplace_back(); + } + + return _Backout._Release(); } template @@ -1788,7 +1892,8 @@ _NODISCARD _CONSTEXPR20 _FwdIt remove_if(_FwdIt _First, const _FwdIt _Last, _Pr // FUNCTION TEMPLATE _Erase_remove template -typename _Container::size_type _Erase_remove(_Container& _Cont, const _Uty& _Val) { // erase each element matching _Val +_CONSTEXPR20_DYNALLOC typename _Container::size_type _Erase_remove(_Container& _Cont, const _Uty& _Val) { + // erase each element matching _Val auto _First = _Cont.begin(); const auto _Last = _Cont.end(); const auto _Old_size = _Cont.size(); @@ -1799,7 +1904,8 @@ typename _Container::size_type _Erase_remove(_Container& _Cont, const _Uty& _Val // FUNCTION TEMPLATE _Erase_remove_if template -typename _Container::size_type _Erase_remove_if(_Container& _Cont, _Pr _Pred) { // erase each element satisfying _Pred +_CONSTEXPR20_DYNALLOC typename _Container::size_type _Erase_remove_if(_Container& _Cont, _Pr _Pred) { + // erase each element satisfying _Pred auto _First = _Cont.begin(); const auto _Last = _Cont.end(); const auto _Old_size = _Cont.size(); @@ -1810,7 +1916,8 @@ typename _Container::size_type _Erase_remove_if(_Container& _Cont, _Pr _Pred) { // FUNCTION TEMPLATE _Erase_nodes_if template -typename _Container::size_type _Erase_nodes_if(_Container& _Cont, _Pr _Pred) { // erase each element satisfying _Pred +typename _Container::size_type _Erase_nodes_if(_Container& _Cont, _Pr _Pred) { + // erase each element satisfying _Pred auto _First = _Cont.begin(); const auto _Last = _Cont.end(); const auto _Old_size = _Cont.size(); diff --git a/stl/inc/xutility b/stl/inc/xutility index 653646d5425..67f0e54f1b6 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -141,13 +141,21 @@ _CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) // FUNCTION TEMPLATE _Construct_in_place template -void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { - ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); +_CONSTEXPR20_DYNALLOC void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept( + is_nothrow_constructible_v<_Ty, _Types...>) { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _STD construct_at(_STD addressof(_Obj), _STD forward<_Types>(_Args)...); + } else +#endif // __cpp_lib_is_constant_evaluated + { + ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); + } } // FUNCTION TEMPLATE _Default_construct_in_place template -void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { +_CONSTEXPR20_DYNALLOC void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty; } From 0d8082aacd3bd713238f5181ef643c589628f885 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 11 Jan 2021 13:19:59 +0100 Subject: [PATCH 02/74] Properly initialize --- stl/inc/xmemory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 73ecb33edbb..745907c3651 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1037,8 +1037,8 @@ struct _Container_proxy { // store head of iterator chain and back pointer _CONSTEXPR20 _Container_proxy() noexcept = default; _CONSTEXPR20 _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_) {} - const _Container_base12* _Mycont; - mutable _Iterator_base12* _Myfirstiter; + const _Container_base12* _Mycont = nullptr; + mutable _Iterator_base12* _Myfirstiter = nullptr; }; struct _Container_base12 { From 0ca2b483658015ab23a2d007f63dac3e199730af Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 18 Jan 2021 13:09:45 +0100 Subject: [PATCH 03/74] Use _CONSTEXPR20_CONTAINER --- stl/inc/xmemory | 76 ++++++++++++++++++++++---------------------- stl/inc/yvals_core.h | 7 ++++ 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 745907c3651..3497438a30a 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1016,15 +1016,15 @@ struct _Alloc_construct_ptr { // pointer used to help construct 1 _Alloc::value_ struct _Fake_allocator {}; struct _Container_base0 { - _CONSTEXPR20 void _Orphan_all() noexcept {} - _CONSTEXPR20 void _Swap_proxy_and_iterators(_Container_base0&) noexcept {} - _CONSTEXPR20 void _Alloc_proxy(const _Fake_allocator&) noexcept {} - _CONSTEXPR20 void _Reload_proxy(const _Fake_allocator&, const _Fake_allocator&) noexcept {} + _CONSTEXPR20_CONTAINER void _Orphan_all() noexcept {} + _CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators(_Container_base0&) noexcept {} + _CONSTEXPR20_CONTAINER void _Alloc_proxy(const _Fake_allocator&) noexcept {} + _CONSTEXPR20_CONTAINER void _Reload_proxy(const _Fake_allocator&, const _Fake_allocator&) noexcept {} }; struct _Iterator_base0 { - _CONSTEXPR20 void _Adopt(const void*) noexcept {} - _CONSTEXPR20 const _Container_base0* _Getcont() const noexcept { + _CONSTEXPR20_CONTAINER void _Adopt(const void*) noexcept {} + _CONSTEXPR20_CONTAINER const _Container_base0* _Getcont() const noexcept { return nullptr; } @@ -1034,8 +1034,8 @@ struct _Iterator_base0 { // CLASS _Container_proxy struct _Container_base12; struct _Container_proxy { // store head of iterator chain and back pointer - _CONSTEXPR20 _Container_proxy() noexcept = default; - _CONSTEXPR20 _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_) {} + _CONSTEXPR20_CONTAINER _Container_proxy() noexcept = default; + _CONSTEXPR20_CONTAINER _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_) {} const _Container_base12* _Mycont = nullptr; mutable _Iterator_base12* _Myfirstiter = nullptr; @@ -1043,16 +1043,16 @@ struct _Container_proxy { // store head of iterator chain and back pointer struct _Container_base12 { public: - _CONSTEXPR20_DYNALLOC _Container_base12() noexcept = default; + _CONSTEXPR20_CONTAINER _Container_base12() noexcept = default; _Container_base12(const _Container_base12&) = delete; _Container_base12& operator=(const _Container_base12&) = delete; - _CONSTEXPR20_DYNALLOC void _Orphan_all() noexcept; - _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators(_Container_base12&) noexcept; + _CONSTEXPR20_CONTAINER void _Orphan_all() noexcept; + _CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators(_Container_base12&) noexcept; template - _CONSTEXPR20_DYNALLOC void _Alloc_proxy(_Alloc&& _Al) { + _CONSTEXPR20_CONTAINER void _Alloc_proxy(_Alloc&& _Al) { _Container_proxy* const _New_proxy = _Unfancy(_Al.allocate(1)); _Construct_in_place(*_New_proxy, this); _Myproxy = _New_proxy; @@ -1060,7 +1060,7 @@ public: } template - _CONSTEXPR20_DYNALLOC void _Reload_proxy(_Alloc&& _Old_alloc, _Alloc&& _New_alloc) { + _CONSTEXPR20_CONTAINER void _Reload_proxy(_Alloc&& _Old_alloc, _Alloc&& _New_alloc) { // pre: no iterators refer to the existing proxy _Container_proxy* const _New_proxy = _Unfancy(_New_alloc.allocate(1)); _Construct_in_place(*_New_proxy, this); @@ -1071,21 +1071,21 @@ public: _Container_proxy* _Myproxy = nullptr; private: - _CONSTEXPR20_DYNALLOC void _Orphan_all_unlocked() noexcept; + _CONSTEXPR20_CONTAINER void _Orphan_all_unlocked() noexcept; inline void _Orphan_all_locked() noexcept; - _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators_unlocked(_Container_base12&) noexcept; + _CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators_unlocked(_Container_base12&) noexcept; inline void _Swap_proxy_and_iterators_locked(_Container_base12&) noexcept; }; struct _Iterator_base12 { // store links to container proxy, next iterator public: - _CONSTEXPR20_DYNALLOC _Iterator_base12() noexcept = default; // construct orphaned iterator + _CONSTEXPR20_CONTAINER _Iterator_base12() noexcept = default; // construct orphaned iterator - _CONSTEXPR20_DYNALLOC _Iterator_base12(const _Iterator_base12& _Right) noexcept { + _CONSTEXPR20_CONTAINER _Iterator_base12(const _Iterator_base12& _Right) noexcept { *this = _Right; } - _CONSTEXPR20_DYNALLOC _Iterator_base12& operator=(const _Iterator_base12& _Right) noexcept { + _CONSTEXPR20_CONTAINER _Iterator_base12& operator=(const _Iterator_base12& _Right) noexcept { if (_Myproxy != _Right._Myproxy) { if (_Right._Myproxy) { _Adopt(_Right._Myproxy->_Mycont); @@ -1101,11 +1101,11 @@ public: } #if _ITERATOR_DEBUG_LEVEL == 2 - _CONSTEXPR20_DYNALLOC ~_Iterator_base12() noexcept { + _CONSTEXPR20_CONTAINER ~_Iterator_base12() noexcept { _Orphan_me(); } - _CONSTEXPR20_DYNALLOC void _Adopt(const _Container_base12* _Parent) noexcept { + _CONSTEXPR20_CONTAINER void _Adopt(const _Container_base12* _Parent) noexcept { if (_Parent) { // have a parent, do adoption _Container_proxy* _Parent_proxy = _Parent->_Myproxy; if (_Myproxy != _Parent_proxy) { // change parentage @@ -1123,7 +1123,7 @@ public: } } - _CONSTEXPR20_DYNALLOC void _Orphan_me() noexcept { + _CONSTEXPR20_CONTAINER void _Orphan_me() noexcept { if (_Myproxy) { // adopted, remove self from list #ifdef __cpp_lib_is_constant_evaluated if (_STD is_constant_evaluated()) { @@ -1137,7 +1137,7 @@ public: } #else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL != 2 vvv - _CONSTEXPR20_DYNALLOC void _Adopt(const _Container_base12* _Parent) noexcept { + _CONSTEXPR20_CONTAINER void _Adopt(const _Container_base12* _Parent) noexcept { if (_Parent) { // have a parent, do adoption _Myproxy = _Parent->_Myproxy; } else { // no future parent, just disown current parent @@ -1146,7 +1146,7 @@ public: } #endif // _ITERATOR_DEBUG_LEVEL != 2 - _CONSTEXPR20_DYNALLOC const _Container_base12* _Getcont() const noexcept { + _CONSTEXPR20_CONTAINER const _Container_base12* _Getcont() const noexcept { return _Myproxy ? _Myproxy->_Mycont : nullptr; } @@ -1157,7 +1157,7 @@ public: #if _ITERATOR_DEBUG_LEVEL == 2 private: - _CONSTEXPR20_DYNALLOC void _Adopt_unlocked(_Container_proxy* _Parent_proxy) noexcept { + _CONSTEXPR20_CONTAINER void _Adopt_unlocked(_Container_proxy* _Parent_proxy) noexcept { if (_Myproxy) { // adopted, remove self from list _Orphan_me_unlocked(); } @@ -1171,7 +1171,7 @@ private: _Adopt_unlocked(_Parent_proxy); } - _CONSTEXPR20_DYNALLOC void _Orphan_me_unlocked() noexcept { + _CONSTEXPR20_CONTAINER void _Orphan_me_unlocked() noexcept { _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; while (*_Pnext && *_Pnext != this) { _Pnext = &(*_Pnext)->_Mynextiter; @@ -1190,7 +1190,7 @@ private: }; // MEMBER FUNCTIONS FOR _Container_base12 -_CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all_unlocked() noexcept { +_CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all_unlocked() noexcept { for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) { (*_Pnext)->_Myproxy = nullptr; } @@ -1202,7 +1202,7 @@ inline void _Container_base12::_Orphan_all_locked() noexcept { _Orphan_all_unlocked(); } -_CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all() noexcept { +_CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 if (_Myproxy) { // proxy allocated, drain it #ifdef __cpp_lib_is_constant_evaluated @@ -1217,7 +1217,7 @@ _CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all() noexcept { #endif // _ITERATOR_DEBUG_LEVEL == 2 } -_CONSTEXPR20_DYNALLOC void _Container_base12::_Swap_proxy_and_iterators_unlocked(_Container_base12& _Right) noexcept { +_CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators_unlocked(_Container_base12& _Right) noexcept { _Container_proxy* _Temp = _Myproxy; _Myproxy = _Right._Myproxy; _Right._Myproxy = _Temp; @@ -1236,7 +1236,7 @@ inline void _Container_base12::_Swap_proxy_and_iterators_locked(_Container_base1 _Swap_proxy_and_iterators_unlocked(_Right); } -_CONSTEXPR20_DYNALLOC void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { +_CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { #if _ITERATOR_DEBUG_LEVEL != 2 _Swap_proxy_and_iterators_unlocked(_Right); #else // ^^^ _ITERATOR_DEBUG_LEVEL != 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL == 2 vvv @@ -1267,11 +1267,11 @@ struct _Leave_proxy_unbound { struct _Fake_proxy_ptr_impl { // fake replacement for a container proxy smart pointer when no container proxy is in use _Fake_proxy_ptr_impl(const _Fake_proxy_ptr_impl&) = delete; _Fake_proxy_ptr_impl& operator=(const _Fake_proxy_ptr_impl&) = delete; - _CONSTEXPR20_DYNALLOC _Fake_proxy_ptr_impl(const _Fake_allocator&, _Leave_proxy_unbound) noexcept {} - _CONSTEXPR20_DYNALLOC _Fake_proxy_ptr_impl(const _Fake_allocator&, const _Container_base0&) noexcept {} + _CONSTEXPR20_CONTAINER _Fake_proxy_ptr_impl(const _Fake_allocator&, _Leave_proxy_unbound) noexcept {} + _CONSTEXPR20_CONTAINER _Fake_proxy_ptr_impl(const _Fake_allocator&, const _Container_base0&) noexcept {} - _CONSTEXPR20_DYNALLOC void _Bind(const _Fake_allocator&, _Container_base0*) noexcept {} - _CONSTEXPR20_DYNALLOC void _Release() noexcept {} + _CONSTEXPR20_CONTAINER void _Bind(const _Fake_allocator&, _Container_base0*) noexcept {} + _CONSTEXPR20_CONTAINER void _Release() noexcept {} }; struct _Basic_container_proxy_ptr12 { @@ -1283,7 +1283,7 @@ struct _Basic_container_proxy_ptr12 { } protected: - _CONSTEXPR20_DYNALLOC _Basic_container_proxy_ptr12() = default; + _CONSTEXPR20_CONTAINER _Basic_container_proxy_ptr12() = default; _Basic_container_proxy_ptr12(const _Basic_container_proxy_ptr12&) = delete; _Basic_container_proxy_ptr12(_Basic_container_proxy_ptr12&&) = delete; }; @@ -1293,27 +1293,27 @@ struct _Container_proxy_ptr12 : _Basic_container_proxy_ptr12 { // smart pointer components for a _Container_proxy * for an allocator family _Alloc& _Al; - _CONSTEXPR20_DYNALLOC _Container_proxy_ptr12(_Alloc& _Al_, _Leave_proxy_unbound) : _Al(_Al_) { + _CONSTEXPR20_CONTAINER _Container_proxy_ptr12(_Alloc& _Al_, _Leave_proxy_unbound) : _Al(_Al_) { // create a new unbound _Container_proxy _Ptr = _Unfancy(_Al_.allocate(1)); _Construct_in_place(*_Ptr); } - _CONSTEXPR20_DYNALLOC _Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont) : _Al(_Al_) { + _CONSTEXPR20_CONTAINER _Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont) : _Al(_Al_) { // create a new _Container_proxy pointing at _Mycont _Ptr = _Unfancy(_Al_.allocate(1)); _Construct_in_place(*_Ptr, _STD addressof(_Mycont)); _Mycont._Myproxy = _Ptr; } - _CONSTEXPR20_DYNALLOC void _Bind(_Alloc& _Old_alloc, _Container_base12* _Mycont) noexcept { + _CONSTEXPR20_CONTAINER void _Bind(_Alloc& _Old_alloc, _Container_base12* _Mycont) noexcept { // Attach the proxy stored in *this to _Mycont, and destroy _Mycont's existing proxy // with _Old_alloc. Requires that no iterators are alive referring to _Mycont. _Ptr->_Mycont = _Mycont; _Delete_plain_internal(_Old_alloc, _STD exchange(_Mycont->_Myproxy, _STD exchange(_Ptr, nullptr))); } - _CONSTEXPR20_DYNALLOC ~_Container_proxy_ptr12() { + _CONSTEXPR20_CONTAINER ~_Container_proxy_ptr12() { if (_Ptr) { _Delete_plain_internal(_Al, _Ptr); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index e37d8daf036..b5d3d18f968 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1263,6 +1263,13 @@ #define _CONSTEXPR20_DYNALLOC inline #endif +// Functions that became constexpr in C++20 via P0980R1 or P1004R2 +#if defined(__cpp_lib_constexpr_dynamic_alloc) && !defined(__clang__) // TRANSITION:LLVM-48606 +#define _CONSTEXPR20_CONTAINER constexpr +#else +#define _CONSTEXPR20_CONTAINER inline +#endif + #ifdef _RTC_CONVERSION_CHECKS_ENABLED #ifndef _ALLOW_RTCc_IN_STL #error /RTCc rejects conformant code, so it is not supported by the C++ Standard Library. Either remove this \ From 4135658ef61bdc2d1d2d43a3023caebd94af2a27 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Thu, 21 Jan 2021 22:22:25 +0100 Subject: [PATCH 04/74] Address review comments --- stl/inc/regex | 2 +- stl/inc/xmemory | 44 +++++++++++++++++++++----------------------- stl/inc/xutility | 2 +- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 0cd17c2b3a0..330944b8a28 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -2466,7 +2466,7 @@ public: _MyRe = nullptr; #if _ITERATOR_DEBUG_LEVEL == 2 - this->_Orphan_me(); + this->_Orphan_me_v2(); #endif // _ITERATOR_DEBUG_LEVEL return *this; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 3497438a30a..61872788623 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -265,10 +265,10 @@ _CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, size_t _Bytes) noexcept { // FUNCTION TEMPLATE _Global_new template -_CONSTEXPR20_DYNALLOC _Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection +_Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection struct _NODISCARD _Guard_type { void* _Result; - _CONSTEXPR20_DYNALLOC ~_Guard_type() { + ~_Guard_type() { if (_Result) { _Deallocate<_New_alignof<_Ty>>(_Result, sizeof(_Ty)); } @@ -991,7 +991,7 @@ struct _Alloc_construct_ptr { // pointer used to help construct 1 _Alloc::value_ _Alloc& _Al; pointer _Ptr; - explicit _Alloc_construct_ptr(_Alloc& _Al_) : _Al(_Al_), _Ptr(nullptr) {} + _CONSTEXPR20_DYNALLOC explicit _Alloc_construct_ptr(_Alloc& _Al_) : _Al(_Al_), _Ptr(nullptr) {} _NODISCARD _CONSTEXPR20_DYNALLOC pointer _Release() noexcept { // disengage *this and return contained pointer return _STD exchange(_Ptr, nullptr); @@ -1072,9 +1072,17 @@ public: private: _CONSTEXPR20_CONTAINER void _Orphan_all_unlocked() noexcept; - inline void _Orphan_all_locked() noexcept; _CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators_unlocked(_Container_base12&) noexcept; - inline void _Swap_proxy_and_iterators_locked(_Container_base12&) noexcept; + + void _Orphan_all_locked() noexcept { + _Lockit _Lock(_LOCK_DEBUG); + _Orphan_all_unlocked(); + } + + void _Swap_proxy_and_iterators_locked(_Container_base12& _Right) noexcept { + _Lockit _Lock(_LOCK_DEBUG); + _Swap_proxy_and_iterators_unlocked(_Right); + } }; struct _Iterator_base12 { // store links to container proxy, next iterator @@ -1091,7 +1099,7 @@ public: _Adopt(_Right._Myproxy->_Mycont); } else { // becoming invalid, disown current parent #if _ITERATOR_DEBUG_LEVEL == 2 - _Orphan_me(); + _Orphan_me_v2(); #else // _ITERATOR_DEBUG_LEVEL == 2 _Myproxy = nullptr; #endif // _ITERATOR_DEBUG_LEVEL == 2 @@ -1102,7 +1110,7 @@ public: #if _ITERATOR_DEBUG_LEVEL == 2 _CONSTEXPR20_CONTAINER ~_Iterator_base12() noexcept { - _Orphan_me(); + _Orphan_me_v2(); } _CONSTEXPR20_CONTAINER void _Adopt(const _Container_base12* _Parent) noexcept { @@ -1119,11 +1127,11 @@ public: } } } else { // no future parent, just disown current parent - _Orphan_me(); + _Orphan_me_v2(); } } - _CONSTEXPR20_CONTAINER void _Orphan_me() noexcept { + _CONSTEXPR20_CONTAINER void _Orphan_me_v2() noexcept { if (_Myproxy) { // adopted, remove self from list #ifdef __cpp_lib_is_constant_evaluated if (_STD is_constant_evaluated()) { @@ -1197,11 +1205,6 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all_unlocked() noexcept { _Myproxy->_Myfirstiter = nullptr; } -inline void _Container_base12::_Orphan_all_locked() noexcept { - _Lockit _Lock(_LOCK_DEBUG); - _Orphan_all_unlocked(); -} - _CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 if (_Myproxy) { // proxy allocated, drain it @@ -1231,15 +1234,8 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators_unlocke } } -inline void _Container_base12::_Swap_proxy_and_iterators_locked(_Container_base12& _Right) noexcept { - _Lockit _Lock(_LOCK_DEBUG); - _Swap_proxy_and_iterators_unlocked(_Right); -} - _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { -#if _ITERATOR_DEBUG_LEVEL != 2 - _Swap_proxy_and_iterators_unlocked(_Right); -#else // ^^^ _ITERATOR_DEBUG_LEVEL != 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL == 2 vvv +#if _ITERATOR_DEBUG_LEVEL == 2 #ifdef __cpp_lib_is_constant_evaluated if (_STD is_constant_evaluated()) { _Swap_proxy_and_iterators_unlocked(_Right); @@ -1248,7 +1244,9 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators(_Contai { _Swap_proxy_and_iterators_locked(_Right); } -#endif // _ITERATOR_DEBUG_LEVEL == 2 +#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL != 2 vvv + _Swap_proxy_and_iterators_unlocked(_Right); +#endif // _ITERATOR_DEBUG_LEVEL != 2 } #if _ITERATOR_DEBUG_LEVEL == 0 diff --git a/stl/inc/xutility b/stl/inc/xutility index 56b05526b87..2264dfb0a0f 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -155,7 +155,7 @@ _CONSTEXPR20_DYNALLOC void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noe // FUNCTION TEMPLATE _Default_construct_in_place template -_CONSTEXPR20_DYNALLOC void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { +void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty; } From 3000309ec78683a2d7f8495dd0e1c2f1ce528d3a Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 22 Jan 2021 08:45:03 +0100 Subject: [PATCH 05/74] Unblock __cpp_lib_constexpr_dynamic_alloc for all compilers that suppport constexpr allocations --- stl/inc/xmemory | 2 +- stl/inc/yvals_core.h | 5 ++--- .../VSO_0157762_feature_test_macros/test.compile.pass.cpp | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 61872788623..e8fcb9f4397 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1274,7 +1274,7 @@ struct _Fake_proxy_ptr_impl { // fake replacement for a container proxy smart po struct _Basic_container_proxy_ptr12 { // smart pointer components for a _Container_proxy * that don't depend on the allocator - _Container_proxy* _Ptr; + _Container_proxy* _Ptr = nullptr; constexpr void _Release() noexcept { // disengage this _Basic_container_proxy_ptr12 _Ptr = nullptr; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index b5d3d18f968..72b2d93e095 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1183,10 +1183,9 @@ #define __cpp_lib_constexpr_algorithms 201806L #define __cpp_lib_constexpr_complex 201711L -#if defined(__cpp_constexpr_dynamic_alloc) \ - && defined(__clang__) // TRANSITION, MSVC support for constexpr dynamic allocation +#ifdef __cpp_constexpr_dynamic_alloc #define __cpp_lib_constexpr_dynamic_alloc 201907L -#endif // defined(__cpp_constexpr_dynamic_alloc) && defined(__clang__) +#endif // __cpp_constexpr_dynamic_alloc #define __cpp_lib_constexpr_functional 201907L #define __cpp_lib_constexpr_iterator 201811L diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 9a6cd10c972..1aa7807505b 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -411,8 +411,7 @@ STATIC_ASSERT(__cpp_lib_constexpr_complex == 201711L); #endif #endif -#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) \ - && defined(__clang__) // TRANSITION, MSVC support for constexpr dynamic allocation +#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) #ifndef __cpp_lib_constexpr_dynamic_alloc #error __cpp_lib_constexpr_dynamic_alloc is not defined #elif __cpp_lib_constexpr_dynamic_alloc != 201907L From 593de17cd32036309f3a011d3a79c6e22e50f102 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 22 Jan 2021 12:25:32 +0100 Subject: [PATCH 06/74] Unskip some tests --- tests/libcxx/expected_results.txt | 9 --------- tests/libcxx/skipped_tests.txt | 9 --------- 2 files changed, 18 deletions(-) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 8961a1cc341..fbcaa710309 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -493,18 +493,9 @@ std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp FAIL std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp FAIL # C++20 P0784R7 "More constexpr containers" -std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp:0 FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp:0 FAIL std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp:0 FAIL std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp:0 FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp:0 FAIL -std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp:0 FAIL std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp:0 FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp:0 FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp:0 FAIL # C++20 P0896R4 "" std/language.support/support.limits/support.limits.general/algorithm.version.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 61b46acc242..91eeaae1370 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -493,18 +493,9 @@ utilities\variant\variant.variant\variant.ctor\conv.pass.cpp utilities\variant\variant.variant\variant.ctor\T.pass.cpp # C++20 P0784R7 "More constexpr containers" -utilities\memory\allocator.traits\allocator.traits.members\allocate.pass.cpp -utilities\memory\allocator.traits\allocator.traits.members\allocate_hint.pass.cpp utilities\memory\allocator.traits\allocator.traits.members\construct.pass.cpp -utilities\memory\allocator.traits\allocator.traits.members\deallocate.pass.cpp utilities\memory\allocator.traits\allocator.traits.members\destroy.pass.cpp -utilities\memory\allocator.traits\allocator.traits.members\max_size.pass.cpp -utilities\memory\allocator.traits\allocator.traits.members\select_on_container_copy_construction.pass.cpp -utilities\memory\default.allocator\allocator.globals\eq.pass.cpp utilities\memory\specialized.algorithms\specialized.construct\construct_at.pass.cpp -utilities\memory\specialized.algorithms\specialized.destroy\destroy.pass.cpp -utilities\memory\specialized.algorithms\specialized.destroy\destroy_at.pass.cpp -utilities\memory\specialized.algorithms\specialized.destroy\destroy_n.pass.cpp # C++20 P0896R4 "" language.support\support.limits\support.limits.general\algorithm.version.pass.cpp From 5e56275e5081524129ef089e1ed0917cae3f07c6 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 22 Jan 2021 12:34:18 +0100 Subject: [PATCH 07/74] Consistently use __cpp_lib_constexpr_dynamic_alloc --- stl/inc/xmemory | 44 ++++++++++++++++++++++---------------------- stl/inc/xutility | 4 ++-- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index e8fcb9f4397..58823353f0a 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1117,11 +1117,11 @@ public: if (_Parent) { // have a parent, do adoption _Container_proxy* _Parent_proxy = _Parent->_Myproxy; if (_Myproxy != _Parent_proxy) { // change parentage -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _Adopt_unlocked(_Parent_proxy); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Adopt_locked(_Parent_proxy); } @@ -1133,11 +1133,11 @@ public: _CONSTEXPR20_CONTAINER void _Orphan_me_v2() noexcept { if (_Myproxy) { // adopted, remove self from list -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _Orphan_me_unlocked(); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Orphan_me_locked(); } @@ -1208,11 +1208,11 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all_unlocked() noexcept { _CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 if (_Myproxy) { // proxy allocated, drain it -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _Orphan_all_unlocked(); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Orphan_all_locked(); } @@ -1236,11 +1236,11 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators_unlocke _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _Swap_proxy_and_iterators_unlocked(_Right); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Swap_proxy_and_iterators_locked(_Right); } @@ -1492,9 +1492,9 @@ _CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_move_unchecked( _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // move [_First, _Last) to raw [_Dest, ...) if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { return _Copy_memmove(_First, _Last, _Dest); } @@ -1554,9 +1554,9 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_copy( if constexpr (conjunction_v::_Really_trivial>, _Uses_default_construct<_Alloc, _Ptrval, decltype(*_UFirst)>>) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); _Dest += _ULast - _UFirst; @@ -1579,9 +1579,9 @@ _CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_copy_unchecked( _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // copy [_First, _Last) to raw [_Dest, ...) if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { return _Copy_memmove(_First, _Last, _Dest); } @@ -1618,9 +1618,9 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_move( const auto _ULast = _Get_unwrapped(_Last); if constexpr (conjunction_v::_Really_trivial>, _Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>>) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); return _Dest + (_ULast - _UFirst); @@ -1641,17 +1641,17 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( // copy _Count copies of _Val to raw _First, using _Al using _Ty = typename _Alloc::value_type; if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Fill_memset(_Unfancy(_First), _Val, static_cast(_Count)); return _First + _Count; } } else if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_Unfancy(_First), static_cast(_Count)); @@ -1713,9 +1713,9 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( // value-initialize _Count objects to raw _First, using _Al using _Ptrty = typename _Alloc::value_type*; if constexpr (_Use_memset_value_construct_v<_Ptrty> && _Uses_default_construct<_Alloc, _Ptrty>::value) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { auto _PFirst = _Unfancy(_First); _Zero_range(_PFirst, _PFirst + _Count); diff --git a/stl/inc/xutility b/stl/inc/xutility index 2264dfb0a0f..8c223caa7a9 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -143,11 +143,11 @@ _CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) template _CONSTEXPR20_DYNALLOC void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept( is_nothrow_constructible_v<_Ty, _Types...>) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _STD construct_at(_STD addressof(_Obj), _STD forward<_Types>(_Args)...); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); } From ed8c2dc303af03661793a9510cbcd8631eec17fa Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 22 Jan 2021 13:59:30 +0100 Subject: [PATCH 08/74] Properly guard ranges in tests --- .../test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 52da34b9f96..08a4de3ae07 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -244,9 +244,11 @@ constexpr void test_compiletime() { assert(s.object == 42); destroy_at(&s.object); +#ifdef __cpp_lib_concepts ranges::construct_at(&s.object, 1729); assert(s.object == 1729); ranges::destroy_at(&s.object); +#endif // __cpp_lib_concepts } struct nontrivial { @@ -262,9 +264,11 @@ constexpr void test_compiletime() { assert(s.object.x == 42); destroy_at(&s.object); +#ifdef __cpp_lib_concepts ranges::construct_at(&s.object, 1729); assert(s.object.x == 1729); ranges::destroy_at(&s.object); +#endif // __cpp_lib_concepts } } static_assert((test_compiletime(), true)); From 5d393af304c37fb83bda7d7f2509495f60557037 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Wed, 27 Jan 2021 11:43:24 -0800 Subject: [PATCH 09/74] Disable portions of P0784 test for EDG due to bugs --- .../test.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 08a4de3ae07..33a9fd23026 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -227,6 +227,7 @@ void test_array(const T& val) { } #ifdef __cpp_lib_constexpr_dynamic_alloc +#ifndef __EDG__ // TRANSITION, VSO-1269976 template struct storage_for { union { @@ -272,6 +273,7 @@ constexpr void test_compiletime() { } } static_assert((test_compiletime(), true)); +#endif // __EDG__ template struct A { @@ -289,7 +291,9 @@ struct nontrivial_A { constexpr ~nontrivial_A() {} }; + constexpr void test_compiletime_destroy_variants() { +#ifndef __EDG__ // TRANSITION, VSO-1270011 { allocator> alloc{}; A* a = alloc.allocate(10); @@ -308,6 +312,7 @@ constexpr void test_compiletime_destroy_variants() { destroy(a, a + 10); alloc.deallocate(a, 10); } +#endif // __EDG__ #ifdef __cpp_lib_concepts { allocator> alloc{}; @@ -389,6 +394,7 @@ constexpr void test_compiletime_destroy_variants() { } static_assert((test_compiletime_destroy_variants(), true)); +#ifndef __EDG__ // TRANSITION, VSO-1269976 template struct Alloc { using value_type = T; @@ -502,6 +508,7 @@ constexpr void test_compiletime_allocator_traits() { } } static_assert((test_compiletime_allocator_traits(), true)); +#endif // __EDG__ constexpr void test_compiletime_allocator() { { From b3140a49ab7fd679d55efc43862da517ad671fac Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 29 Jan 2021 07:03:29 +0100 Subject: [PATCH 10/74] Try to apply workaround --- stl/inc/xmemory | 3 ++- .../test.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 58823353f0a..082cae0c57b 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1182,7 +1182,8 @@ private: _CONSTEXPR20_CONTAINER void _Orphan_me_unlocked() noexcept { _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; while (*_Pnext && *_Pnext != this) { - _Pnext = &(*_Pnext)->_Mynextiter; + const auto _Temp = *_Pnext; // TRANSITION: ASO-XXXXX + _Pnext = &_Temp->_Mynextiter; } _STL_VERIFY(*_Pnext, "ITERATOR LIST CORRUPTED!"); diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 33a9fd23026..7939af14b21 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -291,7 +291,6 @@ struct nontrivial_A { constexpr ~nontrivial_A() {} }; - constexpr void test_compiletime_destroy_variants() { #ifndef __EDG__ // TRANSITION, VSO-1270011 { From 09b3acf2a6c35f79d773c8847fbfa2a4ee3203fa Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 29 Jan 2021 12:33:13 +0100 Subject: [PATCH 11/74] [P0980R1] Implement constexpr string --- stl/inc/xstring | 1256 ++++++++----- stl/inc/yvals_core.h | 14 +- tests/std/include/test_death.hpp | 7 + tests/std/test.lst | 1 + .../tests/P0980R1_constexpr_strings/env.lst | 4 + .../tests/P0980R1_constexpr_strings/test.cpp | 1614 +++++++++++++++++ 6 files changed, 2450 insertions(+), 446 deletions(-) create mode 100644 tests/std/tests/P0980R1_constexpr_strings/env.lst create mode 100644 tests/std/tests/P0980R1_constexpr_strings/test.cpp diff --git a/stl/inc/xstring b/stl/inc/xstring index 80355987c2c..afe098d1dba 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -67,8 +67,8 @@ struct _Char_traits { // properties of a string or stream element _Pre_satisfies_(_Dest_size >= _Count) static _CONSTEXPR20 _Elem* _Copy_s(_Out_writes_all_(_Dest_size) _Elem* const _First1, - const size_t _Dest_size, _In_reads_(_Count) const _Elem* const _First2, - const size_t _Count) noexcept { // copy [_First2, _First2 + _Count) to [_First1, _First1 + _Dest_size) + const size_t _Dest_size, _In_reads_(_Count) const _Elem* const _First2, const size_t _Count) noexcept { + // copy [_First2, _First2 + _Count) to [_First1, _First1 + _Dest_size) _STL_VERIFY(_Count <= _Dest_size, "invalid argument"); return copy(_First1, _First2, _Count); } @@ -161,11 +161,17 @@ struct _Char_traits { // properties of a string or stream element } static _CONSTEXPR20 _Elem* assign( - _Out_writes_all_(_Count) _Elem* const _First, size_t _Count, const _Elem _Ch) noexcept - /* strengthened */ { + _Out_writes_all_(_Count) _Elem* const _First, size_t _Count, const _Elem _Ch) noexcept /* strengthened */ { // assign _Count * _Ch to [_First, ...) for (_Elem* _Next = _First; _Count > 0; --_Count, ++_Next) { - *_Next = _Ch; +#ifdef __cpp_lib_constexpr_string + if (_STD is_constant_evaluated()) { + _STD construct_at(_Next, _Ch); + } else +#endif // __cpp_lib_constexpr_string + { + *_Next = _Ch; + } } return _First; @@ -1841,98 +1847,120 @@ public: using pointer = typename _Mystr::const_pointer; using reference = const value_type&; - _String_const_iterator() noexcept : _Ptr() {} + _CONSTEXPR20_CONTAINER _String_const_iterator() noexcept : _Ptr() {} - _String_const_iterator(pointer _Parg, const _Container_base* _Pstring) noexcept : _Ptr(_Parg) { + _CONSTEXPR20_CONTAINER _String_const_iterator(pointer _Parg, const _Container_base* _Pstring) noexcept + : _Ptr(_Parg) { this->_Adopt(_Pstring); } - _NODISCARD reference operator*() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER reference operator*() const noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 - _STL_VERIFY(_Ptr, "cannot dereference value-initialized string iterator"); - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Mycont, "cannot dereference string iterator because the iterator was" - " invalidated (e.g. reallocation occurred, or the string was destroyed)"); - const auto _Contptr = _Mycont->_Myptr(); - const auto _Rawptr = _Unfancy(_Ptr); - _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr < _Contptr + _Mycont->_Mysize, - "cannot dereference string iterator because it is out of range (e.g. an end iterator)"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Ptr, "cannot dereference value-initialized string iterator"); + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Mycont, "cannot dereference string iterator because the iterator was" + " invalidated (e.g. reallocation occurred, or the string was destroyed)"); + const auto _Contptr = _Mycont->_Myptr(); + const auto _Rawptr = _Unfancy(_Ptr); + _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr < _Contptr + _Mycont->_Mysize, + "cannot dereference string iterator because it is out of range (e.g. an end iterator)"); + } #endif // _ITERATOR_DEBUG_LEVEL >= 1 _Analysis_assume_(_Ptr); return *_Ptr; } - _NODISCARD pointer operator->() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER pointer operator->() const noexcept { return pointer_traits::pointer_to(**this); } - _String_const_iterator& operator++() noexcept { + _CONSTEXPR20_CONTAINER _String_const_iterator& operator++() noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 - _STL_VERIFY(_Ptr, "cannot increment value-initialized string iterator"); - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Mycont, "cannot increment string iterator because the iterator was" - " invalidated (e.g. reallocation occurred, or the string was destroyed)"); - _STL_VERIFY(_Unfancy(_Ptr) < _Mycont->_Myptr() + _Mycont->_Mysize, "cannot increment string iterator past end"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Ptr, "cannot increment value-initialized string iterator"); + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Mycont, "cannot increment string iterator because the iterator was" + " invalidated (e.g. reallocation occurred, or the string was destroyed)"); + _STL_VERIFY( + _Unfancy(_Ptr) < _Mycont->_Myptr() + _Mycont->_Mysize, "cannot increment string iterator past end"); + } #endif // _ITERATOR_DEBUG_LEVEL >= 1 ++_Ptr; return *this; } - _String_const_iterator operator++(int) noexcept { + _CONSTEXPR20_CONTAINER _String_const_iterator operator++(int) noexcept { _String_const_iterator _Tmp = *this; ++*this; return _Tmp; } - _String_const_iterator& operator--() noexcept { + _CONSTEXPR20_CONTAINER _String_const_iterator& operator--() noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 - _STL_VERIFY(_Ptr, "cannot decrement value-initialized string iterator"); - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Mycont, "cannot decrement string iterator because the iterator was" - " invalidated (e.g. reallocation occurred, or the string was destroyed)"); - _STL_VERIFY(_Mycont->_Myptr() < _Unfancy(_Ptr), "cannot decrement string iterator before begin"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Ptr, "cannot decrement value-initialized string iterator"); + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Mycont, "cannot decrement string iterator because the iterator was" + " invalidated (e.g. reallocation occurred, or the string was destroyed)"); + _STL_VERIFY(_Mycont->_Myptr() < _Unfancy(_Ptr), "cannot decrement string iterator before begin"); + } #endif // _ITERATOR_DEBUG_LEVEL >= 1 --_Ptr; return *this; } - _String_const_iterator operator--(int) noexcept { + _CONSTEXPR20_CONTAINER _String_const_iterator operator--(int) noexcept { _String_const_iterator _Tmp = *this; --*this; return _Tmp; } - void _Verify_offset(const difference_type _Off) const noexcept { + _CONSTEXPR20_CONTAINER void _Verify_offset(const difference_type _Off) const noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 if (_Off == 0) { return; } - _STL_ASSERT(_Ptr, "cannot seek value-initialized string iterator"); - const auto _Mycont = static_cast(this->_Getcont()); - _STL_ASSERT(_Mycont, "cannot seek string iterator because the iterator was" - " invalidated (e.g. reallocation occurred, or the string was destroyed)"); - const auto _Contptr = _Mycont->_Myptr(); - const auto _Rawptr = _Unfancy(_Ptr); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_ASSERT(_Ptr, "cannot seek value-initialized string iterator"); + const auto _Mycont = static_cast(this->_Getcont()); + _STL_ASSERT(_Mycont, "cannot seek string iterator because the iterator was" + " invalidated (e.g. reallocation occurred, or the string was destroyed)"); + const auto _Contptr = _Mycont->_Myptr(); + const auto _Rawptr = _Unfancy(_Ptr); - if (_Off < 0) { - _STL_VERIFY(_Contptr - _Rawptr <= _Off, "cannot seek string iterator before begin"); - } + if (_Off < 0) { + _STL_VERIFY(_Contptr - _Rawptr <= _Off, "cannot seek string iterator before begin"); + } - if (_Off > 0) { - using _Size_type = typename _Mystr::size_type; - const auto _Left = _Mycont->_Mysize - static_cast<_Size_type>(_Rawptr - _Contptr); - _STL_VERIFY(static_cast<_Size_type>(_Off) <= _Left, "cannot seek string iterator after end"); + if (_Off > 0) { + using _Size_type = typename _Mystr::size_type; + const auto _Left = _Mycont->_Mysize - static_cast<_Size_type>(_Rawptr - _Contptr); + _STL_VERIFY(static_cast<_Size_type>(_Off) <= _Left, "cannot seek string iterator after end"); + } } #else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv (void) _Off; #endif // _ITERATOR_DEBUG_LEVEL >= 1 } - _String_const_iterator& operator+=(const difference_type _Off) noexcept { + _CONSTEXPR20_CONTAINER _String_const_iterator& operator+=(const difference_type _Off) noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 _Verify_offset(_Off); #endif // _ITERATOR_DEBUG_LEVEL >= 1 @@ -1940,78 +1968,91 @@ public: return *this; } - _NODISCARD _String_const_iterator operator+(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER _String_const_iterator operator+(const difference_type _Off) const noexcept { _String_const_iterator _Tmp = *this; return _Tmp += _Off; } - _String_const_iterator& operator-=(const difference_type _Off) noexcept { + _CONSTEXPR20_CONTAINER _String_const_iterator& operator-=(const difference_type _Off) noexcept { return *this += -_Off; } - _NODISCARD _String_const_iterator operator-(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER _String_const_iterator operator-(const difference_type _Off) const noexcept { _String_const_iterator _Tmp = *this; return _Tmp -= _Off; } - _NODISCARD difference_type operator-(const _String_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER difference_type operator-(const _String_const_iterator& _Right) const noexcept { _Compat(_Right); return _Ptr - _Right._Ptr; } - _NODISCARD reference operator[](const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER reference operator[](const difference_type _Off) const noexcept { return *(*this + _Off); } - _NODISCARD bool operator==(const _String_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool operator==(const _String_const_iterator& _Right) const noexcept { _Compat(_Right); return _Ptr == _Right._Ptr; } - _NODISCARD bool operator!=(const _String_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool operator!=(const _String_const_iterator& _Right) const noexcept { return !(*this == _Right); } - _NODISCARD bool operator<(const _String_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool operator<(const _String_const_iterator& _Right) const noexcept { _Compat(_Right); return _Ptr < _Right._Ptr; } - _NODISCARD bool operator>(const _String_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool operator>(const _String_const_iterator& _Right) const noexcept { return _Right < *this; } - _NODISCARD bool operator<=(const _String_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool operator<=(const _String_const_iterator& _Right) const noexcept { return !(_Right < *this); } - _NODISCARD bool operator>=(const _String_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool operator>=(const _String_const_iterator& _Right) const noexcept { return !(*this < _Right); } - void _Compat(const _String_const_iterator& _Right) const noexcept { // test for compatible iterator pair + _CONSTEXPR20_CONTAINER void _Compat(const _String_const_iterator& _Right) const noexcept { + // test for compatible iterator pair #if _ITERATOR_DEBUG_LEVEL >= 1 - _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "string iterators incompatible (e.g." - " point to different string instances)"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "string iterators incompatible (e.g." + " point to different string instances)"); + } #else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv (void) _Right; #endif // _ITERATOR_DEBUG_LEVEL } #if _ITERATOR_DEBUG_LEVEL >= 1 - friend void _Verify_range(const _String_const_iterator& _First, const _String_const_iterator& _Last) noexcept { - _STL_VERIFY(_First._Getcont() == _Last._Getcont(), "string iterators in range are from different containers"); - _STL_VERIFY(_First._Ptr <= _Last._Ptr, "string iterator range transposed"); + friend _CONSTEXPR20_CONTAINER void _Verify_range( + const _String_const_iterator& _First, const _String_const_iterator& _Last) noexcept { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY( + _First._Getcont() == _Last._Getcont(), "string iterators in range are from different containers"); + _STL_VERIFY(_First._Ptr <= _Last._Ptr, "string iterator range transposed"); + } } #endif // _ITERATOR_DEBUG_LEVEL >= 1 using _Prevent_inheriting_unwrap = _String_const_iterator; - _NODISCARD const value_type* _Unwrapped() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const value_type* _Unwrapped() const noexcept { return _Unfancy(_Ptr); } - void _Seek_to(const value_type* _It) noexcept { + _CONSTEXPR20_CONTAINER void _Seek_to(const value_type* _It) noexcept { _Ptr = _Refancy(const_cast(_It)); } @@ -2033,20 +2074,32 @@ struct pointer_traits<_String_const_iterator<_Mystr>> { _NODISCARD static constexpr element_type* to_address(const pointer _Iter) noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 - const auto _Mycont = static_cast(_Iter._Getcont()); - if (!_Mycont) { - _STL_VERIFY(!_Iter._Ptr, "cannot convert string iterator to pointer because the iterator was invalidated " - "(e.g. reallocation occurred, or the string was destroyed)"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Mycont = static_cast(_Iter._Getcont()); + if (!_Mycont) { + _STL_VERIFY(!_Iter._Ptr, + "cannot convert string iterator to pointer because the iterator was invalidated " + "(e.g. reallocation occurred, or the string was destroyed)"); + } } #endif // _ITERATOR_DEBUG_LEVEL >= 1 const auto _Rawptr = _STD to_address(_Iter._Ptr); #if _ITERATOR_DEBUG_LEVEL >= 1 - if (_Mycont) { - const auto _Contptr = _Mycont->_Myptr(); - _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr <= _Contptr + _Mycont->_Mysize, - "cannot convert string iterator to pointer because it is out of range"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Mycont = static_cast(_Iter._Getcont()); + if (_Mycont) { + const auto _Contptr = _Mycont->_Myptr(); + _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr <= _Contptr + _Mycont->_Mysize, + "cannot convert string iterator to pointer because it is out of range"); + } } #endif // _ITERATOR_DEBUG_LEVEL >= 1 @@ -2072,71 +2125,71 @@ public: using _Mybase::_Mybase; - _NODISCARD reference operator*() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER reference operator*() const noexcept { return const_cast(_Mybase::operator*()); } - _NODISCARD pointer operator->() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER pointer operator->() const noexcept { return pointer_traits::pointer_to(**this); } - _String_iterator& operator++() noexcept { + _CONSTEXPR20_CONTAINER _String_iterator& operator++() noexcept { _Mybase::operator++(); return *this; } - _String_iterator operator++(int) noexcept { + _CONSTEXPR20_CONTAINER _String_iterator operator++(int) noexcept { _String_iterator _Tmp = *this; _Mybase::operator++(); return _Tmp; } - _String_iterator& operator--() noexcept { + _CONSTEXPR20_CONTAINER _String_iterator& operator--() noexcept { _Mybase::operator--(); return *this; } - _String_iterator operator--(int) noexcept { + _CONSTEXPR20_CONTAINER _String_iterator operator--(int) noexcept { _String_iterator _Tmp = *this; _Mybase::operator--(); return _Tmp; } - _String_iterator& operator+=(const difference_type _Off) noexcept { + _CONSTEXPR20_CONTAINER _String_iterator& operator+=(const difference_type _Off) noexcept { _Mybase::operator+=(_Off); return *this; } - _NODISCARD _String_iterator operator+(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER _String_iterator operator+(const difference_type _Off) const noexcept { _String_iterator _Tmp = *this; return _Tmp += _Off; } - _String_iterator& operator-=(const difference_type _Off) noexcept { + _CONSTEXPR20_CONTAINER _String_iterator& operator-=(const difference_type _Off) noexcept { _Mybase::operator-=(_Off); return *this; } using _Mybase::operator-; - _NODISCARD _String_iterator operator-(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER _String_iterator operator-(const difference_type _Off) const noexcept { _String_iterator _Tmp = *this; return _Tmp -= _Off; } - _NODISCARD reference operator[](const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER reference operator[](const difference_type _Off) const noexcept { return const_cast(_Mybase::operator[](_Off)); } using _Prevent_inheriting_unwrap = _String_iterator; - _NODISCARD value_type* _Unwrapped() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER value_type* _Unwrapped() const noexcept { return const_cast(_Unfancy(this->_Ptr)); } }; template -_NODISCARD _String_iterator<_Mystr> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER _String_iterator<_Mystr> operator+( typename _String_iterator<_Mystr>::difference_type _Off, _String_iterator<_Mystr> _Next) noexcept { return _Next += _Off; } @@ -2195,7 +2248,7 @@ public: using reference = value_type&; using const_reference = const value_type&; - _String_val() noexcept : _Bx(), _Mysize(0), _Myres(0) {} + _CONSTEXPR20_CONTAINER _String_val() noexcept : _Bx(), _Mysize{0}, _Myres{0} {} // length of internal buffer, [1, 16]: static constexpr size_type _BUF_SIZE = 16 / sizeof(value_type) < 1 ? 1 : 16 / sizeof(value_type); @@ -2206,7 +2259,7 @@ public: : sizeof(value_type) <= 8 ? 1 : 0; - value_type* _Myptr() noexcept { + _CONSTEXPR20_CONTAINER value_type* _Myptr() noexcept { value_type* _Result = _Bx._Buf; if (_Large_string_engaged()) { _Result = _Unfancy(_Bx._Ptr); @@ -2215,7 +2268,7 @@ public: return _Result; } - const value_type* _Myptr() const noexcept { + _CONSTEXPR20_CONTAINER const value_type* _Myptr() const noexcept { const value_type* _Result = _Bx._Buf; if (_Large_string_engaged()) { _Result = _Unfancy(_Bx._Ptr); @@ -2224,17 +2277,24 @@ public: return _Result; } - bool _Large_string_engaged() const noexcept { + _CONSTEXPR20_CONTAINER bool _Large_string_engaged() const noexcept { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return true; + } +#endif // __cpp_lib_is_constant_evaluated return _BUF_SIZE <= _Myres; } - void _Check_offset(const size_type _Off) const { // checks whether _Off is in the bounds of [0, size()] + _CONSTEXPR20_CONTAINER void _Check_offset(const size_type _Off) const { + // checks whether _Off is in the bounds of [0, size()] if (_Mysize < _Off) { _Xran(); } } - void _Check_offset_exclusive(const size_type _Off) const { // checks whether _Off is in the bounds of [0, size()) + _CONSTEXPR20_CONTAINER void _Check_offset_exclusive(const size_type _Off) const { + // checks whether _Off is in the bounds of [0, size()) if (_Mysize <= _Off) { _Xran(); } @@ -2244,15 +2304,15 @@ public: _Xout_of_range("invalid string position"); } - size_type _Clamp_suffix_size(const size_type _Off, const size_type _Size) const noexcept { + _CONSTEXPR20_CONTAINER size_type _Clamp_suffix_size(const size_type _Off, const size_type _Size) const noexcept { // trims _Size to the longest it can be assuming a string at/after _Off return (_STD min)(_Size, _Mysize - _Off); } union _Bxty { // storage for small buffer or pointer to larger one - _Bxty() noexcept {} // user-provided, for fancy pointers + _CONSTEXPR20_CONTAINER _Bxty() noexcept : _Ptr() {} // user-provided, for fancy pointers - ~_Bxty() noexcept {} // user-provided, for fancy pointers + _CONSTEXPR20_CONTAINER ~_Bxty() noexcept {} // user-provided, for fancy pointers value_type _Buf[_BUF_SIZE]; pointer _Ptr; @@ -2354,7 +2414,7 @@ private: #endif // _HAS_CXX17 public: - basic_string(const basic_string& _Right) + _CONSTEXPR20_CONTAINER basic_string(const basic_string& _Right) : _Mypair(_One_then_variadic_args_t{}, _Alty_traits::select_on_container_copy_construction(_Right._Getal())) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); @@ -2362,24 +2422,27 @@ public: _Proxy._Release(); } - basic_string(const basic_string& _Right, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { + _CONSTEXPR20_CONTAINER basic_string(const basic_string& _Right, const _Alloc& _Al) + : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); _Construct_lv_contents(_Right); _Proxy._Release(); } - basic_string() noexcept(is_nothrow_default_constructible_v<_Alty>) : _Mypair(_Zero_then_variadic_args_t{}) { + _CONSTEXPR20_CONTAINER basic_string() noexcept(is_nothrow_default_constructible_v<_Alty>) + : _Mypair(_Zero_then_variadic_args_t{}) { _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); _Tidy_init(); } - explicit basic_string(const _Alloc& _Al) noexcept : _Mypair(_One_then_variadic_args_t{}, _Al) { + _CONSTEXPR20_CONTAINER explicit basic_string(const _Alloc& _Al) noexcept + : _Mypair(_One_then_variadic_args_t{}, _Al) { _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); _Tidy_init(); } - basic_string(const basic_string& _Right, const size_type _Roff, const _Alloc& _Al = _Alloc()) + _CONSTEXPR20_CONTAINER basic_string(const basic_string& _Right, const size_type _Roff, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { // construct from _Right [_Roff, ) auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); @@ -2388,7 +2451,7 @@ public: _Proxy._Release(); } - basic_string( + _CONSTEXPR20_CONTAINER basic_string( const basic_string& _Right, const size_type _Roff, const size_type _Count, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { // construct from _Right [_Roff, _Roff + _Count) auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); @@ -2398,7 +2461,8 @@ public: _Proxy._Release(); } - basic_string(_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) + _CONSTEXPR20_CONTAINER basic_string( + _In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) : _Mypair(_Zero_then_variadic_args_t{}) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); @@ -2407,7 +2471,7 @@ public: _Proxy._Release(); } - basic_string( + _CONSTEXPR20_CONTAINER basic_string( _In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); @@ -2417,7 +2481,7 @@ public: _Proxy._Release(); } - basic_string(_In_z_ const _Elem* const _Ptr) : _Mypair(_Zero_then_variadic_args_t{}) { + _CONSTEXPR20_CONTAINER basic_string(_In_z_ const _Elem* const _Ptr) : _Mypair(_Zero_then_variadic_args_t{}) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); _Tidy_init(); @@ -2428,7 +2492,8 @@ public: #if _HAS_CXX17 template ::value, int> = 0> #endif // _HAS_CXX17 - basic_string(_In_z_ const _Elem* const _Ptr, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { + _CONSTEXPR20_CONTAINER basic_string(_In_z_ const _Elem* const _Ptr, const _Alloc& _Al) + : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); _Tidy_init(); @@ -2436,7 +2501,8 @@ public: _Proxy._Release(); } - basic_string(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) : _Mypair(_Zero_then_variadic_args_t{}) { + _CONSTEXPR20_CONTAINER basic_string(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) + : _Mypair(_Zero_then_variadic_args_t{}) { // construct from _Count * _Ch auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); @@ -2448,7 +2514,7 @@ public: #if _HAS_CXX17 template ::value, int> = 0> #endif // _HAS_CXX17 - basic_string(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch, const _Alloc& _Al) + _CONSTEXPR20_CONTAINER basic_string(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { // construct from _Count * _Ch with allocator auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); @@ -2458,7 +2524,8 @@ public: } template , int> = 0> - basic_string(_Iter _First, _Iter _Last, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { + _CONSTEXPR20_CONTAINER basic_string(_Iter _First, _Iter _Last, const _Alloc& _Al = _Alloc()) + : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); _Tidy_init(); @@ -2468,7 +2535,7 @@ public: } template - void _Construct(_Iter _First, const _Iter _Last, input_iterator_tag) { + _CONSTEXPR20_CONTAINER void _Construct(_Iter _First, const _Iter _Last, input_iterator_tag) { // initialize from [_First, _Last), input iterators _Tidy_deallocate_guard _Guard{this}; for (; _First != _Last; ++_First) { @@ -2479,33 +2546,42 @@ public: } template - void _Construct(const _Iter _First, const _Iter _Last, forward_iterator_tag) { + _CONSTEXPR20_CONTAINER void _Construct(const _Iter _First, const _Iter _Last, forward_iterator_tag) { // initialize from [_First, _Last), forward iterators const size_type _Count = _Convert_size(static_cast(_STD distance(_First, _Last))); reserve(_Count); _Construct(_First, _Last, input_iterator_tag{}); } - void _Construct(_Elem* const _First, _Elem* const _Last, random_access_iterator_tag) { + _CONSTEXPR20_CONTAINER void _Construct(_Elem* const _First, _Elem* const _Last, random_access_iterator_tag) { // initialize from [_First, _Last), pointers if (_First != _Last) { assign(_First, _Convert_size(static_cast(_Last - _First))); } } - void _Construct(const _Elem* const _First, const _Elem* const _Last, random_access_iterator_tag) { + _CONSTEXPR20_CONTAINER void _Construct( + const _Elem* const _First, const _Elem* const _Last, random_access_iterator_tag) { // initialize from [_First, _Last), const pointers if (_First != _Last) { assign(_First, _Convert_size(static_cast(_Last - _First))); } } - basic_string(basic_string&& _Right) noexcept : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { + _CONSTEXPR20_CONTAINER basic_string(basic_string&& _Right) noexcept + : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); - _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Take_contents(_Right, bool_constant{}); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); + } } - basic_string(basic_string&& _Right, const _Alloc& _Al) noexcept( + _CONSTEXPR20_CONTAINER basic_string(basic_string&& _Right, const _Alloc& _Al) noexcept( _Alty_traits::is_always_equal::value) // strengthened : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); @@ -2518,12 +2594,20 @@ public: } } - _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Take_contents(_Right, bool_constant{}); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); + } _Proxy._Release(); } - basic_string(_String_constructor_concat_tag, const basic_string& _Source_of_al, const _Elem* const _Left_ptr, - const size_type _Left_size, const _Elem* const _Right_ptr, const size_type _Right_size) + _CONSTEXPR20_CONTAINER basic_string(_String_constructor_concat_tag, const basic_string& _Source_of_al, + const _Elem* const _Left_ptr, const size_type _Left_size, const _Elem* const _Right_ptr, + const size_type _Right_size) : _Mypair( _One_then_variadic_args_t{}, _Alty_traits::select_on_container_copy_construction(_Source_of_al._Getal())) { _STL_INTERNAL_CHECK(_Left_size <= max_size()); @@ -2535,12 +2619,24 @@ public: _Elem* _Ptr = _My_data._Bx._Buf; auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws + 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); } +#ifdef __cpp_lib_is_constant_evaluated + else if (_STD is_constant_evaluated()) { // SSO disabled in constexpr context + const pointer _Fancyptr = _Getal().allocate(_New_capacity + 1); // throws + _Ptr = _Unfancy(_Fancyptr); + _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); + } + + if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once + _Traits::assign(_Ptr, _New_capacity + 1, _Elem()); + } +#endif // __cpp_lib_is_constant_evaluated _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; @@ -2550,7 +2646,7 @@ public: _Proxy._Release(); } - basic_string(_String_constructor_concat_tag, basic_string& _Left, basic_string& _Right) + _CONSTEXPR20_CONTAINER basic_string(_String_constructor_concat_tag, basic_string& _Left, basic_string& _Right) : _Mypair(_One_then_variadic_args_t{}, _Left._Getal()) { auto& _My_data = _Mypair._Myval2; auto& _Left_data = _Left._Mypair._Myval2; @@ -2568,7 +2664,14 @@ public: if (_Fits_in_left && _Right_capacity <= _Left_capacity) { // take _Left's buffer, max_size() is OK because _Fits_in_left _My_data._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); // throws, hereafter nothrow in this block - _Take_contents(_Left, bool_constant<_Can_memcpy_val>{}); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Take_contents(_Left, bool_constant{}); // cannot memcpy in constexpr context + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Take_contents(_Left, bool_constant<_Can_memcpy_val>{}); + } const auto _Ptr = _My_data._Myptr(); _Traits::copy(_Ptr + _Left_size, _Right_data._Myptr(), _Right_size + 1); _My_data._Mysize = _New_size; @@ -2588,7 +2691,14 @@ public: // therefore: _Right must have more than the minimum capacity, so it must be _Large_string_engaged() _STL_INTERNAL_CHECK(_Right_data._Large_string_engaged()); _My_data._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); // throws, hereafter nothrow in this block - _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Take_contents(_Right, bool_constant{}); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); + } const auto _Ptr = _Unfancy(_My_data._Bx._Ptr); _Traits::move(_Ptr + _Left_size, _Ptr, _Right_size + 1); _Traits::copy(_Ptr, _Left_data._Myptr(), _Left_size); @@ -2607,6 +2717,11 @@ public: _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws const pointer _Fancyptr = _Getal().allocate(_New_capacity + 1); // throws // nothrow hereafter +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once + _Traits::assign(_Unfancy(_Fancyptr), _New_capacity + 1, _Elem()); + } +#endif // __cpp_lib_is_constant_evaluated _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; @@ -2618,7 +2733,7 @@ public: #if _HAS_CXX17 template = 0> - explicit basic_string(const _StringViewIsh& _Right, const _Alloc& _Al = _Alloc()) + _CONSTEXPR20_CONTAINER explicit basic_string(const _StringViewIsh& _Right, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); @@ -2628,7 +2743,7 @@ public: } template = 0> - basic_string( + _CONSTEXPR20_CONTAINER basic_string( const _StringViewIsh& _Right, const size_type _Roff, const size_type _Count, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { // construct from _Right [_Roff, _Roff + _Count) using _Al auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); @@ -2648,10 +2763,17 @@ public: #endif // _HAS_CXX20 private: - void _Move_assign(basic_string& _Right, _Equal_allocators) noexcept { + _CONSTEXPR20_CONTAINER void _Move_assign(basic_string& _Right, _Equal_allocators) noexcept { _Tidy_deallocate(); _Pocma(_Getal(), _Right._Getal()); - _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Take_contents(_Right, bool_constant{}); + } else +#endif + { + _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); + } } void _Move_assign(basic_string& _Right, _Propagate_allocators) noexcept { @@ -2663,7 +2785,14 @@ private: _Mypair._Myval2._Reload_proxy( _GET_PROXY_ALLOCATOR(_Alty, _Getal()), _GET_PROXY_ALLOCATOR(_Alty, _Right._Getal())); _Pocma(_Getal(), _Right._Getal()); - _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Take_contents(_Right, bool_constant{}); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); + } } } @@ -2677,7 +2806,8 @@ private: public: #if _HAS_CXX20 - bool _Move_assign_from_buffer(_Elem* const _Right, const size_type _Size, const size_type _Res) { + _NODISCARD _CONSTEXPR20_CONTAINER bool _Move_assign_from_buffer( + _Elem* const _Right, const size_type _Size, const size_type _Res) { // Move assign from a buffer, used by basic_stringbuf; returns _Large_string_engaged() _Tidy_deallocate(); pointer _Fancy_right = _Refancy(_Right); @@ -2701,7 +2831,7 @@ public: size_type _Res; }; - _NODISCARD _Released_buffer _Release_to_buffer(_Alloc& _Al) { + _NODISCARD _CONSTEXPR20_CONTAINER _Released_buffer _Release_to_buffer(_Alloc& _Al) { // Release to a buffer, or allocate a new one if in small string mode _Released_buffer _Result; auto& _My_data = _Mypair._Myval2; @@ -2721,7 +2851,8 @@ public: } #endif // _HAS_CXX20 - basic_string& operator=(basic_string&& _Right) noexcept(noexcept(_Move_assign(_Right, _Choose_pocma<_Alty>{}))) { + _CONSTEXPR20_CONTAINER basic_string& operator=(basic_string&& _Right) noexcept( + noexcept(_Move_assign(_Right, _Choose_pocma<_Alty>{}))) { if (this != _STD addressof(_Right)) { _Move_assign(_Right, _Choose_pocma<_Alty>{}); } @@ -2729,7 +2860,7 @@ public: return *this; } - basic_string& assign(basic_string&& _Right) noexcept(noexcept(*this = _STD move(_Right))) { + _CONSTEXPR20_CONTAINER basic_string& assign(basic_string&& _Right) noexcept(noexcept(*this = _STD move(_Right))) { *this = _STD move(_Right); return *this; } @@ -2763,7 +2894,7 @@ private: _Right._Tidy_init(); } - void _Take_contents(basic_string& _Right, false_type) noexcept { + _CONSTEXPR20_CONTAINER void _Take_contents(basic_string& _Right, false_type) noexcept { // assign by stealing _Right's buffer, general case // pre: this != &_Right // pre: allocator propagation (POCMA) from _Right, if necessary, is complete @@ -2785,7 +2916,7 @@ private: _Right._Tidy_init(); } - void _Construct_lv_contents(const basic_string& _Right) { + _CONSTEXPR20_CONTAINER void _Construct_lv_contents(const basic_string& _Right) { // assign by copying data stored in _Right // pre: this != &_Right // pre: *this owns no memory, iterators orphaned (note: @@ -2794,7 +2925,7 @@ private: const size_type _Right_size = _Right_data._Mysize; const _Elem* const _Right_ptr = _Right_data._Myptr(); auto& _My_data = _Mypair._Myval2; - if (_Right_size < _BUF_SIZE) { // stay small, don't allocate + if (!_Right_data._Large_string_engaged()) { // stay small, don't allocate _Traits::copy(_My_data._Bx._Buf, _Right_ptr, _BUF_SIZE); _My_data._Mysize = _Right_size; _My_data._Myres = _BUF_SIZE - 1; @@ -2805,13 +2936,19 @@ private: const size_type _New_capacity = (_STD min)(_Right_size | _ALLOC_MASK, max_size()); const pointer _New_array = _Al.allocate(_New_capacity + 1); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_array); + +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once + _Traits::assign(_Unfancy(_New_array), _New_capacity + 1, _Elem()); + } +#endif // __cpp_lib_is_constant_evaluated _Traits::copy(_Unfancy(_New_array), _Right_ptr, _Right_size + 1); _My_data._Mysize = _Right_size; _My_data._Myres = _New_capacity; } public: - basic_string(initializer_list<_Elem> _Ilist, const _Alloc& _Al = allocator_type()) + _CONSTEXPR20_CONTAINER basic_string(initializer_list<_Elem> _Ilist, const _Alloc& _Al = allocator_type()) : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); @@ -2820,44 +2957,54 @@ public: _Proxy._Release(); } - basic_string& operator=(initializer_list<_Elem> _Ilist) { + _CONSTEXPR20_CONTAINER basic_string& operator=(initializer_list<_Elem> _Ilist) { return assign(_Ilist.begin(), _Convert_size(_Ilist.size())); } - basic_string& operator+=(initializer_list<_Elem> _Ilist) { + _CONSTEXPR20_CONTAINER basic_string& operator+=(initializer_list<_Elem> _Ilist) { return append(_Ilist.begin(), _Convert_size(_Ilist.size())); } - basic_string& assign(initializer_list<_Elem> _Ilist) { + _CONSTEXPR20_CONTAINER basic_string& assign(initializer_list<_Elem> _Ilist) { return assign(_Ilist.begin(), _Convert_size(_Ilist.size())); } - basic_string& append(initializer_list<_Elem> _Ilist) { + _CONSTEXPR20_CONTAINER basic_string& append(initializer_list<_Elem> _Ilist) { return append(_Ilist.begin(), _Convert_size(_Ilist.size())); } - iterator insert(const const_iterator _Where, const initializer_list<_Elem> _Ilist) { + _CONSTEXPR20_CONTAINER iterator insert(const const_iterator _Where, const initializer_list<_Elem> _Ilist) { #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); insert(_Off, _Ilist.begin(), _Convert_size(_Ilist.size())); return begin() + static_cast(_Off); } - basic_string& replace( + _CONSTEXPR20_CONTAINER basic_string& replace( const const_iterator _First, const const_iterator _Last, const initializer_list<_Elem> _Ilist) { // replace with initializer_list _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Offset = static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()); const auto _Length = static_cast(_Last._Ptr - _First._Ptr); return replace(_Offset, _Length, _Ilist.begin(), _Convert_size(_Ilist.size())); } - ~basic_string() noexcept { + _CONSTEXPR20_CONTAINER ~basic_string() noexcept { _Tidy_deallocate(); #if _ITERATOR_DEBUG_LEVEL != 0 auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); @@ -2870,25 +3017,30 @@ public: static constexpr auto npos{static_cast(-1)}; private: - void _Copy_assign_val_from_small(const basic_string& _Right) { + _CONSTEXPR20_CONTAINER void _Copy_assign_val_from_small(const basic_string& _Right) { // TRANSITION, VSO-761321; inline into only caller when that's fixed _Tidy_deallocate(); - if constexpr (_Can_memcpy_val) { - _Memcpy_val_from(_Right); - } else { - _Traits::copy( - _Mypair._Myval2._Bx._Buf, _Right._Mypair._Myval2._Bx._Buf, _Right._Mypair._Myval2._Mysize + 1); - _Mypair._Myval2._Mysize = _Right._Mypair._Myval2._Mysize; - _Mypair._Myval2._Myres = _Right._Mypair._Myval2._Myres; +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + if constexpr (_Can_memcpy_val) { + _Memcpy_val_from(_Right); + return; + } } + + _Traits::copy(_Mypair._Myval2._Bx._Buf, _Right._Mypair._Myval2._Bx._Buf, _Right._Mypair._Myval2._Mysize + 1); + _Mypair._Myval2._Mysize = _Right._Mypair._Myval2._Mysize; + _Mypair._Myval2._Myres = _Right._Mypair._Myval2._Myres; } - void _Copy_assign(const basic_string& _Right, false_type) { + _CONSTEXPR20_CONTAINER void _Copy_assign(const basic_string& _Right, false_type) { _Pocca(_Getal(), _Right._Getal()); assign(_Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); } - void _Copy_assign(const basic_string& _Right, true_type) { + _CONSTEXPR20_CONTAINER void _Copy_assign(const basic_string& _Right, true_type) { auto& _Al = _Getal(); const auto& _Right_al = _Right._Getal(); if (_Al == _Right_al) { @@ -2919,7 +3071,7 @@ private: } public: - basic_string& operator=(const basic_string& _Right) { + _CONSTEXPR20_CONTAINER basic_string& operator=(const basic_string& _Right) { if (this != _STD addressof(_Right)) { _Copy_assign(_Right, _Choose_pocca<_Alty>{}); } @@ -2929,16 +3081,16 @@ public: #if _HAS_CXX17 template = 0> - basic_string& operator=(const _StringViewIsh& _Right) { + _CONSTEXPR20_CONTAINER basic_string& operator=(const _StringViewIsh& _Right) { return assign(_Right); } #endif // _HAS_CXX17 - basic_string& operator=(_In_z_ const _Elem* const _Ptr) { + _CONSTEXPR20_CONTAINER basic_string& operator=(_In_z_ const _Elem* const _Ptr) { return assign(_Ptr); } - basic_string& operator=(const _Elem _Ch) { // assign {_Ch, _Elem()} + _CONSTEXPR20_CONTAINER basic_string& operator=(const _Elem _Ch) { // assign {_Ch, _Elem()} _Mypair._Myval2._Mysize = 1; _Elem* const _Ptr = _Mypair._Myval2._Myptr(); _Traits::assign(_Ptr[0], _Ch); @@ -2946,31 +3098,32 @@ public: return *this; } - basic_string& operator+=(const basic_string& _Right) { + _CONSTEXPR20_CONTAINER basic_string& operator+=(const basic_string& _Right) { return append(_Right); } #if _HAS_CXX17 template = 0> - basic_string& operator+=(const _StringViewIsh& _Right) { + _CONSTEXPR20_CONTAINER basic_string& operator+=(const _StringViewIsh& _Right) { return append(_Right); } #endif // _HAS_CXX17 - basic_string& operator+=(_In_z_ const _Elem* const _Ptr) { // append [_Ptr, ) + _CONSTEXPR20_CONTAINER basic_string& operator+=(_In_z_ const _Elem* const _Ptr) { // append [_Ptr, ) return append(_Ptr); } - basic_string& operator+=(_Elem _Ch) { + _CONSTEXPR20_CONTAINER basic_string& operator+=(_Elem _Ch) { push_back(_Ch); return *this; } - basic_string& append(const basic_string& _Right) { + _CONSTEXPR20_CONTAINER basic_string& append(const basic_string& _Right) { return append(_Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); } - basic_string& append(const basic_string& _Right, const size_type _Roff, size_type _Count = npos) { + _CONSTEXPR20_CONTAINER basic_string& append( + const basic_string& _Right, const size_type _Roff, size_type _Count = npos) { // append _Right [_Roff, _Roff + _Count) _Right._Mypair._Myval2._Check_offset(_Roff); _Count = _Right._Mypair._Myval2._Clamp_suffix_size(_Roff, _Count); @@ -2979,20 +3132,22 @@ public: #if _HAS_CXX17 template = 0> - basic_string& append(const _StringViewIsh& _Right) { + _CONSTEXPR20_CONTAINER basic_string& append(const _StringViewIsh& _Right) { const basic_string_view<_Elem, _Traits> _As_view = _Right; return append(_As_view.data(), _Convert_size(_As_view.size())); } template = 0> - basic_string& append(const _StringViewIsh& _Right, const size_type _Roff, const size_type _Count = npos) { + _CONSTEXPR20_CONTAINER basic_string& append( + const _StringViewIsh& _Right, const size_type _Roff, const size_type _Count = npos) { // append _Right [_Roff, _Roff + _Count) basic_string_view<_Elem, _Traits> _As_view = _Right; return append(_As_view.substr(_Roff, _Count)); } #endif // _HAS_CXX17 - basic_string& append(_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) { + _CONSTEXPR20_CONTAINER basic_string& append( + _In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) { // append [_Ptr, _Ptr + _Count) const size_type _Old_size = _Mypair._Myval2._Mysize; if (_Count <= _Mypair._Myval2._Myres - _Old_size) { @@ -3014,11 +3169,12 @@ public: _Ptr, _Count); } - basic_string& append(_In_z_ const _Elem* const _Ptr) { // append [_Ptr, ) + _CONSTEXPR20_CONTAINER basic_string& append(_In_z_ const _Elem* const _Ptr) { // append [_Ptr, ) return append(_Ptr, _Convert_size(_Traits::length(_Ptr))); } - basic_string& append(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { // append _Count * _Ch + _CONSTEXPR20_CONTAINER basic_string& append(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { + // append _Count * _Ch const size_type _Old_size = _Mypair._Myval2._Mysize; if (_Count <= _Mypair._Myval2._Myres - _Old_size) { _Mypair._Myval2._Mysize = _Old_size + _Count; @@ -3040,7 +3196,8 @@ public: } template , int> = 0> - basic_string& append(const _Iter _First, const _Iter _Last) { // append [_First, _Last), input iterators + _CONSTEXPR20_CONTAINER basic_string& append(const _Iter _First, const _Iter _Last) { + // append [_First, _Last), input iterators _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -3052,12 +3209,13 @@ public: } } - basic_string& assign(const basic_string& _Right) { + _CONSTEXPR20_CONTAINER basic_string& assign(const basic_string& _Right) { *this = _Right; return *this; } - basic_string& assign(const basic_string& _Right, const size_type _Roff, size_type _Count = npos) { + _CONSTEXPR20_CONTAINER basic_string& assign( + const basic_string& _Right, const size_type _Roff, size_type _Count = npos) { // assign _Right [_Roff, _Roff + _Count) _Right._Mypair._Myval2._Check_offset(_Roff); _Count = _Right._Mypair._Myval2._Clamp_suffix_size(_Roff, _Count); @@ -3066,20 +3224,22 @@ public: #if _HAS_CXX17 template = 0> - basic_string& assign(const _StringViewIsh& _Right) { + _CONSTEXPR20_CONTAINER basic_string& assign(const _StringViewIsh& _Right) { const basic_string_view<_Elem, _Traits> _As_view = _Right; return assign(_As_view.data(), _Convert_size(_As_view.size())); } template = 0> - basic_string& assign(const _StringViewIsh& _Right, const size_type _Roff, const size_type _Count = npos) { + _CONSTEXPR20_CONTAINER basic_string& assign( + const _StringViewIsh& _Right, const size_type _Roff, const size_type _Count = npos) { // assign _Right [_Roff, _Roff + _Count) basic_string_view<_Elem, _Traits> _As_view = _Right; return assign(_As_view.substr(_Roff, _Count)); } #endif // _HAS_CXX17 - basic_string& assign(_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) { + _CONSTEXPR20_CONTAINER basic_string& assign( + _In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) { // assign [_Ptr, _Ptr + _Count) if (_Count <= _Mypair._Myval2._Myres) { _Elem* const _Old_ptr = _Mypair._Myval2._Myptr(); @@ -3098,11 +3258,12 @@ public: _Ptr); } - basic_string& assign(_In_z_ const _Elem* const _Ptr) { + _CONSTEXPR20_CONTAINER basic_string& assign(_In_z_ const _Elem* const _Ptr) { return assign(_Ptr, _Convert_size(_Traits::length(_Ptr))); } - basic_string& assign(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { // assign _Count * _Ch + _CONSTEXPR20_CONTAINER basic_string& assign(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { + // assign _Count * _Ch if (_Count <= _Mypair._Myval2._Myres) { _Elem* const _Old_ptr = _Mypair._Myval2._Myptr(); _Mypair._Myval2._Mysize = _Count; @@ -3121,7 +3282,7 @@ public: } template , int> = 0> - basic_string& assign(const _Iter _First, const _Iter _Last) { + _CONSTEXPR20_CONTAINER basic_string& assign(const _Iter _First, const _Iter _Last) { _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -3131,7 +3292,14 @@ public: basic_string _Right(_UFirst, _ULast, get_allocator()); if (_Mypair._Myval2._Myres < _Right._Mypair._Myval2._Myres) { _Mypair._Myval2._Orphan_all(); - _Swap_data(_Right, bool_constant<_Can_memcpy_val>{}); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Swap_data(_Right, bool_constant{}); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Swap_data(_Right, bool_constant<_Can_memcpy_val>{}); + } return *this; } else { return assign(_Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); @@ -3139,11 +3307,12 @@ public: } } - basic_string& insert(const size_type _Off, const basic_string& _Right) { // insert _Right at _Off + _CONSTEXPR20_CONTAINER basic_string& insert(const size_type _Off, const basic_string& _Right) { + // insert _Right at _Off return insert(_Off, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); } - basic_string& insert( + _CONSTEXPR20_CONTAINER basic_string& insert( const size_type _Off, const basic_string& _Right, const size_type _Roff, size_type _Count = npos) { // insert _Right [_Roff, _Roff + _Count) at _Off _Right._Mypair._Myval2._Check_offset(_Roff); @@ -3153,45 +3322,52 @@ public: #if _HAS_CXX17 template = 0> - basic_string& insert(const size_type _Off, const _StringViewIsh& _Right) { // insert _Right at _Off + _CONSTEXPR20_CONTAINER basic_string& insert(const size_type _Off, const _StringViewIsh& _Right) { + // insert _Right at _Off const basic_string_view<_Elem, _Traits> _As_view = _Right; return insert(_Off, _As_view.data(), _Convert_size(_As_view.size())); } template = 0> - basic_string& insert(const size_type _Off, const _StringViewIsh& _Right, const size_type _Roff, - const size_type _Count = npos) { // insert _Right [_Roff, _Roff + _Count) at _Off + _CONSTEXPR20_CONTAINER basic_string& insert( + const size_type _Off, const _StringViewIsh& _Right, const size_type _Roff, const size_type _Count = npos) { + // insert _Right [_Roff, _Roff + _Count) at _Off basic_string_view<_Elem, _Traits> _As_view = _Right; return insert(_Off, _As_view.substr(_Roff, _Count)); } #endif // _HAS_CXX17 - basic_string& insert( + _CONSTEXPR20_CONTAINER basic_string& insert( const size_type _Off, _In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) { // insert [_Ptr, _Ptr + _Count) at _Off _Mypair._Myval2._Check_offset(_Off); const size_type _Old_size = _Mypair._Myval2._Mysize; - if (_Count <= _Mypair._Myval2._Myres - _Old_size) { - _Mypair._Myval2._Mysize = _Old_size + _Count; - _Elem* const _Old_ptr = _Mypair._Myval2._Myptr(); - _Elem* const _Insert_at = _Old_ptr + _Off; - // the range [_Ptr, _Ptr + _Ptr_shifted_after) is left alone by moving the suffix out, - // while the range [_Ptr + _Ptr_shifted_after, _Ptr + _Count) shifts down by _Count - size_type _Ptr_shifted_after; - if (_Ptr + _Count <= _Insert_at - || _Ptr > _Old_ptr + _Old_size) { // inserted content is before the shifted region, or does not alias - _Ptr_shifted_after = _Count; // none of _Ptr's data shifts - } else if (_Insert_at <= _Ptr) { // all of [_Ptr, _Ptr + _Count) shifts - _Ptr_shifted_after = 0; - } else { // [_Ptr, _Ptr + _Count) contains _Insert_at, so only the part after _Insert_at shifts - _Ptr_shifted_after = static_cast(_Insert_at - _Ptr); - } +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { // the check for overlapping ranges is technically UB, so no constant evaluation possible + if (_Count <= _Mypair._Myval2._Myres - _Old_size) { + _Mypair._Myval2._Mysize = _Old_size + _Count; + _Elem* const _Old_ptr = _Mypair._Myval2._Myptr(); + _Elem* const _Insert_at = _Old_ptr + _Off; + // the range [_Ptr, _Ptr + _Ptr_shifted_after) is left alone by moving the suffix out, + // while the range [_Ptr + _Ptr_shifted_after, _Ptr + _Count) shifts down by _Count + size_type _Ptr_shifted_after; + if (_Ptr + _Count <= _Insert_at || _Ptr > _Old_ptr + _Old_size) { + // inserted content is before the shifted region, or does not alias + _Ptr_shifted_after = _Count; // none of _Ptr's data shifts + } else if (_Insert_at <= _Ptr) { // all of [_Ptr, _Ptr + _Count) shifts + _Ptr_shifted_after = 0; + } else { // [_Ptr, _Ptr + _Count) contains _Insert_at, so only the part after _Insert_at shifts + _Ptr_shifted_after = static_cast(_Insert_at - _Ptr); + } - _Traits::move(_Insert_at + _Count, _Insert_at, _Old_size - _Off + 1); // move suffix + null down - _Traits::copy(_Insert_at, _Ptr, _Ptr_shifted_after); - _Traits::copy( - _Insert_at + _Ptr_shifted_after, _Ptr + _Count + _Ptr_shifted_after, _Count - _Ptr_shifted_after); - return *this; + _Traits::move(_Insert_at + _Count, _Insert_at, _Old_size - _Off + 1); // move suffix + null down + _Traits::copy(_Insert_at, _Ptr, _Ptr_shifted_after); + _Traits::copy( + _Insert_at + _Ptr_shifted_after, _Ptr + _Count + _Ptr_shifted_after, _Count - _Ptr_shifted_after); + return *this; + } } return _Reallocate_grow_by( @@ -3205,11 +3381,13 @@ public: _Off, _Ptr, _Count); } - basic_string& insert(const size_type _Off, _In_z_ const _Elem* const _Ptr) { // insert [_Ptr, ) at _Off + _CONSTEXPR20_CONTAINER basic_string& insert(const size_type _Off, _In_z_ const _Elem* const _Ptr) { + // insert [_Ptr, ) at _Off return insert(_Off, _Ptr, _Convert_size(_Traits::length(_Ptr))); } - basic_string& insert(const size_type _Off, _CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { + _CONSTEXPR20_CONTAINER basic_string& insert( + const size_type _Off, _CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { // insert _Count * _Ch at _Off _Mypair._Myval2._Check_offset(_Off); const size_type _Old_size = _Mypair._Myval2._Mysize; @@ -3233,19 +3411,30 @@ public: _Off, _Count, _Ch); } - iterator insert(const const_iterator _Where, const _Elem _Ch) { // insert _Ch at _Where + _CONSTEXPR20_CONTAINER iterator insert(const const_iterator _Where, const _Elem _Ch) { // insert _Ch at _Where #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); insert(_Off, 1, _Ch); return begin() + static_cast(_Off); } - iterator insert(const const_iterator _Where, _CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { + _CONSTEXPR20_CONTAINER iterator insert( + const const_iterator _Where, _CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { // insert _Count * _Elem at _Where #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); insert(_Off, _Count, _Ch); @@ -3253,10 +3442,15 @@ public: } template , int> = 0> - iterator insert(const const_iterator _Where, const _Iter _First, const _Iter _Last) { + _CONSTEXPR20_CONTAINER iterator insert(const const_iterator _Where, const _Iter _First, const _Iter _Last) { // insert [_First, _Last) at _Where, input iterators #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); _Adl_verify_range(_First, _Last); @@ -3272,14 +3466,14 @@ public: return begin() + static_cast(_Off); } - basic_string& erase(const size_type _Off = 0) { // erase elements [_Off, ...) + _CONSTEXPR20_CONTAINER basic_string& erase(const size_type _Off = 0) { // erase elements [_Off, ...) _Mypair._Myval2._Check_offset(_Off); _Eos(_Off); return *this; } private: - basic_string& _Erase_noexcept(const size_type _Off, size_type _Count) noexcept { + _CONSTEXPR20_CONTAINER basic_string& _Erase_noexcept(const size_type _Off, size_type _Count) noexcept { _Count = _Mypair._Myval2._Clamp_suffix_size(_Off, _Count); const size_type _Old_size = _Mypair._Myval2._Mysize; _Elem* const _My_ptr = _Mypair._Myval2._Myptr(); @@ -3291,41 +3485,54 @@ private: } public: - basic_string& erase(const size_type _Off, const size_type _Count) { // erase elements [_Off, _Off + _Count) + _CONSTEXPR20_CONTAINER basic_string& erase(const size_type _Off, const size_type _Count) { + // erase elements [_Off, _Off + _Count) _Mypair._Myval2._Check_offset(_Off); return _Erase_noexcept(_Off, _Count); } - iterator erase(const const_iterator _Where) noexcept /* strengthened */ { + _CONSTEXPR20_CONTAINER iterator erase(const const_iterator _Where) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); _Erase_noexcept(_Off, 1); return begin() + static_cast(_Off); } - iterator erase(const const_iterator _First, const const_iterator _Last) noexcept /* strengthened */ { + _CONSTEXPR20_CONTAINER iterator erase(const const_iterator _First, const const_iterator _Last) noexcept + /* strengthened */ { _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()); _Erase_noexcept(_Off, static_cast(_Last._Ptr - _First._Ptr)); return begin() + static_cast(_Off); } - void clear() noexcept { // erase all + _CONSTEXPR20_CONTAINER void clear() noexcept { // erase all _Eos(0); } - basic_string& replace(const size_type _Off, const size_type _Nx, const basic_string& _Right) { + _CONSTEXPR20_CONTAINER basic_string& replace( + const size_type _Off, const size_type _Nx, const basic_string& _Right) { // replace [_Off, _Off + _Nx) with _Right return replace(_Off, _Nx, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); } - basic_string& replace(const size_type _Off, size_type _Nx, const basic_string& _Right, const size_type _Roff, - size_type _Count = npos) { + _CONSTEXPR20_CONTAINER basic_string& replace(const size_type _Off, size_type _Nx, const basic_string& _Right, + const size_type _Roff, size_type _Count = npos) { // replace [_Off, _Off + _Nx) with _Right [_Roff, _Roff + _Count) _Right._Mypair._Myval2._Check_offset(_Roff); _Count = _Right._Mypair._Myval2._Clamp_suffix_size(_Roff, _Count); @@ -3334,22 +3541,23 @@ public: #if _HAS_CXX17 template = 0> - basic_string& replace(const size_type _Off, const size_type _Nx, const _StringViewIsh& _Right) { + _CONSTEXPR20_CONTAINER basic_string& replace( + const size_type _Off, const size_type _Nx, const _StringViewIsh& _Right) { // replace [_Off, _Off + _Nx) with _Right basic_string_view<_Elem, _Traits> _As_view = _Right; return replace(_Off, _Nx, _As_view.data(), _Convert_size(_As_view.size())); } template = 0> - basic_string& replace(const size_type _Off, const size_type _Nx, const _StringViewIsh& _Right, - const size_type _Roff, const size_type _Count = npos) { + _CONSTEXPR20_CONTAINER basic_string& replace(const size_type _Off, const size_type _Nx, + const _StringViewIsh& _Right, const size_type _Roff, const size_type _Count = npos) { // replace [_Off, _Off + _Nx) with _Right [_Roff, _Roff + _Count) basic_string_view<_Elem, _Traits> _As_view = _Right; return replace(_Off, _Nx, _As_view.substr(_Roff, _Count)); } #endif // _HAS_CXX17 - basic_string& replace( + _CONSTEXPR20_CONTAINER basic_string& replace( const size_type _Off, size_type _Nx, _In_reads_(_Count) const _Elem* const _Ptr, const size_type _Count) { // replace [_Off, _Off + _Nx) with [_Ptr, _Ptr + _Count) _Mypair._Myval2._Check_offset(_Off); @@ -3371,31 +3579,36 @@ public: } const size_type _Growth = static_cast(_Count - _Nx); - if (_Growth <= _Mypair._Myval2._Myres - _Old_size) { // growth fits - _Mypair._Myval2._Mysize = _Old_size + _Growth; - _Elem* const _Old_ptr = _Mypair._Myval2._Myptr(); - _Elem* const _Insert_at = _Old_ptr + _Off; - _Elem* const _Suffix_at = _Insert_at + _Nx; +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { // the check for overlapping ranges is technically UB, so no constant evaluation possible + if (_Growth <= _Mypair._Myval2._Myres - _Old_size) { // growth fits + _Mypair._Myval2._Mysize = _Old_size + _Growth; + _Elem* const _Old_ptr = _Mypair._Myval2._Myptr(); + _Elem* const _Insert_at = _Old_ptr + _Off; + _Elem* const _Suffix_at = _Insert_at + _Nx; + + size_type _Ptr_shifted_after; // see rationale in insert + if (_Ptr + _Count <= _Insert_at || _Ptr > _Old_ptr + _Old_size) { + _Ptr_shifted_after = _Count; + } else if (_Suffix_at <= _Ptr) { + _Ptr_shifted_after = 0; + } else { + _Ptr_shifted_after = static_cast(_Suffix_at - _Ptr); + } - size_type _Ptr_shifted_after; // see rationale in insert - if (_Ptr + _Count <= _Insert_at || _Ptr > _Old_ptr + _Old_size) { - _Ptr_shifted_after = _Count; - } else if (_Suffix_at <= _Ptr) { - _Ptr_shifted_after = 0; - } else { - _Ptr_shifted_after = static_cast(_Suffix_at - _Ptr); + _Traits::move(_Suffix_at + _Growth, _Suffix_at, _Suffix_size); + // next case must be move, in case _Ptr begins before _Insert_at and contains part of the hole; + // this case doesn't occur in insert because the new content must come from outside the removed + // content there (because in insert there is no removed content) + _Traits::move(_Insert_at, _Ptr, _Ptr_shifted_after); + // the next case can be copy, because it comes from the chunk moved out of the way in the + // first move, and the hole we're filling can't alias the chunk we moved out of the way + _Traits::copy( + _Insert_at + _Ptr_shifted_after, _Ptr + _Growth + _Ptr_shifted_after, _Count - _Ptr_shifted_after); + return *this; } - - _Traits::move(_Suffix_at + _Growth, _Suffix_at, _Suffix_size); - // next case must be move, in case _Ptr begins before _Insert_at and contains part of the hole; - // this case doesn't occur in insert because the new content must come from outside the removed - // content there (because in insert there is no removed content) - _Traits::move(_Insert_at, _Ptr, _Ptr_shifted_after); - // the next case can be copy, because it comes from the chunk moved out of the way in the - // first move, and the hole we're filling can't alias the chunk we moved out of the way - _Traits::copy( - _Insert_at + _Ptr_shifted_after, _Ptr + _Growth + _Ptr_shifted_after, _Count - _Ptr_shifted_after); - return *this; } return _Reallocate_grow_by( @@ -3409,12 +3622,14 @@ public: _Off, _Nx, _Ptr, _Count); } - basic_string& replace(const size_type _Off, const size_type _Nx, _In_z_ const _Elem* const _Ptr) { + _CONSTEXPR20_CONTAINER basic_string& replace( + const size_type _Off, const size_type _Nx, _In_z_ const _Elem* const _Ptr) { // replace [_Off, _Off + _Nx) with [_Ptr, ) return replace(_Off, _Nx, _Ptr, _Convert_size(_Traits::length(_Ptr))); } - basic_string& replace(const size_type _Off, size_type _Nx, const size_type _Count, const _Elem _Ch) { + _CONSTEXPR20_CONTAINER basic_string& replace( + const size_type _Off, size_type _Nx, const size_type _Count, const _Elem _Ch) { // replace [_Off, _Off + _Nx) with _Count * _Ch _Mypair._Myval2._Check_offset(_Off); _Nx = _Mypair._Myval2._Clamp_suffix_size(_Off, _Nx); @@ -3424,8 +3639,8 @@ public: } const size_type _Old_size = _Mypair._Myval2._Mysize; - if (_Count < _Nx - || _Count - _Nx <= _Mypair._Myval2._Myres - _Old_size) { // either we are shrinking, or the growth fits + if (_Count < _Nx || _Count - _Nx <= _Mypair._Myval2._Myres - _Old_size) { + // either we are shrinking, or the growth fits _Mypair._Myval2._Mysize = _Old_size + _Count - _Nx; // may temporarily overflow; // OK because size_type must be unsigned _Elem* const _Old_ptr = _Mypair._Myval2._Myptr(); @@ -3446,11 +3661,17 @@ public: _Off, _Nx, _Count, _Ch); } - basic_string& replace(const const_iterator _First, const const_iterator _Last, const basic_string& _Right) { + _CONSTEXPR20_CONTAINER basic_string& replace( + const const_iterator _First, const const_iterator _Last, const basic_string& _Right) { // replace [_First, _Last) with _Right _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Right); @@ -3458,56 +3679,83 @@ public: #if _HAS_CXX17 template = 0> - basic_string& replace(const const_iterator _First, const const_iterator _Last, const _StringViewIsh& _Right) { + _CONSTEXPR20_CONTAINER basic_string& replace( + const const_iterator _First, const const_iterator _Last, const _StringViewIsh& _Right) { // replace [_First, _Last) with _Right _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Right); } #endif // _HAS_CXX17 - basic_string& replace(const const_iterator _First, const const_iterator _Last, + _CONSTEXPR20_CONTAINER basic_string& replace(const const_iterator _First, const const_iterator _Last, _In_reads_(_Count) const _Elem* const _Ptr, const size_type _Count) { // replace [_First, _Last) with [_Ptr, _Ptr + _Count) _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Ptr, _Count); } - basic_string& replace(const const_iterator _First, const const_iterator _Last, _In_z_ const _Elem* const _Ptr) { + _CONSTEXPR20_CONTAINER basic_string& replace( + const const_iterator _First, const const_iterator _Last, _In_z_ const _Elem* const _Ptr) { // replace [_First, _Last) with [_Ptr, ) _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Ptr); } - basic_string& replace( + _CONSTEXPR20_CONTAINER basic_string& replace( const const_iterator _First, const const_iterator _Last, const size_type _Count, const _Elem _Ch) { // replace [_First, _Last) with _Count * _Ch _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Count, _Ch); } template , int> = 0> - basic_string& replace( + _CONSTEXPR20_CONTAINER basic_string& replace( const const_iterator _First, const const_iterator _Last, const _Iter _First2, const _Iter _Last2) { // replace [_First, _Last) with [_First2, _Last2), input iterators _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()); const auto _Length = static_cast(_Last._Ptr - _First._Ptr); @@ -3522,89 +3770,100 @@ public: } } - _NODISCARD iterator begin() noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER iterator begin() noexcept { return iterator(_Refancy(_Mypair._Myval2._Myptr()), _STD addressof(_Mypair._Myval2)); } - _NODISCARD const_iterator begin() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const_iterator begin() const noexcept { return const_iterator(_Refancy(_Mypair._Myval2._Myptr()), _STD addressof(_Mypair._Myval2)); } - _NODISCARD iterator end() noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER iterator end() noexcept { return iterator( _Refancy(_Mypair._Myval2._Myptr()) + static_cast(_Mypair._Myval2._Mysize), _STD addressof(_Mypair._Myval2)); } - _NODISCARD const_iterator end() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const_iterator end() const noexcept { return const_iterator( _Refancy(_Mypair._Myval2._Myptr()) + static_cast(_Mypair._Myval2._Mysize), _STD addressof(_Mypair._Myval2)); } - _Elem* _Unchecked_begin() noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER _Elem* _Unchecked_begin() noexcept { return _Mypair._Myval2._Myptr(); } - const _Elem* _Unchecked_begin() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const _Elem* _Unchecked_begin() const noexcept { return _Mypair._Myval2._Myptr(); } - _Elem* _Unchecked_end() noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER _Elem* _Unchecked_end() noexcept { return _Mypair._Myval2._Myptr() + _Mypair._Myval2._Mysize; } - const _Elem* _Unchecked_end() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const _Elem* _Unchecked_end() const noexcept { return _Mypair._Myval2._Myptr() + _Mypair._Myval2._Mysize; } - _NODISCARD reverse_iterator rbegin() noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } - _NODISCARD const_reverse_iterator rbegin() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } - _NODISCARD reverse_iterator rend() noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER reverse_iterator rend() noexcept { return reverse_iterator(begin()); } - _NODISCARD const_reverse_iterator rend() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } - _NODISCARD const_iterator cbegin() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const_iterator cbegin() const noexcept { return begin(); } - _NODISCARD const_iterator cend() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const_iterator cend() const noexcept { return end(); } - _NODISCARD const_reverse_iterator crbegin() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const_reverse_iterator crbegin() const noexcept { return rbegin(); } - _NODISCARD const_reverse_iterator crend() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER const_reverse_iterator crend() const noexcept { return rend(); } - void shrink_to_fit() { // reduce capacity + _CONSTEXPR20_CONTAINER void shrink_to_fit() { // reduce capacity auto& _My_data = _Mypair._Myval2; if (!_My_data._Large_string_engaged()) { // can't shrink from small mode return; } - - if (_My_data._Mysize < _BUF_SIZE) { - _Become_small(); - return; +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + if (_My_data._Mysize < _BUF_SIZE) { + _Become_small(); + return; + } } 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 + +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once + _Traits::assign(_Unfancy(_New_ptr), _Target_capacity + 1, _Elem()); + } +#endif // __cpp_lib_is_constant_evaluated + _My_data._Orphan_all(); _Traits::copy(_Unfancy(_New_ptr), _Unfancy(_My_data._Bx._Ptr), _My_data._Mysize + 1); _Al.deallocate(_My_data._Bx._Ptr, _My_data._Myres + 1); @@ -3613,24 +3872,25 @@ public: } } - _NODISCARD reference at(const size_type _Off) { + _NODISCARD _CONSTEXPR20_CONTAINER reference at(const size_type _Off) { _Mypair._Myval2._Check_offset_exclusive(_Off); return _Mypair._Myval2._Myptr()[_Off]; } - _NODISCARD const_reference at(const size_type _Off) const { + _NODISCARD _CONSTEXPR20_CONTAINER const_reference at(const size_type _Off) const { _Mypair._Myval2._Check_offset_exclusive(_Off); return _Mypair._Myval2._Myptr()[_Off]; } - _NODISCARD reference operator[](const size_type _Off) noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER reference operator[](const size_type _Off) noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off <= _Mypair._Myval2._Mysize, "string subscript out of range"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return _Mypair._Myval2._Myptr()[_Off]; } - _NODISCARD const_reference operator[](const size_type _Off) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER const_reference operator[](const size_type _Off) const noexcept + /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off <= _Mypair._Myval2._Mysize, "string subscript out of range"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -3638,13 +3898,13 @@ public: } #if _HAS_CXX17 - /* implicit */ operator basic_string_view<_Elem, _Traits>() const noexcept { + /* implicit */ _CONSTEXPR20_CONTAINER operator basic_string_view<_Elem, _Traits>() const noexcept { // return a string_view around *this's character-type sequence return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize); } #endif // _HAS_CXX17 - void push_back(const _Elem _Ch) { // insert element at end + _CONSTEXPR20_CONTAINER void push_back(const _Elem _Ch) { // insert element at end const size_type _Old_size = _Mypair._Myval2._Mysize; if (_Old_size < _Mypair._Myval2._Myres) { _Mypair._Myval2._Mysize = _Old_size + 1; @@ -3664,7 +3924,7 @@ public: _Ch); } - void pop_back() noexcept /* strengthened */ { + _CONSTEXPR20_CONTAINER void pop_back() noexcept /* strengthened */ { const size_type _Old_size = _Mypair._Myval2._Mysize; #if _ITERATOR_DEBUG_LEVEL >= 1 _STL_VERIFY(_Old_size != 0, "invalid to pop_back empty string"); @@ -3672,7 +3932,7 @@ public: _Eos(_Old_size - 1); } - _NODISCARD reference front() noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER reference front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty string"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -3680,7 +3940,7 @@ public: return _Mypair._Myval2._Myptr()[0]; } - _NODISCARD const_reference front() const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER const_reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty string"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -3688,7 +3948,7 @@ public: return _Mypair._Myval2._Myptr()[0]; } - _NODISCARD reference back() noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER reference back() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty string"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -3696,7 +3956,7 @@ public: return _Mypair._Myval2._Myptr()[_Mypair._Myval2._Mysize - 1]; } - _NODISCARD const_reference back() const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER const_reference back() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty string"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -3704,29 +3964,29 @@ public: return _Mypair._Myval2._Myptr()[_Mypair._Myval2._Mysize - 1]; } - _NODISCARD _Ret_z_ const _Elem* c_str() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER _Ret_z_ const _Elem* c_str() const noexcept { return _Mypair._Myval2._Myptr(); } - _NODISCARD _Ret_z_ const _Elem* data() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER _Ret_z_ const _Elem* data() const noexcept { return _Mypair._Myval2._Myptr(); } #if _HAS_CXX17 - _NODISCARD _Ret_z_ _Elem* data() noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER _Ret_z_ _Elem* data() noexcept { return _Mypair._Myval2._Myptr(); } #endif // _HAS_CXX17 - _NODISCARD size_type length() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type length() const noexcept { return _Mypair._Myval2._Mysize; } - _NODISCARD size_type size() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type size() const noexcept { return _Mypair._Myval2._Mysize; } - _NODISCARD size_type max_size() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type max_size() const noexcept { const size_type _Alloc_max = _Alty_traits::max_size(_Getal()); const size_type _Storage_max = // can always store small string (_STD max)(_Alloc_max, static_cast(_BUF_SIZE)); @@ -3735,7 +3995,7 @@ public: ); } - void resize(_CRT_GUARDOVERFLOW const size_type _Newsize, const _Elem _Ch = _Elem()) { + _CONSTEXPR20_CONTAINER void resize(_CRT_GUARDOVERFLOW const size_type _Newsize, const _Elem _Ch = _Elem()) { // determine new length, padding with _Ch elements as needed const size_type _Old_size = size(); if (_Newsize <= _Old_size) { @@ -3745,12 +4005,13 @@ public: } } - _NODISCARD size_type capacity() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type capacity() const noexcept { return _Mypair._Myval2._Myres; } #if _HAS_CXX20 - void reserve(_CRT_GUARDOVERFLOW const size_type _Newcap) { // determine new minimum length of allocated storage + _CONSTEXPR20_CONTAINER void reserve(_CRT_GUARDOVERFLOW const size_type _Newcap) { + // determine new minimum length of allocated storage if (_Mypair._Myval2._Myres >= _Newcap) { // requested capacity is not larger than current capacity, ignore return; // nothing to do } @@ -3800,11 +4061,12 @@ public: } #endif // _HAS_CXX20 - _NODISCARD bool empty() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool empty() const noexcept { return size() == 0; } - size_type copy(_Out_writes_(_Count) _Elem* const _Ptr, size_type _Count, const size_type _Off = 0) const { + _CONSTEXPR20_CONTAINER size_type copy( + _Out_writes_(_Count) _Elem* const _Ptr, size_type _Count, const size_type _Off = 0) const { // copy [_Off, _Off + _Count) to [_Ptr, _Ptr + _Count) _Mypair._Myval2._Check_offset(_Off); _Count = _Mypair._Myval2._Clamp_suffix_size(_Off, _Count); @@ -3812,8 +4074,9 @@ public: return _Count; } - _Pre_satisfies_(_Dest_size >= _Count) size_type _Copy_s(_Out_writes_all_(_Dest_size) _Elem* const _Dest, - const size_type _Dest_size, size_type _Count, const size_type _Off = 0) const { + _CONSTEXPR20_CONTAINER _Pre_satisfies_(_Dest_size >= _Count) size_type + _Copy_s(_Out_writes_all_(_Dest_size) _Elem* const _Dest, const size_type _Dest_size, size_type _Count, + const size_type _Off = 0) const { // copy [_Off, _Off + _Count) to [_Dest, _Dest + _Dest_size) _Mypair._Myval2._Check_offset(_Off); _Count = _Mypair._Myval2._Clamp_suffix_size(_Off, _Count); @@ -3833,7 +4096,7 @@ public: _CSTD memcpy(_Right_data_mem, _Temp_mem, _Memcpy_val_size); } - void _Swap_bx_large_with_small(_Scary_val& _Starts_large, _Scary_val& _Starts_small) { + _CONSTEXPR20_CONTAINER void _Swap_bx_large_with_small(_Scary_val& _Starts_large, _Scary_val& _Starts_small) { // exchange a string in large mode with one in small mode const pointer _Ptr = _Starts_large._Bx._Ptr; _Destroy_in_place(_Starts_large._Bx._Ptr); @@ -3841,7 +4104,7 @@ public: _Construct_in_place(_Starts_small._Bx._Ptr, _Ptr); } - void _Swap_data(basic_string& _Right, false_type) { + _CONSTEXPR20_CONTAINER void _Swap_data(basic_string& _Right, false_type) { // exchange _String_val instances with _Right, general case auto& _My_data = _Mypair._Myval2; auto& _Right_data = _Right._Mypair._Myval2; @@ -3868,7 +4131,7 @@ public: _STD swap(_My_data._Myres, _Right_data._Myres); } - void swap(basic_string& _Right) noexcept /* strengthened */ { + _CONSTEXPR20_CONTAINER void swap(basic_string& _Right) noexcept /* strengthened */ { if (this != _STD addressof(_Right)) { _Pocs(_Getal(), _Right._Getal()); @@ -3889,12 +4152,19 @@ public: #endif // _ITERATOR_DEBUG_LEVEL != 0 } - _Swap_data(_Right, bool_constant<_Can_memcpy_val>{}); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { // cannot call memcpy in a constexpr context + _Swap_data(_Right, bool_constant{}); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Swap_data(_Right, bool_constant<_Can_memcpy_val>{}); + } } #if _HAS_CXX17 template = 0> - _NODISCARD size_type find(const _StringViewIsh& _Right, const size_type _Off = 0) const { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find(const _StringViewIsh& _Right, const size_type _Off = 0) const { // look for _Right beginning at or after _Off basic_string_view<_Elem, _Traits> _As_view = _Right; return static_cast(_Traits_find<_Traits>( @@ -3902,27 +4172,30 @@ public: } #endif // _HAS_CXX17 - _NODISCARD size_type find(const basic_string& _Right, const size_type _Off = 0) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find( + const basic_string& _Right, const size_type _Off = 0) const noexcept { // look for _Right beginning at or after _Off return static_cast(_Traits_find<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize)); } - _NODISCARD size_type find(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, + _NODISCARD _CONSTEXPR20_CONTAINER size_type find(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, const size_type _Count) const noexcept /* strengthened */ { // look for [_Ptr, _Ptr + _Count) beginning at or after _Off return static_cast( _Traits_find<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Count)); } - _NODISCARD size_type find(_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const noexcept + _NODISCARD _CONSTEXPR20_CONTAINER size_type find( + _In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const noexcept /* strengthened */ { // look for [_Ptr, ) beginning at or after _Off return static_cast(_Traits_find<_Traits>( _Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr))); } - _NODISCARD size_type find(const _Elem _Ch, const size_type _Off = 0) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find(const _Elem _Ch, const size_type _Off = 0) const noexcept + /* strengthened */ { // look for _Ch at or after _Off return static_cast( _Traits_find_ch<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ch)); @@ -3930,7 +4203,7 @@ public: #if _HAS_CXX17 template = 0> - _NODISCARD size_type rfind(const _StringViewIsh& _Right, const size_type _Off = npos) const { + _NODISCARD _CONSTEXPR20_CONTAINER size_type rfind(const _StringViewIsh& _Right, const size_type _Off = npos) const { // look for _Right beginning before _Off basic_string_view<_Elem, _Traits> _As_view = _Right; return static_cast(_Traits_rfind<_Traits>( @@ -3938,27 +4211,30 @@ public: } #endif // _HAS_CXX17 - _NODISCARD size_type rfind(const basic_string& _Right, const size_type _Off = npos) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type rfind( + const basic_string& _Right, const size_type _Off = npos) const noexcept { // look for _Right beginning before _Off return static_cast(_Traits_rfind<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize)); } - _NODISCARD size_type rfind(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, + _NODISCARD _CONSTEXPR20_CONTAINER size_type rfind(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, const size_type _Count) const noexcept /* strengthened */ { // look for [_Ptr, _Ptr + _Count) beginning before _Off return static_cast( _Traits_rfind<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Count)); } - _NODISCARD size_type rfind(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const noexcept + _NODISCARD _CONSTEXPR20_CONTAINER size_type rfind( + _In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const noexcept /* strengthened */ { // look for [_Ptr, ) beginning before _Off return static_cast(_Traits_rfind<_Traits>( _Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr))); } - _NODISCARD size_type rfind(const _Elem _Ch, const size_type _Off = npos) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER size_type rfind(const _Elem _Ch, const size_type _Off = npos) const noexcept + /* strengthened */ { // look for _Ch before _Off return static_cast( _Traits_rfind_ch<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ch)); @@ -3966,7 +4242,8 @@ public: #if _HAS_CXX17 template = 0> - _NODISCARD size_type find_first_of(const _StringViewIsh& _Right, const size_type _Off = 0) const { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_of( + const _StringViewIsh& _Right, const size_type _Off = 0) const { // look for one of _Right at or after _Off basic_string_view<_Elem, _Traits> _As_view = _Right; return static_cast(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, @@ -3974,28 +4251,31 @@ public: } #endif // _HAS_CXX17 - _NODISCARD size_type find_first_of(const basic_string& _Right, const size_type _Off = 0) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_of( + const basic_string& _Right, const size_type _Off = 0) const noexcept { // look for one of _Right at or after _Off return static_cast(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize, _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_first_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, - const size_type _Count) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_of(_In_reads_(_Count) const _Elem* const _Ptr, + const size_type _Off, const size_type _Count) const noexcept /* strengthened */ { // look for one of [_Ptr, _Ptr + _Count) at or after _Off return static_cast(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_first_of(_In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const noexcept + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_of( + _In_z_ const _Elem* const _Ptr, const size_type _Off = 0) const noexcept /* strengthened */ { // look for one of [_Ptr, ) at or after _Off return static_cast(_Traits_find_first_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_first_of(const _Elem _Ch, const size_type _Off = 0) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_of(const _Elem _Ch, const size_type _Off = 0) const noexcept + /* strengthened */ { // look for _Ch at or after _Off return static_cast( _Traits_find_ch<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ch)); @@ -4003,7 +4283,8 @@ public: #if _HAS_CXX17 template = 0> - _NODISCARD size_type find_last_of(const _StringViewIsh& _Right, const size_type _Off = npos) const { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_of( + const _StringViewIsh& _Right, const size_type _Off = npos) const { // look for one of _Right before _Off basic_string_view<_Elem, _Traits> _As_view = _Right; return static_cast(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, @@ -4011,28 +4292,32 @@ public: } #endif // _HAS_CXX17 - _NODISCARD size_type find_last_of(const basic_string& _Right, size_type _Off = npos) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_of( + const basic_string& _Right, size_type _Off = npos) const noexcept { // look for one of _Right before _Off return static_cast(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize, _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_last_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, - const size_type _Count) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_of(_In_reads_(_Count) const _Elem* const _Ptr, + const size_type _Off, const size_type _Count) const noexcept /* strengthened */ { // look for one of [_Ptr, _Ptr + _Count) before _Off return static_cast(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_last_of(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const noexcept + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_of( + _In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const noexcept /* strengthened */ { // look for one of [_Ptr, ) before _Off return static_cast(_Traits_find_last_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_last_of(const _Elem _Ch, const size_type _Off = npos) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_of( + const _Elem _Ch, const size_type _Off = npos) const noexcept + /* strengthened */ { // look for _Ch before _Off return static_cast( _Traits_rfind_ch<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ch)); @@ -4040,7 +4325,8 @@ public: #if _HAS_CXX17 template = 0> - _NODISCARD size_type find_first_not_of(const _StringViewIsh& _Right, const size_type _Off = 0) const { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_not_of( + const _StringViewIsh& _Right, const size_type _Off = 0) const { // look for none of _Right at or after _Off basic_string_view<_Elem, _Traits> _As_view = _Right; return static_cast( @@ -4049,28 +4335,31 @@ public: } #endif // _HAS_CXX17 - _NODISCARD size_type find_first_not_of(const basic_string& _Right, const size_type _Off = 0) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_not_of( + const basic_string& _Right, const size_type _Off = 0) const noexcept { // look for none of _Right at or after _Off return static_cast(_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize, _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_first_not_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, - const size_type _Count) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_not_of(_In_reads_(_Count) const _Elem* const _Ptr, + const size_type _Off, const size_type _Count) const noexcept /* strengthened */ { // look for none of [_Ptr, _Ptr + _Count) at or after _Off return static_cast(_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_first_not_of(_In_z_ const _Elem* const _Ptr, size_type _Off = 0) const noexcept + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_not_of( + _In_z_ const _Elem* const _Ptr, size_type _Off = 0) const noexcept /* strengthened */ { // look for one of [_Ptr, ) at or after _Off return static_cast(_Traits_find_first_not_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_first_not_of(const _Elem _Ch, const size_type _Off = 0) const noexcept + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_first_not_of( + const _Elem _Ch, const size_type _Off = 0) const noexcept /* strengthened */ { // look for non-_Ch at or after _Off return static_cast( @@ -4079,7 +4368,8 @@ public: #if _HAS_CXX17 template = 0> - _NODISCARD size_type find_last_not_of(const _StringViewIsh& _Right, const size_type _Off = npos) const { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_not_of( + const _StringViewIsh& _Right, const size_type _Off = npos) const { // look for none of _Right before _Off basic_string_view<_Elem, _Traits> _As_view = _Right; return static_cast( @@ -4088,28 +4378,31 @@ public: } #endif // _HAS_CXX17 - _NODISCARD size_type find_last_not_of(const basic_string& _Right, const size_type _Off = npos) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_not_of( + const basic_string& _Right, const size_type _Off = npos) const noexcept { // look for none of _Right before _Off return static_cast(_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize, _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_last_not_of(_In_reads_(_Count) const _Elem* const _Ptr, const size_type _Off, - const size_type _Count) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_not_of(_In_reads_(_Count) const _Elem* const _Ptr, + const size_type _Off, const size_type _Count) const noexcept /* strengthened */ { // look for none of [_Ptr, _Ptr + _Count) before _Off return static_cast(_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Count, _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_last_not_of(_In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const noexcept + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_not_of( + _In_z_ const _Elem* const _Ptr, const size_type _Off = npos) const noexcept /* strengthened */ { // look for none of [_Ptr, ) before _Off return static_cast(_Traits_find_last_not_of<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Off, _Ptr, _Traits::length(_Ptr), _Is_specialization<_Traits, char_traits>{})); } - _NODISCARD size_type find_last_not_of(const _Elem _Ch, const size_type _Off = npos) const noexcept + _NODISCARD _CONSTEXPR20_CONTAINER size_type find_last_not_of( + const _Elem _Ch, const size_type _Off = npos) const noexcept /* strengthened */ { // look for non-_Ch before _Off return static_cast( @@ -4122,30 +4415,35 @@ public: } #endif // _HAS_CXX17 - _NODISCARD basic_string substr(const size_type _Off = 0, const size_type _Count = npos) const { + _NODISCARD _CONSTEXPR20_CONTAINER basic_string substr( + const size_type _Off = 0, const size_type _Count = npos) const { // return [_Off, _Off + _Count) as new string return basic_string(*this, _Off, _Count, get_allocator()); } - bool _Equal(const basic_string& _Right) const noexcept { // compare [0, size()) with _Right for equality + _CONSTEXPR20_CONTAINER bool _Equal(const basic_string& _Right) const noexcept { + // compare [0, size()) with _Right for equality return _Traits_equal<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); } - bool _Equal(_In_z_ const _Elem* const _Ptr) const noexcept { // compare [0, size()) with _Ptr for equality + _CONSTEXPR20_CONTAINER bool _Equal(_In_z_ const _Elem* const _Ptr) const noexcept { + // compare [0, size()) with _Ptr for equality return _Traits_equal<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Ptr, _Traits::length(_Ptr)); } #if _HAS_CXX17 template = 0> - _NODISCARD int compare(const _StringViewIsh& _Right) const { // compare [0, size()) with _Right + _NODISCARD _CONSTEXPR20_CONTAINER int compare(const _StringViewIsh& _Right) const { + // compare [0, size()) with _Right basic_string_view<_Elem, _Traits> _As_view = _Right; return _Traits_compare<_Traits>( _Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _As_view.data(), _As_view.size()); } template = 0> - _NODISCARD int compare(const size_type _Off, const size_type _Nx, const _StringViewIsh& _Right) const { + _NODISCARD _CONSTEXPR20_CONTAINER int compare( + const size_type _Off, const size_type _Nx, const _StringViewIsh& _Right) const { // compare [_Off, _Off + _Nx) with _Right basic_string_view<_Elem, _Traits> _As_view = _Right; _Mypair._Myval2._Check_offset(_Off); @@ -4154,8 +4452,8 @@ public: } template = 0> - _NODISCARD int compare(const size_type _Off, const size_type _Nx, const _StringViewIsh& _Right, - const size_type _Roff, const size_type _Count = npos) const { + _NODISCARD _CONSTEXPR20_CONTAINER int compare(const size_type _Off, const size_type _Nx, + const _StringViewIsh& _Right, const size_type _Roff, const size_type _Count = npos) const { // compare [_Off, _Off + _Nx) with _Right [_Roff, _Roff + _Count) basic_string_view<_Elem, _Traits> _As_view = _Right; _Mypair._Myval2._Check_offset(_Off); @@ -4165,78 +4463,81 @@ public: } #endif // _HAS_CXX17 - _NODISCARD int compare(const basic_string& _Right) const noexcept { // compare [0, size()) with _Right + _NODISCARD _CONSTEXPR20_CONTAINER int compare(const basic_string& _Right) const noexcept { + // compare [0, size()) with _Right return _Traits_compare<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); } - _NODISCARD int compare(size_type _Off, size_type _Nx, const basic_string& _Right) const { - // compare [_Off, _Off + _Nx) with _Right + _NODISCARD _CONSTEXPR20_CONTAINER int compare(size_type _Off, size_type _Nx, const basic_string& _Right) const { + // compare [_Off, _Off + _N0) with _Right _Mypair._Myval2._Check_offset(_Off); return _Traits_compare<_Traits>(_Mypair._Myval2._Myptr() + _Off, _Mypair._Myval2._Clamp_suffix_size(_Off, _Nx), _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); } - _NODISCARD int compare(const size_type _Off, const size_type _Nx, const basic_string& _Right, const size_type _Roff, - const size_type _Count = npos) const { - // compare [_Off, _Off + _Nx) with _Right [_Roff, _Roff + _Count) + _NODISCARD _CONSTEXPR20_CONTAINER int compare(const size_type _Off, const size_type _Nx, const basic_string& _Right, + const size_type _Roff, const size_type _Count = npos) const { + // compare [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count) _Mypair._Myval2._Check_offset(_Off); _Right._Mypair._Myval2._Check_offset(_Roff); return _Traits_compare<_Traits>(_Mypair._Myval2._Myptr() + _Off, _Mypair._Myval2._Clamp_suffix_size(_Off, _Nx), _Right._Mypair._Myval2._Myptr() + _Roff, _Right._Mypair._Myval2._Clamp_suffix_size(_Roff, _Count)); } - _NODISCARD int compare(_In_z_ const _Elem* const _Ptr) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER int compare(_In_z_ const _Elem* const _Ptr) const noexcept /* strengthened */ { // compare [0, size()) with [_Ptr, ) return _Traits_compare<_Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize, _Ptr, _Traits::length(_Ptr)); } - _NODISCARD int compare(const size_type _Off, const size_type _Nx, _In_z_ const _Elem* const _Ptr) const { - // compare [_Off, _Off + _Nx) with [_Ptr, ) + _NODISCARD _CONSTEXPR20_CONTAINER int compare( + const size_type _Off, const size_type _Nx, _In_z_ const _Elem* const _Ptr) const { + // compare [_Off, _Off + _N0) with [_Ptr, ) _Mypair._Myval2._Check_offset(_Off); return _Traits_compare<_Traits>(_Mypair._Myval2._Myptr() + _Off, _Mypair._Myval2._Clamp_suffix_size(_Off, _Nx), _Ptr, _Traits::length(_Ptr)); } - _NODISCARD int compare(const size_type _Off, const size_type _Nx, _In_reads_(_Count) const _Elem* const _Ptr, - const size_type _Count) const { // compare [_Off, _Off + _Nx) with [_Ptr, _Ptr + _Count) + _NODISCARD _CONSTEXPR20_CONTAINER int compare(const size_type _Off, const size_type _Nx, + _In_reads_(_Count) const _Elem* const _Ptr, const size_type _Count) const { + // compare [_Off, _Off + _N0) with [_Ptr, _Ptr + _Count) _Mypair._Myval2._Check_offset(_Off); return _Traits_compare<_Traits>( _Mypair._Myval2._Myptr() + _Off, _Mypair._Myval2._Clamp_suffix_size(_Off, _Nx), _Ptr, _Count); } #if _HAS_CXX20 - _NODISCARD bool starts_with(const basic_string_view<_Elem, _Traits> _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool starts_with(const basic_string_view<_Elem, _Traits> _Right) const noexcept { return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).starts_with(_Right); } - _NODISCARD bool starts_with(const _Elem _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool starts_with(const _Elem _Right) const noexcept { return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).starts_with(_Right); } - _NODISCARD bool starts_with(const _Elem* const _Right) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER bool starts_with(const _Elem* const _Right) const noexcept /* strengthened */ { return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).starts_with(_Right); } - _NODISCARD bool ends_with(const basic_string_view<_Elem, _Traits> _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool ends_with(const basic_string_view<_Elem, _Traits> _Right) const noexcept { return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).ends_with(_Right); } - _NODISCARD bool ends_with(const _Elem _Right) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER bool ends_with(const _Elem _Right) const noexcept { return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).ends_with(_Right); } - _NODISCARD bool ends_with(const _Elem* const _Right) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_CONTAINER bool ends_with(const _Elem* const _Right) const noexcept /* strengthened */ { return basic_string_view<_Elem, _Traits>(_Mypair._Myval2._Myptr(), _Mypair._Myval2._Mysize).ends_with(_Right); } #endif // _HAS_CXX20 - _NODISCARD allocator_type get_allocator() const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER allocator_type get_allocator() const noexcept { return static_cast(_Getal()); } private: - _NODISCARD static size_type _Calculate_growth( + _NODISCARD static _CONSTEXPR20_CONTAINER size_type _Calculate_growth( const size_type _Requested, const size_type _Old, const size_type _Max) noexcept { const size_type _Masked = _Requested | _ALLOC_MASK; if (_Masked > _Max) { // the mask overflows, settle for max_size() @@ -4250,12 +4551,12 @@ private: return (_STD max)(_Masked, _Old + _Old / 2); } - _NODISCARD size_type _Calculate_growth(const size_type _Requested) const noexcept { + _NODISCARD _CONSTEXPR20_CONTAINER size_type _Calculate_growth(const size_type _Requested) const noexcept { return _Calculate_growth(_Requested, _Mypair._Myval2._Myres, max_size()); } template - basic_string& _Reallocate_for(const size_type _New_size, _Fty _Fn, _ArgTys... _Args) { + _CONSTEXPR20_CONTAINER basic_string& _Reallocate_for(const size_type _New_size, _Fty _Fn, _ArgTys... _Args) { // reallocate to store exactly _New_size elements, new buffer prepared by // _Fn(_New_ptr, _New_size, _Args...) if (_New_size > max_size()) { @@ -4266,22 +4567,36 @@ private: const size_type _New_capacity = _Calculate_growth(_New_size); auto& _Al = _Getal(); const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws + +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once + _Traits::assign(_Unfancy(_New_ptr), _New_capacity + 1, _Elem()); + } +#endif // __cpp_lib_is_constant_evaluated _Mypair._Myval2._Orphan_all(); _Mypair._Myval2._Mysize = _New_size; _Mypair._Myval2._Myres = _New_capacity; _Fn(_Unfancy(_New_ptr), _New_size, _Args...); - if (_BUF_SIZE <= _Old_capacity) { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { _Al.deallocate(_Mypair._Myval2._Bx._Ptr, _Old_capacity + 1); _Mypair._Myval2._Bx._Ptr = _New_ptr; - } else { - _Construct_in_place(_Mypair._Myval2._Bx._Ptr, _New_ptr); + } else +#endif // __cpp_lib_is_constant_evaluated + { + if (_BUF_SIZE <= _Old_capacity) { + _Al.deallocate(_Mypair._Myval2._Bx._Ptr, _Old_capacity + 1); + _Mypair._Myval2._Bx._Ptr = _New_ptr; + } else { + _Construct_in_place(_Mypair._Myval2._Bx._Ptr, _New_ptr); + } } - return *this; } template - basic_string& _Reallocate_grow_by(const size_type _Size_increase, _Fty _Fn, _ArgTys... _Args) { + _CONSTEXPR20_CONTAINER basic_string& _Reallocate_grow_by( + const size_type _Size_increase, _Fty _Fn, _ArgTys... _Args) { // reallocate to increase size by _Size_increase elements, new buffer prepared by // _Fn(_New_ptr, _Old_ptr, _Old_size, _Args...) auto& _My_data = _Mypair._Myval2; @@ -4295,27 +4610,46 @@ private: const size_type _New_capacity = _Calculate_growth(_New_size); auto& _Al = _Getal(); const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws + +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once + _Traits::assign(_Unfancy(_New_ptr), _New_capacity + 1, _Elem()); + } +#endif // __cpp_lib_is_constant_evaluated _My_data._Orphan_all(); _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; _Elem* const _Raw_new = _Unfancy(_New_ptr); - if (_BUF_SIZE <= _Old_capacity) { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { const pointer _Old_ptr = _My_data._Bx._Ptr; _Fn(_Raw_new, _Unfancy(_Old_ptr), _Old_size, _Args...); _Al.deallocate(_Old_ptr, _Old_capacity + 1); _My_data._Bx._Ptr = _New_ptr; - } else { - _Fn(_Raw_new, _My_data._Bx._Buf, _Old_size, _Args...); - _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); + } else +#endif // __cpp_lib_is_constant_evaluated + { + if (_BUF_SIZE <= _Old_capacity) { + const pointer _Old_ptr = _My_data._Bx._Ptr; + _Fn(_Raw_new, _Unfancy(_Old_ptr), _Old_size, _Args...); + _Al.deallocate(_Old_ptr, _Old_capacity + 1); + _My_data._Bx._Ptr = _New_ptr; + } else { + _Fn(_Raw_new, _My_data._Bx._Buf, _Old_size, _Args...); + _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); + } } - return *this; } - void _Become_small() { + _CONSTEXPR20_CONTAINER void _Become_small() { // release any held storage and return to small string mode // pre: *this is in large string mode // pre: this is small enough to return to small string mode +#ifdef __cpp_lib_is_constant_evaluated + _STL_ASSERT(!_STD is_constant_evaluated(), "SSO should be disbaled in a constexpr context"); +#endif // __cpp_lib_is_constant_evaluated + _Mypair._Myval2._Orphan_all(); const pointer _Ptr = _Mypair._Myval2._Bx._Ptr; auto& _Al = _Getal(); @@ -4325,47 +4659,72 @@ private: _Mypair._Myval2._Myres = _BUF_SIZE - 1; } - void _Eos(const size_type _Newsize) { // set new length and null terminator + _CONSTEXPR20_CONTAINER void _Eos(const size_type _Newsize) { // set new length and null terminator _Traits::assign(_Mypair._Myval2._Myptr()[_Mypair._Myval2._Mysize = _Newsize], _Elem()); } - void _Tidy_init() noexcept { // initialize basic_string data members + _CONSTEXPR20_CONTAINER void _Tidy_init() noexcept { // initialize basic_string data members _Mypair._Myval2._Mysize = 0; - _Mypair._Myval2._Myres = _BUF_SIZE - 1; - // the _Traits::assign is last so the codegen doesn't think the char write can alias this - _Traits::assign(_Mypair._Myval2._Bx._Buf[0], _Elem()); + +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + auto& _My_data = _Mypair._Myval2; + _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 // __cpp_lib_is_constant_evaluated + { + _Mypair._Myval2._Myres = _BUF_SIZE - 1; + // the _Traits::assign is last so the codegen doesn't think the char write can alias this + _Traits::assign(_Mypair._Myval2._Bx._Buf[0], _Elem()); + } } - void _Tidy_deallocate() noexcept { // initialize buffer, deallocating any storage + _CONSTEXPR20_CONTAINER void _Tidy_deallocate() noexcept { // initialize buffer, deallocating any storage _Mypair._Myval2._Orphan_all(); - if (_Mypair._Myval2._Large_string_engaged()) { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { const pointer _Ptr = _Mypair._Myval2._Bx._Ptr; auto& _Al = _Getal(); _Destroy_in_place(_Mypair._Myval2._Bx._Ptr); _Al.deallocate(_Ptr, _Mypair._Myval2._Myres + 1); - } + } else +#endif // __cpp_lib_is_constant_evaluated + { + if (_Mypair._Myval2._Large_string_engaged()) { + const pointer _Ptr = _Mypair._Myval2._Bx._Ptr; + auto& _Al = _Getal(); + _Destroy_in_place(_Mypair._Myval2._Bx._Ptr); + _Al.deallocate(_Ptr, _Mypair._Myval2._Myres + 1); + } - _Mypair._Myval2._Mysize = 0; - _Mypair._Myval2._Myres = _BUF_SIZE - 1; - // the _Traits::assign is last so the codegen doesn't think the char write can alias this - _Traits::assign(_Mypair._Myval2._Bx._Buf[0], _Elem()); + _Mypair._Myval2._Mysize = 0; + _Mypair._Myval2._Myres = _BUF_SIZE - 1; + // the _Traits::assign is last so the codegen doesn't think the char write can alias this + _Traits::assign(_Mypair._Myval2._Bx._Buf[0], _Elem()); + } } public: - void _Orphan_all() noexcept { // used by filesystem::path + _CONSTEXPR20_CONTAINER void _Orphan_all() noexcept { // used by filesystem::path _Mypair._Myval2._Orphan_all(); } private: - void _Swap_proxy_and_iterators(basic_string& _Right) { + _CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators(basic_string& _Right) { _Mypair._Myval2._Swap_proxy_and_iterators(_Right._Mypair._Myval2); } - _Alty& _Getal() noexcept { + _CONSTEXPR20_CONTAINER _Alty& _Getal() noexcept { return _Mypair._Get_first(); } - const _Alty& _Getal() const noexcept { + _CONSTEXPR20_CONTAINER const _Alty& _Getal() const noexcept { return _Mypair._Get_first(); } @@ -4390,13 +4749,14 @@ basic_string(basic_string_view<_Elem, _Traits>, _Guide_size_type_t<_Alloc>, _Gui #endif // _HAS_CXX17 template -void swap(basic_string<_Elem, _Traits, _Alloc>& _Left, basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept +_CONSTEXPR20_CONTAINER void swap( + basic_string<_Elem, _Traits, _Alloc>& _Left, basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept /* strengthened */ { _Left.swap(_Right); } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { const auto _Left_size = _Left.size(); const auto _Right_size = _Right.size(); @@ -4408,7 +4768,7 @@ _NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { using _Size_type = typename basic_string<_Elem, _Traits, _Alloc>::size_type; const auto _Left_size = _Convert_size<_Size_type>(_Traits::length(_Left)); @@ -4421,7 +4781,7 @@ _NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( const _Elem _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { const auto _Right_size = _Right.size(); if (_Right_size == _Right.max_size()) { @@ -4432,7 +4792,7 @@ _NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { using _Size_type = typename basic_string<_Elem, _Traits, _Alloc>::size_type; const auto _Left_size = _Left.size(); @@ -4445,7 +4805,7 @@ _NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( const basic_string<_Elem, _Traits, _Alloc>& _Left, const _Elem _Right) { const auto _Left_size = _Left.size(); if (_Left_size == _Left.max_size()) { @@ -4456,19 +4816,19 @@ _NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( const basic_string<_Elem, _Traits, _Alloc>& _Left, basic_string<_Elem, _Traits, _Alloc>&& _Right) { return _STD move(_Right.insert(0, _Left)); } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( basic_string<_Elem, _Traits, _Alloc>&& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { return _STD move(_Left.append(_Right)); } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( basic_string<_Elem, _Traits, _Alloc>&& _Left, basic_string<_Elem, _Traits, _Alloc>&& _Right) { #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(_STD addressof(_Left) != _STD addressof(_Right), @@ -4481,123 +4841,135 @@ _NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( _In_z_ const _Elem* const _Left, basic_string<_Elem, _Traits, _Alloc>&& _Right) { return _STD move(_Right.insert(0, _Left)); } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( const _Elem _Left, basic_string<_Elem, _Traits, _Alloc>&& _Right) { return _STD move(_Right.insert(0, 1, _Left)); } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( basic_string<_Elem, _Traits, _Alloc>&& _Left, _In_z_ const _Elem* const _Right) { return _STD move(_Left.append(_Right)); } template -_NODISCARD basic_string<_Elem, _Traits, _Alloc> operator+( +_NODISCARD _CONSTEXPR20_CONTAINER basic_string<_Elem, _Traits, _Alloc> operator+( basic_string<_Elem, _Traits, _Alloc>&& _Left, const _Elem _Right) { _Left.push_back(_Right); return _STD move(_Left); } template -_NODISCARD bool operator==( +_NODISCARD _CONSTEXPR20_CONTAINER bool operator==( const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { return _Left._Equal(_Right); } template -_NODISCARD bool operator==(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator==( + _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { return _Right._Equal(_Left); } template -_NODISCARD bool operator==(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator==( + const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { return _Left._Equal(_Right); } template -_NODISCARD bool operator!=( +_NODISCARD _CONSTEXPR20_CONTAINER bool operator!=( const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { return !(_Left == _Right); } template -_NODISCARD bool operator!=(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator!=( + _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { return !(_Left == _Right); } template -_NODISCARD bool operator!=(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator!=( + const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { return !(_Left == _Right); } template -_NODISCARD bool operator<( +_NODISCARD _CONSTEXPR20_CONTAINER bool operator<( const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { return _Left.compare(_Right) < 0; } template -_NODISCARD bool operator<(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator<( + _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { return _Right.compare(_Left) > 0; } template -_NODISCARD bool operator<(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator<( + const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { return _Left.compare(_Right) < 0; } template -_NODISCARD bool operator>( +_NODISCARD _CONSTEXPR20_CONTAINER bool operator>( const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { return _Right < _Left; } template -_NODISCARD bool operator>(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator>( + _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { return _Right < _Left; } template -_NODISCARD bool operator>(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator>( + const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { return _Right < _Left; } template -_NODISCARD bool operator<=( +_NODISCARD _CONSTEXPR20_CONTAINER bool operator<=( const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { return !(_Right < _Left); } template -_NODISCARD bool operator<=(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator<=( + _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { return !(_Right < _Left); } template -_NODISCARD bool operator<=(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator<=( + const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { return !(_Right < _Left); } template -_NODISCARD bool operator>=( +_NODISCARD _CONSTEXPR20_CONTAINER bool operator>=( const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) noexcept { return !(_Left < _Right); } template -_NODISCARD bool operator>=(_In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator>=( + _In_z_ const _Elem* const _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { return !(_Left < _Right); } template -_NODISCARD bool operator>=(const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { +_NODISCARD _CONSTEXPR20_CONTAINER bool operator>=( + const basic_string<_Elem, _Traits, _Alloc>& _Left, _In_z_ const _Elem* const _Right) { return !(_Left < _Right); } @@ -4685,25 +5057,25 @@ basic_ostream<_Elem, _Traits>& operator<<( // basic_string LITERALS inline namespace literals { inline namespace string_literals { - _NODISCARD inline string operator"" s(const char* _Str, size_t _Len) { + _NODISCARD _CONSTEXPR20_CONTAINER string operator"" s(const char* _Str, size_t _Len) { return string(_Str, _Len); } - _NODISCARD inline wstring operator"" s(const wchar_t* _Str, size_t _Len) { + _NODISCARD _CONSTEXPR20_CONTAINER wstring operator"" s(const wchar_t* _Str, size_t _Len) { return wstring(_Str, _Len); } #ifdef __cpp_char8_t - _NODISCARD inline basic_string operator"" s(const char8_t* _Str, size_t _Len) { + _NODISCARD _CONSTEXPR20_CONTAINER basic_string operator"" s(const char8_t* _Str, size_t _Len) { return basic_string(_Str, _Len); } #endif // __cpp_char8_t - _NODISCARD inline u16string operator"" s(const char16_t* _Str, size_t _Len) { + _NODISCARD _CONSTEXPR20_CONTAINER u16string operator"" s(const char16_t* _Str, size_t _Len) { return u16string(_Str, _Len); } - _NODISCARD inline u32string operator"" s(const char32_t* _Str, size_t _Len) { + _NODISCARD _CONSTEXPR20_CONTAINER u32string operator"" s(const char32_t* _Str, size_t _Len) { return u32string(_Str, _Len); } } // namespace string_literals @@ -4711,13 +5083,13 @@ inline namespace literals { #if _HAS_CXX20 template -typename basic_string<_Elem, _Traits, _Alloc>::size_type erase( +_CONSTEXPR20_CONTAINER typename basic_string<_Elem, _Traits, _Alloc>::size_type erase( basic_string<_Elem, _Traits, _Alloc>& _Cont, const _Uty& _Val) { return _Erase_remove(_Cont, _Val); } template -typename basic_string<_Elem, _Traits, _Alloc>::size_type erase_if( +_CONSTEXPR20_CONTAINER typename basic_string<_Elem, _Traits, _Alloc>::size_type erase_if( basic_string<_Elem, _Traits, _Alloc>& _Cont, _Pr _Pred) { return _Erase_remove_if(_Cont, _Pass_fn(_Pred)); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 72b2d93e095..be3d504cc40 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -177,6 +177,7 @@ // P0912R5 Library Support For Coroutines // P0919R3 Heterogeneous Lookup For Unordered Containers // P0966R1 string::reserve() Should Not Shrink +// P0980R1 constexpr std::string // P1001R2 execution::unseq // P1006R1 constexpr For pointer_traits::pointer_to() // P1007R3 assume_aligned() @@ -1187,10 +1188,15 @@ #define __cpp_lib_constexpr_dynamic_alloc 201907L #endif // __cpp_constexpr_dynamic_alloc -#define __cpp_lib_constexpr_functional 201907L -#define __cpp_lib_constexpr_iterator 201811L -#define __cpp_lib_constexpr_memory 201811L -#define __cpp_lib_constexpr_numeric 201911L +#define __cpp_lib_constexpr_functional 201907L +#define __cpp_lib_constexpr_iterator 201811L +#define __cpp_lib_constexpr_memory 201811L +#define __cpp_lib_constexpr_numeric 201911L + +#if defined(__cpp_constexpr_dynamic_alloc) && !defined(__clang__) // TRANSITION, LLVM-48606 +#define __cpp_lib_constexpr_string 201907L +#endif // __cpp_constexpr_dynamic_alloc && !__clang__ + #define __cpp_lib_constexpr_string_view 201811L #define __cpp_lib_constexpr_tuple 201811L #define __cpp_lib_constexpr_utility 201811L diff --git a/tests/std/include/test_death.hpp b/tests/std/include/test_death.hpp index 943b0f28a02..296a0f69012 100644 --- a/tests/std/include/test_death.hpp +++ b/tests/std/include/test_death.hpp @@ -79,9 +79,16 @@ namespace std_testing { // buffer was not big enough const size_t str_max_size = result.max_size(); const size_t result_max_size = str_max_size - str_max_size / 2; +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" +#endif // __clang__ if (result_size >= result_max_size) { api_unexpected("GetModuleFileNameW"); } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ result.resize(result_size + result_size / 2); } else if (result_size == 0) { diff --git a/tests/std/test.lst b/tests/std/test.lst index 014d2c798d4..3e777d63dab 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -370,6 +370,7 @@ tests\P0898R3_identity tests\P0912R5_coroutine tests\P0919R3_heterogeneous_unordered_lookup tests\P0966R1_string_reserve_should_not_shrink +tests\P0980R1_constexpr_strings tests\P1007R3_assume_aligned tests\P1020R1_smart_pointer_for_overwrite tests\P1023R0_constexpr_for_array_comparisons diff --git a/tests/std/tests/P0980R1_constexpr_strings/env.lst b/tests/std/tests/P0980R1_constexpr_strings/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0980R1_constexpr_strings/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp new file mode 100644 index 00000000000..11b3b8345f8 --- /dev/null +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -0,0 +1,1614 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma warning(disable : 4389) // signed/unsigned mismatch in arithmetic + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wsign-compare" +#endif // __clang__ + +#include +#include +#include +#include +#include + +using namespace std; + +static constexpr auto literal_input = "Hello fluffy kittens"; +static constexpr auto literal_input_u16 = u"Hello fluffy kittens"; +static constexpr auto literal_input_u32 = U"Hello fluffy kittens"; +static constexpr auto literal_input_w = L"Hello fluffy kittens"; + +static constexpr auto view_input = "Hello fluffy kittens"sv; +static constexpr auto view_input_u16 = u"Hello fluffy kittens"sv; +static constexpr auto view_input_u32 = U"Hello fluffy kittens"sv; +static constexpr auto view_input_w = L"Hello fluffy kittens"sv; + +#ifdef __cpp_char8_t +static constexpr auto literal_input_u8 = u8"Hello fluffy kittens"; +static constexpr auto view_input_u8 = u8"Hello fluffy kittens"sv; +#endif // __cpp_char8_t + +template +constexpr auto get_literal_input() { + if constexpr (is_same_v) { + return literal_input; +#ifdef __cpp_char8_t + } else if constexpr (is_same_v) { + return literal_input_u8; +#endif // __cpp_char8_t + } else if constexpr (is_same_v) { + return literal_input_u16; + } else if constexpr (is_same_v) { + return literal_input_u32; + } else { + return literal_input_w; + } +} + +template +constexpr auto get_view_input() { + if constexpr (is_same_v) { + return view_input; +#ifdef __cpp_char8_t + } else if constexpr (is_same_v) { + return view_input_u8; +#endif // __cpp_char8_t + } else if constexpr (is_same_v) { + return view_input_u16; + } else if constexpr (is_same_v) { + return view_input_u32; + } else { + return view_input_w; + } +} + +template +constexpr auto get_cat() { + if constexpr (is_same_v) { + return "kitten"; +#ifdef __cpp_char8_t + } else if constexpr (is_same_v) { + return u8"kitten"; +#endif // __cpp_char8_t + } else if constexpr (is_same_v) { + return u"kitten"; + } else if constexpr (is_same_v) { + return U"kitten"; + } else { + return L"kitten"; + } +} + +template +constexpr auto get_dog() { + if constexpr (is_same_v) { + return "dog"; +#ifdef __cpp_char8_t + } else if constexpr (is_same_v) { + return u8"dog"; +#endif // __cpp_char8_t + } else if constexpr (is_same_v) { + return u"dog"; + } else if constexpr (is_same_v) { + return U"dog"; + } else { + return L"dog"; + } +} + +template +constexpr auto get_no_needle() { + if constexpr (is_same_v) { + return "vxz"; +#ifdef __cpp_char8_t + } else if constexpr (is_same_v) { + return u8"vxz"; +#endif // __cpp_char8_t + } else if constexpr (is_same_v) { + return u"vxz"; + } else if constexpr (is_same_v) { + return U"vxz"; + } else { + return L"vxz"; + } +} + +template +struct string_view_convertible { + _CONSTEXPR20_CONTAINER operator basic_string_view() const { + if constexpr (is_same_v) { + return view_input; +#ifdef __cpp_char8_t + } else if constexpr (is_same_v) { + return view_input_u8; +#endif // __cpp_char8_t + } else if constexpr (is_same_v) { + return view_input_u16; + } else if constexpr (is_same_v) { + return view_input_u32; + } else { + return view_input_w; + } + } +}; + +template +_CONSTEXPR20_CONTAINER bool test_interface() { + using str = basic_string; + using ranges::equal; + { // constructors + // range constructors + str literal_constructed{get_literal_input()}; + assert(equal(literal_constructed, get_view_input())); + + str view_constructed(get_view_input()); + assert(equal(view_constructed, literal_constructed)); + + str initializer_list_constructed({'m', 'e', 'o', 'w'}); + assert(equal(initializer_list_constructed, "meow"sv)); + + // special member functions + str default_constructed; + str copy_constructed(literal_constructed); + assert(equal(copy_constructed, literal_constructed)); + + str move_constructed(move(copy_constructed)); + assert(equal(move_constructed, literal_constructed)); + assert(copy_constructed.empty()); + + str copy_assigned = literal_constructed; + assert(equal(copy_assigned, literal_constructed)); + + str move_assigned = std::move(copy_assigned); + assert(equal(move_assigned, literal_constructed)); + assert(copy_constructed.empty()); + + // Other constructors + str size_value_constructed(5, CharType{'a'}); + assert(equal(size_value_constructed, "aaaaa"sv)); + + str copy_start_constructed(literal_constructed, 2); + assert(equal(copy_start_constructed, "llo fluffy kittens"sv)); + + str copy_start_length_constructed(literal_constructed, 2, 3); + assert(equal(copy_start_length_constructed, "llo"sv)); + + str ptr_size_constructed(get_literal_input(), 2); + assert(equal(ptr_size_constructed, "He"sv)); + + str iterator_constructed(literal_constructed.begin(), literal_constructed.end()); + assert(equal(iterator_constructed, literal_constructed)); + + const string_view_convertible convertible; + str conversion_constructed(convertible); + assert(equal(conversion_constructed, literal_constructed)); + + str conversion_size_constructed(convertible, 2, 3); + assert(equal(conversion_size_constructed, "llo"sv)); + } + + { // allocator constructors + allocator alloc; + + // range constructors + str literal_constructed{get_literal_input(), alloc}; + assert(equal(literal_constructed, get_view_input())); + + str view_constructed{get_view_input(), alloc}; + assert(equal(view_constructed, literal_constructed)); + + str initializer_list_constructed({'m', 'e', 'o', 'w'}, alloc); + assert(equal(initializer_list_constructed, "meow"sv)); + + // special member functions + str default_constructed{alloc}; + str copy_constructed{literal_constructed, alloc}; + assert(equal(copy_constructed, literal_constructed)); + + str move_constructed{move(copy_constructed), alloc}; + assert(equal(move_constructed, literal_constructed)); + assert(copy_constructed.empty()); + + // Other constructors + str size_value_constructed(5, CharType{'a'}, alloc); + assert(equal(size_value_constructed, "aaaaa"sv)); + + str copy_start_constructed(literal_constructed, 2, alloc); + assert(equal(copy_start_constructed, "llo fluffy kittens"sv)); + + str copy_start_length_constructed(literal_constructed, 2, 3, alloc); + assert(equal(copy_start_length_constructed, "llo"sv)); + + str ptr_size_constructed(get_literal_input(), 2, alloc); + assert(equal(ptr_size_constructed, "He"sv)); + + str iterator_constructed(literal_constructed.begin(), literal_constructed.end(), alloc); + assert(equal(iterator_constructed, literal_constructed)); + + const string_view_convertible convertible; + str conversion_constructed(convertible, alloc); + assert(equal(conversion_constructed, literal_constructed)); + + str conversion_size_constructed(convertible, 2, 3, alloc); + assert(equal(conversion_size_constructed, "llo"sv)); + } + + { // assignment operator + str literal_constructed = get_literal_input(); + + str copy_assigned; + copy_assigned = literal_constructed; + assert(equal(copy_assigned, literal_constructed)); + + str move_assigned; + move_assigned = move(copy_assigned); + assert(equal(move_assigned, literal_constructed)); + assert(copy_assigned.empty()); + + str literal_assigned; + literal_assigned = get_literal_input(); + assert(equal(literal_assigned, literal_constructed)); + + str char_assigned; + char_assigned = CharType{'!'}; + assert(equal(char_assigned, "!"sv)); + + str initializer_list_constructed; + initializer_list_constructed = {'m', 'e', 'o', 'w'}; + assert(equal(initializer_list_constructed, "meow"sv)); + + const string_view_convertible convertible; + str conversion_assigned; + conversion_assigned = convertible; + assert(equal(conversion_assigned, literal_constructed)); + } + + { // assign + str literal_constructed = get_literal_input(); + + str assign_char_size; + assign_char_size.assign(5, CharType{'a'}); + assert(equal(assign_char_size, "aaaaa"sv)); + + str assign_str; + assign_str.assign(literal_constructed); + assert(equal(assign_str, literal_constructed)); + + str assign_str_pos; + assign_str_pos.assign(literal_constructed, 2); + assert(equal(assign_str_pos, "llo fluffy kittens"sv)); + + str assign_str_pos_len; + assign_str_pos_len.assign(literal_constructed, 2, 3); + assert(equal(assign_str_pos_len, "llo"sv)); + + str assign_moved_str; + assign_moved_str.assign(move(assign_str_pos_len)); + assert(equal(assign_moved_str, "llo"sv)); + assert(assign_str_pos_len.empty()); + + str assign_literal; + assign_literal.assign(get_literal_input()); + assert(equal(assign_literal, literal_constructed)); + + str assign_literal_count; + assign_literal_count.assign(get_literal_input(), 2); + assert(equal(assign_literal_count, "He"sv)); + + str assign_iterator; + assign_iterator.assign(begin(get_view_input()), end(get_view_input())); + assert(equal(assign_iterator, get_view_input())); + + str assign_initializer; + assign_initializer.assign({'m', 'e', 'o', 'w'}); + assert(equal(assign_initializer, "meow"sv)); + + const string_view_convertible convertible; + str assign_conversion; + assign_conversion.assign(convertible); + assert(equal(assign_conversion, literal_constructed)); + + str assign_conversion_size; + assign_conversion_size.assign(convertible, 2, 3); + assert(equal(assign_conversion_size, "llo"sv)); + } + + { // allocator + str default_constructed; + [[maybe_unused]] const auto alloc = default_constructed.get_allocator(); + static_assert(is_same_v, allocator>); + } + + { // access + str literal_constructed = get_literal_input(); + const str const_literal_constructed = get_literal_input(); + + const auto at = literal_constructed.at(2); + static_assert(is_same_v, CharType>); + assert(at == CharType{'l'}); + + literal_constructed.at(2) = CharType{'v'}; + + const auto at2 = literal_constructed.at(2); + static_assert(is_same_v, CharType>); + assert(at2 == CharType{'v'}); + + const auto cat = const_literal_constructed.at(2); + static_assert(is_same_v, CharType>); + assert(cat == CharType{'l'}); + + const auto op = literal_constructed[3]; + static_assert(is_same_v, CharType>); + assert(op == CharType{'l'}); + + literal_constructed[3] = CharType{'u'}; + const auto op2 = literal_constructed[3]; + static_assert(is_same_v, CharType>); + assert(op2 == CharType{'u'}); + + const auto cop = const_literal_constructed[3]; + static_assert(is_same_v, CharType>); + assert(cop == CharType{'l'}); + + const auto f = literal_constructed.front(); + static_assert(is_same_v, CharType>); + assert(f == CharType{'H'}); + + const auto cf = const_literal_constructed.front(); + static_assert(is_same_v, CharType>); + assert(cf == CharType{'H'}); + + const auto b = literal_constructed.back(); + static_assert(is_same_v, CharType>); + assert(b == CharType{'s'}); + + const auto cb = const_literal_constructed.back(); + static_assert(is_same_v, CharType>); + assert(cb == CharType{'s'}); + + const auto d = literal_constructed.data(); + static_assert(is_same_v); + assert(*d == CharType{'H'}); + + const auto cd = const_literal_constructed.data(); + static_assert(is_same_v); + assert(*cd == CharType{'H'}); + + const auto cs = literal_constructed.c_str(); + static_assert(is_same_v); + assert(cs == literal_constructed.data()); + assert(char_traits::length(cs) == literal_constructed.size()); + } + + { // iterators + str literal_constructed = get_literal_input(); + const str const_literal_constructed = get_literal_input(); + + const auto b = literal_constructed.begin(); + static_assert(is_same_v, typename str::iterator>); + assert(*b == CharType{'H'}); + + const auto cb = literal_constructed.cbegin(); + static_assert(is_same_v, typename str::const_iterator>); + assert(*cb == CharType{'H'}); + + const auto cb2 = const_literal_constructed.begin(); + static_assert(is_same_v, typename str::const_iterator>); + assert(*cb2 == CharType{'H'}); + + const auto e = literal_constructed.end(); + static_assert(is_same_v, typename str::iterator>); + assert(*prev(e) == CharType{'s'}); + + const auto ce = literal_constructed.cend(); + static_assert(is_same_v, typename str::const_iterator>); + assert(*prev(ce) == CharType{'s'}); + + const auto ce2 = const_literal_constructed.end(); + static_assert(is_same_v, typename str::const_iterator>); + assert(*prev(ce2) == CharType{'s'}); + + const auto rb = literal_constructed.rbegin(); + static_assert(is_same_v, reverse_iterator>); + assert(*rb == CharType{'s'}); + + const auto crb = literal_constructed.crbegin(); + static_assert(is_same_v, reverse_iterator>); + assert(*crb == CharType{'s'}); + + const auto crb2 = const_literal_constructed.rbegin(); + static_assert(is_same_v, reverse_iterator>); + assert(*crb2 == CharType{'s'}); + + const auto re = literal_constructed.rend(); + static_assert(is_same_v, reverse_iterator>); + assert(*prev(re) == CharType{'H'}); + + const auto cre = literal_constructed.crend(); + static_assert(is_same_v, reverse_iterator>); + assert(*prev(cre) == CharType{'H'}); + + const auto cre2 = const_literal_constructed.rend(); + static_assert(is_same_v, reverse_iterator>); + assert(*prev(cre2) == CharType{'H'}); + } + + { // capacity + str literal_constructed = get_literal_input(); + + const auto e = literal_constructed.empty(); + static_assert(is_same_v, bool>); + assert(!e); + + const auto s = literal_constructed.size(); + static_assert(is_same_v, std::size_t>); + assert(s == size(get_view_input())); + + const auto ms = literal_constructed.max_size(); + static_assert(is_same_v, std::size_t>); + if constexpr (is_same_v || is_same_v || is_same_v) { + assert(ms == static_cast(-1) / sizeof(CharType) - 1); + } else { + assert(ms == static_cast(-1) / 2); + } + + literal_constructed.reserve(20); + + const auto c = literal_constructed.capacity(); + static_assert(is_same_v, std::size_t>); + if constexpr (is_same_v || is_same_v || is_same_v) { + assert(c == 23); + } else { + assert(c == 31); + } + + literal_constructed.shrink_to_fit(); + + const auto c2 = literal_constructed.capacity(); + static_assert(is_same_v, std::size_t>); + if constexpr (is_same_v || is_same_v || is_same_v) { + assert(c2 == 23); + } else { + assert(c2 == 31); + } + } + + { // clear + str cleared = get_literal_input(); + cleared.clear(); + assert(cleared.empty()); + assert(cleared.capacity() == str(get_literal_input()).capacity()); + } + + { // insert + str insert_char = get_literal_input(); + const CharType to_be_inserted = CharType{','}; + insert_char.insert(insert_char.begin() + 5, to_be_inserted); + assert(equal(insert_char, "Hello, fluffy kittens"sv)); + + str insert_const_char = get_literal_input(); + insert_const_char.insert(insert_const_char.cbegin() + 5, to_be_inserted); + assert(equal(insert_const_char, "Hello, fluffy kittens"sv)); + + str insert_char_rvalue = get_literal_input(); + insert_char_rvalue.insert(insert_char_rvalue.begin() + 5, CharType{','}); + assert(equal(insert_char_rvalue, "Hello, fluffy kittens"sv)); + + str insert_const_char_rvalue = get_literal_input(); + insert_const_char_rvalue.insert(insert_const_char_rvalue.cbegin() + 5, CharType{','}); + assert(equal(insert_const_char_rvalue, "Hello, fluffy kittens"sv)); + + str insert_range(2, CharType{'b'}); + const auto it = insert_range.insert( + insert_range.begin() + 1, begin(get_view_input()), end(get_view_input())); + assert(it == insert_range.begin() + 1); + assert(equal(insert_range, "bHello fluffy kittensb"sv)); + + str insert_const_range(2, CharType{'b'}); + const auto cit = insert_const_range.insert( + insert_const_range.cbegin() + 1, begin(get_view_input()), end(get_view_input())); + assert(cit == insert_const_range.cbegin() + 1); + assert(equal(insert_const_range, "bHello fluffy kittensb"sv)); + + str insert_initializer = get_literal_input(); + const auto it_ilist = insert_initializer.insert(insert_initializer.begin() + 6, {'c', 'u', 't', 'e', ' '}); + assert(it_ilist == insert_initializer.begin() + 6); + assert(equal(insert_initializer, "Hello cute fluffy kittens"sv)); + + str insert_const_initializer = get_literal_input(); + const auto cit_ilist = + insert_const_initializer.insert(insert_const_initializer.cbegin() + 6, {'c', 'u', 't', 'e', ' '}); + assert(cit_ilist == insert_const_initializer.cbegin() + 6); + assert(equal(insert_const_initializer, "Hello cute fluffy kittens"sv)); + } + + { // erase + str erase_pos_count = get_literal_input(); + erase_pos_count.erase(0, 6); + assert(equal(erase_pos_count, "fluffy kittens"sv)); + + str erase_iter = get_literal_input(); + erase_iter.erase(erase_iter.begin()); + assert(equal(erase_iter, "ello fluffy kittens"sv)); + + str erase_const_iter = get_literal_input(); + erase_const_iter.erase(erase_const_iter.cbegin()); + assert(equal(erase_const_iter, "ello fluffy kittens"sv)); + + str erase_iter_iter = get_literal_input(); + erase_iter_iter.erase(erase_iter_iter.begin(), erase_iter_iter.begin() + 6); + assert(equal(erase_iter_iter, "fluffy kittens"sv)); + + str erase_const_iter_iter = get_literal_input(); + erase_const_iter_iter.erase(erase_const_iter_iter.cbegin(), erase_const_iter_iter.cbegin() + 6); + assert(equal(erase_const_iter_iter, "fluffy kittens"sv)); + + str erased_free = get_literal_input(); + erase(erased_free, CharType{'l'}); + assert(equal(erased_free, "Heo fuffy kittens"sv)); + + str erased_free_if = get_literal_input(); + erase_if(erased_free_if, [](const CharType val) { return val == CharType{'t'}; }); + assert(equal(erased_free_if, "Hello fluffy kiens"sv)); + } + + { // push_back / pop_back + str pushed; + pushed.push_back('y'); + assert(pushed.size() == 1); + assert(pushed.back() == CharType{'y'}); + + const CharType to_be_pushed = CharType{'z'}; + pushed.push_back(to_be_pushed); + assert(pushed.size() == 2); + assert(pushed.back() == CharType{'z'}); + + pushed.pop_back(); + assert(pushed.size() == 1); + assert(pushed.back() == CharType{'y'}); + } + + { // append + const str literal_constructed = get_literal_input(); + + str append_char_size(2, CharType{'b'}); + append_char_size.append(5, CharType{'a'}); + assert(equal(append_char_size, "bbaaaaa"sv)); + + str append_str(2, CharType{'b'}); + append_str.append(literal_constructed); + assert(equal(append_str, "bbHello fluffy kittens"sv)); + + str append_str_pos(2, CharType{'b'}); + append_str_pos.append(literal_constructed, 2); + assert(equal(append_str_pos, "bbllo fluffy kittens"sv)); + + str append_str_pos_len(2, CharType{'b'}); + append_str_pos_len.append(literal_constructed, 2, 3); + assert(equal(append_str_pos_len, "bbllo"sv)); + + str append_literal(2, CharType{'b'}); + append_literal.append(get_literal_input()); + assert(equal(append_literal, "bbHello fluffy kittens"sv)); + + str append_literal_count(2, CharType{'b'}); + append_literal_count.append(get_literal_input(), 2); + assert(equal(append_literal_count, "bbHe"sv)); + + str append_iterator(2, CharType{'b'}); + append_iterator.append(begin(get_view_input()), end(get_view_input())); + assert(equal(append_iterator, "bbHello fluffy kittens"sv)); + + str append_initializer(2, CharType{'b'}); + append_initializer.append({'m', 'e', 'o', 'w'}); + assert(equal(append_initializer, "bbmeow"sv)); + + const string_view_convertible convertible; + str append_conversion(2, CharType{'b'}); + append_conversion.append(convertible); + assert(equal(append_conversion, "bbHello fluffy kittens"sv)); + + str append_conversion_size(2, CharType{'b'}); + append_conversion_size.append(convertible, 2, 3); + assert(equal(append_conversion_size, "bbllo"sv)); + } + + { // operator+= + str literal_constructed = get_literal_input(); + + str plus_string(2, CharType{'b'}); + plus_string += literal_constructed; + assert(equal(plus_string, "bbHello fluffy kittens"sv)); + + str plus_character(2, CharType{'b'}); + plus_character += 'a'; + assert(equal(plus_character, "bba"sv)); + + str plus_literal(2, CharType{'b'}); + plus_literal += get_literal_input(); + assert(equal(plus_literal, "bbHello fluffy kittens"sv)); + + str plus_initializer(2, CharType{'b'}); + plus_initializer += {'m', 'e', 'o', 'w'}; + assert(equal(plus_initializer, "bbmeow"sv)); + + const string_view_convertible convertible; + str plus_conversion(2, CharType{'b'}); + plus_conversion += convertible; + assert(equal(plus_conversion, "bbHello fluffy kittens"sv)); + } + + { // compare + const str first = get_literal_input(); + const str second = get_cat(); + + const int comp_str_eq = first.compare(first); + assert(comp_str_eq == 0); + + const int comp_str_less = first.compare(second); + assert(comp_str_less == -1); + + const int comp_str_greater = second.compare(first); + assert(comp_str_greater == 1); + + const int comp_pos_count_str_eq = first.compare(3, 7, first.substr(3, 7)); + assert(comp_pos_count_str_eq == 0); + + const int comp_pos_count_str_less = first.compare(0, 2, second); + assert(comp_pos_count_str_less == -1); + + const int comp_pos_count_str_greater = second.compare(0, 2, first); + assert(comp_pos_count_str_greater == 1); + + const int comp_pos_count_str_pos_eq = first.compare(3, 20, first, 3); + assert(comp_pos_count_str_pos_eq == 0); + + const int comp_pos_count_str_pos_less = first.compare(0, 2, second, 2); + assert(comp_pos_count_str_pos_less == -1); + + const int comp_pos_count_str_pos_greater = second.compare(0, 2, first, 6); + assert(comp_pos_count_str_pos_greater == 1); + + const int comp_pos_count_str_pos_count_eq = first.compare(3, 5, first, 3, 5); + assert(comp_pos_count_str_pos_count_eq == 0); + + const int comp_pos_count_str_pos_count_less = first.compare(0, 2, second, 2, 3); + assert(comp_pos_count_str_pos_count_less == -1); + + const int comp_pos_count_str_pos_count_greater = second.compare(0, 2, first, 6, 4); + assert(comp_pos_count_str_pos_count_greater == 1); + + const int comp_literal_eq = first.compare(get_literal_input()); + assert(comp_literal_eq == 0); + + const int comp_literal_less = first.compare(get_cat()); + assert(comp_literal_less == -1); + + const int comp_literal_greater = second.compare(get_literal_input()); + assert(comp_literal_greater == 1); + + const int comp_pos_count_literal_eq = first.compare(13, 6, get_cat()); + assert(comp_pos_count_literal_eq == 0); + + const int comp_pos_count_literal_less = first.compare(0, 2, get_cat()); + assert(comp_pos_count_literal_less == -1); + + const int comp_pos_count_literal_greater = second.compare(0, 2, get_literal_input()); + assert(comp_pos_count_literal_greater == 1); + + const int comp_pos_count_literal_count_eq = first.compare(13, 5, get_cat(), 5); + assert(comp_pos_count_literal_count_eq == 0); + + const int comp_pos_count_literal_count_less = first.compare(0, 2, get_cat(), 2); + assert(comp_pos_count_literal_count_less == -1); + + const int comp_pos_count_literal_count_greater = second.compare(0, 2, get_literal_input(), 6); + assert(comp_pos_count_literal_count_greater == 1); + + const int comp_pos_count_literal_pos_count_eq = first.compare(3, 5, get_literal_input(), 3, 5); + assert(comp_pos_count_literal_pos_count_eq == 0); + + const int comp_pos_count_literal_pos_count_less = first.compare(0, 2, get_cat(), 2, 3); + assert(comp_pos_count_literal_pos_count_less == -1); + + const int comp_pos_count_literal_pos_count_greater = second.compare(0, 2, get_literal_input(), 6, 4); + assert(comp_pos_count_literal_pos_count_greater == 1); + + const string_view_convertible convertible; + const int comp_conversion_eq = first.compare(convertible); + assert(comp_conversion_eq == 0); + + const int comp_conversion_less = first.compare(second); + assert(comp_conversion_less == -1); + + const int comp_conversion_greater = second.compare(convertible); + assert(comp_conversion_greater == 1); + + const int comp_pos_count_conversion_eq = first.compare(0, 20, convertible); + assert(comp_pos_count_conversion_eq == 0); + + const int comp_pos_count_conversion_less = first.compare(5, 4, convertible); + assert(comp_pos_count_conversion_less == -1); + + const int comp_pos_count_conversion_greater = second.compare(0, 2, convertible); + assert(comp_pos_count_conversion_greater == 1); + + const int comp_pos_count_conversion_pos_eq = first.compare(3, 20, convertible, 3); + assert(comp_pos_count_conversion_pos_eq == 0); + + const int comp_pos_count_conversion_pos_less = first.compare(0, 2, second, 2); + assert(comp_pos_count_conversion_pos_less == -1); + + const int comp_pos_count_conversion_pos_greater = second.compare(0, 2, convertible, 6); + assert(comp_pos_count_conversion_pos_greater == 1); + + const int comp_pos_count_conversion_pos_count_eq = first.compare(3, 5, convertible, 3, 5); + assert(comp_pos_count_conversion_pos_count_eq == 0); + + const int comp_pos_count_conversion_pos_count_less = first.compare(0, 2, second, 2, 3); + assert(comp_pos_count_conversion_pos_count_less == -1); + + const int comp_pos_count_conversion_pos_count_greater = second.compare(0, 2, convertible, 6, 4); + assert(comp_pos_count_conversion_pos_count_greater == 1); + } + + { // starts_with + const str starts = get_literal_input(); + const str input_string_true = starts.substr(0, 5); + assert(starts.starts_with(input_string_true)); + + const str input_string_false = get_cat(); + assert(!starts.starts_with(input_string_false)); + + assert(starts.starts_with('H')); + assert(!starts.starts_with('h')); + + assert(starts.starts_with(get_literal_input())); + assert(!input_string_false.starts_with(get_literal_input())); + } + + { // ends_with + const str ends = get_literal_input(); + const str input_string_true = ends.substr(5); + assert(ends.ends_with(input_string_true)); + + const str input_string_false = get_cat(); + assert(!ends.ends_with(input_string_false)); + + assert(ends.ends_with('s')); + assert(!ends.ends_with('S')); + + assert(ends.ends_with(get_literal_input())); + assert(!input_string_false.ends_with(get_literal_input())); + } + + { // replace + const str input = get_dog(); + + str replaced_pos_count_str = get_literal_input(); + replaced_pos_count_str.replace(13, 7, input); + assert(equal(replaced_pos_count_str, "Hello fluffy dog"sv)); + + str replaced_pos_count_str_shift = get_literal_input(); + replaced_pos_count_str_shift.replace(13, 2, input); + assert(equal(replaced_pos_count_str_shift, "Hello fluffy dogttens"sv)); + + str replaced_iter_str = get_literal_input(); + replaced_iter_str.replace(replaced_iter_str.cbegin() + 13, replaced_iter_str.cend(), input); + assert(equal(replaced_iter_str, "Hello fluffy dog"sv)); + + str replaced_iter_str_shift = get_literal_input(); + replaced_iter_str_shift.replace( + replaced_iter_str_shift.cbegin() + 13, replaced_iter_str_shift.cbegin() + 15, input); + assert(equal(replaced_iter_str_shift, "Hello fluffy dogttens"sv)); + + str replaced_pos_count_str_pos_count = get_literal_input(); + replaced_pos_count_str_pos_count.replace(13, 7, input, 1); + assert(equal(replaced_pos_count_str_pos_count, "Hello fluffy og"sv)); + + str replaced_pos_count_str_pos_count_less = get_literal_input(); + replaced_pos_count_str_pos_count_less.replace(13, 2, input, 1, 2); + assert(equal(replaced_pos_count_str_pos_count_less, "Hello fluffy ogttens"sv)); + + str replaced_iter_iter = get_literal_input(); + replaced_iter_iter.replace( + replaced_iter_iter.cbegin() + 13, replaced_iter_iter.cend(), input.begin(), input.end()); + assert(equal(replaced_iter_iter, "Hello fluffy dog"sv)); + + str replaced_iter_iter_less = get_literal_input(); + replaced_iter_iter_less.replace(replaced_iter_iter_less.cbegin() + 13, replaced_iter_iter_less.cbegin() + 15, + input.begin() + 1, input.end()); + assert(equal(replaced_iter_iter_less, "Hello fluffy ogttens"sv)); + + str replaced_pos_count_literal = get_literal_input(); + replaced_pos_count_literal.replace(13, 2, get_dog()); + assert(equal(replaced_pos_count_literal, "Hello fluffy dogttens"sv)); + + str replaced_pos_count_literal_count = get_literal_input(); + replaced_pos_count_literal_count.replace(13, 2, get_dog(), 2); + assert(equal(replaced_pos_count_literal_count, "Hello fluffy dottens"sv)); + + str replaced_iter_literal = get_literal_input(); + replaced_iter_literal.replace( + replaced_iter_literal.cbegin() + 13, replaced_iter_literal.cbegin() + 15, get_dog()); + assert(equal(replaced_iter_literal, "Hello fluffy dogttens"sv)); + + str replaced_iter_literal_count = get_literal_input(); + replaced_iter_literal_count.replace(replaced_iter_literal_count.cbegin() + 13, + replaced_iter_literal_count.cbegin() + 15, get_dog(), 2); + assert(equal(replaced_iter_literal_count, "Hello fluffy dottens"sv)); + + str replaced_pos_count_chars = get_literal_input(); + replaced_pos_count_chars.replace(13, 2, 5, 'a'); + assert(equal(replaced_pos_count_chars, "Hello fluffy aaaaattens"sv)); + + str replaced_iter_chars = get_literal_input(); + replaced_iter_chars.replace(replaced_iter_chars.cbegin() + 13, replaced_iter_chars.cbegin() + 15, 5, 'a'); + assert(equal(replaced_iter_chars, "Hello fluffy aaaaattens"sv)); + + str replaced_iter_init = get_literal_input(); + replaced_iter_init.replace( + replaced_iter_init.cbegin() + 13, replaced_iter_init.cbegin() + 15, {'c', 'u', 't', 'e', ' '}); + assert(equal(replaced_iter_init, "Hello fluffy cute ttens"sv)); + + const string_view_convertible convertible; + str replaced_pos_count_conversion = get_dog(); + replaced_pos_count_conversion.replace(1, 5, convertible); + assert(equal(replaced_pos_count_conversion, "dHello fluffy kittens"sv)); + + str replaced_iter_conversion = get_dog(); + replaced_iter_conversion.replace( + replaced_iter_conversion.cbegin() + 1, replaced_iter_conversion.cbegin() + 2, convertible); + assert(equal(replaced_iter_conversion, "dHello fluffy kittensg"sv)); + + str replaced_pos_count_conversion_pos = get_dog(); + replaced_pos_count_conversion_pos.replace(1, 5, convertible, 6); + assert(equal(replaced_pos_count_conversion_pos, "dfluffy kittens"sv)); + + str replaced_pos_count_conversion_pos_count = get_dog(); + replaced_pos_count_conversion_pos_count.replace(1, 5, convertible, 6, 6); + assert(equal(replaced_pos_count_conversion_pos_count, "dfluffy"sv)); + } + + { // substr + const str input = get_literal_input(); + + const str substr_pos = input.substr(6); + assert(equal(substr_pos, "fluffy kittens"sv)); + + const str substr_pos_count = input.substr(6, 6); + assert(equal(substr_pos_count, "fluffy"sv)); + } + + { // copy + const str input = get_literal_input(); + + CharType copy_count[5]; + input.copy(copy_count, 5); + assert(equal(copy_count, "Hello"sv)); + + CharType copy_count_pos[6]; + input.copy(copy_count_pos, 6, 6); + assert(equal(copy_count_pos, "fluffy"sv)); + } + + { // resize + str resized = get_literal_input(); + resized.resize(3); + assert(equal(resized, "Hel"sv)); + + resized.resize(6, 'a'); + assert(equal(resized, "Helaaa"sv)); + } + + { // swap + constexpr basic_string_view expected_first = get_dog(); + constexpr basic_string_view expected_second = get_cat(); + str first{get_cat()}; + str second{get_dog()}; + swap(first, second); + + assert(equal(first, expected_first)); + assert(equal(second, expected_second)); + + first.swap(second); + assert(equal(second, expected_first)); + assert(equal(first, expected_second)); + } + + { // find + const str input = get_literal_input(); + const str needle = get_cat(); + const str no_needle = get_no_needle(); + + const auto find_str = input.find(needle); + assert(find_str == 13u); + + const auto find_str_none = input.find(no_needle); + assert(find_str_none == str::npos); + + const auto find_str_pos = input.find(needle, 6); + assert(find_str_pos == 13u); + + const auto find_str_pos_none = input.find(needle, 14); + assert(find_str_pos_none == str::npos); + + const auto find_str_overflow = input.find(needle, 50); + assert(find_str_overflow == str::npos); + + const auto find_literal = input.find(get_cat()); + assert(find_literal == 13u); + + const auto find_literal_none = input.find(get_dog()); + assert(find_literal_none == str::npos); + + const auto find_literal_pos = input.find(get_cat(), 6); + assert(find_literal_pos == 13u); + + const auto find_literal_pos_none = input.find(get_cat(), 14); + assert(find_literal_pos_none == str::npos); + + const auto find_literal_overflow = input.find(get_cat(), 50); + assert(find_literal_overflow == str::npos); + + const auto find_literal_pos_count = input.find(get_cat(), 6, 4); + assert(find_literal_pos_count == 13u); + + const auto find_literal_pos_count_none = input.find(get_dog(), 14, 4); + assert(find_literal_pos_count_none == str::npos); + + const auto find_char = input.find('e'); + assert(find_char == 1u); + + const auto find_char_none = input.find('x'); + assert(find_char_none == str::npos); + + const auto find_char_pos = input.find('e', 4); + assert(find_char_pos == 17u); + + const string_view_convertible convertible; + const auto find_convertible = input.find(convertible); + assert(find_convertible == 0); + + const auto find_convertible_pos = input.find(convertible, 2); + assert(find_convertible_pos == str::npos); + } + + { // rfind + const str input = get_literal_input(); + const str needle = get_cat(); + const str no_needle = get_no_needle(); + + const auto rfind_str = input.rfind(needle); + assert(rfind_str == 13u); + + const auto rfind_str_none = input.rfind(no_needle); + assert(rfind_str_none == str::npos); + + const auto rfind_str_pos = input.rfind(needle, 15); + assert(rfind_str_pos == 13u); + + const auto rfind_str_pos_none = input.rfind(needle, 6); + assert(rfind_str_pos_none == str::npos); + + const auto rfind_str_overflow = input.rfind(needle, 50); + assert(rfind_str_overflow == 13u); + + const auto rfind_literal = input.rfind(get_cat()); + assert(rfind_literal == 13u); + + const auto rfind_literal_none = input.rfind(get_dog()); + assert(rfind_literal_none == str::npos); + + const auto rfind_literal_pos = input.rfind(get_cat(), 15); + assert(rfind_literal_pos == 13u); + + const auto rfind_literal_pos_none = input.rfind(get_cat(), 6); + assert(rfind_literal_pos_none == str::npos); + + const auto rfind_literal_overflow = input.rfind(get_cat(), 50); + assert(rfind_literal_overflow == 13u); + + const auto rfind_literal_pos_count = input.rfind(get_cat(), 15, 4); + assert(rfind_literal_pos_count == 13u); + + const auto rfind_literal_pos_count_none = input.rfind(get_dog(), 6, 4); + assert(rfind_literal_pos_count_none == str::npos); + + const auto rfind_char = input.rfind('e'); + assert(rfind_char == 17u); + + const auto rfind_char_none = input.rfind('x'); + assert(rfind_char_none == str::npos); + + const auto rfind_char_pos = input.rfind('e', 4); + assert(rfind_char_pos == 1u); + + const string_view_convertible convertible; + const auto rfind_convertible = input.rfind(convertible); + assert(rfind_convertible == 0); + + const auto rfind_convertible_pos = input.rfind(convertible, 5); + assert(rfind_convertible_pos == 0); + } + + { // find_first_of + const str input = get_literal_input(); + const str needle = get_cat(); + const str no_needle = get_no_needle(); + + const auto find_first_of_str = input.find_first_of(needle); + assert(find_first_of_str == 1u); + + const auto find_first_of_str_none = input.find_first_of(no_needle); + assert(find_first_of_str_none == str::npos); + + const auto find_first_of_str_pos = input.find_first_of(needle, 6); + assert(find_first_of_str_pos == 13u); + + const auto find_first_of_str_pos_none = input.find_first_of(no_needle, 14); + assert(find_first_of_str_pos_none == str::npos); + + const auto find_first_of_str_overflow = input.find_first_of(needle, 50); + assert(find_first_of_str_overflow == str::npos); + + const auto find_first_of_literal = input.find_first_of(get_cat()); + assert(find_first_of_literal == 1u); + + const auto find_first_of_literal_none = input.find_first_of(get_no_needle()); + assert(find_first_of_literal_none == str::npos); + + const auto find_first_of_literal_pos = input.find_first_of(get_cat(), 6); + assert(find_first_of_literal_pos == 13u); + + const auto find_first_of_literal_pos_none = input.find_first_of(get_no_needle(), 14); + assert(find_first_of_literal_pos_none == str::npos); + + const auto find_first_of_literal_overflow = input.find_first_of(get_cat(), 50); + assert(find_first_of_literal_overflow == str::npos); + + const auto find_first_of_literal_pos_count = input.find_first_of(get_cat(), 6, 4); + assert(find_first_of_literal_pos_count == 13u); + + const auto find_first_of_literal_pos_count_none = input.find_first_of(get_no_needle(), 14, 4); + assert(find_first_of_literal_pos_count_none == str::npos); + + const auto find_first_of_char = input.find_first_of('e'); + assert(find_first_of_char == 1u); + + const auto find_first_of_char_none = input.find_first_of('x'); + assert(find_first_of_char_none == str::npos); + + const auto find_first_of_char_pos = input.find_first_of('e', 4); + assert(find_first_of_char_pos == 17u); + + const string_view_convertible convertible; + const auto find_first_of_convertible = input.find_first_of(convertible); + assert(find_first_of_convertible == 0); + + const auto find_first_of_convertible_pos = input.find_first_of(convertible, 2); + assert(find_first_of_convertible_pos == 2u); + } + + { // find_first_not_of + const str input = get_literal_input(); + const str needle = get_cat(); + const str no_needle = get_no_needle(); + + const auto find_first_not_of_str = input.find_first_not_of(needle); + assert(find_first_not_of_str == 0u); + + const auto find_first_not_of_str_none = input.find_first_not_of(input); + assert(find_first_not_of_str_none == str::npos); + + const auto find_first_not_of_str_pos = input.find_first_not_of(needle, 6); + assert(find_first_not_of_str_pos == 6u); + + const auto find_first_not_of_str_pos_none = input.find_first_not_of(input, 14); + assert(find_first_not_of_str_pos_none == str::npos); + + const auto find_first_not_of_str_overflow = input.find_first_not_of(needle, 50); + assert(find_first_not_of_str_overflow == str::npos); + + const auto find_first_not_of_literal = input.find_first_not_of(get_cat()); + assert(find_first_not_of_literal == 0u); + + const auto find_first_not_of_literal_none = input.find_first_not_of(get_literal_input()); + assert(find_first_not_of_literal_none == str::npos); + + const auto find_first_not_of_literal_pos = input.find_first_not_of(get_cat(), 6); + assert(find_first_not_of_literal_pos == 6u); + + const auto find_first_not_of_literal_pos_none = input.find_first_not_of(get_literal_input(), 2); + assert(find_first_not_of_literal_pos_none == str::npos); + + const auto find_first_not_of_literal_overflow = input.find_first_not_of(get_cat(), 50); + assert(find_first_not_of_literal_overflow == str::npos); + + const auto find_first_not_of_literal_pos_count = input.find_first_not_of(get_cat(), 6, 4); + assert(find_first_not_of_literal_pos_count == 6u); + + const auto find_first_not_of_literal_pos_count_none = + input.find_first_not_of(get_literal_input(), 14, 20); + assert(find_first_not_of_literal_pos_count_none == str::npos); + + const auto find_first_not_of_char = input.find_first_not_of('H'); + assert(find_first_not_of_char == 1u); + + const auto find_first_not_of_char_pos = input.find_first_not_of('e', 1); + assert(find_first_not_of_char_pos == 2u); + + const string_view_convertible convertible; + const auto find_first_not_of_convertible = input.find_first_not_of(convertible); + assert(find_first_not_of_convertible == str::npos); + + const auto find_first_not_of_convertible_pos = input.find_first_not_of(convertible, 2); + assert(find_first_not_of_convertible_pos == str::npos); + } + + { // find_last_of + const str input = get_literal_input(); + const str needle = get_cat(); + const str no_needle = get_no_needle(); + + const auto find_last_of_str = input.find_last_of(needle); + assert(find_last_of_str == 18u); + + const auto find_last_of_str_none = input.find_last_of(no_needle); + assert(find_last_of_str_none == str::npos); + + const auto find_last_of_str_pos = input.find_last_of(needle, 6); + assert(find_last_of_str_pos == 1u); + + const auto find_last_of_str_pos_none = input.find_last_of(no_needle, 14); + assert(find_last_of_str_pos_none == str::npos); + + const auto find_last_of_str_overflow = input.find_last_of(needle, 50); + assert(find_last_of_str_overflow == 18u); + + const auto find_last_of_literal = input.find_last_of(get_cat()); + assert(find_last_of_literal == 18u); + + const auto find_last_of_literal_none = input.find_last_of(get_no_needle()); + assert(find_last_of_literal_none == str::npos); + + const auto find_last_of_literal_pos = input.find_last_of(get_cat(), 6); + assert(find_last_of_literal_pos == 1u); + + const auto find_last_of_literal_pos_none = input.find_last_of(get_no_needle(), 14); + assert(find_last_of_literal_pos_none == str::npos); + + const auto find_last_of_literal_overflow = input.find_last_of(get_cat(), 50); + assert(find_last_of_literal_overflow == 18u); + + const auto find_last_of_literal_pos_count = input.find_last_of(get_cat(), 6, 7); + assert(find_last_of_literal_pos_count == 1u); + + const auto find_last_of_literal_pos_count_none = input.find_last_of(get_no_needle(), 14, 4); + assert(find_last_of_literal_pos_count_none == str::npos); + + const auto find_last_of_char = input.find_last_of('e'); + assert(find_last_of_char == 17u); + + const auto find_last_of_char_none = input.find_last_of('x'); + assert(find_last_of_char_none == str::npos); + + const auto find_last_of_char_pos = input.find_last_of('e', 4); + assert(find_last_of_char_pos == 1u); + + const string_view_convertible convertible; + const auto find_last_of_convertible = input.find_last_of(convertible); + assert(find_last_of_convertible == 19u); + + const auto find_last_of_convertible_pos = input.find_last_of(convertible, 4); + assert(find_last_of_convertible_pos == 4u); + } + + { // find_last_not_of + const str input = get_literal_input(); + const str needle = get_cat(); + const str no_needle = get_no_needle(); + + const auto find_last_not_of_str = input.find_last_not_of(needle); + assert(find_last_not_of_str == 19u); + + const auto find_last_not_of_str_none = input.find_last_not_of(input); + assert(find_last_not_of_str_none == str::npos); + + const auto find_last_not_of_str_pos = input.find_last_not_of(needle, 6); + assert(find_last_not_of_str_pos == 6u); + + const auto find_last_not_of_str_pos_none = input.find_last_not_of(input, 14); + assert(find_last_not_of_str_pos_none == str::npos); + + const auto find_last_not_of_str_overflow = input.find_last_not_of(needle, 50); + assert(find_last_not_of_str_overflow == 19u); + + const auto find_last_not_of_literal = input.find_last_not_of(get_cat()); + assert(find_last_not_of_literal == 19u); + + const auto find_last_not_of_literal_none = input.find_last_not_of(get_literal_input()); + assert(find_last_not_of_literal_none == str::npos); + + const auto find_last_not_of_literal_pos = input.find_last_not_of(get_cat(), 6); + assert(find_last_not_of_literal_pos == 6u); + + const auto find_last_not_of_literal_pos_none = input.find_last_not_of(get_literal_input(), 2); + assert(find_last_not_of_literal_pos_none == str::npos); + + const auto find_last_not_of_literal_overflow = input.find_last_not_of(get_cat(), 50); + assert(find_last_not_of_literal_overflow == 19u); + + const auto find_last_not_of_literal_pos_count = input.find_last_not_of(get_cat(), 6, 4); + assert(find_last_not_of_literal_pos_count == 6u); + + const auto find_last_not_of_literal_pos_count_none = + input.find_last_not_of(get_literal_input(), 14, 20); + assert(find_last_not_of_literal_pos_count_none == str::npos); + + const auto find_last_not_of_char = input.find_last_not_of('H'); + assert(find_last_not_of_char == 19u); + + const auto find_last_not_of_char_pos = input.find_last_not_of('e', 2); + assert(find_last_not_of_char_pos == 2u); + + const string_view_convertible convertible; + const auto find_last_not_of_convertible = input.find_last_not_of(convertible); + assert(find_last_not_of_convertible == str::npos); + + const auto find_last_not_of_convertible_pos = input.find_last_not_of(convertible, 2); + assert(find_last_not_of_convertible_pos == str::npos); + } + + { // operator+ + const str first = get_cat(); + const str second = get_dog(); + + const str op_str_str = first + second; + assert(equal(op_str_str, "kittendog"sv)); + + const str op_str_literal = first + get_dog(); + assert(equal(op_str_literal, "kittendog"sv)); + + const str op_str_char = first + CharType{'!'}; + assert(equal(op_str_char, "kitten!"sv)); + + const str op_literal_str = get_cat() + second; + assert(equal(op_str_literal, "kittendog"sv)); + + const str op_char_str = CharType{'!'} + second; + assert(equal(op_char_str, "!dog"sv)); + + const str op_rstr_rstr = str{get_cat()} + str{get_dog()}; + assert(equal(op_rstr_rstr, "kittendog"sv)); + + const str op_rstr_str = str{get_cat()} + second; + assert(equal(op_rstr_str, "kittendog"sv)); + + const str op_rstr_literal = str{get_cat()} + get_dog(); + assert(equal(op_rstr_literal, "kittendog"sv)); + + const str op_rstr_char = str{get_cat()} + CharType{'!'}; + assert(equal(op_rstr_char, "kitten!"sv)); + + const str op_str_rstr = first + str{get_dog()}; + assert(equal(op_str_rstr, "kittendog"sv)); + + const str op_literal_rst = get_cat() + str{get_dog()}; + assert(equal(op_rstr_literal, "kittendog"sv)); + + const str op_char_rstr = CharType{'!'} + str{get_dog()}; + assert(equal(op_char_rstr, "!dog"sv)); + } + + { // comparison + str first(get_view_input()); + str second(get_view_input()); + str third{get_cat()}; + + const bool eq_str_str = first == second; + assert(eq_str_str); + + const bool ne_str_str = first != third; + assert(ne_str_str); + + const bool less_str_str = first < third; + assert(less_str_str); + + const bool less_eq_str_str = first <= third; + assert(less_eq_str_str); + + const bool greater_str_str = first > third; + assert(!greater_str_str); + + const bool greater_eq_str_str = first >= third; + assert(!greater_eq_str_str); + + const bool eq_str_literal = first == get_view_input(); + assert(eq_str_literal); + + const bool ne_str_literal = first != get_cat(); + assert(ne_str_literal); + + const bool less_str_literal = first < get_cat(); + assert(less_str_literal); + + const bool less_eq_str_literal = first <= get_cat(); + assert(less_eq_str_literal); + + const bool greater_str_literal = first > get_cat(); + assert(!greater_str_literal); + + const bool greater_eq_str_literal = first >= get_cat(); + assert(!greater_eq_str_literal); + + const bool eq_literal_str = get_view_input() == second; + assert(eq_literal_str); + + const bool ne_literal_str = get_view_input() != third; + assert(ne_literal_str); + + const bool less_literal_str = get_view_input() < third; + assert(less_literal_str); + + const bool less_eq_literal_str = get_view_input() <= third; + assert(less_eq_literal_str); + + const bool greater_literal_str = get_view_input() > third; + assert(!greater_literal_str); + + const bool greater_eq_literal_str = get_view_input() >= third; + assert(!greater_eq_literal_str); + } + return true; +} + +template +_CONSTEXPR20_CONTAINER bool test_iterators() { + using str = basic_string; + str literal_constructed = get_literal_input(); + + { // increment + auto it = literal_constructed.begin(); + assert(*++it == 'e'); + assert(*it++ == 'e'); + assert(*it == 'l'); + + auto cit = literal_constructed.cbegin(); + assert(*++cit == 'e'); + assert(*cit++ == 'e'); + assert(*cit == 'l'); + } + + { // advance + auto it = literal_constructed.begin() + 2; + assert(*it == 'l'); + it += 2; + assert(*it == 'o'); + + auto cit = literal_constructed.cbegin() + 2; + assert(*cit == 'l'); + cit += 2; + assert(*cit == 'o'); + } + + { // decrement + auto it = literal_constructed.end(); + assert(*--it == 's'); + assert(*it-- == 's'); + assert(*it == 'n'); + + auto cit = literal_constructed.cend(); + assert(*--cit == 's'); + assert(*cit-- == 's'); + assert(*cit == 'n'); + } + + { // advance back + auto it = literal_constructed.end() - 2; + assert(*it == 'n'); + it -= 2; + assert(*it == 't'); + + auto cit = literal_constructed.cend() - 2; + assert(*cit == 'n'); + cit -= 2; + assert(*cit == 't'); + } + + { // difference + const auto it1 = literal_constructed.begin(); + const auto it2 = literal_constructed.end(); + assert(it2 - it1 == ssize(get_view_input())); + + const auto cit1 = literal_constructed.cbegin(); + const auto cit2 = literal_constructed.cend(); + assert(cit2 - cit1 == ssize(get_view_input())); + + assert(it2 - cit1 == ssize(get_view_input())); + assert(cit2 - it1 == ssize(get_view_input())); + } + + { // comparison + const auto it1 = literal_constructed.begin(); + const auto it2 = literal_constructed.begin(); + const auto it3 = literal_constructed.end(); + + assert(it1 == it2); + assert(it1 != it3); + assert(it1 < it3); + assert(it1 <= it3); + assert(it3 > it1); + assert(it3 >= it1); + } + + { // access + const auto it = literal_constructed.begin() + 2; + it[2] = 'l'; + assert(literal_constructed[4] == 'l'); + + const auto cit = literal_constructed.cbegin() + 2; + assert(cit[2] == 'l'); + } + return true; +} + +template +_CONSTEXPR20_CONTAINER bool test_growth() { + using str = basic_string; + + { + str v(1007, 'a'); + + assert(v.size() == 1007); + assert(v.capacity() == 1007); + + v.resize(1008); + + assert(v.size() == 1008); + assert(v.capacity() == 1510); + } + + { + str v(1007, 'a'); + + assert(v.size() == 1007); + assert(v.capacity() == 1007); + + v.resize(8007); + + assert(v.size() == 8007); + if constexpr (is_same_v || is_same_v || is_same_v) { + assert(v.capacity() == 8007); + } else { + assert(v.capacity() == 8015); + } + } + + { + str v(1007, 'a'); + + assert(v.size() == 1007); + assert(v.capacity() == 1007); + + v.push_back(47); + + assert(v.size() == 1008); + assert(v.capacity() == 1510); + } + + { + str v(1007, 'a'); + + assert(v.size() == 1007); + assert(v.capacity() == 1007); + + str l(3, 47); + + v.insert(v.end(), l.begin(), l.end()); + + assert(v.size() == 1010); + assert(v.capacity() == 1510); + } + + { + str v(1007, 'a'); + + assert(v.size() == 1007); + assert(v.capacity() == 1007); + + str l(7000, 'b'); + + v.insert(v.end(), l.begin(), l.end()); + + assert(v.size() == 8007); + if constexpr (is_same_v || is_same_v || is_same_v) { + assert(v.capacity() == 8007); + } else { + assert(v.capacity() == 8015); + } + } + + { + str v(1007, 'a'); + + assert(v.size() == 1007); + assert(v.capacity() == 1007); + + v.insert(v.end(), 3, 'b'); + + assert(v.size() == 1010); + assert(v.capacity() == 1510); + } + + { + str v(1007, 'a'); + + assert(v.size() == 1007); + assert(v.capacity() == 1007); + + v.insert(v.end(), 7000, 'b'); + + assert(v.size() == 8007); + if constexpr (is_same_v || is_same_v || is_same_v) { + assert(v.capacity() == 8007); + } else { + assert(v.capacity() == 8015); + } + } + return true; +} + +int main() { + test_interface(); +#ifdef __cpp_char8_t + test_interface(); +#endif // __cpp_char8_t + test_interface(); + test_interface(); + test_interface(); + + test_iterators(); +#ifdef __cpp_char8_t + test_iterators(); +#endif // __cpp_char8_t + test_iterators(); + test_iterators(); + test_iterators(); + + test_growth(); +#ifdef __cpp_char8_t + test_growth(); +#endif // __cpp_char8_t + test_growth(); + test_growth(); + test_growth(); + +#ifdef __cpp_lib_constexpr_string + static_assert(test_interface()); +#ifdef __cpp_char8_t + static_assert(test_interface()); +#endif // __cpp_char8_t + static_assert(test_interface()); + static_assert(test_interface()); + static_assert(test_interface()); + + static_assert(test_iterators()); +#ifdef __cpp_char8_t + static_assert(test_iterators()); +#endif // __cpp_char8_t + static_assert(test_iterators()); + static_assert(test_iterators()); + static_assert(test_iterators()); + + static_assert(test_growth()); +#ifdef __cpp_char8_t + static_assert(test_growth()); +#endif // __cpp_char8_t + static_assert(test_growth()); + static_assert(test_growth()); + static_assert(test_growth()); +#endif // __cpp_lib_constexpr_string +} From 5908b20b75b4912d547ffb7a44accff84a2fc2aa Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Tue, 9 Feb 2021 00:11:30 -0800 Subject: [PATCH 12/74] EDG workaround for nonlit ret type --- stl/inc/xstring | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index afe098d1dba..0aa23e4a33e 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -5057,25 +5057,45 @@ basic_ostream<_Elem, _Traits>& operator<<( // basic_string LITERALS inline namespace literals { inline namespace string_literals { - _NODISCARD _CONSTEXPR20_CONTAINER string operator"" s(const char* _Str, size_t _Len) { + _NODISCARD +#ifndef __EDG__ // TRANSITION, VSO-1273381 + _CONSTEXPR20_CONTAINER +#endif // __EDG__ + string operator"" s(const char* _Str, size_t _Len) { return string(_Str, _Len); } - _NODISCARD _CONSTEXPR20_CONTAINER wstring operator"" s(const wchar_t* _Str, size_t _Len) { + _NODISCARD +#ifndef __EDG__ // TRANSITION, VSO-1273381 + _CONSTEXPR20_CONTAINER +#endif // __EDG__ + wstring operator"" s(const wchar_t* _Str, size_t _Len) { return wstring(_Str, _Len); } #ifdef __cpp_char8_t - _NODISCARD _CONSTEXPR20_CONTAINER basic_string operator"" s(const char8_t* _Str, size_t _Len) { + _NODISCARD +#ifndef __EDG__ // TRANSITION, VSO-1273381 + _CONSTEXPR20_CONTAINER +#endif // __EDG__ + basic_string operator"" s(const char8_t* _Str, size_t _Len) { return basic_string(_Str, _Len); } #endif // __cpp_char8_t - _NODISCARD _CONSTEXPR20_CONTAINER u16string operator"" s(const char16_t* _Str, size_t _Len) { + _NODISCARD +#ifndef __EDG__ // TRANSITION, VSO-1273381 + _CONSTEXPR20_CONTAINER +#endif // __EDG__ + u16string operator"" s(const char16_t* _Str, size_t _Len) { return u16string(_Str, _Len); } - _NODISCARD _CONSTEXPR20_CONTAINER u32string operator"" s(const char32_t* _Str, size_t _Len) { + _NODISCARD +#ifndef __EDG__ // TRANSITION, VSO-1273381 + _CONSTEXPR20_CONTAINER +#endif // __EDG__ + u32string operator"" s(const char32_t* _Str, size_t _Len) { return u32string(_Str, _Len); } } // namespace string_literals From f7266e1afefcf88bc67b8455fcd9c49c75095313 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Tue, 9 Feb 2021 00:24:37 -0800 Subject: [PATCH 13/74] workaround for filesystem ICE --- tests/std/tests/P0218R1_filesystem/test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/std/tests/P0218R1_filesystem/test.cpp b/tests/std/tests/P0218R1_filesystem/test.cpp index 610e1003b8b..b767e94abdb 100644 --- a/tests/std/tests/P0218R1_filesystem/test.cpp +++ b/tests/std/tests/P0218R1_filesystem/test.cpp @@ -3908,7 +3908,9 @@ void run_interactive_tests(int argc, wchar_t* argv[]) { // mode. void test_devcom_953628() { // COMPILE-ONLY struct S : wstring {}; +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1270432 path{S{}}; +#endif // defined(__clang__) || defined(__EDG__) } int wmain(int argc, wchar_t* argv[]) { From 230f056f644a69a50a17cfdc67f501be9167d75d Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Wed, 10 Feb 2021 11:46:45 -0800 Subject: [PATCH 14/74] Disable portions of test according to current bugs --- .../tests/P0980R1_constexpr_strings/test.cpp | 59 ++++++++++++------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index 11b3b8345f8..38dc9d77e68 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -138,6 +138,7 @@ template _CONSTEXPR20_CONTAINER bool test_interface() { using str = basic_string; using ranges::equal; +#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 { // constructors // range constructors str literal_constructed{get_literal_input()}; @@ -177,10 +178,10 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str ptr_size_constructed(get_literal_input(), 2); assert(equal(ptr_size_constructed, "He"sv)); - +#ifdef __EDG__ // TRANSITION, VSO-1270433 str iterator_constructed(literal_constructed.begin(), literal_constructed.end()); assert(equal(iterator_constructed, literal_constructed)); - +#endif // __EDG__ const string_view_convertible convertible; str conversion_constructed(convertible); assert(equal(conversion_constructed, literal_constructed)); @@ -223,10 +224,10 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str ptr_size_constructed(get_literal_input(), 2, alloc); assert(equal(ptr_size_constructed, "He"sv)); - +#ifdef __EDG__ // TRANSITION, VSO-1270433 str iterator_constructed(literal_constructed.begin(), literal_constructed.end(), alloc); assert(equal(iterator_constructed, literal_constructed)); - +#endif // __EDG__ const string_view_convertible convertible; str conversion_constructed(convertible, alloc); assert(equal(conversion_constructed, literal_constructed)); @@ -314,13 +315,13 @@ _CONSTEXPR20_CONTAINER bool test_interface() { assign_conversion_size.assign(convertible, 2, 3); assert(equal(assign_conversion_size, "llo"sv)); } - +#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 { // allocator str default_constructed; [[maybe_unused]] const auto alloc = default_constructed.get_allocator(); static_assert(is_same_v, allocator>); } - +#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 { // access str literal_constructed = get_literal_input(); const str const_literal_constructed = get_literal_input(); @@ -400,17 +401,24 @@ _CONSTEXPR20_CONTAINER bool test_interface() { const auto e = literal_constructed.end(); static_assert(is_same_v, typename str::iterator>); +#ifdef __EDG__ // TRANSITION, VSO-1275530 assert(*prev(e) == CharType{'s'}); +#endif // __EDG__ const auto ce = literal_constructed.cend(); static_assert(is_same_v, typename str::const_iterator>); +#ifdef __EDG__ // TRANSITION, VSO-1275530 assert(*prev(ce) == CharType{'s'}); +#endif // __EDG__ const auto ce2 = const_literal_constructed.end(); static_assert(is_same_v, typename str::const_iterator>); +#ifdef __EDG__ // TRANSITION, VSO-1275530 assert(*prev(ce2) == CharType{'s'}); +#endif // __EDG__ - const auto rb = literal_constructed.rbegin(); +#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 2 // TODO: need to file a new bug? + const auto rb = literal_constructed.rbegin(); // <--(sub-)expression error static_assert(is_same_v, reverse_iterator>); assert(*rb == CharType{'s'}); @@ -433,6 +441,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { const auto cre2 = const_literal_constructed.rend(); static_assert(is_same_v, reverse_iterator>); assert(*prev(cre2) == CharType{'H'}); +#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 2 } { // capacity @@ -483,6 +492,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { } { // insert +#ifdef __EDG__ // TRANSITION, VSO-1275530 str insert_char = get_literal_input(); const CharType to_be_inserted = CharType{','}; insert_char.insert(insert_char.begin() + 5, to_be_inserted); @@ -522,13 +532,14 @@ _CONSTEXPR20_CONTAINER bool test_interface() { insert_const_initializer.insert(insert_const_initializer.cbegin() + 6, {'c', 'u', 't', 'e', ' '}); assert(cit_ilist == insert_const_initializer.cbegin() + 6); assert(equal(insert_const_initializer, "Hello cute fluffy kittens"sv)); +#endif // __EDG__ } { // erase str erase_pos_count = get_literal_input(); erase_pos_count.erase(0, 6); assert(equal(erase_pos_count, "fluffy kittens"sv)); - +#ifdef __EDG__ // TRANSITION, VSO-1275530 str erase_iter = get_literal_input(); erase_iter.erase(erase_iter.begin()); assert(equal(erase_iter, "ello fluffy kittens"sv)); @@ -552,7 +563,9 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str erased_free_if = get_literal_input(); erase_if(erased_free_if, [](const CharType val) { return val == CharType{'t'}; }); assert(equal(erased_free_if, "Hello fluffy kiens"sv)); +#endif // __EDG__ } +#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 { // push_back / pop_back str pushed; @@ -569,7 +582,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { assert(pushed.size() == 1); assert(pushed.back() == CharType{'y'}); } - +#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 { // append const str literal_constructed = get_literal_input(); @@ -794,7 +807,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str replaced_pos_count_str_shift = get_literal_input(); replaced_pos_count_str_shift.replace(13, 2, input); assert(equal(replaced_pos_count_str_shift, "Hello fluffy dogttens"sv)); - +#ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_str = get_literal_input(); replaced_iter_str.replace(replaced_iter_str.cbegin() + 13, replaced_iter_str.cend(), input); assert(equal(replaced_iter_str, "Hello fluffy dog"sv)); @@ -803,7 +816,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { replaced_iter_str_shift.replace( replaced_iter_str_shift.cbegin() + 13, replaced_iter_str_shift.cbegin() + 15, input); assert(equal(replaced_iter_str_shift, "Hello fluffy dogttens"sv)); - +#endif // __EDG__ str replaced_pos_count_str_pos_count = get_literal_input(); replaced_pos_count_str_pos_count.replace(13, 7, input, 1); assert(equal(replaced_pos_count_str_pos_count, "Hello fluffy og"sv)); @@ -811,7 +824,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str replaced_pos_count_str_pos_count_less = get_literal_input(); replaced_pos_count_str_pos_count_less.replace(13, 2, input, 1, 2); assert(equal(replaced_pos_count_str_pos_count_less, "Hello fluffy ogttens"sv)); - +#ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_iter = get_literal_input(); replaced_iter_iter.replace( replaced_iter_iter.cbegin() + 13, replaced_iter_iter.cend(), input.begin(), input.end()); @@ -821,7 +834,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { replaced_iter_iter_less.replace(replaced_iter_iter_less.cbegin() + 13, replaced_iter_iter_less.cbegin() + 15, input.begin() + 1, input.end()); assert(equal(replaced_iter_iter_less, "Hello fluffy ogttens"sv)); - +#endif // __EDG__ str replaced_pos_count_literal = get_literal_input(); replaced_pos_count_literal.replace(13, 2, get_dog()); assert(equal(replaced_pos_count_literal, "Hello fluffy dogttens"sv)); @@ -829,7 +842,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str replaced_pos_count_literal_count = get_literal_input(); replaced_pos_count_literal_count.replace(13, 2, get_dog(), 2); assert(equal(replaced_pos_count_literal_count, "Hello fluffy dottens"sv)); - +#ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_literal = get_literal_input(); replaced_iter_literal.replace( replaced_iter_literal.cbegin() + 13, replaced_iter_literal.cbegin() + 15, get_dog()); @@ -839,11 +852,11 @@ _CONSTEXPR20_CONTAINER bool test_interface() { replaced_iter_literal_count.replace(replaced_iter_literal_count.cbegin() + 13, replaced_iter_literal_count.cbegin() + 15, get_dog(), 2); assert(equal(replaced_iter_literal_count, "Hello fluffy dottens"sv)); - +#endif // __EDG__ str replaced_pos_count_chars = get_literal_input(); replaced_pos_count_chars.replace(13, 2, 5, 'a'); assert(equal(replaced_pos_count_chars, "Hello fluffy aaaaattens"sv)); - +#ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_chars = get_literal_input(); replaced_iter_chars.replace(replaced_iter_chars.cbegin() + 13, replaced_iter_chars.cbegin() + 15, 5, 'a'); assert(equal(replaced_iter_chars, "Hello fluffy aaaaattens"sv)); @@ -852,17 +865,17 @@ _CONSTEXPR20_CONTAINER bool test_interface() { replaced_iter_init.replace( replaced_iter_init.cbegin() + 13, replaced_iter_init.cbegin() + 15, {'c', 'u', 't', 'e', ' '}); assert(equal(replaced_iter_init, "Hello fluffy cute ttens"sv)); - +#endif // __EDG__ const string_view_convertible convertible; str replaced_pos_count_conversion = get_dog(); replaced_pos_count_conversion.replace(1, 5, convertible); assert(equal(replaced_pos_count_conversion, "dHello fluffy kittens"sv)); - +#ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_conversion = get_dog(); replaced_iter_conversion.replace( replaced_iter_conversion.cbegin() + 1, replaced_iter_conversion.cbegin() + 2, convertible); assert(equal(replaced_iter_conversion, "dHello fluffy kittensg"sv)); - +#endif // __EDG__ str replaced_pos_count_conversion_pos = get_dog(); replaced_pos_count_conversion_pos.replace(1, 5, convertible, 6); assert(equal(replaced_pos_count_conversion_pos, "dfluffy kittens"sv)); @@ -1362,11 +1375,13 @@ _CONSTEXPR20_CONTAINER bool test_interface() { const bool greater_eq_literal_str = get_view_input() >= third; assert(!greater_eq_literal_str); } +#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 return true; } template _CONSTEXPR20_CONTAINER bool test_iterators() { +#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 using str = basic_string; str literal_constructed = get_literal_input(); @@ -1452,11 +1467,13 @@ _CONSTEXPR20_CONTAINER bool test_iterators() { const auto cit = literal_constructed.cbegin() + 2; assert(cit[2] == 'l'); } +#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 return true; } template _CONSTEXPR20_CONTAINER bool test_growth() { +#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 using str = basic_string; { @@ -1498,7 +1515,7 @@ _CONSTEXPR20_CONTAINER bool test_growth() { assert(v.size() == 1008); assert(v.capacity() == 1510); } - +#ifdef __EDG__ // TRANSITION, VSO-1275530 { str v(1007, 'a'); @@ -1558,6 +1575,8 @@ _CONSTEXPR20_CONTAINER bool test_growth() { assert(v.capacity() == 8015); } } +#endif // __EDG__ +#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 return true; } From ce625edfcef72952b00415ca7c7d9c6f3119bbff Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Wed, 10 Feb 2021 11:48:09 -0800 Subject: [PATCH 15/74] add workarounds for DevCom-1331017 --- stl/inc/xstring | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stl/inc/xstring b/stl/inc/xstring index 0aa23e4a33e..67d9399e751 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -1854,6 +1854,9 @@ public: this->_Adopt(_Pstring); } + // TRANSITION, DevCom-1331017 + _CONSTEXPR20_CONTAINER _String_const_iterator& operator=(const _String_const_iterator&) = default; + _NODISCARD _CONSTEXPR20_CONTAINER reference operator*() const noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 #ifdef __cpp_lib_is_constant_evaluated @@ -2125,6 +2128,9 @@ public: using _Mybase::_Mybase; + // TRANSITION, DevCom-1331017 + _CONSTEXPR20_CONTAINER _String_iterator& operator=(const _String_iterator&) = default; + _NODISCARD _CONSTEXPR20_CONTAINER reference operator*() const noexcept { return const_cast(_Mybase::operator*()); } From 1cee6924adf238da8ce0f8c4d053c5475422bca4 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Wed, 10 Feb 2021 13:52:23 -0800 Subject: [PATCH 16/74] fix comment for bug fix --- tests/std/tests/P0980R1_constexpr_strings/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index 38dc9d77e68..df91adddba5 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -417,8 +417,8 @@ _CONSTEXPR20_CONTAINER bool test_interface() { assert(*prev(ce2) == CharType{'s'}); #endif // __EDG__ -#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 2 // TODO: need to file a new bug? - const auto rb = literal_constructed.rbegin(); // <--(sub-)expression error +#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 2 // TRANSITION, 16.10p1 + const auto rb = literal_constructed.rbegin(); static_assert(is_same_v, reverse_iterator>); assert(*rb == CharType{'s'}); From 01ed70d68f3a91d891fca7ee49f6c86c83b56748 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Wed, 10 Feb 2021 17:09:09 -0800 Subject: [PATCH 17/74] Skip affected libcxx tests with recorded bugs --- tests/libcxx/expected_results.txt | 7 +++++++ tests/libcxx/skipped_tests.txt | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index e406827dbd4..0946a73cb78 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -364,6 +364,13 @@ std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp:0 FAIL std/containers/views/span.cons/ptr_len.pass.cpp:0 FAIL std/containers/views/span.cons/ptr_ptr.pass.cpp:0 FAIL +# DevCom-1336816 "cl errors on constexpr array of std::string" +std/numerics/numeric.ops/adjacent.difference/adjacent_difference_op.pass.cpp:0 FAIL + +# DevCom-1336819 "cl constexpr temporary passing issue" +std/numerics/numeric.ops/inner.product/inner_product_comp.pass.cpp:0 FAIL +std/numerics/numeric.ops/accumulate/accumulate_op.pass.cpp:0 FAIL + # VSO-1168723 "Implicit copy assignment incorrectly not constexpr when subobject has explicit constexpr copy constructor" std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp:0 FAIL std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp:0 FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 9482df7db03..53f335c299c 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -364,6 +364,13 @@ utilities\meta\meta.unary\meta.unary.prop\is_constructible.pass.cpp containers\views\span.cons\ptr_len.pass.cpp containers\views\span.cons\ptr_ptr.pass.cpp +# DevCom-1336816 "cl errors on constexpr array of std::string" +numerics\numeric.ops\adjacent.difference\adjacent_difference_op.pass.cpp + +# DevCom-1336819 "cl constexpr temporary passing issue" +numerics\numeric.ops\inner.product\inner_product_comp.pass.cpp +numerics\numeric.ops\accumulate\accumulate_op.pass.cpp + # VSO-1168723 "Implicit copy assignment incorrectly not constexpr when subobject has explicit constexpr copy constructor" utilities\utility\pairs\pairs.pair\assign_pair.pass.cpp utilities\utility\pairs\pairs.pair\assign_rv_pair.pass.cpp From 1fe5aeeda9e0643dc8e1a8a0db449c209731b905 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Wed, 10 Feb 2021 17:31:01 -0800 Subject: [PATCH 18/74] Oops - missed one --- tests/libcxx/expected_results.txt | 1 + tests/libcxx/skipped_tests.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 0946a73cb78..f990c48b415 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -366,6 +366,7 @@ std/containers/views/span.cons/ptr_ptr.pass.cpp:0 FAIL # DevCom-1336816 "cl errors on constexpr array of std::string" std/numerics/numeric.ops/adjacent.difference/adjacent_difference_op.pass.cpp:0 FAIL +std/numerics/numeric.ops/partial.sum/partial_sum_op.pass.cpp:0 FAIL # DevCom-1336819 "cl constexpr temporary passing issue" std/numerics/numeric.ops/inner.product/inner_product_comp.pass.cpp:0 FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 53f335c299c..f5f3e4c681c 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -366,6 +366,7 @@ containers\views\span.cons\ptr_ptr.pass.cpp # DevCom-1336816 "cl errors on constexpr array of std::string" numerics\numeric.ops\adjacent.difference\adjacent_difference_op.pass.cpp +numerics\numeric.ops\partial.sum\partial_sum_op.pass.cpp # DevCom-1336819 "cl constexpr temporary passing issue" numerics\numeric.ops\inner.product\inner_product_comp.pass.cpp From 9bf3514d66dec56d2583c0f36cfbfd72b4a9b371 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Sun, 14 Feb 2021 19:54:38 +0100 Subject: [PATCH 19/74] Lets see what happens without concepts --- .../tests/P0980R1_constexpr_strings/env.lst | 2 +- .../tests/P0980R1_constexpr_strings/test.cpp | 235 +++++++++--------- 2 files changed, 121 insertions(+), 116 deletions(-) diff --git a/tests/std/tests/P0980R1_constexpr_strings/env.lst b/tests/std/tests/P0980R1_constexpr_strings/env.lst index f3ccc8613c6..19f025bd0e6 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/env.lst +++ b/tests/std/tests/P0980R1_constexpr_strings/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\concepts_matrix.lst +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index df91adddba5..bc2a403fa92 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -134,60 +134,65 @@ struct string_view_convertible { } }; +// TRANSITION, EDG concepts support +template +constexpr bool equalRanges(const Range1& range1, const Range2& range2) noexcept { + return equal(begin(range1), end(range1), begin(range2), end(range2)); +} + template _CONSTEXPR20_CONTAINER bool test_interface() { using str = basic_string; - using ranges::equal; #if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 { // constructors // range constructors str literal_constructed{get_literal_input()}; - assert(equal(literal_constructed, get_view_input())); + assert(equalRanges(literal_constructed, get_view_input())); str view_constructed(get_view_input()); - assert(equal(view_constructed, literal_constructed)); + assert(equalRanges(view_constructed, literal_constructed)); str initializer_list_constructed({'m', 'e', 'o', 'w'}); - assert(equal(initializer_list_constructed, "meow"sv)); + assert(equalRanges(initializer_list_constructed, "meow"sv)); // special member functions str default_constructed; str copy_constructed(literal_constructed); - assert(equal(copy_constructed, literal_constructed)); + assert(equalRanges(copy_constructed, literal_constructed)); str move_constructed(move(copy_constructed)); - assert(equal(move_constructed, literal_constructed)); + assert(equalRanges(move_constructed, literal_constructed)); assert(copy_constructed.empty()); str copy_assigned = literal_constructed; - assert(equal(copy_assigned, literal_constructed)); + assert(equalRanges(copy_assigned, literal_constructed)); str move_assigned = std::move(copy_assigned); - assert(equal(move_assigned, literal_constructed)); + assert(equalRanges(move_assigned, literal_constructed)); assert(copy_constructed.empty()); // Other constructors str size_value_constructed(5, CharType{'a'}); - assert(equal(size_value_constructed, "aaaaa"sv)); + assert(equalRanges(size_value_constructed, "aaaaa"sv)); str copy_start_constructed(literal_constructed, 2); - assert(equal(copy_start_constructed, "llo fluffy kittens"sv)); + assert(equalRanges(copy_start_constructed, "llo fluffy kittens"sv)); str copy_start_length_constructed(literal_constructed, 2, 3); - assert(equal(copy_start_length_constructed, "llo"sv)); + assert(equalRanges(copy_start_length_constructed, "llo"sv)); str ptr_size_constructed(get_literal_input(), 2); - assert(equal(ptr_size_constructed, "He"sv)); + assert(equalRanges(ptr_size_constructed, "He"sv)); #ifdef __EDG__ // TRANSITION, VSO-1270433 str iterator_constructed(literal_constructed.begin(), literal_constructed.end()); - assert(equal(iterator_constructed, literal_constructed)); + assert(equalRanges(iterator_constructed, literal_constructed)); #endif // __EDG__ const string_view_convertible convertible; str conversion_constructed(convertible); - assert(equal(conversion_constructed, literal_constructed)); + assert(equalRanges(conversion_constructed, literal_constructed)); str conversion_size_constructed(convertible, 2, 3); - assert(equal(conversion_size_constructed, "llo"sv)); + assert(equalRanges(conversion_size_constructed, "llo"sv)); } { // allocator constructors @@ -195,45 +200,45 @@ _CONSTEXPR20_CONTAINER bool test_interface() { // range constructors str literal_constructed{get_literal_input(), alloc}; - assert(equal(literal_constructed, get_view_input())); + assert(equalRanges(literal_constructed, get_view_input())); str view_constructed{get_view_input(), alloc}; - assert(equal(view_constructed, literal_constructed)); + assert(equalRanges(view_constructed, literal_constructed)); str initializer_list_constructed({'m', 'e', 'o', 'w'}, alloc); - assert(equal(initializer_list_constructed, "meow"sv)); + assert(equalRanges(initializer_list_constructed, "meow"sv)); // special member functions str default_constructed{alloc}; str copy_constructed{literal_constructed, alloc}; - assert(equal(copy_constructed, literal_constructed)); + assert(equalRanges(copy_constructed, literal_constructed)); str move_constructed{move(copy_constructed), alloc}; - assert(equal(move_constructed, literal_constructed)); + assert(equalRanges(move_constructed, literal_constructed)); assert(copy_constructed.empty()); // Other constructors str size_value_constructed(5, CharType{'a'}, alloc); - assert(equal(size_value_constructed, "aaaaa"sv)); + assert(equalRanges(size_value_constructed, "aaaaa"sv)); str copy_start_constructed(literal_constructed, 2, alloc); - assert(equal(copy_start_constructed, "llo fluffy kittens"sv)); + assert(equalRanges(copy_start_constructed, "llo fluffy kittens"sv)); str copy_start_length_constructed(literal_constructed, 2, 3, alloc); - assert(equal(copy_start_length_constructed, "llo"sv)); + assert(equalRanges(copy_start_length_constructed, "llo"sv)); str ptr_size_constructed(get_literal_input(), 2, alloc); - assert(equal(ptr_size_constructed, "He"sv)); + assert(equalRanges(ptr_size_constructed, "He"sv)); #ifdef __EDG__ // TRANSITION, VSO-1270433 str iterator_constructed(literal_constructed.begin(), literal_constructed.end(), alloc); - assert(equal(iterator_constructed, literal_constructed)); + assert(equalRanges(iterator_constructed, literal_constructed)); #endif // __EDG__ const string_view_convertible convertible; str conversion_constructed(convertible, alloc); - assert(equal(conversion_constructed, literal_constructed)); + assert(equalRanges(conversion_constructed, literal_constructed)); str conversion_size_constructed(convertible, 2, 3, alloc); - assert(equal(conversion_size_constructed, "llo"sv)); + assert(equalRanges(conversion_size_constructed, "llo"sv)); } { // assignment operator @@ -241,29 +246,29 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str copy_assigned; copy_assigned = literal_constructed; - assert(equal(copy_assigned, literal_constructed)); + assert(equalRanges(copy_assigned, literal_constructed)); str move_assigned; move_assigned = move(copy_assigned); - assert(equal(move_assigned, literal_constructed)); + assert(equalRanges(move_assigned, literal_constructed)); assert(copy_assigned.empty()); str literal_assigned; literal_assigned = get_literal_input(); - assert(equal(literal_assigned, literal_constructed)); + assert(equalRanges(literal_assigned, literal_constructed)); str char_assigned; char_assigned = CharType{'!'}; - assert(equal(char_assigned, "!"sv)); + assert(equalRanges(char_assigned, "!"sv)); str initializer_list_constructed; initializer_list_constructed = {'m', 'e', 'o', 'w'}; - assert(equal(initializer_list_constructed, "meow"sv)); + assert(equalRanges(initializer_list_constructed, "meow"sv)); const string_view_convertible convertible; str conversion_assigned; conversion_assigned = convertible; - assert(equal(conversion_assigned, literal_constructed)); + assert(equalRanges(conversion_assigned, literal_constructed)); } { // assign @@ -271,49 +276,49 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str assign_char_size; assign_char_size.assign(5, CharType{'a'}); - assert(equal(assign_char_size, "aaaaa"sv)); + assert(equalRanges(assign_char_size, "aaaaa"sv)); str assign_str; assign_str.assign(literal_constructed); - assert(equal(assign_str, literal_constructed)); + assert(equalRanges(assign_str, literal_constructed)); str assign_str_pos; assign_str_pos.assign(literal_constructed, 2); - assert(equal(assign_str_pos, "llo fluffy kittens"sv)); + assert(equalRanges(assign_str_pos, "llo fluffy kittens"sv)); str assign_str_pos_len; assign_str_pos_len.assign(literal_constructed, 2, 3); - assert(equal(assign_str_pos_len, "llo"sv)); + assert(equalRanges(assign_str_pos_len, "llo"sv)); str assign_moved_str; assign_moved_str.assign(move(assign_str_pos_len)); - assert(equal(assign_moved_str, "llo"sv)); + assert(equalRanges(assign_moved_str, "llo"sv)); assert(assign_str_pos_len.empty()); str assign_literal; assign_literal.assign(get_literal_input()); - assert(equal(assign_literal, literal_constructed)); + assert(equalRanges(assign_literal, literal_constructed)); str assign_literal_count; assign_literal_count.assign(get_literal_input(), 2); - assert(equal(assign_literal_count, "He"sv)); + assert(equalRanges(assign_literal_count, "He"sv)); str assign_iterator; assign_iterator.assign(begin(get_view_input()), end(get_view_input())); - assert(equal(assign_iterator, get_view_input())); + assert(equalRanges(assign_iterator, get_view_input())); str assign_initializer; assign_initializer.assign({'m', 'e', 'o', 'w'}); - assert(equal(assign_initializer, "meow"sv)); + assert(equalRanges(assign_initializer, "meow"sv)); const string_view_convertible convertible; str assign_conversion; assign_conversion.assign(convertible); - assert(equal(assign_conversion, literal_constructed)); + assert(equalRanges(assign_conversion, literal_constructed)); str assign_conversion_size; assign_conversion_size.assign(convertible, 2, 3); - assert(equal(assign_conversion_size, "llo"sv)); + assert(equalRanges(assign_conversion_size, "llo"sv)); } #endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 { // allocator @@ -496,73 +501,73 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str insert_char = get_literal_input(); const CharType to_be_inserted = CharType{','}; insert_char.insert(insert_char.begin() + 5, to_be_inserted); - assert(equal(insert_char, "Hello, fluffy kittens"sv)); + assert(equalRanges(insert_char, "Hello, fluffy kittens"sv)); str insert_const_char = get_literal_input(); insert_const_char.insert(insert_const_char.cbegin() + 5, to_be_inserted); - assert(equal(insert_const_char, "Hello, fluffy kittens"sv)); + assert(equalRanges(insert_const_char, "Hello, fluffy kittens"sv)); str insert_char_rvalue = get_literal_input(); insert_char_rvalue.insert(insert_char_rvalue.begin() + 5, CharType{','}); - assert(equal(insert_char_rvalue, "Hello, fluffy kittens"sv)); + assert(equalRanges(insert_char_rvalue, "Hello, fluffy kittens"sv)); str insert_const_char_rvalue = get_literal_input(); insert_const_char_rvalue.insert(insert_const_char_rvalue.cbegin() + 5, CharType{','}); - assert(equal(insert_const_char_rvalue, "Hello, fluffy kittens"sv)); + assert(equalRanges(insert_const_char_rvalue, "Hello, fluffy kittens"sv)); str insert_range(2, CharType{'b'}); const auto it = insert_range.insert( insert_range.begin() + 1, begin(get_view_input()), end(get_view_input())); assert(it == insert_range.begin() + 1); - assert(equal(insert_range, "bHello fluffy kittensb"sv)); + assert(equalRanges(insert_range, "bHello fluffy kittensb"sv)); str insert_const_range(2, CharType{'b'}); const auto cit = insert_const_range.insert( insert_const_range.cbegin() + 1, begin(get_view_input()), end(get_view_input())); assert(cit == insert_const_range.cbegin() + 1); - assert(equal(insert_const_range, "bHello fluffy kittensb"sv)); + assert(equalRanges(insert_const_range, "bHello fluffy kittensb"sv)); str insert_initializer = get_literal_input(); const auto it_ilist = insert_initializer.insert(insert_initializer.begin() + 6, {'c', 'u', 't', 'e', ' '}); assert(it_ilist == insert_initializer.begin() + 6); - assert(equal(insert_initializer, "Hello cute fluffy kittens"sv)); + assert(equalRanges(insert_initializer, "Hello cute fluffy kittens"sv)); str insert_const_initializer = get_literal_input(); const auto cit_ilist = insert_const_initializer.insert(insert_const_initializer.cbegin() + 6, {'c', 'u', 't', 'e', ' '}); assert(cit_ilist == insert_const_initializer.cbegin() + 6); - assert(equal(insert_const_initializer, "Hello cute fluffy kittens"sv)); + assert(equalRanges(insert_const_initializer, "Hello cute fluffy kittens"sv)); #endif // __EDG__ } { // erase str erase_pos_count = get_literal_input(); erase_pos_count.erase(0, 6); - assert(equal(erase_pos_count, "fluffy kittens"sv)); + assert(equalRanges(erase_pos_count, "fluffy kittens"sv)); #ifdef __EDG__ // TRANSITION, VSO-1275530 str erase_iter = get_literal_input(); erase_iter.erase(erase_iter.begin()); - assert(equal(erase_iter, "ello fluffy kittens"sv)); + assert(equalRanges(erase_iter, "ello fluffy kittens"sv)); str erase_const_iter = get_literal_input(); erase_const_iter.erase(erase_const_iter.cbegin()); - assert(equal(erase_const_iter, "ello fluffy kittens"sv)); + assert(equalRanges(erase_const_iter, "ello fluffy kittens"sv)); str erase_iter_iter = get_literal_input(); erase_iter_iter.erase(erase_iter_iter.begin(), erase_iter_iter.begin() + 6); - assert(equal(erase_iter_iter, "fluffy kittens"sv)); + assert(equalRanges(erase_iter_iter, "fluffy kittens"sv)); str erase_const_iter_iter = get_literal_input(); erase_const_iter_iter.erase(erase_const_iter_iter.cbegin(), erase_const_iter_iter.cbegin() + 6); - assert(equal(erase_const_iter_iter, "fluffy kittens"sv)); + assert(equalRanges(erase_const_iter_iter, "fluffy kittens"sv)); str erased_free = get_literal_input(); erase(erased_free, CharType{'l'}); - assert(equal(erased_free, "Heo fuffy kittens"sv)); + assert(equalRanges(erased_free, "Heo fuffy kittens"sv)); str erased_free_if = get_literal_input(); erase_if(erased_free_if, [](const CharType val) { return val == CharType{'t'}; }); - assert(equal(erased_free_if, "Hello fluffy kiens"sv)); + assert(equalRanges(erased_free_if, "Hello fluffy kiens"sv)); #endif // __EDG__ } #endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 @@ -588,44 +593,44 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str append_char_size(2, CharType{'b'}); append_char_size.append(5, CharType{'a'}); - assert(equal(append_char_size, "bbaaaaa"sv)); + assert(equalRanges(append_char_size, "bbaaaaa"sv)); str append_str(2, CharType{'b'}); append_str.append(literal_constructed); - assert(equal(append_str, "bbHello fluffy kittens"sv)); + assert(equalRanges(append_str, "bbHello fluffy kittens"sv)); str append_str_pos(2, CharType{'b'}); append_str_pos.append(literal_constructed, 2); - assert(equal(append_str_pos, "bbllo fluffy kittens"sv)); + assert(equalRanges(append_str_pos, "bbllo fluffy kittens"sv)); str append_str_pos_len(2, CharType{'b'}); append_str_pos_len.append(literal_constructed, 2, 3); - assert(equal(append_str_pos_len, "bbllo"sv)); + assert(equalRanges(append_str_pos_len, "bbllo"sv)); str append_literal(2, CharType{'b'}); append_literal.append(get_literal_input()); - assert(equal(append_literal, "bbHello fluffy kittens"sv)); + assert(equalRanges(append_literal, "bbHello fluffy kittens"sv)); str append_literal_count(2, CharType{'b'}); append_literal_count.append(get_literal_input(), 2); - assert(equal(append_literal_count, "bbHe"sv)); + assert(equalRanges(append_literal_count, "bbHe"sv)); str append_iterator(2, CharType{'b'}); append_iterator.append(begin(get_view_input()), end(get_view_input())); - assert(equal(append_iterator, "bbHello fluffy kittens"sv)); + assert(equalRanges(append_iterator, "bbHello fluffy kittens"sv)); str append_initializer(2, CharType{'b'}); append_initializer.append({'m', 'e', 'o', 'w'}); - assert(equal(append_initializer, "bbmeow"sv)); + assert(equalRanges(append_initializer, "bbmeow"sv)); const string_view_convertible convertible; str append_conversion(2, CharType{'b'}); append_conversion.append(convertible); - assert(equal(append_conversion, "bbHello fluffy kittens"sv)); + assert(equalRanges(append_conversion, "bbHello fluffy kittens"sv)); str append_conversion_size(2, CharType{'b'}); append_conversion_size.append(convertible, 2, 3); - assert(equal(append_conversion_size, "bbllo"sv)); + assert(equalRanges(append_conversion_size, "bbllo"sv)); } { // operator+= @@ -633,24 +638,24 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str plus_string(2, CharType{'b'}); plus_string += literal_constructed; - assert(equal(plus_string, "bbHello fluffy kittens"sv)); + assert(equalRanges(plus_string, "bbHello fluffy kittens"sv)); str plus_character(2, CharType{'b'}); plus_character += 'a'; - assert(equal(plus_character, "bba"sv)); + assert(equalRanges(plus_character, "bba"sv)); str plus_literal(2, CharType{'b'}); plus_literal += get_literal_input(); - assert(equal(plus_literal, "bbHello fluffy kittens"sv)); + assert(equalRanges(plus_literal, "bbHello fluffy kittens"sv)); str plus_initializer(2, CharType{'b'}); plus_initializer += {'m', 'e', 'o', 'w'}; - assert(equal(plus_initializer, "bbmeow"sv)); + assert(equalRanges(plus_initializer, "bbmeow"sv)); const string_view_convertible convertible; str plus_conversion(2, CharType{'b'}); plus_conversion += convertible; - assert(equal(plus_conversion, "bbHello fluffy kittens"sv)); + assert(equalRanges(plus_conversion, "bbHello fluffy kittens"sv)); } { // compare @@ -802,97 +807,97 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str replaced_pos_count_str = get_literal_input(); replaced_pos_count_str.replace(13, 7, input); - assert(equal(replaced_pos_count_str, "Hello fluffy dog"sv)); + assert(equalRanges(replaced_pos_count_str, "Hello fluffy dog"sv)); str replaced_pos_count_str_shift = get_literal_input(); replaced_pos_count_str_shift.replace(13, 2, input); - assert(equal(replaced_pos_count_str_shift, "Hello fluffy dogttens"sv)); + assert(equalRanges(replaced_pos_count_str_shift, "Hello fluffy dogttens"sv)); #ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_str = get_literal_input(); replaced_iter_str.replace(replaced_iter_str.cbegin() + 13, replaced_iter_str.cend(), input); - assert(equal(replaced_iter_str, "Hello fluffy dog"sv)); + assert(equalRanges(replaced_iter_str, "Hello fluffy dog"sv)); str replaced_iter_str_shift = get_literal_input(); replaced_iter_str_shift.replace( replaced_iter_str_shift.cbegin() + 13, replaced_iter_str_shift.cbegin() + 15, input); - assert(equal(replaced_iter_str_shift, "Hello fluffy dogttens"sv)); + assert(equalRanges(replaced_iter_str_shift, "Hello fluffy dogttens"sv)); #endif // __EDG__ str replaced_pos_count_str_pos_count = get_literal_input(); replaced_pos_count_str_pos_count.replace(13, 7, input, 1); - assert(equal(replaced_pos_count_str_pos_count, "Hello fluffy og"sv)); + assert(equalRanges(replaced_pos_count_str_pos_count, "Hello fluffy og"sv)); str replaced_pos_count_str_pos_count_less = get_literal_input(); replaced_pos_count_str_pos_count_less.replace(13, 2, input, 1, 2); - assert(equal(replaced_pos_count_str_pos_count_less, "Hello fluffy ogttens"sv)); + assert(equalRanges(replaced_pos_count_str_pos_count_less, "Hello fluffy ogttens"sv)); #ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_iter = get_literal_input(); replaced_iter_iter.replace( replaced_iter_iter.cbegin() + 13, replaced_iter_iter.cend(), input.begin(), input.end()); - assert(equal(replaced_iter_iter, "Hello fluffy dog"sv)); + assert(equalRanges(replaced_iter_iter, "Hello fluffy dog"sv)); str replaced_iter_iter_less = get_literal_input(); replaced_iter_iter_less.replace(replaced_iter_iter_less.cbegin() + 13, replaced_iter_iter_less.cbegin() + 15, input.begin() + 1, input.end()); - assert(equal(replaced_iter_iter_less, "Hello fluffy ogttens"sv)); + assert(equalRanges(replaced_iter_iter_less, "Hello fluffy ogttens"sv)); #endif // __EDG__ str replaced_pos_count_literal = get_literal_input(); replaced_pos_count_literal.replace(13, 2, get_dog()); - assert(equal(replaced_pos_count_literal, "Hello fluffy dogttens"sv)); + assert(equalRanges(replaced_pos_count_literal, "Hello fluffy dogttens"sv)); str replaced_pos_count_literal_count = get_literal_input(); replaced_pos_count_literal_count.replace(13, 2, get_dog(), 2); - assert(equal(replaced_pos_count_literal_count, "Hello fluffy dottens"sv)); + assert(equalRanges(replaced_pos_count_literal_count, "Hello fluffy dottens"sv)); #ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_literal = get_literal_input(); replaced_iter_literal.replace( replaced_iter_literal.cbegin() + 13, replaced_iter_literal.cbegin() + 15, get_dog()); - assert(equal(replaced_iter_literal, "Hello fluffy dogttens"sv)); + assert(equalRanges(replaced_iter_literal, "Hello fluffy dogttens"sv)); str replaced_iter_literal_count = get_literal_input(); replaced_iter_literal_count.replace(replaced_iter_literal_count.cbegin() + 13, replaced_iter_literal_count.cbegin() + 15, get_dog(), 2); - assert(equal(replaced_iter_literal_count, "Hello fluffy dottens"sv)); + assert(equalRanges(replaced_iter_literal_count, "Hello fluffy dottens"sv)); #endif // __EDG__ str replaced_pos_count_chars = get_literal_input(); replaced_pos_count_chars.replace(13, 2, 5, 'a'); - assert(equal(replaced_pos_count_chars, "Hello fluffy aaaaattens"sv)); + assert(equalRanges(replaced_pos_count_chars, "Hello fluffy aaaaattens"sv)); #ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_chars = get_literal_input(); replaced_iter_chars.replace(replaced_iter_chars.cbegin() + 13, replaced_iter_chars.cbegin() + 15, 5, 'a'); - assert(equal(replaced_iter_chars, "Hello fluffy aaaaattens"sv)); + assert(equalRanges(replaced_iter_chars, "Hello fluffy aaaaattens"sv)); str replaced_iter_init = get_literal_input(); replaced_iter_init.replace( replaced_iter_init.cbegin() + 13, replaced_iter_init.cbegin() + 15, {'c', 'u', 't', 'e', ' '}); - assert(equal(replaced_iter_init, "Hello fluffy cute ttens"sv)); + assert(equalRanges(replaced_iter_init, "Hello fluffy cute ttens"sv)); #endif // __EDG__ const string_view_convertible convertible; str replaced_pos_count_conversion = get_dog(); replaced_pos_count_conversion.replace(1, 5, convertible); - assert(equal(replaced_pos_count_conversion, "dHello fluffy kittens"sv)); + assert(equalRanges(replaced_pos_count_conversion, "dHello fluffy kittens"sv)); #ifdef __EDG__ // TRANSITION, VSO-1275530 str replaced_iter_conversion = get_dog(); replaced_iter_conversion.replace( replaced_iter_conversion.cbegin() + 1, replaced_iter_conversion.cbegin() + 2, convertible); - assert(equal(replaced_iter_conversion, "dHello fluffy kittensg"sv)); + assert(equalRanges(replaced_iter_conversion, "dHello fluffy kittensg"sv)); #endif // __EDG__ str replaced_pos_count_conversion_pos = get_dog(); replaced_pos_count_conversion_pos.replace(1, 5, convertible, 6); - assert(equal(replaced_pos_count_conversion_pos, "dfluffy kittens"sv)); + assert(equalRanges(replaced_pos_count_conversion_pos, "dfluffy kittens"sv)); str replaced_pos_count_conversion_pos_count = get_dog(); replaced_pos_count_conversion_pos_count.replace(1, 5, convertible, 6, 6); - assert(equal(replaced_pos_count_conversion_pos_count, "dfluffy"sv)); + assert(equalRanges(replaced_pos_count_conversion_pos_count, "dfluffy"sv)); } { // substr const str input = get_literal_input(); const str substr_pos = input.substr(6); - assert(equal(substr_pos, "fluffy kittens"sv)); + assert(equalRanges(substr_pos, "fluffy kittens"sv)); const str substr_pos_count = input.substr(6, 6); - assert(equal(substr_pos_count, "fluffy"sv)); + assert(equalRanges(substr_pos_count, "fluffy"sv)); } { // copy @@ -900,20 +905,20 @@ _CONSTEXPR20_CONTAINER bool test_interface() { CharType copy_count[5]; input.copy(copy_count, 5); - assert(equal(copy_count, "Hello"sv)); + assert(equalRanges(copy_count, "Hello"sv)); CharType copy_count_pos[6]; input.copy(copy_count_pos, 6, 6); - assert(equal(copy_count_pos, "fluffy"sv)); + assert(equalRanges(copy_count_pos, "fluffy"sv)); } { // resize str resized = get_literal_input(); resized.resize(3); - assert(equal(resized, "Hel"sv)); + assert(equalRanges(resized, "Hel"sv)); resized.resize(6, 'a'); - assert(equal(resized, "Helaaa"sv)); + assert(equalRanges(resized, "Helaaa"sv)); } { // swap @@ -923,12 +928,12 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str second{get_dog()}; swap(first, second); - assert(equal(first, expected_first)); - assert(equal(second, expected_second)); + assert(equalRanges(first, expected_first)); + assert(equalRanges(second, expected_second)); first.swap(second); - assert(equal(second, expected_first)); - assert(equal(first, expected_second)); + assert(equalRanges(second, expected_first)); + assert(equalRanges(first, expected_second)); } { // find @@ -1280,40 +1285,40 @@ _CONSTEXPR20_CONTAINER bool test_interface() { const str second = get_dog(); const str op_str_str = first + second; - assert(equal(op_str_str, "kittendog"sv)); + assert(equalRanges(op_str_str, "kittendog"sv)); const str op_str_literal = first + get_dog(); - assert(equal(op_str_literal, "kittendog"sv)); + assert(equalRanges(op_str_literal, "kittendog"sv)); const str op_str_char = first + CharType{'!'}; - assert(equal(op_str_char, "kitten!"sv)); + assert(equalRanges(op_str_char, "kitten!"sv)); const str op_literal_str = get_cat() + second; - assert(equal(op_str_literal, "kittendog"sv)); + assert(equalRanges(op_str_literal, "kittendog"sv)); const str op_char_str = CharType{'!'} + second; - assert(equal(op_char_str, "!dog"sv)); + assert(equalRanges(op_char_str, "!dog"sv)); const str op_rstr_rstr = str{get_cat()} + str{get_dog()}; - assert(equal(op_rstr_rstr, "kittendog"sv)); + assert(equalRanges(op_rstr_rstr, "kittendog"sv)); const str op_rstr_str = str{get_cat()} + second; - assert(equal(op_rstr_str, "kittendog"sv)); + assert(equalRanges(op_rstr_str, "kittendog"sv)); const str op_rstr_literal = str{get_cat()} + get_dog(); - assert(equal(op_rstr_literal, "kittendog"sv)); + assert(equalRanges(op_rstr_literal, "kittendog"sv)); const str op_rstr_char = str{get_cat()} + CharType{'!'}; - assert(equal(op_rstr_char, "kitten!"sv)); + assert(equalRanges(op_rstr_char, "kitten!"sv)); const str op_str_rstr = first + str{get_dog()}; - assert(equal(op_str_rstr, "kittendog"sv)); + assert(equalRanges(op_str_rstr, "kittendog"sv)); const str op_literal_rst = get_cat() + str{get_dog()}; - assert(equal(op_rstr_literal, "kittendog"sv)); + assert(equalRanges(op_rstr_literal, "kittendog"sv)); const str op_char_rstr = CharType{'!'} + str{get_dog()}; - assert(equal(op_char_rstr, "!dog"sv)); + assert(equalRanges(op_char_rstr, "!dog"sv)); } { // comparison From 2fa81143f45c5c912d04ae58452caa391c3886a5 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Sun, 14 Feb 2021 20:31:00 +0100 Subject: [PATCH 20/74] Use latest... --- tests/std/tests/P0980R1_constexpr_strings/env.lst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0980R1_constexpr_strings/env.lst b/tests/std/tests/P0980R1_constexpr_strings/env.lst index 19f025bd0e6..642f530ffad 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/env.lst +++ b/tests/std/tests/P0980R1_constexpr_strings/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\usual_matrix.lst +RUNALL_INCLUDE ..\usual_latest_matrix.lst From 1f4075ac3038abb9f4a3068aff9946b86cdecc67 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 15 Feb 2021 20:17:00 +0100 Subject: [PATCH 21/74] Try to unblock MSVC --- tests/std/tests/P0980R1_constexpr_strings/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index bc2a403fa92..fa94894ba01 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -137,7 +137,11 @@ struct string_view_convertible { // TRANSITION, EDG concepts support template constexpr bool equalRanges(const Range1& range1, const Range2& range2) noexcept { +#ifdef __cpp_lib_concepts + return ranges::equal(range1, range2); +#else // ^^^ __cpp_lib_concepts ^^^ / vvv !__cpp_lib_concepts vvv return equal(begin(range1), end(range1), begin(range2), end(range2)); +#endif // !__cpp_lib_concepts } template From 1047d741f949c2d2c60a6d6fa4a01940e1112631 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Tue, 16 Feb 2021 13:56:21 -0800 Subject: [PATCH 22/74] add feature test macro test, fix comment --- stl/inc/yvals_core.h | 2 +- .../test.compile.pass.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 13825f48e27..a5dfb5f18e7 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1202,7 +1202,7 @@ #if defined(__cpp_constexpr_dynamic_alloc) && !defined(__clang__) // TRANSITION, LLVM-48606 #define __cpp_lib_constexpr_string 201907L -#endif // __cpp_constexpr_dynamic_alloc && !__clang__ +#endif // defined(__cpp_constexpr_dynamic_alloc) && !defined(__clang__) #define __cpp_lib_constexpr_string_view 201811L #define __cpp_lib_constexpr_tuple 201811L diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index b0f604ebbca..7299b981e02 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -481,6 +481,20 @@ STATIC_ASSERT(__cpp_lib_constexpr_numeric == 201911L); #endif #endif +#if _HAS_CXX20 && !defined(__clang__) // TRANSITION, LLVM-48606 +#ifndef __cpp_lib_constexpr_string +#error __cpp_lib_constexpr_string is not defined +#elif __cpp_lib_constexpr_string != 201907L +#error __cpp_lib_constexpr_string is not 201907L +#else +STATIC_ASSERT(__cpp_lib_constexpr_string == 201907L); +#endif +#else +#ifdef __cpp_lib_constexpr_string +#error __cpp_lib_constexpr_string is defined +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_constexpr_string_view #error __cpp_lib_constexpr_string_view is not defined From 3754d0160c4bdd58896ee68e73ee9bf3fdccb650 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Tue, 16 Feb 2021 15:13:45 -0800 Subject: [PATCH 23/74] re-enable _STL_VERIFY and use __cpp_lib_constexpr_string for basic_string is_constant_evaluated codepaths --- stl/inc/xstring | 324 ++++++++++++++++-------------------------------- 1 file changed, 108 insertions(+), 216 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 67d9399e751..9f54a6fbe91 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -1855,23 +1855,18 @@ public: } // TRANSITION, DevCom-1331017 - _CONSTEXPR20_CONTAINER _String_const_iterator& operator=(const _String_const_iterator&) = default; + _CONSTEXPR20_CONTAINER _String_const_iterator& operator=(const _String_const_iterator&) noexcept = default; _NODISCARD _CONSTEXPR20_CONTAINER reference operator*() const noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_Ptr, "cannot dereference value-initialized string iterator"); - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Mycont, "cannot dereference string iterator because the iterator was" - " invalidated (e.g. reallocation occurred, or the string was destroyed)"); - const auto _Contptr = _Mycont->_Myptr(); - const auto _Rawptr = _Unfancy(_Ptr); - _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr < _Contptr + _Mycont->_Mysize, - "cannot dereference string iterator because it is out of range (e.g. an end iterator)"); - } + _STL_VERIFY(_Ptr, "cannot dereference value-initialized string iterator"); + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Mycont, "cannot dereference string iterator because the iterator was" + " invalidated (e.g. reallocation occurred, or the string was destroyed)"); + const auto _Contptr = _Mycont->_Myptr(); + const auto _Rawptr = _Unfancy(_Ptr); + _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr < _Contptr + _Mycont->_Mysize, + "cannot dereference string iterator because it is out of range (e.g. an end iterator)"); #endif // _ITERATOR_DEBUG_LEVEL >= 1 _Analysis_assume_(_Ptr); @@ -1884,17 +1879,11 @@ public: _CONSTEXPR20_CONTAINER _String_const_iterator& operator++() noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_Ptr, "cannot increment value-initialized string iterator"); - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Mycont, "cannot increment string iterator because the iterator was" - " invalidated (e.g. reallocation occurred, or the string was destroyed)"); - _STL_VERIFY( - _Unfancy(_Ptr) < _Mycont->_Myptr() + _Mycont->_Mysize, "cannot increment string iterator past end"); - } + _STL_VERIFY(_Ptr, "cannot increment value-initialized string iterator"); + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Mycont, "cannot increment string iterator because the iterator was" + " invalidated (e.g. reallocation occurred, or the string was destroyed)"); + _STL_VERIFY(_Unfancy(_Ptr) < _Mycont->_Myptr() + _Mycont->_Mysize, "cannot increment string iterator past end"); #endif // _ITERATOR_DEBUG_LEVEL >= 1 ++_Ptr; @@ -1909,16 +1898,11 @@ public: _CONSTEXPR20_CONTAINER _String_const_iterator& operator--() noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_Ptr, "cannot decrement value-initialized string iterator"); - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Mycont, "cannot decrement string iterator because the iterator was" - " invalidated (e.g. reallocation occurred, or the string was destroyed)"); - _STL_VERIFY(_Mycont->_Myptr() < _Unfancy(_Ptr), "cannot decrement string iterator before begin"); - } + _STL_VERIFY(_Ptr, "cannot decrement value-initialized string iterator"); + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Mycont, "cannot decrement string iterator because the iterator was" + " invalidated (e.g. reallocation occurred, or the string was destroyed)"); + _STL_VERIFY(_Mycont->_Myptr() < _Unfancy(_Ptr), "cannot decrement string iterator before begin"); #endif // _ITERATOR_DEBUG_LEVEL >= 1 --_Ptr; @@ -1937,26 +1921,21 @@ public: return; } -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_ASSERT(_Ptr, "cannot seek value-initialized string iterator"); - const auto _Mycont = static_cast(this->_Getcont()); - _STL_ASSERT(_Mycont, "cannot seek string iterator because the iterator was" - " invalidated (e.g. reallocation occurred, or the string was destroyed)"); - const auto _Contptr = _Mycont->_Myptr(); - const auto _Rawptr = _Unfancy(_Ptr); + _STL_ASSERT(_Ptr, "cannot seek value-initialized string iterator"); + const auto _Mycont = static_cast(this->_Getcont()); + _STL_ASSERT(_Mycont, "cannot seek string iterator because the iterator was" + " invalidated (e.g. reallocation occurred, or the string was destroyed)"); + const auto _Contptr = _Mycont->_Myptr(); + const auto _Rawptr = _Unfancy(_Ptr); - if (_Off < 0) { - _STL_VERIFY(_Contptr - _Rawptr <= _Off, "cannot seek string iterator before begin"); - } + if (_Off < 0) { + _STL_VERIFY(_Contptr - _Rawptr <= _Off, "cannot seek string iterator before begin"); + } - if (_Off > 0) { - using _Size_type = typename _Mystr::size_type; - const auto _Left = _Mycont->_Mysize - static_cast<_Size_type>(_Rawptr - _Contptr); - _STL_VERIFY(static_cast<_Size_type>(_Off) <= _Left, "cannot seek string iterator after end"); - } + if (_Off > 0) { + using _Size_type = typename _Mystr::size_type; + const auto _Left = _Mycont->_Mysize - static_cast<_Size_type>(_Rawptr - _Contptr); + _STL_VERIFY(static_cast<_Size_type>(_Off) <= _Left, "cannot seek string iterator after end"); } #else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv (void) _Off; @@ -2023,13 +2002,8 @@ public: _CONSTEXPR20_CONTAINER void _Compat(const _String_const_iterator& _Right) const noexcept { // test for compatible iterator pair #if _ITERATOR_DEBUG_LEVEL >= 1 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "string iterators incompatible (e.g." - " point to different string instances)"); - } + _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "string iterators incompatible (e.g." + " point to different string instances)"); #else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv (void) _Right; #endif // _ITERATOR_DEBUG_LEVEL @@ -2038,14 +2012,8 @@ public: #if _ITERATOR_DEBUG_LEVEL >= 1 friend _CONSTEXPR20_CONTAINER void _Verify_range( const _String_const_iterator& _First, const _String_const_iterator& _Last) noexcept { -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY( - _First._Getcont() == _Last._Getcont(), "string iterators in range are from different containers"); - _STL_VERIFY(_First._Ptr <= _Last._Ptr, "string iterator range transposed"); - } + _STL_VERIFY(_First._Getcont() == _Last._Getcont(), "string iterators in range are from different containers"); + _STL_VERIFY(_First._Ptr <= _Last._Ptr, "string iterator range transposed"); } #endif // _ITERATOR_DEBUG_LEVEL >= 1 @@ -2077,32 +2045,21 @@ struct pointer_traits<_String_const_iterator<_Mystr>> { _NODISCARD static constexpr element_type* to_address(const pointer _Iter) noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - const auto _Mycont = static_cast(_Iter._Getcont()); - if (!_Mycont) { - _STL_VERIFY(!_Iter._Ptr, - "cannot convert string iterator to pointer because the iterator was invalidated " - "(e.g. reallocation occurred, or the string was destroyed)"); - } + const auto _Mycont = static_cast(_Iter._Getcont()); + if (!_Mycont) { + _STL_VERIFY(!_Iter._Ptr, "cannot convert string iterator to pointer because the iterator was invalidated " + "(e.g. reallocation occurred, or the string was destroyed)"); } #endif // _ITERATOR_DEBUG_LEVEL >= 1 const auto _Rawptr = _STD to_address(_Iter._Ptr); #if _ITERATOR_DEBUG_LEVEL >= 1 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - const auto _Mycont = static_cast(_Iter._Getcont()); - if (_Mycont) { - const auto _Contptr = _Mycont->_Myptr(); - _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr <= _Contptr + _Mycont->_Mysize, - "cannot convert string iterator to pointer because it is out of range"); - } + const auto _Mycont = static_cast(_Iter._Getcont()); + if (_Mycont) { + const auto _Contptr = _Mycont->_Myptr(); + _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr <= _Contptr + _Mycont->_Mysize, + "cannot convert string iterator to pointer because it is out of range"); } #endif // _ITERATOR_DEBUG_LEVEL >= 1 @@ -2129,7 +2086,7 @@ public: using _Mybase::_Mybase; // TRANSITION, DevCom-1331017 - _CONSTEXPR20_CONTAINER _String_iterator& operator=(const _String_iterator&) = default; + _CONSTEXPR20_CONTAINER _String_iterator& operator=(const _String_iterator&) noexcept = default; _NODISCARD _CONSTEXPR20_CONTAINER reference operator*() const noexcept { return const_cast(_Mybase::operator*()); @@ -2284,11 +2241,11 @@ public: } _CONSTEXPR20_CONTAINER bool _Large_string_engaged() const noexcept { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { return true; } -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string return _BUF_SIZE <= _Myres; } @@ -2577,11 +2534,11 @@ public: _CONSTEXPR20_CONTAINER basic_string(basic_string&& _Right) noexcept : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { _Take_contents(_Right, bool_constant{}); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); } @@ -2600,11 +2557,11 @@ public: } } -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { _Take_contents(_Right, bool_constant{}); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); } @@ -2632,7 +2589,7 @@ public: _Ptr = _Unfancy(_Fancyptr); _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); } -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string else if (_STD is_constant_evaluated()) { // SSO disabled in constexpr context const pointer _Fancyptr = _Getal().allocate(_New_capacity + 1); // throws _Ptr = _Unfancy(_Fancyptr); @@ -2642,7 +2599,7 @@ public: if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once _Traits::assign(_Ptr, _New_capacity + 1, _Elem()); } -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; @@ -2670,11 +2627,11 @@ public: if (_Fits_in_left && _Right_capacity <= _Left_capacity) { // take _Left's buffer, max_size() is OK because _Fits_in_left _My_data._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); // throws, hereafter nothrow in this block -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { _Take_contents(_Left, bool_constant{}); // cannot memcpy in constexpr context } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { _Take_contents(_Left, bool_constant<_Can_memcpy_val>{}); } @@ -2697,11 +2654,11 @@ public: // therefore: _Right must have more than the minimum capacity, so it must be _Large_string_engaged() _STL_INTERNAL_CHECK(_Right_data._Large_string_engaged()); _My_data._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); // throws, hereafter nothrow in this block -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { _Take_contents(_Right, bool_constant{}); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); } @@ -2723,11 +2680,11 @@ public: _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws const pointer _Fancyptr = _Getal().allocate(_New_capacity + 1); // throws // nothrow hereafter -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once _Traits::assign(_Unfancy(_Fancyptr), _New_capacity + 1, _Elem()); } -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; @@ -2772,11 +2729,11 @@ private: _CONSTEXPR20_CONTAINER void _Move_assign(basic_string& _Right, _Equal_allocators) noexcept { _Tidy_deallocate(); _Pocma(_Getal(), _Right._Getal()); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { _Take_contents(_Right, bool_constant{}); } else -#endif +#endif // __cpp_lib_constexpr_string { _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); } @@ -2791,11 +2748,11 @@ private: _Mypair._Myval2._Reload_proxy( _GET_PROXY_ALLOCATOR(_Alty, _Getal()), _GET_PROXY_ALLOCATOR(_Alty, _Right._Getal())); _Pocma(_Getal(), _Right._Getal()); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { _Take_contents(_Right, bool_constant{}); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { _Take_contents(_Right, bool_constant<_Can_memcpy_val>{}); } @@ -2943,11 +2900,11 @@ private: const pointer _New_array = _Al.allocate(_New_capacity + 1); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_array); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once _Traits::assign(_Unfancy(_New_array), _New_capacity + 1, _Elem()); } -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string _Traits::copy(_Unfancy(_New_array), _Right_ptr, _Right_size + 1); _My_data._Mysize = _Right_size; _My_data._Myres = _New_capacity; @@ -2981,12 +2938,7 @@ public: _CONSTEXPR20_CONTAINER iterator insert(const const_iterator _Where, const initializer_list<_Elem> _Ilist) { #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); - } + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); insert(_Off, _Ilist.begin(), _Convert_size(_Ilist.size())); @@ -2998,12 +2950,7 @@ public: // replace with initializer_list _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); - } + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Offset = static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()); const auto _Length = static_cast(_Last._Ptr - _First._Ptr); @@ -3026,9 +2973,9 @@ private: _CONSTEXPR20_CONTAINER void _Copy_assign_val_from_small(const basic_string& _Right) { // TRANSITION, VSO-761321; inline into only caller when that's fixed _Tidy_deallocate(); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { if constexpr (_Can_memcpy_val) { _Memcpy_val_from(_Right); @@ -3298,11 +3245,11 @@ public: basic_string _Right(_UFirst, _ULast, get_allocator()); if (_Mypair._Myval2._Myres < _Right._Mypair._Myval2._Myres) { _Mypair._Myval2._Orphan_all(); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { _Swap_data(_Right, bool_constant{}); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { _Swap_data(_Right, bool_constant<_Can_memcpy_val>{}); } @@ -3348,9 +3295,9 @@ public: // insert [_Ptr, _Ptr + _Count) at _Off _Mypair._Myval2._Check_offset(_Off); const size_type _Old_size = _Mypair._Myval2._Mysize; -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { // the check for overlapping ranges is technically UB, so no constant evaluation possible if (_Count <= _Mypair._Myval2._Myres - _Old_size) { _Mypair._Myval2._Mysize = _Old_size + _Count; @@ -3419,12 +3366,7 @@ public: _CONSTEXPR20_CONTAINER iterator insert(const const_iterator _Where, const _Elem _Ch) { // insert _Ch at _Where #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); - } + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); insert(_Off, 1, _Ch); @@ -3435,12 +3377,7 @@ public: const const_iterator _Where, _CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) { // insert _Count * _Elem at _Where #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); - } + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); insert(_Off, _Count, _Ch); @@ -3451,12 +3388,7 @@ public: _CONSTEXPR20_CONTAINER iterator insert(const const_iterator _Where, const _Iter _First, const _Iter _Last) { // insert [_First, _Last) at _Where, input iterators #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); - } + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); _Adl_verify_range(_First, _Last); @@ -3499,12 +3431,7 @@ public: _CONSTEXPR20_CONTAINER iterator erase(const const_iterator _Where) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); - } + _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "string iterator incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_Where._Ptr) - _Mypair._Myval2._Myptr()); _Erase_noexcept(_Off, 1); @@ -3515,12 +3442,7 @@ public: /* strengthened */ { _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); - } + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()); _Erase_noexcept(_Off, static_cast(_Last._Ptr - _First._Ptr)); @@ -3585,9 +3507,9 @@ public: } const size_type _Growth = static_cast(_Count - _Nx); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { // the check for overlapping ranges is technically UB, so no constant evaluation possible if (_Growth <= _Mypair._Myval2._Myres - _Old_size) { // growth fits _Mypair._Myval2._Mysize = _Old_size + _Growth; @@ -3672,12 +3594,7 @@ public: // replace [_First, _Last) with _Right _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); - } + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Right); @@ -3690,12 +3607,7 @@ public: // replace [_First, _Last) with _Right _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); - } + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Right); @@ -3707,12 +3619,7 @@ public: // replace [_First, _Last) with [_Ptr, _Ptr + _Count) _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); - } + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Ptr, _Count); @@ -3723,12 +3630,7 @@ public: // replace [_First, _Last) with [_Ptr, ) _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); - } + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Ptr); @@ -3739,12 +3641,7 @@ public: // replace [_First, _Last) with _Count * _Ch _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); - } + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return replace(static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()), static_cast(_Last._Ptr - _First._Ptr), _Count, _Ch); @@ -3756,12 +3653,7 @@ public: // replace [_First, _Last) with [_First2, _Last2), input iterators _Adl_verify_range(_First, _Last); #if _ITERATOR_DEBUG_LEVEL != 0 -#ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated - { - _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); - } + _STL_VERIFY(_First._Getcont() == _STD addressof(_Mypair._Myval2), "string iterators incompatible"); #endif // _ITERATOR_DEBUG_LEVEL != 0 const auto _Off = static_cast(_Unfancy(_First._Ptr) - _Mypair._Myval2._Myptr()); const auto _Length = static_cast(_Last._Ptr - _First._Ptr); @@ -3849,9 +3741,9 @@ public: if (!_My_data._Large_string_engaged()) { // can't shrink from small mode return; } -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { if (_My_data._Mysize < _BUF_SIZE) { _Become_small(); @@ -3864,11 +3756,11 @@ public: auto& _Al = _Getal(); const pointer _New_ptr = _Al.allocate(_Target_capacity + 1); // throws -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once _Traits::assign(_Unfancy(_New_ptr), _Target_capacity + 1, _Elem()); } -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string _My_data._Orphan_all(); _Traits::copy(_Unfancy(_New_ptr), _Unfancy(_My_data._Bx._Ptr), _My_data._Mysize + 1); @@ -4158,11 +4050,11 @@ public: #endif // _ITERATOR_DEBUG_LEVEL != 0 } -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { // cannot call memcpy in a constexpr context _Swap_data(_Right, bool_constant{}); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { _Swap_data(_Right, bool_constant<_Can_memcpy_val>{}); } @@ -4574,21 +4466,21 @@ private: auto& _Al = _Getal(); const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once _Traits::assign(_Unfancy(_New_ptr), _New_capacity + 1, _Elem()); } -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string _Mypair._Myval2._Orphan_all(); _Mypair._Myval2._Mysize = _New_size; _Mypair._Myval2._Myres = _New_capacity; _Fn(_Unfancy(_New_ptr), _New_size, _Args...); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { _Al.deallocate(_Mypair._Myval2._Bx._Ptr, _Old_capacity + 1); _Mypair._Myval2._Bx._Ptr = _New_ptr; } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { if (_BUF_SIZE <= _Old_capacity) { _Al.deallocate(_Mypair._Myval2._Bx._Ptr, _Old_capacity + 1); @@ -4617,23 +4509,23 @@ private: auto& _Al = _Getal(); const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it once _Traits::assign(_Unfancy(_New_ptr), _New_capacity + 1, _Elem()); } -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string _My_data._Orphan_all(); _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; _Elem* const _Raw_new = _Unfancy(_New_ptr); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { const pointer _Old_ptr = _My_data._Bx._Ptr; _Fn(_Raw_new, _Unfancy(_Old_ptr), _Old_size, _Args...); _Al.deallocate(_Old_ptr, _Old_capacity + 1); _My_data._Bx._Ptr = _New_ptr; } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { if (_BUF_SIZE <= _Old_capacity) { const pointer _Old_ptr = _My_data._Bx._Ptr; @@ -4652,9 +4544,9 @@ private: // release any held storage and return to small string mode // pre: *this is in large string mode // pre: this is small enough to return to small string mode -#ifdef __cpp_lib_is_constant_evaluated - _STL_ASSERT(!_STD is_constant_evaluated(), "SSO should be disbaled in a constexpr context"); -#endif // __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string + _STL_ASSERT(!_STD is_constant_evaluated(), "SSO should be disabled in a constexpr context"); +#endif // __cpp_lib_constexpr_string _Mypair._Myval2._Orphan_all(); const pointer _Ptr = _Mypair._Myval2._Bx._Ptr; @@ -4672,7 +4564,7 @@ private: _CONSTEXPR20_CONTAINER void _Tidy_init() noexcept { // initialize basic_string data members _Mypair._Myval2._Mysize = 0; -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { auto& _My_data = _Mypair._Myval2; _My_data._Myres = _BUF_SIZE; // SSO disabled in constexpr context @@ -4683,7 +4575,7 @@ private: _Elem* const _Raw_new = _Unfancy(_New_ptr); _Traits::assign(_Raw_new, _BUF_SIZE + 1, _Elem()); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { _Mypair._Myval2._Myres = _BUF_SIZE - 1; // the _Traits::assign is last so the codegen doesn't think the char write can alias this @@ -4693,14 +4585,14 @@ private: _CONSTEXPR20_CONTAINER void _Tidy_deallocate() noexcept { // initialize buffer, deallocating any storage _Mypair._Myval2._Orphan_all(); -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_string if (_STD is_constant_evaluated()) { const pointer _Ptr = _Mypair._Myval2._Bx._Ptr; auto& _Al = _Getal(); _Destroy_in_place(_Mypair._Myval2._Bx._Ptr); _Al.deallocate(_Ptr, _Mypair._Myval2._Myres + 1); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_string { if (_Mypair._Myval2._Large_string_engaged()) { const pointer _Ptr = _Mypair._Myval2._Bx._Ptr; From 098b9f8cc5445539fcf93791b24146462445bf55 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Tue, 16 Feb 2021 15:16:12 -0800 Subject: [PATCH 24/74] fix regression in comments --- stl/inc/xstring | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 9f54a6fbe91..0027b75e628 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -4368,7 +4368,7 @@ public: } _NODISCARD _CONSTEXPR20_CONTAINER int compare(size_type _Off, size_type _Nx, const basic_string& _Right) const { - // compare [_Off, _Off + _N0) with _Right + // compare [_Off, _Off + _Nx) with _Right _Mypair._Myval2._Check_offset(_Off); return _Traits_compare<_Traits>(_Mypair._Myval2._Myptr() + _Off, _Mypair._Myval2._Clamp_suffix_size(_Off, _Nx), _Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize); @@ -4376,7 +4376,7 @@ public: _NODISCARD _CONSTEXPR20_CONTAINER int compare(const size_type _Off, const size_type _Nx, const basic_string& _Right, const size_type _Roff, const size_type _Count = npos) const { - // compare [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count) + // compare [_Off, _Off + _Nx) with _Right [_Roff, _Roff + _Count) _Mypair._Myval2._Check_offset(_Off); _Right._Mypair._Myval2._Check_offset(_Roff); return _Traits_compare<_Traits>(_Mypair._Myval2._Myptr() + _Off, _Mypair._Myval2._Clamp_suffix_size(_Off, _Nx), @@ -4390,7 +4390,7 @@ public: _NODISCARD _CONSTEXPR20_CONTAINER int compare( const size_type _Off, const size_type _Nx, _In_z_ const _Elem* const _Ptr) const { - // compare [_Off, _Off + _N0) with [_Ptr, ) + // compare [_Off, _Off + _Nx) with [_Ptr, ) _Mypair._Myval2._Check_offset(_Off); return _Traits_compare<_Traits>(_Mypair._Myval2._Myptr() + _Off, _Mypair._Myval2._Clamp_suffix_size(_Off, _Nx), _Ptr, _Traits::length(_Ptr)); @@ -4398,7 +4398,7 @@ public: _NODISCARD _CONSTEXPR20_CONTAINER int compare(const size_type _Off, const size_type _Nx, _In_reads_(_Count) const _Elem* const _Ptr, const size_type _Count) const { - // compare [_Off, _Off + _N0) with [_Ptr, _Ptr + _Count) + // compare [_Off, _Off + _Nx) with [_Ptr, _Ptr + _Count) _Mypair._Myval2._Check_offset(_Off); return _Traits_compare<_Traits>( _Mypair._Myval2._Myptr() + _Off, _Mypair._Myval2._Clamp_suffix_size(_Off, _Nx), _Ptr, _Count); From 99ea643946d6f3b737e955f8fabd8a8ebddb58cb Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Tue, 16 Feb 2021 16:20:20 -0800 Subject: [PATCH 25/74] remove extra declaration --- stl/inc/xstring | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 0027b75e628..fda70ec5b5b 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2055,7 +2055,6 @@ struct pointer_traits<_String_const_iterator<_Mystr>> { const auto _Rawptr = _STD to_address(_Iter._Ptr); #if _ITERATOR_DEBUG_LEVEL >= 1 - const auto _Mycont = static_cast(_Iter._Getcont()); if (_Mycont) { const auto _Contptr = _Mycont->_Myptr(); _STL_VERIFY(_Contptr <= _Rawptr && _Rawptr <= _Contptr + _Mycont->_Mysize, From 40e6b43920435ad6360533b7ca8942370a910084 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Tue, 16 Feb 2021 20:06:09 -0800 Subject: [PATCH 26/74] address some review comments --- stl/inc/xstring | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index fda70ec5b5b..e663228a3e4 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2581,7 +2581,6 @@ public: _Elem* _Ptr = _My_data._Bx._Buf; auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws - 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 @@ -2738,7 +2737,7 @@ private: } } - void _Move_assign(basic_string& _Right, _Propagate_allocators) noexcept { + _CONSTEXPR20_CONTAINER void _Move_assign(basic_string& _Right, _Propagate_allocators) noexcept { if (_Getal() == _Right._Getal()) { _Move_assign(_Right, _Equal_allocators{}); } else { @@ -2758,7 +2757,7 @@ private: } } - void _Move_assign(basic_string& _Right, _No_propagate_allocators) { + _CONSTEXPR20_CONTAINER void _Move_assign(basic_string& _Right, _No_propagate_allocators) { if (_Getal() == _Right._Getal()) { _Move_assign(_Right, _Equal_allocators{}); } else { @@ -2971,11 +2970,12 @@ public: private: _CONSTEXPR20_CONTAINER void _Copy_assign_val_from_small(const basic_string& _Right) { // TRANSITION, VSO-761321; inline into only caller when that's fixed - _Tidy_deallocate(); #ifdef __cpp_lib_constexpr_string + _STL_ASSERT(!_STD is_constant_evaluated(), "SSO should be disabled in a constexpr context"); if (!_STD is_constant_evaluated()) #endif // __cpp_lib_constexpr_string { + _Tidy_deallocate(); if constexpr (_Can_memcpy_val) { _Memcpy_val_from(_Right); return; @@ -3009,6 +3009,12 @@ private: const auto _New_capacity = _Calculate_growth(_New_size, 0, _Right.max_size()); auto _Right_al_non_const = _Right_al; const auto _New_ptr = _Right_al_non_const.allocate(_New_capacity); // throws + + // if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it + // once + // _Traits::assign(_Unfancy(_New_ptr), _New_size + 1, _Elem()); + // } + _Traits::copy(_Unfancy(_New_ptr), _Unfancy(_Right._Mypair._Myval2._Bx._Ptr), _New_size + 1); _Tidy_deallocate(); _Mypair._Myval2._Bx._Ptr = _New_ptr; @@ -3995,6 +4001,10 @@ public: _CONSTEXPR20_CONTAINER void _Swap_bx_large_with_small(_Scary_val& _Starts_large, _Scary_val& _Starts_small) { // exchange a string in large mode with one in small mode + +#ifdef __cpp_lib_constexpr_string + _STL_ASSERT(!_STD is_constant_evaluated(), "SSO should be disabled in a constexpr context"); +#endif // __cpp_lib_constexpr_string const pointer _Ptr = _Starts_large._Bx._Ptr; _Destroy_in_place(_Starts_large._Bx._Ptr); _Traits::copy(_Starts_large._Bx._Buf, _Starts_small._Bx._Buf, _BUF_SIZE); From 861d262359dcdbebd0c3acecb5aabb2271b07ca2 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Tue, 16 Feb 2021 20:07:10 -0800 Subject: [PATCH 27/74] disable tests for EDG because bugs :( --- tests/std/tests/P0980R1_constexpr_strings/test.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index fa94894ba01..222e0d585d5 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -146,6 +146,7 @@ constexpr bool equalRanges(const Range1& range1, const Range2& range2) noexcept template _CONSTEXPR20_CONTAINER bool test_interface() { +#ifndef __EDG__ // TRANSITION, VSO-1273296 using str = basic_string; #if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 { // constructors @@ -1384,6 +1385,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { const bool greater_eq_literal_str = get_view_input() >= third; assert(!greater_eq_literal_str); } +#endif // __EDG__ #endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 return true; } @@ -1391,6 +1393,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { template _CONSTEXPR20_CONTAINER bool test_iterators() { #if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 +#ifndef __EDG__ // TRANSITION, VSO-1273296s using str = basic_string; str literal_constructed = get_literal_input(); @@ -1476,6 +1479,7 @@ _CONSTEXPR20_CONTAINER bool test_iterators() { const auto cit = literal_constructed.cbegin() + 2; assert(cit[2] == 'l'); } +#endif // __EDG__ #endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 return true; } @@ -1484,7 +1488,7 @@ template _CONSTEXPR20_CONTAINER bool test_growth() { #if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 using str = basic_string; - +#ifndef __EDG__ // TRANSITION, VSO-1273296 { str v(1007, 'a'); @@ -1585,6 +1589,7 @@ _CONSTEXPR20_CONTAINER bool test_growth() { } } #endif // __EDG__ +#endif // __EDG__ #endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 return true; } From 5a16936fec04835ad4bb971a2927a7b43923c95b Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Thu, 18 Feb 2021 11:37:06 -0800 Subject: [PATCH 28/74] re-enable fixes from review comments --- stl/inc/xstring | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index e663228a3e4..37986429504 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2972,14 +2972,11 @@ private: // TRANSITION, VSO-761321; inline into only caller when that's fixed #ifdef __cpp_lib_constexpr_string _STL_ASSERT(!_STD is_constant_evaluated(), "SSO should be disabled in a constexpr context"); - if (!_STD is_constant_evaluated()) #endif // __cpp_lib_constexpr_string - { - _Tidy_deallocate(); - if constexpr (_Can_memcpy_val) { - _Memcpy_val_from(_Right); - return; - } + _Tidy_deallocate(); + if constexpr (_Can_memcpy_val) { + _Memcpy_val_from(_Right); + return; } _Traits::copy(_Mypair._Myval2._Bx._Buf, _Right._Mypair._Myval2._Bx._Buf, _Right._Mypair._Myval2._Mysize + 1); @@ -3010,10 +3007,11 @@ private: auto _Right_al_non_const = _Right_al; const auto _New_ptr = _Right_al_non_const.allocate(_New_capacity); // throws - // if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it - // once - // _Traits::assign(_Unfancy(_New_ptr), _New_size + 1, _Elem()); - // } +#ifdef __cpp_lib_constexpr_string + if (_STD is_constant_evaluated()) { // Copying into uninitialized memory is technically UB, so fill it + _Traits::assign(_Unfancy(_New_ptr), _New_size + 1, _Elem()); + } +#endif // __cpp_lib_constexpr_string _Traits::copy(_Unfancy(_New_ptr), _Unfancy(_Right._Mypair._Myval2._Bx._Ptr), _New_size + 1); _Tidy_deallocate(); From 58d345ddedbe7c57f6e8085d6b356b3ce34f6b02 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Thu, 18 Feb 2021 15:38:04 -0800 Subject: [PATCH 29/74] Use MSVC_INTERNAL_TESTING throughout added test --- .../tests/P0980R1_constexpr_strings/test.cpp | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index 222e0d585d5..ea15f371e06 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -148,7 +148,7 @@ template _CONSTEXPR20_CONTAINER bool test_interface() { #ifndef __EDG__ // TRANSITION, VSO-1273296 using str = basic_string; -#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 { // constructors // range constructors str literal_constructed{get_literal_input()}; @@ -188,10 +188,10 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str ptr_size_constructed(get_literal_input(), 2); assert(equalRanges(ptr_size_constructed, "He"sv)); -#ifdef __EDG__ // TRANSITION, VSO-1270433 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1270433 str iterator_constructed(literal_constructed.begin(), literal_constructed.end()); assert(equalRanges(iterator_constructed, literal_constructed)); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) const string_view_convertible convertible; str conversion_constructed(convertible); assert(equalRanges(conversion_constructed, literal_constructed)); @@ -234,10 +234,10 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str ptr_size_constructed(get_literal_input(), 2, alloc); assert(equalRanges(ptr_size_constructed, "He"sv)); -#ifdef __EDG__ // TRANSITION, VSO-1270433 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1270433 str iterator_constructed(literal_constructed.begin(), literal_constructed.end(), alloc); assert(equalRanges(iterator_constructed, literal_constructed)); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) const string_view_convertible convertible; str conversion_constructed(convertible, alloc); assert(equalRanges(conversion_constructed, literal_constructed)); @@ -325,13 +325,13 @@ _CONSTEXPR20_CONTAINER bool test_interface() { assign_conversion_size.assign(convertible, 2, 3); assert(equalRanges(assign_conversion_size, "llo"sv)); } -#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 { // allocator str default_constructed; [[maybe_unused]] const auto alloc = default_constructed.get_allocator(); static_assert(is_same_v, allocator>); } -#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 { // access str literal_constructed = get_literal_input(); const str const_literal_constructed = get_literal_input(); @@ -411,23 +411,23 @@ _CONSTEXPR20_CONTAINER bool test_interface() { const auto e = literal_constructed.end(); static_assert(is_same_v, typename str::iterator>); -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 assert(*prev(e) == CharType{'s'}); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) const auto ce = literal_constructed.cend(); static_assert(is_same_v, typename str::const_iterator>); -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 assert(*prev(ce) == CharType{'s'}); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) const auto ce2 = const_literal_constructed.end(); static_assert(is_same_v, typename str::const_iterator>); -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 assert(*prev(ce2) == CharType{'s'}); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) -#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 2 // TRANSITION, 16.10p1 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 2 // TRANSITION, 16.10p1 const auto rb = literal_constructed.rbegin(); static_assert(is_same_v, reverse_iterator>); assert(*rb == CharType{'s'}); @@ -451,7 +451,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { const auto cre2 = const_literal_constructed.rend(); static_assert(is_same_v, reverse_iterator>); assert(*prev(cre2) == CharType{'H'}); -#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 2 +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 2 } { // capacity @@ -502,7 +502,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { } { // insert -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 str insert_char = get_literal_input(); const CharType to_be_inserted = CharType{','}; insert_char.insert(insert_char.begin() + 5, to_be_inserted); @@ -542,14 +542,14 @@ _CONSTEXPR20_CONTAINER bool test_interface() { insert_const_initializer.insert(insert_const_initializer.cbegin() + 6, {'c', 'u', 't', 'e', ' '}); assert(cit_ilist == insert_const_initializer.cbegin() + 6); assert(equalRanges(insert_const_initializer, "Hello cute fluffy kittens"sv)); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) } { // erase str erase_pos_count = get_literal_input(); erase_pos_count.erase(0, 6); assert(equalRanges(erase_pos_count, "fluffy kittens"sv)); -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 str erase_iter = get_literal_input(); erase_iter.erase(erase_iter.begin()); assert(equalRanges(erase_iter, "ello fluffy kittens"sv)); @@ -573,9 +573,9 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str erased_free_if = get_literal_input(); erase_if(erased_free_if, [](const CharType val) { return val == CharType{'t'}; }); assert(equalRanges(erased_free_if, "Hello fluffy kiens"sv)); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) } -#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 { // push_back / pop_back str pushed; @@ -592,7 +592,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { assert(pushed.size() == 1); assert(pushed.back() == CharType{'y'}); } -#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 { // append const str literal_constructed = get_literal_input(); @@ -817,7 +817,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str replaced_pos_count_str_shift = get_literal_input(); replaced_pos_count_str_shift.replace(13, 2, input); assert(equalRanges(replaced_pos_count_str_shift, "Hello fluffy dogttens"sv)); -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 str replaced_iter_str = get_literal_input(); replaced_iter_str.replace(replaced_iter_str.cbegin() + 13, replaced_iter_str.cend(), input); assert(equalRanges(replaced_iter_str, "Hello fluffy dog"sv)); @@ -826,7 +826,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { replaced_iter_str_shift.replace( replaced_iter_str_shift.cbegin() + 13, replaced_iter_str_shift.cbegin() + 15, input); assert(equalRanges(replaced_iter_str_shift, "Hello fluffy dogttens"sv)); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) str replaced_pos_count_str_pos_count = get_literal_input(); replaced_pos_count_str_pos_count.replace(13, 7, input, 1); assert(equalRanges(replaced_pos_count_str_pos_count, "Hello fluffy og"sv)); @@ -834,7 +834,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str replaced_pos_count_str_pos_count_less = get_literal_input(); replaced_pos_count_str_pos_count_less.replace(13, 2, input, 1, 2); assert(equalRanges(replaced_pos_count_str_pos_count_less, "Hello fluffy ogttens"sv)); -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 str replaced_iter_iter = get_literal_input(); replaced_iter_iter.replace( replaced_iter_iter.cbegin() + 13, replaced_iter_iter.cend(), input.begin(), input.end()); @@ -844,7 +844,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { replaced_iter_iter_less.replace(replaced_iter_iter_less.cbegin() + 13, replaced_iter_iter_less.cbegin() + 15, input.begin() + 1, input.end()); assert(equalRanges(replaced_iter_iter_less, "Hello fluffy ogttens"sv)); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) str replaced_pos_count_literal = get_literal_input(); replaced_pos_count_literal.replace(13, 2, get_dog()); assert(equalRanges(replaced_pos_count_literal, "Hello fluffy dogttens"sv)); @@ -852,7 +852,7 @@ _CONSTEXPR20_CONTAINER bool test_interface() { str replaced_pos_count_literal_count = get_literal_input(); replaced_pos_count_literal_count.replace(13, 2, get_dog(), 2); assert(equalRanges(replaced_pos_count_literal_count, "Hello fluffy dottens"sv)); -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 str replaced_iter_literal = get_literal_input(); replaced_iter_literal.replace( replaced_iter_literal.cbegin() + 13, replaced_iter_literal.cbegin() + 15, get_dog()); @@ -862,11 +862,11 @@ _CONSTEXPR20_CONTAINER bool test_interface() { replaced_iter_literal_count.replace(replaced_iter_literal_count.cbegin() + 13, replaced_iter_literal_count.cbegin() + 15, get_dog(), 2); assert(equalRanges(replaced_iter_literal_count, "Hello fluffy dottens"sv)); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) str replaced_pos_count_chars = get_literal_input(); replaced_pos_count_chars.replace(13, 2, 5, 'a'); assert(equalRanges(replaced_pos_count_chars, "Hello fluffy aaaaattens"sv)); -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 str replaced_iter_chars = get_literal_input(); replaced_iter_chars.replace(replaced_iter_chars.cbegin() + 13, replaced_iter_chars.cbegin() + 15, 5, 'a'); assert(equalRanges(replaced_iter_chars, "Hello fluffy aaaaattens"sv)); @@ -875,17 +875,17 @@ _CONSTEXPR20_CONTAINER bool test_interface() { replaced_iter_init.replace( replaced_iter_init.cbegin() + 13, replaced_iter_init.cbegin() + 15, {'c', 'u', 't', 'e', ' '}); assert(equalRanges(replaced_iter_init, "Hello fluffy cute ttens"sv)); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) const string_view_convertible convertible; str replaced_pos_count_conversion = get_dog(); replaced_pos_count_conversion.replace(1, 5, convertible); assert(equalRanges(replaced_pos_count_conversion, "dHello fluffy kittens"sv)); -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 str replaced_iter_conversion = get_dog(); replaced_iter_conversion.replace( replaced_iter_conversion.cbegin() + 1, replaced_iter_conversion.cbegin() + 2, convertible); assert(equalRanges(replaced_iter_conversion, "dHello fluffy kittensg"sv)); -#endif // __EDG__ +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) str replaced_pos_count_conversion_pos = get_dog(); replaced_pos_count_conversion_pos.replace(1, 5, convertible, 6); assert(equalRanges(replaced_pos_count_conversion_pos, "dfluffy kittens"sv)); @@ -1385,14 +1385,14 @@ _CONSTEXPR20_CONTAINER bool test_interface() { const bool greater_eq_literal_str = get_view_input() >= third; assert(!greater_eq_literal_str); } +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 #endif // __EDG__ -#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 return true; } template _CONSTEXPR20_CONTAINER bool test_iterators() { -#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 #ifndef __EDG__ // TRANSITION, VSO-1273296s using str = basic_string; str literal_constructed = get_literal_input(); @@ -1480,13 +1480,13 @@ _CONSTEXPR20_CONTAINER bool test_iterators() { assert(cit[2] == 'l'); } #endif // __EDG__ -#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 return true; } template _CONSTEXPR20_CONTAINER bool test_growth() { -#if defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1269894 using str = basic_string; #ifndef __EDG__ // TRANSITION, VSO-1273296 { @@ -1528,7 +1528,7 @@ _CONSTEXPR20_CONTAINER bool test_growth() { assert(v.size() == 1008); assert(v.capacity() == 1510); } -#ifdef __EDG__ // TRANSITION, VSO-1275530 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, VSO-1275530 { str v(1007, 'a'); @@ -1588,9 +1588,9 @@ _CONSTEXPR20_CONTAINER bool test_growth() { assert(v.capacity() == 8015); } } +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) #endif // __EDG__ -#endif // __EDG__ -#endif // defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 return true; } From 7ffe8b93f41e387dcfa122a337d6f5e2fb399c62 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Fri, 19 Feb 2021 08:59:50 -0800 Subject: [PATCH 30/74] Disable offending portions of moving allocators test --- tests/std/tests/VSO_0102478_moving_allocators/test.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/std/tests/VSO_0102478_moving_allocators/test.cpp b/tests/std/tests/VSO_0102478_moving_allocators/test.cpp index e0619b09e0b..8b73387e168 100644 --- a/tests/std/tests/VSO_0102478_moving_allocators/test.cpp +++ b/tests/std/tests/VSO_0102478_moving_allocators/test.cpp @@ -76,6 +76,7 @@ using expected_table_t = vector; #pragma warning(disable : 4640) // 'variable': construction of local static object is not thread-safe #if _ITERATOR_DEBUG_LEVEL == 0 +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) // TRANSITION, 16.10p1 const expected_table_t& get_expected_moves_table() { static const expected_table_t s_expected_moves{ {"*", "*", 1}, @@ -96,6 +97,7 @@ const expected_table_t& get_expected_copies_table() { return s_expected_copies; } +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) #else // _ITERATOR_DEBUG_LEVEL == 0 @@ -130,6 +132,7 @@ const expected_table_t& get_expected_copies_table() { #endif // _ITERATOR_DEBUG_LEVEL == 0 #pragma warning(pop) +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, 16.10p1 int query_expected_table(const expected_table_t& table, const string& type_name, const string& test_name) { auto exact_match = find_if(begin(table), end(table), [&](const test_info& other) { return type_name == other.type_name && test_name == other.test_name; }); @@ -183,6 +186,7 @@ void move_test(T val, const string& type_name, const string& test_name) { // no copying of the allocator should occur, only moves. assert(passed); } +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 template class Alloc { @@ -362,6 +366,7 @@ using container_t = typename bind_alloc_container::type; template class Dictionary> using dictionary_t = typename bind_alloc_dictionary::type; +#if defined(MSVC_INTERNAL_TESTING) || defined(__EDG__) || _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, 16.10p1 template