diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -94,6 +94,7 @@ __algorithm/pstl_generate.h __algorithm/pstl_is_partitioned.h __algorithm/pstl_merge.h + __algorithm/pstl_move.h __algorithm/pstl_replace.h __algorithm/pstl_stable_sort.h __algorithm/pstl_transform.h diff --git a/libcxx/include/__algorithm/pstl_move.h b/libcxx/include/__algorithm/pstl_move.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_move.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_MOVE_H +#define _LIBCPP___ALGORITHM_PSTL_MOVE_H + +#include <__algorithm/copy_n.h> +#include <__algorithm/pstl_frontend_dispatch.h> +#include <__algorithm/pstl_transform.h> +#include <__config> +#include <__functional/identity.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_execution_policy.h> +#include <__type_traits/is_trivially_copyable.h> +#include <__type_traits/remove_cvref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +// TODO: Use the std::copy/move shenanigans to forward to std::memmove + +template +void __pstl_move(); + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +move(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) { + return std::__pstl_frontend_dispatch( + _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_move), + [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _ForwardOutIterator __g_result) { + return std::transform(__policy, __g_first, __g_last, __g_result, [](auto&& __v) { return std::move(__v); }); + }, + std::move(__first), + std::move(__last), + std::move(__result)); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_MOVE_H diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -1817,6 +1817,7 @@ #include <__algorithm/pstl_generate.h> #include <__algorithm/pstl_is_partitioned.h> #include <__algorithm/pstl_merge.h> +#include <__algorithm/pstl_move.h> #include <__algorithm/pstl_replace.h> #include <__algorithm/pstl_stable_sort.h> #include <__algorithm/pstl_transform.h> diff --git a/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp b/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp --- a/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp +++ b/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp @@ -146,6 +146,14 @@ pstl_fill_n_called = true; } +bool pstl_move_called = false; + +template +void __pstl_move(TestBackend, ForwardIterator, Size, Func) { + assert(!pstl_move_called); + pstl_fill_n_called = true; +} + bool pstl_is_partitioned_called = false; template @@ -297,7 +305,9 @@ (void)std::generate_n(TestPolicy{}, std::begin(a), std::size(a), pred); assert(std::pstl_generate_n_called); (void)std::is_partitioned(TestPolicy{}, std::begin(a), std::end(a), pred); - assert(std::pstl_generate_n_called); + assert(std::pstl_is_partitioned_called); + (void)std::move(TestPolicy{}, std::begin(a), std::end(a), std::begin(a)); + assert(std::pstl_move_called); (void)std::replace(TestPolicy{}, std::begin(a), std::end(a), 0, 0); assert(std::pstl_replace_called); (void)std::replace_if(TestPolicy{}, std::begin(a), std::end(a), pred, 0); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/pstl.copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/pstl.copy.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/pstl.copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/pstl.copy.pass.cpp @@ -8,7 +8,7 @@ // UNSUPPORTED: c++03, c++11, c++14 -// REQUIRES: with-pstl +// UNSUPPORTED: libcpp-has-no-incomplete-pstl // @@ -50,16 +50,16 @@ } }; -struct CopiedToTester { - bool copied_to = false; - CopiedToTester() = default; - CopiedToTester(const CopiedToTester&) {} - CopiedToTester& operator=(const CopiedToTester&) { - assert(!copied_to); - copied_to = true; +struct MovedToTester { + bool moved_to = false; + MovedToTester() = default; + MovedToTester(const MovedToTester&) {} + MovedToTester& operator=(const MovedToTester&) { + assert(!moved_to); + moved_to = true; return *this; } - ~CopiedToTester() = default; + ~MovedToTester() = default; }; template @@ -68,13 +68,13 @@ void operator()(Policy&& policy) { // simple test for (const int size : {0, 1, 2, 100, 350}) { - std::vector a(size); + std::vector a(size); - std::vector out(std::size(a)); + std::vector out(std::size(a)); auto ret = std::copy(policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::data(out))); assert(base(ret) == std::data(out) + std::size(out)); - assert(std::all_of(std::begin(out), std::end(out), [](CopiedToTester& t) { return t.copied_to; })); - assert(std::none_of(std::begin(a), std::end(a), [](CopiedToTester& t) { return t.copied_to; })); + assert(std::all_of(std::begin(out), std::end(out), [](MovedToTester& t) { return t.moved_to; })); + assert(std::none_of(std::begin(a), std::end(a), [](MovedToTester& t) { return t.moved_to; })); } } }; @@ -93,10 +93,10 @@ }}); types::for_each( - types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { + types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { using Iter = typename decltype(v)::type; types::for_each( - types::forward_iterator_list{}, + types::forward_iterator_list{}, TestIteratorWithPolicies< types::partial_instantiation::template apply>{}); }}); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/pstl.copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.move.pass.cpp copy from libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/pstl.copy.pass.cpp copy to libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.move.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/pstl.copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/pstl.move.pass.cpp @@ -8,12 +8,12 @@ // UNSUPPORTED: c++03, c++11, c++14 -// REQUIRES: with-pstl +// UNSUPPORTED: libcpp-has-no-incomplete-pstl // // template -// ForwardIterator2 copy(ExecutionPolicy&& policy, +// ForwardIterator2 move(ExecutionPolicy&& policy, // ForwardIterator1 first, ForwardIterator1 last, // ForwardIterator2 result); @@ -24,10 +24,10 @@ #include "test_execution_policies.h" #include "test_iterators.h" -EXECUTION_POLICY_SFINAE_TEST(copy); +EXECUTION_POLICY_SFINAE_TEST(move); -static_assert(sfinae_test_copy); -static_assert(!sfinae_test_copy); +static_assert(sfinae_test_move); +static_assert(!sfinae_test_move); template struct TestInt { @@ -41,7 +41,7 @@ std::vector out(std::size(a)); decltype(auto) ret = - std::copy(policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::data(out))); + std::move(policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::data(out))); static_assert(std::is_same_v); assert(base(ret) == std::data(out) + std::size(out)); for (int i = 0; i != size; ++i) @@ -50,16 +50,16 @@ } }; -struct CopiedToTester { - bool copied_to = false; - CopiedToTester() = default; - CopiedToTester(const CopiedToTester&) {} - CopiedToTester& operator=(const CopiedToTester&) { - assert(!copied_to); - copied_to = true; +struct MovedToTester { + bool moved_to = false; + MovedToTester() = default; + MovedToTester(MovedToTester&&) {} + MovedToTester& operator=(MovedToTester&&) { + assert(!moved_to); + moved_to = true; return *this; } - ~CopiedToTester() = default; + ~MovedToTester() = default; }; template @@ -68,13 +68,13 @@ void operator()(Policy&& policy) { // simple test for (const int size : {0, 1, 2, 100, 350}) { - std::vector a(size); + std::vector a(size); - std::vector out(std::size(a)); - auto ret = std::copy(policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::data(out))); + std::vector out(std::size(a)); + auto ret = std::move(policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::data(out))); assert(base(ret) == std::data(out) + std::size(out)); - assert(std::all_of(std::begin(out), std::end(out), [](CopiedToTester& t) { return t.copied_to; })); - assert(std::none_of(std::begin(a), std::end(a), [](CopiedToTester& t) { return t.copied_to; })); + assert(std::all_of(std::begin(out), std::end(out), [](MovedToTester& t) { return t.moved_to; })); + assert(std::none_of(std::begin(a), std::end(a), [](MovedToTester& t) { return t.moved_to; })); } } }; @@ -93,10 +93,10 @@ }}); types::for_each( - types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { + types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { using Iter = typename decltype(v)::type; types::for_each( - types::forward_iterator_list{}, + types::forward_iterator_list{}, TestIteratorWithPolicies< types::partial_instantiation::template apply>{}); }});