[libcxx-commits] [libcxx] [libc++][PSTL] Implement adjacent_difference (PR #102431)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Aug 8 07:41:48 PDT 2024
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/102431
>From 522dd60df4ee5d958abfdb178cf68f9e3960d0ab Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 8 Aug 2024 09:49:55 +0200
Subject: [PATCH] [libc++][PSTL] Implement adjacent_difference
---
libcxx/docs/Status/PSTLPaper.csv | 2 +-
libcxx/include/__numeric/pstl.h | 35 ++++++
libcxx/include/__pstl/backend_fwd.h | 8 ++
libcxx/include/__pstl/backends/default.h | 19 ++++
.../pstl.adjacent_difference.pass.cpp | 104 ++++++++++++++++++
5 files changed, 167 insertions(+), 1 deletion(-)
create mode 100644 libcxx/test/std/numerics/numeric.ops/adjacent.difference/pstl.adjacent_difference.pass.cpp
diff --git a/libcxx/docs/Status/PSTLPaper.csv b/libcxx/docs/Status/PSTLPaper.csv
index 3fb5adfe3ec46a..cb0e2423e42a36 100644
--- a/libcxx/docs/Status/PSTLPaper.csv
+++ b/libcxx/docs/Status/PSTLPaper.csv
@@ -1,5 +1,5 @@
Section,Description,Assignee,Complete
-| `[adjacent.difference] <https://wg21.link/adjacent.difference>`_,std::adjacent_difference,Nikolas Klauser,|Not Started|
+| `[adjacent.difference] <https://wg21.link/adjacent.difference>`_,std::adjacent_difference,Nikolas Klauser,|Complete|
| `[alg.adjacent.find] <https://wg21.link/alg.adjacent.find>`_,std::adjacent_find,Nikolas Klauser,|Not Started|
| `[alg.all.of] <https://wg21.link/alg.all.of>`_,std::all_of,Nikolas Klauser,|Complete|
| `[alg.any.of] <https://wg21.link/alg.any.of>`_,std::any_of,Nikolas Klauser,|Complete|
diff --git a/libcxx/include/__numeric/pstl.h b/libcxx/include/__numeric/pstl.h
index 7557686a3663db..08d7fa9cbebd63 100644
--- a/libcxx/include/__numeric/pstl.h
+++ b/libcxx/include/__numeric/pstl.h
@@ -165,6 +165,41 @@ _LIBCPP_HIDE_FROM_ABI _Tp transform_reduce(
std::move(__transform));
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _ForwardOutIterator,
+ class _BinaryOperation,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator adjacent_difference(
+ _ExecutionPolicy&& __policy,
+ _ForwardIterator __first,
+ _ForwardIterator __last,
+ _ForwardOutIterator __out_it,
+ _BinaryOperation __bin_op) {
+ using _Implementation =
+ __pstl::__dispatch<__pstl::__adjacent_difference, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy),
+ std::move(__first),
+ std::move(__last),
+ std::move(__out_it),
+ std::move(__bin_op));
+}
+
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _ForwardOutIterator,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator adjacent_difference(
+ _ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __out_it) {
+ using _Implementation =
+ __pstl::__dispatch<__pstl::__adjacent_difference, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__out_it), minus{});
+}
+
_LIBCPP_END_NAMESPACE_STD
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index 32c5da576fb3c0..92cbb6dbbc2093 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -63,6 +63,14 @@ using __current_configuration = __backend_configuration<__libdispatch_backend_ta
# error "Invalid PSTL backend configuration"
#endif
+template <class _Backend, class _ExecutionPolicy>
+struct __adjacent_difference;
+// template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _BinaryOp>
+// optional<_ForwardOutIterator>
+// operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last,
+// _ForwardOutIterator __out_it,
+// _BinaryOp __bin_op) const noexcept;
+
template <class _Backend, class _ExecutionPolicy>
struct __find_if;
// template <class _Policy, class _ForwardIterator, class _Predicate>
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 61a128805f8549..195a0b08e95450 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -19,6 +19,7 @@
#include <__functional/operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
#include <__pstl/backend_fwd.h>
#include <__pstl/dispatch.h>
#include <__utility/empty.h>
@@ -88,6 +89,7 @@ namespace __pstl {
// - copy
// - copy_n
// - rotate_copy
+// - adjacent_difference
//
//////////////////////////////////////////////////////////////
@@ -495,6 +497,23 @@ struct __rotate_copy<__default_backend_tag, _ExecutionPolicy> {
}
};
+template <class _ExecutionPolicy>
+struct __adjacent_difference<__default_backend_tag, _ExecutionPolicy> {
+ template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _BinaryOp>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
+ operator()(_Policy&& __policy,
+ _ForwardIterator __first,
+ _ForwardIterator __last,
+ _ForwardOutIterator __out_it,
+ _BinaryOp __bin_op) const noexcept {
+ if (__first == __last)
+ return __out_it;
+
+ using _TransformBinary = __dispatch<__transform_binary, __current_configuration, _ExecutionPolicy>;
+ return _TransformBinary()(__policy, std::next(__first), __last, __first, __out_it, __bin_op);
+ }
+};
+
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/numerics/numeric.ops/adjacent.difference/pstl.adjacent_difference.pass.cpp b/libcxx/test/std/numerics/numeric.ops/adjacent.difference/pstl.adjacent_difference.pass.cpp
new file mode 100644
index 00000000000000..b5e3902a4f0d0c
--- /dev/null
+++ b/libcxx/test/std/numerics/numeric.ops/adjacent.difference/pstl.adjacent_difference.pass.cpp
@@ -0,0 +1,104 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// <numeric>
+
+// template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2>
+// ForwardIterator2
+// adjacent_difference(ExecutionPolicy&& exec,
+// ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result);
+//
+// template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2,
+// class BinaryOperation>
+// ForwardIterator2
+// adjacent_difference(ExecutionPolicy&& exec,
+// ForwardIterator1 first, ForwardIterator1 last,
+// ForwardIterator2 result, BinaryOperation binary_op);
+
+#include <algorithm>
+#include <array>
+#include <numeric>
+#include <vector>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+template <class Iter1, class Iter2>
+struct Test {
+ template <int N, int OutN = N - 1, class Policy>
+ void test(Policy&& policy,
+ std::array<int, N> input,
+ std::array<int, OutN> plus_expected,
+ std::array<int, OutN> minus_expected) {
+ {
+ std::array<int, OutN> out;
+ auto ret =
+ std::adjacent_difference(policy, Iter1(input.data()), Iter1(input.data() + input.size()), Iter2(out.data()));
+ assert(base(ret) == out.data() + out.size());
+ assert(out == minus_expected);
+ }
+ {
+ std::array<int, OutN> out;
+ auto ret = std::adjacent_difference(
+ policy, Iter1(input.data()), Iter1(input.data() + input.size()), Iter2(out.data()), std::plus{});
+ assert(base(ret) == out.data() + out.size());
+ assert(out == plus_expected);
+ }
+ }
+
+ template <class Policy>
+ void operator()(Policy&& policy) {
+ // simple test
+ test<4>(policy, {1, 2, 3, 4}, {3, 5, 7}, {1, 1, 1});
+ // empty range
+ test<0, 0>(policy, {}, {}, {});
+ // single element range
+ test<1>(policy, {1}, {}, {});
+ // two element range
+ test<2>(policy, {10, 5}, {15}, {-5});
+
+ // Large inputs with generated data
+ for (auto e : {100, 322, 497, 2048}) {
+ std::vector<int> input(e);
+ std::iota(input.begin(), input.end(), 0);
+ std::vector<int> expected(e - 1);
+ auto binop = [](int lhs, int rhs) { return lhs + rhs * 3; };
+ std::adjacent_difference(input.begin(), input.end(), expected.begin(), binop);
+ std::vector<int> output(e - 1);
+ std::adjacent_difference(input.begin(), input.end(), output.begin(), binop);
+ assert(output == expected);
+ }
+
+ { // ensure that all values are used exactly once
+ std::array input = {0, 1, 2, 3, 4, 5, 6, 7};
+ std::array<bool, input.size() - 1> called{};
+ std::array<int, input.size() - 1> output;
+ std::adjacent_difference(input.data(), input.data() + input.size(), output.data(), [&](int lhs, int rhs) {
+ assert(!called[rhs]);
+ called[rhs] = true;
+ return rhs - lhs;
+ });
+ assert(std::all_of(called.begin(), called.end(), [](bool b) { return b; }));
+ }
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<int*>{}, types::apply_type_identity{[](auto v1) {
+ using Iter1 = typename decltype(v1)::type;
+ types::for_each(
+ types::forward_iterator_list<int*>{},
+ TestIteratorWithPolicies<types::partial_instantiation<Test, Iter1>::template apply>{});
+ }});
+
+ return 0;
+}
More information about the libcxx-commits
mailing list