From fa1b742463a19196af63491999f61926a2795d78 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 5 Sep 2020 12:22:34 +0200 Subject: [PATCH 01/15] Optimize fill with zero --- stl/inc/algorithm | 27 ++++++++++--- stl/inc/memory | 21 ++++++++++ stl/inc/xmemory | 12 ++++++ stl/inc/xutility | 40 ++++++++++++++++--- .../tests/P0896R4_ranges_alg_fill/test.cpp | 8 ++++ .../tests/P0896R4_ranges_alg_fill_n/test.cpp | 8 ++++ 6 files changed, 104 insertions(+), 12 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 9e0d2458f7d..9cf359a5541 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3938,16 +3938,24 @@ namespace ranges { _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); - if constexpr (_Fill_memset_is_safe) { #ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated - { + { + if constexpr (_Fill_memset_is_safe) { const auto _Distance = static_cast(_ULast - _UFirst); _Fill_memset(_UFirst, _Value, _Distance); _UFirst += _Distance; _Seek_wrapped(_First, _UFirst); return _First; + } else if constexpr (_Fill_zero_memset_is_safe) { + if (_Is_scalar_zero(_Value)) { + const auto _Distance = static_cast(_ULast - _UFirst); + _Fill_zero_memset(_UFirst, _Distance); + _UFirst += _Distance; + _Seek_wrapped(_First, _UFirst); + return _First; + } } } @@ -3978,15 +3986,22 @@ namespace ranges { constexpr _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Value) const { if (_Count > 0) { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - if constexpr (_Fill_memset_is_safe) { #ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated - { + { + if constexpr (_Fill_memset_is_safe) { _Fill_memset(_UFirst, _Value, static_cast(_Count)); _UFirst += _Count; _Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer return _First; + } else if constexpr (_Fill_zero_memset_is_safe) { + if (_Is_scalar_zero(_Value)) { + _Fill_zero_memset(_UFirst, static_cast(_Count)); + _UFirst += _Count; + _Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer + return _First; + } } } diff --git a/stl/inc/memory b/stl/inc/memory index 42ad7303c0e..efd514013ea 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -236,6 +236,14 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, _Fill_memset(_UFirst, _Val, _Count); _UFirst += _Count; } else { + if constexpr (_Fill_zero_memset_is_safe) { + if (_Is_scalar_zero(_Val)) { + _Fill_zero_memset(_UFirst, _Count); + _UFirst += _Count; + _Seek_wrapped(_First, _UFirst); + return _First; + } + } _Uninitialized_backout<_Unwrapped_n_t> _Backout{_UFirst}; for (; 0 < _Count; --_Count) { _Backout._Emplace_back(_Val); @@ -1754,6 +1762,12 @@ void _Uninitialized_fill_multidimensional_n(_Ty* const _Out, const size_t _Size, } else if constexpr (_Fill_memset_is_safe<_Ty*, _Ty>) { _Fill_memset(_Out, _Val, _Size); } else { + if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty>) { + if (_Is_scalar_zero(_Val)) { + _Fill_zero_memset(_Out, _Size); + return; + } + } _Uninitialized_rev_destroying_backout _Backout{_Out}; for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Backout._Emplace_back(_Val); @@ -2077,6 +2091,13 @@ void _Uninitialized_fill_multidimensional_n_al(_Ty* const _Out, const size_t _Si } else if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) { _Fill_memset(_Out, _Val, _Size); } else { + if constexpr (_Fill_zero_memset_is_safe<_Ty*, + _Ty> && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) { + if (_Is_scalar_zero(_Val)) { + _Fill_zero_memset(_Out, _Size); + return; + } + } _Uninitialized_rev_destroying_backout_al _Backout{_Out, _Al}; for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Backout._Emplace_back(_Val); diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 0a375c4f177..8b055f76e85 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1754,6 +1754,12 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( _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) { + if (_Is_scalar_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); @@ -1804,6 +1810,12 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c if constexpr (_Fill_memset_is_safe<_Unwrapped_t, _Tval>) { _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); } else { + if constexpr (_Fill_zero_memset_is_safe<_Unwrapped_t, _Tval>) { + if (_Is_scalar_zero(_Val)) { + _Fill_zero_memset(_UFirst, static_cast(_ULast - _UFirst)); + return; + } + } _Uninitialized_backout<_Unwrapped_t> _Backout{_UFirst}; while (_Backout._Last != _ULast) { _Backout._Emplace_back(_Val); diff --git a/stl/inc/xutility b/stl/inc/xutility index f35a2ace52c..9ebe929593a 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4787,12 +4787,28 @@ _INLINE_VAR constexpr bool _Fill_memset_is_safe = conjunction_v, template _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; +template +_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe = + conjunction_v, is_scalar<_Ty>, is_scalar<_Iter_value_t<_FwdIt>>, + negation>>>, is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; + template void _Fill_memset(_DestTy* const _Dest, const _Ty _Val, const size_t _Count) { _DestTy _Dest_val = _Val; // implicitly convert (a cast would suppress warnings); also handles _DestTy being bool _CSTD memset(_Dest, static_cast(_Dest_val), _Count); } +template +void _Fill_zero_memset(_DestTy* const _Dest, const size_t _Count) { + _CSTD memset(_Dest, 0, _Count * sizeof(_DestTy)); +} + +template +bool _Is_scalar_zero(const _Ty& _Val) { + // checks if scalar type has all bits set to zero, avoids using user defined operator== for enums + return static_cast<_Unwrap_enum_t<_Ty>>(_Val) == static_cast<_Unwrap_enum_t<_Ty>>(0); +} + #if _HAS_IF_CONSTEXPR template _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { @@ -4803,13 +4819,18 @@ _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) } else { auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Fill_memset_is_safe) { #ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated - { + { + if constexpr (_Fill_memset_is_safe) { _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); return; + } else if constexpr (_Fill_zero_memset_is_safe) { + if (_Is_scalar_zero(_Val)) { + _Fill_zero_memset(_UFirst, static_cast(_ULast - _UFirst)); + return; + } } } @@ -4864,15 +4885,22 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val return _Last; } else { auto _UDest = _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Fill_memset_is_safe) { #ifdef __cpp_lib_is_constant_evaluated - if (!_STD is_constant_evaluated()) + if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated - { + { + if constexpr (_Fill_memset_is_safe) { _Fill_memset(_UDest, _Val, static_cast(_Count)); _UDest += _Count; _Seek_wrapped(_Dest, _UDest); return _Dest; + } else if constexpr (_Fill_zero_memset_is_safe) { + if (_Is_scalar_zero(_Val)) { + _Fill_zero_memset(_UDest, static_cast(_Count)); + _UDest += _Count; + _Seek_wrapped(_Dest, _UDest); + return _Dest; + } } } diff --git a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp index 0bea140c685..2deecbc3eef 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp @@ -38,6 +38,14 @@ struct instantiator { assert(elem == true); } } + { // Validate zero-ing + int output[] = {13, 42, 1367}; + auto result = fill(output, 0); + for (const auto& elem : output) { + assert(elem == 0); + } + assert(result == ranges::end(output)); + } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp index 622794b11c3..4799a43f149 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp @@ -43,6 +43,14 @@ struct instantiator { assert(elem == true); } } + { // Validate zero-ing + int output[] = {13, 42, 1367}; + auto result = fill_n(ranges::begin(output), ranges::distance(output), 0); + for (const auto& elem : output) { + assert(elem == 0); + } + assert(result == ranges::end(output)); + } } }; From a2589ff36f3e9cc357a75762733b5f756ee24ac5 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 5 Sep 2020 12:47:27 +0200 Subject: [PATCH 02/15] Disable for member pointers --- stl/inc/xutility | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 9ebe929593a..9d06e6e04c1 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4788,9 +4788,9 @@ template _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; template -_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe = - conjunction_v, is_scalar<_Ty>, is_scalar<_Iter_value_t<_FwdIt>>, - negation>>>, is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; +_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe = conjunction_v, is_scalar<_Ty>, + is_scalar<_Iter_value_t<_FwdIt>>, negation>>, + negation>>>, is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; template void _Fill_memset(_DestTy* const _Dest, const _Ty _Val, const size_t _Count) { From 069c9db88a9b03b404f9b190845710e99477fafb Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 5 Sep 2020 13:16:54 +0200 Subject: [PATCH 03/15] static_cast --- stl/inc/memory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index efd514013ea..3490da5d132 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -233,12 +233,12 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, if (0 < _Count) { auto _UFirst = _Get_unwrapped_n(_First, _Count); if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t, _Tval>) { - _Fill_memset(_UFirst, _Val, _Count); + _Fill_memset(_UFirst, _Val, static_cast(_Count)); _UFirst += _Count; } else { if constexpr (_Fill_zero_memset_is_safe) { if (_Is_scalar_zero(_Val)) { - _Fill_zero_memset(_UFirst, _Count); + _Fill_zero_memset(_UFirst, static_cast(_Count)); _UFirst += _Count; _Seek_wrapped(_First, _UFirst); return _First; From 5a56eedf4816f3ee4c8fc37309ef1afc1be187b6 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 5 Sep 2020 13:27:09 +0200 Subject: [PATCH 04/15] Fix test fail --- stl/inc/xutility | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 9d06e6e04c1..f130f29b119 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4787,10 +4787,13 @@ _INLINE_VAR constexpr bool _Fill_memset_is_safe = conjunction_v, template _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; +template > +_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe = + conjunction_v, is_scalar<_Iter_value_t<_FwdIt>>, negation>>, + negation>>>, is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; + template -_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe = conjunction_v, is_scalar<_Ty>, - is_scalar<_Iter_value_t<_FwdIt>>, negation>>, - negation>>>, is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; +_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe<_FwdIt, _Ty, false> = false; template void _Fill_memset(_DestTy* const _Dest, const _Ty _Val, const size_t _Count) { From 1be0d93ad20c91e969f35fb65734c48e048dc6b8 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 23 Sep 2020 17:34:48 +0200 Subject: [PATCH 05/15] ranges::uninitialized_fill(_n) --- stl/inc/algorithm | 12 ++---- stl/inc/memory | 24 ++++++++--- stl/inc/xutility | 6 +-- .../tests/P0896R4_ranges_alg_fill/test.cpp | 2 +- .../test.cpp | 17 ++++++++ .../test.cpp | 41 ++++++++++++++----- 6 files changed, 73 insertions(+), 29 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 9cf359a5541..bd61610929d 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3945,15 +3945,13 @@ namespace ranges { if constexpr (_Fill_memset_is_safe) { const auto _Distance = static_cast(_ULast - _UFirst); _Fill_memset(_UFirst, _Value, _Distance); - _UFirst += _Distance; - _Seek_wrapped(_First, _UFirst); + _Seek_wrapped(_First, _UFirst + _Distance); return _First; } else if constexpr (_Fill_zero_memset_is_safe) { if (_Is_scalar_zero(_Value)) { const auto _Distance = static_cast(_ULast - _UFirst); _Fill_zero_memset(_UFirst, _Distance); - _UFirst += _Distance; - _Seek_wrapped(_First, _UFirst); + _Seek_wrapped(_First, _UFirst + _Distance); return _First; } } @@ -3992,14 +3990,12 @@ namespace ranges { { if constexpr (_Fill_memset_is_safe) { _Fill_memset(_UFirst, _Value, static_cast(_Count)); - _UFirst += _Count; - _Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer + _Seek_wrapped(_First, _UFirst + _Count); // no need to move since _UFirst is a pointer return _First; } else if constexpr (_Fill_zero_memset_is_safe) { if (_Is_scalar_zero(_Value)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); - _UFirst += _Count; - _Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer + _Seek_wrapped(_First, _UFirst + _Count); // no need to move since _UFirst is a pointer return _First; } } diff --git a/stl/inc/memory b/stl/inc/memory index 8ada38806c0..521453f48d9 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -428,10 +428,17 @@ namespace ranges { if constexpr (_Fill_memset_is_safe<_It, _Ty>) { const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); - const auto _Diff = static_cast(_OFinal - _OFirst); - _Fill_memset(_OFirst, _Val, _Diff); + _Fill_memset(_OFirst, _Val, static_cast(_OFinal - _OFirst)); return _OFinal; } else { + if constexpr (_Fill_zero_memset_is_safe<_It, _Ty>) { + if (_Is_scalar_zero(_Val)) { + const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); + _Fill_zero_memset(_OFirst, static_cast(_OFinal - _OFirst)); + return _OFinal; + } + } + _Uninitialized_backout _Backout{_STD move(_OFirst)}; while (_Backout._Last != _OLast) { @@ -465,8 +472,7 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, if constexpr (_Fill_zero_memset_is_safe) { if (_Is_scalar_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); - _UFirst += _Count; - _Seek_wrapped(_First, _UFirst); + _Seek_wrapped(_First, _UFirst + _Count); return _First; } } @@ -536,10 +542,18 @@ namespace ranges { } auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - if constexpr (_Fill_memset_is_safe<_It, _Ty>) { + if constexpr (_Fill_memset_is_safe) { _Fill_memset(_UFirst, _Val, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); } else { + if constexpr (_Fill_zero_memset_is_safe) { + if (_Is_scalar_zero(_Val)) { + _Fill_zero_memset(_UFirst, static_cast(_Count)); + _Seek_wrapped(_First, _UFirst + _Count); + return _First; + } + } + _Uninitialized_backout _Backout{_STD move(_UFirst)}; for (; _Count > 0; --_Count) { diff --git a/stl/inc/xutility b/stl/inc/xutility index 036d8022ec7..d914bb2f786 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4912,14 +4912,12 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val { if constexpr (_Fill_memset_is_safe) { _Fill_memset(_UDest, _Val, static_cast(_Count)); - _UDest += _Count; - _Seek_wrapped(_Dest, _UDest); + _Seek_wrapped(_Dest, _UDest + _Count); return _Dest; } else if constexpr (_Fill_zero_memset_is_safe) { if (_Is_scalar_zero(_Val)) { _Fill_zero_memset(_UDest, static_cast(_Count)); - _UDest += _Count; - _Seek_wrapped(_Dest, _UDest); + _Seek_wrapped(_Dest, _UDest + _Count); return _Dest; } } diff --git a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp index 2deecbc3eef..ca8ebd049fb 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp @@ -33,7 +33,7 @@ struct instantiator { } { // Validate int is properly converted to bool bool output[] = {false, true, false}; - fill(ranges::begin(output), ranges::end(output), 5); + fill(output, 5); for (const bool& elem : output) { assert(elem == true); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp index 1defdd193d2..387b0c9b752 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp @@ -100,6 +100,23 @@ struct instantiator { assert(int_wrapper::constructions == 3); assert(int_wrapper::destructions == 3); } + + { // Validate int is properly converted to bool + bool output[] = {false, true, false}; + uninitialized_fill(output, 5); + for (const bool& elem : output) { + assert(elem == true); + } + } + + { // Validate zero-ing + int output[] = {13, 42, 1367}; + auto result = uninitialized_fill(output, 0); + for (const auto& elem : output) { + assert(elem == 0); + } + assert(result == ranges::end(output)); + } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp index 97da0b88fd1..4d0be9f186c 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp @@ -66,18 +66,37 @@ struct instantiator { static void call() { using ranges::uninitialized_fill_n, ranges::equal, ranges::equal_to, ranges::iterator_t; - holder mem; - Write wrapped_input{mem.as_span()}; + { + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_fill_n(wrapped_input.begin(), 3, 42); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } - int_wrapper::clear_counts(); - const same_as> auto result = uninitialized_fill_n(wrapped_input.begin(), 3, 42); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); - assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); - not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + { // Validate int is properly converted to bool + bool output[] = {false, true, false}; + uninitialized_fill_n(ranges::begin(output), ranges::distance(output), 5); + for (const bool& elem : output) { + assert(elem == true); + } + } + + { // Validate zero-ing + int output[] = {13, 42, 1367}; + auto result = uninitialized_fill_n(ranges::begin(output), ranges::distance(output), 0); + for (const auto& elem : output) { + assert(elem == 0); + } + assert(result == ranges::end(output)); + } } }; From b57d91b51fe7db09dd4ae995ac9694b5383ebbc9 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 23 Sep 2020 17:40:18 +0200 Subject: [PATCH 06/15] clang-format --- tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp index 387b0c9b752..2c7801a5348 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp @@ -100,7 +100,7 @@ struct instantiator { assert(int_wrapper::constructions == 3); assert(int_wrapper::destructions == 3); } - + { // Validate int is properly converted to bool bool output[] = {false, true, false}; uninitialized_fill(output, 5); From 4b0f4cda440581567d80c7d61bd6e0ccd54a3835 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 10:03:49 +0200 Subject: [PATCH 07/15] static_assert is_scalar Co-authored-by: Casey Carter --- stl/inc/xutility | 1 + 1 file changed, 1 insertion(+) diff --git a/stl/inc/xutility b/stl/inc/xutility index d914bb2f786..d7483ba755e 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4827,6 +4827,7 @@ void _Fill_zero_memset(_DestTy* const _Dest, const size_t _Count) { template bool _Is_scalar_zero(const _Ty& _Val) { // checks if scalar type has all bits set to zero, avoids using user defined operator== for enums + _STL_INTERNAL_STATIC_ASSERT(is_scalar_v<_Ty>); return static_cast<_Unwrap_enum_t<_Ty>>(_Val) == static_cast<_Unwrap_enum_t<_Ty>>(0); } From 1c75cef9cf7189c768dcd156ab81e129a18bf63f Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 11:06:11 +0200 Subject: [PATCH 08/15] is_constant_evaluated is always available in c++20 mode --- stl/inc/algorithm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index bd61610929d..611f726f2dc 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3938,9 +3938,7 @@ namespace ranges { _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); -#ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated { if constexpr (_Fill_memset_is_safe) { const auto _Distance = static_cast(_ULast - _UFirst); @@ -3984,9 +3982,7 @@ namespace ranges { constexpr _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Value) const { if (_Count > 0) { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); -#ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated { if constexpr (_Fill_memset_is_safe) { _Fill_memset(_UFirst, _Value, static_cast(_Count)); From a9698548fd1576560401e91368b0c35c6bc3fc3c Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Thu, 24 Sep 2020 11:25:39 +0200 Subject: [PATCH 09/15] clang-format --- stl/inc/algorithm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 611f726f2dc..a4dc7633789 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3938,8 +3938,7 @@ namespace ranges { _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); - if (!_STD is_constant_evaluated()) - { + if (!_STD is_constant_evaluated()) { if constexpr (_Fill_memset_is_safe) { const auto _Distance = static_cast(_ULast - _UFirst); _Fill_memset(_UFirst, _Value, _Distance); @@ -3982,8 +3981,7 @@ namespace ranges { constexpr _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Value) const { if (_Count > 0) { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - if (!_STD is_constant_evaluated()) - { + if (!_STD is_constant_evaluated()) { if constexpr (_Fill_memset_is_safe) { _Fill_memset(_UFirst, _Value, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); // no need to move since _UFirst is a pointer From 30a272a642a2cc43f831b8888f4a3417b82edacd Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 29 Sep 2020 21:07:12 +0200 Subject: [PATCH 10/15] More tests --- .../P0674R1_make_shared_for_arrays/test.cpp | 22 +++++++++++++++++++ .../tests/VSO_0180469_fill_family/test.cpp | 9 ++++++++ 2 files changed, 31 insertions(+) diff --git a/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp b/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp index 3a3304571c7..c4936f19085 100644 --- a/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp +++ b/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp @@ -221,6 +221,11 @@ void test_make_shared_array_known_bounds() { test_make_init_destruct_order(); // success multidimensional test_make_init_destruct_order(); // failure multidimensional + + shared_ptr p7 = make_shared(0); + for (int i = 0; i < 7; ++i) { + assert(p7[i] == 0); + } } void test_make_shared_array_unknown_bounds() { @@ -286,6 +291,11 @@ void test_make_shared_array_unknown_bounds() { test_make_init_destruct_order(2u); // success multidimensional test_make_init_destruct_order(3u); // failure multidimensional + + shared_ptr p8 = make_shared(7u, 0); + for (int i = 0; i < 7; ++i) { + assert(p8[i] == 0); + } } int constructCount = 0; @@ -506,6 +516,12 @@ void test_allocate_shared_array_known_bounds() { test_allocate_init_destruct_order(); // success multidimensional test_allocate_init_destruct_order(); // failure multidimensional + + allocator a7; + shared_ptr p7 = allocate_shared(a7, 0); + for (int i = 0; i < 7; ++i) { + assert(p7[i] == 0); + } } void test_allocate_shared_array_unknown_bounds() { @@ -599,6 +615,12 @@ void test_allocate_shared_array_unknown_bounds() { test_allocate_init_destruct_order(2u); // success multidimensional test_allocate_init_destruct_order(3u); // failure multidimensional + + allocator a8; + shared_ptr p8 = allocate_shared(a8, 0); + for (int i = 0; i < 7; ++i) { + assert(p8[i] == 0); + } } int main() { diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 2ec62a9404f..efece7e2497 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -14,6 +14,7 @@ #include #include #include +#include using namespace std; @@ -168,4 +169,12 @@ int main() { assert(elem == true); } } + + // Test (indirectly) _Uninitialized_fill_n with zero + { + vector vec(43, nullptr); + for (void* p : vec) { + assert(p == nullptr); + } + } } From 599542e534ef5ff9374200a5fc7aa3e52fafaa19 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 28 Oct 2020 09:01:03 +0100 Subject: [PATCH 11/15] Apply suggestions from code review Co-authored-by: Stephan T. Lavavej --- stl/inc/xutility | 2 +- tests/std/tests/VSO_0180469_fill_family/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index d7483ba755e..df8b86024b3 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4825,7 +4825,7 @@ void _Fill_zero_memset(_DestTy* const _Dest, const size_t _Count) { } template -bool _Is_scalar_zero(const _Ty& _Val) { +_NODISCARD bool _Is_scalar_zero(const _Ty& _Val) { // checks if scalar type has all bits set to zero, avoids using user defined operator== for enums _STL_INTERNAL_STATIC_ASSERT(is_scalar_v<_Ty>); return static_cast<_Unwrap_enum_t<_Ty>>(_Val) == static_cast<_Unwrap_enum_t<_Ty>>(0); diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index efece7e2497..827c2debead 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -173,7 +173,7 @@ int main() { // Test (indirectly) _Uninitialized_fill_n with zero { vector vec(43, nullptr); - for (void* p : vec) { + for (const auto& p : vec) { assert(p == nullptr); } } From 0048d222d3c76aef8d54e671f1171cce1575b336 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 28 Oct 2020 09:39:53 +0100 Subject: [PATCH 12/15] Code review --- stl/inc/algorithm | 4 ++-- stl/inc/memory | 14 +++++++------- stl/inc/xmemory | 4 ++-- stl/inc/xutility | 17 +++++++---------- .../P0896R4_ranges_iterator_machinery/test.cpp | 1 - .../std/tests/VSO_0180469_fill_family/test.cpp | 9 +++++++++ 6 files changed, 27 insertions(+), 22 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index a4dc7633789..c0ff38e069c 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3945,7 +3945,7 @@ namespace ranges { _Seek_wrapped(_First, _UFirst + _Distance); return _First; } else if constexpr (_Fill_zero_memset_is_safe) { - if (_Is_scalar_zero(_Value)) { + if (_Is_all_bits_zero(_Value)) { const auto _Distance = static_cast(_ULast - _UFirst); _Fill_zero_memset(_UFirst, _Distance); _Seek_wrapped(_First, _UFirst + _Distance); @@ -3987,7 +3987,7 @@ namespace ranges { _Seek_wrapped(_First, _UFirst + _Count); // no need to move since _UFirst is a pointer return _First; } else if constexpr (_Fill_zero_memset_is_safe) { - if (_Is_scalar_zero(_Value)) { + if (_Is_all_bits_zero(_Value)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); // no need to move since _UFirst is a pointer return _First; diff --git a/stl/inc/memory b/stl/inc/memory index 521453f48d9..b9f2663602f 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -432,7 +432,7 @@ namespace ranges { return _OFinal; } else { if constexpr (_Fill_zero_memset_is_safe<_It, _Ty>) { - if (_Is_scalar_zero(_Val)) { + if (_Is_all_bits_zero(_Val)) { const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); _Fill_zero_memset(_OFirst, static_cast(_OFinal - _OFirst)); return _OFinal; @@ -465,19 +465,19 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, } auto _UFirst = _Get_unwrapped_n(_First, _Count); - if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t, _Tval>) { + if constexpr (_Fill_memset_is_safe) { _Fill_memset(_UFirst, _Val, static_cast(_Count)); _UFirst += _Count; } else { if constexpr (_Fill_zero_memset_is_safe) { - if (_Is_scalar_zero(_Val)) { + if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); return _First; } } - _Uninitialized_backout<_Unwrapped_n_t> _Backout{_UFirst}; + _Uninitialized_backout _Backout{_UFirst}; for (; _Count > 0; --_Count) { _Backout._Emplace_back(_Val); @@ -547,7 +547,7 @@ namespace ranges { _Seek_wrapped(_First, _UFirst + _Count); } else { if constexpr (_Fill_zero_memset_is_safe) { - if (_Is_scalar_zero(_Val)) { + if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); return _First; @@ -2386,7 +2386,7 @@ void _Uninitialized_fill_multidimensional_n(_Ty* const _Out, const size_t _Size, _Fill_memset(_Out, _Val, _Size); } else { if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty>) { - if (_Is_scalar_zero(_Val)) { + if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_Out, _Size); return; } @@ -2716,7 +2716,7 @@ void _Uninitialized_fill_multidimensional_n_al(_Ty* const _Out, const size_t _Si } else { if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) { - if (_Is_scalar_zero(_Val)) { + if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_Out, _Size); return; } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index e98f51ff2dd..1b4bdd9142b 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1747,7 +1747,7 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( return _First + _Count; } else { if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { - if (_Is_scalar_zero(_Val)) { + if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_Unfancy(_First), static_cast(_Count)); return _First + _Count; } @@ -1803,7 +1803,7 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); } else { if constexpr (_Fill_zero_memset_is_safe<_Unwrapped_t, _Tval>) { - if (_Is_scalar_zero(_Val)) { + if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_ULast - _UFirst)); return; } diff --git a/stl/inc/xutility b/stl/inc/xutility index df8b86024b3..926b0951b3c 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1477,10 +1477,6 @@ _NODISCARD constexpr _Ty* _Get_unwrapped_n(_Ty* const _Src, _Diff) { } #endif // _HAS_IF_CONSTEXPR -template -using _Unwrapped_n_t = - _Remove_cvref_t(), _Iter_diff_t<_Remove_cvref_t<_Iter>>{}))>; - // FUNCTION TEMPLATE _Seek_wrapped template _INLINE_VAR constexpr bool _Wrapped_seekable_v = false; @@ -4825,10 +4821,11 @@ void _Fill_zero_memset(_DestTy* const _Dest, const size_t _Count) { } template -_NODISCARD bool _Is_scalar_zero(const _Ty& _Val) { - // checks if scalar type has all bits set to zero, avoids using user defined operator== for enums - _STL_INTERNAL_STATIC_ASSERT(is_scalar_v<_Ty>); - return static_cast<_Unwrap_enum_t<_Ty>>(_Val) == static_cast<_Unwrap_enum_t<_Ty>>(0); +_NODISCARD bool _Is_all_bits_zero(const _Ty& _Val) { + // checks if scalar type has all bits set to zero + _STL_INTERNAL_STATIC_ASSERT(is_scalar_v<_Ty> && !is_member_pointer_v<_Ty>); + constexpr _Ty _Zero = static_cast<_Ty>(0); + return _CSTD memcmp(&_Val, &_Zero, sizeof(_Ty)) == 0; } #if _HAS_IF_CONSTEXPR @@ -4849,7 +4846,7 @@ _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); return; } else if constexpr (_Fill_zero_memset_is_safe) { - if (_Is_scalar_zero(_Val)) { + if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UFirst, static_cast(_ULast - _UFirst)); return; } @@ -4916,7 +4913,7 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val _Seek_wrapped(_Dest, _UDest + _Count); return _Dest; } else if constexpr (_Fill_zero_memset_is_safe) { - if (_Is_scalar_zero(_Val)) { + if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_UDest, static_cast(_Count)); _Seek_wrapped(_Dest, _UDest + _Count); return _Dest; diff --git a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp index f748c811daf..c6d2f5b9bee 100644 --- a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp @@ -1846,7 +1846,6 @@ namespace unwrap_move_only { STATIC_ASSERT(!std::_Unwrappable_for_offset_v const&>); STATIC_ASSERT(std::_Unwrappable_for_offset_v>); STATIC_ASSERT(!std::_Unwrappable_for_offset_v const>); - STATIC_ASSERT(std::same_as>, iter>); STATIC_ASSERT(!std::_Wrapped_seekable_v, iter&>); STATIC_ASSERT(!std::_Wrapped_seekable_v, iter const&>); diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 827c2debead..155bf5cb73d 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -170,6 +170,15 @@ int main() { } } + // Test floating-point negative zero + { + float output[] = {1.0f, 2.0f, 3.0f}; + fill(output, output + 3, -0.0f); + for (const float& elem : output) { + assert(_Bit_cast(elem) == _Bit_cast(-0.0f)); + } + } + // Test (indirectly) _Uninitialized_fill_n with zero { vector vec(43, nullptr); From 3a937b33b1ca12da7e1551ce588a47fefe994921 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Oct 2020 16:31:53 -0700 Subject: [PATCH 13/15] Avoid Clang's -Wzero-as-null-pointer-constant warning. `static_cast<_Ty>(0)` emits this warning for object pointers, function pointers, and `nullptr_t`. We can avoid this warning by using empty braces to request zero-initialization. --- stl/inc/xutility | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 926b0951b3c..ec27f849066 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4824,7 +4824,7 @@ template _NODISCARD bool _Is_all_bits_zero(const _Ty& _Val) { // checks if scalar type has all bits set to zero _STL_INTERNAL_STATIC_ASSERT(is_scalar_v<_Ty> && !is_member_pointer_v<_Ty>); - constexpr _Ty _Zero = static_cast<_Ty>(0); + constexpr _Ty _Zero{}; return _CSTD memcmp(&_Val, &_Zero, sizeof(_Ty)) == 0; } From 2866b64b582130e914352007bd3ec32ce48a2b02 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Oct 2020 16:42:25 -0700 Subject: [PATCH 14/15] Portably test for negative zero. --- tests/std/tests/VSO_0180469_fill_family/test.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 155bf5cb73d..c932d75f092 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -10,6 +10,7 @@ // calls std::fill and std::uninitialized_fill with (signed*, signed*, unsigned) #include #include +#include #include #include #include @@ -175,7 +176,8 @@ int main() { float output[] = {1.0f, 2.0f, 3.0f}; fill(output, output + 3, -0.0f); for (const float& elem : output) { - assert(_Bit_cast(elem) == _Bit_cast(-0.0f)); + assert(elem == 0.0f); // elem is positive or negative zero + assert(signbit(elem)); // elem is negative } } From 3d21ed44659b0be44cb46d69263b5156abc569c2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 28 Oct 2020 16:47:59 -0700 Subject: [PATCH 15/15] Test `allocate_shared`. --- tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp b/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp index c4936f19085..0a9082fe926 100644 --- a/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp +++ b/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp @@ -617,7 +617,7 @@ void test_allocate_shared_array_unknown_bounds() { test_allocate_init_destruct_order(3u); // failure multidimensional allocator a8; - shared_ptr p8 = allocate_shared(a8, 0); + shared_ptr p8 = allocate_shared(a8, 7u, 0); for (int i = 0; i < 7; ++i) { assert(p8[i] == 0); }