From d12c8b09bf7fe5719ac05e408fe6315145c2f1cc Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Sat, 8 Aug 2020 14:12:35 +0200 Subject: [PATCH 01/23] Implement several specialized memory range algorithms: * `ranges::uninitialized_default_construct`, `ranges::uninitialized_default_construct_n` * `ranges::uninitialized_value_construct`, `ranges::uninitialized_value_construct_n` * `ranges::uninitialized_fill`, `ranges::uninitialized_fill_n` * `ranges::uninitialized_copy`, `ranges::uninitialized_copy_n` * `ranges::uninitialized_move_n` --- stl/inc/memory | 533 +++++++++++++++++- tests/std/test.lst | 9 + .../env.lst | 4 + .../test.cpp | 180 ++++++ .../env.lst | 4 + .../test.cpp | 148 +++++ .../env.lst | 4 + .../test.cpp | 128 +++++ .../env.lst | 4 + .../test.cpp | 109 ++++ .../env.lst | 4 + .../test.cpp | 135 +++++ .../env.lst | 4 + .../test.cpp | 115 ++++ .../env.lst | 4 + .../test.cpp | 150 +++++ .../env.lst | 4 + .../test.cpp | 132 +++++ .../env.lst | 4 + .../test.cpp | 112 ++++ 20 files changed, 1775 insertions(+), 12 deletions(-) create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp diff --git a/stl/inc/memory b/stl/inc/memory index 69eed6da175..db01ad24621 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -56,6 +56,72 @@ namespace ranges { concept _No_throw_forward_range = _No_throw_input_range<_Rng> && _No_throw_forward_iterator>; // clang-format on + + // ALIAS TEMPLATE uninitialized_copy_result + template + using uninitialized_copy_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::uninitialized_copy + class _Uninitialized_copy_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se1, _No_throw_forward_iterator _Out, + _No_throw_sentinel_for<_Out> _Se2> + requires constructible_from, iter_reference_t<_It>> + uninitialized_copy_result<_It, _Out> operator()(_It _First1, _Se1 _Last1, _Out _First2, _Se2 _Last2) const { + // clang-format on + _Adl_verify_range(_First1, _Last1); + _Adl_verify_range(_First2, _Last2); + auto _UResult = + _Uninitialized_copy_unchecked(_Get_unwrapped(_STD move(_First1)), _Get_unwrapped(_STD move(_Last1)), + _Get_unwrapped(_STD move(_First2)), _Get_unwrapped(_STD move(_Last2))); + + _Seek_wrapped(_First1, _STD move(_UResult.in)); + _Seek_wrapped(_First2, _STD move(_UResult.out)); + return {_STD move(_First1), _STD move(_First2)}; + } + + // clang-format off + template + requires constructible_from, range_reference_t<_Rng1>> + uninitialized_copy_result, borrowed_iterator_t<_Rng2>> operator()( + _Rng1&& _Range1, _Rng2&& _Range2) const { + // clang-format on + auto _First1 = _RANGES begin(_Range1); + auto _UResult = _Uninitialized_copy_unchecked( + _Get_unwrapped(_STD move(_First1)), _Uend(_Range1), _Ubegin(_Range2), _Uend(_Range2)); + + _Seek_wrapped(_First1, _STD move(_UResult.in)); + return {_STD move(_First1), _Rewrap_iterator(_Range2, _STD move(_UResult.out))}; + } + + private: + template + _NODISCARD static uninitialized_copy_result<_It, _Out> _Uninitialized_copy_unchecked( + _It _IFirst, const _Se1 _ILast, _Out _OFirst, const _Se2 _OLast) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_Out>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se2, _Out>); + _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_reference_t<_It>>); + + if constexpr (is_same_v<_Se1, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { + return _Copy_memmove(_IFirst, _ILast, _OFirst); + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { + _Backout._Emplace_back(*_IFirst); + } + + return {_STD move(_IFirst), _Backout._Release()}; + } + } + }; + + inline constexpr _Uninitialized_copy_fn uninitialized_copy{_Not_quite_object::_Construct_tag{}}; } // namespace ranges #endif // __cpp_lib_concepts @@ -117,6 +183,53 @@ _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _ } #endif // _HAS_IF_CONSTEXPR +#ifdef __cpp_lib_concepts +namespace ranges { + // ALIAS TEMPLATE uninitialized_copy_n_result + template + using uninitialized_copy_n_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::uninitialized_copy_n + class _Uninitialized_copy_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se2> + requires constructible_from, iter_reference_t<_It>> + uninitialized_copy_n_result<_It, _Out> operator()( + _It _First1, const iter_difference_t<_It> _Count_raw, _Out _First2, _Se2) const { + // clang-format on + _Algorithm_int_t> _Count = _Count_raw; + if (_Count > 0) { + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped_n(_STD move(_First2), _Count); + if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) { + _OFirst = _Copy_memmove(_IFirst, _IFirst + _Count, _OFirst); + } else if constexpr (is_nothrow_constructible_v, const iter_value_t<_Out>&>) { + for (; 0 < _Count; --_Count, (void) ++_IFirst, ++_OFirst) { + *_OFirst = *_IFirst; + } + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + for (; 0 < _Count; --_Count, (void) ++_IFirst) { + _Backout._Emplace_back(*_IFirst); + } + + _OFirst = _STD move(_Backout._Release()); + } + + _Seek_wrapped(_First1, _IFirst); + _Seek_wrapped(_First2, _OFirst); + } + return {_STD move(_First1), _STD move(_First2)}; + } + }; + + inline constexpr _Uninitialized_copy_n_fn uninitialized_copy_n{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + #if _HAS_CXX17 // FUNCTION TEMPLATE uninitialized_move template @@ -142,10 +255,10 @@ namespace ranges { using _Not_quite_object::_Not_quite_object; // clang-format off - template _Se1, _No_throw_forward_iterator _It2, - _No_throw_sentinel_for<_It2> _Se2> - requires constructible_from, iter_rvalue_reference_t<_It1>> - uninitialized_move_result<_It1, _It2> operator()(_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2) const { + template _Se1, _No_throw_forward_iterator _Out, + _No_throw_sentinel_for<_Out> _Se2> + requires constructible_from, iter_rvalue_reference_t<_It>> + uninitialized_move_result<_It, _Out> operator()(_It _First1, _Se1 _Last1, _Out _First2, _Se2 _Last2) const { // clang-format on _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -173,14 +286,14 @@ namespace ranges { } private: - template - _NODISCARD static uninitialized_move_result<_It1, _It2> _Uninitialized_move_unchecked( - _It1 _IFirst, const _Se1 _ILast, _It2 _OFirst, const _Se2 _OLast) { - _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It1>); - _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It1>); - _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It2>); - _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se2, _It2>); - _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It1>>); + template + _NODISCARD static uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( + _It _IFirst, const _Se1 _ILast, _Out _OFirst, const _Se2 _OLast) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_Out>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se2, _Out>); + _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It>>); _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -224,6 +337,118 @@ pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count } #endif // _HAS_CXX17 + +#ifdef __cpp_lib_concepts +namespace ranges { + // ALIAS TEMPLATE uninitialized_move_n_result + template + using uninitialized_move_n_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::uninitialized_move_n + class _Uninitialized_move_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se> + requires constructible_from, iter_rvalue_reference_t<_It>> + uninitialized_move_n_result<_It, _Out> operator()( + _It _First1, const iter_difference_t<_It> _Count_raw, _Out _First2, _Se) const { + // clang-format on + _Algorithm_int_t> _Count = _Count_raw; + if (_Count > 0) { + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped_n(_STD move(_First2), _Count); + if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { + _OFirst = _Copy_memmove(_IFirst, _IFirst + _Count, _OFirst); + } else if constexpr (is_nothrow_constructible_v, iter_value_t<_Out>&&>) { + for (; 0 < _Count; --_Count, (void) ++_IFirst, ++_OFirst) { + *_OFirst = _RANGES iter_move(_IFirst); + } + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + for (; 0 < _Count; --_Count, (void) ++_IFirst) { + _Backout._Emplace_back(_RANGES iter_move(_IFirst)); + } + + _OFirst = _STD move(_Backout._Release()); + } + + _Seek_wrapped(_First1, _IFirst); + _Seek_wrapped(_First2, _OFirst); + } + return {_STD move(_First1), _STD move(_First2)}; + } + }; + + inline constexpr _Uninitialized_move_n_fn uninitialized_move_n{_Not_quite_object::_Construct_tag{}}; + + // VARIABLE ranges::uninitialized_fill + class _Uninitialized_fill_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se, class _Ty> + requires constructible_from, const _Ty&> + _It operator()(_It _First, _Se _Last, const _Ty& _Val) const { + // clang-format on + _Adl_verify_range(_First, _Last); + auto _UResult = _Uninitialized_fill_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Val); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + + // clang-format off + template <_No_throw_forward_range _Rng, class _Ty> + requires constructible_from, const _Ty&> + borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, const _Ty& _Val) const { + // clang-format on + return _Rewrap_iterator(_Range, _Uninitialized_fill_unchecked(_Ubegin(_Range), _Uend(_Range), _Val)); + } + + private: + template + _NODISCARD static _It _Uninitialized_fill_unchecked(_It _OFirst, const _Se _OLast, const _Ty& _Val) { + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(constructible_from, const _Ty&>); + + if constexpr (_Fill_memset_is_safe<_It, _Ty>) { + if constexpr (is_same_v<_Se, _It>) { + _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OLast - _OFirst)); + return _OLast; + } else if constexpr (sized_sentinel_for<_Se, _It>) { + _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OLast - _OFirst)); + return _RANGES next(_OFirst, _OLast - _OFirst); + } else { + const _It _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); + _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OFinal - _OFirst)); + return _OFinal; + } + } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { + for (; _OFirst != _OLast; ++_OFirst) { + _Construct_in_place(*_OFirst, _Val); + } + return _OFirst; + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + while (_Backout._Last != _OLast) { + _Backout._Emplace_back(_Val); + } + + return _Backout._Release(); + } + } + }; + + inline constexpr _Uninitialized_fill_fn uninitialized_fill{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_fill_n #if _HAS_IF_CONSTEXPR template @@ -284,6 +509,47 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, } #endif // _HAS_IF_CONSTEXPR +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::uninitialized_fill_n + class _Uninitialized_fill_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It, class _Ty> + requires constructible_from, const _Ty&> + _It operator()(_It _First, const iter_difference_t<_It> _Count_raw, const _Ty& _Val) const { + // clang-format on + _Algorithm_int_t> _Count = _Count_raw; + if (_Count > 0) { + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + if constexpr (_Fill_memset_is_safe<_It, _Ty>) { + _CSTD memset(_STD move(_UFirst), static_cast(_Val), _Count); + _RANGES advance(_First, _Count); + } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { + for (; 0 < _Count; ++_UFirst, (void) --_Count) { + _Construct_in_place(*_UFirst, _Val); + } + _Seek_wrapped(_First, _STD move(_UFirst)); + } else { + _Uninitialized_backout _Backout{_STD move(_UFirst)}; + + for (; 0 < _Count; --_Count) { + _Backout._Emplace_back(_Val); + } + + _Seek_wrapped(_First, _STD move(_Backout._Release())); + } + } + return _First; + } + }; + + inline constexpr _Uninitialized_fill_n_fn uninitialized_fill_n{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + #if _HAS_CXX20 template auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept(noexcept(::new (const_cast( @@ -352,6 +618,75 @@ void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowF } } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::uninitialized_default_construct + class _Uninitialized_default_construct_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se> + requires default_initializable> + _It operator()(_It _First, _Se _Last) const { + // clang-format on + _Adl_verify_range(_First, _Last); + auto _UResult = _Uninitialized_default_construct_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last))); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + + // clang-format off + template <_No_throw_forward_range _Rng> + requires default_initializable> + borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const { + // clang-format on + auto _UResult = _Uninitialized_default_construct_unchecked(_Ubegin(_Range), _Uend(_Range)); + + return _Rewrap_iterator(_Range, _STD move(_UResult)); + } + + private: + template + _NODISCARD static _It _Uninitialized_default_construct_unchecked(_It _OFirst, const _Se _OLast) { + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(default_initializable>); + + using _Ty = iter_value_t<_It>; + if constexpr (is_trivially_default_constructible_v<_Ty>) { + if constexpr (is_same_v<_Se, _It>) { + return _OLast; + } else if constexpr (sized_sentinel_for<_Se, _It>) { + return _RANGES next(_OFirst, _OLast - _OFirst); + } else { + return _RANGES next(_OFirst, _STD move(_OLast)); + } + } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { + for (; _OFirst != _OLast; ++_OFirst) { + ::new (static_cast(_Unfancy(_OFirst))) _Ty; + } + + return _OFirst; + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _Backout._Last != _OLast; ++_Backout._Last) { + ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; + } + + return _Backout._Release(); + } + } + }; + + inline constexpr _Uninitialized_default_construct_fn uninitialized_default_construct{ + _Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_default_construct_n template _NoThrowFwdIt uninitialized_default_construct_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { @@ -374,6 +709,49 @@ _NoThrowFwdIt uninitialized_default_construct_n(_NoThrowFwdIt _First, const _Dif return _First; } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::uninitialized_default_construct_n + class _Uninitialized_default_construct_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It> + requires default_initializable> + _It operator()(_It _First, const iter_difference_t<_It> _Count_raw) const { + // clang-format on + using _Ty = iter_value_t<_It>; + _Algorithm_int_t> _Count = _Count_raw; + if (_Count > 0) { + if constexpr (is_trivially_default_constructible_v<_Ty>) { + _RANGES advance(_First, _Count); + } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { + auto _UFirst = _Get_unwrapped_n(_STD move(_First)); + for (; 0 < _Count; ++_UFirst, (void) --_Count) { + ::new (static_cast(_Unfancy(_UFirst))) _Ty; + } + + _Seek_wrapped(_First, _STD move(_UFirst)); + } else { + _Uninitialized_backout _Backout{_Get_unwrapped_n(_STD move(_First), _Count)}; + + for (; 0 < _Count; ++_Backout._Last, (void) --_Count) { + ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; + } + + _Seek_wrapped(_First, _STD move(_Backout._Release())); + } + } + return _First; + } + }; + + inline constexpr _Uninitialized_default_construct_n_fn uninitialized_default_construct_n{ + _Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_value_construct template void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { @@ -393,6 +771,95 @@ void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwd } } +#ifdef __cpp_lib_concepts +namespace ranges { + // clang-format off + template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se> + requires default_initializable> + _It _Zero_range(const _It _First, const _Se _Last) { + // clang-format on + // fill [_First, _Last) with zeroes + if constexpr (is_same_v<_Se, _It>) { + char* const _First_ch = reinterpret_cast(_First); + char* const _Last_ch = reinterpret_cast(_Last); + _CSTD memset(_First_ch, 0, static_cast(_Last_ch - _First_ch)); + return _Last; + } else if constexpr (sized_sentinel_for<_Se, _It>) { + const _It _Final = _RANGES next(_First, _Last - _First); + char* const _First_ch = reinterpret_cast(_First); + char* const _Final_ch = reinterpret_cast(_Final); + _CSTD memset(_First_ch, 0, static_cast(_Final_ch - _First_ch)); + return _Final; + } else { + const _It _Final = _RANGES next(_First, _STD move(_Last)); + char* const _First_ch = reinterpret_cast(_First); + char* const _Final_ch = reinterpret_cast(_Final); + _CSTD memset(_First_ch, 0, static_cast(_Final_ch - _First_ch)); + return _Final; + } + } + + // VARIABLE ranges::uninitialized_value_construct + class _Uninitialized_value_construct_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se> + requires default_initializable> + _It operator()(_It _First, _Se _Last) const { + // clang-format on + _Adl_verify_range(_First, _Last); + auto _UResult = _Uninitialized_value_construct_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last))); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + + // clang-format off + template <_No_throw_forward_range _Rng> + requires default_initializable> + borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const { + // clang-format on + auto _UResult = _Uninitialized_value_construct_unchecked(_Ubegin(_Range), _Uend(_Range)); + + return _Rewrap_iterator(_Range, _STD move(_UResult)); + } + + private: + template + _NODISCARD static _It _Uninitialized_value_construct_unchecked(_It _OFirst, const _Se _OLast) { + _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(default_initializable>); + + using _Ty = iter_value_t<_It>; + if constexpr (_Use_memset_value_construct_v<_It>) { + return _RANGES _Zero_range(_OFirst, _OLast); + } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { + for (; _OFirst != _OLast; ++_OFirst) { + ::new (static_cast(_Unfancy(_OFirst))) _Ty{}; + } + + return _OFirst; + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + while (_Backout._Last != _OLast) { + _Backout._Emplace_back(); + } + + return _Backout._Release(); + } + } + }; + + inline constexpr _Uninitialized_value_construct_fn uninitialized_value_construct{ + _Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE uninitialized_value_construct_n template _NoThrowFwdIt uninitialized_value_construct_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { @@ -405,6 +872,48 @@ _NoThrowFwdIt uninitialized_value_construct_n(_NoThrowFwdIt _First, const _Diff return _First; } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::uninitialized_value_construct_n + class _Uninitialized_value_construct_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template <_No_throw_forward_iterator _It> + requires default_initializable> + _It operator()(_It _First, const iter_difference_t<_It> _Count_raw) const { + // clang-format on + using _Ty = iter_value_t<_It>; + _Algorithm_int_t> _Count = _Count_raw; + if (_Count > 0) { + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + if constexpr (_Use_memset_value_construct_v<_It>) { + _Seek_wrapped(_First, _RANGES _Zero_range(_UFirst, _UFirst + _Count)); + } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { + for (; 0 < _Count; ++_UFirst, (void) --_Count) { + ::new (static_cast(_Unfancy(_UFirst))) _Ty{}; + } + + _Seek_wrapped(_First, _STD move(_UFirst)); + } else { + _Uninitialized_backout _Backout{_STD move(_UFirst)}; + + for (; 0 < _Count; --_Count) { + _Backout._Emplace_back(); + } + + _Seek_wrapped(_First, _STD move(_Backout._Release())); + } + } + return _First; + } + }; + + inline constexpr _Uninitialized_value_construct_n_fn uninitialized_value_construct_n{ + _Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts #endif // _HAS_CXX17 diff --git a/tests/std/test.lst b/tests/std/test.lst index 499a40f9004..cb3e4b48d2b 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -307,7 +307,16 @@ tests\P0896R4_ranges_alg_sort tests\P0896R4_ranges_alg_swap_ranges tests\P0896R4_ranges_alg_transform_binary tests\P0896R4_ranges_alg_transform_unary +tests\P0896R4_ranges_alg_uninitialized_copy +tests\P0896R4_ranges_alg_uninitialized_copy_n +tests\P0896R4_ranges_alg_uninitialized_default_construct +tests\P0896R4_ranges_alg_uninitialized_default_construct_n +tests\P0896R4_ranges_alg_uninitialized_fill +tests\P0896R4_ranges_alg_uninitialized_fill_n tests\P0896R4_ranges_alg_uninitialized_move +tests\P0896R4_ranges_alg_uninitialized_move_n +tests\P0896R4_ranges_alg_uninitialized_value_construct +tests\P0896R4_ranges_alg_uninitialized_value_construct_n tests\P0896R4_ranges_alg_unique tests\P0896R4_ranges_alg_unique_copy tests\P0896R4_ranges_algorithm_machinery diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp new file mode 100644 index 00000000000..0f33c08eec7 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate that uninitialized_copy_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_copy_result>); +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_copy_result>); +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_copy_result>); +STATIC_ASSERT(same_as{}, borrowed{})), + ranges::uninitialized_copy_result>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 29; + int val = 10; + + int_wrapper() { + ++constructions; + } + int_wrapper(int x) : val{x} { + ++constructions; + } + + int_wrapper(const int_wrapper& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + + val = that.val; + ++constructions; + } + + ~int_wrapper() { + ++destructions; + } + + int_wrapper& operator=(const int_wrapper& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + val = that.val; + return *this; + } + + auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_input[] = {13, 55, 12345}; + + template + static void call() { + using ranges::uninitialized_copy, ranges::uninitialized_copy_result, ranges::equal, ranges::equal_to, + ranges::iterator_t; + + { // Validate range overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = + uninitialized_copy(wrapped_input, wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + + { // Validate iterator overload + int_wrapper input[3] = {13, 55, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = uninitialized_copy( + wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + static constexpr int expected_input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + + template + static void call() { + // Validate only range overload (one is plenty since they both use the same backend) + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + R wrapped_input{input}; + holder mem; + W wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_copy(wrapped_input, wrapped_output); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. + + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp new file mode 100644 index 00000000000..6d8ea5adfba --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate that uninitialized_copy_n_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 29; + int val = 10; + + int_wrapper() { + ++constructions; + } + int_wrapper(int x) : val{x} { + ++constructions; + } + + int_wrapper(const int_wrapper& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + + val = that.val; + ++constructions; + } + + ~int_wrapper() { + ++destructions; + } + + int_wrapper& operator=(const int_wrapper& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + val = that.val; + return *this; + } + + auto operator<=>(const int_wrapper&) const = default; +}; + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_input[] = {13, 55, 12345}; + + template + static void call() { + using ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal, ranges::equal_to, + ranges::iterator_t; + + { // Validate iterator overload + int_wrapper input[3] = {13, 55, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = + uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + static constexpr int expected_input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + + template + static void call() { + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_copy_n(wrapped_input.begin(), 4, wrapped_output.begin(), wrapped_output.end()); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp new file mode 100644 index 00000000000..40c228e122c --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate dangling story +STATIC_ASSERT(same_as{})), ranges::dangling>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val; + + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + template + static void call() { + using ranges::uninitialized_default_construct, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate range overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_default_construct(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + + { // Validate iterator overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = + uninitialized_default_construct(wrapped_input.begin(), wrapped_input.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + template + static void call() { + // Validate only range overload (one is plenty since they both use the same backend) + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_default_construct(wrapped_input); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp new file mode 100644 index 00000000000..2f096938517 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val; + + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + template + static void call() { + using ranges::uninitialized_default_construct_n, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate iterator overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_default_construct_n(wrapped_input.begin(), 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + template + static void call() { + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_default_construct_n(wrapped_input.begin(), int_wrapper::magic_throwing_val); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp new file mode 100644 index 00000000000..504798b2c93 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate dangling story +STATIC_ASSERT(same_as{}, 42)), ranges::dangling>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val; + + int_wrapper() = default; + + int_wrapper(const int v) { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + val = v; + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected[3] = {42, 42, 42}; + + template + static void call() { + using ranges::uninitialized_fill, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate range overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_fill(wrapped_input, 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 iterator overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = + uninitialized_fill(wrapped_input.begin(), wrapped_input.end(), 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); + } + } +}; + +struct throwing_test { + template + static void call() { + // Validate only range overload (one is plenty since they both use the same backend) + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_fill(wrapped_input, 42); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp new file mode 100644 index 00000000000..96c5081ce1b --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill_n/test.cpp @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val; + + int_wrapper() = default; + + int_wrapper(const int v) { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + val = v; + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected[3] = {42, 42, 42}; + + template + static void call() { + using ranges::uninitialized_fill_n, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate iterator overload + 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); + } + } +}; + +struct throwing_test { + template + static void call() { + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_fill_n(wrapped_input.begin(), int_wrapper::magic_throwing_val, 42); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp new file mode 100644 index 00000000000..01965c618c7 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate that uninitialized_move_n_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 29; + int val = 10; + + int_wrapper() { + ++constructions; + } + int_wrapper(int x) : val{x} { + ++constructions; + } + + int_wrapper(int_wrapper&& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + + val = exchange(that.val, -1); + ++constructions; + } + + ~int_wrapper() { + ++destructions; + } + + int_wrapper& operator=(int_wrapper&& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } + val = exchange(that.val, -1); + return *this; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(movable && !copyable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected_output[] = {13, 55, 12345}; + static constexpr int expected_input[] = {-1, -1, -1}; + + template + static void call() { + using ranges::uninitialized_move_n, ranges::uninitialized_move_n_result, ranges::equal, ranges::equal_to, + ranges::iterator_t; + + { // Validate iterator overload + int_wrapper input[3] = {13, 55, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = + uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); + } + } +}; + +struct throwing_test { + static constexpr int expected_input[] = {-1, -1, int_wrapper::magic_throwing_val, 12345}; + + template + static void call() { + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_move_n(wrapped_input.begin(), 4, wrapped_output.begin(), wrapped_output.end()); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + } +}; + +template +using test_input = test::range; +using test_output = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp new file mode 100644 index 00000000000..39d479a4823 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate dangling story +STATIC_ASSERT(same_as{})), ranges::dangling>); + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val = 10; + + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected[3] = {10, 10, 10}; + + template + static void call() { + using ranges::uninitialized_value_construct, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate range overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_value_construct(wrapped_input); + 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 iterator overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = + uninitialized_value_construct(wrapped_input.begin(), wrapped_input.end()); + 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); + } + } +}; + +struct throwing_test { + template + static void call() { + // Validate only range overload (one is plenty since they both use the same backend) + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_value_construct(wrapped_input); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp new file mode 100644 index 00000000000..6a9f08449d8 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +struct int_wrapper { + inline static int constructions = 0; + inline static int destructions = 0; + + static void clear_counts() { + constructions = 0; + destructions = 0; + } + + static constexpr int magic_throwing_val = 4; + int val = 10; + + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; + } + } + + ~int_wrapper() { + ++destructions; + } + + auto operator<=>(const int_wrapper&) const = default; +}; +STATIC_ASSERT(default_initializable); + +template +struct holder { + STATIC_ASSERT(N < ~size_t{0} / sizeof(T)); + alignas(T) unsigned char space[N * sizeof(T)]; + + auto as_span() { + return span{reinterpret_cast(space + 0), N}; + } +}; + +template +void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy + for (auto& e : r) { + destroy_at(&e); + } +} + +struct instantiator { + static constexpr int expected[3] = {10, 10, 10}; + + template + static void call() { + using ranges::uninitialized_value_construct_n, ranges::equal, ranges::equal_to, ranges::iterator_t; + + { // Validate iterator overload + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_value_construct_n(wrapped_input.begin(), 3); + 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); + } + } +}; + +struct throwing_test { + template + static void call() { + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + try { + (void) ranges::uninitialized_value_construct_n(wrapped_input.begin(), int_wrapper::magic_throwing_val); + assert(false); + } catch (int i) { + assert(i == int_wrapper::magic_throwing_val); + } catch (...) { + assert(false); + } + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + } +}; + +using test_range = test::range; + +int main() { + // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it + // requires non-proxy references for the input range. + + instantiator::call(); + throwing_test::call(); +} From 577eab32d6e799a55237f08e3a1728141dda1dd4 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 31 Aug 2020 17:06:03 +0200 Subject: [PATCH 02/23] Address review comments --- stl/inc/memory | 136 +++++++++++++++++++++++++---------------------- stl/inc/xutility | 22 ++++++++ 2 files changed, 94 insertions(+), 64 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index db01ad24621..1b5a9f0493a 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -67,10 +67,10 @@ namespace ranges { using _Not_quite_object::_Not_quite_object; // clang-format off - template _Se1, _No_throw_forward_iterator _Out, - _No_throw_sentinel_for<_Out> _Se2> + template _Se, _No_throw_forward_iterator _Out, + _No_throw_sentinel_for<_Out> _OSe> requires constructible_from, iter_reference_t<_It>> - uninitialized_copy_result<_It, _Out> operator()(_It _First1, _Se1 _Last1, _Out _First2, _Se2 _Last2) const { + uninitialized_copy_result<_It, _Out> operator()(_It _First1, _Se _Last1, _Out _First2, _OSe _Last2) const { // clang-format on _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -98,17 +98,22 @@ namespace ranges { } private: - template + template _NODISCARD static uninitialized_copy_result<_It, _Out> _Uninitialized_copy_unchecked( - _It _IFirst, const _Se1 _ILast, _Out _OFirst, const _Se2 _OLast) { + _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_Out>); - _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se2, _Out>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_reference_t<_It>>); - if constexpr (is_same_v<_Se1, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { - return _Copy_memmove(_IFirst, _ILast, _OFirst); + if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { + return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); + } else if constexpr (is_nothrow_constructible_v, iter_reference_t<_It>>) { + for (; _IFirst != _ILast && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { + _Construct_in_place(*_OFirst, *_IFirst); + } + return {_STD move(_IFirst), _STD move(_OFirst)}; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -135,7 +140,7 @@ _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _ auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Ptr_copy_cat::_Really_trivial) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + _UDest = _Copy_memcpy(_UFirst, _UFirst + _Count, _UDest); } else { _Uninitialized_backout _Backout{_UDest}; for (; 0 < _Count; --_Count, (void) ++_UFirst) { @@ -195,28 +200,29 @@ namespace ranges { using _Not_quite_object::_Not_quite_object; // clang-format off - template _Se2> + template _OSe> requires constructible_from, iter_reference_t<_It>> uninitialized_copy_n_result<_It, _Out> operator()( - _It _First1, const iter_difference_t<_It> _Count_raw, _Out _First2, _Se2) const { + _It _First1, iter_difference_t<_It> _Count, _Out _First2, _OSe _Last2) const { // clang-format on - _Algorithm_int_t> _Count = _Count_raw; if (_Count > 0) { - auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); - auto _OFirst = _Get_unwrapped_n(_STD move(_First2), _Count); + _Adl_verify_range(_First2, _Last2); + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped(_STD move(_First2)); + const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) { - _OFirst = _Copy_memmove(_IFirst, _IFirst + _Count, _OFirst); - } else if constexpr (is_nothrow_constructible_v, const iter_value_t<_Out>&>) { - for (; 0 < _Count; --_Count, (void) ++_IFirst, ++_OFirst) { - *_OFirst = *_IFirst; + _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + } else if constexpr (is_nothrow_constructible_v, iter_reference_t<_It>>) { + for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst, ++_OFirst) { + _Construct_in_place(*_OFirst, *_IFirst); } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; - for (; 0 < _Count; --_Count, (void) ++_IFirst) { + for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst) { _Backout._Emplace_back(*_IFirst); } - _OFirst = _STD move(_Backout._Release()); + _OFirst = _Backout._Release(); } _Seek_wrapped(_First1, _IFirst); @@ -255,10 +261,10 @@ namespace ranges { using _Not_quite_object::_Not_quite_object; // clang-format off - template _Se1, _No_throw_forward_iterator _Out, - _No_throw_sentinel_for<_Out> _Se2> + template _Se, _No_throw_forward_iterator _Out, + _No_throw_sentinel_for<_Out> _OSe> requires constructible_from, iter_rvalue_reference_t<_It>> - uninitialized_move_result<_It, _Out> operator()(_It _First1, _Se1 _Last1, _Out _First2, _Se2 _Last2) const { + uninitialized_move_result<_It, _Out> operator()(_It _First1, _Se _Last1, _Out _First2, _OSe _Last2) const { // clang-format on _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -286,22 +292,31 @@ namespace ranges { } private: - template + template _NODISCARD static uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( - _It _IFirst, const _Se1 _ILast, _Out _OFirst, const _Se2 _OLast) { + _It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) { _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); _STL_INTERNAL_STATIC_ASSERT(_No_throw_forward_iterator<_Out>); - _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se2, _Out>); + _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It>>); - _Uninitialized_backout _Backout{_STD move(_OFirst)}; + if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { + return _Copy_memmove_common(_IFirst, _ILast, _OFirst, _OLast); + } else if constexpr (is_nothrow_constructible_v, iter_rvalue_reference_t<_It>>) { + for (; _IFirst != _ILast && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { + _Construct_in_place(*_OFirst, _RANGES iter_move(_IFirst)); + } + return {_STD move(_IFirst), _STD move(_OFirst)}; + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; - for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { - _Backout._Emplace_back(_RANGES iter_move(_IFirst)); - } + for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { + _Backout._Emplace_back(_RANGES iter_move(_IFirst)); + } - return {_STD move(_IFirst), _Backout._Release()}; + return {_STD move(_IFirst), _Backout._Release()}; + } } }; @@ -350,28 +365,29 @@ namespace ranges { using _Not_quite_object::_Not_quite_object; // clang-format off - template _Se> + template _OSe> requires constructible_from, iter_rvalue_reference_t<_It>> uninitialized_move_n_result<_It, _Out> operator()( - _It _First1, const iter_difference_t<_It> _Count_raw, _Out _First2, _Se) const { + _It _First1, iter_difference_t<_It> _Count, _Out _First2, _OSe _Last2) const { // clang-format on - _Algorithm_int_t> _Count = _Count_raw; if (_Count > 0) { - auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); - auto _OFirst = _Get_unwrapped_n(_STD move(_First2), _Count); + _Adl_verify_range(_First2, _Last2); + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped(_STD move(_First2)); + const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { - _OFirst = _Copy_memmove(_IFirst, _IFirst + _Count, _OFirst); - } else if constexpr (is_nothrow_constructible_v, iter_value_t<_Out>&&>) { - for (; 0 < _Count; --_Count, (void) ++_IFirst, ++_OFirst) { - *_OFirst = _RANGES iter_move(_IFirst); + _OFirst = _Copy_memmove_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + } else if constexpr (is_nothrow_constructible_v, iter_rvalue_reference_t<_It>>) { + for (; _Count > 0 && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { + _Construct_in_place(*_OFirst, _RANGES iter_move(_IFirst)); } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; - for (; 0 < _Count; --_Count, (void) ++_IFirst) { + for (; _Count > 0; --_Count, (void) ++_IFirst) { _Backout._Emplace_back(_RANGES iter_move(_IFirst)); } - _OFirst = _STD move(_Backout._Release()); + _OFirst = _Backout._Release(); } _Seek_wrapped(_First1, _IFirst); @@ -422,7 +438,7 @@ namespace ranges { return _OLast; } else if constexpr (sized_sentinel_for<_Se, _It>) { _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OLast - _OFirst)); - return _RANGES next(_OFirst, _OLast - _OFirst); + return _OFirst + (_OLast - _OFirst); } else { const _It _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OFinal - _OFirst)); @@ -519,23 +535,22 @@ namespace ranges { // clang-format off template <_No_throw_forward_iterator _It, class _Ty> requires constructible_from, const _Ty&> - _It operator()(_It _First, const iter_difference_t<_It> _Count_raw, const _Ty& _Val) const { + _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Val) const { // clang-format on - _Algorithm_int_t> _Count = _Count_raw; if (_Count > 0) { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if constexpr (_Fill_memset_is_safe<_It, _Ty>) { _CSTD memset(_STD move(_UFirst), static_cast(_Val), _Count); - _RANGES advance(_First, _Count); + _Seek_wrapped(_First, _UFirst + _Count); } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { - for (; 0 < _Count; ++_UFirst, (void) --_Count) { + for (; _Count > 0; --_Count, (void) ++_UFirst) { _Construct_in_place(*_UFirst, _Val); } _Seek_wrapped(_First, _STD move(_UFirst)); } else { _Uninitialized_backout _Backout{_STD move(_UFirst)}; - for (; 0 < _Count; --_Count) { + for (; _Count > 0; --_Count) { _Backout._Emplace_back(_Val); } @@ -655,20 +670,14 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); _STL_INTERNAL_STATIC_ASSERT(default_initializable>); - using _Ty = iter_value_t<_It>; + using _Ty = remove_reference_t>; if constexpr (is_trivially_default_constructible_v<_Ty>) { - if constexpr (is_same_v<_Se, _It>) { - return _OLast; - } else if constexpr (sized_sentinel_for<_Se, _It>) { - return _RANGES next(_OFirst, _OLast - _OFirst); - } else { - return _RANGES next(_OFirst, _STD move(_OLast)); - } + _RANGES advance(_OFirst, _OLast); + return _OFirst; } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { for (; _OFirst != _OLast; ++_OFirst) { ::new (static_cast(_Unfancy(_OFirst))) _Ty; } - return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -719,16 +728,15 @@ namespace ranges { // clang-format off template <_No_throw_forward_iterator _It> requires default_initializable> - _It operator()(_It _First, const iter_difference_t<_It> _Count_raw) const { + _It operator()(_It _First, iter_difference_t<_It> _Count) const { // clang-format on - using _Ty = iter_value_t<_It>; - _Algorithm_int_t> _Count = _Count_raw; + using _Ty = remove_reference_t>; if (_Count > 0) { if constexpr (is_trivially_default_constructible_v<_Ty>) { _RANGES advance(_First, _Count); } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { auto _UFirst = _Get_unwrapped_n(_STD move(_First)); - for (; 0 < _Count; ++_UFirst, (void) --_Count) { + for (; _Count > 0; --_Count, (void) ++_UFirst) { ::new (static_cast(_Unfancy(_UFirst))) _Ty; } @@ -736,7 +744,7 @@ namespace ranges { } else { _Uninitialized_backout _Backout{_Get_unwrapped_n(_STD move(_First), _Count)}; - for (; 0 < _Count; ++_Backout._Last, (void) --_Count) { + for (; _Count > 0; --_Count, (void) ++_Backout._Last) { ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; } diff --git a/stl/inc/xutility b/stl/inc/xutility index 7a08e0a3cc5..cd53caff417 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4335,6 +4335,28 @@ _OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _O return _Copy_memmove(_First.base(), _Last.base(), _Dest); } +template +_OutIt _Copy_memmove_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) { + const char* const _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); + const char* const _ILast_ch = const_cast(reinterpret_cast(_ILast)); + char* const _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); + const char* const _OLast_ch = const_cast(reinterpret_cast(_OLast)); + const auto _Count = static_cast(min(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + _CSTD memmove(_OFirst_ch, _IFirst_ch, _Count); + return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); +} + +template +_OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) { + const char* const _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); + const char* const _ILast_ch = const_cast(reinterpret_cast(_ILast)); + char* const _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); + const char* const _OLast_ch = const_cast(reinterpret_cast(_OLast)); + const auto _Count = static_cast(min(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); + return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); +} + #if _HAS_IF_CONSTEXPR // VARIABLE TEMPLATE _Is_vb_iterator template From 9415328195646ec83144399ee464e1e80a3da80d Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Tue, 1 Sep 2020 14:22:32 +0200 Subject: [PATCH 03/23] Remove noexcept case without _Backout as ++_IFirst could throw too --- stl/inc/memory | 52 -------------------------------------------------- 1 file changed, 52 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 1b5a9f0493a..92d33842306 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -109,11 +109,6 @@ namespace ranges { if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); - } else if constexpr (is_nothrow_constructible_v, iter_reference_t<_It>>) { - for (; _IFirst != _ILast && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { - _Construct_in_place(*_OFirst, *_IFirst); - } - return {_STD move(_IFirst), _STD move(_OFirst)}; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -212,10 +207,6 @@ namespace ranges { const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) { _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); - } else if constexpr (is_nothrow_constructible_v, iter_reference_t<_It>>) { - for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst, ++_OFirst) { - _Construct_in_place(*_OFirst, *_IFirst); - } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst) { @@ -303,11 +294,6 @@ namespace ranges { if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { return _Copy_memmove_common(_IFirst, _ILast, _OFirst, _OLast); - } else if constexpr (is_nothrow_constructible_v, iter_rvalue_reference_t<_It>>) { - for (; _IFirst != _ILast && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { - _Construct_in_place(*_OFirst, _RANGES iter_move(_IFirst)); - } - return {_STD move(_IFirst), _STD move(_OFirst)}; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -377,10 +363,6 @@ namespace ranges { const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { _OFirst = _Copy_memmove_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); - } else if constexpr (is_nothrow_constructible_v, iter_rvalue_reference_t<_It>>) { - for (; _Count > 0 && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { - _Construct_in_place(*_OFirst, _RANGES iter_move(_IFirst)); - } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; for (; _Count > 0; --_Count, (void) ++_IFirst) { @@ -444,11 +426,6 @@ namespace ranges { _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OFinal - _OFirst)); return _OFinal; } - } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { - for (; _OFirst != _OLast; ++_OFirst) { - _Construct_in_place(*_OFirst, _Val); - } - return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -542,11 +519,6 @@ namespace ranges { if constexpr (_Fill_memset_is_safe<_It, _Ty>) { _CSTD memset(_STD move(_UFirst), static_cast(_Val), _Count); _Seek_wrapped(_First, _UFirst + _Count); - } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { - for (; _Count > 0; --_Count, (void) ++_UFirst) { - _Construct_in_place(*_UFirst, _Val); - } - _Seek_wrapped(_First, _STD move(_UFirst)); } else { _Uninitialized_backout _Backout{_STD move(_UFirst)}; @@ -674,11 +646,6 @@ namespace ranges { if constexpr (is_trivially_default_constructible_v<_Ty>) { _RANGES advance(_OFirst, _OLast); return _OFirst; - } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { - for (; _OFirst != _OLast; ++_OFirst) { - ::new (static_cast(_Unfancy(_OFirst))) _Ty; - } - return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -734,13 +701,6 @@ namespace ranges { if (_Count > 0) { if constexpr (is_trivially_default_constructible_v<_Ty>) { _RANGES advance(_First, _Count); - } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { - auto _UFirst = _Get_unwrapped_n(_STD move(_First)); - for (; _Count > 0; --_Count, (void) ++_UFirst) { - ::new (static_cast(_Unfancy(_UFirst))) _Ty; - } - - _Seek_wrapped(_First, _STD move(_UFirst)); } else { _Uninitialized_backout _Backout{_Get_unwrapped_n(_STD move(_First), _Count)}; @@ -845,12 +805,6 @@ namespace ranges { using _Ty = iter_value_t<_It>; if constexpr (_Use_memset_value_construct_v<_It>) { return _RANGES _Zero_range(_OFirst, _OLast); - } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { - for (; _OFirst != _OLast; ++_OFirst) { - ::new (static_cast(_Unfancy(_OFirst))) _Ty{}; - } - - return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -898,12 +852,6 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if constexpr (_Use_memset_value_construct_v<_It>) { _Seek_wrapped(_First, _RANGES _Zero_range(_UFirst, _UFirst + _Count)); - } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { - for (; 0 < _Count; ++_UFirst, (void) --_Count) { - ::new (static_cast(_Unfancy(_UFirst))) _Ty{}; - } - - _Seek_wrapped(_First, _STD move(_UFirst)); } else { _Uninitialized_backout _Backout{_STD move(_UFirst)}; From f2d424edb823fafc133bcd0dae037893f4f35854 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Tue, 1 Sep 2020 14:37:50 +0200 Subject: [PATCH 04/23] Use early returns everywhere --- stl/inc/memory | 304 ++++++++++++++++++++++++++----------------------- 1 file changed, 164 insertions(+), 140 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 92d33842306..ede8534b834 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -131,23 +131,25 @@ template _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...) _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - auto _UDest = _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Ptr_copy_cat::_Really_trivial) { - _UDest = _Copy_memcpy(_UFirst, _UFirst + _Count, _UDest); - } else { - _Uninitialized_backout _Backout{_UDest}; - for (; 0 < _Count; --_Count, (void) ++_UFirst) { - _Backout._Emplace_back(*_UFirst); - } + if (_Count <= 0) { + return _Dest; + } + + auto _UFirst = _Get_unwrapped_n(_First, _Count); + auto _UDest = _Get_unwrapped_n(_Dest, _Count); + if constexpr (_Ptr_copy_cat::_Really_trivial) { + _UDest = _Copy_memcpy(_UFirst, _UFirst + _Count, _UDest); + } else { + _Uninitialized_backout _Backout{_UDest}; - _UDest = _Backout._Release(); + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Backout._Emplace_back(*_UFirst); } - _Seek_wrapped(_Dest, _UDest); + _UDest = _Backout._Release(); } + _Seek_wrapped(_Dest, _UDest); return _Dest; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv @@ -155,7 +157,8 @@ template _NoThrowFwdIt _Uninitialized_copy_n_unchecked2(_InIt _First, _Diff _Count, const _NoThrowFwdIt _Dest, false_type) { // copy [_First, _First + _Count) to [_Dest, ...), no special optimization _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; - for (; 0 < _Count; --_Count, (void) ++_First) { + + for (; _Count > 0; --_Count, (void) ++_First) { _Backout._Emplace_back(*_First); } @@ -172,13 +175,14 @@ template _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { // copy [_First, _First + _Count) to [_Dest, ...)] _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - auto _UDest = _Get_unwrapped_n(_Dest, _Count); - _Seek_wrapped(_Dest, _Uninitialized_copy_n_unchecked2(_UFirst, _Count, _UDest, - bool_constant<_Ptr_copy_cat::_Really_trivial>{})); + if (_Count <= 0) { + return _Dest; } + auto _UFirst = _Get_unwrapped_n(_First, _Count); + auto _UDest = _Get_unwrapped_n(_Dest, _Count); + _Seek_wrapped(_Dest, _Uninitialized_copy_n_unchecked2(_UFirst, _Count, _UDest, + bool_constant<_Ptr_copy_cat::_Really_trivial>{})); return _Dest; } #endif // _HAS_IF_CONSTEXPR @@ -200,25 +204,28 @@ namespace ranges { uninitialized_copy_n_result<_It, _Out> operator()( _It _First1, iter_difference_t<_It> _Count, _Out _First2, _OSe _Last2) const { // clang-format on - if (_Count > 0) { - _Adl_verify_range(_First2, _Last2); - auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); - auto _OFirst = _Get_unwrapped(_STD move(_First2)); - const auto _OLast = _Get_unwrapped(_STD move(_Last2)); - if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) { - _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); - } else { - _Uninitialized_backout _Backout{_STD move(_OFirst)}; - for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst) { - _Backout._Emplace_back(*_IFirst); - } + if (_Count <= 0) { + return {_STD move(_First1), _STD move(_First2)}; + } + + _Adl_verify_range(_First2, _Last2); + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped(_STD move(_First2)); + const auto _OLast = _Get_unwrapped(_STD move(_Last2)); + if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) { + _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; - _OFirst = _Backout._Release(); + for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst) { + _Backout._Emplace_back(*_IFirst); } - _Seek_wrapped(_First1, _IFirst); - _Seek_wrapped(_First2, _OFirst); + _OFirst = _Backout._Release(); } + + _Seek_wrapped(_First1, _IFirst); + _Seek_wrapped(_First2, _OFirst); return {_STD move(_First1), _STD move(_First2)}; } }; @@ -315,25 +322,27 @@ template pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) { // move [_First, _First + _Count) to [_Dest, ...) _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - auto _UDest = _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Ptr_move_cat::_Really_trivial) { - _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); - _UFirst += _Count; - } else { - _Uninitialized_backout _Backout{_UDest}; - for (; 0 < _Count; --_Count, (void) ++_UFirst) { - _Backout._Emplace_back(_STD move(*_UFirst)); - } + if (_Count <= 0) { + return {_First, _Dest}; + } - _UDest = _Backout._Release(); + auto _UFirst = _Get_unwrapped_n(_First, _Count); + auto _UDest = _Get_unwrapped_n(_Dest, _Count); + if constexpr (_Ptr_move_cat::_Really_trivial) { + _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); + _UFirst += _Count; + } else { + _Uninitialized_backout _Backout{_UDest}; + + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Backout._Emplace_back(_STD move(*_UFirst)); } - _Seek_wrapped(_Dest, _UDest); - _Seek_wrapped(_First, _UFirst); + _UDest = _Backout._Release(); } + _Seek_wrapped(_Dest, _UDest); + _Seek_wrapped(_First, _UFirst); return {_First, _Dest}; } #endif // _HAS_CXX17 @@ -356,25 +365,28 @@ namespace ranges { uninitialized_move_n_result<_It, _Out> operator()( _It _First1, iter_difference_t<_It> _Count, _Out _First2, _OSe _Last2) const { // clang-format on - if (_Count > 0) { - _Adl_verify_range(_First2, _Last2); - auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); - auto _OFirst = _Get_unwrapped(_STD move(_First2)); - const auto _OLast = _Get_unwrapped(_STD move(_Last2)); - if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { - _OFirst = _Copy_memmove_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); - } else { - _Uninitialized_backout _Backout{_STD move(_OFirst)}; - for (; _Count > 0; --_Count, (void) ++_IFirst) { - _Backout._Emplace_back(_RANGES iter_move(_IFirst)); - } + if (_Count <= 0) { + return {_STD move(_First1), _STD move(_First2)}; + } - _OFirst = _Backout._Release(); + _Adl_verify_range(_First2, _Last2); + auto _IFirst = _Get_unwrapped_n(_STD move(_First1), _Count); + auto _OFirst = _Get_unwrapped(_STD move(_First2)); + const auto _OLast = _Get_unwrapped(_STD move(_Last2)); + if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { + _OFirst = _Copy_memmove_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + } else { + _Uninitialized_backout _Backout{_STD move(_OFirst)}; + + for (; _Count > 0; --_Count, (void) ++_IFirst) { + _Backout._Emplace_back(_RANGES iter_move(_IFirst)); } - _Seek_wrapped(_First1, _IFirst); - _Seek_wrapped(_First2, _OFirst); + _OFirst = _Backout._Release(); } + + _Seek_wrapped(_First1, _IFirst); + _Seek_wrapped(_First2, _OFirst); return {_STD move(_First1), _STD move(_First2)}; } }; @@ -448,23 +460,25 @@ template _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) { // copy _Count copies of _Val to raw _First _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t, _Tval>) { - _CSTD memset(_UFirst, static_cast(_Val), _Count); - _UFirst += _Count; - } else { - _Uninitialized_backout<_Unwrapped_n_t> _Backout{_UFirst}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(_Val); - } + if (_Count <= 0) { + return _First; + } + + auto _UFirst = _Get_unwrapped_n(_First, _Count); + if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t, _Tval>) { + _CSTD memset(_UFirst, static_cast(_Val), _Count); + _UFirst += _Count; + } else { + _Uninitialized_backout<_Unwrapped_n_t> _Backout{_UFirst}; - _UFirst = _Backout._Release(); + for (; _Count > 0; --_Count) { + _Backout._Emplace_back(_Val); } - _Seek_wrapped(_First, _UFirst); + _UFirst = _Backout._Release(); } + _Seek_wrapped(_First, _UFirst); return _First; } #else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv @@ -473,7 +487,7 @@ _NoThrowFwdIt _Uninitialized_fill_n_unchecked1( const _NoThrowFwdIt _First, _Diff _Count, const _Tval& _Val, false_type) { // copy _Count copies of _Val to raw _First, no special optimization _Uninitialized_backout<_NoThrowFwdIt> _Backout{_First}; - for (; 0 < _Count; --_Count) { + for (; _Count > 0; --_Count) { _Backout._Emplace_back(_Val); } @@ -492,12 +506,13 @@ template _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) { // copy _Count copies of _Val to raw _First _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - _Seek_wrapped(_First, _Uninitialized_fill_n_unchecked1(_STD move(_UFirst), _Count, _Val, - bool_constant<_Fill_memset_is_safe<_Unwrapped_t<_NoThrowFwdIt>, _Tval>>{})); + if (_Count <= 0) { + return _First; } + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + _Seek_wrapped(_First, _Uninitialized_fill_n_unchecked1(_STD move(_UFirst), _Count, _Val, + bool_constant<_Fill_memset_is_safe<_Unwrapped_t<_NoThrowFwdIt>, _Tval>>{})); return _First; } #endif // _HAS_IF_CONSTEXPR @@ -514,20 +529,22 @@ namespace ranges { requires constructible_from, const _Ty&> _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Val) const { // clang-format on - if (_Count > 0) { - auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - if constexpr (_Fill_memset_is_safe<_It, _Ty>) { - _CSTD memset(_STD move(_UFirst), static_cast(_Val), _Count); - _Seek_wrapped(_First, _UFirst + _Count); - } else { - _Uninitialized_backout _Backout{_STD move(_UFirst)}; + if (_Count <= 0) { + return _First; + } - for (; _Count > 0; --_Count) { - _Backout._Emplace_back(_Val); - } + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + if constexpr (_Fill_memset_is_safe<_It, _Ty>) { + _CSTD memset(_STD move(_UFirst), static_cast(_Val), _Count); + _Seek_wrapped(_First, _UFirst + _Count); + } else { + _Uninitialized_backout _Backout{_STD move(_UFirst)}; - _Seek_wrapped(_First, _STD move(_Backout._Release())); + for (; _Count > 0; --_Count) { + _Backout._Emplace_back(_Val); } + + _Seek_wrapped(_First, _STD move(_Backout._Release())); } return _First; } @@ -570,21 +587,20 @@ template _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { // destroy all elements in [_First, _First + _Count) _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - auto _UFirst = _Get_unwrapped_n(_First, _Count); - if constexpr (is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) { - _STD advance(_UFirst, _Count); - } else { - do { - _Destroy_in_place(*_UFirst); - ++_UFirst; - --_Count; - } while (0 < _Count); - } + if (_Count <= 0) { + return _First; + } - _Seek_wrapped(_First, _UFirst); + auto _UFirst = _Get_unwrapped_n(_First, _Count); + if constexpr (is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) { + _STD advance(_UFirst, _Count); + } else { + for (; _Count > 0; --_Count, (void) _UFirst) { + _Destroy_in_place(*_UFirst); + } } + _Seek_wrapped(_First, _UFirst); return _First; } @@ -592,12 +608,12 @@ _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { template void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // default-initialize all elements in [_First, _Last) - using _Ty = _Iter_value_t<_NoThrowFwdIt>; + using _Ty = remove_reference_t>; _Adl_verify_range(_First, _Last); if constexpr (!is_trivially_default_constructible_v<_Ty>) { - const auto _ULast = _Get_unwrapped(_Last); _Uninitialized_backout _Backout{_Get_unwrapped(_First)}; - for (; _Backout._Last != _ULast; ++_Backout._Last) { + + for (const auto _ULast = _Get_unwrapped(_Last); _Backout._Last != _ULast; ++_Backout._Last) { ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; } @@ -669,19 +685,21 @@ _NoThrowFwdIt uninitialized_default_construct_n(_NoThrowFwdIt _First, const _Dif // default-initialize all elements in [_First, _First + _Count_raw) using _Ty = _Iter_value_t<_NoThrowFwdIt>; _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - if constexpr (is_trivially_default_constructible_v<_Ty>) { - _STD advance(_First, _Count); - } else { - _Uninitialized_backout _Backout{_Get_unwrapped_n(_First, _Count)}; - for (; 0 < _Count; ++_Backout._Last, (void) --_Count) { - ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; - } + if (_Count <= 0) { + return _First; + } - _Seek_wrapped(_First, _Backout._Release()); + if constexpr (is_trivially_default_constructible_v<_Ty>) { + _STD advance(_First, _Count); + } else { + _Uninitialized_backout _Backout{_Get_unwrapped_n(_First, _Count)}; + + for (; _Count > 0; ++_Backout._Last, (void) --_Count) { + ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; } - } + _Seek_wrapped(_First, _Backout._Release()); + } return _First; } @@ -698,18 +716,20 @@ namespace ranges { _It operator()(_It _First, iter_difference_t<_It> _Count) const { // clang-format on using _Ty = remove_reference_t>; - if (_Count > 0) { - if constexpr (is_trivially_default_constructible_v<_Ty>) { - _RANGES advance(_First, _Count); - } else { - _Uninitialized_backout _Backout{_Get_unwrapped_n(_STD move(_First), _Count)}; + if (_Count <= 0) { + return _First; + } - for (; _Count > 0; --_Count, (void) ++_Backout._Last) { - ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; - } + if constexpr (is_trivially_default_constructible_v<_Ty>) { + _RANGES advance(_First, _Count); + } else { + _Uninitialized_backout _Backout{_Get_unwrapped_n(_STD move(_First), _Count)}; - _Seek_wrapped(_First, _STD move(_Backout._Release())); + for (; _Count > 0; --_Count, (void) ++_Backout._Last) { + ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; } + + _Seek_wrapped(_First, _STD move(_Backout._Release())); } return _First; } @@ -731,6 +751,7 @@ void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwd _Zero_range(_UFirst, _ULast); } else { _Uninitialized_backout _Backout{_UFirst}; + while (_Backout._Last != _ULast) { _Backout._Emplace_back(); } @@ -802,7 +823,7 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); _STL_INTERNAL_STATIC_ASSERT(default_initializable>); - using _Ty = iter_value_t<_It>; + using _Ty = remove_reference_t>; if constexpr (_Use_memset_value_construct_v<_It>) { return _RANGES _Zero_range(_OFirst, _OLast); } else { @@ -827,10 +848,11 @@ template _NoThrowFwdIt uninitialized_value_construct_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { // value-initialize all elements in [_First, _First + _Count_raw) _Algorithm_int_t<_Diff> _Count = _Count_raw; - if (0 < _Count) { - _Seek_wrapped(_First, _Uninitialized_value_construct_n_unchecked1(_Get_unwrapped_n(_First, _Count), _Count)); + if (_Count <= 0) { + return _First; } + _Seek_wrapped(_First, _Uninitialized_value_construct_n_unchecked1(_Get_unwrapped_n(_First, _Count), _Count)); return _First; } @@ -844,23 +866,25 @@ namespace ranges { // clang-format off template <_No_throw_forward_iterator _It> requires default_initializable> - _It operator()(_It _First, const iter_difference_t<_It> _Count_raw) const { + _It operator()(_It _First, iter_difference_t<_It> _Count) const { // clang-format on - using _Ty = iter_value_t<_It>; - _Algorithm_int_t> _Count = _Count_raw; - if (_Count > 0) { - auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); - if constexpr (_Use_memset_value_construct_v<_It>) { - _Seek_wrapped(_First, _RANGES _Zero_range(_UFirst, _UFirst + _Count)); - } else { - _Uninitialized_backout _Backout{_STD move(_UFirst)}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(); - } + using _Ty = remove_reference_t>; + if (_Count <= 0) { + return _First; + } + + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + if constexpr (_Use_memset_value_construct_v<_It>) { + _Seek_wrapped(_First, _RANGES _Zero_range(_UFirst, _UFirst + _Count)); + } else { + _Uninitialized_backout _Backout{_STD move(_UFirst)}; - _Seek_wrapped(_First, _STD move(_Backout._Release())); + for (; _Count > 0; --_Count) { + _Backout._Emplace_back(); } + + _Seek_wrapped(_First, _STD move(_Backout._Release())); } return _First; } From 3ffbf82b9b335b5803f8b4fc679b6a0774ebd492 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 2 Sep 2020 09:30:41 +0200 Subject: [PATCH 05/23] Bring back the specializations as we have nothrow iterators --- stl/inc/memory | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index ede8534b834..e62cc4a9272 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -109,6 +109,11 @@ namespace ranges { if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); + } else if constexpr (is_nothrow_constructible_v, iter_reference_t<_It>>) { + for (; _IFirst != _ILast && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { + _Construct_in_place(*_OFirst, *_IFirst); + } + return {_STD move(_IFirst), _STD move(_OFirst)}; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -214,6 +219,10 @@ namespace ranges { const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) { _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + } else if constexpr (is_nothrow_constructible_v, iter_reference_t<_It>>) { + for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst, ++_OFirst) { + _Construct_in_place(*_OFirst, *_IFirst); + } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -301,6 +310,11 @@ namespace ranges { if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { return _Copy_memmove_common(_IFirst, _ILast, _OFirst, _OLast); + } else if constexpr (is_nothrow_constructible_v, iter_rvalue_reference_t<_It>>) { + for (; _IFirst != _ILast && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { + _Construct_in_place(*_OFirst, _RANGES iter_move(_IFirst)); + } + return {_STD move(_IFirst), _STD move(_OFirst)}; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -375,10 +389,14 @@ namespace ranges { const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { _OFirst = _Copy_memmove_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + } else if constexpr (is_nothrow_constructible_v, iter_rvalue_reference_t<_It>>) { + for (; _Count > 0 && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { + _Construct_in_place(*_OFirst, _RANGES iter_move(_IFirst)); + } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; - for (; _Count > 0; --_Count, (void) ++_IFirst) { + for (; _Count > 0 && _Backout._Last != _OLast; --_Count, (void) ++_IFirst) { _Backout._Emplace_back(_RANGES iter_move(_IFirst)); } @@ -438,6 +456,11 @@ namespace ranges { _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OFinal - _OFirst)); return _OFinal; } + } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { + for (; _OFirst != _OLast; ++_OFirst) { + _Construct_in_place(*_OFirst, _Val); + } + return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -537,6 +560,11 @@ namespace ranges { if constexpr (_Fill_memset_is_safe<_It, _Ty>) { _CSTD memset(_STD move(_UFirst), static_cast(_Val), _Count); _Seek_wrapped(_First, _UFirst + _Count); + } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Construct_in_place(*_UFirst, _Val); + } + _Seek_wrapped(_First, _STD move(_UFirst)); } else { _Uninitialized_backout _Backout{_STD move(_UFirst)}; @@ -662,6 +690,11 @@ namespace ranges { if constexpr (is_trivially_default_constructible_v<_Ty>) { _RANGES advance(_OFirst, _OLast); return _OFirst; + } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { + for (; _OFirst != _OLast; ++_OFirst) { + ::new (static_cast(_Unfancy(_OFirst))) _Ty; + } + return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -715,13 +748,21 @@ namespace ranges { requires default_initializable> _It operator()(_It _First, iter_difference_t<_It> _Count) const { // clang-format on - using _Ty = remove_reference_t>; if (_Count <= 0) { return _First; } + using _Ty = remove_reference_t>; if constexpr (is_trivially_default_constructible_v<_Ty>) { _RANGES advance(_First, _Count); + } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { + auto _UFirst = _Get_unwrapped_n(_STD move(_First)); + + for (; _Count > 0; --_Count, (void) ++_UFirst) { + ::new (static_cast(_Unfancy(_UFirst))) _Ty; + } + + _Seek_wrapped(_First, _STD move(_UFirst)); } else { _Uninitialized_backout _Backout{_Get_unwrapped_n(_STD move(_First), _Count)}; @@ -826,6 +867,12 @@ namespace ranges { using _Ty = remove_reference_t>; if constexpr (_Use_memset_value_construct_v<_It>) { return _RANGES _Zero_range(_OFirst, _OLast); + } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { + for (; _OFirst != _OLast; ++_OFirst) { + ::new (static_cast(_Unfancy(_OFirst))) _Ty{}; + } + + return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -877,6 +924,12 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if constexpr (_Use_memset_value_construct_v<_It>) { _Seek_wrapped(_First, _RANGES _Zero_range(_UFirst, _UFirst + _Count)); + } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { + for (; _Count > 0; --_Count, (void) ++_UFirst) { + ::new (static_cast(_Unfancy(_UFirst))) _Ty{}; + } + + _Seek_wrapped(_First, _STD move(_UFirst)); } else { _Uninitialized_backout _Backout{_STD move(_UFirst)}; From 580f1ba7bfc5282e4a6e6d5a11e566463f9b454f Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 2 Sep 2020 20:57:49 +0200 Subject: [PATCH 06/23] Cleanup memset --- stl/inc/memory | 51 +++++++++++--------------------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index e62cc4a9272..7d8b1045aba 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -445,17 +445,10 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(constructible_from, const _Ty&>); if constexpr (_Fill_memset_is_safe<_It, _Ty>) { - if constexpr (is_same_v<_Se, _It>) { - _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OLast - _OFirst)); - return _OLast; - } else if constexpr (sized_sentinel_for<_Se, _It>) { - _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OLast - _OFirst)); - return _OFirst + (_OLast - _OFirst); - } else { - const _It _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); - _CSTD memset(_OFirst, static_cast(_Val), static_cast(_OFinal - _OFirst)); - return _OFinal; - } + const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); + const auto _Diff = static_cast(_OFinal - _OFirst); + _CSTD memset(_OFirst, static_cast(_Val), _Diff); + return _OFinal; } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { for (; _OFirst != _OLast; ++_OFirst) { _Construct_in_place(*_OFirst, _Val); @@ -558,7 +551,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if constexpr (_Fill_memset_is_safe<_It, _Ty>) { - _CSTD memset(_STD move(_UFirst), static_cast(_Val), _Count); + _CSTD memset(_UFirst, static_cast(_Val), _Count); _Seek_wrapped(_First, _UFirst + _Count); } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { for (; _Count > 0; --_Count, (void) ++_UFirst) { @@ -803,32 +796,6 @@ void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwd #ifdef __cpp_lib_concepts namespace ranges { - // clang-format off - template <_No_throw_forward_iterator _It, _No_throw_sentinel_for<_It> _Se> - requires default_initializable> - _It _Zero_range(const _It _First, const _Se _Last) { - // clang-format on - // fill [_First, _Last) with zeroes - if constexpr (is_same_v<_Se, _It>) { - char* const _First_ch = reinterpret_cast(_First); - char* const _Last_ch = reinterpret_cast(_Last); - _CSTD memset(_First_ch, 0, static_cast(_Last_ch - _First_ch)); - return _Last; - } else if constexpr (sized_sentinel_for<_Se, _It>) { - const _It _Final = _RANGES next(_First, _Last - _First); - char* const _First_ch = reinterpret_cast(_First); - char* const _Final_ch = reinterpret_cast(_Final); - _CSTD memset(_First_ch, 0, static_cast(_Final_ch - _First_ch)); - return _Final; - } else { - const _It _Final = _RANGES next(_First, _STD move(_Last)); - char* const _First_ch = reinterpret_cast(_First); - char* const _Final_ch = reinterpret_cast(_Final); - _CSTD memset(_First_ch, 0, static_cast(_Final_ch - _First_ch)); - return _Final; - } - } - // VARIABLE ranges::uninitialized_value_construct class _Uninitialized_value_construct_fn : private _Not_quite_object { public: @@ -866,7 +833,10 @@ namespace ranges { using _Ty = remove_reference_t>; if constexpr (_Use_memset_value_construct_v<_It>) { - return _RANGES _Zero_range(_OFirst, _OLast); + const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); + const auto _Diff = static_cast(_OFinal - _OFirst); + _CSTD memset(_OFirst, 0, _Diff); + return _OFinal; } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { for (; _OFirst != _OLast; ++_OFirst) { ::new (static_cast(_Unfancy(_OFirst))) _Ty{}; @@ -923,7 +893,8 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); if constexpr (_Use_memset_value_construct_v<_It>) { - _Seek_wrapped(_First, _RANGES _Zero_range(_UFirst, _UFirst + _Count)); + _CSTD memset(_UFirst, 0, static_cast(_Count)); + _Seek_wrapped(_First, _UFirst + _Count); } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { for (; _Count > 0; --_Count, (void) ++_UFirst) { ::new (static_cast(_Unfancy(_UFirst))) _Ty{}; From a995b007ff719440dbc4c5f81b4a1da1a7a0c02b Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 2 Sep 2020 21:07:58 +0200 Subject: [PATCH 07/23] Define and use voidify_iter --- stl/inc/memory | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 7d8b1045aba..a1dd647432c 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -626,6 +626,11 @@ _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { } // FUNCTION TEMPLATE uninitialized_default_construct +template +void* _Voidify_iter(_Iter _It) noexcept { + return const_cast(static_cast(_STD addressof(*_It))); +} + template void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // default-initialize all elements in [_First, _Last) @@ -635,7 +640,7 @@ void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowF _Uninitialized_backout _Backout{_Get_unwrapped(_First)}; for (const auto _ULast = _Get_unwrapped(_Last); _Backout._Last != _ULast; ++_Backout._Last) { - ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; + ::new (_Voidify_iter(_Backout._Last)) _Ty; } _Backout._Release(); @@ -685,14 +690,14 @@ namespace ranges { return _OFirst; } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { for (; _OFirst != _OLast; ++_OFirst) { - ::new (static_cast(_Unfancy(_OFirst))) _Ty; + ::new (_Voidify_iter(_OFirst)) _Ty; } return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; for (; _Backout._Last != _OLast; ++_Backout._Last) { - ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; + ::new (_Voidify_iter(_Backout._Last)) _Ty; } return _Backout._Release(); @@ -721,7 +726,7 @@ _NoThrowFwdIt uninitialized_default_construct_n(_NoThrowFwdIt _First, const _Dif _Uninitialized_backout _Backout{_Get_unwrapped_n(_First, _Count)}; for (; _Count > 0; ++_Backout._Last, (void) --_Count) { - ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; + ::new (_Voidify_iter(_Backout._Last)) _Ty; } _Seek_wrapped(_First, _Backout._Release()); @@ -752,7 +757,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped_n(_STD move(_First)); for (; _Count > 0; --_Count, (void) ++_UFirst) { - ::new (static_cast(_Unfancy(_UFirst))) _Ty; + ::new (_Voidify_iter(_UFirst)) _Ty; } _Seek_wrapped(_First, _STD move(_UFirst)); @@ -760,7 +765,7 @@ namespace ranges { _Uninitialized_backout _Backout{_Get_unwrapped_n(_STD move(_First), _Count)}; for (; _Count > 0; --_Count, (void) ++_Backout._Last) { - ::new (static_cast(_Unfancy(_Backout._Last))) _Ty; + ::new (_Voidify_iter(_Backout._Last)) _Ty; } _Seek_wrapped(_First, _STD move(_Backout._Release())); @@ -839,7 +844,7 @@ namespace ranges { return _OFinal; } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { for (; _OFirst != _OLast; ++_OFirst) { - ::new (static_cast(_Unfancy(_OFirst))) _Ty{}; + ::new (_Voidify_iter(_OFirst)) _Ty{}; } return _OFirst; @@ -897,7 +902,7 @@ namespace ranges { _Seek_wrapped(_First, _UFirst + _Count); } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { for (; _Count > 0; --_Count, (void) ++_UFirst) { - ::new (static_cast(_Unfancy(_UFirst))) _Ty{}; + ::new (_Voidify_iter(_UFirst)) _Ty{}; } _Seek_wrapped(_First, _STD move(_UFirst)); @@ -2873,7 +2878,7 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (static_cast(_Unfancy(_Constructor._Ptr))) _Refc(_Al); + ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al); shared_ptr<_Ty> _Ret; const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); @@ -2889,7 +2894,7 @@ _NODISCARD enable_if_t, shared_ptr<_Ty>> allocate_shared _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (static_cast(_Unfancy(_Constructor._Ptr))) _Refc(_Al, _Val); + ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al, _Val); shared_ptr<_Ty> _Ret; const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); From e2e3a32ad4d8b23f1d11de4bee63c280ba6f651a Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 2 Sep 2020 21:10:25 +0200 Subject: [PATCH 08/23] Fix derp --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index a1dd647432c..94a0f66eb20 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -754,7 +754,7 @@ namespace ranges { if constexpr (is_trivially_default_constructible_v<_Ty>) { _RANGES advance(_First, _Count); } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { - auto _UFirst = _Get_unwrapped_n(_STD move(_First)); + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); for (; _Count > 0; --_Count, (void) ++_UFirst) { ::new (_Voidify_iter(_UFirst)) _Ty; From c9258443c4c4d22b2c6955f9e61bd74b2bf5af87 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 2 Sep 2020 21:11:28 +0200 Subject: [PATCH 09/23] Only move once --- stl/inc/memory | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 94a0f66eb20..0d3c793ffd7 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -565,7 +565,7 @@ namespace ranges { _Backout._Emplace_back(_Val); } - _Seek_wrapped(_First, _STD move(_Backout._Release())); + _Seek_wrapped(_First, _Backout._Release()); } return _First; } @@ -768,7 +768,7 @@ namespace ranges { ::new (_Voidify_iter(_Backout._Last)) _Ty; } - _Seek_wrapped(_First, _STD move(_Backout._Release())); + _Seek_wrapped(_First, _Backout._Release()); } return _First; } @@ -913,7 +913,7 @@ namespace ranges { _Backout._Emplace_back(); } - _Seek_wrapped(_First, _STD move(_Backout._Release())); + _Seek_wrapped(_First, _Backout._Release()); } return _First; } From 5f5d1cbb38ece2a345632a2311ad605961cac2d3 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 4 Sep 2020 20:41:34 +0200 Subject: [PATCH 10/23] Fix missing increment --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index 0d3c793ffd7..5a1ddeaf9cf 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -616,7 +616,7 @@ _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { if constexpr (is_trivially_destructible_v<_Iter_value_t<_NoThrowFwdIt>>) { _STD advance(_UFirst, _Count); } else { - for (; _Count > 0; --_Count, (void) _UFirst) { + for (; _Count > 0; --_Count, (void) ++_UFirst) { _Destroy_in_place(*_UFirst); } } From b9ba5f7c0e9c7c4c2ba7b52f1723ebb741c3b220 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 4 Sep 2020 20:44:00 +0200 Subject: [PATCH 11/23] Use _Iter_ref-t? --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index 5a1ddeaf9cf..5f279820ea0 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -634,7 +634,7 @@ void* _Voidify_iter(_Iter _It) noexcept { template void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // default-initialize all elements in [_First, _Last) - using _Ty = remove_reference_t>; + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; _Adl_verify_range(_First, _Last); if constexpr (!is_trivially_default_constructible_v<_Ty>) { _Uninitialized_backout _Backout{_Get_unwrapped(_First)}; From 154ee95a058fb4a7a2ecd4e3fec60427acc70db3 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 16 Sep 2020 15:41:27 +0200 Subject: [PATCH 12/23] Expand uninitialized_copy test for possibly throwing copy construction --- .../test.cpp | 104 ++++++++++-------- 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp index 0f33c08eec7..2b5b6501d9b 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp @@ -26,6 +26,10 @@ STATIC_ASSERT(same_as{}, borr STATIC_ASSERT(same_as{}, borrowed{})), ranges::uninitialized_copy_result>); + +enum class CanThrowAtCopyConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -45,9 +49,11 @@ struct int_wrapper { ++constructions; } - int_wrapper(const int_wrapper& that) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper(const int_wrapper& that) noexcept(!static_cast(CanThrow)) { + if constexpr (CanThrow == CanThrowAtCopyConstruction::yes) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } } val = that.val; @@ -59,11 +65,8 @@ struct int_wrapper { } int_wrapper& operator=(const int_wrapper& that) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; - } - val = that.val; - return *this; + // Shall never be used as we construct in place + throw magic_throwing_val; } auto operator<=>(const int_wrapper&) const = default; @@ -86,6 +89,7 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { static constexpr int expected_output[] = {13, 55, 12345}; static constexpr int expected_input[] = {13, 55, 12345}; @@ -94,87 +98,101 @@ struct instantiator { static void call() { using ranges::uninitialized_copy, ranges::uninitialized_copy_result, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate range overload - int_wrapper input[3] = {13, 55, 12345}; + wrapper input[3] = {13, 55, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_copy(wrapped_input, wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } { // Validate iterator overload - int_wrapper input[3] = {13, 55, 12345}; + wrapper input[3] = {13, 55, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_copy( wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; struct throwing_test { - static constexpr int expected_input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + using wrapper = int_wrapper; + static constexpr int expected_input[] = {13, 55, wrapper::magic_throwing_val, 12345}; template static void call() { + // Validate only range overload (one is plenty since they both use the same backend) - int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + wrapper input[] = {13, 55, wrapper::magic_throwing_val, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { (void) ranges::uninitialized_copy(wrapped_input, wrapped_output); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == 2); - assert(int_wrapper::destructions == 2); - assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + assert(wrapper::constructions == 2); + assert(wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &wrapper::val)); } }; -template -using test_input = test::range; -using test_output = test::range; +template +using test_input = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, IsProxy>; +template +using test_output = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. - instantiator::call, test_output>(); - instantiator::call, test_output>(); - throwing_test::call, test_output>(); - throwing_test::call, test_output>(); + instantiator::call, + test_output>(); + instantiator::call< + test_input, + test_output>(); + instantiator::call, + test_output>(); + instantiator::call, + test_output>(); + + throwing_test::call, + test_output>(); + throwing_test::call, + test_output>(); } From adc4253f1406b98a66f3dbbdea783b6e7280b251 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 16 Sep 2020 23:17:09 +0200 Subject: [PATCH 13/23] unchecked_copy uses _Copy_memmove ... --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index 8f6001f6749..295caec008a 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -143,7 +143,7 @@ _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _ auto _UFirst = _Get_unwrapped_n(_First, _Count); auto _UDest = _Get_unwrapped_n(_Dest, _Count); if constexpr (_Ptr_copy_cat::_Really_trivial) { - _UDest = _Copy_memcpy(_UFirst, _UFirst + _Count, _UDest); + _UDest = _Copy_memmove(_UFirst, _UFirst + _Count, _UDest); } else { _Uninitialized_backout _Backout{_UDest}; From e4e1eb389f5e73000dd8bf4bd7a17229d3f5cc4b Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Thu, 17 Sep 2020 09:00:55 +0200 Subject: [PATCH 14/23] unname unused variable --- tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp index 2b5b6501d9b..5664847153c 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp @@ -64,7 +64,7 @@ struct int_wrapper { ++destructions; } - int_wrapper& operator=(const int_wrapper& that) { + int_wrapper& operator=(const int_wrapper&) { // Shall never be used as we construct in place throw magic_throwing_val; } From 80310358ea4f0b342690c490f6194aca5a547833 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Thu, 17 Sep 2020 14:38:41 +0200 Subject: [PATCH 15/23] Expand all the tests --- .../test.cpp | 3 +- .../test.cpp | 84 ++++++++------ .../test.cpp | 61 ++++++---- .../test.cpp | 51 +++++---- .../test.cpp | 65 ++++++----- .../test.cpp | 53 +++++---- .../test.cpp | 108 ++++++++++-------- .../test.cpp | 89 +++++++++------ .../test.cpp | 65 ++++++----- .../test.cpp | 53 +++++---- 10 files changed, 373 insertions(+), 259 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp index 5664847153c..5c0b1341c3d 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp @@ -26,7 +26,6 @@ STATIC_ASSERT(same_as{}, borr STATIC_ASSERT(same_as{}, borrowed{})), ranges::uninitialized_copy_result>); - enum class CanThrowAtCopyConstruction : bool { no, yes }; template @@ -66,7 +65,7 @@ struct int_wrapper { int_wrapper& operator=(const int_wrapper&) { // Shall never be used as we construct in place - throw magic_throwing_val; + throw magic_throwing_val + 1; } auto operator<=>(const int_wrapper&) const = default; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp index 6d8ea5adfba..ae09a975463 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp @@ -16,6 +16,9 @@ using namespace std; // Validate that uninitialized_copy_n_result aliases in_out_result STATIC_ASSERT(same_as, ranges::in_out_result>); +enum class CanThrowAtCopyConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -35,9 +38,11 @@ struct int_wrapper { ++constructions; } - int_wrapper(const int_wrapper& that) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper(const int_wrapper& that) noexcept(!static_cast(CanThrow)) { + if constexpr (CanThrow == CanThrowAtCopyConstruction::yes) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } } val = that.val; @@ -48,12 +53,9 @@ struct int_wrapper { ++destructions; } - int_wrapper& operator=(const int_wrapper& that) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; - } - val = that.val; - return *this; + int_wrapper& operator=(const int_wrapper&) { + // Shall never be used as we construct in place + throw magic_throwing_val + 1; } auto operator<=>(const int_wrapper&) const = default; @@ -76,6 +78,7 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { static constexpr int expected_output[] = {13, 55, 12345}; static constexpr int expected_input[] = {13, 55, 12345}; @@ -84,65 +87,78 @@ struct instantiator { static void call() { using ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate iterator overload - int_wrapper input[3] = {13, 55, 12345}; + wrapper input[3] = {13, 55, 12345}; Read wrapped_input{input}; - holder mem; + holder mem; Write wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; struct throwing_test { - static constexpr int expected_input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + using wrapper = int_wrapper; + static constexpr int expected_input[] = {13, 55, wrapper::magic_throwing_val, 12345}; template static void call() { - int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + wrapper input[] = {13, 55, wrapper::magic_throwing_val, 12345}; Read wrapped_input{input}; - holder mem; + holder mem; Write wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { (void) ranges::uninitialized_copy_n(wrapped_input.begin(), 4, wrapped_output.begin(), wrapped_output.end()); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == 2); - assert(int_wrapper::destructions == 2); + assert(wrapper::constructions == 2); + assert(wrapper::destructions == 2); } }; -template -using test_input = test::range; -using test_output = test::range; +template +using test_input = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, IsProxy>; +template +using test_output = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call, test_output>(); - instantiator::call, test_output>(); - throwing_test::call, test_output>(); - throwing_test::call, test_output>(); + instantiator::call, + test_output>(); + instantiator::call< + test_input, + test_output>(); + instantiator::call, + test_output>(); + instantiator::call, + test_output>(); + + throwing_test::call, + test_output>(); + throwing_test::call, + test_output>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp index 40c228e122c..688b57bf99a 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp @@ -16,6 +16,9 @@ using namespace std; // Validate dangling story STATIC_ASSERT(same_as{})), ranges::dangling>); +enum class CanThrowAtDefaultConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -28,9 +31,12 @@ struct int_wrapper { static constexpr int magic_throwing_val = 4; int val; - int_wrapper() { - if (++constructions == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper() noexcept(!static_cast(CanThrow)) { + ++constructions; + if constexpr (CanThrow == CanThrowAtDefaultConstruction::yes) { + if (constructions == magic_throwing_val) { + throw magic_throwing_val; + } } } @@ -40,7 +46,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable); +STATIC_ASSERT(default_initializable>); template struct holder { @@ -59,38 +65,40 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { template static void call() { using ranges::uninitialized_default_construct, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate range overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as> auto result = uninitialized_default_construct(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result == wrapped_input.end()); not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as> auto result = uninitialized_default_construct(wrapped_input.begin(), wrapped_input.end()); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result == wrapped_input.end()); not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; @@ -99,30 +107,33 @@ struct throwing_test { template static void call() { // Validate only range overload (one is plenty since they both use the same backend) - holder mem; + using wrapper = int_wrapper; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { (void) ranges::uninitialized_default_construct(wrapped_input); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); - assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + assert(wrapper::constructions == wrapper::magic_throwing_val); + assert(wrapper::destructions == wrapper::magic_throwing_val - 1); } }; -using test_range = test::range; +template +using test_range = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call(); - throwing_test::call(); + instantiator::call>(); + instantiator::call>(); + throwing_test::call>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp index 2f096938517..95dbb9071dc 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp @@ -13,6 +13,9 @@ using namespace std; +enum class CanThrowAtDefaultConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -25,9 +28,12 @@ struct int_wrapper { static constexpr int magic_throwing_val = 4; int val; - int_wrapper() { - if (++constructions == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper() noexcept(!static_cast(CanThrow)) { + ++constructions; + if constexpr (CanThrow == CanThrowAtDefaultConstruction::yes) { + if (constructions == magic_throwing_val) { + throw magic_throwing_val; + } } } @@ -37,7 +43,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable); +STATIC_ASSERT(default_initializable>); template struct holder { @@ -56,23 +62,25 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { template static void call() { using ranges::uninitialized_default_construct_n, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as> auto result = uninitialized_default_construct_n(wrapped_input.begin(), 3); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result == wrapped_input.end()); not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; @@ -80,30 +88,33 @@ struct instantiator { struct throwing_test { template static void call() { - holder mem; + using wrapper = int_wrapper; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { - (void) ranges::uninitialized_default_construct_n(wrapped_input.begin(), int_wrapper::magic_throwing_val); + (void) ranges::uninitialized_default_construct_n(wrapped_input.begin(), wrapper::magic_throwing_val); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); - assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + assert(wrapper::constructions == wrapper::magic_throwing_val); + assert(wrapper::destructions == wrapper::magic_throwing_val - 1); } }; -using test_range = test::range; +template +using test_range = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call(); - throwing_test::call(); + instantiator::call>(); + instantiator::call>(); + throwing_test::call>(); } 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 504798b2c93..b3982023d1f 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp @@ -16,6 +16,9 @@ using namespace std; // Validate dangling story STATIC_ASSERT(same_as{}, 42)), ranges::dangling>); +enum class CanThrowAtConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -30,9 +33,12 @@ struct int_wrapper { int_wrapper() = default; - int_wrapper(const int v) { - if (++constructions == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper(const int v) noexcept(!static_cast(CanThrow)) { + ++constructions; + if constexpr (CanThrow == CanThrowAtConstruction::yes) { + if (constructions == magic_throwing_val) { + throw magic_throwing_val; + } } val = v; } @@ -43,7 +49,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable); +STATIC_ASSERT(default_initializable>); template struct holder { @@ -62,42 +68,44 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { static constexpr int expected[3] = {42, 42, 42}; template static void call() { using ranges::uninitialized_fill, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate range overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as> auto result = uninitialized_fill(wrapped_input, 42); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as> auto result = uninitialized_fill(wrapped_input.begin(), wrapped_input.end(), 42); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; @@ -106,30 +114,33 @@ struct throwing_test { template static void call() { // Validate only range overload (one is plenty since they both use the same backend) - holder mem; + using wrapper = int_wrapper; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { (void) ranges::uninitialized_fill(wrapped_input, 42); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); - assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + assert(wrapper::constructions == wrapper::magic_throwing_val); + assert(wrapper::destructions == wrapper::magic_throwing_val - 1); } }; -using test_range = test::range; +template +using test_range = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call(); - throwing_test::call(); + instantiator::call>(); + instantiator::call>(); + throwing_test::call>(); } 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 96c5081ce1b..3852368e56d 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 @@ -13,6 +13,9 @@ using namespace std; +enum class CanThrowAtConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -27,9 +30,12 @@ struct int_wrapper { int_wrapper() = default; - int_wrapper(const int v) { - if (++constructions == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper(const int v) noexcept(!static_cast(CanThrow)) { + ++constructions; + if constexpr (CanThrow == CanThrowAtConstruction::yes) { + if (constructions == magic_throwing_val) { + throw magic_throwing_val; + } } val = v; } @@ -40,7 +46,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable); +STATIC_ASSERT(default_initializable>); template struct holder { @@ -59,26 +65,28 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { static constexpr int expected[3] = {42, 42, 42}; template static void call() { using ranges::uninitialized_fill_n, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + 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(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; @@ -86,30 +94,33 @@ struct instantiator { struct throwing_test { template static void call() { - holder mem; + using wrapper = int_wrapper; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { - (void) ranges::uninitialized_fill_n(wrapped_input.begin(), int_wrapper::magic_throwing_val, 42); + (void) ranges::uninitialized_fill_n(wrapped_input.begin(), wrapper::magic_throwing_val, 42); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); - assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + assert(wrapper::constructions == wrapper::magic_throwing_val); + assert(wrapper::destructions == wrapper::magic_throwing_val - 1); } }; -using test_range = test::range; +template +using test_range = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call(); - throwing_test::call(); + instantiator::call>(); + instantiator::call>(); + throwing_test::call>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp index 773378f42f4..eea98bcc7af 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp @@ -26,6 +26,9 @@ STATIC_ASSERT(same_as{}, borr STATIC_ASSERT(same_as{}, borrowed{})), ranges::uninitialized_move_result>); +enum class CanThrowAtMoveConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -45,9 +48,11 @@ struct int_wrapper { ++constructions; } - int_wrapper(int_wrapper&& that) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper(int_wrapper&& that) noexcept(!static_cast(CanThrow)) { + if constexpr (CanThrow == CanThrowAtMoveConstruction::yes) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } } val = exchange(that.val, -1); @@ -58,17 +63,15 @@ struct int_wrapper { ++destructions; } - int_wrapper& operator=(int_wrapper&& that) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; - } - val = exchange(that.val, -1); - return *this; + int_wrapper& operator=(int_wrapper&&) { + // Shall never be used as we construct in place + throw magic_throwing_val + 1; } auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(movable && !copyable); +STATIC_ASSERT( + movable> && !copyable>); template struct holder { @@ -87,6 +90,7 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { static constexpr int expected_output[] = {13, 55, 12345}; static constexpr int expected_input[] = {-1, -1, -1}; @@ -95,87 +99,99 @@ struct instantiator { static void call() { using ranges::uninitialized_move, ranges::uninitialized_move_result, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate range overload - int_wrapper input[3] = {13, 55, 12345}; + wrapper input[3] = {13, 55, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_move(wrapped_input, wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } { // Validate iterator overload - int_wrapper input[3] = {13, 55, 12345}; + wrapper input[3] = {13, 55, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_move( wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; struct throwing_test { - static constexpr int expected_input[] = {-1, -1, int_wrapper::magic_throwing_val, 12345}; + using wrapper = int_wrapper; + static constexpr int expected_input[] = {-1, -1, wrapper::magic_throwing_val, 12345}; template static void call() { // Validate only range overload (one is plenty since they both use the same backend) - int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + wrapper input[] = {13, 55, wrapper::magic_throwing_val, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { (void) ranges::uninitialized_move(wrapped_input, wrapped_output); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == 2); - assert(int_wrapper::destructions == 2); - assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + assert(wrapper::constructions == 2); + assert(wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &wrapper::val)); } }; -template -using test_input = test::range; -using test_output = test::range; - +template +using test_input = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, IsProxy>; +template +using test_output = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. - instantiator::call, test_output>(); - instantiator::call, test_output>(); - throwing_test::call, test_output>(); - throwing_test::call, test_output>(); + instantiator::call, + test_output>(); + instantiator::call< + test_input, + test_output>(); + instantiator::call, + test_output>(); + instantiator::call, + test_output>(); + + throwing_test::call, + test_output>(); + throwing_test::call, + test_output>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp index 01965c618c7..6b0cdca2393 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -16,6 +16,9 @@ using namespace std; // Validate that uninitialized_move_n_result aliases in_out_result STATIC_ASSERT(same_as, ranges::in_out_result>); +enum class CanThrowAtMoveConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -35,9 +38,11 @@ struct int_wrapper { ++constructions; } - int_wrapper(int_wrapper&& that) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper(int_wrapper&& that) noexcept(!static_cast(CanThrow)) { + if constexpr (CanThrow == CanThrowAtMoveConstruction::yes) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; + } } val = exchange(that.val, -1); @@ -48,17 +53,15 @@ struct int_wrapper { ++destructions; } - int_wrapper& operator=(int_wrapper&& that) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; - } - val = exchange(that.val, -1); - return *this; + int_wrapper& operator=(int_wrapper&&) { + // Shall never be used as we construct in place + throw magic_throwing_val + 1; } auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(movable && !copyable); +STATIC_ASSERT( + movable> && !copyable>); template struct holder { @@ -77,6 +80,7 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { static constexpr int expected_output[] = {13, 55, 12345}; static constexpr int expected_input[] = {-1, -1, -1}; @@ -85,66 +89,79 @@ struct instantiator { static void call() { using ranges::uninitialized_move_n, ranges::uninitialized_move_n_result, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate iterator overload - int_wrapper input[3] = {13, 55, 12345}; + wrapper input[3] = {13, 55, 12345}; Read wrapped_input{input}; - holder mem; + holder mem; Write wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; struct throwing_test { - static constexpr int expected_input[] = {-1, -1, int_wrapper::magic_throwing_val, 12345}; + using wrapper = int_wrapper; + static constexpr int expected_input[] = {-1, -1, wrapper::magic_throwing_val, 12345}; template static void call() { - int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; + wrapper input[] = {13, 55, wrapper::magic_throwing_val, 12345}; Read wrapped_input{input}; - holder mem; + holder mem; Write wrapped_output{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { (void) ranges::uninitialized_move_n(wrapped_input.begin(), 4, wrapped_output.begin(), wrapped_output.end()); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == 2); - assert(int_wrapper::destructions == 2); - assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); + assert(wrapper::constructions == 2); + assert(wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &wrapper::val)); } }; -template -using test_input = test::range; -using test_output = test::range; +template +using test_input = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, IsProxy>; +template +using test_output = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call, test_output>(); - instantiator::call, test_output>(); - throwing_test::call, test_output>(); - throwing_test::call, test_output>(); + instantiator::call, + test_output>(); + instantiator::call< + test_input, + test_output>(); + instantiator::call, + test_output>(); + instantiator::call, + test_output>(); + + throwing_test::call, + test_output>(); + throwing_test::call, + test_output>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp index 39d479a4823..86bca517be4 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp @@ -16,6 +16,9 @@ using namespace std; // Validate dangling story STATIC_ASSERT(same_as{})), ranges::dangling>); +enum class CanThrowAtDefaultConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -28,9 +31,12 @@ struct int_wrapper { static constexpr int magic_throwing_val = 4; int val = 10; - int_wrapper() { - if (++constructions == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper() noexcept(!static_cast(CanThrow)) { + ++constructions; + if constexpr (CanThrow == CanThrowAtDefaultConstruction::yes) { + if (constructions == magic_throwing_val) { + throw magic_throwing_val; + } } } @@ -40,7 +46,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable); +STATIC_ASSERT(default_initializable>); template struct holder { @@ -59,42 +65,44 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { static constexpr int expected[3] = {10, 10, 10}; template static void call() { using ranges::uninitialized_value_construct, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate range overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as> auto result = uninitialized_value_construct(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as> auto result = uninitialized_value_construct(wrapped_input.begin(), wrapped_input.end()); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; @@ -103,30 +111,33 @@ struct throwing_test { template static void call() { // Validate only range overload (one is plenty since they both use the same backend) - holder mem; + using wrapper = int_wrapper; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { (void) ranges::uninitialized_value_construct(wrapped_input); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); - assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + assert(wrapper::constructions == wrapper::magic_throwing_val); + assert(wrapper::destructions == wrapper::magic_throwing_val - 1); } }; -using test_range = test::range; +template +using test_range = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call(); - throwing_test::call(); + instantiator::call>(); + instantiator::call>(); + throwing_test::call>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp index 6a9f08449d8..e841c76657f 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp @@ -13,6 +13,9 @@ using namespace std; +enum class CanThrowAtDefaultConstruction : bool { no, yes }; + +template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -25,9 +28,12 @@ struct int_wrapper { static constexpr int magic_throwing_val = 4; int val = 10; - int_wrapper() { - if (++constructions == magic_throwing_val) { - throw magic_throwing_val; + int_wrapper() noexcept(!static_cast(CanThrow)) { + ++constructions; + if constexpr (CanThrow == CanThrowAtDefaultConstruction::yes) { + if (constructions == magic_throwing_val) { + throw magic_throwing_val; + } } } @@ -37,7 +43,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable); +STATIC_ASSERT(default_initializable>); template struct holder { @@ -56,26 +62,28 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } +template struct instantiator { static constexpr int expected[3] = {10, 10, 10}; template static void call() { using ranges::uninitialized_value_construct_n, ranges::equal, ranges::equal_to, ranges::iterator_t; + using wrapper = int_wrapper; { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); const same_as> auto result = uninitialized_value_construct_n(wrapped_input.begin(), 3); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(wrapper::constructions == 3); + assert(wrapper::destructions == 3); } } }; @@ -83,30 +91,33 @@ struct instantiator { struct throwing_test { template static void call() { - holder mem; + using wrapper = int_wrapper; + holder mem; Write wrapped_input{mem.as_span()}; - int_wrapper::clear_counts(); + wrapper::clear_counts(); try { - (void) ranges::uninitialized_value_construct_n(wrapped_input.begin(), int_wrapper::magic_throwing_val); + (void) ranges::uninitialized_value_construct_n(wrapped_input.begin(), wrapper::magic_throwing_val); assert(false); } catch (int i) { - assert(i == int_wrapper::magic_throwing_val); + assert(i == wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); - assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); + assert(wrapper::constructions == wrapper::magic_throwing_val); + assert(wrapper::destructions == wrapper::magic_throwing_val - 1); } }; -using test_range = test::range; +template +using test_range = test::range, test::Sized::no, test::CanDifference::no, + test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call(); - throwing_test::call(); + instantiator::call>(); + instantiator::call>(); + throwing_test::call>(); } From 03a412d4a73ca421fecf058f25612ff42729de75 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Thu, 17 Sep 2020 21:07:37 +0200 Subject: [PATCH 16/23] Remove unneeded specializations that are not better than _Backout --- stl/inc/memory | 45 --------- .../test.cpp | 96 +++++++----------- .../test.cpp | 75 ++++++-------- .../test.cpp | 61 +++++------- .../test.cpp | 51 ++++------ .../test.cpp | 65 +++++------- .../test.cpp | 53 ++++------ .../test.cpp | 99 ++++++++----------- .../test.cpp | 80 ++++++--------- .../test.cpp | 65 +++++------- .../test.cpp | 53 ++++------ 11 files changed, 277 insertions(+), 466 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 295caec008a..fe2b46a0ba9 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -109,11 +109,6 @@ namespace ranges { if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); - } else if constexpr (is_nothrow_constructible_v, iter_reference_t<_It>>) { - for (; _IFirst != _ILast && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { - _Construct_in_place(*_OFirst, *_IFirst); - } - return {_STD move(_IFirst), _STD move(_OFirst)}; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -219,10 +214,6 @@ namespace ranges { const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) { _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); - } else if constexpr (is_nothrow_constructible_v, iter_reference_t<_It>>) { - for (; _Count > 0 && _OFirst != _OLast; --_Count, (void) ++_IFirst, ++_OFirst) { - _Construct_in_place(*_OFirst, *_IFirst); - } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -310,11 +301,6 @@ namespace ranges { if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { return _Copy_memmove_common(_IFirst, _ILast, _OFirst, _OLast); - } else if constexpr (is_nothrow_constructible_v, iter_rvalue_reference_t<_It>>) { - for (; _IFirst != _ILast && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { - _Construct_in_place(*_OFirst, _RANGES iter_move(_IFirst)); - } - return {_STD move(_IFirst), _STD move(_OFirst)}; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -389,10 +375,6 @@ namespace ranges { const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { _OFirst = _Copy_memmove_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); - } else if constexpr (is_nothrow_constructible_v, iter_rvalue_reference_t<_It>>) { - for (; _Count > 0 && _OFirst != _OLast; ++_IFirst, (void) ++_OFirst) { - _Construct_in_place(*_OFirst, _RANGES iter_move(_IFirst)); - } } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -449,11 +431,6 @@ namespace ranges { const auto _Diff = static_cast(_OFinal - _OFirst); _CSTD memset(_OFirst, static_cast(_Val), _Diff); return _OFinal; - } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { - for (; _OFirst != _OLast; ++_OFirst) { - _Construct_in_place(*_OFirst, _Val); - } - return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -553,11 +530,6 @@ namespace ranges { if constexpr (_Fill_memset_is_safe<_It, _Ty>) { _Fill_memset(_UFirst, _Val, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); - } else if constexpr (is_nothrow_constructible_v, const _Ty&>) { - for (; _Count > 0; --_Count, (void) ++_UFirst) { - _Construct_in_place(*_UFirst, _Val); - } - _Seek_wrapped(_First, _STD move(_UFirst)); } else { _Uninitialized_backout _Backout{_STD move(_UFirst)}; @@ -688,11 +660,6 @@ namespace ranges { if constexpr (is_trivially_default_constructible_v<_Ty>) { _RANGES advance(_OFirst, _OLast); return _OFirst; - } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { - for (; _OFirst != _OLast; ++_OFirst) { - ::new (_Voidify_iter(_OFirst)) _Ty; - } - return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -842,12 +809,6 @@ namespace ranges { const auto _Count = static_cast(_OFinal - _OFirst); _CSTD memset(_OFirst, 0, _Count); return _OFinal; - } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { - for (; _OFirst != _OLast; ++_OFirst) { - ::new (_Voidify_iter(_OFirst)) _Ty{}; - } - - return _OFirst; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -900,12 +861,6 @@ namespace ranges { if constexpr (_Use_memset_value_construct_v<_It>) { _CSTD memset(_UFirst, 0, static_cast(_Count)); _Seek_wrapped(_First, _UFirst + _Count); - } else if constexpr (is_nothrow_default_constructible_v<_Ty>) { - for (; _Count > 0; --_Count, (void) ++_UFirst) { - ::new (_Voidify_iter(_UFirst)) _Ty{}; - } - - _Seek_wrapped(_First, _STD move(_UFirst)); } else { _Uninitialized_backout _Backout{_STD move(_UFirst)}; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp index 5c0b1341c3d..ae242436aa2 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp @@ -26,9 +26,6 @@ STATIC_ASSERT(same_as{}, borr STATIC_ASSERT(same_as{}, borrowed{})), ranges::uninitialized_copy_result>); -enum class CanThrowAtCopyConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -48,11 +45,9 @@ struct int_wrapper { ++constructions; } - int_wrapper(const int_wrapper& that) noexcept(!static_cast(CanThrow)) { - if constexpr (CanThrow == CanThrowAtCopyConstruction::yes) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper(const int_wrapper& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; } val = that.val; @@ -88,7 +83,6 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { static constexpr int expected_output[] = {13, 55, 12345}; static constexpr int expected_input[] = {13, 55, 12345}; @@ -97,101 +91,87 @@ struct instantiator { static void call() { using ranges::uninitialized_copy, ranges::uninitialized_copy_result, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate range overload - wrapper input[3] = {13, 55, 12345}; + int_wrapper input[3] = {13, 55, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_copy(wrapped_input, wrapped_output); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_output); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } { // Validate iterator overload - wrapper input[3] = {13, 55, 12345}; + int_wrapper input[3] = {13, 55, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_copy( wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_output); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; struct throwing_test { - using wrapper = int_wrapper; - static constexpr int expected_input[] = {13, 55, wrapper::magic_throwing_val, 12345}; + static constexpr int expected_input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; template static void call() { - // Validate only range overload (one is plenty since they both use the same backend) - wrapper input[] = {13, 55, wrapper::magic_throwing_val, 12345}; + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { (void) ranges::uninitialized_copy(wrapped_input, wrapped_output); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == 2); - assert(wrapper::destructions == 2); - assert(ranges::equal(input, expected_input, ranges::equal_to{}, &wrapper::val)); + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); } }; -template -using test_input = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, IsProxy>; -template -using test_output = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +template +using test_input = test::range; +using test_output = test::range; int main() { // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. - instantiator::call, - test_output>(); - instantiator::call< - test_input, - test_output>(); - instantiator::call, - test_output>(); - instantiator::call, - test_output>(); - - throwing_test::call, - test_output>(); - throwing_test::call, - test_output>(); + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp index ae09a975463..9e0f51612c2 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp @@ -16,9 +16,6 @@ using namespace std; // Validate that uninitialized_copy_n_result aliases in_out_result STATIC_ASSERT(same_as, ranges::in_out_result>); -enum class CanThrowAtCopyConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -38,11 +35,9 @@ struct int_wrapper { ++constructions; } - int_wrapper(const int_wrapper& that) noexcept(!static_cast(CanThrow)) { - if constexpr (CanThrow == CanThrowAtCopyConstruction::yes) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper(const int_wrapper& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; } val = that.val; @@ -78,7 +73,6 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { static constexpr int expected_output[] = {13, 55, 12345}; static constexpr int expected_input[] = {13, 55, 12345}; @@ -87,78 +81,65 @@ struct instantiator { static void call() { using ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate iterator overload - wrapper input[3] = {13, 55, 12345}; + int_wrapper input[3] = {13, 55, 12345}; Read wrapped_input{input}; - holder mem; + holder mem; Write wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_output); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; struct throwing_test { - using wrapper = int_wrapper; - static constexpr int expected_input[] = {13, 55, wrapper::magic_throwing_val, 12345}; + static constexpr int expected_input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; template static void call() { - wrapper input[] = {13, 55, wrapper::magic_throwing_val, 12345}; + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; Read wrapped_input{input}; - holder mem; + holder mem; Write wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { (void) ranges::uninitialized_copy_n(wrapped_input.begin(), 4, wrapped_output.begin(), wrapped_output.end()); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == 2); - assert(wrapper::destructions == 2); + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); } }; -template -using test_input = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, IsProxy>; -template -using test_output = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +template +using test_input = test::range; +using test_output = test::range; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call, - test_output>(); - instantiator::call< - test_input, - test_output>(); - instantiator::call, - test_output>(); - instantiator::call, - test_output>(); - - throwing_test::call, - test_output>(); - throwing_test::call, - test_output>(); + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp index 688b57bf99a..40c228e122c 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp @@ -16,9 +16,6 @@ using namespace std; // Validate dangling story STATIC_ASSERT(same_as{})), ranges::dangling>); -enum class CanThrowAtDefaultConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -31,12 +28,9 @@ struct int_wrapper { static constexpr int magic_throwing_val = 4; int val; - int_wrapper() noexcept(!static_cast(CanThrow)) { - ++constructions; - if constexpr (CanThrow == CanThrowAtDefaultConstruction::yes) { - if (constructions == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; } } @@ -46,7 +40,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable>); +STATIC_ASSERT(default_initializable); template struct holder { @@ -65,40 +59,38 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { template static void call() { using ranges::uninitialized_default_construct, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate range overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as> auto result = uninitialized_default_construct(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result == wrapped_input.end()); not_ranges_destroy(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as> auto result = uninitialized_default_construct(wrapped_input.begin(), wrapped_input.end()); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result == wrapped_input.end()); not_ranges_destroy(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; @@ -107,33 +99,30 @@ struct throwing_test { template static void call() { // Validate only range overload (one is plenty since they both use the same backend) - using wrapper = int_wrapper; - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { (void) ranges::uninitialized_default_construct(wrapped_input); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == wrapper::magic_throwing_val); - assert(wrapper::destructions == wrapper::magic_throwing_val - 1); + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); } }; -template -using test_range = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +using test_range = test::range; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call>(); - instantiator::call>(); - throwing_test::call>(); + instantiator::call(); + throwing_test::call(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp index 95dbb9071dc..2f096938517 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp @@ -13,9 +13,6 @@ using namespace std; -enum class CanThrowAtDefaultConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -28,12 +25,9 @@ struct int_wrapper { static constexpr int magic_throwing_val = 4; int val; - int_wrapper() noexcept(!static_cast(CanThrow)) { - ++constructions; - if constexpr (CanThrow == CanThrowAtDefaultConstruction::yes) { - if (constructions == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; } } @@ -43,7 +37,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable>); +STATIC_ASSERT(default_initializable); template struct holder { @@ -62,25 +56,23 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { template static void call() { using ranges::uninitialized_default_construct_n, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as> auto result = uninitialized_default_construct_n(wrapped_input.begin(), 3); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result == wrapped_input.end()); not_ranges_destroy(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; @@ -88,33 +80,30 @@ struct instantiator { struct throwing_test { template static void call() { - using wrapper = int_wrapper; - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { - (void) ranges::uninitialized_default_construct_n(wrapped_input.begin(), wrapper::magic_throwing_val); + (void) ranges::uninitialized_default_construct_n(wrapped_input.begin(), int_wrapper::magic_throwing_val); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == wrapper::magic_throwing_val); - assert(wrapper::destructions == wrapper::magic_throwing_val - 1); + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); } }; -template -using test_range = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +using test_range = test::range; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call>(); - instantiator::call>(); - throwing_test::call>(); + instantiator::call(); + throwing_test::call(); } 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 b3982023d1f..504798b2c93 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp @@ -16,9 +16,6 @@ using namespace std; // Validate dangling story STATIC_ASSERT(same_as{}, 42)), ranges::dangling>); -enum class CanThrowAtConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -33,12 +30,9 @@ struct int_wrapper { int_wrapper() = default; - int_wrapper(const int v) noexcept(!static_cast(CanThrow)) { - ++constructions; - if constexpr (CanThrow == CanThrowAtConstruction::yes) { - if (constructions == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper(const int v) { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; } val = v; } @@ -49,7 +43,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable>); +STATIC_ASSERT(default_initializable); template struct holder { @@ -68,44 +62,42 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { static constexpr int expected[3] = {42, 42, 42}; template static void call() { using ranges::uninitialized_fill, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate range overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as> auto result = uninitialized_fill(wrapped_input, 42); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as> auto result = uninitialized_fill(wrapped_input.begin(), wrapped_input.end(), 42); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; @@ -114,33 +106,30 @@ struct throwing_test { template static void call() { // Validate only range overload (one is plenty since they both use the same backend) - using wrapper = int_wrapper; - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { (void) ranges::uninitialized_fill(wrapped_input, 42); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == wrapper::magic_throwing_val); - assert(wrapper::destructions == wrapper::magic_throwing_val - 1); + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); } }; -template -using test_range = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +using test_range = test::range; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call>(); - instantiator::call>(); - throwing_test::call>(); + instantiator::call(); + throwing_test::call(); } 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 3852368e56d..96c5081ce1b 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 @@ -13,9 +13,6 @@ using namespace std; -enum class CanThrowAtConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -30,12 +27,9 @@ struct int_wrapper { int_wrapper() = default; - int_wrapper(const int v) noexcept(!static_cast(CanThrow)) { - ++constructions; - if constexpr (CanThrow == CanThrowAtConstruction::yes) { - if (constructions == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper(const int v) { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; } val = v; } @@ -46,7 +40,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable>); +STATIC_ASSERT(default_initializable); template struct holder { @@ -65,28 +59,26 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { static constexpr int expected[3] = {42, 42, 42}; template static void call() { using ranges::uninitialized_fill_n, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as> auto result = uninitialized_fill_n(wrapped_input.begin(), 3, 42); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; @@ -94,33 +86,30 @@ struct instantiator { struct throwing_test { template static void call() { - using wrapper = int_wrapper; - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { - (void) ranges::uninitialized_fill_n(wrapped_input.begin(), wrapper::magic_throwing_val, 42); + (void) ranges::uninitialized_fill_n(wrapped_input.begin(), int_wrapper::magic_throwing_val, 42); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == wrapper::magic_throwing_val); - assert(wrapper::destructions == wrapper::magic_throwing_val - 1); + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); } }; -template -using test_range = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +using test_range = test::range; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call>(); - instantiator::call>(); - throwing_test::call>(); + instantiator::call(); + throwing_test::call(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp index eea98bcc7af..74abb7599f5 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp @@ -26,9 +26,6 @@ STATIC_ASSERT(same_as{}, borr STATIC_ASSERT(same_as{}, borrowed{})), ranges::uninitialized_move_result>); -enum class CanThrowAtMoveConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -48,11 +45,9 @@ struct int_wrapper { ++constructions; } - int_wrapper(int_wrapper&& that) noexcept(!static_cast(CanThrow)) { - if constexpr (CanThrow == CanThrowAtMoveConstruction::yes) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper(int_wrapper&& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; } val = exchange(that.val, -1); @@ -70,8 +65,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT( - movable> && !copyable>); +STATIC_ASSERT(movable && !copyable); template struct holder { @@ -90,7 +84,6 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { static constexpr int expected_output[] = {13, 55, 12345}; static constexpr int expected_input[] = {-1, -1, -1}; @@ -99,99 +92,87 @@ struct instantiator { static void call() { using ranges::uninitialized_move, ranges::uninitialized_move_result, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate range overload - wrapper input[3] = {13, 55, 12345}; + int_wrapper input[3] = {13, 55, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_move(wrapped_input, wrapped_output); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_output); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } { // Validate iterator overload - wrapper input[3] = {13, 55, 12345}; + int_wrapper input[3] = {13, 55, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_move( wrapped_input.begin(), wrapped_input.end(), wrapped_output.begin(), wrapped_output.end()); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_output); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; struct throwing_test { - using wrapper = int_wrapper; - static constexpr int expected_input[] = {-1, -1, wrapper::magic_throwing_val, 12345}; + static constexpr int expected_input[] = {-1, -1, int_wrapper::magic_throwing_val, 12345}; template static void call() { // Validate only range overload (one is plenty since they both use the same backend) - wrapper input[] = {13, 55, wrapper::magic_throwing_val, 12345}; + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; R wrapped_input{input}; - holder mem; + holder mem; W wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { (void) ranges::uninitialized_move(wrapped_input, wrapped_output); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == 2); - assert(wrapper::destructions == 2); - assert(ranges::equal(input, expected_input, ranges::equal_to{}, &wrapper::val)); + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); } }; -template -using test_input = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, IsProxy>; -template -using test_output = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +template +using test_input = test::range; +using test_output = test::range; + int main() { // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. - instantiator::call, - test_output>(); - instantiator::call< - test_input, - test_output>(); - instantiator::call, - test_output>(); - instantiator::call, - test_output>(); - - throwing_test::call, - test_output>(); - throwing_test::call, - test_output>(); + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp index 6b0cdca2393..b41b3388c86 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -16,9 +16,6 @@ using namespace std; // Validate that uninitialized_move_n_result aliases in_out_result STATIC_ASSERT(same_as, ranges::in_out_result>); -enum class CanThrowAtMoveConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -38,11 +35,9 @@ struct int_wrapper { ++constructions; } - int_wrapper(int_wrapper&& that) noexcept(!static_cast(CanThrow)) { - if constexpr (CanThrow == CanThrowAtMoveConstruction::yes) { - if (that.val == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper(int_wrapper&& that) { + if (that.val == magic_throwing_val) { + throw magic_throwing_val; } val = exchange(that.val, -1); @@ -60,8 +55,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT( - movable> && !copyable>); +STATIC_ASSERT(movable && !copyable); template struct holder { @@ -80,7 +74,6 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { static constexpr int expected_output[] = {13, 55, 12345}; static constexpr int expected_input[] = {-1, -1, -1}; @@ -89,79 +82,66 @@ struct instantiator { static void call() { using ranges::uninitialized_move_n, ranges::uninitialized_move_n_result, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate iterator overload - wrapper input[3] = {13, 55, 12345}; + int_wrapper input[3] = {13, 55, 12345}; Read wrapped_input{input}; - holder mem; + holder mem; Write wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as, iterator_t>> auto result = uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result.in == wrapped_input.end()); assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &wrapper::val)); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_output); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; struct throwing_test { - using wrapper = int_wrapper; - static constexpr int expected_input[] = {-1, -1, wrapper::magic_throwing_val, 12345}; + static constexpr int expected_input[] = {-1, -1, int_wrapper::magic_throwing_val, 12345}; template static void call() { - wrapper input[] = {13, 55, wrapper::magic_throwing_val, 12345}; + int_wrapper input[] = {13, 55, int_wrapper::magic_throwing_val, 12345}; Read wrapped_input{input}; - holder mem; + holder mem; Write wrapped_output{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { (void) ranges::uninitialized_move_n(wrapped_input.begin(), 4, wrapped_output.begin(), wrapped_output.end()); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == 2); - assert(wrapper::destructions == 2); - assert(ranges::equal(input, expected_input, ranges::equal_to{}, &wrapper::val)); + assert(int_wrapper::constructions == 2); + assert(int_wrapper::destructions == 2); + assert(ranges::equal(input, expected_input, ranges::equal_to{}, &int_wrapper::val)); } }; -template -using test_input = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, IsProxy>; -template -using test_output = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +template +using test_input = test::range; +using test_output = test::range; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call, - test_output>(); - instantiator::call< - test_input, - test_output>(); - instantiator::call, - test_output>(); - instantiator::call, - test_output>(); - - throwing_test::call, - test_output>(); - throwing_test::call, - test_output>(); + instantiator::call, test_output>(); + instantiator::call, test_output>(); + throwing_test::call, test_output>(); + throwing_test::call, test_output>(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp index 86bca517be4..39d479a4823 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp @@ -16,9 +16,6 @@ using namespace std; // Validate dangling story STATIC_ASSERT(same_as{})), ranges::dangling>); -enum class CanThrowAtDefaultConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -31,12 +28,9 @@ struct int_wrapper { static constexpr int magic_throwing_val = 4; int val = 10; - int_wrapper() noexcept(!static_cast(CanThrow)) { - ++constructions; - if constexpr (CanThrow == CanThrowAtDefaultConstruction::yes) { - if (constructions == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; } } @@ -46,7 +40,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable>); +STATIC_ASSERT(default_initializable); template struct holder { @@ -65,44 +59,42 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { static constexpr int expected[3] = {10, 10, 10}; template static void call() { using ranges::uninitialized_value_construct, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate range overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as> auto result = uninitialized_value_construct(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as> auto result = uninitialized_value_construct(wrapped_input.begin(), wrapped_input.end()); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; @@ -111,33 +103,30 @@ struct throwing_test { template static void call() { // Validate only range overload (one is plenty since they both use the same backend) - using wrapper = int_wrapper; - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { (void) ranges::uninitialized_value_construct(wrapped_input); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == wrapper::magic_throwing_val); - assert(wrapper::destructions == wrapper::magic_throwing_val - 1); + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); } }; -template -using test_range = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +using test_range = test::range; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call>(); - instantiator::call>(); - throwing_test::call>(); + instantiator::call(); + throwing_test::call(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp index e841c76657f..6a9f08449d8 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct_n/test.cpp @@ -13,9 +13,6 @@ using namespace std; -enum class CanThrowAtDefaultConstruction : bool { no, yes }; - -template struct int_wrapper { inline static int constructions = 0; inline static int destructions = 0; @@ -28,12 +25,9 @@ struct int_wrapper { static constexpr int magic_throwing_val = 4; int val = 10; - int_wrapper() noexcept(!static_cast(CanThrow)) { - ++constructions; - if constexpr (CanThrow == CanThrowAtDefaultConstruction::yes) { - if (constructions == magic_throwing_val) { - throw magic_throwing_val; - } + int_wrapper() { + if (++constructions == magic_throwing_val) { + throw magic_throwing_val; } } @@ -43,7 +37,7 @@ struct int_wrapper { auto operator<=>(const int_wrapper&) const = default; }; -STATIC_ASSERT(default_initializable>); +STATIC_ASSERT(default_initializable); template struct holder { @@ -62,28 +56,26 @@ void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy } } -template struct instantiator { static constexpr int expected[3] = {10, 10, 10}; template static void call() { using ranges::uninitialized_value_construct_n, ranges::equal, ranges::equal_to, ranges::iterator_t; - using wrapper = int_wrapper; { // Validate iterator overload - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); const same_as> auto result = uninitialized_value_construct_n(wrapped_input.begin(), 3); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 0); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); assert(result == wrapped_input.end()); - assert(equal(wrapped_input, expected, equal_to{}, &wrapper::val)); + assert(equal(wrapped_input, expected, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_input); - assert(wrapper::constructions == 3); - assert(wrapper::destructions == 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } } }; @@ -91,33 +83,30 @@ struct instantiator { struct throwing_test { template static void call() { - using wrapper = int_wrapper; - holder mem; + holder mem; Write wrapped_input{mem.as_span()}; - wrapper::clear_counts(); + int_wrapper::clear_counts(); try { - (void) ranges::uninitialized_value_construct_n(wrapped_input.begin(), wrapper::magic_throwing_val); + (void) ranges::uninitialized_value_construct_n(wrapped_input.begin(), int_wrapper::magic_throwing_val); assert(false); } catch (int i) { - assert(i == wrapper::magic_throwing_val); + assert(i == int_wrapper::magic_throwing_val); } catch (...) { assert(false); } - assert(wrapper::constructions == wrapper::magic_throwing_val); - assert(wrapper::destructions == wrapper::magic_throwing_val - 1); + assert(int_wrapper::constructions == int_wrapper::magic_throwing_val); + assert(int_wrapper::destructions == int_wrapper::magic_throwing_val - 1); } }; -template -using test_range = test::range, test::Sized::no, test::CanDifference::no, - test::Common::no, test::CanCompare::yes, test::ProxyRef::no>; +using test_range = test::range; int main() { // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it // requires non-proxy references for the input range. - instantiator::call>(); - instantiator::call>(); - throwing_test::call>(); + instantiator::call(); + throwing_test::call(); } From fec98ef4db8fed2eb48c04c3d93f984353eb9e9e Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Thu, 17 Sep 2020 22:47:56 +0200 Subject: [PATCH 17/23] Address review comments --- stl/inc/memory | 3 -- stl/inc/xutility | 8 ++-- .../test.cpp | 3 +- .../test.cpp | 39 +++++++++---------- .../test.cpp | 1 + .../test.cpp | 24 ++++++------ .../test.cpp | 1 + .../test.cpp | 26 ++++++------- .../test.cpp | 3 +- .../test.cpp | 39 +++++++++---------- .../test.cpp | 1 + 11 files changed, 68 insertions(+), 80 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index fe2b46a0ba9..bc6bf81dfd0 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -803,7 +803,6 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_Se, _It>); _STL_INTERNAL_STATIC_ASSERT(default_initializable>); - using _Ty = remove_reference_t>; if constexpr (_Use_memset_value_construct_v<_It>) { const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast)); const auto _Count = static_cast(_OFinal - _OFirst); @@ -851,8 +850,6 @@ namespace ranges { requires default_initializable> _It operator()(_It _First, iter_difference_t<_It> _Count) const { // clang-format on - - using _Ty = remove_reference_t>; if (_Count <= 0) { return _First; } diff --git a/stl/inc/xutility b/stl/inc/xutility index b703e94d2fe..015232831af 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4379,23 +4379,23 @@ _OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _O } template -_OutIt _Copy_memmove_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) { +_OutIt _Copy_memmove_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { const char* const _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); const char* const _ILast_ch = const_cast(reinterpret_cast(_ILast)); char* const _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); const char* const _OLast_ch = const_cast(reinterpret_cast(_OLast)); - const auto _Count = static_cast(min(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + const auto _Count = static_cast(_STD min(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); _CSTD memmove(_OFirst_ch, _IFirst_ch, _Count); return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); } template -_OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) { +_OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { const char* const _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); const char* const _ILast_ch = const_cast(reinterpret_cast(_ILast)); char* const _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); const char* const _OLast_ch = const_cast(reinterpret_cast(_OLast)); - const auto _Count = static_cast(min(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + const auto _Count = static_cast(_STD min(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); } diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp index ae242436aa2..bc42814e2fd 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp @@ -59,8 +59,7 @@ struct int_wrapper { } int_wrapper& operator=(const int_wrapper&) { - // Shall never be used as we construct in place - throw magic_throwing_val + 1; + abort(); } auto operator<=>(const int_wrapper&) const = default; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp index 9e0f51612c2..4605f3f3b69 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp @@ -49,8 +49,7 @@ struct int_wrapper { } int_wrapper& operator=(const int_wrapper&) { - // Shall never be used as we construct in place - throw magic_throwing_val + 1; + abort(); } auto operator<=>(const int_wrapper&) const = default; @@ -82,25 +81,23 @@ struct instantiator { using ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal, ranges::equal_to, ranges::iterator_t; - { // Validate iterator overload - int_wrapper input[3] = {13, 55, 12345}; - Read wrapped_input{input}; - holder mem; - Write wrapped_output{mem.as_span()}; - - int_wrapper::clear_counts(); - const same_as, iterator_t>> auto result = - uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); - assert(result.in == wrapped_input.end()); - assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); - not_ranges_destroy(wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); - } + int_wrapper input[3] = {13, 55, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = + uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp index 40c228e122c..2f99b0aef75 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct/test.cpp @@ -14,6 +14,7 @@ using namespace std; // Validate dangling story +STATIC_ASSERT(same_as{})), int*>); STATIC_ASSERT(same_as{})), ranges::dangling>); struct int_wrapper { diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp index 2f096938517..d28eefede3c 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_default_construct_n/test.cpp @@ -61,19 +61,17 @@ struct instantiator { static void call() { using ranges::uninitialized_default_construct_n, ranges::equal, ranges::equal_to, ranges::iterator_t; - { // Validate iterator overload - holder mem; - Write wrapped_input{mem.as_span()}; - - int_wrapper::clear_counts(); - const same_as> auto result = uninitialized_default_construct_n(wrapped_input.begin(), 3); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); - assert(result == wrapped_input.end()); - not_ranges_destroy(wrapped_input); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); - } + holder mem; + Write wrapped_input{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as> auto result = uninitialized_default_construct_n(wrapped_input.begin(), 3); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result == wrapped_input.end()); + not_ranges_destroy(wrapped_input); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } }; 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 504798b2c93..1defdd193d2 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp @@ -14,6 +14,7 @@ using namespace std; // Validate dangling story +STATIC_ASSERT(same_as{}, 42)), int*>); STATIC_ASSERT(same_as{}, 42)), ranges::dangling>); struct int_wrapper { 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 96c5081ce1b..97da0b88fd1 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,20 +66,18 @@ struct instantiator { static void call() { using ranges::uninitialized_fill_n, ranges::equal, ranges::equal_to, ranges::iterator_t; - { // Validate iterator overload - 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); - } + 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); } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp index 74abb7599f5..ad979982ddf 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp @@ -59,8 +59,7 @@ struct int_wrapper { } int_wrapper& operator=(int_wrapper&&) { - // Shall never be used as we construct in place - throw magic_throwing_val + 1; + abort(); } auto operator<=>(const int_wrapper&) const = default; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp index b41b3388c86..aa3a57229ee 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -49,8 +49,7 @@ struct int_wrapper { } int_wrapper& operator=(int_wrapper&&) { - // Shall never be used as we construct in place - throw magic_throwing_val + 1; + abort(); } auto operator<=>(const int_wrapper&) const = default; @@ -83,25 +82,23 @@ struct instantiator { using ranges::uninitialized_move_n, ranges::uninitialized_move_n_result, ranges::equal, ranges::equal_to, ranges::iterator_t; - { // Validate iterator overload - int_wrapper input[3] = {13, 55, 12345}; - Read wrapped_input{input}; - holder mem; - Write wrapped_output{mem.as_span()}; - - int_wrapper::clear_counts(); - const same_as, iterator_t>> auto result = - uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 0); - assert(result.in == wrapped_input.end()); - assert(result.out == wrapped_output.end()); - assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); - assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); - not_ranges_destroy(wrapped_output); - assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); - } + int_wrapper input[3] = {13, 55, 12345}; + Read wrapped_input{input}; + holder mem; + Write wrapped_output{mem.as_span()}; + + int_wrapper::clear_counts(); + const same_as, iterator_t>> auto result = + uninitialized_move_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end()); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 0); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.end()); + assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val)); + assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); + not_ranges_destroy(wrapped_output); + assert(int_wrapper::constructions == 3); + assert(int_wrapper::destructions == 3); } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp index 39d479a4823..a17ede367c5 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_value_construct/test.cpp @@ -14,6 +14,7 @@ using namespace std; // Validate dangling story +STATIC_ASSERT(same_as{})), int*>); STATIC_ASSERT(same_as{})), ranges::dangling>); struct int_wrapper { From b1eaed6a9608eb609bd5e02f416557d9820653f6 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Thu, 17 Sep 2020 23:01:38 +0200 Subject: [PATCH 18/23] Thanks vscode --- .../std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp index aa3a57229ee..b15ee30281c 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -98,7 +98,7 @@ struct instantiator { assert(equal(input, expected_input, equal_to{}, &int_wrapper::val)); not_ranges_destroy(wrapped_output); assert(int_wrapper::constructions == 3); - assert(int_wrapper::destructions == 3); + assert(int_wrapper::destructions == 3); } }; From aaccea9b2d160ffe6830222e4f8c5ef532fe3a89 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 17 Sep 2020 15:01:20 -0700 Subject: [PATCH 19/23] Add macro-defense parentheses. --- stl/inc/xutility | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 015232831af..2ea70898d14 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4384,7 +4384,7 @@ _OutIt _Copy_memmove_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt const char* const _ILast_ch = const_cast(reinterpret_cast(_ILast)); char* const _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); const char* const _OLast_ch = const_cast(reinterpret_cast(_OLast)); - const auto _Count = static_cast(_STD min(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); _CSTD memmove(_OFirst_ch, _IFirst_ch, _Count); return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); } @@ -4395,7 +4395,7 @@ _OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _ const char* const _ILast_ch = const_cast(reinterpret_cast(_ILast)); char* const _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); const char* const _OLast_ch = const_cast(reinterpret_cast(_OLast)); - const auto _Count = static_cast(_STD min(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); } From 7f31e9e3eaff0feeb61f72088e2c5a38a5cb5d23 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 18 Sep 2020 09:13:12 +0200 Subject: [PATCH 20/23] Apply suggestions from code review Co-authored-by: Stephan T. Lavavej --- stl/inc/memory | 2 +- stl/inc/xutility | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index bc6bf81dfd0..fc38d3b134d 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -599,7 +599,7 @@ _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) { // FUNCTION TEMPLATE uninitialized_default_construct template -void* _Voidify_iter(_Iter _It) noexcept { +_NODISCARD void* _Voidify_iter(_Iter _It) noexcept { return const_cast(static_cast(_STD addressof(*_It))); } diff --git a/stl/inc/xutility b/stl/inc/xutility index 2ea70898d14..8caa611dabf 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4380,22 +4380,22 @@ _OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _O template _OutIt _Copy_memmove_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { - const char* const _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); - const char* const _ILast_ch = const_cast(reinterpret_cast(_ILast)); - char* const _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); - const char* const _OLast_ch = const_cast(reinterpret_cast(_OLast)); - const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); + const auto _ILast_ch = const_cast(reinterpret_cast(_ILast)); + const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); + const auto _OLast_ch = const_cast(reinterpret_cast(_OLast)); + const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); _CSTD memmove(_OFirst_ch, _IFirst_ch, _Count); return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); } template _OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { - const char* const _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); - const char* const _ILast_ch = const_cast(reinterpret_cast(_ILast)); - char* const _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); - const char* const _OLast_ch = const_cast(reinterpret_cast(_OLast)); - const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); + const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); + const auto _ILast_ch = const_cast(reinterpret_cast(_ILast)); + const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); + const auto _OLast_ch = const_cast(reinterpret_cast(_OLast)); + const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); _CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count); return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); } From 3b7e991563e781abcde97cc3f7a5de6aa542c55f Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 18 Sep 2020 09:33:54 +0200 Subject: [PATCH 21/23] Address review comments --- stl/inc/memory | 6 +++--- stl/inc/xutility | 11 ----------- .../P0896R4_ranges_alg_uninitialized_copy/test.cpp | 1 + .../P0896R4_ranges_alg_uninitialized_copy_n/test.cpp | 5 +++-- .../P0896R4_ranges_alg_uninitialized_move/test.cpp | 1 + .../P0896R4_ranges_alg_uninitialized_move_n/test.cpp | 1 + 6 files changed, 9 insertions(+), 16 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index fc38d3b134d..d32be98cb0f 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -299,8 +299,8 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_rvalue_reference_t<_It>>); - if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) { - return _Copy_memmove_common(_IFirst, _ILast, _OFirst, _OLast); + if constexpr (is_same_v<_Se, _It> && _Ptr_move_cat<_It, _Out>::_Really_trivial) { + return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; @@ -374,7 +374,7 @@ namespace ranges { auto _OFirst = _Get_unwrapped(_STD move(_First2)); const auto _OLast = _Get_unwrapped(_STD move(_Last2)); if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) { - _OFirst = _Copy_memmove_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); + _OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast); } else { _Uninitialized_backout _Backout{_STD move(_OFirst)}; diff --git a/stl/inc/xutility b/stl/inc/xutility index 8caa611dabf..0a402f4d210 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4378,17 +4378,6 @@ _OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _O return _Copy_memmove(_First.base(), _Last.base(), _Dest); } -template -_OutIt _Copy_memmove_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { - const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); - const auto _ILast_ch = const_cast(reinterpret_cast(_ILast)); - const auto _OFirst_ch = const_cast(reinterpret_cast(_OFirst)); - const auto _OLast_ch = const_cast(reinterpret_cast(_OLast)); - const auto _Count = static_cast((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch)); - _CSTD memmove(_OFirst_ch, _IFirst_ch, _Count); - return reinterpret_cast<_OutIt>(_OFirst_ch + _Count); -} - template _OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept { const auto _IFirst_ch = const_cast(reinterpret_cast(_IFirst)); diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp index bc42814e2fd..f2c607162fe 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp index 4605f3f3b69..9e86c952d8d 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -132,8 +133,8 @@ using test_output = test::range; int main() { - // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it - // requires non-proxy references for the input range. + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. instantiator::call, test_output>(); instantiator::call, test_output>(); diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp index ad979982ddf..736a6cb9340 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp index b15ee30281c..07db174dde5 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include From 282f1b3e8abcb8ab7f2701edad80ff6f1c60883c Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 18 Sep 2020 09:46:17 +0200 Subject: [PATCH 22/23] Saving a file helps... --- .../tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp index 07db174dde5..eef82b952c4 100644 --- a/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_uninitialized_move_n/test.cpp @@ -135,8 +135,8 @@ using test_output = test::range; int main() { - // The algorithm is oblivious to non-required category, size, difference. It _is_ sensitive to proxyness in that it - // requires non-proxy references for the input range. + // The algorithm is oblivious to non-required category, size, difference, and "proxyness" of the input range. It + // _is_ sensitive to proxyness in that it requires non-proxy references for the output range. instantiator::call, test_output>(); instantiator::call, test_output>(); From 13978292c43d15dd1ea97f75d9eea3aa23fb80b2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 19 Sep 2020 03:53:12 -0700 Subject: [PATCH 23/23] Use _Fill_memset for correctness Co-authored-by: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> --- stl/inc/memory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/memory b/stl/inc/memory index d32be98cb0f..af520a73cf4 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -429,7 +429,7 @@ 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); - _CSTD memset(_OFirst, static_cast(_Val), _Diff); + _Fill_memset(_OFirst, _Val, _Diff); return _OFinal; } else { _Uninitialized_backout _Backout{_STD move(_OFirst)};