From 2ab5b2d8a995c6c6ae3f58cfe72a23f65675f4e5 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 8 Oct 2022 11:46:05 +0800 Subject: [PATCH 01/30] Test files for parallel memory algorithms --- .../env.lst | 4 + .../test.cpp | 229 ++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 tests/std/tests/P0040R3_parallel_memory_algorithms/env.lst create mode 100644 tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/env.lst b/tests/std/tests/P0040R3_parallel_memory_algorithms/env.lst new file mode 100644 index 00000000000..1f3dc81ee8b --- /dev/null +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\native_17_matrix.lst diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp new file mode 100644 index 00000000000..f1b7076e2b5 --- /dev/null +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -0,0 +1,229 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace std::execution; + +class wrap_uchar { +private: + unsigned char ch_ = 42; + +public: + bool is_expected() const noexcept { + return ch_ == 42; + } +}; + +static_assert(sizeof(wrap_uchar) == 1); + +const auto expectation = [](const wrap_uchar& x) { return x.is_expected(); }; + +struct test_case_uninitialized_default_construct_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + const auto begin_it = reinterpret_cast(buffer.get()); + const auto end_it = begin_it + testSize; + uninitialized_default_construct(exec, begin_it, end_it); + assert(all_of(begin_it, end_it, expectation)); + } +}; + +struct test_case_uninitialized_default_construct_n_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + const auto begin_it = reinterpret_cast(buffer.get()); + const auto end_it = begin_it + testSize; + const auto result_it = uninitialized_default_construct_n(exec, begin_it, testSize); + assert(all_of(begin_it, end_it, expectation)); + assert(end_it == result_it); + } +}; + +struct test_case_uninitialized_value_construct_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + const auto begin_it = reinterpret_cast(buffer.get()); + const auto end_it = begin_it + testSize; + uninitialized_value_construct(exec, begin_it, end_it); + assert(all_of(begin_it, end_it, expectation)); + } +}; + +struct test_case_uninitialized_value_construct_n_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + const auto begin_it = reinterpret_cast(buffer.get()); + const auto end_it = begin_it + testSize; + const auto result_it = uninitialized_value_construct_n(exec, begin_it, testSize); + assert(all_of(begin_it, end_it, expectation)); + assert(end_it == result_it); + } +}; + +struct test_case_destroy_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + const auto begin_it = reinterpret_cast(buffer.get()); + const auto end_it = begin_it + testSize; + + uninitialized_default_construct(begin_it, end_it); + destroy(exec, begin_it, end_it); + } +}; + +struct test_case_destroy_n_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + const auto begin_it = reinterpret_cast(buffer.get()); + const auto end_it = begin_it + testSize; + + uninitialized_default_construct_n(begin_it, testSize); + const auto result_it = destroy_n(exec, begin_it, testSize); + assert(end_it == result_it); + } +}; + +struct test_case_uninitialized_copy_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + auto buffer2 = make_unique(testSize); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + + iota(begin_it, end_it, 42); + + const auto begin_it2 = buffer2.get(); + const auto end_it2 = begin_it2 + testSize; + + uninitialized_copy(begin_it, end_it, begin_it2); + assert(equal(begin_it, end_it, begin_it2, end_it2)); + } +}; + +struct test_case_uninitialized_copy_n_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + auto buffer2 = make_unique(testSize); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + + iota(begin_it, end_it, 42); + + const auto begin_it2 = buffer2.get(); + const auto end_it2 = begin_it2 + testSize; + + uninitialized_copy_n(begin_it, testSize, begin_it2); + assert(equal(begin_it, end_it, begin_it2, end_it2)); + } +}; + +struct test_case_uninitialized_move_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + auto buffer2 = make_unique(testSize); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + + iota(begin_it, end_it, 42); + + const auto begin_it2 = buffer2.get(); + const auto end_it2 = begin_it2 + testSize; + + uninitialized_move(begin_it, end_it, begin_it2); + assert(equal(begin_it, end_it, begin_it2, end_it2)); + } +}; + +struct test_case_uninitialized_move_n_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + auto buffer2 = make_unique(testSize); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + + iota(begin_it, end_it, 42); + + const auto begin_it2 = buffer2.get(); + const auto end_it2 = begin_it2 + testSize; + + uninitialized_move_n(begin_it, testSize, begin_it2); + assert(equal(begin_it, end_it, begin_it2, end_it2)); + } +}; + +struct test_case_uninitialized_fill_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + + uninitialized_fill(begin_it, end_it, 42); + assert(all_of(begin_it, end_it, [](int n) { return n == 42; })); + } +}; + +struct test_case_uninitialized_fill_n_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unique(testSize); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + + uninitialized_fill_n(begin_it, testSize, 42); + assert(all_of(begin_it, end_it, [](int n) { return n == 42; })); + } +}; + +int main() { + parallel_test_case(test_case_uninitialized_default_construct_parallel{}, par); + parallel_test_case(test_case_uninitialized_default_construct_n_parallel{}, par); + parallel_test_case(test_case_uninitialized_value_construct_parallel{}, par); + parallel_test_case(test_case_uninitialized_value_construct_n_parallel{}, par); + parallel_test_case(test_case_destroy_parallel{}, par); + parallel_test_case(test_case_destroy_n_parallel{}, par); + + // currently not parallelized + parallel_test_case(test_case_uninitialized_copy_parallel{}, par); + parallel_test_case(test_case_uninitialized_copy_n_parallel{}, par); + parallel_test_case(test_case_uninitialized_move_parallel{}, par); + parallel_test_case(test_case_uninitialized_move_n_parallel{}, par); + parallel_test_case(test_case_uninitialized_fill_parallel{}, par); + parallel_test_case(test_case_uninitialized_fill_n_parallel{}, par); +#if _HAS_CXX20 + parallel_test_case(test_case_uninitialized_default_construct_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_default_construct_n_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_value_construct_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_value_construct_n_parallel{}, unseq); + parallel_test_case(test_case_destroy_parallel{}, unseq); + parallel_test_case(test_case_destroy_n_parallel{}, unseq); + + // currently not parallelized + parallel_test_case(test_case_uninitialized_copy_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_copy_n_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_move_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_move_n_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_fill_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_fill_n_parallel{}, unseq); +#endif // _HAS_CXX20 +} From bb38f9115b1e765669eb690e3192d5917704e293 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 8 Oct 2022 11:48:01 +0800 Subject: [PATCH 02/30] Add `P0040R3_parallel_memory_algorithms` to list --- tests/std/test.lst | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/test.lst b/tests/std/test.lst index 24d9ded681f..7bffe611716 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -256,6 +256,7 @@ tests\P0024R2_parallel_algorithms_transform_inclusive_scan tests\P0024R2_parallel_algorithms_transform_reduce tests\P0035R4_over_aligned_allocation tests\P0040R3_extending_memory_management_tools +tests\P0040R3_parallel_memory_algorithms tests\P0053R7_cpp_synchronized_buffered_ostream tests\P0067R5_charconv tests\P0083R3_splicing_maps_and_sets From dbcf1a4716e5a703e59a833ed55f7de10f0f6547 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 8 Oct 2022 11:50:43 +0800 Subject: [PATCH 03/30] Implement parallel memory algorithms Parallelized algorithms: * destroy * destroy_n * uninitialized_default_construct * uninitialized_default_construct_n * uninitialized_value_construct * uninitialized_value_construct_n Non-parallelized algorithms: * uninitialized_copy * uninitialized_copy_n * uninitialized_fill * uninitialized_fill_n * uninitialized_move * uninitialized_move_n --- stl/inc/execution | 177 ++++++++++++++++++++++++++++++++++++++++++- stl/inc/memory | 98 +++++++++++++++++++++++- stl/inc/yvals_core.h | 14 ++++ 3 files changed, 287 insertions(+), 2 deletions(-) diff --git a/stl/inc/execution b/stl/inc/execution index e465e848f48..103da637305 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -110,7 +110,8 @@ namespace execution { // indicates support by element access functions for weakly parallel forward progress guarantees, and for // executing interleaved on the same thread, and requests termination on exceptions // - // (at this time, equivalent to sequenced_policy except for the for_each family) + // (at this time, equivalent to sequenced_policy except for the for_each(_n), destroy(_n), + // uninitialized_default_construct(_n), and uninitialized_value_construct(_n)) public: using _Standard_execution_policy = int; static constexpr bool _Parallelize = false; @@ -5043,6 +5044,180 @@ _FwdIt2 adjacent_difference(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last, _Get_unwrapped_n(_Dest, _Idl_distance<_FwdIt1>(_UFirst, _ULast)), _Pass_fn(_Diff_op))); return _Dest; } + +_EXPORT_STD template /* = 0 */> +void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept /* terminates */ { + // destroy all elements in [_First, _Last) + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + _Adl_verify_range(_First, _Last); + if constexpr (!is_trivially_destructible_v<_Ty>) { + _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _Destroy_in_place(_Obj); }); + } +} + +_EXPORT_STD template /* = 0 */> +_NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept /* terminates */ { + // destroy all elements in [_First, _First + _Count) + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + using _Ty = _Iter_value_t<_NoThrowFwdIt>; + _Algorithm_int_t<_Diff> _Count = _Count_raw; + if (_Count <= 0) { + return _First; + } + + if constexpr (is_trivially_destructible_v<_Ty>) { + _STD advance(_First, _Count); + return _First; + } else { + return _STD for_each_n(_STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _Destroy_in_place(_Obj); }); + } +} + +_EXPORT_STD template /* = 0 */> +void uninitialized_default_construct(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept +/* terminates */ { + // default-initialize all elements in [_First, _Last) + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + _Adl_verify_range(_First, _Last); + if constexpr (!is_trivially_default_constructible_v<_Ty>) { + _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _Default_construct_in_place(_Obj); }); + } +} + +_EXPORT_STD template /* = 0 */> +_NoThrowFwdIt uninitialized_default_construct_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept +/* terminates */ { + // default-initialize all elements in [_First, _First + _Count_raw) + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + using _Ty = _Iter_value_t<_NoThrowFwdIt>; + _Algorithm_int_t<_Diff> _Count = _Count_raw; + if (_Count <= 0) { + return _First; + } + + if constexpr (is_trivially_default_constructible_v<_Ty>) { + _STD advance(_First, _Count); + return _First; + } else { + return _STD for_each_n( + _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _Default_construct_in_place(_Obj); }); + } +} + +template +void _Uninitialized_value_construct_ivdep(_UnwrappedNoThrowFwdIt _UFirst, const _UnwrappedNoThrowFwdIt _ULast) { + // value-initialize all elements in [_First, _Last) assuming independent loop bodies + if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { + _Zero_range(_UFirst, _ULast); + } else { +#pragma loop(ivdep) + for (; _UFirst != _ULast; ++_UFirst) { + _Construct_in_place(*_UFirst); + } + } +} + +_EXPORT_STD template /* = 0 */> +void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt _Last) noexcept /* terminates */ { + // value-initialize all elements in [_First, _Last) + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _Adl_verify_range(_First, _Last); + auto _UFirst = _Get_unwrapped(_First); + const auto _ULast = _Get_unwrapped(_Last); + + using _UnwrappedNoThrowFwdIt = _Unwrapped_t; + auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _Construct_in_place(_Obj); }; + if constexpr (remove_reference_t<_ExPo>::_Parallelize) { + const size_t _Hw_threads = __std_parallel_algorithms_hw_threads(); + if (_Hw_threads > 1) { // parallelize on multiprocessor machines... + auto _Count = _STD distance(_UFirst, _ULast); + if (_Count >= 2) { // ... with at least 2 elements + _TRY_BEGIN + _Static_partitioned_for_each2 _Operation{ + _Hw_threads, _Count, _Ctor_fn}; + _Operation._Basis._Populate(_Operation._Team, _UFirst); + _Run_chunked_parallel_work(_Hw_threads, _Operation); + return; + _CATCH(const _Parallelism_resources_exhausted&) + // fall through to serial case below + _CATCH_END + } + } + + _Uninitialized_value_construct_ivdep(_UFirst, _ULast); + } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { + _Uninitialized_value_construct_ivdep(_UFirst, _ULast); + } else { + if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { + _Zero_range(_UFirst, _ULast); + } else { + for (; _First != _Last; ++_First) { + _Construct_in_place(*_UFirst); + } + } + } +} + +template +_UnwrappedNoThrowFwdIt _Uninitialized_value_construct_n_ivdep(_UnwrappedNoThrowFwdIt _UFirst, _Diff _Count) { + // value-initialize all elements in [_First, _First + _Count) assuming independent loop bodies + if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { + _Zero_range(_UFirst, _UFirst + _Count); + } else { +#pragma loop(ivdep) + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Construct_in_place(*_UFirst); + } + } + + return _UFirst; +} + +_EXPORT_STD template /* = 0 */> +_NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept +/* terminates */ { + // value-initialize all elements in [_First, _First + _Count_raw) + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _Algorithm_int_t<_Diff> _Count = _Count_raw; + + using _UnwrappedNoThrowFwdIt = _Unwrapped_t; + auto _UFirst = _Get_unwrapped_n(_First, _Count); + auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _Construct_in_place(_Obj); }; + if (_Count > 0) { + if constexpr (remove_reference_t<_ExPo>::_Parallelize) { + const size_t _Hw_threads = __std_parallel_algorithms_hw_threads(); + if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements + _TRY_BEGIN + _Static_partitioned_for_each2 _Operation{ + _Hw_threads, _Count, _Ctor_fn}; + _Seek_wrapped(_First, _Operation._Basis._Populate(_Operation._Team, _UFirst)); + _Run_chunked_parallel_work(_Hw_threads, _Operation); + return _First; + _CATCH(const _Parallelism_resources_exhausted&) + // fall through to serial case below + _CATCH_END + } + + _Seek_wrapped(_First, _Uninitialized_value_construct_n_ivdep(_UFirst, _Count)); + } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { + _Seek_wrapped(_First, _Uninitialized_value_construct_n_ivdep(_UFirst, _Count)); + } else { + if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { + _Zero_range(_UFirst, _UFirst + _Count); + } else { + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _Construct_in_place(*_UFirst); + } + } + + _Seek_wrapped(_First, _UFirst); + } + } + + return _First; +} _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS diff --git a/stl/inc/memory b/stl/inc/memory index 94ac50ab41a..f56e0777a99 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -26,6 +26,19 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN +#if _HAS_CXX17 +_EXPORT_STD template = 0> +_NoThrowFwdIt uninitialized_copy(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _NoThrowFwdIt _Dest) noexcept +/* terminates */ { + // copy [_First, _Last) to raw [_Dest, ...) + // not parallelized at present + _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + + return _STD uninitialized_copy(_First, _Last, _Dest); +} +#endif // _HAS_CXX17 + #ifdef __cpp_lib_concepts namespace ranges { _EXPORT_STD template @@ -133,6 +146,21 @@ _NoThrowFwdIt uninitialized_copy_n(const _InIt _First, const _Diff _Count_raw, _ return _Dest; } +#if _HAS_CXX17 +_EXPORT_STD template = 0> +_NoThrowFwdIt uninitialized_copy_n(_ExPo&&, const _FwdIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) noexcept +/* terminates */ { + // copy [_First, _First + _Count) to raw [_Dest, ...) + // not parallelized at present + _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + + _Algorithm_int_t<_Diff> _Count = _Count_raw; + return _STD uninitialized_copy_n(_First, _Count, _Dest); +} +#endif // _HAS_CXX17 + #ifdef __cpp_lib_concepts namespace ranges { _EXPORT_STD template @@ -200,6 +228,17 @@ _NoThrowFwdIt uninitialized_move(const _InIt _First, const _InIt _Last, _NoThrow return _Dest; } +_EXPORT_STD template = 0> +_NoThrowFwdIt uninitialized_move(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _NoThrowFwdIt _Dest) noexcept +/* terminates */ { + // move [_First, _Last) to raw [_Dest, ...) + // not parallelized at present + _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + + return _STD uninitialized_move(_First, _Last, _Dest); +} + #ifdef __cpp_lib_concepts namespace ranges { class _Uninitialized_move_fn : private _Not_quite_object { @@ -269,8 +308,30 @@ pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count _Seek_wrapped(_First, _UFirst); return {_First, _Dest}; } -#endif // _HAS_CXX17 +_EXPORT_STD template = 0> +_NoThrowFwdIt uninitialized_move_n(_ExPo&&, const _FwdIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) noexcept +/* terminates */ { + // move [_First, _First + _Count) to raw [_Dest, ...) + // not parallelized at present + _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + + _Algorithm_int_t<_Diff> _Count = _Count_raw; + return _STD uninitialized_move_n(_First, _Count, _Dest); +} + +_EXPORT_STD template = 0> +void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) noexcept +/* terminates */ { + // copy _Val throughout raw [_First, _Last) + // not parallelized at present + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + + _STD uninitialized_fill(_First, _Last, _Val); +} +#endif // _HAS_CXX17 #ifdef __cpp_lib_concepts namespace ranges { @@ -419,6 +480,20 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, return _First; } +#if _HAS_CXX17 +_EXPORT_STD template = 0> +_NoThrowFwdIt uninitialized_fill_n(_ExPo&&, _NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) noexcept +/* terminates */ { + // copy _Count copies of _Val to raw _First + // not parallelized at present + _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + + _Algorithm_int_t<_Diff> _Count = _Count_raw; + return _STD uninitialized_fill_n(_First, _Count, _Val); +} +#endif // _HAS_CXX17 + #ifdef __cpp_lib_concepts namespace ranges { class _Uninitialized_fill_n_fn : private _Not_quite_object { @@ -513,6 +588,9 @@ _CONSTEXPR20 void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) _Destroy_range(_Get_unwrapped(_First), _Get_unwrapped(_Last)); } +_EXPORT_STD template = 0> +void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept; // terminates + #ifdef __cpp_lib_concepts namespace ranges { // clang-format off @@ -583,6 +661,9 @@ _CONSTEXPR20 _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_ra return _First; } +_EXPORT_STD template = 0> +_NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept; // terminates + #ifdef __cpp_lib_concepts namespace ranges { class _Destroy_n_fn : private _Not_quite_object { @@ -635,6 +716,10 @@ void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowF } } +_EXPORT_STD template = 0> +void uninitialized_default_construct( + _ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept; // terminates + #ifdef __cpp_lib_concepts namespace ranges { class _Uninitialized_default_construct_fn : private _Not_quite_object { @@ -715,6 +800,10 @@ _NoThrowFwdIt uninitialized_default_construct_n(_NoThrowFwdIt _First, const _Dif return _First; } +_EXPORT_STD template = 0> +_NoThrowFwdIt uninitialized_default_construct_n( + _ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept; // terminates + #ifdef __cpp_lib_concepts namespace ranges { class _Uninitialized_default_construct_n_fn : private _Not_quite_object { @@ -770,6 +859,9 @@ void uninitialized_value_construct(const _NoThrowFwdIt _First, const _NoThrowFwd } } +_EXPORT_STD template = 0> +void uninitialized_value_construct(_ExPo&& _Exec, _NoThrowFwdIt _First, _NoThrowFwdIt _Last) noexcept; // terminates + #ifdef __cpp_lib_concepts namespace ranges { class _Uninitialized_value_construct_fn : private _Not_quite_object { @@ -837,6 +929,10 @@ _NoThrowFwdIt uninitialized_value_construct_n(_NoThrowFwdIt _First, const _Diff return _First; } +_EXPORT_STD template = 0> +_NoThrowFwdIt uninitialized_value_construct_n( + _ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept; // terminates + #ifdef __cpp_lib_concepts namespace ranges { class _Uninitialized_value_construct_n_fn : private _Not_quite_object { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 9075b1aee5e..3f7ea85dd33 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -355,6 +355,8 @@ // * any_of // * count // * count_if +// * destroy +// * destroy_n // * equal // * exclusive_scan // * find @@ -388,6 +390,10 @@ // * transform_exclusive_scan // * transform_inclusive_scan // * transform_reduce +// * uninitialized_default_construct +// * uninitialized_default_construct_n +// * uninitialized_value_construct +// * uninitialized_value_construct_n // // The following are not presently parallelized: // @@ -406,6 +412,14 @@ // * shift_right // * swap_ranges // +// Possibly same as above, but not yet tested. +// * uninitialized_copy +// * uninitialized_copy_n +// * uninitialized_fill +// * uninitialized_fill_n +// * uninitialized_move +// * uninitialized_move_n +// // Confusion over user parallelism requirements exists; likely in the above category anyway. // * generate // * generate_n From df9f83e5dc3f7ee5c0c588167e8c45f64a359096 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 8 Oct 2022 12:47:28 +0800 Subject: [PATCH 04/30] Remove UTF-8 BOM Why can't we just ignore it? --- tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index f1b7076e2b5..a17c1b3cd08 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include From 03d5cbb0a5e7c6400458cea02ae1384266ce81e5 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 8 Oct 2022 13:13:00 +0800 Subject: [PATCH 05/30] Fix `uninitialized_move_n` and `uninitialized_fill` --- stl/inc/memory | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index f56e0777a99..56b8085127c 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -311,8 +311,8 @@ pair<_InIt, _NoThrowFwdIt> uninitialized_move_n(_InIt _First, const _Diff _Count _EXPORT_STD template = 0> -_NoThrowFwdIt uninitialized_move_n(_ExPo&&, const _FwdIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) noexcept -/* terminates */ { +pair<_FwdIt, _NoThrowFwdIt> uninitialized_move_n( + _ExPo&&, const _FwdIt _First, const _Diff _Count_raw, _NoThrowFwdIt _Dest) noexcept /* terminates */ { // move [_First, _First + _Count) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); @@ -323,7 +323,7 @@ _NoThrowFwdIt uninitialized_move_n(_ExPo&&, const _FwdIt _First, const _Diff _Co } _EXPORT_STD template = 0> -void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) noexcept +void uninitialized_fill(_ExPo&&, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) noexcept /* terminates */ { // copy _Val throughout raw [_First, _Last) // not parallelized at present From f12b6be70c9128791f97e2f256fcc4e53a581770 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 8 Oct 2022 13:18:06 +0800 Subject: [PATCH 06/30] Fix the test file --- .../P0040R3_parallel_memory_algorithms/test.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index a17c1b3cd08..f905d93a689 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -81,7 +81,7 @@ struct test_case_destroy_parallel { const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; - uninitialized_default_construct(begin_it, end_it); + uninitialized_default_construct(exec, begin_it, end_it); destroy(exec, begin_it, end_it); } }; @@ -112,7 +112,7 @@ struct test_case_uninitialized_copy_parallel { const auto begin_it2 = buffer2.get(); const auto end_it2 = begin_it2 + testSize; - uninitialized_copy(begin_it, end_it, begin_it2); + uninitialized_copy(exec, begin_it, end_it, begin_it2); assert(equal(begin_it, end_it, begin_it2, end_it2)); } }; @@ -130,7 +130,7 @@ struct test_case_uninitialized_copy_n_parallel { const auto begin_it2 = buffer2.get(); const auto end_it2 = begin_it2 + testSize; - uninitialized_copy_n(begin_it, testSize, begin_it2); + uninitialized_copy_n(exec, begin_it, testSize, begin_it2); assert(equal(begin_it, end_it, begin_it2, end_it2)); } }; @@ -148,7 +148,7 @@ struct test_case_uninitialized_move_parallel { const auto begin_it2 = buffer2.get(); const auto end_it2 = begin_it2 + testSize; - uninitialized_move(begin_it, end_it, begin_it2); + uninitialized_move(exec, begin_it, end_it, begin_it2); assert(equal(begin_it, end_it, begin_it2, end_it2)); } }; @@ -166,7 +166,7 @@ struct test_case_uninitialized_move_n_parallel { const auto begin_it2 = buffer2.get(); const auto end_it2 = begin_it2 + testSize; - uninitialized_move_n(begin_it, testSize, begin_it2); + uninitialized_move_n(exec, begin_it, testSize, begin_it2); assert(equal(begin_it, end_it, begin_it2, end_it2)); } }; @@ -178,7 +178,7 @@ struct test_case_uninitialized_fill_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - uninitialized_fill(begin_it, end_it, 42); + uninitialized_fill(exec, begin_it, end_it, 42); assert(all_of(begin_it, end_it, [](int n) { return n == 42; })); } }; @@ -190,7 +190,7 @@ struct test_case_uninitialized_fill_n_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - uninitialized_fill_n(begin_it, testSize, 42); + uninitialized_fill_n(exec, begin_it, testSize, 42); assert(all_of(begin_it, end_it, [](int n) { return n == 42; })); } }; From c387462ff87c539f6cb295dc7ed37782840651f1 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 21 Nov 2022 01:46:41 +0800 Subject: [PATCH 07/30] Address @barcharcraz's review comments --- stl/inc/memory | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 56b8085127c..d63b82ba51b 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -27,13 +27,18 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN #if _HAS_CXX17 +#define _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_Iter) \ + static_assert(_Is_cpp17_fwd_iter_v<_Iter> && is_lvalue_reference_v<_Iter_ref_t<_Iter>>, \ + "Specialized algorithms require that mutable iterators are Cpp17ForwardIterators or stronger and " \ + "deference to lvalues.") + _EXPORT_STD template = 0> _NoThrowFwdIt uninitialized_copy(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _NoThrowFwdIt _Dest) noexcept /* terminates */ { // copy [_First, _Last) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); return _STD uninitialized_copy(_First, _Last, _Dest); } @@ -154,7 +159,7 @@ _NoThrowFwdIt uninitialized_copy_n(_ExPo&&, const _FwdIt _First, const _Diff _Co // copy [_First, _First + _Count) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; return _STD uninitialized_copy_n(_First, _Count, _Dest); @@ -234,7 +239,7 @@ _NoThrowFwdIt uninitialized_move(_ExPo&&, const _FwdIt _First, const _FwdIt _Las // move [_First, _Last) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); return _STD uninitialized_move(_First, _Last, _Dest); } @@ -316,7 +321,7 @@ pair<_FwdIt, _NoThrowFwdIt> uninitialized_move_n( // move [_First, _First + _Count) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; return _STD uninitialized_move_n(_First, _Count, _Dest); @@ -327,7 +332,7 @@ void uninitialized_fill(_ExPo&&, const _NoThrowFwdIt _First, const _NoThrowFwdIt /* terminates */ { // copy _Val throughout raw [_First, _Last) // not parallelized at present - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); _STD uninitialized_fill(_First, _Last, _Val); } @@ -487,7 +492,7 @@ _NoThrowFwdIt uninitialized_fill_n(_ExPo&&, _NoThrowFwdIt _First, const _Diff _C /* terminates */ { // copy _Count copies of _Val to raw _First // not parallelized at present - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; return _STD uninitialized_fill_n(_First, _Count, _Val); From c48f9d78bfd25656d0f44c76ae900f289cffb757 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 21 Nov 2022 01:51:25 +0800 Subject: [PATCH 08/30] Address @barcharcraz's review comments (``) --- stl/inc/execution | 156 +++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 79 deletions(-) diff --git a/stl/inc/execution b/stl/inc/execution index 103da637305..fe1fc2f88d9 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -5056,10 +5056,21 @@ void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Las } } +_EXPORT_STD template /* = 0 */> +void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept /* terminates */ { + // destroy all elements in [_First, _Last) + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + _STD _Adl_verify_range(_First, _Last); + if constexpr (!is_trivially_destructible_v<_Ty>) { + _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); }); + } +} + _EXPORT_STD template /* = 0 */> _NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept /* terminates */ { // destroy all elements in [_First, _First + _Count) - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); using _Ty = _Iter_value_t<_NoThrowFwdIt>; _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { @@ -5070,7 +5081,8 @@ _NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_ _STD advance(_First, _Count); return _First; } else { - return _STD for_each_n(_STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _Destroy_in_place(_Obj); }); + return _STD for_each_n( + _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); }); } } @@ -5078,11 +5090,12 @@ _EXPORT_STD template >; - _Adl_verify_range(_First, _Last); + _STD _Adl_verify_range(_First, _Last); if constexpr (!is_trivially_default_constructible_v<_Ty>) { - _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _Default_construct_in_place(_Obj); }); + _STD for_each( + _STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); }); } } @@ -5090,7 +5103,7 @@ _EXPORT_STD template ; _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { @@ -5102,43 +5115,32 @@ _NoThrowFwdIt uninitialized_default_construct_n(_ExPo&& _Exec, _NoThrowFwdIt _Fi return _First; } else { return _STD for_each_n( - _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _Default_construct_in_place(_Obj); }); - } -} - -template -void _Uninitialized_value_construct_ivdep(_UnwrappedNoThrowFwdIt _UFirst, const _UnwrappedNoThrowFwdIt _ULast) { - // value-initialize all elements in [_First, _Last) assuming independent loop bodies - if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { - _Zero_range(_UFirst, _ULast); - } else { -#pragma loop(ivdep) - for (; _UFirst != _ULast; ++_UFirst) { - _Construct_in_place(*_UFirst); - } + _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); }); } } _EXPORT_STD template /* = 0 */> void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt _Last) noexcept /* terminates */ { // value-initialize all elements in [_First, _Last) - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); - _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_First); - const auto _ULast = _Get_unwrapped(_Last); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + _STD _Adl_verify_range(_First, _Last); + auto _UFirst = _STD _Get_unwrapped(_First); + const auto _ULast = _STD _Get_unwrapped(_Last); using _UnwrappedNoThrowFwdIt = _Unwrapped_t; - auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _Construct_in_place(_Obj); }; - if constexpr (remove_reference_t<_ExPo>::_Parallelize) { - const size_t _Hw_threads = __std_parallel_algorithms_hw_threads(); + if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { + _STD _Zero_range(_UFirst, _ULast); + } else if constexpr (remove_reference_t<_ExPo>::_Parallelize) { + const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads(); if (_Hw_threads > 1) { // parallelize on multiprocessor machines... auto _Count = _STD distance(_UFirst, _ULast); if (_Count >= 2) { // ... with at least 2 elements _TRY_BEGIN + auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _STD _Construct_in_place(_Obj); }; _Static_partitioned_for_each2 _Operation{ _Hw_threads, _Count, _Ctor_fn}; _Operation._Basis._Populate(_Operation._Team, _UFirst); - _Run_chunked_parallel_work(_Hw_threads, _Operation); + _STD _Run_chunked_parallel_work(_Hw_threads, _Operation); return; _CATCH(const _Parallelism_resources_exhausted&) // fall through to serial case below @@ -5146,74 +5148,70 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt } } - _Uninitialized_value_construct_ivdep(_UFirst, _ULast); +#pragma loop(ivdep) + for (; _UFirst != _ULast; ++_UFirst) { + _STD _Construct_in_place(*_UFirst); + } } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { - _Uninitialized_value_construct_ivdep(_UFirst, _ULast); - } else { - if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { - _Zero_range(_UFirst, _ULast); - } else { - for (; _First != _Last; ++_First) { - _Construct_in_place(*_UFirst); - } +#pragma loop(ivdep) + for (; _UFirst != _ULast; ++_UFirst) { + _STD _Construct_in_place(*_UFirst); } - } -} - -template -_UnwrappedNoThrowFwdIt _Uninitialized_value_construct_n_ivdep(_UnwrappedNoThrowFwdIt _UFirst, _Diff _Count) { - // value-initialize all elements in [_First, _First + _Count) assuming independent loop bodies - if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { - _Zero_range(_UFirst, _UFirst + _Count); } else { -#pragma loop(ivdep) - for (; _Count > 0; --_Count, (void) ++_UFirst) { - _Construct_in_place(*_UFirst); + for (; _First != _Last; ++_First) { + _STD _Construct_in_place(*_UFirst); } } - - return _UFirst; } _EXPORT_STD template /* = 0 */> _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept /* terminates */ { // value-initialize all elements in [_First, _First + _Count_raw) - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; + if (_Count <= 0) { + return _First; + } + using _UnwrappedNoThrowFwdIt = _Unwrapped_t; - auto _UFirst = _Get_unwrapped_n(_First, _Count); - auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _Construct_in_place(_Obj); }; - if (_Count > 0) { - if constexpr (remove_reference_t<_ExPo>::_Parallelize) { - const size_t _Hw_threads = __std_parallel_algorithms_hw_threads(); - if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements - _TRY_BEGIN - _Static_partitioned_for_each2 _Operation{ - _Hw_threads, _Count, _Ctor_fn}; - _Seek_wrapped(_First, _Operation._Basis._Populate(_Operation._Team, _UFirst)); - _Run_chunked_parallel_work(_Hw_threads, _Operation); - return _First; - _CATCH(const _Parallelism_resources_exhausted&) - // fall through to serial case below - _CATCH_END - } + auto _UFirst = _STD _Get_unwrapped_n(_First, _Count); - _Seek_wrapped(_First, _Uninitialized_value_construct_n_ivdep(_UFirst, _Count)); - } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { - _Seek_wrapped(_First, _Uninitialized_value_construct_n_ivdep(_UFirst, _Count)); - } else { - if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { - _Zero_range(_UFirst, _UFirst + _Count); - } else { - for (; _Count > 0; --_Count, (void) ++_UFirst) { - _Construct_in_place(*_UFirst); - } - } + if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { + _STD _Zero_range(_UFirst, _UFirst + _Count); + _STD _Seek_wrapped(_First, _UFirst + _Count); + } else if constexpr(remove_reference_t<_ExPo>::_Parallelize) { + const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads(); + if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements + _TRY_BEGIN + auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _STD _Construct_in_place(_Obj); }; + _Static_partitioned_for_each2 _Operation{ + _Hw_threads, _Count, _Ctor_fn}; + _STD _Seek_wrapped(_First, _Operation._Basis._Populate(_Operation._Team, _UFirst)); + _STD _Run_chunked_parallel_work(_Hw_threads, _Operation); + return _First; + _CATCH(const _Parallelism_resources_exhausted&) + // fall through to serial case below + _CATCH_END + } - _Seek_wrapped(_First, _UFirst); +#pragma loop(ivdep) + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _STD _Construct_in_place(*_UFirst); + } + _STD _Seek_wrapped(_First, _UFirst); + } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { +#pragma loop(ivdep) + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _STD _Construct_in_place(*_UFirst); + } + _STD _Seek_wrapped(_First, _UFirst); + } else { + for (; _Count > 0; --_Count, (void) ++_UFirst) { + _STD _Construct_in_place(*_UFirst); } + _STD _Seek_wrapped(_First, _UFirst); } return _First; From 97c4f5468d2e258e31cebcc70da81ecad98d998f Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 21 Nov 2022 01:52:18 +0800 Subject: [PATCH 09/30] Add `memset` test cases and check the returned iterators --- .../test.cpp | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index f905d93a689..f1016482c64 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -28,6 +28,8 @@ static_assert(sizeof(wrap_uchar) == 1); const auto expectation = [](const wrap_uchar& x) { return x.is_expected(); }; +const auto expectation_zero = [](int n) { return n == 0; }; + struct test_case_uninitialized_default_construct_parallel { template void operator()(const size_t testSize, const ExecutionPolicy& exec) { @@ -74,6 +76,29 @@ struct test_case_uninitialized_value_construct_n_parallel { } }; +struct test_case_uninitialized_value_construct_memset_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = unique_ptr(new int[testSize]); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + uninitialized_value_construct(exec, begin_it, end_it); + assert(all_of(begin_it, end_it, expectation_zero)); + } +}; + +struct test_case_uninitialized_value_construct_n_memset_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = unique_ptr(new int[testSize]); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + const auto result_it = uninitialized_value_construct_n(exec, begin_it, testSize); + assert(all_of(begin_it, end_it, expectation_zero)); + assert(end_it == result_it); + } +}; + struct test_case_destroy_parallel { template void operator()(const size_t testSize, const ExecutionPolicy& exec) { @@ -126,12 +151,13 @@ struct test_case_uninitialized_copy_n_parallel { const auto end_it = begin_it + testSize; iota(begin_it, end_it, 42); - + const auto begin_it2 = buffer2.get(); const auto end_it2 = begin_it2 + testSize; - uninitialized_copy_n(exec, begin_it, testSize, begin_it2); + const auto result_it = uninitialized_copy_n(exec, begin_it, testSize, begin_it2); assert(equal(begin_it, end_it, begin_it2, end_it2)); + assert(end_it2 == result_it); } }; @@ -166,8 +192,9 @@ struct test_case_uninitialized_move_n_parallel { const auto begin_it2 = buffer2.get(); const auto end_it2 = begin_it2 + testSize; - uninitialized_move_n(exec, begin_it, testSize, begin_it2); + const auto result_pair = uninitialized_move_n(exec, begin_it, testSize, begin_it2); assert(equal(begin_it, end_it, begin_it2, end_it2)); + assert(end_it == result_pair.first && end_it2 == result_pair.second); } }; @@ -190,8 +217,9 @@ struct test_case_uninitialized_fill_n_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - uninitialized_fill_n(exec, begin_it, testSize, 42); + const auto result_it = uninitialized_fill_n(exec, begin_it, testSize, 42); assert(all_of(begin_it, end_it, [](int n) { return n == 42; })); + assert(end_it == result_it); } }; @@ -200,6 +228,8 @@ int main() { parallel_test_case(test_case_uninitialized_default_construct_n_parallel{}, par); parallel_test_case(test_case_uninitialized_value_construct_parallel{}, par); parallel_test_case(test_case_uninitialized_value_construct_n_parallel{}, par); + parallel_test_case(test_case_uninitialized_value_construct_memset_parallel{}, par); + parallel_test_case(test_case_uninitialized_value_construct_n_memset_parallel{}, par); parallel_test_case(test_case_destroy_parallel{}, par); parallel_test_case(test_case_destroy_n_parallel{}, par); @@ -215,6 +245,8 @@ int main() { parallel_test_case(test_case_uninitialized_default_construct_n_parallel{}, unseq); parallel_test_case(test_case_uninitialized_value_construct_parallel{}, unseq); parallel_test_case(test_case_uninitialized_value_construct_n_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_value_construct_memset_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_value_construct_n_memset_parallel{}, unseq); parallel_test_case(test_case_destroy_parallel{}, unseq); parallel_test_case(test_case_destroy_n_parallel{}, unseq); From d96ccc387160c8c83e4533f3d7cc1f2a4e4b2026 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 21 Nov 2022 01:57:31 +0800 Subject: [PATCH 10/30] Clang-format --- tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index f1016482c64..9a9d1692d4d 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -151,7 +151,7 @@ struct test_case_uninitialized_copy_n_parallel { const auto end_it = begin_it + testSize; iota(begin_it, end_it, 42); - + const auto begin_it2 = buffer2.get(); const auto end_it2 = begin_it2 + testSize; From e963846ae50a40a201d56234cd89f64e775c5126 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 21 Nov 2022 01:57:43 +0800 Subject: [PATCH 11/30] Clang-format --- stl/inc/execution | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/execution b/stl/inc/execution index 49f62aa889b..1019ef1fc40 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -5186,7 +5186,7 @@ _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, con if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { _STD _Zero_range(_UFirst, _UFirst + _Count); _STD _Seek_wrapped(_First, _UFirst + _Count); - } else if constexpr(remove_reference_t<_ExPo>::_Parallelize) { + } else if constexpr (remove_reference_t<_ExPo>::_Parallelize) { const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads(); if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements _TRY_BEGIN From 4aa74a8512e85152736ac47e4e0a18467d9686a2 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 21 Nov 2022 02:21:58 +0800 Subject: [PATCH 12/30] Use `usual_17_matrix.lst` for the test --- tests/std/tests/P0040R3_parallel_memory_algorithms/env.lst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/env.lst b/tests/std/tests/P0040R3_parallel_memory_algorithms/env.lst index 1f3dc81ee8b..2de7aab2959 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/env.lst +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\native_17_matrix.lst +RUNALL_INCLUDE ..\usual_17_matrix.lst From 9294b4f32b4edd57495ed6cdfdaf3766ed13eeb2 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 21 Nov 2022 02:22:58 +0800 Subject: [PATCH 13/30] Fix missing `_REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR` --- stl/inc/execution | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/execution b/stl/inc/execution index 1019ef1fc40..0066f9d8f3e 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -5053,7 +5053,7 @@ _FwdIt2 adjacent_difference(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last, _EXPORT_STD template /* = 0 */> void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept /* terminates */ { // destroy all elements in [_First, _Last) - _REQUIRE_CPP17_MUTABLE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; _Adl_verify_range(_First, _Last); if constexpr (!is_trivially_destructible_v<_Ty>) { From c4d8a340b3b89d804006a42db8939df0eecb0632 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 21 Nov 2022 07:13:50 +0800 Subject: [PATCH 14/30] Remove DUPLICATED `destroy`! --- stl/inc/execution | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/stl/inc/execution b/stl/inc/execution index 0066f9d8f3e..24224df0954 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -5050,17 +5050,6 @@ _FwdIt2 adjacent_difference(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last, return _Dest; } -_EXPORT_STD template /* = 0 */> -void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept /* terminates */ { - // destroy all elements in [_First, _Last) - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); - using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; - _Adl_verify_range(_First, _Last); - if constexpr (!is_trivially_destructible_v<_Ty>) { - _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _Destroy_in_place(_Obj); }); - } -} - _EXPORT_STD template /* = 0 */> void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept /* terminates */ { // destroy all elements in [_First, _Last) From 36fcf358a75e82f0c813b880dc7e4974aeafba2b Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 15 Dec 2022 00:57:08 +0800 Subject: [PATCH 15/30] Address @CaseyCarter's review comments --- stl/inc/execution | 43 ++++++++++++++++++++++--------------------- stl/inc/memory | 26 +++++++++++++------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/stl/inc/execution b/stl/inc/execution index c7d3b5fcff3..e0f241da2fc 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -110,7 +110,7 @@ namespace execution { // indicates support by element access functions for weakly parallel forward progress guarantees, and for // executing interleaved on the same thread, and requests termination on exceptions // - // (at this time, equivalent to sequenced_policy except for the for_each(_n), destroy(_n), + // (at this time, equivalent to sequenced_policy except the for_each(_n), destroy(_n), // uninitialized_default_construct(_n), and uninitialized_value_construct(_n)) public: using _Standard_execution_policy = int; @@ -5055,7 +5055,7 @@ _FwdIt2 adjacent_difference(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last, _EXPORT_STD template /* = 0 */> void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept /* terminates */ { // destroy all elements in [_First, _Last) - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; _STD _Adl_verify_range(_First, _Last); if constexpr (!is_trivially_destructible_v<_Ty>) { @@ -5066,8 +5066,8 @@ void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Las _EXPORT_STD template /* = 0 */> _NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept /* terminates */ { // destroy all elements in [_First, _First + _Count) - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); - using _Ty = _Iter_value_t<_NoThrowFwdIt>; + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { return _First; @@ -5086,12 +5086,12 @@ _EXPORT_STD template >; + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + using _Ty = _Iter_value_t<_NoThrowFwdIt>; _STD _Adl_verify_range(_First, _Last); if constexpr (!is_trivially_default_constructible_v<_Ty>) { - _STD for_each( - _STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); }); + _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, + [](auto& _Obj) { _STD _Default_construct_in_place(reinterpret_cast<_Ty&>(_Obj)); }); } } @@ -5099,7 +5099,7 @@ _EXPORT_STD template ; _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { @@ -5110,21 +5110,20 @@ _NoThrowFwdIt uninitialized_default_construct_n(_ExPo&& _Exec, _NoThrowFwdIt _Fi _STD advance(_First, _Count); return _First; } else { - return _STD for_each_n( - _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); }); + return _STD for_each_n(_STD forward<_ExPo>(_Exec), _First, _Count, + [](auto& _Obj) { _STD _Default_construct_in_place(reinterpret_cast<_Ty&>(_Obj)); }); } } _EXPORT_STD template /* = 0 */> void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt _Last) noexcept /* terminates */ { // value-initialize all elements in [_First, _Last) - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _STD _Adl_verify_range(_First, _Last); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); - using _UnwrappedNoThrowFwdIt = _Unwrapped_t; - if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { + if constexpr (_Use_memset_value_construct_v) { _STD _Zero_range(_UFirst, _ULast); } else if constexpr (remove_reference_t<_ExPo>::_Parallelize) { const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads(); @@ -5132,7 +5131,9 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt auto _Count = _STD distance(_UFirst, _ULast); if (_Count >= 2) { // ... with at least 2 elements _TRY_BEGIN - auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _STD _Construct_in_place(_Obj); }; + auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { + _STD _Construct_in_place(reinterpret_cast<_Iter_value_t<_NoThrowFwdIt>&>(_Obj)); + }; _Static_partitioned_for_each2 _Operation{ _Hw_threads, _Count, _Ctor_fn}; _Operation._Basis._Populate(_Operation._Team, _UFirst); @@ -5164,24 +5165,24 @@ _EXPORT_STD template _Count = _Count_raw; if (_Count <= 0) { return _First; } - using _UnwrappedNoThrowFwdIt = _Unwrapped_t; - auto _UFirst = _STD _Get_unwrapped_n(_First, _Count); - - if constexpr (_Use_memset_value_construct_v<_UnwrappedNoThrowFwdIt>) { + auto _UFirst = _STD _Get_unwrapped_n(_First, _Count); + if constexpr (_Use_memset_value_construct_v) { _STD _Zero_range(_UFirst, _UFirst + _Count); _STD _Seek_wrapped(_First, _UFirst + _Count); } else if constexpr (remove_reference_t<_ExPo>::_Parallelize) { const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads(); if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements _TRY_BEGIN - auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _STD _Construct_in_place(_Obj); }; + auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { + _STD _Construct_in_place(reinterpret_cast<_Iter_value_t<_NoThrowFwdIt>&>(_Obj)); + }; _Static_partitioned_for_each2 _Operation{ _Hw_threads, _Count, _Ctor_fn}; _STD _Seek_wrapped(_First, _Operation._Basis._Populate(_Operation._Team, _UFirst)); diff --git a/stl/inc/memory b/stl/inc/memory index ae17e836249..78f01acdb42 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -27,10 +27,10 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN #if _HAS_CXX17 -#define _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_Iter) \ - static_assert(_Is_cpp17_fwd_iter_v<_Iter> && is_lvalue_reference_v<_Iter_ref_t<_Iter>>, \ - "Specialized algorithms require that mutable iterators are Cpp17ForwardIterators or stronger and " \ - "deference to lvalues.") +#define _REQUIRE_PARELLEL_LVALUE_ITERATOR(_Iter) \ + static_assert(_Is_ranges_fwd_iter_v<_Iter> && is_lvalue_reference_v<_Iter_ref_t<_Iter>>, \ + "Parallel specialized algorithms require the iterator type to be forward iterator and dereference " \ + "to lvalues.") _EXPORT_STD template = 0> _NoThrowFwdIt uninitialized_copy(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _NoThrowFwdIt _Dest) noexcept @@ -38,7 +38,7 @@ _NoThrowFwdIt uninitialized_copy(_ExPo&&, const _FwdIt _First, const _FwdIt _Las // copy [_First, _Last) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); return _STD uninitialized_copy(_First, _Last, _Dest); } @@ -155,7 +155,7 @@ _NoThrowFwdIt uninitialized_copy_n(_ExPo&&, const _FwdIt _First, const _Diff _Co // copy [_First, _First + _Count) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; return _STD uninitialized_copy_n(_First, _Count, _Dest); @@ -233,7 +233,7 @@ _NoThrowFwdIt uninitialized_move(_ExPo&&, const _FwdIt _First, const _FwdIt _Las // move [_First, _Last) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); return _STD uninitialized_move(_First, _Last, _Dest); } @@ -311,7 +311,7 @@ pair<_FwdIt, _NoThrowFwdIt> uninitialized_move_n( // move [_First, _First + _Count) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; return _STD uninitialized_move_n(_First, _Count, _Dest); @@ -322,7 +322,7 @@ void uninitialized_fill(_ExPo&&, const _NoThrowFwdIt _First, const _NoThrowFwdIt /* terminates */ { // copy _Val throughout raw [_First, _Last) // not parallelized at present - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _STD uninitialized_fill(_First, _Last, _Val); } @@ -476,7 +476,7 @@ _NoThrowFwdIt uninitialized_fill_n(_ExPo&&, _NoThrowFwdIt _First, const _Diff _C /* terminates */ { // copy _Count copies of _Val to raw _First // not parallelized at present - _REQUIRE_CPP17_MUTABLE_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; return _STD uninitialized_fill_n(_First, _Count, _Val); @@ -4162,7 +4162,7 @@ struct _Pointer_of_helper<_Ty> { }; template <_Has_member_element_type _Ty> - requires (!_Has_member_pointer<_Ty>) + requires(!_Has_member_pointer<_Ty>) struct _Pointer_of_helper<_Ty> { using type = typename _Ty::element_type*; }; @@ -4235,7 +4235,7 @@ public: } operator void**() const noexcept - requires (!is_same_v<_Pointer, void*>) + requires(!is_same_v<_Pointer, void*>) { static_assert(is_pointer_v<_Pointer>, "conversion of out_ptr_t to void** requires " "Pointer to be a raw pointer (N4892 [out.ptr.t]/13)"); @@ -4317,7 +4317,7 @@ public: } operator void**() const noexcept - requires (!is_same_v<_Pointer, void*>) + requires(!is_same_v<_Pointer, void*>) { static_assert(is_pointer_v<_Pointer>, "conversion of inout_ptr_t to void** requires " "Pointer to be a raw pointer (N4892 [inout.ptr.t]/15)"); From 504b1209d7c6e8f2b2962de68906a1a1b3e95ae4 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 15 Dec 2022 01:15:35 +0800 Subject: [PATCH 16/30] Clang-format: revert changes of unrelated lines --- stl/inc/memory | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 78f01acdb42..7d1d4f961fd 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4162,7 +4162,7 @@ struct _Pointer_of_helper<_Ty> { }; template <_Has_member_element_type _Ty> - requires(!_Has_member_pointer<_Ty>) + requires (!_Has_member_pointer<_Ty>) struct _Pointer_of_helper<_Ty> { using type = typename _Ty::element_type*; }; @@ -4235,7 +4235,7 @@ public: } operator void**() const noexcept - requires(!is_same_v<_Pointer, void*>) + requires (!is_same_v<_Pointer, void*>) { static_assert(is_pointer_v<_Pointer>, "conversion of out_ptr_t to void** requires " "Pointer to be a raw pointer (N4892 [out.ptr.t]/13)"); @@ -4317,7 +4317,7 @@ public: } operator void**() const noexcept - requires(!is_same_v<_Pointer, void*>) + requires (!is_same_v<_Pointer, void*>) { static_assert(is_pointer_v<_Pointer>, "conversion of inout_ptr_t to void** requires " "Pointer to be a raw pointer (N4892 [inout.ptr.t]/15)"); From a32de8b505607528eaad4cdec82a408ddf10b5f5 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 15 Dec 2022 07:39:25 +0800 Subject: [PATCH 17/30] Test coverage for more cases --- .../test.cpp | 182 ++++++++++++++++-- 1 file changed, 168 insertions(+), 14 deletions(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index 9a9d1692d4d..01b997b9974 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -30,46 +30,127 @@ const auto expectation = [](const wrap_uchar& x) { return x.is_expected(); }; const auto expectation_zero = [](int n) { return n == 0; }; +struct resetting_guard { + int* ptr_ = nullptr; + + ~resetting_guard() { + if (ptr_) { + *ptr_ = 0; + } + } + + resetting_guard& operator=(const resetting_guard&) = delete; + resetting_guard& operator=(resetting_guard&&) = delete; +}; + +template +struct deallocating_only_deleter { + size_t count_; + + void operator()(T* ptr) const noexcept { + allocator{}.deallocate(ptr, count_); + } +}; + +template +unique_ptr> make_constructed_nondestroying_buffer(size_t n) { + if (n == 0) { + return unique_ptr>{}; + } + + allocator al; + auto up = unique_ptr>{al.allocate(n), deallocating_only_deleter{n}}; + for (size_t i = 0; i != n; ++i) { + allocator_traits>::construct(al, up.get() + i); + } + + return up; +} + +template +unique_ptr> make_unconstructed_nondestroying_buffer(size_t n) { + if (n == 0) { + return unique_ptr>{}; + } else { + return unique_ptr>{allocator{}.allocate(n), deallocating_only_deleter{n}}; + } +} + struct test_case_uninitialized_default_construct_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; + + fill_n(buffer.get(), testSize, 0xcc); + uninitialized_default_construct(exec, begin_it, end_it); assert(all_of(begin_it, end_it, expectation)); } }; struct test_case_uninitialized_default_construct_n_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; + + fill_n(buffer.get(), testSize, 0xcc); + const auto result_it = uninitialized_default_construct_n(exec, begin_it, testSize); assert(all_of(begin_it, end_it, expectation)); assert(end_it == result_it); } }; +struct test_case_uninitialized_default_construct_trivial_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unconstructed_nondestroying_buffer(testSize); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + + uninitialized_default_construct(exec, begin_it, end_it); + } +}; + +struct test_case_uninitialized_default_construct_n_trivial_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer = make_unconstructed_nondestroying_buffer(testSize); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; + + const auto result_it = uninitialized_default_construct_n(exec, begin_it, testSize); + assert(end_it == result_it); + } +}; + struct test_case_uninitialized_value_construct_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; + + fill_n(buffer.get(), testSize, 0xcc); + uninitialized_value_construct(exec, begin_it, end_it); assert(all_of(begin_it, end_it, expectation)); } }; struct test_case_uninitialized_value_construct_n_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; + + fill_n(buffer.get(), testSize, 0xcc); + const auto result_it = uninitialized_value_construct_n(exec, begin_it, testSize); assert(all_of(begin_it, end_it, expectation)); assert(end_it == result_it); @@ -77,22 +158,28 @@ struct test_case_uninitialized_value_construct_n_parallel { }; struct test_case_uninitialized_value_construct_memset_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = unique_ptr(new int[testSize]); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; + + fill_n(begin_it, testSize, static_cast(0xdeadbeaf)); + uninitialized_value_construct(exec, begin_it, end_it); assert(all_of(begin_it, end_it, expectation_zero)); } }; struct test_case_uninitialized_value_construct_n_memset_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = unique_ptr(new int[testSize]); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; + + fill_n(begin_it, testSize, static_cast(0xdeadbeaf)); + const auto result_it = uninitialized_value_construct_n(exec, begin_it, testSize); assert(all_of(begin_it, end_it, expectation_zero)); assert(end_it == result_it); @@ -100,38 +187,90 @@ struct test_case_uninitialized_value_construct_n_memset_parallel { }; struct test_case_destroy_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; + fill_n(buffer.get(), testSize, 0xcc); + uninitialized_default_construct(exec, begin_it, end_it); destroy(exec, begin_it, end_it); } }; struct test_case_destroy_n_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; + fill_n(buffer.get(), testSize, 0xcc); + uninitialized_default_construct_n(begin_it, testSize); const auto result_it = destroy_n(exec, begin_it, testSize); assert(end_it == result_it); } }; +struct test_case_destroy_nontrivial_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer_to_destroy = make_constructed_nondestroying_buffer(testSize); + const auto begin_it = buffer_to_destroy.get(); + const auto end_it = begin_it + testSize; + + auto buffer_to_clear = make_unique(testSize); + const auto begin_it_validation = buffer_to_clear.get(); + const auto end_it_validation = begin_it_validation + testSize; + + fill(begin_it_validation, end_it_validation, static_cast(0xdeadbeaf)); + auto it_guard = begin_it; + for (auto it_int = begin_it_validation; it_int != end_it_validation; ++it_int) { + it_guard->ptr_ = it_int; + ++it_guard; + } + + destroy(exec, begin_it, end_it); + assert(all_of(begin_it_validation, end_it_validation, expectation_zero)); + } +}; + +struct test_case_destroy_n_nontrivial_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto buffer_to_destroy = make_constructed_nondestroying_buffer(testSize); + const auto begin_it = buffer_to_destroy.get(); + const auto end_it = begin_it + testSize; + + auto buffer_to_clear = make_unique(testSize); + const auto begin_it_validation = buffer_to_clear.get(); + const auto end_it_validation = begin_it_validation + testSize; + + fill_n(begin_it_validation, testSize, static_cast(0xdeadbeaf)); + auto it_guard = begin_it; + for (auto it_int = begin_it_validation; it_int != end_it_validation; ++it_int) { + it_guard->ptr_ = it_int; + ++it_guard; + } + + const auto result_it = destroy_n(exec, begin_it, testSize); + assert(end_it == result_it); + assert(all_of(begin_it_validation, end_it_validation, expectation_zero)); + } +}; + struct test_case_uninitialized_copy_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); auto buffer2 = make_unique(testSize); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; + fill_n(buffer2.get(), testSize, static_cast(0xdeadbeaf)); iota(begin_it, end_it, 42); const auto begin_it2 = buffer2.get(); @@ -143,13 +282,14 @@ struct test_case_uninitialized_copy_parallel { }; struct test_case_uninitialized_copy_n_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); auto buffer2 = make_unique(testSize); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; + fill_n(buffer2.get(), testSize, static_cast(0xdeadbeaf)); iota(begin_it, end_it, 42); const auto begin_it2 = buffer2.get(); @@ -162,13 +302,14 @@ struct test_case_uninitialized_copy_n_parallel { }; struct test_case_uninitialized_move_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); auto buffer2 = make_unique(testSize); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; + fill_n(buffer2.get(), testSize, static_cast(0xdeadbeaf)); iota(begin_it, end_it, 42); const auto begin_it2 = buffer2.get(); @@ -180,13 +321,14 @@ struct test_case_uninitialized_move_parallel { }; struct test_case_uninitialized_move_n_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); auto buffer2 = make_unique(testSize); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; + fill_n(buffer2.get(), testSize, static_cast(0xdeadbeaf)); iota(begin_it, end_it, 42); const auto begin_it2 = buffer2.get(); @@ -199,24 +341,28 @@ struct test_case_uninitialized_move_n_parallel { }; struct test_case_uninitialized_fill_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; + fill(begin_it, end_it, static_cast(0xdeadbeaf)); + uninitialized_fill(exec, begin_it, end_it, 42); assert(all_of(begin_it, end_it, [](int n) { return n == 42; })); } }; struct test_case_uninitialized_fill_n_parallel { - template + template void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto buffer = make_unique(testSize); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; + fill_n(begin_it, testSize, static_cast(0xdeadbeaf)); + const auto result_it = uninitialized_fill_n(exec, begin_it, testSize, 42); assert(all_of(begin_it, end_it, [](int n) { return n == 42; })); assert(end_it == result_it); @@ -226,12 +372,16 @@ struct test_case_uninitialized_fill_n_parallel { int main() { parallel_test_case(test_case_uninitialized_default_construct_parallel{}, par); parallel_test_case(test_case_uninitialized_default_construct_n_parallel{}, par); + parallel_test_case(test_case_uninitialized_default_construct_trivial_parallel{}, par); + parallel_test_case(test_case_uninitialized_default_construct_n_trivial_parallel{}, par); parallel_test_case(test_case_uninitialized_value_construct_parallel{}, par); parallel_test_case(test_case_uninitialized_value_construct_n_parallel{}, par); parallel_test_case(test_case_uninitialized_value_construct_memset_parallel{}, par); parallel_test_case(test_case_uninitialized_value_construct_n_memset_parallel{}, par); parallel_test_case(test_case_destroy_parallel{}, par); parallel_test_case(test_case_destroy_n_parallel{}, par); + parallel_test_case(test_case_destroy_nontrivial_parallel{}, par); + parallel_test_case(test_case_destroy_n_nontrivial_parallel{}, par); // currently not parallelized parallel_test_case(test_case_uninitialized_copy_parallel{}, par); @@ -243,12 +393,16 @@ int main() { #if _HAS_CXX20 parallel_test_case(test_case_uninitialized_default_construct_parallel{}, unseq); parallel_test_case(test_case_uninitialized_default_construct_n_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_default_construct_trivial_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_default_construct_n_trivial_parallel{}, unseq); parallel_test_case(test_case_uninitialized_value_construct_parallel{}, unseq); parallel_test_case(test_case_uninitialized_value_construct_n_parallel{}, unseq); parallel_test_case(test_case_uninitialized_value_construct_memset_parallel{}, unseq); parallel_test_case(test_case_uninitialized_value_construct_n_memset_parallel{}, unseq); parallel_test_case(test_case_destroy_parallel{}, unseq); parallel_test_case(test_case_destroy_n_parallel{}, unseq); + parallel_test_case(test_case_destroy_nontrivial_parallel{}, unseq); + parallel_test_case(test_case_destroy_n_nontrivial_parallel{}, unseq); // currently not parallelized parallel_test_case(test_case_uninitialized_copy_parallel{}, unseq); From 7c72ff7f775deadf04ca0c3b00030bec876456fe Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 15 Dec 2022 08:03:39 +0800 Subject: [PATCH 18/30] Clang-format: remove additional spaces Why isn't this automatically formatted...? --- .../test.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index 01b997b9974..0ed4b012b37 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -93,9 +93,9 @@ struct test_case_uninitialized_default_construct_parallel { struct test_case_uninitialized_default_construct_n_parallel { template void operator()(const size_t testSize, const ExecutionPolicy& exec) { - auto buffer = make_unique(testSize); - const auto begin_it = reinterpret_cast(buffer.get()); - const auto end_it = begin_it + testSize; + auto buffer = make_unique(testSize); + const auto begin_it = reinterpret_cast(buffer.get()); + const auto end_it = begin_it + testSize; fill_n(buffer.get(), testSize, 0xcc); @@ -145,9 +145,9 @@ struct test_case_uninitialized_value_construct_parallel { struct test_case_uninitialized_value_construct_n_parallel { template void operator()(const size_t testSize, const ExecutionPolicy& exec) { - auto buffer = make_unique(testSize); - const auto begin_it = reinterpret_cast(buffer.get()); - const auto end_it = begin_it + testSize; + auto buffer = make_unique(testSize); + const auto begin_it = reinterpret_cast(buffer.get()); + const auto end_it = begin_it + testSize; fill_n(buffer.get(), testSize, 0xcc); @@ -174,9 +174,9 @@ struct test_case_uninitialized_value_construct_memset_parallel { struct test_case_uninitialized_value_construct_n_memset_parallel { template void operator()(const size_t testSize, const ExecutionPolicy& exec) { - auto buffer = unique_ptr(new int[testSize]); - const auto begin_it = buffer.get(); - const auto end_it = begin_it + testSize; + auto buffer = unique_ptr(new int[testSize]); + const auto begin_it = buffer.get(); + const auto end_it = begin_it + testSize; fill_n(begin_it, testSize, static_cast(0xdeadbeaf)); From adcc243853f66a21471b4a3a5ec92e6038331506 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 15 Dec 2022 09:00:48 +0800 Subject: [PATCH 19/30] Signedness issues --- .../test.cpp | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index 0ed4b012b37..043dc334581 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -30,6 +30,9 @@ const auto expectation = [](const wrap_uchar& x) { return x.is_expected(); }; const auto expectation_zero = [](int n) { return n == 0; }; +constexpr auto bad_uchar = static_cast(0xcd); +constexpr auto bad_int = static_cast(0xdeadbeaf); + struct resetting_guard { int* ptr_ = nullptr; @@ -83,7 +86,7 @@ struct test_case_uninitialized_default_construct_parallel { const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; - fill_n(buffer.get(), testSize, 0xcc); + fill_n(buffer.get(), testSize, bad_uchar); uninitialized_default_construct(exec, begin_it, end_it); assert(all_of(begin_it, end_it, expectation)); @@ -97,7 +100,7 @@ struct test_case_uninitialized_default_construct_n_parallel { const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; - fill_n(buffer.get(), testSize, 0xcc); + fill_n(buffer.get(), testSize, bad_uchar); const auto result_it = uninitialized_default_construct_n(exec, begin_it, testSize); assert(all_of(begin_it, end_it, expectation)); @@ -135,7 +138,7 @@ struct test_case_uninitialized_value_construct_parallel { const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; - fill_n(buffer.get(), testSize, 0xcc); + fill_n(buffer.get(), testSize, bad_uchar); uninitialized_value_construct(exec, begin_it, end_it); assert(all_of(begin_it, end_it, expectation)); @@ -149,7 +152,7 @@ struct test_case_uninitialized_value_construct_n_parallel { const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; - fill_n(buffer.get(), testSize, 0xcc); + fill_n(buffer.get(), testSize, bad_uchar); const auto result_it = uninitialized_value_construct_n(exec, begin_it, testSize); assert(all_of(begin_it, end_it, expectation)); @@ -164,7 +167,7 @@ struct test_case_uninitialized_value_construct_memset_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - fill_n(begin_it, testSize, static_cast(0xdeadbeaf)); + fill_n(begin_it, testSize, bad_int); uninitialized_value_construct(exec, begin_it, end_it); assert(all_of(begin_it, end_it, expectation_zero)); @@ -178,7 +181,7 @@ struct test_case_uninitialized_value_construct_n_memset_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - fill_n(begin_it, testSize, static_cast(0xdeadbeaf)); + fill_n(begin_it, testSize, bad_int); const auto result_it = uninitialized_value_construct_n(exec, begin_it, testSize); assert(all_of(begin_it, end_it, expectation_zero)); @@ -193,7 +196,7 @@ struct test_case_destroy_parallel { const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; - fill_n(buffer.get(), testSize, 0xcc); + fill_n(buffer.get(), testSize, bad_uchar); uninitialized_default_construct(exec, begin_it, end_it); destroy(exec, begin_it, end_it); @@ -207,7 +210,7 @@ struct test_case_destroy_n_parallel { const auto begin_it = reinterpret_cast(buffer.get()); const auto end_it = begin_it + testSize; - fill_n(buffer.get(), testSize, 0xcc); + fill_n(buffer.get(), testSize, bad_uchar); uninitialized_default_construct_n(begin_it, testSize); const auto result_it = destroy_n(exec, begin_it, testSize); @@ -226,7 +229,7 @@ struct test_case_destroy_nontrivial_parallel { const auto begin_it_validation = buffer_to_clear.get(); const auto end_it_validation = begin_it_validation + testSize; - fill(begin_it_validation, end_it_validation, static_cast(0xdeadbeaf)); + fill(begin_it_validation, end_it_validation, bad_int); auto it_guard = begin_it; for (auto it_int = begin_it_validation; it_int != end_it_validation; ++it_int) { it_guard->ptr_ = it_int; @@ -249,7 +252,7 @@ struct test_case_destroy_n_nontrivial_parallel { const auto begin_it_validation = buffer_to_clear.get(); const auto end_it_validation = begin_it_validation + testSize; - fill_n(begin_it_validation, testSize, static_cast(0xdeadbeaf)); + fill_n(begin_it_validation, testSize, bad_int); auto it_guard = begin_it; for (auto it_int = begin_it_validation; it_int != end_it_validation; ++it_int) { it_guard->ptr_ = it_int; @@ -270,7 +273,7 @@ struct test_case_uninitialized_copy_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - fill_n(buffer2.get(), testSize, static_cast(0xdeadbeaf)); + fill_n(buffer2.get(), testSize, bad_int); iota(begin_it, end_it, 42); const auto begin_it2 = buffer2.get(); @@ -289,7 +292,7 @@ struct test_case_uninitialized_copy_n_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - fill_n(buffer2.get(), testSize, static_cast(0xdeadbeaf)); + fill_n(buffer2.get(), testSize, bad_int); iota(begin_it, end_it, 42); const auto begin_it2 = buffer2.get(); @@ -309,7 +312,7 @@ struct test_case_uninitialized_move_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - fill_n(buffer2.get(), testSize, static_cast(0xdeadbeaf)); + fill_n(buffer2.get(), testSize, bad_int); iota(begin_it, end_it, 42); const auto begin_it2 = buffer2.get(); @@ -328,7 +331,7 @@ struct test_case_uninitialized_move_n_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - fill_n(buffer2.get(), testSize, static_cast(0xdeadbeaf)); + fill_n(buffer2.get(), testSize, bad_int); iota(begin_it, end_it, 42); const auto begin_it2 = buffer2.get(); @@ -347,7 +350,7 @@ struct test_case_uninitialized_fill_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - fill(begin_it, end_it, static_cast(0xdeadbeaf)); + fill(begin_it, end_it, bad_int); uninitialized_fill(exec, begin_it, end_it, 42); assert(all_of(begin_it, end_it, [](int n) { return n == 42; })); @@ -361,7 +364,7 @@ struct test_case_uninitialized_fill_n_parallel { const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; - fill_n(begin_it, testSize, static_cast(0xdeadbeaf)); + fill_n(begin_it, testSize, bad_int); const auto result_it = uninitialized_fill_n(exec, begin_it, testSize, 42); assert(all_of(begin_it, end_it, [](int n) { return n == 42; })); From 9c80ffe6d12f06f483a43438e8e2409ff1cc8ca5 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 15 Dec 2022 10:06:30 +0800 Subject: [PATCH 20/30] Complete addressing @CaseyCarter's review comments --- stl/inc/execution | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/stl/inc/execution b/stl/inc/execution index e0f241da2fc..1951bb335d6 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -110,7 +110,7 @@ namespace execution { // indicates support by element access functions for weakly parallel forward progress guarantees, and for // executing interleaved on the same thread, and requests termination on exceptions // - // (at this time, equivalent to sequenced_policy except the for_each(_n), destroy(_n), + // (at this time, equivalent to sequenced_policy except for for_each(_n), destroy(_n), // uninitialized_default_construct(_n), and uninitialized_value_construct(_n)) public: using _Standard_execution_policy = int; @@ -5123,6 +5123,7 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); + using _Value_type = _Iter_value_t<_NoThrowFwdIt>; if constexpr (_Use_memset_value_construct_v) { _STD _Zero_range(_UFirst, _ULast); } else if constexpr (remove_reference_t<_ExPo>::_Parallelize) { @@ -5132,7 +5133,7 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt if (_Count >= 2) { // ... with at least 2 elements _TRY_BEGIN auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { - _STD _Construct_in_place(reinterpret_cast<_Iter_value_t<_NoThrowFwdIt>&>(_Obj)); + _STD _Construct_in_place(reinterpret_cast<_Value_type&>(_Obj)); }; _Static_partitioned_for_each2 _Operation{ _Hw_threads, _Count, _Ctor_fn}; @@ -5147,16 +5148,16 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt #pragma loop(ivdep) for (; _UFirst != _ULast; ++_UFirst) { - _STD _Construct_in_place(*_UFirst); + _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); } } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { #pragma loop(ivdep) for (; _UFirst != _ULast; ++_UFirst) { - _STD _Construct_in_place(*_UFirst); + _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); } } else { for (; _First != _Last; ++_First) { - _STD _Construct_in_place(*_UFirst); + _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); } } } @@ -5172,7 +5173,8 @@ _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, con return _First; } - auto _UFirst = _STD _Get_unwrapped_n(_First, _Count); + using _Value_type = _Iter_value_t<_NoThrowFwdIt>; + auto _UFirst = _STD _Get_unwrapped_n(_First, _Count); if constexpr (_Use_memset_value_construct_v) { _STD _Zero_range(_UFirst, _UFirst + _Count); _STD _Seek_wrapped(_First, _UFirst + _Count); @@ -5181,7 +5183,7 @@ _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, con if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements _TRY_BEGIN auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { - _STD _Construct_in_place(reinterpret_cast<_Iter_value_t<_NoThrowFwdIt>&>(_Obj)); + _STD _Construct_in_place(reinterpret_cast<_Value_type&>(_Obj)); }; _Static_partitioned_for_each2 _Operation{ _Hw_threads, _Count, _Ctor_fn}; @@ -5195,18 +5197,18 @@ _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, con #pragma loop(ivdep) for (; _Count > 0; --_Count, (void) ++_UFirst) { - _STD _Construct_in_place(*_UFirst); + _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); } _STD _Seek_wrapped(_First, _UFirst); } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { #pragma loop(ivdep) for (; _Count > 0; --_Count, (void) ++_UFirst) { - _STD _Construct_in_place(*_UFirst); + _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); } _STD _Seek_wrapped(_First, _UFirst); } else { for (; _Count > 0; --_Count, (void) ++_UFirst) { - _STD _Construct_in_place(*_UFirst); + _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); } _STD _Seek_wrapped(_First, _UFirst); } From afb20a8d1ef280e75eac897abc6c71f4d84fd9ad Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 15 Dec 2022 13:02:12 -0800 Subject: [PATCH 21/30] Use make_unique in a couple more places --- tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index 043dc334581..b744809522a 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -163,7 +163,7 @@ struct test_case_uninitialized_value_construct_n_parallel { struct test_case_uninitialized_value_construct_memset_parallel { template void operator()(const size_t testSize, const ExecutionPolicy& exec) { - auto buffer = unique_ptr(new int[testSize]); + auto buffer = make_unique(testSize); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; @@ -177,7 +177,7 @@ struct test_case_uninitialized_value_construct_memset_parallel { struct test_case_uninitialized_value_construct_n_memset_parallel { template void operator()(const size_t testSize, const ExecutionPolicy& exec) { - auto buffer = unique_ptr(new int[testSize]); + auto buffer = make_unique(testSize); const auto begin_it = buffer.get(); const auto end_it = begin_it + testSize; From 79ca246fda8f8f2f829c6d1ab49d6289b1b6fd30 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 17 Dec 2022 00:14:28 +0800 Subject: [PATCH 22/30] Style changes per @StephanTLavavej's review comments --- .../P0040R3_parallel_memory_algorithms/test.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index b744809522a..a0ba0fc2c39 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -2,10 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include -#include #include #include -#include #include #include @@ -31,24 +29,26 @@ const auto expectation = [](const wrap_uchar& x) { return x.is_expected(); }; const auto expectation_zero = [](int n) { return n == 0; }; constexpr auto bad_uchar = static_cast(0xcd); -constexpr auto bad_int = static_cast(0xdeadbeaf); +constexpr auto bad_int = static_cast(0xdeadbeef); struct resetting_guard { int* ptr_ = nullptr; + resetting_guard() = default; + ~resetting_guard() { if (ptr_) { *ptr_ = 0; } } + resetting_guard(const resetting_guard&) = delete; resetting_guard& operator=(const resetting_guard&) = delete; - resetting_guard& operator=(resetting_guard&&) = delete; }; template struct deallocating_only_deleter { - size_t count_; + size_t count_ = 0; void operator()(T* ptr) const noexcept { allocator{}.deallocate(ptr, count_); @@ -62,7 +62,7 @@ unique_ptr> make_constructed_nondestroying_buffe } allocator al; - auto up = unique_ptr>{al.allocate(n), deallocating_only_deleter{n}}; + unique_ptr> up{al.allocate(n), deallocating_only_deleter{n}}; for (size_t i = 0; i != n; ++i) { allocator_traits>::construct(al, up.get() + i); } From a9895fff56e7bfd87274986cbce318616f0f72c0 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 17 Dec 2022 00:59:51 +0800 Subject: [PATCH 23/30] Partially address @StephanTLavavej's review comments - PARALLEL - const _NoThrowFwdIt _First - consistent `_Value_type` - iteration on `_UFirst` (fixing copy-pasta) --- stl/inc/execution | 39 ++++++++++++++++++++------------------- stl/inc/memory | 23 ++++++++++++----------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/stl/inc/execution b/stl/inc/execution index 1951bb335d6..31b41b293d4 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -5055,30 +5055,31 @@ _FwdIt2 adjacent_difference(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last, _EXPORT_STD template /* = 0 */> void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept /* terminates */ { // destroy all elements in [_First, _Last) - _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); - using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + using _Value_type = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; _STD _Adl_verify_range(_First, _Last); - if constexpr (!is_trivially_destructible_v<_Ty>) { - _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); }); + if constexpr (!is_trivially_destructible_v<_Value_type>) { + _STD for_each( + _STD forward<_ExPo>(_Exec), _First, _Last, [](_Value_type& _Obj) { _STD _Destroy_in_place(_Obj); }); } } _EXPORT_STD template /* = 0 */> _NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept /* terminates */ { // destroy all elements in [_First, _First + _Count) - _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); - using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + using _Value_type = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { return _First; } - if constexpr (is_trivially_destructible_v<_Ty>) { + if constexpr (is_trivially_destructible_v<_Value_type>) { _STD advance(_First, _Count); return _First; } else { return _STD for_each_n( - _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); }); + _STD forward<_ExPo>(_Exec), _First, _Count, [](_Value_type& _Obj) { _STD _Destroy_in_place(_Obj); }); } } @@ -5086,12 +5087,12 @@ _EXPORT_STD template ; + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + using _Value_type = _Iter_value_t<_NoThrowFwdIt>; _STD _Adl_verify_range(_First, _Last); - if constexpr (!is_trivially_default_constructible_v<_Ty>) { + if constexpr (!is_trivially_default_constructible_v<_Value_type>) { _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, - [](auto& _Obj) { _STD _Default_construct_in_place(reinterpret_cast<_Ty&>(_Obj)); }); + [](auto& _Obj) { _STD _Default_construct_in_place(reinterpret_cast<_Value_type&>(_Obj)); }); } } @@ -5099,26 +5100,26 @@ _EXPORT_STD template ; + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + using _Value_type = _Iter_value_t<_NoThrowFwdIt>; _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { return _First; } - if constexpr (is_trivially_default_constructible_v<_Ty>) { + if constexpr (is_trivially_default_constructible_v<_Value_type>) { _STD advance(_First, _Count); return _First; } else { return _STD for_each_n(_STD forward<_ExPo>(_Exec), _First, _Count, - [](auto& _Obj) { _STD _Default_construct_in_place(reinterpret_cast<_Ty&>(_Obj)); }); + [](auto& _Obj) { _STD _Default_construct_in_place(reinterpret_cast<_Value_type&>(_Obj)); }); } } _EXPORT_STD template /* = 0 */> void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt _Last) noexcept /* terminates */ { // value-initialize all elements in [_First, _Last) - _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _STD _Adl_verify_range(_First, _Last); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); @@ -5156,7 +5157,7 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); } } else { - for (; _First != _Last; ++_First) { + for (; _UFirst != _ULast; ++_UFirst) { _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); } } @@ -5166,7 +5167,7 @@ _EXPORT_STD template _Count = _Count_raw; if (_Count <= 0) { diff --git a/stl/inc/memory b/stl/inc/memory index 7d1d4f961fd..d47969e5375 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -27,7 +27,7 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN #if _HAS_CXX17 -#define _REQUIRE_PARELLEL_LVALUE_ITERATOR(_Iter) \ +#define _REQUIRE_PARALLEL_LVALUE_ITERATOR(_Iter) \ static_assert(_Is_ranges_fwd_iter_v<_Iter> && is_lvalue_reference_v<_Iter_ref_t<_Iter>>, \ "Parallel specialized algorithms require the iterator type to be forward iterator and dereference " \ "to lvalues.") @@ -38,7 +38,7 @@ _NoThrowFwdIt uninitialized_copy(_ExPo&&, const _FwdIt _First, const _FwdIt _Las // copy [_First, _Last) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); return _STD uninitialized_copy(_First, _Last, _Dest); } @@ -155,7 +155,7 @@ _NoThrowFwdIt uninitialized_copy_n(_ExPo&&, const _FwdIt _First, const _Diff _Co // copy [_First, _First + _Count) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; return _STD uninitialized_copy_n(_First, _Count, _Dest); @@ -233,7 +233,7 @@ _NoThrowFwdIt uninitialized_move(_ExPo&&, const _FwdIt _First, const _FwdIt _Las // move [_First, _Last) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); return _STD uninitialized_move(_First, _Last, _Dest); } @@ -311,7 +311,7 @@ pair<_FwdIt, _NoThrowFwdIt> uninitialized_move_n( // move [_First, _First + _Count) to raw [_Dest, ...) // not parallelized at present _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; return _STD uninitialized_move_n(_First, _Count, _Dest); @@ -322,7 +322,7 @@ void uninitialized_fill(_ExPo&&, const _NoThrowFwdIt _First, const _NoThrowFwdIt /* terminates */ { // copy _Val throughout raw [_First, _Last) // not parallelized at present - _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _STD uninitialized_fill(_First, _Last, _Val); } @@ -472,11 +472,12 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, #if _HAS_CXX17 _EXPORT_STD template = 0> -_NoThrowFwdIt uninitialized_fill_n(_ExPo&&, _NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) noexcept +_NoThrowFwdIt uninitialized_fill_n( + _ExPo&&, const _NoThrowFwdIt _First, const _Diff _Count_raw, const _Tval& _Val) noexcept /* terminates */ { // copy _Count copies of _Val to raw _First // not parallelized at present - _REQUIRE_PARELLEL_LVALUE_ITERATOR(_NoThrowFwdIt); + _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; return _STD uninitialized_fill_n(_First, _Count, _Val); @@ -4162,7 +4163,7 @@ struct _Pointer_of_helper<_Ty> { }; template <_Has_member_element_type _Ty> - requires (!_Has_member_pointer<_Ty>) + requires(!_Has_member_pointer<_Ty>) struct _Pointer_of_helper<_Ty> { using type = typename _Ty::element_type*; }; @@ -4235,7 +4236,7 @@ public: } operator void**() const noexcept - requires (!is_same_v<_Pointer, void*>) + requires(!is_same_v<_Pointer, void*>) { static_assert(is_pointer_v<_Pointer>, "conversion of out_ptr_t to void** requires " "Pointer to be a raw pointer (N4892 [out.ptr.t]/13)"); @@ -4317,7 +4318,7 @@ public: } operator void**() const noexcept - requires (!is_same_v<_Pointer, void*>) + requires(!is_same_v<_Pointer, void*>) { static_assert(is_pointer_v<_Pointer>, "conversion of inout_ptr_t to void** requires " "Pointer to be a raw pointer (N4892 [inout.ptr.t]/15)"); From 930a866fdc7d1e6acdfd6c383c465bd844305669 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 17 Dec 2022 01:03:36 +0800 Subject: [PATCH 24/30] Revert unrelated bad changes (again!) --- stl/inc/memory | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index d47969e5375..d5cd3cabf70 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -4163,7 +4163,7 @@ struct _Pointer_of_helper<_Ty> { }; template <_Has_member_element_type _Ty> - requires(!_Has_member_pointer<_Ty>) + requires (!_Has_member_pointer<_Ty>) struct _Pointer_of_helper<_Ty> { using type = typename _Ty::element_type*; }; @@ -4236,7 +4236,7 @@ public: } operator void**() const noexcept - requires(!is_same_v<_Pointer, void*>) + requires (!is_same_v<_Pointer, void*>) { static_assert(is_pointer_v<_Pointer>, "conversion of out_ptr_t to void** requires " "Pointer to be a raw pointer (N4892 [out.ptr.t]/13)"); @@ -4318,7 +4318,7 @@ public: } operator void**() const noexcept - requires(!is_same_v<_Pointer, void*>) + requires (!is_same_v<_Pointer, void*>) { static_assert(is_pointer_v<_Pointer>, "conversion of inout_ptr_t to void** requires " "Pointer to be a raw pointer (N4892 [inout.ptr.t]/15)"); From c02455d98a49931147ce6f3418644cc287f0e4a7 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 17 Dec 2022 01:43:57 +0800 Subject: [PATCH 25/30] Drop `const` for parameter objects in forward declarations --- stl/inc/memory | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index d5cd3cabf70..a7f9cf259bc 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -575,7 +575,7 @@ _CONSTEXPR20 void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) } _EXPORT_STD template = 0> -void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept; // terminates +void destroy(_ExPo&& _Exec, _NoThrowFwdIt _First, _NoThrowFwdIt _Last) noexcept; // terminates #ifdef __cpp_lib_concepts namespace ranges { @@ -642,7 +642,7 @@ _CONSTEXPR20 _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_ra } _EXPORT_STD template = 0> -_NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept; // terminates +_NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, _Diff _Count_raw) noexcept; // terminates #ifdef __cpp_lib_concepts namespace ranges { @@ -695,8 +695,7 @@ void uninitialized_default_construct(const _NoThrowFwdIt _First, const _NoThrowF } _EXPORT_STD template = 0> -void uninitialized_default_construct( - _ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept; // terminates +void uninitialized_default_construct(_ExPo&& _Exec, _NoThrowFwdIt _First, _NoThrowFwdIt _Last) noexcept; // terminates #ifdef __cpp_lib_concepts namespace ranges { @@ -776,7 +775,7 @@ _NoThrowFwdIt uninitialized_default_construct_n(_NoThrowFwdIt _First, const _Dif _EXPORT_STD template = 0> _NoThrowFwdIt uninitialized_default_construct_n( - _ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept; // terminates + _ExPo&& _Exec, _NoThrowFwdIt _First, _Diff _Count_raw) noexcept; // terminates #ifdef __cpp_lib_concepts namespace ranges { From 300d413bb726d434c24ea342a8e9c85844bea8cb Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 16 Dec 2022 11:43:48 -0800 Subject: [PATCH 26/30] Revert Casey's reinterpret_cast suggestion --- stl/inc/execution | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/stl/inc/execution b/stl/inc/execution index 31b41b293d4..91d677d4972 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -5088,11 +5088,10 @@ void uninitialized_default_construct(_ExPo&& _Exec, const _NoThrowFwdIt _First, /* terminates */ { // default-initialize all elements in [_First, _Last) _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); - using _Value_type = _Iter_value_t<_NoThrowFwdIt>; _STD _Adl_verify_range(_First, _Last); - if constexpr (!is_trivially_default_constructible_v<_Value_type>) { + if constexpr (!is_trivially_default_constructible_v<_Iter_value_t<_NoThrowFwdIt>>) { _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, - [](auto& _Obj) { _STD _Default_construct_in_place(reinterpret_cast<_Value_type&>(_Obj)); }); + [](_Iter_ref_t<_NoThrowFwdIt> _Obj) { _STD _Default_construct_in_place(_Obj); }); } } @@ -5101,18 +5100,17 @@ _NoThrowFwdIt uninitialized_default_construct_n(_ExPo&& _Exec, _NoThrowFwdIt _Fi /* terminates */ { // default-initialize all elements in [_First, _First + _Count_raw) _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); - using _Value_type = _Iter_value_t<_NoThrowFwdIt>; _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { return _First; } - if constexpr (is_trivially_default_constructible_v<_Value_type>) { + if constexpr (is_trivially_default_constructible_v<_Iter_value_t<_NoThrowFwdIt>>) { _STD advance(_First, _Count); return _First; } else { return _STD for_each_n(_STD forward<_ExPo>(_Exec), _First, _Count, - [](auto& _Obj) { _STD _Default_construct_in_place(reinterpret_cast<_Value_type&>(_Obj)); }); + [](_Iter_ref_t<_NoThrowFwdIt> _Obj) { _STD _Default_construct_in_place(_Obj); }); } } @@ -5124,7 +5122,6 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); - using _Value_type = _Iter_value_t<_NoThrowFwdIt>; if constexpr (_Use_memset_value_construct_v) { _STD _Zero_range(_UFirst, _ULast); } else if constexpr (remove_reference_t<_ExPo>::_Parallelize) { @@ -5133,9 +5130,7 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt auto _Count = _STD distance(_UFirst, _ULast); if (_Count >= 2) { // ... with at least 2 elements _TRY_BEGIN - auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { - _STD _Construct_in_place(reinterpret_cast<_Value_type&>(_Obj)); - }; + auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _STD _Construct_in_place(_Obj); }; _Static_partitioned_for_each2 _Operation{ _Hw_threads, _Count, _Ctor_fn}; _Operation._Basis._Populate(_Operation._Team, _UFirst); @@ -5149,16 +5144,16 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt #pragma loop(ivdep) for (; _UFirst != _ULast; ++_UFirst) { - _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); + _STD _Construct_in_place(*_UFirst); } } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { #pragma loop(ivdep) for (; _UFirst != _ULast; ++_UFirst) { - _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); + _STD _Construct_in_place(*_UFirst); } } else { for (; _UFirst != _ULast; ++_UFirst) { - _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); + _STD _Construct_in_place(*_UFirst); } } } @@ -5174,8 +5169,7 @@ _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, con return _First; } - using _Value_type = _Iter_value_t<_NoThrowFwdIt>; - auto _UFirst = _STD _Get_unwrapped_n(_First, _Count); + auto _UFirst = _STD _Get_unwrapped_n(_First, _Count); if constexpr (_Use_memset_value_construct_v) { _STD _Zero_range(_UFirst, _UFirst + _Count); _STD _Seek_wrapped(_First, _UFirst + _Count); @@ -5183,9 +5177,7 @@ _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, con const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads(); if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements _TRY_BEGIN - auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { - _STD _Construct_in_place(reinterpret_cast<_Value_type&>(_Obj)); - }; + auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _STD _Construct_in_place(_Obj); }; _Static_partitioned_for_each2 _Operation{ _Hw_threads, _Count, _Ctor_fn}; _STD _Seek_wrapped(_First, _Operation._Basis._Populate(_Operation._Team, _UFirst)); @@ -5198,18 +5190,18 @@ _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, con #pragma loop(ivdep) for (; _Count > 0; --_Count, (void) ++_UFirst) { - _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); + _STD _Construct_in_place(*_UFirst); } _STD _Seek_wrapped(_First, _UFirst); } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { #pragma loop(ivdep) for (; _Count > 0; --_Count, (void) ++_UFirst) { - _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); + _STD _Construct_in_place(*_UFirst); } _STD _Seek_wrapped(_First, _UFirst); } else { for (; _Count > 0; --_Count, (void) ++_UFirst) { - _STD _Construct_in_place(reinterpret_cast<_Value_type&>(*_UFirst)); + _STD _Construct_in_place(*_UFirst); } _STD _Seek_wrapped(_First, _UFirst); } From f2ae6e7bacced02e2764b5705dbef430b6ef613e Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 16 Dec 2022 12:02:40 -0800 Subject: [PATCH 27/30] Consistency pass --- stl/inc/execution | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/stl/inc/execution b/stl/inc/execution index 91d677d4972..ab6e00c0b81 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -5056,11 +5056,10 @@ _EXPORT_STD template >; _STD _Adl_verify_range(_First, _Last); - if constexpr (!is_trivially_destructible_v<_Value_type>) { - _STD for_each( - _STD forward<_ExPo>(_Exec), _First, _Last, [](_Value_type& _Obj) { _STD _Destroy_in_place(_Obj); }); + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + if constexpr (!is_trivially_destructible_v<_Ty>) { + _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); }); } } @@ -5068,18 +5067,18 @@ _EXPORT_STD template >; _Algorithm_int_t<_Diff> _Count = _Count_raw; if (_Count <= 0) { return _First; } - if constexpr (is_trivially_destructible_v<_Value_type>) { + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + if constexpr (is_trivially_destructible_v<_Ty>) { _STD advance(_First, _Count); return _First; } else { return _STD for_each_n( - _STD forward<_ExPo>(_Exec), _First, _Count, [](_Value_type& _Obj) { _STD _Destroy_in_place(_Obj); }); + _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); }); } } @@ -5089,9 +5088,10 @@ void uninitialized_default_construct(_ExPo&& _Exec, const _NoThrowFwdIt _First, // default-initialize all elements in [_First, _Last) _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); _STD _Adl_verify_range(_First, _Last); - if constexpr (!is_trivially_default_constructible_v<_Iter_value_t<_NoThrowFwdIt>>) { - _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, - [](_Iter_ref_t<_NoThrowFwdIt> _Obj) { _STD _Default_construct_in_place(_Obj); }); + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + if constexpr (!is_trivially_default_constructible_v<_Ty>) { + _STD for_each( + _STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); }); } } @@ -5105,12 +5105,13 @@ _NoThrowFwdIt uninitialized_default_construct_n(_ExPo&& _Exec, _NoThrowFwdIt _Fi return _First; } - if constexpr (is_trivially_default_constructible_v<_Iter_value_t<_NoThrowFwdIt>>) { + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + if constexpr (is_trivially_default_constructible_v<_Ty>) { _STD advance(_First, _Count); return _First; } else { - return _STD for_each_n(_STD forward<_ExPo>(_Exec), _First, _Count, - [](_Iter_ref_t<_NoThrowFwdIt> _Obj) { _STD _Default_construct_in_place(_Obj); }); + return _STD for_each_n( + _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); }); } } @@ -5130,7 +5131,8 @@ void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt auto _Count = _STD distance(_UFirst, _ULast); if (_Count >= 2) { // ... with at least 2 elements _TRY_BEGIN - auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _STD _Construct_in_place(_Obj); }; + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + auto _Ctor_fn = [](_Ty& _Obj) { _STD _Construct_in_place(_Obj); }; _Static_partitioned_for_each2 _Operation{ _Hw_threads, _Count, _Ctor_fn}; _Operation._Basis._Populate(_Operation._Team, _UFirst); @@ -5177,7 +5179,8 @@ _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, con const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads(); if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements _TRY_BEGIN - auto _Ctor_fn = [](decltype(*_UFirst) _Obj) { _STD _Construct_in_place(_Obj); }; + using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; + auto _Ctor_fn = [](_Ty& _Obj) { _STD _Construct_in_place(_Obj); }; _Static_partitioned_for_each2 _Operation{ _Hw_threads, _Count, _Ctor_fn}; _STD _Seek_wrapped(_First, _Operation._Basis._Populate(_Operation._Team, _UFirst)); From 976092680b7d38b6ce824998c5bee097e3175511 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 17 Dec 2022 16:20:49 +0800 Subject: [PATCH 28/30] Test coverage for wrapped iterators --- .../test.cpp | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index a0ba0fc2c39..9d9b7a3af04 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -189,6 +190,31 @@ struct test_case_uninitialized_value_construct_n_memset_parallel { } }; +struct test_case_uninitialized_value_construct_unwrap_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto vec = vector(testSize, bad_int); + const auto begin_it = vec.begin(); + const auto end_it = vec.end(); + + uninitialized_value_construct(exec, begin_it, end_it); + assert(all_of(begin_it, end_it, expectation_zero)); + } +}; + +struct test_case_uninitialized_value_construct_n_unwrap_parallel { + template + void operator()(const size_t testSize, const ExecutionPolicy& exec) { + auto vec = vector(testSize, bad_int); + const auto begin_it = vec.begin(); + const auto end_it = vec.begin() + vec.size(); + + const auto result_it = uninitialized_value_construct_n(exec, begin_it, testSize); + assert(all_of(begin_it, end_it, expectation_zero)); + assert(end_it == result_it); + } +}; + struct test_case_destroy_parallel { template void operator()(const size_t testSize, const ExecutionPolicy& exec) { @@ -381,6 +407,8 @@ int main() { parallel_test_case(test_case_uninitialized_value_construct_n_parallel{}, par); parallel_test_case(test_case_uninitialized_value_construct_memset_parallel{}, par); parallel_test_case(test_case_uninitialized_value_construct_n_memset_parallel{}, par); + parallel_test_case(test_case_uninitialized_value_construct_unwrap_parallel{}, par); + parallel_test_case(test_case_uninitialized_value_construct_n_unwrap_parallel{}, par); parallel_test_case(test_case_destroy_parallel{}, par); parallel_test_case(test_case_destroy_n_parallel{}, par); parallel_test_case(test_case_destroy_nontrivial_parallel{}, par); @@ -402,6 +430,8 @@ int main() { parallel_test_case(test_case_uninitialized_value_construct_n_parallel{}, unseq); parallel_test_case(test_case_uninitialized_value_construct_memset_parallel{}, unseq); parallel_test_case(test_case_uninitialized_value_construct_n_memset_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_value_construct_unwrap_parallel{}, unseq); + parallel_test_case(test_case_uninitialized_value_construct_n_unwrap_parallel{}, unseq); parallel_test_case(test_case_destroy_parallel{}, unseq); parallel_test_case(test_case_destroy_n_parallel{}, unseq); parallel_test_case(test_case_destroy_nontrivial_parallel{}, unseq); From a8c8d5462aab7112d276b60bbd1c4b363a27272a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 17 Dec 2022 16:58:16 +0800 Subject: [PATCH 29/30] Eliminate possibly problematic iterator arithmetic --- tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index 9d9b7a3af04..e040f958564 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -207,7 +207,7 @@ struct test_case_uninitialized_value_construct_n_unwrap_parallel { void operator()(const size_t testSize, const ExecutionPolicy& exec) { auto vec = vector(testSize, bad_int); const auto begin_it = vec.begin(); - const auto end_it = vec.begin() + vec.size(); + const auto end_it = vec.end(); const auto result_it = uninitialized_value_construct_n(exec, begin_it, testSize); assert(all_of(begin_it, end_it, expectation_zero)); From ca84b3f5c43e7331a4e8c087be2bc349b65c7349 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 21 Jan 2023 01:45:39 -0800 Subject: [PATCH 30/30] Fix /clr. --- tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp index e040f958564..abeb44503aa 100644 --- a/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp +++ b/tests/std/tests/P0040R3_parallel_memory_algorithms/test.cpp @@ -399,6 +399,7 @@ struct test_case_uninitialized_fill_n_parallel { }; int main() { +#ifndef _M_CEE // TRANSITION, VSO-1664463 parallel_test_case(test_case_uninitialized_default_construct_parallel{}, par); parallel_test_case(test_case_uninitialized_default_construct_n_parallel{}, par); parallel_test_case(test_case_uninitialized_default_construct_trivial_parallel{}, par); @@ -445,4 +446,5 @@ int main() { parallel_test_case(test_case_uninitialized_fill_parallel{}, unseq); parallel_test_case(test_case_uninitialized_fill_n_parallel{}, unseq); #endif // _HAS_CXX20 +#endif // _M_CEE }