diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -70,6 +70,7 @@ __algorithm/pop_heap.h __algorithm/prev_permutation.h __algorithm/pstl_any_all_none_of.h + __algorithm/pstl_for_each.h __algorithm/push_heap.h __algorithm/ranges_adjacent_find.h __algorithm/ranges_all_of.h diff --git a/libcxx/include/__algorithm/pstl_for_each.h b/libcxx/include/__algorithm/pstl_for_each.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/pstl_for_each.h @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// 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_FOR_EACH_H +#define _LIBCPP___ALGORITHM_PSTL_FOR_EACH_H + +#include <__algorithm/for_each.h> +#include <__algorithm/for_each_n.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__pstl/internal/parallel_backend.h> +#include <__pstl/internal/unseq_backend_simd.h> +#include <__type_traits/is_execution_policy.h> +#include <__utility/terminate_on_exception.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if defined(_LIBCPP_HAS_PARALLEL_ALGORITHMS) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template >, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +for_each(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Function __func) { + if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + std::__terminate_on_exception([&] { + __pstl::__par_backend::__parallel_for( + {}, + __policy, + __first, + __last, + [&__policy, __func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + std::for_each(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __func); + }); + }); + } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && + __is_cpp17_random_access_iterator<_ForwardIterator>::value) { + __pstl::__unseq_backend::__simd_walk_1(__first, __last - __first, __func); + } else { + std::for_each(__first, __last, __func); + } +} + +template >, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) { + if constexpr (__is_cpp17_random_access_iterator<_ForwardIterator>::value) { + std::for_each(__policy, __first, __first + __size, __func); + } else { + std::for_each_n(__first, __size, __func); + } +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // defined(_LIBCPP_HAS_PARALLEL_ALGORITHMS) && _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___ALGORITHM_PSTL_FOR_EACH_H diff --git a/libcxx/include/__pstl/internal/glue_algorithm_defs.h b/libcxx/include/__pstl/internal/glue_algorithm_defs.h --- a/libcxx/include/__pstl/internal/glue_algorithm_defs.h +++ b/libcxx/include/__pstl/internal/glue_algorithm_defs.h @@ -20,16 +20,6 @@ namespace std { -// [alg.foreach] - -template -__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void> -for_each(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Function __f); - -template -__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator> -for_each_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n, _Function __f); - // [alg.find] template diff --git a/libcxx/include/__pstl/internal/glue_algorithm_impl.h b/libcxx/include/__pstl/internal/glue_algorithm_impl.h --- a/libcxx/include/__pstl/internal/glue_algorithm_impl.h +++ b/libcxx/include/__pstl/internal/glue_algorithm_impl.h @@ -25,25 +25,6 @@ namespace std { -// [alg.foreach] - -template -__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void> -for_each(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Function __f) { - auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first); - - __pstl::__internal::__pattern_walk1(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec), __first, __last, __f); -} - -template -__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator> -for_each_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n, _Function __f) { - auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first); - - return __pstl::__internal::__pattern_walk1_n( - __dispatch_tag, std::forward<_ExecutionPolicy>(__exec), __first, __n, __f); -} - // [alg.find] template diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -1910,6 +1910,7 @@ #ifdef _LIBCPP_HAS_PARALLEL_ALGORITHMS # include <__algorithm/pstl_any_all_none_of.h> +# include <__algorithm/pstl_for_each.h> #endif // standard-mandated includes diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// REQUIRES: with-pstl + +// + +// template +// void for_each(ExecutionPolicy&& exec, +// ForwardIterator first, ForwardIterator last, +// Function f); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +EXECUTION_POLICY_SFINAE_TEST(for_each); + +static_assert(sfinae_test_for_each); +static_assert(!sfinae_test_for_each); + +template +struct Test { + template + void operator()(Policy&& policy) { + int sizes[] = {0, 1, 2, 100}; + for (auto size : sizes) { + std::vector a(size); + std::vector called(size); + std::for_each(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), [&](int& v) { + assert(!called[&v - a.data()]); + called[&v - a.data()] = true; + }); + assert(std::all_of(std::begin(called), std::end(called), [](bool b) { return b; })); + } + } +}; + +int main(int, char**) { + types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); + +#ifndef TEST_HAS_NO_EXCEPTIONS + std::set_terminate(terminate_successful); + int a[] = {1, 2}; + try { + std::for_each(std::execution::par, std::begin(a), std::end(a), [](int) { throw int{}; }); + } catch (int) { + assert(false); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// REQUIRES: with-pstl + +// + +// template +// void for_each(ExecutionPolicy&& exec, +// ForwardIterator first, ForwardIterator last, +// Function f); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +EXECUTION_POLICY_SFINAE_TEST(for_each); + +static_assert(sfinae_test_for_each); +static_assert(!sfinae_test_for_each); + +template +struct Test { + template + void operator()(Policy&& policy) { + int sizes[] = {0, 1, 2, 100}; + for (auto size : sizes) { + std::vector a(size); + std::vector called(size); + std::for_each_n(policy, Iter(std::data(a)), std::size(a), [&](int& v) { + assert(!called[&v - a.data()]); + called[&v - a.data()] = true; + }); + assert(std::all_of(std::begin(called), std::end(called), [](bool b) { return b; })); + } + } +}; + +int main(int, char**) { + types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); + +#ifndef TEST_HAS_NO_EXCEPTIONS + std::set_terminate(terminate_successful); + int a[] = {1, 2}; + try { + std::for_each_n(std::execution::par, std::data(a), std::size(a), [](int) { throw int{}; }); + } catch (int) { + assert(false); + } +#endif + + return 0; +} diff --git a/libcxx/test/support/test_execution_policies.h b/libcxx/test/support/test_execution_policies.h --- a/libcxx/test/support/test_execution_policies.h +++ b/libcxx/test/support/test_execution_policies.h @@ -47,6 +47,16 @@ } }; +struct Bool { + bool b_; + Bool() = default; + Bool(bool b) : b_(b) {} + + operator bool&() { + return b_; + } +}; + [[noreturn]] inline void terminate_successful() { std::exit(0); } #endif // TEST_SUPPORT_TEST_EXECUTION_POLICIES