From b7fa4685b3558ee03b1487af85825dcb3889ca56 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 20 Nov 2020 20:13:16 +0100 Subject: [PATCH] [P1004] Implement constexpr vector Fixes #45 --- stl/inc/memory | 35 +- stl/inc/vector | 1038 ++++++++++------- stl/inc/xmemory | 601 ++++++---- stl/inc/xutility | 26 +- stl/inc/yvals_core.h | 9 +- tests/libcxx/expected_results.txt | 15 +- tests/std/test.lst | 3 + .../tests/P0784R7_library_machinery/env.lst | 4 + .../tests/P0784R7_library_machinery/test.cpp | 147 +++ .../tests/P1004R2_constexpr_vector/env.lst | 4 + .../tests/P1004R2_constexpr_vector/test.cpp | 638 ++++++++++ .../P1004R2_constexpr_vector_bool/env.lst | 4 + .../P1004R2_constexpr_vector_bool/test.cpp | 538 +++++++++ 13 files changed, 2401 insertions(+), 661 deletions(-) create mode 100644 tests/std/tests/P0784R7_library_machinery/env.lst create mode 100644 tests/std/tests/P0784R7_library_machinery/test.cpp create mode 100644 tests/std/tests/P1004R2_constexpr_vector/env.lst create mode 100644 tests/std/tests/P1004R2_constexpr_vector/test.cpp create mode 100644 tests/std/tests/P1004R2_constexpr_vector_bool/env.lst create mode 100644 tests/std/tests/P1004R2_constexpr_vector_bool/test.cpp diff --git a/stl/inc/memory b/stl/inc/memory index e9050c26eee..a35e1a076ab 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -567,22 +567,7 @@ namespace ranges { }; inline constexpr _Uninitialized_fill_n_fn uninitialized_fill_n{_Not_quite_object::_Construct_tag{}}; -} // namespace ranges -#endif // __cpp_lib_concepts - -// FUNCTION TEMPLATE construct_at -#if _HAS_CXX20 -template -_CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( - noexcept(::new (const_cast(static_cast(_Location))) - _Ty(_STD forward<_Types>(_Args)...))) // strengthened - -> decltype( - ::new (const_cast(static_cast(_Location))) _Ty(_STD forward<_Types>(_Args)...)) { - return ::new (const_cast(static_cast(_Location))) _Ty(_STD forward<_Types>(_Args)...); -} -#ifdef __cpp_lib_concepts -namespace ranges { // VARIABLE ranges::construct_at class _Construct_at_fn : private _Not_quite_object { public: @@ -603,26 +588,7 @@ namespace ranges { }; inline constexpr _Construct_at_fn construct_at{_Not_quite_object::_Construct_tag{}}; -} // namespace ranges -#endif // __cpp_lib_concepts -#endif // _HAS_CXX20 -#if _HAS_CXX17 -// FUNCTION TEMPLATE destroy_at -template -_CONSTEXPR20_DYNALLOC void destroy_at(_Ty* const _Location) noexcept /* strengthened */ { -#if _HAS_CXX20 - if constexpr (is_array_v<_Ty>) { - _Destroy_range(_STD begin(*_Location), _STD end(*_Location)); - } else -#endif // _HAS_CXX20 - { - _Location->~_Ty(); - } -} - -#ifdef __cpp_lib_concepts -namespace ranges { // VARIABLE ranges::destroy_at // clang-format off template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se> @@ -648,6 +614,7 @@ namespace ranges { } // namespace ranges #endif // __cpp_lib_concepts +#if _HAS_CXX17 // FUNCTION TEMPLATE destroy template void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // destroy all elements in [_First, _Last) diff --git a/stl/inc/vector b/stl/inc/vector index dcafb3e2272..64994cdc73f 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -37,161 +37,199 @@ public: using _Tptr = typename _Myvec::pointer; - _Vector_const_iterator() noexcept : _Ptr() {} + _CONSTEXPR20_DYNALLOC _Vector_const_iterator() noexcept : _Ptr() {} - _Vector_const_iterator(_Tptr _Parg, const _Container_base* _Pvector) noexcept : _Ptr(_Parg) { + _CONSTEXPR20_DYNALLOC _Vector_const_iterator(_Tptr _Parg, const _Container_base* _Pvector) noexcept : _Ptr(_Parg) { this->_Adopt(_Pvector); } - _NODISCARD reference operator*() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reference operator*() const noexcept { #if _ITERATOR_DEBUG_LEVEL != 0 - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Ptr, "can't dereference value-initialized vector iterator"); - _STL_VERIFY( - _Mycont->_Myfirst <= _Ptr && _Ptr < _Mycont->_Mylast, "can't dereference out of range vector iterator"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Ptr, "can't dereference value-initialized vector iterator"); + _STL_VERIFY( + _Mycont->_Myfirst <= _Ptr && _Ptr < _Mycont->_Mylast, "can't dereference out of range vector iterator"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return *_Ptr; } - _NODISCARD pointer operator->() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC pointer operator->() const noexcept { #if _ITERATOR_DEBUG_LEVEL != 0 - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Ptr, "can't dereference value-initialized vector iterator"); - _STL_VERIFY( - _Mycont->_Myfirst <= _Ptr && _Ptr < _Mycont->_Mylast, "can't dereference out of range vector iterator"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Ptr, "can't dereference value-initialized vector iterator"); + _STL_VERIFY( + _Mycont->_Myfirst <= _Ptr && _Ptr < _Mycont->_Mylast, "can't dereference out of range vector iterator"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return _Ptr; } - _Vector_const_iterator& operator++() noexcept { + _CONSTEXPR20_DYNALLOC _Vector_const_iterator& operator++() noexcept { #if _ITERATOR_DEBUG_LEVEL != 0 - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Ptr, "can't increment value-initialized vector iterator"); - _STL_VERIFY(_Ptr < _Mycont->_Mylast, "can't increment vector iterator past end"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Ptr, "can't increment value-initialized vector iterator"); + _STL_VERIFY(_Ptr < _Mycont->_Mylast, "can't increment vector iterator past end"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 ++_Ptr; return *this; } - _Vector_const_iterator operator++(int) noexcept { + _CONSTEXPR20_DYNALLOC _Vector_const_iterator operator++(int) noexcept { _Vector_const_iterator _Tmp = *this; ++*this; return _Tmp; } - _Vector_const_iterator& operator--() noexcept { + _CONSTEXPR20_DYNALLOC _Vector_const_iterator& operator--() noexcept { #if _ITERATOR_DEBUG_LEVEL != 0 - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Ptr, "can't decrement value-initialized vector iterator"); - _STL_VERIFY(_Mycont->_Myfirst < _Ptr, "can't decrement vector iterator before begin"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Ptr, "can't decrement value-initialized vector iterator"); + _STL_VERIFY(_Mycont->_Myfirst < _Ptr, "can't decrement vector iterator before begin"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 --_Ptr; return *this; } - _Vector_const_iterator operator--(int) noexcept { + _CONSTEXPR20_DYNALLOC _Vector_const_iterator operator--(int) noexcept { _Vector_const_iterator _Tmp = *this; --*this; return _Tmp; } - void _Verify_offset(const difference_type _Off) const noexcept { + _CONSTEXPR20_DYNALLOC void _Verify_offset(const difference_type _Off) const noexcept { #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Off; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 ^^^ // vvv _ITERATOR_DEBUG_LEVEL != 0 vvv - const auto _Mycont = static_cast(this->_Getcont()); - _STL_VERIFY(_Off == 0 || _Ptr, "cannot seek value-initialized vector iterator"); - if (_Off < 0) { - _STL_VERIFY(_Off >= _Mycont->_Myfirst - _Ptr, "cannot seek vector iterator before begin"); - } +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(_Off == 0 || _Ptr, "cannot seek value-initialized vector iterator"); + if (_Off < 0) { + _STL_VERIFY(_Off >= _Mycont->_Myfirst - _Ptr, "cannot seek vector iterator before begin"); + } - if (_Off > 0) { - _STL_VERIFY(_Off <= _Mycont->_Mylast - _Ptr, "cannot seek vector iterator after end"); + if (_Off > 0) { + _STL_VERIFY(_Off <= _Mycont->_Mylast - _Ptr, "cannot seek vector iterator after end"); + } } #endif // _ITERATOR_DEBUG_LEVEL == 0 } - _Vector_const_iterator& operator+=(const difference_type _Off) noexcept { + _CONSTEXPR20_DYNALLOC _Vector_const_iterator& operator+=(const difference_type _Off) noexcept { _Verify_offset(_Off); _Ptr += _Off; return *this; } - _NODISCARD _Vector_const_iterator operator+(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _Vector_const_iterator operator+(const difference_type _Off) const noexcept { _Vector_const_iterator _Tmp = *this; return _Tmp += _Off; } - _Vector_const_iterator& operator-=(const difference_type _Off) noexcept { + _CONSTEXPR20_DYNALLOC _Vector_const_iterator& operator-=(const difference_type _Off) noexcept { return *this += -_Off; } - _NODISCARD _Vector_const_iterator operator-(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _Vector_const_iterator operator-(const difference_type _Off) const noexcept { _Vector_const_iterator _Tmp = *this; return _Tmp -= _Off; } - _NODISCARD difference_type operator-(const _Vector_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC difference_type operator-(const _Vector_const_iterator& _Right) const noexcept { _Compat(_Right); return _Ptr - _Right._Ptr; } - _NODISCARD reference operator[](const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reference operator[](const difference_type _Off) const noexcept { return *(*this + _Off); } - _NODISCARD bool operator==(const _Vector_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator==(const _Vector_const_iterator& _Right) const noexcept { _Compat(_Right); return _Ptr == _Right._Ptr; } - _NODISCARD bool operator!=(const _Vector_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator!=(const _Vector_const_iterator& _Right) const noexcept { return !(*this == _Right); } - _NODISCARD bool operator<(const _Vector_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator<(const _Vector_const_iterator& _Right) const noexcept { _Compat(_Right); return _Ptr < _Right._Ptr; } - _NODISCARD bool operator>(const _Vector_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator>(const _Vector_const_iterator& _Right) const noexcept { return _Right < *this; } - _NODISCARD bool operator<=(const _Vector_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator<=(const _Vector_const_iterator& _Right) const noexcept { return !(_Right < *this); } - _NODISCARD bool operator>=(const _Vector_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator>=(const _Vector_const_iterator& _Right) const noexcept { return !(*this < _Right); } - void _Compat(const _Vector_const_iterator& _Right) const noexcept { // test for compatible iterator pair + _CONSTEXPR20_DYNALLOC void _Compat(const _Vector_const_iterator& _Right) const noexcept { + // test for compatible iterator pair #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Right; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 ^^^ // vvv _ITERATOR_DEBUG_LEVEL != 0 vvv - _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "vector iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "vector iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL == 0 } #if _ITERATOR_DEBUG_LEVEL != 0 - friend void _Verify_range(const _Vector_const_iterator& _First, const _Vector_const_iterator& _Last) noexcept { - _STL_VERIFY(_First._Getcont() == _Last._Getcont(), "vector iterators in range are from different containers"); - _STL_VERIFY(_First._Ptr <= _Last._Ptr, "vector iterator range transposed"); + friend _CONSTEXPR20_DYNALLOC void _Verify_range( + const _Vector_const_iterator& _First, const _Vector_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(), "vector iterators in range are from different containers"); + _STL_VERIFY(_First._Ptr <= _Last._Ptr, "vector iterator range transposed"); + } } #endif // _ITERATOR_DEBUG_LEVEL != 0 using _Prevent_inheriting_unwrap = _Vector_const_iterator; - _NODISCARD const value_type* _Unwrapped() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const value_type* _Unwrapped() const noexcept { return _Unfancy(_Ptr); } - void _Seek_to(const value_type* _It) noexcept { + _CONSTEXPR20_DYNALLOC void _Seek_to(const value_type* _It) noexcept { _Ptr = _Refancy<_Tptr>(const_cast(_It)); } @@ -199,7 +237,7 @@ public: }; template -_NODISCARD _Vector_const_iterator<_Myvec> operator+( +_NODISCARD _CONSTEXPR20_DYNALLOC _Vector_const_iterator<_Myvec> operator+( typename _Vector_const_iterator<_Myvec>::difference_type _Off, _Vector_const_iterator<_Myvec> _Next) noexcept { return _Next += _Off; } @@ -217,12 +255,17 @@ struct pointer_traits<_Vector_const_iterator<_Myvec>> { // capacity() of 0 is not. This function cannot distinguish those two cases, so it incorrectly does not diagnose // the latter. In practice, this isn't a significant problem since to_address returns nullptr for such an // iterator. - const auto _Mycont = static_cast(_Iter._Getcont()); - if (_Mycont) { - _STL_VERIFY(_Mycont->_Myfirst <= _Iter._Ptr && _Iter._Ptr <= _Mycont->_Mylast, - "can't convert out-of-range vector iterator to pointer"); - } else { - _STL_VERIFY(!_Iter._Ptr, "can't convert invalid vector iterator to pointer"); +#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(_Mycont->_Myfirst <= _Iter._Ptr && _Iter._Ptr <= _Mycont->_Mylast, + "can't convert out-of-range vector iterator to pointer"); + } else { + _STL_VERIFY(!_Iter._Ptr, "can't convert invalid vector iterator to pointer"); + } } #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -248,71 +291,83 @@ public: using _Mybase::_Mybase; - _NODISCARD reference operator*() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reference operator*() const noexcept { return const_cast(_Mybase::operator*()); } - _NODISCARD pointer operator->() const noexcept { - return _Const_cast(_Mybase::operator->()); + _NODISCARD _CONSTEXPR20_DYNALLOC pointer operator->() const noexcept { +#if _ITERATOR_DEBUG_LEVEL != 0 +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Mycont = static_cast(this->_Getcont()); + _STL_VERIFY(this->_Ptr, "can't dereference value-initialized vector iterator"); + _STL_VERIFY(_Mycont->_Myfirst <= this->_Ptr && this->_Ptr < _Mycont->_Mylast, + "can't dereference out of range vector iterator"); + } +#endif // _ITERATOR_DEBUG_LEVEL != 0 + + return this->_Ptr; } - _Vector_iterator& operator++() noexcept { + _CONSTEXPR20_DYNALLOC _Vector_iterator& operator++() noexcept { _Mybase::operator++(); return *this; } - _Vector_iterator operator++(int) noexcept { + _CONSTEXPR20_DYNALLOC _Vector_iterator operator++(int) noexcept { _Vector_iterator _Tmp = *this; _Mybase::operator++(); return _Tmp; } - _Vector_iterator& operator--() noexcept { + _CONSTEXPR20_DYNALLOC _Vector_iterator& operator--() noexcept { _Mybase::operator--(); return *this; } - _Vector_iterator operator--(int) noexcept { + _CONSTEXPR20_DYNALLOC _Vector_iterator operator--(int) noexcept { _Vector_iterator _Tmp = *this; _Mybase::operator--(); return _Tmp; } - _Vector_iterator& operator+=(const difference_type _Off) noexcept { + _CONSTEXPR20_DYNALLOC _Vector_iterator& operator+=(const difference_type _Off) noexcept { _Mybase::operator+=(_Off); return *this; } - _NODISCARD _Vector_iterator operator+(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _Vector_iterator operator+(const difference_type _Off) const noexcept { _Vector_iterator _Tmp = *this; return _Tmp += _Off; } - _Vector_iterator& operator-=(const difference_type _Off) noexcept { + _CONSTEXPR20_DYNALLOC _Vector_iterator& operator-=(const difference_type _Off) noexcept { _Mybase::operator-=(_Off); return *this; } using _Mybase::operator-; - _NODISCARD _Vector_iterator operator-(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _Vector_iterator operator-(const difference_type _Off) const noexcept { _Vector_iterator _Tmp = *this; return _Tmp -= _Off; } - _NODISCARD reference operator[](const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reference operator[](const difference_type _Off) const noexcept { return const_cast(_Mybase::operator[](_Off)); } using _Prevent_inheriting_unwrap = _Vector_iterator; - _NODISCARD value_type* _Unwrapped() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC value_type* _Unwrapped() const noexcept { return _Unfancy(this->_Ptr); } }; template -_NODISCARD _Vector_iterator<_Myvec> operator+( +_NODISCARD _CONSTEXPR20_DYNALLOC _Vector_iterator<_Myvec> operator+( typename _Vector_iterator<_Myvec>::difference_type _Off, _Vector_iterator<_Myvec> _Next) noexcept { return _Next += _Off; } @@ -330,12 +385,17 @@ struct pointer_traits<_Vector_iterator<_Myvec>> { // capacity() of 0 is not. This function cannot distinguish those two cases, so it incorrectly does not diagnose // the latter. In practice, this isn't a significant problem since to_address returns nullptr for such an // iterator. - const auto _Mycont = static_cast(_Iter._Getcont()); - if (_Mycont) { - _STL_VERIFY(_Mycont->_Myfirst <= _Iter._Ptr && _Iter._Ptr <= _Mycont->_Mylast, - "can't convert out-of-range vector iterator to pointer"); - } else { - _STL_VERIFY(!_Iter._Ptr, "can't convert invalid vector iterator to pointer"); +#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(_Mycont->_Myfirst <= _Iter._Ptr && _Iter._Ptr <= _Mycont->_Mylast, + "can't convert out-of-range vector iterator to pointer"); + } else { + _STL_VERIFY(!_Iter._Ptr, "can't convert invalid vector iterator to pointer"); + } } #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -372,19 +432,19 @@ public: using reference = value_type&; using const_reference = const value_type&; - _Vector_val() noexcept : _Myfirst(), _Mylast(), _Myend() {} + _CONSTEXPR20_DYNALLOC _Vector_val() noexcept : _Myfirst(), _Mylast(), _Myend() {} - _Vector_val(pointer _First, pointer _Last, pointer _End) noexcept + _CONSTEXPR20_DYNALLOC _Vector_val(pointer _First, pointer _Last, pointer _End) noexcept : _Myfirst(_First), _Mylast(_Last), _Myend(_End) {} - void _Swap_val(_Vector_val& _Right) noexcept { + _CONSTEXPR20_DYNALLOC void _Swap_val(_Vector_val& _Right) noexcept { this->_Swap_proxy_and_iterators(_Right); _Swap_adl(_Myfirst, _Right._Myfirst); _Swap_adl(_Mylast, _Right._Mylast); _Swap_adl(_Myend, _Right._Myend); } - void _Take_contents(_Vector_val& _Right) noexcept { + _CONSTEXPR20_DYNALLOC void _Take_contents(_Vector_val& _Right) noexcept { this->_Swap_proxy_and_iterators(_Right); _Myfirst = _Right._Myfirst; _Mylast = _Right._Mylast; @@ -402,12 +462,13 @@ public: // FUNCTION TEMPLATE _Unfancy_maybe_null template -auto _Unfancy_maybe_null(_Ptrty _Ptr) noexcept { // converts from a (potentially null) fancy pointer to a plain pointer +_CONSTEXPR20_DYNALLOC auto _Unfancy_maybe_null(_Ptrty _Ptr) noexcept { + // converts from a (potentially null) fancy pointer to a plain pointer return _Ptr ? _STD addressof(*_Ptr) : nullptr; } template -_Ty* _Unfancy_maybe_null(_Ty* _Ptr) noexcept { // do nothing for plain pointers +_CONSTEXPR20_DYNALLOC _Ty* _Unfancy_maybe_null(_Ty* _Ptr) noexcept { // do nothing for plain pointers return _Ptr; } @@ -445,17 +506,18 @@ public: using reverse_iterator = _STD reverse_iterator; using const_reverse_iterator = _STD reverse_iterator; - vector() noexcept(is_nothrow_default_constructible_v<_Alty>) : _Mypair(_Zero_then_variadic_args_t{}) { + _CONSTEXPR20_DYNALLOC vector() noexcept(is_nothrow_default_constructible_v<_Alty>) + : _Mypair(_Zero_then_variadic_args_t{}) { _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); } - explicit vector(const _Alloc& _Al) noexcept : _Mypair(_One_then_variadic_args_t{}, _Al) { + _CONSTEXPR20_DYNALLOC explicit vector(const _Alloc& _Al) noexcept : _Mypair(_One_then_variadic_args_t{}, _Al) { _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); } private: template - void _Construct_n_copies_of_ty(_CRT_GUARDOVERFLOW const size_type _Count, const _Ty2& _Val) { + _CONSTEXPR20_DYNALLOC void _Construct_n_copies_of_ty(_CRT_GUARDOVERFLOW const size_type _Count, const _Ty2& _Val) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); auto& _My_data = _Mypair._Myval2; _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); @@ -470,19 +532,20 @@ private: } public: - explicit vector(_CRT_GUARDOVERFLOW const size_type _Count, const _Alloc& _Al = _Alloc()) + _CONSTEXPR20_DYNALLOC explicit vector(_CRT_GUARDOVERFLOW const size_type _Count, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { _Construct_n_copies_of_ty(_Count, _Value_init_tag{}); } - vector(_CRT_GUARDOVERFLOW const size_type _Count, const _Ty& _Val, const _Alloc& _Al = _Alloc()) + _CONSTEXPR20_DYNALLOC vector( + _CRT_GUARDOVERFLOW const size_type _Count, const _Ty& _Val, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { _Construct_n_copies_of_ty(_Count, _Val); } private: template - void _Range_construct_or_tidy(_Iter _First, _Iter _Last, input_iterator_tag) { + _CONSTEXPR20_DYNALLOC void _Range_construct_or_tidy(_Iter _First, _Iter _Last, input_iterator_tag) { _Tidy_guard _Guard{this}; for (; _First != _Last; ++_First) { emplace_back(*_First); // performance note: emplace_back()'s strong guarantee is unnecessary here @@ -492,7 +555,7 @@ private: } template - void _Range_construct_or_tidy(_Iter _First, _Iter _Last, forward_iterator_tag) { + _CONSTEXPR20_DYNALLOC void _Range_construct_or_tidy(_Iter _First, _Iter _Last, forward_iterator_tag) { const auto _Count = _Convert_size(static_cast(_STD distance(_First, _Last))); if (_Count != 0) { _Buy_nonzero(_Count); @@ -505,7 +568,8 @@ private: public: template , int> = 0> - vector(_Iter _First, _Iter _Last, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { + _CONSTEXPR20_DYNALLOC vector(_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); _Adl_verify_range(_First, _Last); @@ -513,14 +577,15 @@ public: _Proxy._Release(); } - vector(initializer_list<_Ty> _Ilist, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { + _CONSTEXPR20_DYNALLOC vector(initializer_list<_Ty> _Ilist, 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); _Range_construct_or_tidy(_Ilist.begin(), _Ilist.end(), random_access_iterator_tag{}); _Proxy._Release(); } - vector(const vector& _Right) + _CONSTEXPR20_DYNALLOC vector(const vector& _Right) : _Mypair(_One_then_variadic_args_t{}, _Alty_traits::select_on_container_copy_construction(_Right._Getal())) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); auto& _My_data = _Mypair._Myval2; @@ -538,7 +603,7 @@ public: _Proxy._Release(); } - vector(const vector& _Right, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { + _CONSTEXPR20_DYNALLOC vector(const vector& _Right, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); auto& _My_data = _Mypair._Myval2; const auto& _Right_data = _Right._Mypair._Myval2; @@ -556,11 +621,13 @@ public: } private: - void _Move_construct(vector& _Right, true_type) noexcept { // move from _Right, stealing its contents + _CONSTEXPR20_DYNALLOC void _Move_construct(vector& _Right, true_type) noexcept { + // move from _Right, stealing its contents _Mypair._Myval2._Take_contents(_Right._Mypair._Myval2); } - void _Move_construct(vector& _Right, false_type) { // move from _Right, possibly moving its contents + _CONSTEXPR20_DYNALLOC void _Move_construct(vector& _Right, false_type) { + // move from _Right, possibly moving its contents if _CONSTEXPR_IF (!_Alty_traits::is_always_equal::value) { if (_Getal() != _Right._Getal()) { const auto& _Right_data = _Right._Mypair._Myval2; @@ -581,7 +648,7 @@ private: } public: - vector(vector&& _Right) noexcept + _CONSTEXPR20_DYNALLOC vector(vector&& _Right) noexcept : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal()), _STD exchange(_Right._Mypair._Myval2._Myfirst, nullptr), _STD exchange(_Right._Mypair._Myval2._Mylast, nullptr), @@ -590,7 +657,8 @@ public: _Mypair._Myval2._Swap_proxy_and_iterators(_Right._Mypair._Myval2); } - vector(vector&& _Right, const _Alloc& _Al) noexcept(_Alty_traits::is_always_equal::value) // strengthened + _CONSTEXPR20_DYNALLOC vector(vector&& _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()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); @@ -599,13 +667,13 @@ public: } private: - void _Move_assign(vector& _Right, _Equal_allocators) noexcept { + _CONSTEXPR20_DYNALLOC void _Move_assign(vector& _Right, _Equal_allocators) noexcept { _Tidy(); _Pocma(_Getal(), _Right._Getal()); _Mypair._Myval2._Take_contents(_Right._Mypair._Myval2); } - void _Move_assign(vector& _Right, _Propagate_allocators) noexcept /* terminates */ { + _CONSTEXPR20_DYNALLOC void _Move_assign(vector& _Right, _Propagate_allocators) noexcept /* terminates */ { _Tidy(); #if _ITERATOR_DEBUG_LEVEL != 0 if (_Getal() != _Right._Getal()) { @@ -619,7 +687,7 @@ private: _Mypair._Myval2._Take_contents(_Right._Mypair._Myval2); } - void _Move_assign(vector& _Right, _No_propagate_allocators) { + _CONSTEXPR20_DYNALLOC void _Move_assign(vector& _Right, _No_propagate_allocators) { if (_Getal() == _Right._Getal()) { _Move_assign(_Right, _Equal_allocators{}); } else { @@ -668,7 +736,8 @@ private: } public: - vector& operator=(vector&& _Right) noexcept(noexcept(_Move_assign(_Right, _Choose_pocma<_Alty>{}))) { + _CONSTEXPR20_DYNALLOC vector& operator=(vector&& _Right) noexcept( + noexcept(_Move_assign(_Right, _Choose_pocma<_Alty>{}))) { if (this != _STD addressof(_Right)) { _Move_assign(_Right, _Choose_pocma<_Alty>{}); } @@ -676,7 +745,7 @@ public: return *this; } - ~vector() noexcept { + _CONSTEXPR20_DYNALLOC ~vector() noexcept { _Tidy(); #if _ITERATOR_DEBUG_LEVEL != 0 auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); @@ -686,7 +755,7 @@ public: private: template - decltype(auto) _Emplace_back_with_unused_capacity(_Valty&&... _Val) { + _CONSTEXPR20_DYNALLOC decltype(auto) _Emplace_back_with_unused_capacity(_Valty&&... _Val) { // insert by perfectly forwarding into element at end, provide strong guarantee auto& _My_data = _Mypair._Myval2; pointer& _Mylast = _My_data._Mylast; @@ -704,7 +773,7 @@ private: public: template - decltype(auto) emplace_back(_Valty&&... _Val) { + _CONSTEXPR20_DYNALLOC decltype(auto) emplace_back(_Valty&&... _Val) { // insert by perfectly forwarding into element at end, provide strong guarantee auto& _My_data = _Mypair._Myval2; pointer& _Mylast = _My_data._Mylast; @@ -720,16 +789,16 @@ public: #endif // _HAS_CXX17 } - void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee + _CONSTEXPR20_DYNALLOC void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee emplace_back(_Val); } - void push_back(_Ty&& _Val) { // insert by moving into element at end, provide strong guarantee + _CONSTEXPR20_DYNALLOC void push_back(_Ty&& _Val) { // insert by moving into element at end, provide strong guarantee emplace_back(_STD move(_Val)); } template - pointer _Emplace_reallocate(const pointer _Whereptr, _Valty&&... _Val) { + _CONSTEXPR20_DYNALLOC pointer _Emplace_reallocate(const pointer _Whereptr, _Valty&&... _Val) { // reallocate and insert by perfectly forwarding _Val at _Whereptr _Alty& _Al = _Getal(); auto& _My_data = _Mypair._Myval2; @@ -774,14 +843,20 @@ public: } template - iterator emplace(const_iterator _Where, _Valty&&... _Val) { // insert by perfectly forwarding _Val at _Where + _CONSTEXPR20_DYNALLOC iterator emplace(const_iterator _Where, _Valty&&... _Val) { + // insert by perfectly forwarding _Val at _Where const pointer _Whereptr = _Where._Ptr; auto& _My_data = _Mypair._Myval2; const pointer _Oldlast = _My_data._Mylast; #if _ITERATOR_DEBUG_LEVEL == 2 - _STL_VERIFY( - _Where._Getcont() == _STD addressof(_My_data) && _Whereptr >= _My_data._Myfirst && _Oldlast >= _Whereptr, - "vector emplace iterator outside range"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Where._Getcont() == _STD addressof(_My_data) && _Whereptr >= _My_data._Myfirst + && _Oldlast >= _Whereptr, + "vector emplace iterator outside range"); + } #endif // _ITERATOR_DEBUG_LEVEL == 2 if (_Oldlast != _My_data._Myend) { @@ -804,15 +879,16 @@ public: return _Make_iterator(_Emplace_reallocate(_Whereptr, _STD forward<_Valty>(_Val)...)); } - iterator insert(const_iterator _Where, const _Ty& _Val) { // insert _Val at _Where + _CONSTEXPR20_DYNALLOC iterator insert(const_iterator _Where, const _Ty& _Val) { // insert _Val at _Where return emplace(_Where, _Val); } - iterator insert(const_iterator _Where, _Ty&& _Val) { // insert by moving _Val at _Where + _CONSTEXPR20_DYNALLOC iterator insert(const_iterator _Where, _Ty&& _Val) { // insert by moving _Val at _Where return emplace(_Where, _STD move(_Val)); } - iterator insert(const_iterator _Where, _CRT_GUARDOVERFLOW const size_type _Count, const _Ty& _Val) { + _CONSTEXPR20_DYNALLOC iterator insert( + const_iterator _Where, _CRT_GUARDOVERFLOW const size_type _Count, const _Ty& _Val) { // insert _Count * _Val at _Where const pointer _Whereptr = _Where._Ptr; @@ -822,8 +898,14 @@ public: const pointer _Oldfirst = _My_data._Myfirst; const pointer _Oldlast = _Mylast; #if _ITERATOR_DEBUG_LEVEL == 2 - _STL_VERIFY(_Where._Getcont() == _STD addressof(_My_data) && _Whereptr >= _Oldfirst && _Oldlast >= _Whereptr, - "vector insert iterator outside range"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY( + _Where._Getcont() == _STD addressof(_My_data) && _Whereptr >= _Oldfirst && _Oldlast >= _Whereptr, + "vector insert iterator outside range"); + } #endif // _ITERATOR_DEBUG_LEVEL == 2 const auto _Whereoff = static_cast(_Whereptr - _Oldfirst); @@ -886,7 +968,7 @@ public: private: template - void _Insert_range(const_iterator _Where, _Iter _First, _Iter _Last, input_iterator_tag) { + _CONSTEXPR20_DYNALLOC void _Insert_range(const_iterator _Where, _Iter _First, _Iter _Last, input_iterator_tag) { // insert input range [_First, _Last) at _Where if (_First == _Last) { return; // nothing to do, avoid invalidating iterators @@ -912,7 +994,7 @@ private: } template - void _Insert_range(const_iterator _Where, _Iter _First, _Iter _Last, forward_iterator_tag) { + _CONSTEXPR20_DYNALLOC void _Insert_range(const_iterator _Where, _Iter _First, _Iter _Last, forward_iterator_tag) { // insert forward range [_First, _Last) at _Where const pointer _Whereptr = _Where._Ptr; const auto _Count = _Convert_size(static_cast(_STD distance(_First, _Last))); @@ -1021,14 +1103,19 @@ private: public: template , int> = 0> - iterator insert(const_iterator _Where, _Iter _First, _Iter _Last) { + _CONSTEXPR20_DYNALLOC iterator insert(const_iterator _Where, _Iter _First, _Iter _Last) { const pointer _Whereptr = _Where._Ptr; auto& _My_data = _Mypair._Myval2; const pointer _Oldfirst = _My_data._Myfirst; #if _ITERATOR_DEBUG_LEVEL == 2 - _STL_VERIFY( - _Where._Getcont() == _STD addressof(_My_data) && _Whereptr >= _Oldfirst && _My_data._Mylast >= _Whereptr, - "vector insert iterator outside range"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_Where._Getcont() == _STD addressof(_My_data) && _Whereptr >= _Oldfirst + && _My_data._Mylast >= _Whereptr, + "vector insert iterator outside range"); + } #endif // _ITERATOR_DEBUG_LEVEL == 2 _Adl_verify_range(_First, _Last); @@ -1037,11 +1124,12 @@ public: return _Make_iterator_offset(_Whereoff); } - iterator insert(const_iterator _Where, initializer_list<_Ty> _Ilist) { + _CONSTEXPR20_DYNALLOC iterator insert(const_iterator _Where, initializer_list<_Ty> _Ilist) { return insert(_Where, _Ilist.begin(), _Ilist.end()); } - void assign(_CRT_GUARDOVERFLOW const size_type _Newsize, const _Ty& _Val) { // assign _Newsize * _Val + _CONSTEXPR20_DYNALLOC void assign(_CRT_GUARDOVERFLOW const size_type _Newsize, const _Ty& _Val) { + // assign _Newsize * _Val auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; pointer& _Mylast = _My_data._Mylast; @@ -1069,7 +1157,8 @@ public: private: template - void _Assign_range(_Iter _First, _Iter _Last, input_iterator_tag) { // assign input range [_First, _Last) + _CONSTEXPR20_DYNALLOC void _Assign_range(_Iter _First, _Iter _Last, input_iterator_tag) { + // assign input range [_First, _Last) auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; pointer& _Mylast = _My_data._Mylast; @@ -1098,7 +1187,8 @@ private: } template - void _Assign_range(_Iter _First, _Iter _Last, forward_iterator_tag) { // assign forward range [_First, _Last) + _CONSTEXPR20_DYNALLOC void _Assign_range(_Iter _First, _Iter _Last, forward_iterator_tag) { + // assign forward range [_First, _Last) const auto _Newsize = _Convert_size(static_cast(_STD distance(_First, _Last))); auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; @@ -1111,13 +1201,19 @@ private: if constexpr (conjunction_v::_Trivially_copyable>, _Uses_default_construct<_Alty, _Ty*, decltype(*_First)>, _Uses_default_destroy<_Alty, _Ty*>>) { - const auto _Oldcapacity = static_cast(_Myend - _Myfirst); - if (_Newsize > _Oldcapacity) { - _Clear_and_reserve_geometric(_Newsize); - } +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Oldcapacity = static_cast(_Myend - _Myfirst); + if (_Newsize > _Oldcapacity) { + _Clear_and_reserve_geometric(_Newsize); + } - _Mylast = _Refancy(_Copy_memmove(_First, _Last, _Unfancy(_Myfirst))); - } else + _Mylast = _Refancy(_Copy_memmove(_First, _Last, _Unfancy(_Myfirst))); + return; + } + } #endif // _HAS_IF_CONSTEXPR { auto _Oldsize = static_cast(_Mylast - _Myfirst); @@ -1144,23 +1240,23 @@ private: public: template , int> = 0> - void assign(_Iter _First, _Iter _Last) { + _CONSTEXPR20_DYNALLOC void assign(_Iter _First, _Iter _Last) { _Adl_verify_range(_First, _Last); _Assign_range(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Iter_cat_t<_Iter>{}); } - void assign(initializer_list<_Ty> _Ilist) { + _CONSTEXPR20_DYNALLOC void assign(initializer_list<_Ty> _Ilist) { _Assign_range(_Ilist.begin(), _Ilist.end(), random_access_iterator_tag{}); } private: - void _Copy_assign(const vector& _Right, false_type) { + _CONSTEXPR20_DYNALLOC void _Copy_assign(const vector& _Right, false_type) { _Pocca(_Getal(), _Right._Getal()); auto& _Right_data = _Right._Mypair._Myval2; assign(_Right_data._Myfirst, _Right_data._Mylast); } - void _Copy_assign(const vector& _Right, true_type) { + _CONSTEXPR20_DYNALLOC void _Copy_assign(const vector& _Right, true_type) { if (_Getal() != _Right._Getal()) { _Tidy(); _Mypair._Myval2._Reload_proxy( @@ -1171,7 +1267,7 @@ private: } public: - vector& operator=(const vector& _Right) { + _CONSTEXPR20_DYNALLOC vector& operator=(const vector& _Right) { if (this != _STD addressof(_Right)) { _Copy_assign(_Right, _Choose_pocca<_Alty>{}); } @@ -1179,14 +1275,14 @@ public: return *this; } - vector& operator=(initializer_list<_Ty> _Ilist) { + _CONSTEXPR20_DYNALLOC vector& operator=(initializer_list<_Ty> _Ilist) { _Assign_range(_Ilist.begin(), _Ilist.end(), random_access_iterator_tag{}); return *this; } private: template - void _Resize_reallocate(const size_type _Newsize, const _Ty2& _Val) { + _CONSTEXPR20_DYNALLOC void _Resize_reallocate(const size_type _Newsize, const _Ty2& _Val) { if (_Newsize > max_size()) { _Xlength(); } @@ -1215,7 +1311,8 @@ private: } template - void _Resize(const size_type _Newsize, const _Ty2& _Val) { // trim or append elements, provide strong guarantee + _CONSTEXPR20_DYNALLOC void _Resize(const size_type _Newsize, const _Ty2& _Val) { + // trim or append elements, provide strong guarantee auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; pointer& _Mylast = _My_data._Mylast; @@ -1244,18 +1341,18 @@ private: } public: - void resize(_CRT_GUARDOVERFLOW const size_type _Newsize) { + _CONSTEXPR20_DYNALLOC void resize(_CRT_GUARDOVERFLOW const size_type _Newsize) { // trim or append value-initialized elements, provide strong guarantee _Resize(_Newsize, _Value_init_tag{}); } - void resize(_CRT_GUARDOVERFLOW const size_type _Newsize, const _Ty& _Val) { + _CONSTEXPR20_DYNALLOC void resize(_CRT_GUARDOVERFLOW const size_type _Newsize, const _Ty& _Val) { // trim or append copies of _Val, provide strong guarantee _Resize(_Newsize, _Val); } private: - void _Reallocate_exactly(const size_type _Newcapacity) { + _CONSTEXPR20_DYNALLOC void _Reallocate_exactly(const size_type _Newcapacity) { // set capacity to _Newcapacity (without geometric growth), provide strong guarantee auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; @@ -1275,7 +1372,24 @@ private: _Change_array(_Newvec, _Size, _Newcapacity); } - void _Clear_and_reserve_geometric(const size_type _Newsize) { +#if _ITERATOR_DEBUG_LEVEL != 0 + void _Check_all_orphaned_locked() const noexcept { + _Lockit _Lock(_LOCK_DEBUG); + auto& _My_data = _Mypair._Myval2; + _STL_INTERNAL_CHECK(!_My_data._Myproxy->_Myfirstiter); + } + + _CONSTEXPR20_DYNALLOC void _Check_all_orphaned() const noexcept { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Check_all_orphaned_locked(); + } + } +#endif // _ITERATOR_DEBUG_LEVEL != 0 + + _CONSTEXPR20_DYNALLOC void _Clear_and_reserve_geometric(const size_type _Newsize) { auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; pointer& _Mylast = _My_data._Mylast; @@ -1283,10 +1397,7 @@ private: #if _ITERATOR_DEBUG_LEVEL != 0 && defined(_ENABLE_STL_INTERNAL_CHECK) _STL_INTERNAL_CHECK(_Newsize != 0); - { - _Lockit _Lock(_LOCK_DEBUG); - _STL_INTERNAL_CHECK(!_My_data._Myproxy->_Myfirstiter); // asserts that all iterators are orphaned - } // unlock + _Check_all_orphaned(); #endif // _ITERATOR_DEBUG_LEVEL != 0 && defined(_ENABLE_STL_INTERNAL_CHECK) if (_Newsize > max_size()) { @@ -1308,7 +1419,7 @@ private: } public: - void reserve(_CRT_GUARDOVERFLOW const size_type _Newcapacity) { + _CONSTEXPR20_DYNALLOC void reserve(_CRT_GUARDOVERFLOW const size_type _Newcapacity) { // increase capacity to _Newcapacity (without geometric growth), provide strong guarantee if (_Newcapacity > capacity()) { // something to do (reserve() never shrinks) if (_Newcapacity > max_size()) { @@ -1319,7 +1430,7 @@ public: } } - void shrink_to_fit() { // reduce capacity to size, provide strong guarantee + _CONSTEXPR20_DYNALLOC void shrink_to_fit() { // reduce capacity to size, provide strong guarantee auto& _My_data = _Mypair._Myval2; const pointer _Oldlast = _My_data._Mylast; if (_Oldlast != _My_data._Myend) { // something to do @@ -1332,29 +1443,40 @@ public: } } - void pop_back() noexcept /* strengthened */ { + _CONSTEXPR20_DYNALLOC void pop_back() noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; pointer& _Mylast = _My_data._Mylast; #if _ITERATOR_DEBUG_LEVEL == 2 - _STL_VERIFY(_My_data._Myfirst != _Mylast, "vector empty before pop"); - _Orphan_range(_Mylast - 1, _Mylast); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_My_data._Myfirst != _Mylast, "vector empty before pop"); + _Orphan_range(_Mylast - 1, _Mylast); + } #endif // _ITERATOR_DEBUG_LEVEL == 2 _Alty_traits::destroy(_Getal(), _Unfancy(_Mylast - 1)); --_Mylast; } - iterator erase(const_iterator _Where) noexcept(is_nothrow_move_assignable_v) /* strengthened */ { + _CONSTEXPR20_DYNALLOC iterator erase(const_iterator _Where) noexcept( + is_nothrow_move_assignable_v) /* strengthened */ { const pointer _Whereptr = _Where._Ptr; auto& _My_data = _Mypair._Myval2; pointer& _Mylast = _My_data._Mylast; #if _ITERATOR_DEBUG_LEVEL == 2 - _STL_VERIFY( - _Where._Getcont() == _STD addressof(_My_data) && _Whereptr >= _My_data._Myfirst && _Mylast > _Whereptr, - "vector erase iterator outside range"); - _Orphan_range(_Whereptr, _Mylast); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY( + _Where._Getcont() == _STD addressof(_My_data) && _Whereptr >= _My_data._Myfirst && _Mylast > _Whereptr, + "vector erase iterator outside range"); + _Orphan_range(_Whereptr, _Mylast); + } #endif // _ITERATOR_DEBUG_LEVEL == 2 _Move_unchecked(_Whereptr + 1, _Mylast, _Whereptr); @@ -1363,7 +1485,7 @@ public: return iterator(_Whereptr, _STD addressof(_My_data)); } - iterator erase(const_iterator _First, const_iterator _Last) noexcept( + _CONSTEXPR20_DYNALLOC iterator erase(const_iterator _First, const_iterator _Last) noexcept( is_nothrow_move_assignable_v) /* strengthened */ { const pointer _Firstptr = _First._Ptr; const pointer _Lastptr = _Last._Ptr; @@ -1371,9 +1493,14 @@ public: pointer& _Mylast = _My_data._Mylast; #if _ITERATOR_DEBUG_LEVEL == 2 - _STL_VERIFY(_First._Getcont() == _STD addressof(_My_data) && _Last._Getcont() == _STD addressof(_My_data) - && _Firstptr >= _My_data._Myfirst && _Lastptr >= _Firstptr && _Mylast >= _Lastptr, - "vector erase iterator outside range"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_First._Getcont() == _STD addressof(_My_data) && _Last._Getcont() == _STD addressof(_My_data) + && _Firstptr >= _My_data._Myfirst && _Lastptr >= _Firstptr && _Mylast >= _Lastptr, + "vector erase iterator outside range"); + } #endif // _ITERATOR_DEBUG_LEVEL == 2 if (_Firstptr != _Lastptr) { // something to do, invalidate iterators @@ -1387,7 +1514,7 @@ public: return iterator(_Firstptr, _STD addressof(_My_data)); } - void clear() noexcept { // erase all + _CONSTEXPR20_DYNALLOC void clear() noexcept { // erase all auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; pointer& _Mylast = _My_data._Mylast; @@ -1398,130 +1525,140 @@ public: } public: - void swap(vector& _Right) noexcept /* strengthened */ { + _CONSTEXPR20_DYNALLOC void swap(vector& _Right) noexcept /* strengthened */ { if (this != _STD addressof(_Right)) { _Pocs(_Getal(), _Right._Getal()); _Mypair._Myval2._Swap_val(_Right._Mypair._Myval2); } } - _NODISCARD _Ty* data() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _Ty* data() noexcept { return _Unfancy_maybe_null(_Mypair._Myval2._Myfirst); } - _NODISCARD const _Ty* data() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const _Ty* data() const noexcept { return _Unfancy_maybe_null(_Mypair._Myval2._Myfirst); } - _NODISCARD iterator begin() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC iterator begin() noexcept { auto& _My_data = _Mypair._Myval2; return iterator(_My_data._Myfirst, _STD addressof(_My_data)); } - _NODISCARD const_iterator begin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator begin() const noexcept { auto& _My_data = _Mypair._Myval2; return const_iterator(_My_data._Myfirst, _STD addressof(_My_data)); } - _NODISCARD iterator end() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC iterator end() noexcept { auto& _My_data = _Mypair._Myval2; return iterator(_My_data._Mylast, _STD addressof(_My_data)); } - _NODISCARD const_iterator end() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator end() const noexcept { auto& _My_data = _Mypair._Myval2; return const_iterator(_My_data._Mylast, _STD addressof(_My_data)); } - _NODISCARD reverse_iterator rbegin() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } - _NODISCARD const_reverse_iterator rbegin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } - _NODISCARD reverse_iterator rend() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reverse_iterator rend() noexcept { return reverse_iterator(begin()); } - _NODISCARD const_reverse_iterator rend() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } - _NODISCARD const_iterator cbegin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator cbegin() const noexcept { return begin(); } - _NODISCARD const_iterator cend() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator cend() const noexcept { return end(); } - _NODISCARD const_reverse_iterator crbegin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reverse_iterator crbegin() const noexcept { return rbegin(); } - _NODISCARD const_reverse_iterator crend() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reverse_iterator crend() const noexcept { return rend(); } - pointer _Unchecked_begin() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC pointer _Unchecked_begin() noexcept { return _Mypair._Myval2._Myfirst; } - const_pointer _Unchecked_begin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_pointer _Unchecked_begin() const noexcept { return _Mypair._Myval2._Myfirst; } - pointer _Unchecked_end() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC pointer _Unchecked_end() noexcept { return _Mypair._Myval2._Mylast; } - const_pointer _Unchecked_end() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_pointer _Unchecked_end() const noexcept { return _Mypair._Myval2._Mylast; } - _NODISCARD bool empty() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool empty() const noexcept { auto& _My_data = _Mypair._Myval2; return _My_data._Myfirst == _My_data._Mylast; } - _NODISCARD size_type size() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC size_type size() const noexcept { auto& _My_data = _Mypair._Myval2; return static_cast(_My_data._Mylast - _My_data._Myfirst); } - _NODISCARD size_type max_size() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC size_type max_size() const noexcept { return (_STD min)( static_cast((numeric_limits::max)()), _Alty_traits::max_size(_Getal())); } - _NODISCARD size_type capacity() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC size_type capacity() const noexcept { auto& _My_data = _Mypair._Myval2; return static_cast(_My_data._Myend - _My_data._Myfirst); } - _NODISCARD _Ty& operator[](const size_type _Pos) noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC _Ty& operator[](const size_type _Pos) noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY( - _Pos < static_cast(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY( + _Pos < static_cast(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range"); + } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _My_data._Myfirst[_Pos]; } - _NODISCARD const _Ty& operator[](const size_type _Pos) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC const _Ty& operator[](const size_type _Pos) const noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY( - _Pos < static_cast(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY( + _Pos < static_cast(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range"); + } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _My_data._Myfirst[_Pos]; } - _NODISCARD _Ty& at(const size_type _Pos) { + _NODISCARD _CONSTEXPR20_DYNALLOC _Ty& at(const size_type _Pos) { auto& _My_data = _Mypair._Myval2; if (static_cast(_My_data._Mylast - _My_data._Myfirst) <= _Pos) { _Xrange(); @@ -1530,7 +1667,7 @@ public: return _My_data._Myfirst[_Pos]; } - _NODISCARD const _Ty& at(const size_type _Pos) const { + _NODISCARD _CONSTEXPR20_DYNALLOC const _Ty& at(const size_type _Pos) const { auto& _My_data = _Mypair._Myval2; if (static_cast(_My_data._Mylast - _My_data._Myfirst) <= _Pos) { _Xrange(); @@ -1539,87 +1676,109 @@ public: return _My_data._Myfirst[_Pos]; } - _NODISCARD _Ty& front() noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC _Ty& front() noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "front() called on empty vector"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "front() called on empty vector"); + } #endif // _CONTAINER_DEBUG_LEVEL > 0 return *_My_data._Myfirst; } - _NODISCARD const _Ty& front() const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC const _Ty& front() const noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "front() called on empty vector"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "front() called on empty vector"); + } #endif // _CONTAINER_DEBUG_LEVEL > 0 return *_My_data._Myfirst; } - _NODISCARD _Ty& back() noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC _Ty& back() noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "back() called on empty vector"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "back() called on empty vector"); + } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _My_data._Mylast[-1]; } - _NODISCARD const _Ty& back() const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC const _Ty& back() const noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "back() called on empty vector"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "back() called on empty vector"); + } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _My_data._Mylast[-1]; } - _NODISCARD allocator_type get_allocator() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC allocator_type get_allocator() const noexcept { return static_cast(_Getal()); } private: - pointer _Ufill(pointer _Dest, const size_type _Count, const _Ty& _Val) { + _CONSTEXPR20_DYNALLOC pointer _Ufill(pointer _Dest, const size_type _Count, const _Ty& _Val) { // fill raw _Dest with _Count copies of _Val, using allocator return _Uninitialized_fill_n(_Dest, _Count, _Val, _Getal()); } - pointer _Ufill(pointer _Dest, const size_type _Count, _Value_init_tag) { + _CONSTEXPR20_DYNALLOC pointer _Ufill(pointer _Dest, const size_type _Count, _Value_init_tag) { // fill raw _Dest with _Count value-initialized objects, using allocator return _Uninitialized_value_construct_n(_Dest, _Count, _Getal()); } template - pointer _Ucopy(_Iter _First, _Iter _Last, pointer _Dest) { // copy [_First, _Last) to raw _Dest, using allocator + _CONSTEXPR20_DYNALLOC pointer _Ucopy(_Iter _First, _Iter _Last, pointer _Dest) { + // copy [_First, _Last) to raw _Dest, using allocator return _Uninitialized_copy(_First, _Last, _Dest, _Getal()); } - pointer _Umove(pointer _First, pointer _Last, pointer _Dest) { // move [_First, _Last) to raw _Dest, using allocator + _CONSTEXPR20_DYNALLOC pointer _Umove(pointer _First, pointer _Last, pointer _Dest) { + // move [_First, _Last) to raw _Dest, using allocator return _Uninitialized_move(_First, _Last, _Dest, _Getal()); } - void _Umove_if_noexcept1(pointer _First, pointer _Last, pointer _Dest, true_type) { + _CONSTEXPR20_DYNALLOC void _Umove_if_noexcept1(pointer _First, pointer _Last, pointer _Dest, true_type) { // move [_First, _Last) to raw _Dest, using allocator _Uninitialized_move(_First, _Last, _Dest, _Getal()); } - void _Umove_if_noexcept1(pointer _First, pointer _Last, pointer _Dest, false_type) { + _CONSTEXPR20_DYNALLOC void _Umove_if_noexcept1(pointer _First, pointer _Last, pointer _Dest, false_type) { // copy [_First, _Last) to raw _Dest, using allocator _Uninitialized_copy(_First, _Last, _Dest, _Getal()); } - void _Umove_if_noexcept(pointer _First, pointer _Last, pointer _Dest) { + _CONSTEXPR20_DYNALLOC void _Umove_if_noexcept(pointer _First, pointer _Last, pointer _Dest) { // move_if_noexcept [_First, _Last) to raw _Dest, using allocator _Umove_if_noexcept1(_First, _Last, _Dest, bool_constant, negation>>>{}); } - void _Destroy(pointer _First, pointer _Last) { // destroy [_First, _Last) using allocator + _CONSTEXPR20_DYNALLOC void _Destroy(pointer _First, pointer _Last) { // destroy [_First, _Last) using allocator _Destroy_range(_First, _Last, _Getal()); } - size_type _Calculate_growth(const size_type _Newsize) const { + _CONSTEXPR20_DYNALLOC size_type _Calculate_growth(const size_type _Newsize) const { // given _Oldcapacity and _Newsize, calculate geometric growth const size_type _Oldcapacity = capacity(); const auto _Max = max_size(); @@ -1637,7 +1796,7 @@ private: return _Geometric; // geometric growth is sufficient } - void _Buy_raw(const size_type _Newcapacity) { + _CONSTEXPR20_DYNALLOC void _Buy_raw(const size_type _Newcapacity) { // allocate array with _Newcapacity elements auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; @@ -1653,7 +1812,7 @@ private: _Myend = _Newvec + _Newcapacity; } - void _Buy_nonzero(const size_type _Newcapacity) { + _CONSTEXPR20_DYNALLOC void _Buy_nonzero(const size_type _Newcapacity) { // allocate array with _Newcapacity elements #ifdef _ENABLE_STL_INTERNAL_CHECK auto& _My_data = _Mypair._Myval2; @@ -1671,7 +1830,8 @@ private: _Buy_raw(_Newcapacity); } - void _Change_array(const pointer _Newvec, const size_type _Newsize, const size_type _Newcapacity) { + _CONSTEXPR20_DYNALLOC void _Change_array( + const pointer _Newvec, const size_type _Newsize, const size_type _Newcapacity) { // orphan all iterators, discard old array, acquire new array auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; @@ -1690,7 +1850,7 @@ private: _Myend = _Newvec + _Newcapacity; } - void _Tidy() noexcept { // free all storage + _CONSTEXPR20_DYNALLOC void _Tidy() noexcept { // free all storage auto& _My_data = _Mypair._Myval2; pointer& _Myfirst = _My_data._Myfirst; pointer& _Mylast = _My_data._Mylast; @@ -1716,10 +1876,9 @@ private: _Xout_of_range("invalid vector subscript"); } - void _Orphan_range(pointer _First, pointer _Last) const { // orphan iterators within specified (inclusive) range #if _ITERATOR_DEBUG_LEVEL == 2 + void _Orphan_range_locked(pointer _First, pointer _Last) const { _Lockit _Lock(_LOCK_DEBUG); - _Iterator_base12** _Pnext = &_Mypair._Myval2._Myproxy->_Myfirstiter; while (*_Pnext) { const auto _Pnextptr = static_cast(**_Pnext)._Ptr; @@ -1730,25 +1889,33 @@ private: *_Pnext = (*_Pnext)->_Mynextiter; } } -#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ // vvv _ITERATOR_DEBUG_LEVEL != 2 vvv - (void) _First; - (void) _Last; -#endif // _ITERATOR_DEBUG_LEVEL == 2 } - _Alty& _Getal() noexcept { + _CONSTEXPR20_DYNALLOC void _Orphan_range(pointer _First, pointer _Last) const { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Orphan_range_locked(_First, _Last); + } + } +#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ // vvv _ITERATOR_DEBUG_LEVEL != 2 vvv + _CONSTEXPR20_DYNALLOC void _Orphan_range(pointer, pointer) const {} +#endif // _ITERATOR_DEBUG_LEVEL != 2 + + _NODISCARD _CONSTEXPR20_DYNALLOC _Alty& _Getal() noexcept { return _Mypair._Get_first(); } - const _Alty& _Getal() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const _Alty& _Getal() const noexcept { return _Mypair._Get_first(); } - iterator _Make_iterator(const pointer _Ptr) noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC iterator _Make_iterator(const pointer _Ptr) noexcept { return iterator(_Ptr, _STD addressof(_Mypair._Myval2)); } - iterator _Make_iterator_offset(const size_type _Offset) noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC iterator _Make_iterator_offset(const size_type _Offset) noexcept { // return the iterator begin() + _Offset without a debugging check auto& _My_data = _Mypair._Myval2; return iterator(_My_data._Myfirst + _Offset, _STD addressof(_My_data)); @@ -1764,39 +1931,39 @@ vector(_Iter, _Iter, _Alloc = _Alloc()) -> vector<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 template -void swap(vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right) noexcept /* strengthened */ { +_CONSTEXPR20_DYNALLOC void swap(vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right) noexcept /* strengthened */ { _Left.swap(_Right); } template -_NODISCARD bool operator==(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator==(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { return _Left.size() == _Right.size() && _STD equal(_Left._Unchecked_begin(), _Left._Unchecked_end(), _Right._Unchecked_begin()); } template -_NODISCARD bool operator!=(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator!=(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { return !(_Left == _Right); } template -_NODISCARD bool operator<(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator<(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { return _STD lexicographical_compare( _Left._Unchecked_begin(), _Left._Unchecked_end(), _Right._Unchecked_begin(), _Right._Unchecked_end()); } template -_NODISCARD bool operator>(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator>(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { return _Right < _Left; } template -_NODISCARD bool operator<=(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator<=(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { return !(_Right < _Left); } template -_NODISCARD bool operator>=(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator>=(const vector<_Ty, _Alloc>& _Left, const vector<_Ty, _Alloc>& _Right) { return !(_Left < _Right); } @@ -1819,21 +1986,21 @@ public: using _Difference_type = typename allocator_traits<_Alvbase>::difference_type; using _Mycont = vector>; - _Vb_iter_base() = default; + _CONSTEXPR20_DYNALLOC _Vb_iter_base() = default; - _Vb_iter_base(const _Vbase* _Ptr, _Size_type _Off, const _Container_base* _Mypvbool) noexcept + _CONSTEXPR20_DYNALLOC _Vb_iter_base(const _Vbase* _Ptr, _Size_type _Off, const _Container_base* _Mypvbool) noexcept : _Myptr(_Ptr), _Myoff(_Off) { this->_Adopt(_Mypvbool); } - void _Advance(_Size_type _Off) noexcept { + _CONSTEXPR20_DYNALLOC void _Advance(_Size_type _Off) noexcept { _Myoff += _Off; _Myptr += _Myoff / _VBITS; _Myoff %= _VBITS; } #if _ITERATOR_DEBUG_LEVEL != 0 - _Difference_type _Total_off(const _Mycont* _Cont) const noexcept { + _CONSTEXPR20_DYNALLOC _Difference_type _Total_off(const _Mycont* _Cont) const noexcept { return static_cast<_Difference_type>(_VBITS * (_Myptr - _Cont->_Myvec.data()) + _Myoff); } #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -1851,18 +2018,19 @@ class _Vb_reference : public _Vb_iter_base<_Alvbase_wrapped> { using _Difference_type = typename _Mybase::_Difference_type; // TRANSITION, ABI: non-trivial constructor - _Vb_reference() = default; + _CONSTEXPR20_DYNALLOC _Vb_reference() = default; public: - _Vb_reference(const _Vb_reference&) = default; + _CONSTEXPR20_DYNALLOC _Vb_reference(const _Vb_reference&) = default; - _Vb_reference(const _Mybase& _Right) noexcept : _Mybase(_Right._Myptr, _Right._Myoff, _Right._Getcont()) {} + _CONSTEXPR20_DYNALLOC _Vb_reference(const _Mybase& _Right) noexcept + : _Mybase(_Right._Myptr, _Right._Myoff, _Right._Getcont()) {} - _Vb_reference& operator=(const _Vb_reference& _Right) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_reference& operator=(const _Vb_reference& _Right) noexcept { return *this = static_cast(_Right); } - _Vb_reference& operator=(bool _Val) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_reference& operator=(bool _Val) noexcept { if (_Val) { *const_cast<_Vbase*>(_Getptr()) |= _Mask(); } else { @@ -1872,33 +2040,38 @@ public: return *this; } - void flip() noexcept { + _CONSTEXPR20_DYNALLOC void flip() noexcept { *const_cast<_Vbase*>(_Getptr()) ^= _Mask(); } - operator bool() const noexcept { + _CONSTEXPR20_DYNALLOC operator bool() const noexcept { return (*_Getptr() & _Mask()) != 0; } - const _Vbase* _Getptr() const noexcept { + _CONSTEXPR20_DYNALLOC const _Vbase* _Getptr() const noexcept { #if _ITERATOR_DEBUG_LEVEL != 0 - const auto _Cont = static_cast(this->_Getcont()); - _STL_VERIFY(_Cont, "cannot dereference value-initialized vector iterator"); - _STL_VERIFY(this->_Total_off(_Cont) <= static_cast<_Difference_type>(_Cont->_Mysize), - "vector iterator not dereferenceable"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Cont = static_cast(this->_Getcont()); + _STL_VERIFY(_Cont, "cannot dereference value-initialized vector iterator"); + _STL_VERIFY(this->_Total_off(_Cont) <= static_cast<_Difference_type>(_Cont->_Mysize), + "vector iterator not dereferenceable"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return this->_Myptr; } - friend void swap(_Vb_reference _Left, _Vb_reference _Right) noexcept { + friend _CONSTEXPR20_DYNALLOC void swap(_Vb_reference _Left, _Vb_reference _Right) noexcept { bool _Val = _Left; // NOT _STD swap _Left = _Right; _Right = _Val; } protected: - _Vbase _Mask() const noexcept { + _CONSTEXPR20_DYNALLOC _Vbase _Mask() const noexcept { return static_cast<_Vbase>(1) << this->_Myoff; } }; @@ -1922,142 +2095,165 @@ public: using pointer = const_reference*; using reference = const_reference; - _Vb_const_iterator() = default; + _CONSTEXPR20_DYNALLOC _Vb_const_iterator() = default; - _Vb_const_iterator(const _Vbase* _Ptr, const _Container_base* _Mypvbool) noexcept : _Mybase(_Ptr, 0, _Mypvbool) {} + _CONSTEXPR20_DYNALLOC _Vb_const_iterator(const _Vbase* _Ptr, const _Container_base* _Mypvbool) noexcept + : _Mybase(_Ptr, 0, _Mypvbool) {} - _NODISCARD const_reference operator*() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reference operator*() const noexcept { #if _ITERATOR_DEBUG_LEVEL != 0 - const auto _Cont = static_cast(this->_Getcont()); - _STL_VERIFY(_Cont, "cannot dereference value-initialized vector iterator"); - _STL_VERIFY(this->_Total_off(_Cont) < static_cast<_Difference_type>(_Cont->_Mysize), - "vector iterator not dereferenceable"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Cont = static_cast(this->_Getcont()); + _STL_VERIFY(_Cont, "cannot dereference value-initialized vector iterator"); + _STL_VERIFY(this->_Total_off(_Cont) < static_cast<_Difference_type>(_Cont->_Mysize), + "vector iterator not dereferenceable"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return _Reft(*this); } - _Vb_const_iterator& operator++() noexcept { + _CONSTEXPR20_DYNALLOC _Vb_const_iterator& operator++() noexcept { _Inc(); return *this; } - _Vb_const_iterator operator++(int) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_const_iterator operator++(int) noexcept { _Vb_const_iterator _Tmp = *this; _Inc(); return _Tmp; } - _Vb_const_iterator& operator--() noexcept { + _CONSTEXPR20_DYNALLOC _Vb_const_iterator& operator--() noexcept { _Dec(); return *this; } - _Vb_const_iterator operator--(int) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_const_iterator operator--(int) noexcept { _Vb_const_iterator _Tmp = *this; _Dec(); return _Tmp; } - _Vb_const_iterator& operator+=(const difference_type _Off) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_const_iterator& operator+=(const difference_type _Off) noexcept { #if _ITERATOR_DEBUG_LEVEL != 0 - if (_Off != 0) { - const auto _Cont = static_cast(this->_Getcont()); - _STL_VERIFY(_Cont, "cannot seek value-initialized vector iterator"); - const auto _Start_offset = this->_Total_off(_Cont); - if (_Off < 0) { - _STL_VERIFY(-_Start_offset <= _Off, "cannot seek vector iterator before begin"); - } else if (0 < _Off) { - _STL_VERIFY(_Off <= static_cast<_Difference_type>(_Cont->_Mysize - _Start_offset), - "cannot seek vector iterator after end"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + if (_Off != 0) { + const auto _Cont = static_cast(this->_Getcont()); + _STL_VERIFY(_Cont, "cannot seek value-initialized vector iterator"); + const auto _Start_offset = this->_Total_off(_Cont); + if (_Off < 0) { + _STL_VERIFY(-_Start_offset <= _Off, "cannot seek vector iterator before begin"); + } else if (0 < _Off) { + _STL_VERIFY(_Off <= static_cast<_Difference_type>(_Cont->_Mysize - _Start_offset), + "cannot seek vector iterator after end"); + } } } #endif // _ITERATOR_DEBUG_LEVEL != 0 if (_Off < 0 && this->_Myoff < 0 - static_cast<_Size_type>(_Off)) { // add negative increment - this->_Myoff += _Off; + this->_Myoff += static_cast<_Size_type>(_Off); this->_Myptr -= 1 + (static_cast<_Size_type>(-1) - this->_Myoff) / _VBITS; this->_Myoff %= _VBITS; } else { // add non-negative increment - this->_Myoff += _Off; + this->_Myoff += static_cast<_Size_type>(_Off); this->_Myptr += this->_Myoff / _VBITS; this->_Myoff %= _VBITS; } return *this; } - _NODISCARD _Vb_const_iterator operator+(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _Vb_const_iterator operator+(const difference_type _Off) const noexcept { _Vb_const_iterator _Tmp = *this; return _Tmp += _Off; } - _Vb_const_iterator& operator-=(const difference_type _Off) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_const_iterator& operator-=(const difference_type _Off) noexcept { return *this += -_Off; } - _NODISCARD _Vb_const_iterator operator-(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _Vb_const_iterator operator-(const difference_type _Off) const noexcept { _Vb_const_iterator _Tmp = *this; return _Tmp -= _Off; } - _NODISCARD difference_type operator-(const _Vb_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC difference_type operator-(const _Vb_const_iterator& _Right) const noexcept { _Compat(_Right); return static_cast(_VBITS * (this->_Myptr - _Right._Myptr)) + static_cast(this->_Myoff) - static_cast(_Right._Myoff); } - _NODISCARD const_reference operator[](const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reference operator[](const difference_type _Off) const noexcept { return *(*this + _Off); } - _NODISCARD bool operator==(const _Vb_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator==(const _Vb_const_iterator& _Right) const noexcept { _Compat(_Right); return this->_Myptr == _Right._Myptr && this->_Myoff == _Right._Myoff; } - _NODISCARD bool operator!=(const _Vb_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator!=(const _Vb_const_iterator& _Right) const noexcept { return !(*this == _Right); } - _NODISCARD bool operator<(const _Vb_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator<(const _Vb_const_iterator& _Right) const noexcept { _Compat(_Right); return this->_Myptr < _Right._Myptr || (this->_Myptr == _Right._Myptr && this->_Myoff < _Right._Myoff); } - _NODISCARD bool operator>(const _Vb_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator>(const _Vb_const_iterator& _Right) const noexcept { return _Right < *this; } - _NODISCARD bool operator<=(const _Vb_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator<=(const _Vb_const_iterator& _Right) const noexcept { return !(_Right < *this); } - _NODISCARD bool operator>=(const _Vb_const_iterator& _Right) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool operator>=(const _Vb_const_iterator& _Right) const noexcept { return !(*this < _Right); } - void _Compat(const _Vb_const_iterator& _Right) const noexcept { // test for compatible iterator pair + _CONSTEXPR20_DYNALLOC void _Compat( + const _Vb_const_iterator& _Right) const noexcept { // test for compatible iterator pair #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Right; #else // _ITERATOR_DEBUG_LEVEL == 0 - _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "vector iterators incompatible"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "vector iterators incompatible"); + } #endif // _ITERATOR_DEBUG_LEVEL } #if _ITERATOR_DEBUG_LEVEL != 0 using _Prevent_inheriting_unwrap = _Vb_const_iterator; - friend void _Verify_range(const _Vb_const_iterator& _First, const _Vb_const_iterator& _Last) noexcept { + friend _CONSTEXPR20_DYNALLOC void _Verify_range( + const _Vb_const_iterator& _First, const _Vb_const_iterator& _Last) noexcept { // note _Compat check inside <= _STL_VERIFY(_First <= _Last, "vector iterator range transposed"); } #endif // _ITERATOR_DEBUG_LEVEL != 0 - void _Dec() noexcept { // decrement bit position + _CONSTEXPR20_DYNALLOC void _Dec() noexcept { // decrement bit position #if _ITERATOR_DEBUG_LEVEL != 0 - const auto _Cont = static_cast(this->_Getcont()); - _STL_VERIFY(_Cont, "cannot decrement value-initialized vector iterator"); - _STL_VERIFY(this->_Total_off(_Cont) > 0, "cannot decrement vector begin iterator"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Cont = static_cast(this->_Getcont()); + _STL_VERIFY(_Cont, "cannot decrement value-initialized vector iterator"); + _STL_VERIFY(this->_Total_off(_Cont) > 0, "cannot decrement vector begin iterator"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 if (this->_Myoff != 0) { @@ -2068,12 +2264,17 @@ public: } } - void _Inc() noexcept { // increment bit position + _CONSTEXPR20_DYNALLOC void _Inc() noexcept { // increment bit position #if _ITERATOR_DEBUG_LEVEL != 0 - const auto _Cont = static_cast(this->_Getcont()); - _STL_VERIFY(_Cont, "cannot increment value-initialized vector iterator"); - _STL_VERIFY(this->_Total_off(_Cont) < static_cast<_Difference_type>(_Cont->_Mysize), - "cannot increment vector end iterator"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Cont = static_cast(this->_Getcont()); + _STL_VERIFY(_Cont, "cannot increment value-initialized vector iterator"); + _STL_VERIFY(this->_Total_off(_Cont) < static_cast<_Difference_type>(_Cont->_Mysize), + "cannot increment vector end iterator"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 if (this->_Myoff < _VBITS - 1) { @@ -2086,7 +2287,7 @@ public: }; template -_NODISCARD _Vb_const_iterator<_Alvbase_wrapped> operator+( +_NODISCARD _CONSTEXPR20_DYNALLOC _Vb_const_iterator<_Alvbase_wrapped> operator+( typename _Vb_const_iterator<_Alvbase_wrapped>::difference_type _Off, _Vb_const_iterator<_Alvbase_wrapped> _Right) noexcept { return _Right += _Off; @@ -2111,62 +2312,67 @@ public: using _Mybase::_Mybase; - _NODISCARD reference operator*() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reference operator*() const noexcept { #if _ITERATOR_DEBUG_LEVEL != 0 - const auto _Cont = static_cast(this->_Getcont()); - _STL_VERIFY(_Cont, "cannot dereference value-initialized vector iterator"); - _STL_VERIFY(this->_Total_off(_Cont) < static_cast<_Difference_type>(_Cont->_Mysize), - "vector iterator not dereferenceable"); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Cont = static_cast(this->_Getcont()); + _STL_VERIFY(_Cont, "cannot dereference value-initialized vector iterator"); + _STL_VERIFY(this->_Total_off(_Cont) < static_cast<_Difference_type>(_Cont->_Mysize), + "vector iterator not dereferenceable"); + } #endif // _ITERATOR_DEBUG_LEVEL != 0 return _Reft(*this); } - _Vb_iterator& operator++() noexcept { + _CONSTEXPR20_DYNALLOC _Vb_iterator& operator++() noexcept { _Mybase::operator++(); return *this; } - _Vb_iterator operator++(int) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_iterator operator++(int) noexcept { _Vb_iterator _Tmp = *this; _Mybase::operator++(); return _Tmp; } - _Vb_iterator& operator--() noexcept { + _CONSTEXPR20_DYNALLOC _Vb_iterator& operator--() noexcept { _Mybase::operator--(); return *this; } - _Vb_iterator operator--(int) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_iterator operator--(int) noexcept { _Vb_iterator _Tmp = *this; _Mybase::operator--(); return _Tmp; } - _Vb_iterator& operator+=(const difference_type _Off) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_iterator& operator+=(const difference_type _Off) noexcept { _Mybase::operator+=(_Off); return *this; } - _NODISCARD _Vb_iterator operator+(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _Vb_iterator operator+(const difference_type _Off) const noexcept { _Vb_iterator _Tmp = *this; return _Tmp += _Off; } - _Vb_iterator& operator-=(const difference_type _Off) noexcept { + _CONSTEXPR20_DYNALLOC _Vb_iterator& operator-=(const difference_type _Off) noexcept { _Mybase::operator-=(_Off); return *this; } using _Mybase::operator-; - _NODISCARD _Vb_iterator operator-(const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC _Vb_iterator operator-(const difference_type _Off) const noexcept { _Vb_iterator _Tmp = *this; return _Tmp -= _Off; } - _NODISCARD reference operator[](const difference_type _Off) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reference operator[](const difference_type _Off) const noexcept { return *(*this + _Off); } @@ -2174,7 +2380,7 @@ public: }; template -_NODISCARD _Vb_iterator<_Alvbase_wrapped> operator+( +_NODISCARD _CONSTEXPR20_DYNALLOC _Vb_iterator<_Alvbase_wrapped> operator+( typename _Vb_iterator<_Alvbase_wrapped>::difference_type _Off, _Vb_iterator<_Alvbase_wrapped> _Right) noexcept { return _Right += _Off; } @@ -2189,39 +2395,41 @@ public: using _Alvbase_wrapped = _Wrap_alloc<_Alvbase>; using size_type = typename _Alvbase_traits::size_type; - _Vb_val() noexcept(is_nothrow_default_constructible_v<_Vectype>) : _Myvec(), _Mysize(0) { + _CONSTEXPR20_DYNALLOC _Vb_val() noexcept(is_nothrow_default_constructible_v<_Vectype>) : _Myvec(), _Mysize(0) { this->_Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alvbase, _Getal())); } - _Vb_val(const _Alloc& _Al) noexcept(is_nothrow_constructible_v<_Vectype, _Alvbase>) + _CONSTEXPR20_DYNALLOC _Vb_val(const _Alloc& _Al) noexcept(is_nothrow_constructible_v<_Vectype, _Alvbase>) : _Myvec(static_cast<_Alvbase>(_Al)), _Mysize(0) { this->_Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alvbase, _Getal())); } - _Vb_val(size_type _Count, const bool& _Val) : _Myvec(_Nw(_Count), static_cast<_Vbase>(_Val ? -1 : 0)), _Mysize(0) { + _CONSTEXPR20_DYNALLOC _Vb_val(size_type _Count, const bool& _Val) + : _Myvec(_Nw(_Count), static_cast<_Vbase>(_Val ? -1 : 0)), _Mysize(0) { this->_Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alvbase, _Getal())); } - _Vb_val(size_type _Count, const bool& _Val, const _Alloc& _Al) + _CONSTEXPR20_DYNALLOC _Vb_val(size_type _Count, const bool& _Val, const _Alloc& _Al) : _Myvec(_Nw(_Count), static_cast<_Vbase>(_Val ? -1 : 0), static_cast<_Alvbase>(_Al)), _Mysize(0) { this->_Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alvbase, _Getal())); } - _Vb_val(const _Vb_val& _Right) : _Myvec(_Right._Myvec), _Mysize(_Right._Mysize) { + _CONSTEXPR20_DYNALLOC _Vb_val(const _Vb_val& _Right) : _Myvec(_Right._Myvec), _Mysize(_Right._Mysize) { this->_Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alvbase, _Getal())); } - _Vb_val(const _Vb_val& _Right, const _Alloc& _Al) + _CONSTEXPR20_DYNALLOC _Vb_val(const _Vb_val& _Right, const _Alloc& _Al) : _Myvec(_Right._Myvec, static_cast<_Alvbase>(_Al)), _Mysize(_Right._Mysize) { this->_Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alvbase, _Getal())); } - _Vb_val(_Vb_val&& _Right) noexcept(is_nothrow_move_constructible_v<_Vectype>) + _CONSTEXPR20_DYNALLOC _Vb_val(_Vb_val&& _Right) noexcept(is_nothrow_move_constructible_v<_Vectype>) : _Myvec(_STD move(_Right._Myvec)), _Mysize(_STD exchange(_Right._Mysize, size_type{0})) { this->_Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alvbase, _Getal())); } - _Vb_val(_Vb_val&& _Right, const _Alloc& _Al) noexcept(is_nothrow_constructible_v<_Vectype, _Vectype, _Alvbase>) + _CONSTEXPR20_DYNALLOC _Vb_val(_Vb_val&& _Right, const _Alloc& _Al) noexcept( + is_nothrow_constructible_v<_Vectype, _Vectype, _Alvbase>) : _Myvec(_STD move(_Right._Myvec), static_cast<_Alvbase>(_Al)), _Mysize(_Right._Mysize) { if (_Right._Myvec.empty()) { // we took _Right's buffer, so zero out size @@ -2231,7 +2439,7 @@ public: this->_Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alvbase, _Getal())); } - ~_Vb_val() noexcept { + _CONSTEXPR20_DYNALLOC ~_Vb_val() noexcept { #if _ITERATOR_DEBUG_LEVEL != 0 this->_Orphan_all(); auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alvbase, this->_Getal()); @@ -2239,15 +2447,15 @@ public: #endif // _ITERATOR_DEBUG_LEVEL != 0 } - _Alvbase& _Getal() noexcept { + _CONSTEXPR20_DYNALLOC _Alvbase& _Getal() noexcept { return _Myvec._Getal(); } - const _Alvbase& _Getal() const noexcept { + _CONSTEXPR20_DYNALLOC const _Alvbase& _Getal() const noexcept { return _Myvec._Getal(); } - static size_type _Nw(size_type _Count) noexcept { + static _CONSTEXPR20_DYNALLOC size_type _Nw(size_type _Count) noexcept { return (_Count + _VBITS - 1) / _VBITS; } @@ -2287,41 +2495,44 @@ public: static const int _VBITS = _STD _VBITS; enum { _EEN_VBITS = _VBITS }; // helper for expression evaluator - vector() noexcept(is_nothrow_default_constructible_v<_Mybase>) // strengthened + _CONSTEXPR20_DYNALLOC vector() noexcept(is_nothrow_default_constructible_v<_Mybase>) // strengthened : _Mybase() {} - explicit vector(const _Alloc& _Al) noexcept(is_nothrow_constructible_v<_Mybase, const _Alloc&>) // strengthened + _CONSTEXPR20_DYNALLOC explicit vector(const _Alloc& _Al) noexcept( + is_nothrow_constructible_v<_Mybase, const _Alloc&>) // strengthened : _Mybase(_Al) {} - explicit vector(_CRT_GUARDOVERFLOW size_type _Count, const _Alloc& _Al = _Alloc()) : _Mybase(_Count, false, _Al) { + _CONSTEXPR20_DYNALLOC explicit vector(_CRT_GUARDOVERFLOW size_type _Count, const _Alloc& _Al = _Alloc()) + : _Mybase(_Count, false, _Al) { _Trim(_Count); } - vector(_CRT_GUARDOVERFLOW size_type _Count, const bool& _Val, const _Alloc& _Al = _Alloc()) + _CONSTEXPR20_DYNALLOC vector(_CRT_GUARDOVERFLOW size_type _Count, const bool& _Val, const _Alloc& _Al = _Alloc()) : _Mybase(_Count, _Val, _Al) { _Trim(_Count); } - vector(const vector& _Right) : _Mybase(_Right) {} + _CONSTEXPR20_DYNALLOC vector(const vector& _Right) : _Mybase(_Right) {} - vector(const vector& _Right, const _Alloc& _Al) : _Mybase(_Right, _Al) {} + _CONSTEXPR20_DYNALLOC vector(const vector& _Right, const _Alloc& _Al) : _Mybase(_Right, _Al) {} template , int> = 0> - vector(_Iter _First, _Iter _Last, const _Alloc& _Al = _Alloc()) : _Mybase(_Al) { + _CONSTEXPR20_DYNALLOC vector(_Iter _First, _Iter _Last, const _Alloc& _Al = _Alloc()) : _Mybase(_Al) { _BConstruct(_First, _Last); } template - void _BConstruct(_Iter _First, _Iter _Last) { + _CONSTEXPR20_DYNALLOC void _BConstruct(_Iter _First, _Iter _Last) { insert(begin(), _First, _Last); } - vector(vector&& _Right) noexcept(is_nothrow_move_constructible_v<_Mybase>) // strengthened + _CONSTEXPR20_DYNALLOC vector(vector&& _Right) noexcept(is_nothrow_move_constructible_v<_Mybase>) // strengthened : _Mybase(_STD move(_Right)) { this->_Swap_proxy_and_iterators(_Right); } - vector(vector&& _Right, const _Alloc& _Al) noexcept(is_nothrow_constructible_v<_Mybase, _Mybase, const _Alloc&>) + _CONSTEXPR20_DYNALLOC vector(vector&& _Right, const _Alloc& _Al) noexcept( + is_nothrow_constructible_v<_Mybase, _Mybase, const _Alloc&>) : _Mybase(_STD move(_Right), _Al) { if _CONSTEXPR_IF (!_Alvbase_traits::is_always_equal::value) { if (this->_Getal() != _Right._Getal()) { @@ -2334,13 +2545,13 @@ public: private: #if _ITERATOR_DEBUG_LEVEL != 0 - void _Move_assign(vector& _Right, _Equal_allocators) noexcept { + _CONSTEXPR20_DYNALLOC void _Move_assign(vector& _Right, _Equal_allocators) noexcept { this->_Myvec = _STD move(_Right._Myvec); this->_Mysize = _STD exchange(_Right._Mysize, size_type{0}); this->_Swap_proxy_and_iterators(_Right); } - void _Move_assign(vector& _Right, _Propagate_allocators) noexcept { + _CONSTEXPR20_DYNALLOC void _Move_assign(vector& _Right, _Propagate_allocators) noexcept { using _Alproxy_type = _Rebind_alloc_t<_Alvbase, _Container_proxy>; if (this->_Getal() != _Right._Getal()) { // reload proxy // intentionally slams into noexcept on OOM, TRANSITION, VSO-466800 @@ -2359,7 +2570,7 @@ private: this->_Swap_proxy_and_iterators(_Right); } - void _Move_assign(vector& _Right, _No_propagate_allocators) { + _CONSTEXPR20_DYNALLOC void _Move_assign(vector& _Right, _No_propagate_allocators) { this->_Myvec = _STD move(_Right._Myvec); this->_Mysize = _Right._Mysize; if (_Right._Myvec.empty()) { @@ -2374,7 +2585,7 @@ private: #endif // _ITERATOR_DEBUG_LEVEL != 0 public: - vector& operator=(vector&& _Right) noexcept(is_nothrow_move_assignable_v<_Mybase>) { + _CONSTEXPR20_DYNALLOC vector& operator=(vector&& _Right) noexcept(is_nothrow_move_assignable_v<_Mybase>) { if (this != _STD addressof(_Right)) { #if _ITERATOR_DEBUG_LEVEL == 0 this->_Myvec = _STD move(_Right._Myvec); @@ -2388,7 +2599,7 @@ public: } template - decltype(auto) emplace_back(_Valty&&... _Val) { + _CONSTEXPR20_DYNALLOC decltype(auto) emplace_back(_Valty&&... _Val) { bool _Tmp(_STD forward<_Valty>(_Val)...); push_back(_Tmp); @@ -2398,38 +2609,39 @@ public: } template - iterator emplace(const_iterator _Where, _Valty&&... _Val) { + _CONSTEXPR20_DYNALLOC iterator emplace(const_iterator _Where, _Valty&&... _Val) { bool _Tmp(_STD forward<_Valty>(_Val)...); return insert(_Where, _Tmp); } - vector(initializer_list _Ilist, const _Alloc& _Al = allocator_type()) : _Mybase(0, false, _Al) { + _CONSTEXPR20_DYNALLOC vector(initializer_list _Ilist, const _Alloc& _Al = allocator_type()) + : _Mybase(0, false, _Al) { insert(begin(), _Ilist.begin(), _Ilist.end()); } - vector& operator=(initializer_list _Ilist) { + _CONSTEXPR20_DYNALLOC vector& operator=(initializer_list _Ilist) { assign(_Ilist.begin(), _Ilist.end()); return *this; } - void assign(initializer_list _Ilist) { + _CONSTEXPR20_DYNALLOC void assign(initializer_list _Ilist) { assign(_Ilist.begin(), _Ilist.end()); } - iterator insert(const_iterator _Where, initializer_list _Ilist) { + _CONSTEXPR20_DYNALLOC iterator insert(const_iterator _Where, initializer_list _Ilist) { return insert(_Where, _Ilist.begin(), _Ilist.end()); } - ~vector() noexcept {} + _CONSTEXPR20_DYNALLOC ~vector() noexcept {} private: #if _ITERATOR_DEBUG_LEVEL != 0 - void _Copy_assign(const vector& _Right, false_type) { + _CONSTEXPR20_DYNALLOC void _Copy_assign(const vector& _Right, false_type) { this->_Myvec = _Right._Myvec; this->_Mysize = _Right._Mysize; } - void _Copy_assign(const vector& _Right, true_type) { + _CONSTEXPR20_DYNALLOC void _Copy_assign(const vector& _Right, true_type) { if (this->_Getal() == _Right._Getal()) { _Copy_assign(_Right, false_type{}); } else { @@ -2446,7 +2658,7 @@ private: #endif // _ITERATOR_DEBUG_LEVEL != 0 public: - vector& operator=(const vector& _Right) { + _CONSTEXPR20_DYNALLOC vector& operator=(const vector& _Right) { if (this != _STD addressof(_Right)) { #if _ITERATOR_DEBUG_LEVEL == 0 this->_Myvec = _Right._Myvec; @@ -2460,70 +2672,70 @@ public: return *this; } - void reserve(_CRT_GUARDOVERFLOW size_type _Count) { + _CONSTEXPR20_DYNALLOC void reserve(_CRT_GUARDOVERFLOW size_type _Count) { this->_Myvec.reserve(this->_Nw(_Count)); } - _NODISCARD size_type capacity() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC size_type capacity() const noexcept { return this->_Myvec.capacity() * _VBITS; } - _NODISCARD iterator begin() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC iterator begin() noexcept { return iterator(this->_Myvec.data(), this); } - _NODISCARD const_iterator begin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator begin() const noexcept { return const_iterator(this->_Myvec.data(), this); } - _NODISCARD iterator end() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC iterator end() noexcept { return begin() + static_cast(this->_Mysize); } - _NODISCARD const_iterator end() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator end() const noexcept { return begin() + static_cast(this->_Mysize); } - _NODISCARD const_iterator cbegin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator cbegin() const noexcept { return begin(); } - _NODISCARD const_iterator cend() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator cend() const noexcept { return end(); } - _NODISCARD const_reverse_iterator crbegin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reverse_iterator crbegin() const noexcept { return rbegin(); } - _NODISCARD const_reverse_iterator crend() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reverse_iterator crend() const noexcept { return rend(); } - _NODISCARD iterator _Unchecked_begin() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC iterator _Unchecked_begin() noexcept { return iterator(this->_Myvec.data(), this); } - _NODISCARD const_iterator _Unchecked_begin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator _Unchecked_begin() const noexcept { return const_iterator(this->_Myvec.data(), this); } - _NODISCARD iterator _Unchecked_end() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC iterator _Unchecked_end() noexcept { return _Unchecked_begin() + static_cast(this->_Mysize); } - _NODISCARD const_iterator _Unchecked_end() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_iterator _Unchecked_end() const noexcept { return _Unchecked_begin() + static_cast(this->_Mysize); } - void shrink_to_fit() { + _CONSTEXPR20_DYNALLOC void shrink_to_fit() { if (this->_Myvec.capacity() != this->_Myvec.size()) { this->_Orphan_all(); this->_Myvec.shrink_to_fit(); } } - iterator _Make_iter(const_iterator _Where) noexcept { + _CONSTEXPR20_DYNALLOC iterator _Make_iter(const_iterator _Where) noexcept { iterator _Tmp = begin(); if (0 < this->_Mysize) { _Tmp += _Where - begin(); @@ -2532,23 +2744,23 @@ public: return _Tmp; } - _NODISCARD reverse_iterator rbegin() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } - _NODISCARD const_reverse_iterator rbegin() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } - _NODISCARD reverse_iterator rend() noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC reverse_iterator rend() noexcept { return reverse_iterator(begin()); } - _NODISCARD const_reverse_iterator rend() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } - void resize(_CRT_GUARDOVERFLOW size_type _Newsize, bool _Val = false) { + _CONSTEXPR20_DYNALLOC void resize(_CRT_GUARDOVERFLOW size_type _Newsize, bool _Val = false) { if (size() < _Newsize) { _Insert_n(end(), _Newsize - size(), _Val); } else if (_Newsize < size()) { @@ -2556,11 +2768,11 @@ public: } } - _NODISCARD size_type size() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC size_type size() const noexcept { return this->_Mysize; } - _NODISCARD size_type max_size() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC size_type max_size() const noexcept { constexpr auto _Diff_max = static_cast((numeric_limits::max)()); const size_type _Ints_max = this->_Myvec.max_size(); if (_Ints_max > _Diff_max / _VBITS) { // max_size bound by difference_type limits @@ -2571,15 +2783,15 @@ public: return _Ints_max * _VBITS; } - _NODISCARD bool empty() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC bool empty() const noexcept { return size() == 0; } - _NODISCARD allocator_type get_allocator() const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC allocator_type get_allocator() const noexcept { return static_cast(this->_Myvec.get_allocator()); } - _NODISCARD const_reference at(size_type _Off) const { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reference at(size_type _Off) const { if (size() <= _Off) { _Xran(); } @@ -2587,7 +2799,7 @@ public: return (*this)[_Off]; } - _NODISCARD reference at(size_type _Off) { + _NODISCARD _CONSTEXPR20_DYNALLOC reference at(size_type _Off) { if (size() <= _Off) { _Xran(); } @@ -2595,7 +2807,7 @@ public: return (*this)[_Off]; } - _NODISCARD const_reference operator[](size_type _Off) const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reference operator[](size_type _Off) const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off < this->_Mysize, "vector subscript out of range"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -2605,7 +2817,7 @@ public: return *_It; } - _NODISCARD reference operator[](size_type _Off) noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC reference operator[](size_type _Off) noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off < this->_Mysize, "vector subscript out of range"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -2615,7 +2827,7 @@ public: return *_It; } - _NODISCARD reference front() noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC reference front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Mysize != 0, "front() called on empty vector"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -2623,7 +2835,7 @@ public: return *begin(); } - _NODISCARD const_reference front() const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Mysize != 0, "front() called on empty vector"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -2631,7 +2843,7 @@ public: return *begin(); } - _NODISCARD reference back() noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC reference back() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Mysize != 0, "back() called on empty vector"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -2639,7 +2851,7 @@ public: return *(end() - 1); } - _NODISCARD const_reference back() const noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20_DYNALLOC const_reference back() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Mysize != 0, "back() called on empty vector"); #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -2647,42 +2859,43 @@ public: return *(end() - 1); } - void push_back(const bool& _Val) { + _CONSTEXPR20_DYNALLOC void push_back(const bool& _Val) { insert(end(), _Val); } - void pop_back() noexcept /* strengthened */ { + _CONSTEXPR20_DYNALLOC void pop_back() noexcept /* strengthened */ { erase(end() - 1); } template , int> = 0> - void assign(_Iter _First, _Iter _Last) { + _CONSTEXPR20_DYNALLOC void assign(_Iter _First, _Iter _Last) { clear(); insert(begin(), _First, _Last); } - void assign(_CRT_GUARDOVERFLOW size_type _Count, const bool& _Val) { + _CONSTEXPR20_DYNALLOC void assign(_CRT_GUARDOVERFLOW size_type _Count, const bool& _Val) { clear(); _Insert_n(begin(), _Count, _Val); } - iterator insert(const_iterator _Where, const bool& _Val) { + _CONSTEXPR20_DYNALLOC iterator insert(const_iterator _Where, const bool& _Val) { return _Insert_n(_Where, static_cast(1), _Val); } - iterator insert(const_iterator _Where, _CRT_GUARDOVERFLOW size_type _Count, const bool& _Val) { + _CONSTEXPR20_DYNALLOC iterator insert( + const_iterator _Where, _CRT_GUARDOVERFLOW size_type _Count, const bool& _Val) { return _Insert_n(_Where, _Count, _Val); } template , int> = 0> - iterator insert(const_iterator _Where, _Iter _First, _Iter _Last) { + _CONSTEXPR20_DYNALLOC iterator insert(const_iterator _Where, _Iter _First, _Iter _Last) { difference_type _Off = _Where - begin(); _Insert(_Where, _First, _Last, _Iter_cat_t<_Iter>{}); return begin() + _Off; } template - void _Insert(const_iterator _Where, _Iter _First, _Iter _Last, input_iterator_tag) { + _CONSTEXPR20_DYNALLOC void _Insert(const_iterator _Where, _Iter _First, _Iter _Last, input_iterator_tag) { difference_type _Off = _Where - begin(); for (; _First != _Last; ++_First, (void) ++_Off) { @@ -2691,14 +2904,14 @@ public: } template - void _Insert(const_iterator _Where, _Iter _First, _Iter _Last, forward_iterator_tag) { + _CONSTEXPR20_DYNALLOC void _Insert(const_iterator _Where, _Iter _First, _Iter _Last, forward_iterator_tag) { _Adl_verify_range(_First, _Last); auto _Count = _Convert_size(static_cast(_STD distance(_First, _Last))); size_type _Off = _Insert_x(_Where, _Count); _Copy_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), begin() + static_cast(_Off)); } - iterator erase(const_iterator _Where_arg) noexcept /* strengthened */ { + _CONSTEXPR20_DYNALLOC iterator erase(const_iterator _Where_arg) noexcept /* strengthened */ { iterator _Where = _Make_iter(_Where_arg); difference_type _Off = _Where - begin(); @@ -2715,7 +2928,8 @@ public: return begin() + _Off; } - iterator erase(const_iterator _First_arg, const_iterator _Last_arg) noexcept /* strengthened */ { + _CONSTEXPR20_DYNALLOC iterator erase(const_iterator _First_arg, const_iterator _Last_arg) noexcept + /* strengthened */ { iterator _First = _Make_iter(_First_arg); iterator _Last = _Make_iter(_Last_arg); difference_type _Off = _First - begin(); @@ -2736,13 +2950,13 @@ public: return begin() + _Off; } - void clear() noexcept { + _CONSTEXPR20_DYNALLOC void clear() noexcept { this->_Orphan_all(); this->_Myvec.clear(); this->_Mysize = 0; } - void flip() noexcept { // toggle all elements + _CONSTEXPR20_DYNALLOC void flip() noexcept { // toggle all elements for (auto& _Elem : this->_Myvec) { _Elem = ~_Elem; } @@ -2750,7 +2964,7 @@ public: _Trim(this->_Mysize); } - void swap(vector& _Right) noexcept /* strengthened */ { + _CONSTEXPR20_DYNALLOC void swap(vector& _Right) noexcept /* strengthened */ { if (this != _STD addressof(_Right)) { this->_Swap_proxy_and_iterators(_Right); this->_Myvec.swap(_Right._Myvec); @@ -2758,7 +2972,7 @@ public: } } - static void swap(reference _Left, reference _Right) noexcept { + static _CONSTEXPR20_DYNALLOC void swap(reference _Left, reference _Right) noexcept { bool _Val = _Left; // NOT _STD swap _Left = _Right; _Right = _Val; @@ -2766,14 +2980,14 @@ public: friend hash>; - iterator _Insert_n(const_iterator _Where, size_type _Count, const bool& _Val) { + _CONSTEXPR20_DYNALLOC iterator _Insert_n(const_iterator _Where, size_type _Count, const bool& _Val) { size_type _Off = _Insert_x(_Where, _Count); const auto _Result = begin() + static_cast(_Off); _STD fill(_Result, _Result + static_cast(_Count), _Val); return _Result; } - size_type _Insert_x(const_iterator _Where, size_type _Count) { + _CONSTEXPR20_DYNALLOC size_type _Insert_x(const_iterator _Where, size_type _Count) { difference_type _Off = _Where - begin(); #if _ITERATOR_DEBUG_LEVEL == 2 @@ -2805,7 +3019,7 @@ public: } #if _ITERATOR_DEBUG_LEVEL == 2 - void _Orphan_range(size_type _Offlo, size_type _Offhi) const { + void _Orphan_range_locked(size_type _Offlo, size_type _Offhi) const { _Lockit _Lock(_LOCK_DEBUG); const auto _Base = this->_Myvec.data(); @@ -2822,11 +3036,17 @@ public: } } -#else // _ITERATOR_DEBUG_LEVEL == 2 - void _Orphan_range(size_type, size_type) const {} + _CONSTEXPR20_DYNALLOC void _Orphan_range(size_type _Offlo, size_type _Offhi) const { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Orphan_range_locked(_Offlo, _Offhi); + } + } #endif // _ITERATOR_DEBUG_LEVEL == 2 - void _Trim(size_type _Size) { + _CONSTEXPR20_DYNALLOC void _Trim(size_type _Size) { if (max_size() < _Size) { _Xlen(); // result too long } @@ -2853,12 +3073,14 @@ public: }; template -_NODISCARD bool operator==(const vector& _Left, const vector& _Right) { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator==( + const vector& _Left, const vector& _Right) { return _Left.size() == _Right.size() && _Left._Myvec == _Right._Myvec; } template -_NODISCARD bool operator!=(const vector& _Left, const vector& _Right) { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator!=( + const vector& _Left, const vector& _Right) { return !(_Left == _Right); } @@ -2868,19 +3090,19 @@ struct hash> { _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef vector _ARGUMENT_TYPE_NAME; _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; - _NODISCARD size_t operator()(const vector& _Keyval) const noexcept { + _NODISCARD _CONSTEXPR20_DYNALLOC size_t operator()(const vector& _Keyval) const noexcept { return _Hash_array_representation(_Keyval._Myvec.data(), _Keyval._Myvec.size()); } }; #if _HAS_CXX20 template -typename vector<_Ty, _Alloc>::size_type erase(vector<_Ty, _Alloc>& _Cont, const _Uty& _Val) { +_CONSTEXPR20_DYNALLOC typename vector<_Ty, _Alloc>::size_type erase(vector<_Ty, _Alloc>& _Cont, const _Uty& _Val) { return _Erase_remove(_Cont, _Val); } template -typename vector<_Ty, _Alloc>::size_type erase_if(vector<_Ty, _Alloc>& _Cont, _Pr _Pred) { +_CONSTEXPR20_DYNALLOC typename vector<_Ty, _Alloc>::size_type erase_if(vector<_Ty, _Alloc>& _Cont, _Pr _Pred) { return _Erase_remove_if(_Cont, _Pass_fn(_Pred)); } #endif // _HAS_CXX20 diff --git a/stl/inc/xmemory b/stl/inc/xmemory index b1d8bfd0807..97b47d659ea 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(); } @@ -73,13 +73,28 @@ _INLINE_VAR constexpr size_t _New_alignof = (_STD max)(alignof(_Ty), // STRUCT _Default_allocate_traits struct _Default_allocate_traits { +#ifdef __clang__ + _CONSTEXPR20_DYNALLOC +#endif // __clang__ __declspec(allocator) static void* _Allocate(const size_t _Bytes) { return ::operator new(_Bytes); } #ifdef __cpp_aligned_new +#ifdef __clang__ + _CONSTEXPR20_DYNALLOC +#endif // __clang__ __declspec(allocator) static void* _Allocate_aligned(const size_t _Bytes, const size_t _Align) { - return ::operator new (_Bytes, align_val_t{_Align}); +#ifdef __clang__ +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return ::operator new(_Bytes); + } else +#endif // __cpp_lib_is_constant_evaluated +#endif // __clang__ + { + return ::operator new (_Bytes, align_val_t{_Align}); + } } #endif // __cpp_aligned_new }; @@ -157,34 +172,46 @@ inline void _Adjust_manually_vector_aligned(void*& _Ptr, size_t& _Bytes) { #ifdef __cpp_aligned_new template __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0> -__declspec(allocator) void* _Allocate(const size_t _Bytes) { +_CONSTEXPR20_DYNALLOC __declspec(allocator) void* _Allocate(const size_t _Bytes) { // allocate _Bytes when __cpp_aligned_new && _Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__ if (_Bytes == 0) { return nullptr; } - size_t _Passed_align = _Align; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return _Traits::_Allocate(_Bytes); + } else +#endif // __cpp_lib_is_constant_evaluated + { + size_t _Passed_align = _Align; #if defined(_M_IX86) || defined(_M_X64) - if (_Bytes >= _Big_allocation_threshold) { - // boost the alignment of big allocations to help autovectorization - _Passed_align = (_STD max)(_Align, _Big_allocation_alignment); - } + if (_Bytes >= _Big_allocation_threshold) { + // boost the alignment of big allocations to help autovectorization + _Passed_align = (_STD max)(_Align, _Big_allocation_alignment); + } #endif // defined(_M_IX86) || defined(_M_X64) - - return _Traits::_Allocate_aligned(_Bytes, _Passed_align); + return _Traits::_Allocate_aligned(_Bytes, _Passed_align); + } } template __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0> -void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept { +_CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept { // deallocate storage allocated by _Allocate when __cpp_aligned_new && _Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__ - size_t _Passed_align = _Align; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + ::operator delete(_Ptr); + } else +#endif // __cpp_lib_is_constant_evaluated + { + size_t _Passed_align = _Align; #if defined(_M_IX86) || defined(_M_X64) - if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization - _Passed_align = (_STD max)(_Align, _Big_allocation_alignment); - } + if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization + _Passed_align = (_STD max)(_Align, _Big_allocation_alignment); + } #endif // defined(_M_IX86) || defined(_M_X64) - - ::operator delete (_Ptr, _Bytes, align_val_t{_Passed_align}); + ::operator delete (_Ptr, _Bytes, align_val_t{_Passed_align}); + } } #define _HAS_ALIGNED_NEW 1 @@ -194,11 +221,16 @@ void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept { template = 0> -__declspec(allocator) void* _Allocate(const size_t _Bytes) { +_CONSTEXPR20_DYNALLOC __declspec(allocator) void* _Allocate(const size_t _Bytes) { // allocate _Bytes when !_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__ #if defined(_M_IX86) || defined(_M_X64) - if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization - return _Allocate_manually_vector_aligned<_Traits>(_Bytes); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization + return _Allocate_manually_vector_aligned<_Traits>(_Bytes); + } } #endif // defined(_M_IX86) || defined(_M_X64) @@ -210,25 +242,31 @@ __declspec(allocator) void* _Allocate(const size_t _Bytes) { } template = 0> -void _Deallocate(void* _Ptr, size_t _Bytes) noexcept { +_CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, size_t _Bytes) noexcept { // deallocate storage allocated by _Allocate when !_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__ +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + ::operator delete(_Ptr); + } else +#endif // __cpp_lib_is_constant_evaluated + { #if defined(_M_IX86) || defined(_M_X64) - if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization - _Adjust_manually_vector_aligned(_Ptr, _Bytes); - } + if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization + _Adjust_manually_vector_aligned(_Ptr, _Bytes); + } #endif // defined(_M_IX86) || defined(_M_X64) - - ::operator delete(_Ptr, _Bytes); + ::operator delete(_Ptr, _Bytes); + } } #undef _HAS_ALIGNED_NEW // 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)); } @@ -246,12 +284,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_DYNALLOC _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_DYNALLOC _Pointer _Refancy(_Pointer _Ptr) noexcept { return _Ptr; } @@ -271,6 +309,21 @@ _CONSTEXPR20_DYNALLOC void _Destroy_in_place(_Ty& _Obj) noexcept { } } +#if _HAS_CXX17 +// FUNCTION TEMPLATE destroy_at +template +_CONSTEXPR20_DYNALLOC void destroy_at(_Ty* const _Location) noexcept /* strengthened */ { +#if _HAS_CXX20 + if constexpr (is_array_v<_Ty>) { + _Destroy_range(_STD begin(*_Location), _STD end(*_Location)); + } else +#endif // _HAS_CXX20 + { + _Location->~_Ty(); + } +} +#endif // _HAS_CXX17 + // FUNCTION TEMPLATE _Const_cast template auto _Const_cast(_Ptrty _Ptr) noexcept { // remove constness from a fancy pointer @@ -519,12 +572,13 @@ struct _Normal_allocator_traits { // defines traits for allocators template using rebind_traits = allocator_traits>; - _NODISCARD static __declspec(allocator) pointer allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) { + _NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer + allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) { return _Al.allocate(_Count); } #if _HAS_IF_CONSTEXPR - _NODISCARD static __declspec(allocator) pointer + _NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const const_void_pointer _Hint) { if constexpr (_Has_allocate_hint<_Alloc, size_type, const_void_pointer>::value) { return _Al.allocate(_Count, _Hint); @@ -549,16 +603,23 @@ struct _Normal_allocator_traits { // defines traits for allocators } #endif // _HAS_IF_CONSTEXPR - static void deallocate(_Alloc& _Al, pointer _Ptr, size_type _Count) { + static _CONSTEXPR20_DYNALLOC void deallocate(_Alloc& _Al, pointer _Ptr, size_type _Count) { _Al.deallocate(_Ptr, _Count); } #if _HAS_IF_CONSTEXPR template - static void construct(_Alloc& _Al, _Ty* _Ptr, _Types&&... _Args) { + static _CONSTEXPR20_DYNALLOC void construct(_Alloc& _Al, _Ty* _Ptr, _Types&&... _Args) { if constexpr (_Uses_default_construct<_Alloc, _Ty*, _Types...>::value) { - (void) _Al; // TRANSITION, DevCom-1004719 - ::new (static_cast(_Ptr)) _Ty(_STD forward<_Types>(_Args)...); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _STD construct_at(_Ptr, _STD forward<_Types>(_Args)...); + } else +#endif // __cpp_lib_is_constant_evaluated + { + (void) _Al; // TRANSITION, DevCom-1004719 + ::new (static_cast(_Ptr)) _Ty(_STD forward<_Types>(_Args)...); + } } else { _Al.construct(_Ptr, _STD forward<_Types>(_Args)...); } @@ -583,9 +644,16 @@ struct _Normal_allocator_traits { // defines traits for allocators #if _HAS_IF_CONSTEXPR template - static void destroy(_Alloc& _Al, _Ty* _Ptr) { + static _CONSTEXPR20_DYNALLOC void destroy(_Alloc& _Al, _Ty* _Ptr) { if constexpr (_Uses_default_destroy<_Alloc, _Ty*>::value) { - _Ptr->~_Ty(); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _STD destroy_at(_Ptr); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Ptr->~_Ty(); + } } else { _Al.destroy(_Ptr); } @@ -608,7 +676,7 @@ struct _Normal_allocator_traits { // defines traits for allocators #endif // _HAS_IF_CONSTEXPR #if _HAS_IF_CONSTEXPR - _NODISCARD static size_type max_size(const _Alloc& _Al) noexcept { + _NODISCARD static _CONSTEXPR20_DYNALLOC size_type max_size(const _Alloc& _Al) noexcept { if constexpr (_Has_max_size<_Alloc>::value) { return _Al.max_size(); } else { @@ -630,7 +698,7 @@ struct _Normal_allocator_traits { // defines traits for allocators #endif // _HAS_IF_CONSTEXPR #if _HAS_IF_CONSTEXPR - _NODISCARD static _Alloc select_on_container_copy_construction(const _Alloc& _Al) { + _NODISCARD static _CONSTEXPR20_DYNALLOC _Alloc select_on_container_copy_construction(const _Alloc& _Al) { if constexpr (_Has_select_on_container_copy_construction<_Alloc>::value) { return _Al.select_on_container_copy_construction(); } else { @@ -677,35 +745,76 @@ struct _Default_allocator_traits { // traits for std::allocator template using rebind_traits = allocator_traits>; - _NODISCARD static __declspec(allocator) pointer allocate(_Alloc&, _CRT_GUARDOVERFLOW const size_type _Count) { - return static_cast(_Allocate<_New_alignof>(_Get_size_of_n(_Count))); + _NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer + allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return _Al.allocate(_Count); + } else +#endif // __cpp_lib_is_constant_evaluated + { + (void) _Al; + return static_cast( + _Allocate<_New_alignof>(_Get_size_of_n(_Count))); + } } - _NODISCARD static __declspec(allocator) pointer - allocate(_Alloc&, _CRT_GUARDOVERFLOW const size_type _Count, const_void_pointer) { - return static_cast(_Allocate<_New_alignof>(_Get_size_of_n(_Count))); + _NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer + allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const_void_pointer) { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return _Al.allocate(_Count); + } else +#endif // __cpp_lib_is_constant_evaluated + { + (void) _Al; + return static_cast( + _Allocate<_New_alignof>(_Get_size_of_n(_Count))); + } } - static void deallocate(_Alloc&, const pointer _Ptr, const size_type _Count) { + static _CONSTEXPR20_DYNALLOC void deallocate(_Alloc& _Al, const pointer _Ptr, const size_type _Count) { // no overflow check on the following multiply; we assume _Allocate did that check - _Deallocate<_New_alignof>(_Ptr, sizeof(value_type) * _Count); +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Al.deallocate(_Ptr, _Count); + } else +#endif // __cpp_lib_is_constant_evaluated + { + (void) _Al; + _Deallocate<_New_alignof>(_Ptr, sizeof(value_type) * _Count); + } } template - static void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) { - ::new (const_cast(static_cast(_Ptr))) _Objty(_STD forward<_Types>(_Args)...); + static _CONSTEXPR20_DYNALLOC void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _STD construct_at(_Ptr, _STD forward<_Types>(_Args)...); + } else +#endif // __cpp_lib_is_constant_evaluated + { + ::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); + } } template - static void destroy(_Alloc&, _Uty* const _Ptr) { - _Ptr->~_Uty(); + static _CONSTEXPR20_DYNALLOC void destroy(_Alloc&, _Uty* const _Ptr) { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _STD destroy_at(_Ptr); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Ptr->~_Uty(); + } } - _NODISCARD static size_type max_size(const _Alloc&) noexcept { + _NODISCARD static constexpr size_type max_size(const _Alloc&) noexcept { return static_cast(-1) / sizeof(value_type); } - _NODISCARD static _Alloc select_on_container_copy_construction(const _Alloc& _Al) { + _NODISCARD static constexpr _Alloc select_on_container_copy_construction(const _Alloc& _Al) { return _Al; } }; @@ -786,11 +895,12 @@ public: using other = allocator<_Other>; }; - _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD _Ty* address(_Ty& _Val) const noexcept { + _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD _CONSTEXPR20_DYNALLOC _Ty* address(_Ty& _Val) const noexcept { return _STD addressof(_Val); } - _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD const _Ty* address(const _Ty& _Val) const noexcept { + _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD _CONSTEXPR20_DYNALLOC const _Ty* address( + const _Ty& _Val) const noexcept { return _STD addressof(_Val); } @@ -800,31 +910,31 @@ public: template constexpr allocator(const allocator<_Other>&) noexcept {} - void deallocate(_Ty* const _Ptr, const size_t _Count) { + _CONSTEXPR20_DYNALLOC void deallocate(_Ty* const _Ptr, const size_t _Count) { // no overflow check on the following multiply; we assume _Allocate did that check _Deallocate<_New_alignof<_Ty>>(_Ptr, sizeof(_Ty) * _Count); } - _NODISCARD __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) { + _NODISCARD _CONSTEXPR20_DYNALLOC __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) { return static_cast<_Ty*>(_Allocate<_New_alignof<_Ty>>(_Get_size_of_n(_Count))); } - _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD __declspec(allocator) _Ty* allocate( + _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD _CONSTEXPR20_DYNALLOC __declspec(allocator) _Ty* allocate( _CRT_GUARDOVERFLOW const size_t _Count, const void*) { return allocate(_Count); } template - _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS void construct(_Objty* const _Ptr, _Types&&... _Args) { - ::new (const_cast(static_cast(_Ptr))) _Objty(_STD forward<_Types>(_Args)...); + _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _CONSTEXPR20_DYNALLOC void construct(_Objty* const _Ptr, _Types&&... _Args) { + ::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); } template - _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS void destroy(_Uty* const _Ptr) { + _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _CONSTEXPR20_DYNALLOC void destroy(_Uty* const _Ptr) { _Ptr->~_Uty(); } - _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD size_t max_size() const noexcept { + _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD _CONSTEXPR20_DYNALLOC size_t max_size() const noexcept { return static_cast(-1) / sizeof(_Ty); } }; @@ -850,12 +960,12 @@ public: }; template -_NODISCARD bool operator==(const allocator<_Ty>&, const allocator<_Other>&) noexcept { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator==(const allocator<_Ty>&, const allocator<_Other>&) noexcept { return true; } template -_NODISCARD bool operator!=(const allocator<_Ty>&, const allocator<_Other>&) noexcept { +_NODISCARD _CONSTEXPR20_DYNALLOC bool operator!=(const allocator<_Ty>&, const allocator<_Other>&) noexcept { return false; } @@ -877,7 +987,7 @@ using _Alloc_size_t = typename allocator_traits<_Alloc>::size_type; // FUNCTION TEMPLATE _Pocca #if _HAS_IF_CONSTEXPR template -void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { +_CONSTEXPR20_DYNALLOC void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { if constexpr (allocator_traits<_Alloc>::propagate_on_container_copy_assignment::value) { _Left = _Right; } @@ -900,7 +1010,8 @@ void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { // FUNCTION TEMPLATE _Pocma #if _HAS_IF_CONSTEXPR template -void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // (maybe) propagate on container move assignment +_CONSTEXPR20_DYNALLOC 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); } @@ -924,7 +1035,7 @@ void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // FUNCTION TEMPLATE _Pocs #if _HAS_IF_CONSTEXPR template -void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { +_CONSTEXPR20_DYNALLOC void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { if constexpr (allocator_traits<_Alloc>::propagate_on_container_swap::value) { _Swap_adl(_Left, _Right); } else { @@ -953,7 +1064,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_IF (!conjunction_v, _Uses_default_destroy<_Alloc, _Ty*>>) { @@ -994,7 +1106,7 @@ _NODISCARD constexpr size_t _Convert_size(const size_t _Len) noexcept { // FUNCTION TEMPLATE _Deallocate_plain #if _HAS_IF_CONSTEXPR 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*>) { @@ -1022,7 +1134,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(); @@ -1038,16 +1150,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); } @@ -1061,15 +1173,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_DYNALLOC void _Orphan_all() noexcept {} + _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators(_Container_base0&) noexcept {} + _CONSTEXPR20_DYNALLOC void _Alloc_proxy(const _Fake_allocator&) noexcept {} + _CONSTEXPR20_DYNALLOC 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_DYNALLOC void _Adopt(const void*) noexcept {} + _CONSTEXPR20_DYNALLOC const _Container_base0* _Getcont() const noexcept { return nullptr; } @@ -1079,8 +1191,9 @@ 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_DYNALLOC _Container_proxy() noexcept : _Mycont(nullptr), _Myfirstiter(nullptr) {} + _CONSTEXPR20_DYNALLOC _Container_proxy(_Container_base12* _Mycont_) noexcept + : _Mycont(_Mycont_), _Myfirstiter(nullptr) {} const _Container_base12* _Mycont; _Iterator_base12* _Myfirstiter; @@ -1088,16 +1201,18 @@ struct _Container_proxy { // store head of iterator chain and back pointer struct _Container_base12 { public: - _Container_base12() noexcept : _Myproxy(nullptr) {} + _CONSTEXPR20_DYNALLOC _Container_base12() noexcept : _Myproxy(nullptr) {} - _Container_base12(const _Container_base12&) = delete; - _Container_base12& operator=(const _Container_base12&) = delete; + _CONSTEXPR20_DYNALLOC _Container_base12(const _Container_base12&) = delete; + _CONSTEXPR20_DYNALLOC _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; + inline void _Orphan_all_locked() noexcept; + _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators(_Container_base12&) noexcept; + inline void _Swap_proxy_and_iterators_locked(_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; @@ -1105,7 +1220,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); @@ -1117,19 +1232,20 @@ public: }; struct _Iterator_base12 { // store links to container proxy, next iterator - _Iterator_base12() noexcept : _Myproxy(nullptr), _Mynextiter(nullptr) {} // construct orphaned iterator + _CONSTEXPR20_DYNALLOC _Iterator_base12() noexcept + : _Myproxy(nullptr), _Mynextiter(nullptr) {} // construct orphaned iterator - _Iterator_base12(const _Iterator_base12& _Right) noexcept : _Myproxy(nullptr), _Mynextiter(nullptr) { + _CONSTEXPR20_DYNALLOC _Iterator_base12(const _Iterator_base12& _Right) noexcept + : _Myproxy(nullptr), _Mynextiter(nullptr) { *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; @@ -1140,47 +1256,58 @@ struct _Iterator_base12 { // store links to container proxy, next iterator return *this; } - ~_Iterator_base12() noexcept { + _CONSTEXPR20_DYNALLOC ~_Iterator_base12() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 - _Lockit _Lock(_LOCK_DEBUG); _Orphan_me(); #endif // _ITERATOR_DEBUG_LEVEL == 2 } - 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); + void _Adopt_locked(const _Container_base12* _Parent) noexcept { + _Container_proxy* _Parent_proxy = _Parent->_Myproxy; + + if (_Myproxy != _Parent_proxy) { // change parentage + _Lockit _Lock(_LOCK_DEBUG); + _Orphan_me(); + _Mynextiter = _Parent_proxy->_Myfirstiter; + _Parent_proxy->_Myfirstiter = this; + _Myproxy = _Parent_proxy; + } + } + + _CONSTEXPR20_DYNALLOC void _Adopt(const _Container_base12* _Parent) noexcept { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + if (_Parent) { + _Adopt_locked(_Parent); + } else { + // no future parent, just disown current parent _Orphan_me(); - _Mynextiter = _Parent_proxy->_Myfirstiter; - _Parent_proxy->_Myfirstiter = this; - _Myproxy = _Parent_proxy; } - -#else // _ITERATOR_DEBUG_LEVEL == 2 + } + } +#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 + _Container_proxy* _Parent_proxy = _Parent->_Myproxy; _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); - _Orphan_me(); -#else // _ITERATOR_DEBUG_LEVEL == 2 _Myproxy = nullptr; -#endif // _ITERATOR_DEBUG_LEVEL == 2 } } +#endif // _ITERATOR_DEBUG_LEVEL == 2 - const _Container_base12* _Getcont() const noexcept { + _CONSTEXPR20_DYNALLOC const _Container_base12* _Getcont() const noexcept { return _Myproxy ? _Myproxy->_Mycont : nullptr; } #if _ITERATOR_DEBUG_LEVEL == 2 - void _Orphan_me() noexcept { + void _Orphan_me_locked() noexcept { + _Lockit _Lock(_LOCK_DEBUG); if (_Myproxy) { // adopted, remove self from list _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; while (*_Pnext && *_Pnext != this) { @@ -1192,6 +1319,15 @@ struct _Iterator_base12 { // store links to container proxy, next iterator _Myproxy = nullptr; } } + + _CONSTEXPR20_DYNALLOC void _Orphan_me() noexcept { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Orphan_me_locked(); + } + } #endif // _ITERATOR_DEBUG_LEVEL == 2 static constexpr bool _Unwrap_when_unverified = _ITERATOR_DEBUG_LEVEL == 0; @@ -1201,25 +1337,28 @@ struct _Iterator_base12 { // store links to container proxy, next iterator }; // MEMBER FUNCTIONS FOR _Container_base12 -inline void _Container_base12::_Orphan_all() noexcept { -#if _ITERATOR_DEBUG_LEVEL == 2 - if (_Myproxy) { // proxy allocated, drain it - _Lockit _Lock(_LOCK_DEBUG); +inline void _Container_base12::_Orphan_all_locked() noexcept { + _Lockit _Lock(_LOCK_DEBUG); + for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) { + (*_Pnext)->_Myproxy = nullptr; + } - for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) { - (*_Pnext)->_Myproxy = nullptr; - } + _Myproxy->_Myfirstiter = nullptr; +} - _Myproxy->_Myfirstiter = nullptr; +_CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all() noexcept { + if (_Myproxy) { // proxy allocated, drain it +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Orphan_all_locked(); + } } -#endif // _ITERATOR_DEBUG_LEVEL == 2 } -inline void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { -#if _ITERATOR_DEBUG_LEVEL == 2 +inline void _Container_base12::_Swap_proxy_and_iterators_locked(_Container_base12& _Right) noexcept { _Lockit _Lock(_LOCK_DEBUG); -#endif // _ITERATOR_DEBUG_LEVEL == 2 - _Container_proxy* _Temp = _Myproxy; _Myproxy = _Right._Myproxy; _Right._Myproxy = _Temp; @@ -1233,6 +1372,15 @@ inline void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Rig } } +_CONSTEXPR20_DYNALLOC void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Swap_proxy_and_iterators_locked(_Right); + } +} + #if _ITERATOR_DEBUG_LEVEL == 0 using _Container_base = _Container_base0; using _Iterator_base = _Iterator_base0; @@ -1249,23 +1397,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 + _CONSTEXPR20_DYNALLOC 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; }; @@ -1275,26 +1423,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) + _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); } @@ -1427,18 +1576,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; } @@ -1472,18 +1621,23 @@ namespace ranges { // FUNCTION TEMPLATE _Uninitialized_move_unchecked #if _HAS_IF_CONSTEXPR 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(); } #else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv template @@ -1519,22 +1673,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; } @@ -1548,7 +1703,7 @@ private: // FUNCTION TEMPLATE _Uninitialized_copy WITH ALLOCATOR #if _HAS_IF_CONSTEXPR 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 @@ -1559,16 +1714,21 @@ _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; } @@ -1612,6 +1772,28 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_copy( // FUNCTION TEMPLATE uninitialized_copy #if _HAS_IF_CONSTEXPR +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, ...) @@ -1619,18 +1801,7 @@ _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; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv @@ -1668,7 +1839,7 @@ _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrow // FUNCTION TEMPLATE _Uninitialized_move WITH ALLOCATOR #if _HAS_IF_CONSTEXPR 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 @@ -1677,16 +1848,20 @@ _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(); } #else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv template @@ -1733,27 +1908,37 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_move( // FUNCTION TEMPLATE _Uninitialized_fill_n WITH ALLOCATOR #if _HAS_IF_CONSTEXPR 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; + } + } + 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(); } #else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv template @@ -1857,22 +2042,26 @@ _Ptr _Zero_range(const _Ptr _First, const _Ptr _Last) { // fill [_First, _Last) #if _HAS_IF_CONSTEXPR 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(); } #else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv template @@ -2087,7 +2276,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(); @@ -2098,7 +2288,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(); diff --git a/stl/inc/xutility b/stl/inc/xutility index a613a5f8548..c12d539bb99 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -121,7 +121,7 @@ struct _Get_rebind_alias<_Ty, _Other, void_t -_NODISCARD void* _Voidify_iter(_Iter _It) noexcept { +_NODISCARD _CONSTEXPR20_DYNALLOC void* _Voidify_iter(_Iter _It) noexcept { #if _HAS_IF_CONSTEXPR if constexpr (is_pointer_v<_Iter>) { return const_cast(static_cast(_It)); @@ -132,15 +132,33 @@ _NODISCARD void* _Voidify_iter(_Iter _It) noexcept { } } +// FUNCTION TEMPLATE construct_at +#if _HAS_CXX20 +template +_CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( + noexcept(::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...))) // strengthened + -> decltype(::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...)) { + return ::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...); +} +#endif // _HAS_CXX20 + // 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; } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index c99f468a540..dd6e3ecdea2 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -176,6 +176,7 @@ // P0919R3 Heterogeneous Lookup For Unordered Containers // P0966R1 string::reserve() Should Not Shrink // P1001R2 execution::unseq +// P1004R2 constexpr std::vector // P1006R1 constexpr For pointer_traits::pointer_to() // P1007R3 assume_aligned() // P1020R1 Smart Pointer Creation With Default Initialization @@ -554,11 +555,11 @@ #endif // ^^^ inline (not constexpr) in C++17 and earlier ^^^ // Functions that became constexpr in C++20 via P0784R7 -#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) +#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) && defined(__clang__) #define _CONSTEXPR20_DYNALLOC constexpr #else #define _CONSTEXPR20_DYNALLOC inline -#endif +#endif // _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) && defined(__clang__) // P0607R0 Inline Variables For The STL #if _HAS_CXX17 @@ -1204,6 +1205,10 @@ #define __cpp_lib_constexpr_tuple 201811L #define __cpp_lib_constexpr_utility 201811L +#if defined(__cpp_constexpr_dynamic_alloc) && defined(__clang__) +#define __cpp_lib_constexpr_vector 201907L +#endif // __cpp_constexpr_dynamic_alloc && __clang__ + #ifdef __cpp_impl_coroutine // TRANSITION, Clang coroutine support #define __cpp_lib_coroutine 201902L #endif // __cpp_impl_coroutine diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 3996fe4e0ed..cf5bb191a44 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -493,18 +493,17 @@ 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 FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp FAIL +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 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 FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp FAIL -std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp FAIL -std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp:1 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 FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp 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 FAIL # C++20 P0896R4 "" diff --git a/tests/std/test.lst b/tests/std/test.lst index 3d71f043206..5237ab311ed 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -252,6 +252,7 @@ tests\P0758R1_is_nothrow_convertible tests\P0768R1_spaceship_cpos tests\P0768R1_spaceship_operator tests\P0769R2_shift_left_shift_right +tests\P0784R7_library_machinery tests\P0784R7_library_support_for_more_constexpr_containers tests\P0811R3_midpoint_lerp tests\P0896R4_common_iterator @@ -368,6 +369,8 @@ tests\P0898R3_identity tests\P0912R5_coroutine tests\P0919R3_heterogeneous_unordered_lookup tests\P0966R1_string_reserve_should_not_shrink +tests\P1004R2_constexpr_vector +tests\P1004R2_constexpr_vector_bool tests\P1007R3_assume_aligned tests\P1020R1_smart_pointer_for_overwrite tests\P1023R0_constexpr_for_array_comparisons diff --git a/tests/std/tests/P0784R7_library_machinery/env.lst b/tests/std/tests/P0784R7_library_machinery/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P0784R7_library_machinery/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P0784R7_library_machinery/test.cpp b/tests/std/tests/P0784R7_library_machinery/test.cpp new file mode 100644 index 00000000000..b5dd430f7c5 --- /dev/null +++ b/tests/std/tests/P0784R7_library_machinery/test.cpp @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +#pragma warning(disable : 4582) // '%s': constructor is not implicitly called +#pragma warning(disable : 4583) // '%s': destructor is not implicitly called + +using namespace std; + +struct int_wrapper_copy { + constexpr int_wrapper_copy() = default; + constexpr int_wrapper_copy(const int v) : _val(v){}; + + constexpr int_wrapper_copy(const int_wrapper_copy& other) : _val(other._val) {} + constexpr int_wrapper_copy& operator=(const int_wrapper_copy& other) { + _val = other._val; + return *this; + } + + constexpr int_wrapper_copy(int_wrapper_copy&&) = delete; + constexpr int_wrapper_copy& operator=(int_wrapper_copy&&) = delete; + + constexpr bool operator==(const int_wrapper_copy&) const = default; + + int _val = 0; +}; + +struct int_wrapper_move { + constexpr int_wrapper_move() = default; + constexpr int_wrapper_move(const int v) : _val(v){}; + + constexpr int_wrapper_move(const int_wrapper_move&) = delete; + constexpr int_wrapper_move& operator=(const int_wrapper_move&) = delete; + + constexpr int_wrapper_move(int_wrapper_move&& other) : _val(exchange(other._val, -1)) {} + constexpr int_wrapper_move& operator=(int_wrapper_move&& other) { + _val = exchange(other._val, -1); + return *this; + } + + constexpr bool operator==(const int_wrapper_move&) const = default; + + int _val = 0; +}; + +static constexpr int_wrapper_copy expected_copy[] = {1, 2, 3, 4}; +static constexpr int_wrapper_move expected_move[] = {1, 2, 3, 4}; +static constexpr int_wrapper_move expected_after_move[] = {-1, -1, -1, -1}; + +constexpr bool test() { + { // _Copy_unchecked + int_wrapper_copy input[] = {1, 2, 3, 4}; + int_wrapper_copy output[4] = {5, 6, 7, 8}; + + const auto result = _Copy_unchecked(begin(input), end(input), begin(output)); + static_assert(is_same_v, int_wrapper_copy*>); + assert(result == end(output)); + assert(equal(begin(expected_copy), end(expected_copy), begin(output), end(output))); + } + + { // _Copy_backward_unchecked + int_wrapper_copy input[] = {1, 2, 3, 4}; + int_wrapper_copy output[4] = {5, 6, 7, 8}; + + const auto result = _Copy_backward_unchecked(begin(input), end(input), end(output)); + static_assert(is_same_v, int_wrapper_copy*>); + assert(result == begin(output)); + assert(equal(begin(expected_copy), end(expected_copy), begin(output), end(output))); + } + +#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) && defined(__clang__) + { // _Uninitialized_copy_unchecked + int_wrapper_copy input[] = {1, 2, 3, 4}; + int_wrapper_copy output[4]; + + const auto result = _Uninitialized_copy_unchecked(begin(input), end(input), begin(output)); + static_assert(is_same_v, int_wrapper_copy*>); + assert(result == end(output)); + assert(equal(begin(expected_copy), end(expected_copy), begin(output), end(output))); + } +#endif // _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) + + { // _Move_unchecked + int_wrapper_move input[] = {1, 2, 3, 4}; + int_wrapper_move output[4] = {5, 6, 7, 8}; + + const auto result = _Move_unchecked(begin(input), end(input), begin(output)); + static_assert(is_same_v, int_wrapper_move*>); + assert(result == end(output)); + assert(equal(begin(expected_move), end(expected_move), begin(output), end(output))); + if (is_constant_evaluated()) { + assert(equal(begin(input), end(input), begin(expected_after_move), end(expected_after_move))); + } + } + + { // _Move_backward_unchecked + int_wrapper_move input[] = {1, 2, 3, 4}; + int_wrapper_move output[4] = {5, 6, 7, 8}; + + const auto result = _Move_backward_unchecked(begin(input), end(input), end(output)); + static_assert(is_same_v, int_wrapper_move*>); + assert(result == begin(output)); + assert(equal(begin(expected_move), end(expected_move), begin(output), end(output))); + if (is_constant_evaluated()) { + assert(equal(begin(input), end(input), begin(expected_after_move), end(expected_after_move))); + } + } + +#ifdef __cpp_lib_concepts + { // _Move_backward_common + int_wrapper_move input[] = {1, 2, 3, 4}; + int_wrapper_move output[4] = {5, 6, 7, 8}; + + const auto result = ranges::_Move_backward_common(begin(input), end(input), end(output)); + static_assert(is_same_v, int_wrapper_move*>); + assert(result == begin(output)); + assert(equal(begin(expected_move), end(expected_move), begin(output), end(output))); + if (is_constant_evaluated()) { + assert(equal(begin(input), end(input), begin(expected_after_move), end(expected_after_move))); + } + } +#endif // __cpp_lib_concepts + +#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) && defined(__clang__) + { // _Uninitialized_move_unchecked + int_wrapper_move input[] = {1, 2, 3, 4}; + int_wrapper_move output[4]; + + const auto result = _Uninitialized_move_unchecked(begin(input), end(input), begin(output)); + static_assert(is_same_v, int_wrapper_move*>); + assert(result == end(output)); + assert(equal(begin(expected_move), end(expected_move), begin(output), end(output))); + if (is_constant_evaluated()) { + assert(equal(begin(input), end(input), begin(expected_after_move), end(expected_after_move))); + } + } +#endif // _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) + return true; +} + +int main() { + test(); + static_assert(test()); +} diff --git a/tests/std/tests/P1004R2_constexpr_vector/env.lst b/tests/std/tests/P1004R2_constexpr_vector/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P1004R2_constexpr_vector/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P1004R2_constexpr_vector/test.cpp b/tests/std/tests/P1004R2_constexpr_vector/test.cpp new file mode 100644 index 00000000000..99942d10401 --- /dev/null +++ b/tests/std/tests/P1004R2_constexpr_vector/test.cpp @@ -0,0 +1,638 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; + +static constexpr int input[] = {0, 1, 2, 3, 4, 5}; + +template +struct soccc_allocator { + using value_type = T; + + _CONSTEXPR20_DYNALLOC soccc_allocator() noexcept = default; + _CONSTEXPR20_DYNALLOC explicit soccc_allocator(const int id_) noexcept : id(id_), soccc_generation(0) {} + _CONSTEXPR20_DYNALLOC explicit soccc_allocator(const int id_, const int soccc_generation_) noexcept + : id(id_), soccc_generation(soccc_generation_) {} + template + _CONSTEXPR20_DYNALLOC soccc_allocator(const soccc_allocator& other) noexcept + : id(other.id), soccc_generation(other.soccc_generation) {} + _CONSTEXPR20_DYNALLOC soccc_allocator(const soccc_allocator& other) noexcept + : id(other.id + 1), soccc_generation(other.soccc_generation){}; + + _CONSTEXPR20_DYNALLOC soccc_allocator& operator=(const soccc_allocator&) noexcept { + return *this; + } + + _CONSTEXPR20_DYNALLOC soccc_allocator select_on_container_copy_construction() const noexcept { + return soccc_allocator(id, soccc_generation + 1); + } + + template + _CONSTEXPR20_DYNALLOC bool operator==(const soccc_allocator& other) const noexcept { + return id == other.id; + } + + template + _CONSTEXPR20_DYNALLOC bool operator!=(const soccc_allocator& other) const noexcept { + return id != other.id; + } + + _CONSTEXPR20_DYNALLOC T* allocate(const size_t n) { + return allocator{}.allocate(n); + } + + _CONSTEXPR20_DYNALLOC void deallocate(T* const p, const size_t n) noexcept { + allocator{}.deallocate(p, n); + } + + template + _CONSTEXPR20_DYNALLOC void construct(T* const p, Args&&... args) { + construct_at(p, std::forward(args)...); + } + + int id = 0; + int soccc_generation = 0; +}; + +using vec = vector>; + +_CONSTEXPR20_DYNALLOC bool test_interface() { + { // constructors + + // Non allocator constructors + vec size_default_constructed(5); + assert(size_default_constructed.size() == 5); + assert(all_of( + size_default_constructed.begin(), size_default_constructed.end(), [](const int val) { return val == 0; })); + + vec size_value_constructed(5, 7); + assert(size_value_constructed.size() == 5); + assert(all_of( + size_value_constructed.begin(), size_value_constructed.end(), [](const int val) { return val == 7; })); + + vec range_constructed(begin(input), end(input)); + assert(equal(range_constructed.begin(), range_constructed.end(), begin(input), end(input))); + + vec initializer_list_constructed({2, 3, 4, 5}); + assert(equal( + initializer_list_constructed.begin(), initializer_list_constructed.end(), begin(input) + 2, end(input))); + + // special member functions + vec default_constructed; + vec copy_constructed(size_default_constructed); + assert(equal(copy_constructed.begin(), copy_constructed.end(), size_default_constructed.begin(), + size_default_constructed.end())); + + vec move_constructed(move(copy_constructed)); + assert(equal(move_constructed.begin(), move_constructed.end(), size_default_constructed.begin(), + size_default_constructed.end())); + assert(copy_constructed.empty()); + + vec copy_assigned = range_constructed; + assert(equal(copy_assigned.begin(), copy_assigned.end(), range_constructed.begin(), range_constructed.end())); + + vec move_assigned = std::move(copy_assigned); + assert(equal(move_assigned.begin(), move_assigned.end(), range_constructed.begin(), range_constructed.end())); + assert(copy_assigned.empty()); + + // allocator constructors + soccc_allocator alloc(2, 3); + assert(alloc.id == 2); + assert(alloc.soccc_generation == 3); + + vec al_default_constructed(alloc); + assert(al_default_constructed.empty()); + assert(al_default_constructed.get_allocator().id == 4); + assert(al_default_constructed.get_allocator().soccc_generation == 3); + + vec al_copy_constructed(size_value_constructed, alloc); + assert(all_of(al_copy_constructed.begin(), al_copy_constructed.end(), [](const int val) { return val == 7; })); + assert(al_copy_constructed.get_allocator().id == 4); + assert(al_copy_constructed.get_allocator().soccc_generation == 3); + + vec al_move_constructed(move(al_copy_constructed), alloc); + assert(all_of(al_move_constructed.begin(), al_move_constructed.end(), [](const int val) { return val == 7; })); + assert(al_copy_constructed.empty()); + assert(al_move_constructed.get_allocator().id == 4); + assert(al_move_constructed.get_allocator().soccc_generation == 3); + + vec al_size_default_constructed(5, alloc); + assert(al_size_default_constructed.size() == 5); + assert(all_of(al_size_default_constructed.begin(), al_size_default_constructed.end(), + [](const int val) { return val == 0; })); + assert(al_size_default_constructed.get_allocator().id == 4); + assert(al_size_default_constructed.get_allocator().soccc_generation == 3); + + vec al_size_value_constructed(5, 7, alloc); + assert(al_size_value_constructed.size() == 5); + assert(all_of(al_size_value_constructed.begin(), al_size_value_constructed.end(), + [](const int val) { return val == 7; })); + assert(al_size_value_constructed.get_allocator().id == 4); + assert(al_size_value_constructed.get_allocator().soccc_generation == 3); + + vec al_range_constructed(begin(input), end(input), alloc); + assert(equal(al_range_constructed.begin(), al_range_constructed.end(), begin(input), end(input))); + assert(al_range_constructed.get_allocator().id == 4); + assert(al_range_constructed.get_allocator().soccc_generation == 3); + + vec al_initializer_list_constructed({2, 3, 4, 5}, alloc); + assert(equal(al_initializer_list_constructed.begin(), al_initializer_list_constructed.end(), begin(input) + 2, + end(input))); + assert(al_initializer_list_constructed.get_allocator().id == 4); + assert(al_initializer_list_constructed.get_allocator().soccc_generation == 3); + } + + { // assignment + vec range_constructed(begin(input), end(input)); + + vec copy_constructed; + copy_constructed = range_constructed; + assert(equal( + copy_constructed.begin(), copy_constructed.end(), range_constructed.begin(), range_constructed.end())); + + vec move_constructed; + move_constructed = move(copy_constructed); + assert(equal( + move_constructed.begin(), move_constructed.end(), range_constructed.begin(), range_constructed.end())); + assert(copy_constructed.empty()); + + vec initializer_list_constructed; + initializer_list_constructed = {0, 1, 2, 3, 4, 5}; + assert( + equal(initializer_list_constructed.begin(), initializer_list_constructed.end(), begin(input), end(input))); + + vec assigned; + constexpr int expected_assign_value[] = {4, 4, 4, 4, 4}; + assigned.assign(5, 4); + assert(equal(assigned.begin(), assigned.end(), begin(expected_assign_value), end(expected_assign_value))); + + assigned.assign(begin(input), end(input)); + assert(equal(assigned.begin(), assigned.end(), begin(input), end(input))); + + constexpr int expected_assign_initializer[] = {2, 3, 4, 5}; + assigned.assign({2, 3, 4, 5}); + assert(equal( + assigned.begin(), assigned.end(), begin(expected_assign_initializer), end(expected_assign_initializer))); + } + + { // allocator + vec default_constructed; + const auto alloc = default_constructed.get_allocator(); + static_assert(is_same_v, soccc_allocator>); + assert(alloc.id == 1); + assert(alloc.soccc_generation == 0); + } + + { // iterators + vec range_constructed(begin(input), end(input)); + const vec const_range_constructed(begin(input), end(input)); + + const auto b = range_constructed.begin(); + static_assert(is_same_v, vec::iterator>); + assert(*b == 0); + + const auto cb = range_constructed.cbegin(); + static_assert(is_same_v, vec::const_iterator>); + assert(*cb == 0); + + const auto cb2 = const_range_constructed.begin(); + static_assert(is_same_v, vec::const_iterator>); + assert(*cb2 == 0); + + const auto e = range_constructed.end(); + static_assert(is_same_v, vec::iterator>); + assert(*prev(e) == 5); + + const auto ce = range_constructed.cend(); + static_assert(is_same_v, vec::const_iterator>); + assert(*prev(ce) == 5); + + const auto ce2 = const_range_constructed.end(); + static_assert(is_same_v, vec::const_iterator>); + assert(*prev(ce2) == 5); + + const auto rb = range_constructed.rbegin(); + static_assert(is_same_v, reverse_iterator>); + assert(*rb == 5); + + const auto crb = range_constructed.crbegin(); + static_assert(is_same_v, reverse_iterator>); + assert(*crb == 5); + + const auto crb2 = const_range_constructed.rbegin(); + static_assert(is_same_v, reverse_iterator>); + assert(*crb2 == 5); + + const auto re = range_constructed.rend(); + static_assert(is_same_v, reverse_iterator>); + assert(*prev(re) == 0); + + const auto cre = range_constructed.crend(); + static_assert(is_same_v, reverse_iterator>); + assert(*prev(cre) == 0); + + const auto cre2 = const_range_constructed.rend(); + static_assert(is_same_v, reverse_iterator>); + assert(*prev(cre2) == 0); + } + + { // access + vec range_constructed(begin(input), end(input)); + const vec const_range_constructed(begin(input), end(input)); + + const auto at = range_constructed.at(2); + static_assert(is_same_v, int>); + assert(at == 2); + + range_constructed.at(2) = 3; + + const auto at2 = range_constructed.at(2); + static_assert(is_same_v, int>); + assert(at2 == 3); + + const auto cat = const_range_constructed.at(2); + static_assert(is_same_v, int>); + assert(cat == 2); + + const auto op = range_constructed[3]; + static_assert(is_same_v, int>); + assert(op == 3); + + range_constructed[3] = 4; + const auto op2 = range_constructed[3]; + static_assert(is_same_v, int>); + assert(op2 == 4); + + const auto cop = const_range_constructed[3]; + static_assert(is_same_v, int>); + assert(cop == 3); + + const auto f = range_constructed.front(); + static_assert(is_same_v, int>); + assert(f == 0); + + const auto cf = const_range_constructed.front(); + static_assert(is_same_v, int>); + assert(cf == 0); + + const auto b = range_constructed.back(); + static_assert(is_same_v, int>); + assert(b == 5); + + const auto cb = const_range_constructed.back(); + static_assert(is_same_v, int>); + assert(cb == 5); + + const auto d = range_constructed.data(); + static_assert(is_same_v, int*>); + assert(*d == 0); + + const auto cd = const_range_constructed.data(); + static_assert(is_same_v, const int*>); + assert(*cd == 0); + } + + { // capacity + vec range_constructed(begin(input), end(input)); + + const auto e = range_constructed.empty(); + static_assert(is_same_v, bool>); + assert(!e); + + const auto s = range_constructed.size(); + static_assert(is_same_v, std::size_t>); + assert(s == size(input)); + + const auto ms = range_constructed.max_size(); + static_assert(is_same_v, std::size_t>); + assert(ms == static_cast(-1) / 4); + + range_constructed.reserve(20); + + const auto c = range_constructed.capacity(); + static_assert(is_same_v, std::size_t>); + assert(c == 20); + + range_constructed.shrink_to_fit(); + + const auto c2 = range_constructed.capacity(); + static_assert(is_same_v, std::size_t>); + assert(c2 == 6); + } + + { // modifiers + vec range_constructed(begin(input), end(input)); + + vec cleared = range_constructed; + cleared.clear(); + assert(cleared.empty()); + assert(cleared.capacity() == range_constructed.capacity()); + + vec inserted; + + const int to_be_inserted = 3; + inserted.insert(inserted.begin(), to_be_inserted); + assert(inserted.size() == 1); + assert(inserted.front() == 3); + + const int to_be_inserted2 = 4; + inserted.insert(inserted.cbegin(), to_be_inserted2); + assert(inserted.size() == 2); + assert(inserted.front() == 4); + + inserted.insert(inserted.begin(), 1); + assert(inserted.size() == 3); + assert(inserted.front() == 1); + + inserted.insert(inserted.cbegin(), 2); + assert(inserted.size() == 4); + assert(inserted.front() == 2); + + const auto it = inserted.insert(inserted.begin(), begin(input), end(input)); + assert(inserted.size() == 10); + assert(it == inserted.begin()); + + const auto it2 = inserted.insert(inserted.cbegin(), begin(input), end(input)); + assert(inserted.size() == 16); + assert(it2 == inserted.begin()); + + const auto it3 = inserted.insert(inserted.begin(), {2, 3, 4}); + assert(inserted.size() == 19); + assert(it3 == inserted.begin()); + + inserted.insert(inserted.cbegin(), {2, 3, 4}); + assert(inserted.size() == 22); + + vec emplaced; + emplaced.emplace(emplaced.cbegin(), 42); + assert(emplaced.size() == 1); + assert(emplaced.front() == 42); + + emplaced.emplace_back(43); + assert(emplaced.size() == 2); + assert(emplaced.back() == 43); + + emplaced.push_back(44); + assert(emplaced.size() == 3); + assert(emplaced.back() == 44); + + const int to_be_pushed = 45; + emplaced.push_back(to_be_pushed); + assert(emplaced.size() == 4); + assert(emplaced.back() == 45); + + emplaced.pop_back(); + assert(emplaced.size() == 3); + assert(emplaced.back() == 44); + + emplaced.resize(1); + assert(emplaced.size() == 1); + assert(emplaced.front() == 42); + + emplaced.swap(inserted); + assert(inserted.size() == 1); + assert(inserted.front() == 42); + assert(emplaced.size() == 22); + } + + { // swap + vec first{2, 3, 4}; + vec second{5, 6, 7, 8}; + swap(first, second); + + constexpr int expected_first[] = {5, 6, 7, 8}; + constexpr int expected_second[] = {2, 3, 4}; + assert(equal(first.begin(), first.end(), begin(expected_first), end(expected_first))); + assert(equal(second.begin(), second.end(), begin(expected_second), end(expected_second))); + } + + { // erase + vec erased{1, 2, 3, 4, 2, 3, 2}; + erase(erased, 2); + constexpr int expected_erased[] = {1, 3, 4, 3}; + assert(equal(erased.begin(), erased.end(), begin(expected_erased), end(expected_erased))); + + erase_if(erased, [](const int val) { return val < 4; }); + constexpr int expected_erase_if[] = {4}; + assert(equal(erased.begin(), erased.end(), begin(expected_erase_if), end(expected_erase_if))); + } + + { // comparison + vec first(begin(input), end(input)); + vec second(begin(input), end(input)); + vec third{2, 3, 4}; + + const auto e = first == second; + static_assert(is_same_v, bool>); + assert(e); + + const auto ne = first != third; + static_assert(is_same_v, bool>); + assert(ne); + } + return true; +} + +_CONSTEXPR20_DYNALLOC bool test_iterators() { + vec range_constructed(begin(input), end(input)); + + { // increment + auto it = range_constructed.begin(); + assert(*++it == 1); + assert(*it++ == 1); + assert(*it == 2); + + auto cit = range_constructed.cbegin(); + assert(*++cit == 1); + assert(*cit++ == 1); + assert(*cit == 2); + } + + { // advance + auto it = range_constructed.begin() + 2; + assert(*it == 2); + it += 2; + assert(*it == 4); + + auto cit = range_constructed.cbegin() + 2; + assert(*cit == 2); + cit += 2; + assert(*cit == 4); + } + + { // decrement + auto it = range_constructed.end(); + assert(*--it == 5); + assert(*it-- == 5); + assert(*it == 4); + + auto cit = range_constructed.cend(); + assert(*--cit == 5); + assert(*cit-- == 5); + assert(*cit == 4); + } + + { // advance back + auto it = range_constructed.end() - 2; + assert(*it == 4); + it -= 2; + assert(*it == 2); + + auto cit = range_constructed.cend() - 2; + assert(*cit == 4); + cit -= 2; + assert(*cit == 2); + } + + { // difference + const auto it1 = range_constructed.begin(); + const auto it2 = range_constructed.end(); + assert(it2 - it1 == ssize(input)); + + const auto cit1 = range_constructed.cbegin(); + const auto cit2 = range_constructed.cend(); + assert(cit2 - cit1 == ssize(input)); + + assert(it2 - cit1 == ssize(input)); + assert(cit2 - it1 == ssize(input)); + } + + { // comparison + const auto it1 = range_constructed.begin(); + const auto it2 = range_constructed.begin(); + const auto it3 = range_constructed.end(); + + assert(it1 == it2); + assert(it1 != it3); + assert(it1 < it3); + assert(it1 <= it3); + assert(it3 > it1); + assert(it3 >= it1); + } + + { // access + const auto it = range_constructed.begin() + 2; + it[2] = 3; + assert(range_constructed[4] == 3); + + const auto cit = range_constructed.cbegin() + 2; + assert(cit[2] == 3); + + std::vector> vec2 = {{1, 2}, {2, 3}}; + const auto it2 = vec2.begin(); + assert(it2->second == 2); + + const auto cit2 = vec2.cbegin(); + assert(cit2->first == 1); + } + + return true; +} + +_CONSTEXPR20_DYNALLOC bool test_growth() { + { + vector v(1000, 1729); + + assert(v.size() == 1000); + assert(v.capacity() == 1000); + + v.resize(1003); + + assert(v.size() == 1003); + assert(v.capacity() == 1500); + } + + { + vector v(1000, 1729); + + assert(v.size() == 1000); + assert(v.capacity() == 1000); + + v.resize(8000); + + assert(v.size() == 8000); + assert(v.capacity() == 8000); + } + + { + vector v(1000, 1729); + + assert(v.size() == 1000); + assert(v.capacity() == 1000); + + v.push_back(47); + + assert(v.size() == 1001); + assert(v.capacity() == 1500); + } + + { + vector v(1000, 1729); + + assert(v.size() == 1000); + assert(v.capacity() == 1000); + + vector l(3, 47); + + v.insert(v.end(), l.begin(), l.end()); + + assert(v.size() == 1003); + assert(v.capacity() == 1500); + } + + { + vector v(1000, 1729); + + assert(v.size() == 1000); + assert(v.capacity() == 1000); + + vector l(7000, 47); + + v.insert(v.end(), l.begin(), l.end()); + + assert(v.size() == 8000); + assert(v.capacity() == 8000); + } + + { + vector v(1000, 1729); + + assert(v.size() == 1000); + assert(v.capacity() == 1000); + + v.insert(v.end(), 3, 47); + + assert(v.size() == 1003); + assert(v.capacity() == 1500); + } + + { + vector v(1000, 1729); + + assert(v.size() == 1000); + assert(v.capacity() == 1000); + + v.insert(v.end(), 7000, 47); + + assert(v.size() == 8000); + assert(v.capacity() == 8000); + } + return true; +} + +int main() { + test_interface(); + test_iterators(); + test_growth(); +#ifdef __cpp_lib_constexpr_vector + static_assert(test_interface()); + static_assert(test_iterators()); + static_assert(test_growth()); +#endif // __cpp_lib_constexpr_vector +} diff --git a/tests/std/tests/P1004R2_constexpr_vector_bool/env.lst b/tests/std/tests/P1004R2_constexpr_vector_bool/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P1004R2_constexpr_vector_bool/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P1004R2_constexpr_vector_bool/test.cpp b/tests/std/tests/P1004R2_constexpr_vector_bool/test.cpp new file mode 100644 index 00000000000..c13ba554c0c --- /dev/null +++ b/tests/std/tests/P1004R2_constexpr_vector_bool/test.cpp @@ -0,0 +1,538 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; + +static constexpr bool input[] = {true, false, true, true, false, true}; + +template +struct soccc_allocator { + using value_type = T; + + _CONSTEXPR20_DYNALLOC soccc_allocator() noexcept = default; + _CONSTEXPR20_DYNALLOC explicit soccc_allocator(const int id_) noexcept : id(id_), soccc_generation(0) {} + _CONSTEXPR20_DYNALLOC explicit soccc_allocator(const int id_, const int soccc_generation_) noexcept + : id(id_), soccc_generation(soccc_generation_) {} + template + _CONSTEXPR20_DYNALLOC soccc_allocator(const soccc_allocator& other) noexcept + : id(other.id), soccc_generation(other.soccc_generation) {} + _CONSTEXPR20_DYNALLOC soccc_allocator(const soccc_allocator& other) noexcept + : id(other.id + 1), soccc_generation(other.soccc_generation){}; + + _CONSTEXPR20_DYNALLOC soccc_allocator& operator=(const soccc_allocator&) noexcept { + return *this; + } + + _CONSTEXPR20_DYNALLOC soccc_allocator select_on_container_copy_construction() const noexcept { + return soccc_allocator(id, soccc_generation + 1); + } + + template + _CONSTEXPR20_DYNALLOC bool operator==(const soccc_allocator& other) const noexcept { + return id == other.id; + } + + template + _CONSTEXPR20_DYNALLOC bool operator!=(const soccc_allocator& other) const noexcept { + return id != other.id; + } + + _CONSTEXPR20_DYNALLOC T* allocate(const size_t n) { + return allocator{}.allocate(n); + } + + _CONSTEXPR20_DYNALLOC void deallocate(T* const p, const size_t n) noexcept { + allocator{}.deallocate(p, n); + } + + template + _CONSTEXPR20_DYNALLOC void construct(T* const p, Args&&... args) { + construct_at(p, std::forward(args)...); + } + + int id = 0; + int soccc_generation = 0; +}; + +using vec = vector>; + +_CONSTEXPR20_DYNALLOC bool test_interface() { + { // constructors + + // Non allocator constructors + vec size_default_constructed(5); + assert(size_default_constructed.size() == 5); + assert(all_of( + size_default_constructed.begin(), size_default_constructed.end(), [](const bool val) { return !val; })); + + vec size_value_constructed(5, true); + assert(size_value_constructed.size() == 5); + assert( + all_of(size_value_constructed.begin(), size_value_constructed.end(), [](const bool val) { return val; })); + + vec range_constructed(begin(input), end(input)); + assert(equal(range_constructed.begin(), range_constructed.end(), begin(input), end(input))); + + vec initializer_list_constructed({true, true, false, true}); + assert(equal( + initializer_list_constructed.begin(), initializer_list_constructed.end(), begin(input) + 2, end(input))); + + // special member functions + vec default_constructed; + vec copy_constructed(size_default_constructed); + assert(equal(copy_constructed.begin(), copy_constructed.end(), size_default_constructed.begin(), + size_default_constructed.end())); + + vec move_constructed(move(copy_constructed)); + assert(equal(move_constructed.begin(), move_constructed.end(), size_default_constructed.begin(), + size_default_constructed.end())); + assert(copy_constructed.empty()); + + vec copy_assigned = range_constructed; + assert(equal(copy_assigned.begin(), copy_assigned.end(), range_constructed.begin(), range_constructed.end())); + + vec move_assigned = std::move(copy_assigned); + assert(equal(move_assigned.begin(), move_assigned.end(), range_constructed.begin(), range_constructed.end())); + assert(copy_assigned.empty()); + + // allocator constructors + soccc_allocator alloc(2, 3); + assert(alloc.id == 2); + assert(alloc.soccc_generation == 3); + + vec al_default_constructed(alloc); + assert(al_default_constructed.empty()); + assert(al_default_constructed.get_allocator().id == 4); + assert(al_default_constructed.get_allocator().soccc_generation == 3); + + vec al_copy_constructed(size_value_constructed, alloc); + assert(all_of(al_copy_constructed.begin(), al_copy_constructed.end(), [](const bool val) { return val; })); + assert(al_copy_constructed.get_allocator().id == 4); + assert(al_copy_constructed.get_allocator().soccc_generation == 3); + + vec al_move_constructed(move(al_copy_constructed), alloc); + assert(all_of(al_move_constructed.begin(), al_move_constructed.end(), [](const bool val) { return val; })); + assert(al_copy_constructed.empty()); + assert(al_move_constructed.get_allocator().id == 4); + assert(al_move_constructed.get_allocator().soccc_generation == 3); + + vec al_size_default_constructed(5, alloc); + assert(al_size_default_constructed.size() == 5); + assert(all_of(al_size_default_constructed.begin(), al_size_default_constructed.end(), + [](const bool val) { return !val; })); + assert(al_size_default_constructed.get_allocator().id == 4); + assert(al_size_default_constructed.get_allocator().soccc_generation == 3); + + vec al_size_value_constructed(5, true, alloc); + assert(al_size_value_constructed.size() == 5); + assert(all_of( + al_size_value_constructed.begin(), al_size_value_constructed.end(), [](const bool val) { return val; })); + assert(al_size_value_constructed.get_allocator().id == 4); + assert(al_size_value_constructed.get_allocator().soccc_generation == 3); + + vec al_range_constructed(begin(input), end(input), alloc); + assert(equal(al_range_constructed.begin(), al_range_constructed.end(), begin(input), end(input))); + assert(al_range_constructed.get_allocator().id == 4); + assert(al_range_constructed.get_allocator().soccc_generation == 3); + + vec al_initializer_list_constructed({true, true, false, true}, alloc); + assert(equal(al_initializer_list_constructed.begin(), al_initializer_list_constructed.end(), begin(input) + 2, + end(input))); + assert(al_initializer_list_constructed.get_allocator().id == 4); + assert(al_initializer_list_constructed.get_allocator().soccc_generation == 3); + } + + { // assignment + vec range_constructed(begin(input), end(input)); + + vec copy_constructed; + copy_constructed = range_constructed; + assert(equal( + copy_constructed.begin(), copy_constructed.end(), range_constructed.begin(), range_constructed.end())); + + vec move_constructed; + move_constructed = move(copy_constructed); + assert(equal( + move_constructed.begin(), move_constructed.end(), range_constructed.begin(), range_constructed.end())); + assert(copy_constructed.empty()); + + vec initializer_list_constructed; + initializer_list_constructed = {true, false, true, true, false, true}; + assert( + equal(initializer_list_constructed.begin(), initializer_list_constructed.end(), begin(input), end(input))); + + vec assigned; + constexpr bool expected_assign_value[] = {true, true, true, true, true}; + assigned.assign(5, true); + assert(equal(assigned.begin(), assigned.end(), begin(expected_assign_value), end(expected_assign_value))); + + assigned.assign(begin(input), end(input)); + assert(equal(assigned.begin(), assigned.end(), begin(input), end(input))); + + constexpr bool expected_assign_initializer[] = {true, false, true, true, false, true}; + assigned.assign({true, false, true, true, false, true}); + assert(equal( + assigned.begin(), assigned.end(), begin(expected_assign_initializer), end(expected_assign_initializer))); + } + + { // allocator + vec default_constructed; + const auto alloc = default_constructed.get_allocator(); + static_assert(is_same_v, soccc_allocator>); + assert(alloc.id == 1); + assert(alloc.soccc_generation == 0); + } + + { // iterators + vec range_constructed(begin(input), end(input)); + const vec const_range_constructed(begin(input), end(input)); + + const auto b = range_constructed.begin(); + static_assert(is_same_v, vec::iterator>); + assert(*b); + + const auto cb = range_constructed.cbegin(); + static_assert(is_same_v, vec::const_iterator>); + assert(*cb); + + const auto cb2 = const_range_constructed.begin(); + static_assert(is_same_v, vec::const_iterator>); + assert(*cb2); + + const auto e = range_constructed.end(); + static_assert(is_same_v, vec::iterator>); + assert(*prev(e)); + + const auto ce = range_constructed.cend(); + static_assert(is_same_v, vec::const_iterator>); + assert(*prev(ce)); + + const auto ce2 = const_range_constructed.end(); + static_assert(is_same_v, vec::const_iterator>); + assert(*prev(ce2)); + + const auto rb = range_constructed.rbegin(); + static_assert(is_same_v, reverse_iterator>); + assert(*rb); + + const auto crb = range_constructed.crbegin(); + static_assert(is_same_v, reverse_iterator>); + assert(*crb); + + const auto crb2 = const_range_constructed.rbegin(); + static_assert(is_same_v, reverse_iterator>); + assert(*crb2); + + const auto re = range_constructed.rend(); + static_assert(is_same_v, reverse_iterator>); + assert(*prev(re)); + + const auto cre = range_constructed.crend(); + static_assert(is_same_v, reverse_iterator>); + assert(*prev(cre)); + + const auto cre2 = const_range_constructed.rend(); + static_assert(is_same_v, reverse_iterator>); + assert(*prev(cre2)); + } + + { // access + vec range_constructed(begin(input), end(input)); + const vec const_range_constructed(begin(input), end(input)); + + const auto at = range_constructed.at(2); + static_assert(is_same_v, _Iter_ref_t>); + assert(at); + + range_constructed.at(2) = false; + + const auto at2 = range_constructed.at(2); + static_assert(is_same_v, _Iter_ref_t>); + assert(at2 == false); + + const auto cat = const_range_constructed.at(2); + static_assert(is_same_v, _Iter_ref_t>); + assert(cat); + + const auto op = range_constructed[3]; + static_assert(is_same_v, _Iter_ref_t>); + assert(op); + + range_constructed[3] = true; + const auto op2 = range_constructed[3]; + static_assert(is_same_v, _Iter_ref_t>); + assert(op2); + + const auto cop = const_range_constructed[3]; + static_assert(is_same_v, _Iter_ref_t>); + assert(cop); + + const auto f = range_constructed.front(); + static_assert(is_same_v, _Iter_ref_t>); + assert(f); + + const auto cf = const_range_constructed.front(); + static_assert(is_same_v, _Iter_ref_t>); + assert(cf); + + const auto b = range_constructed.back(); + static_assert(is_same_v, _Iter_ref_t>); + assert(b); + + const auto cb = const_range_constructed.back(); + static_assert(is_same_v, _Iter_ref_t>); + assert(cb); + } + + { // capacity + vec range_constructed(begin(input), end(input)); + + const auto e = range_constructed.empty(); + static_assert(is_same_v, bool>); + assert(e == false); + + const auto s = range_constructed.size(); + static_assert(is_same_v, std::size_t>); + assert(s == size(input)); + + const auto ms = range_constructed.max_size(); + static_assert(is_same_v, std::size_t>); + assert(ms == static_cast(std::numeric_limits::max())); + + range_constructed.reserve(20); + + const auto c = range_constructed.capacity(); + static_assert(is_same_v, std::size_t>); + assert(c == 32); + + range_constructed.shrink_to_fit(); + + const auto c2 = range_constructed.capacity(); + static_assert(is_same_v, std::size_t>); + assert(c2 == 32); + } + + { // modifiers + vec range_constructed(begin(input), end(input)); + + vec cleared = range_constructed; + cleared.clear(); + assert(cleared.empty()); + assert(cleared.capacity() == range_constructed.capacity()); + + vec inserted; + + const bool to_be_inserted = true; + inserted.insert(inserted.begin(), to_be_inserted); + assert(inserted.size() == 1); + assert(inserted.front()); + + const bool to_be_inserted2 = false; + inserted.insert(inserted.cbegin(), to_be_inserted2); + assert(inserted.size() == 2); + assert(inserted.front() == false); + + inserted.insert(inserted.begin(), true); + assert(inserted.size() == 3); + assert(inserted.front()); + + inserted.insert(inserted.cbegin(), false); + assert(inserted.size() == 4); + assert(inserted.front() == false); + + const auto it = inserted.insert(inserted.begin(), begin(input), end(input)); + assert(inserted.size() == 10); + assert(it == inserted.begin()); + + const auto it2 = inserted.insert(inserted.cbegin(), begin(input), end(input)); + assert(inserted.size() == 16); + assert(it2 == inserted.begin()); + + const auto it3 = inserted.insert(inserted.begin(), {true, false, true}); + assert(inserted.size() == 19); + assert(it3 == inserted.begin()); + + inserted.insert(inserted.cbegin(), {false, true, false}); + assert(inserted.size() == 22); + + vec emplaced; + emplaced.emplace(emplaced.cbegin(), false); + assert(emplaced.size() == 1); + assert(emplaced.front() == false); + + emplaced.emplace_back(true); + assert(emplaced.size() == 2); + assert(emplaced.back()); + + emplaced.push_back(false); + assert(emplaced.size() == 3); + assert(emplaced.back() == false); + + const bool to_be_pushed = true; + emplaced.push_back(to_be_pushed); + assert(emplaced.size() == 4); + assert(emplaced.back()); + + emplaced.pop_back(); + assert(emplaced.size() == 3); + assert(emplaced.back() == false); + + emplaced.resize(1); + assert(emplaced.size() == 1); + assert(emplaced.front() == false); + + emplaced.swap(inserted); + assert(inserted.size() == 1); + assert(inserted.front() == false); + assert(emplaced.size() == 22); + } + + { // swap + vec first{true, false, true}; + vec second{false, false, true, false}; + swap(first, second); + + constexpr bool expected_first[] = {false, false, true, false}; + constexpr bool expected_second[] = {true, false, true}; + assert(equal(first.begin(), first.end(), begin(expected_first), end(expected_first))); + assert(equal(second.begin(), second.end(), begin(expected_second), end(expected_second))); + } + + { // erase + vec erased{false, false, true, false, true}; + erase(erased, false); + constexpr bool expected_erased[] = {true, true}; + assert(equal(erased.begin(), erased.end(), begin(expected_erased), end(expected_erased))); + + vec erased_if{false, false, true, false, true}; + erase_if(erased_if, [](const bool val) { return val; }); + constexpr bool expected_erase_if[] = {false, false, false}; + assert(equal(erased_if.begin(), erased_if.end(), begin(expected_erase_if), end(expected_erase_if))); + } + + { // comparison + vec first(begin(input), end(input)); + vec second(begin(input), end(input)); + vec third{true, false, true}; + + const auto e = first == second; + static_assert(is_same_v, bool>); + assert(e); + + const auto ne = first != third; + static_assert(is_same_v, bool>); + assert(ne); + } + return true; +} + +_CONSTEXPR20_DYNALLOC bool test_iterators() { + vec range_constructed(begin(input), end(input)); + + { // increment + auto it = range_constructed.begin(); + assert(*++it == false); + assert(*it++ == false); + assert(*it); + + auto cit = range_constructed.cbegin(); + assert(*++cit == false); + assert(*cit++ == false); + assert(*cit); + } + + { // advance + auto it = range_constructed.begin() + 2; + assert(*it); + it += 2; + assert(*it == false); + + auto cit = range_constructed.cbegin() + 2; + assert(*cit); + cit += 2; + assert(*cit == false); + } + + { // decrement + auto it = range_constructed.end(); + assert(*--it); + assert(*it--); + assert(*it == false); + + auto cit = range_constructed.cend(); + assert(*--cit); + assert(*cit--); + assert(*cit == false); + } + + { // advance back + auto it = range_constructed.end() - 2; + assert(*it == false); + it -= 2; + assert(*it); + + auto cit = range_constructed.cend() - 2; + assert(*cit == false); + cit -= 2; + assert(*cit); + } + + { // difference + const auto it1 = range_constructed.begin(); + const auto it2 = range_constructed.end(); + assert(it2 - it1 == ssize(input)); + + const auto cit1 = range_constructed.cbegin(); + const auto cit2 = range_constructed.cend(); + assert(cit2 - cit1 == ssize(input)); + + assert(it2 - cit1 == ssize(input)); + assert(cit2 - it1 == ssize(input)); + } + + { // comparison + const auto it1 = range_constructed.begin(); + const auto it2 = range_constructed.begin(); + const auto it3 = range_constructed.end(); + + assert(it1 == it2); + assert(it1 != it3); + assert(it1 < it3); + assert(it1 <= it3); + assert(it3 > it1); + assert(it3 >= it1); + } + + { // access + const auto it = range_constructed.begin() + 2; + it[2] = false; + assert(range_constructed[4] == false); + + const auto cit = range_constructed.cbegin() + 2; + assert(cit[2] == false); + + std::vector> vec2 = {{false, true}, {true, false}}; + const auto it2 = vec2.begin(); + assert(it2->second); + + const auto cit2 = vec2.cbegin(); + assert(cit2->first == false); + } + + return true; +} + +int main() { + test_interface(); + test_iterators(); +#ifdef __cpp_lib_constexpr_vector + static_assert(test_interface()); + static_assert(test_iterators()); +#endif // __cpp_lib_constexpr_vector +}