Skip to content

Commit 522dd60

Browse files
committed
[libc++][PSTL] Implement adjacent_difference
1 parent 1fb1a5d commit 522dd60

File tree

5 files changed

+167
-1
lines changed

5 files changed

+167
-1
lines changed

libcxx/docs/Status/PSTLPaper.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Section,Description,Assignee,Complete
2-
| `[adjacent.difference] <https://wg21.link/adjacent.difference>`_,std::adjacent_difference,Nikolas Klauser,|Not Started|
2+
| `[adjacent.difference] <https://wg21.link/adjacent.difference>`_,std::adjacent_difference,Nikolas Klauser,|Complete|
33
| `[alg.adjacent.find] <https://wg21.link/alg.adjacent.find>`_,std::adjacent_find,Nikolas Klauser,|Not Started|
44
| `[alg.all.of] <https://wg21.link/alg.all.of>`_,std::all_of,Nikolas Klauser,|Complete|
55
| `[alg.any.of] <https://wg21.link/alg.any.of>`_,std::any_of,Nikolas Klauser,|Complete|

libcxx/include/__numeric/pstl.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,41 @@ _LIBCPP_HIDE_FROM_ABI _Tp transform_reduce(
165165
std::move(__transform));
166166
}
167167

168+
template <class _ExecutionPolicy,
169+
class _ForwardIterator,
170+
class _ForwardOutIterator,
171+
class _BinaryOperation,
172+
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
173+
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
174+
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator adjacent_difference(
175+
_ExecutionPolicy&& __policy,
176+
_ForwardIterator __first,
177+
_ForwardIterator __last,
178+
_ForwardOutIterator __out_it,
179+
_BinaryOperation __bin_op) {
180+
using _Implementation =
181+
__pstl::__dispatch<__pstl::__adjacent_difference, __pstl::__current_configuration, _RawPolicy>;
182+
return __pstl::__handle_exception<_Implementation>(
183+
std::forward<_ExecutionPolicy>(__policy),
184+
std::move(__first),
185+
std::move(__last),
186+
std::move(__out_it),
187+
std::move(__bin_op));
188+
}
189+
190+
template <class _ExecutionPolicy,
191+
class _ForwardIterator,
192+
class _ForwardOutIterator,
193+
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
194+
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
195+
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator adjacent_difference(
196+
_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __out_it) {
197+
using _Implementation =
198+
__pstl::__dispatch<__pstl::__adjacent_difference, __pstl::__current_configuration, _RawPolicy>;
199+
return __pstl::__handle_exception<_Implementation>(
200+
std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__out_it), minus{});
201+
}
202+
168203
_LIBCPP_END_NAMESPACE_STD
169204

170205
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

libcxx/include/__pstl/backend_fwd.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ using __current_configuration = __backend_configuration<__libdispatch_backend_ta
6363
# error "Invalid PSTL backend configuration"
6464
#endif
6565

66+
template <class _Backend, class _ExecutionPolicy>
67+
struct __adjacent_difference;
68+
// template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _BinaryOp>
69+
// optional<_ForwardOutIterator>
70+
// operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last,
71+
// _ForwardOutIterator __out_it,
72+
// _BinaryOp __bin_op) const noexcept;
73+
6674
template <class _Backend, class _ExecutionPolicy>
6775
struct __find_if;
6876
// template <class _Policy, class _ForwardIterator, class _Predicate>

libcxx/include/__pstl/backends/default.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <__functional/operations.h>
2020
#include <__iterator/concepts.h>
2121
#include <__iterator/iterator_traits.h>
22+
#include <__iterator/next.h>
2223
#include <__pstl/backend_fwd.h>
2324
#include <__pstl/dispatch.h>
2425
#include <__utility/empty.h>
@@ -88,6 +89,7 @@ namespace __pstl {
8889
// - copy
8990
// - copy_n
9091
// - rotate_copy
92+
// - adjacent_difference
9193
//
9294

9395
//////////////////////////////////////////////////////////////
@@ -495,6 +497,23 @@ struct __rotate_copy<__default_backend_tag, _ExecutionPolicy> {
495497
}
496498
};
497499

500+
template <class _ExecutionPolicy>
501+
struct __adjacent_difference<__default_backend_tag, _ExecutionPolicy> {
502+
template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _BinaryOp>
503+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
504+
operator()(_Policy&& __policy,
505+
_ForwardIterator __first,
506+
_ForwardIterator __last,
507+
_ForwardOutIterator __out_it,
508+
_BinaryOp __bin_op) const noexcept {
509+
if (__first == __last)
510+
return __out_it;
511+
512+
using _TransformBinary = __dispatch<__transform_binary, __current_configuration, _ExecutionPolicy>;
513+
return _TransformBinary()(__policy, std::next(__first), __last, __first, __out_it, __bin_op);
514+
}
515+
};
516+
498517
} // namespace __pstl
499518
_LIBCPP_END_NAMESPACE_STD
500519

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14
10+
11+
// UNSUPPORTED: libcpp-has-no-incomplete-pstl
12+
13+
// <numeric>
14+
15+
// template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2>
16+
// ForwardIterator2
17+
// adjacent_difference(ExecutionPolicy&& exec,
18+
// ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 result);
19+
//
20+
// template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2,
21+
// class BinaryOperation>
22+
// ForwardIterator2
23+
// adjacent_difference(ExecutionPolicy&& exec,
24+
// ForwardIterator1 first, ForwardIterator1 last,
25+
// ForwardIterator2 result, BinaryOperation binary_op);
26+
27+
#include <algorithm>
28+
#include <array>
29+
#include <numeric>
30+
#include <vector>
31+
32+
#include "test_execution_policies.h"
33+
#include "test_iterators.h"
34+
35+
template <class Iter1, class Iter2>
36+
struct Test {
37+
template <int N, int OutN = N - 1, class Policy>
38+
void test(Policy&& policy,
39+
std::array<int, N> input,
40+
std::array<int, OutN> plus_expected,
41+
std::array<int, OutN> minus_expected) {
42+
{
43+
std::array<int, OutN> out;
44+
auto ret =
45+
std::adjacent_difference(policy, Iter1(input.data()), Iter1(input.data() + input.size()), Iter2(out.data()));
46+
assert(base(ret) == out.data() + out.size());
47+
assert(out == minus_expected);
48+
}
49+
{
50+
std::array<int, OutN> out;
51+
auto ret = std::adjacent_difference(
52+
policy, Iter1(input.data()), Iter1(input.data() + input.size()), Iter2(out.data()), std::plus{});
53+
assert(base(ret) == out.data() + out.size());
54+
assert(out == plus_expected);
55+
}
56+
}
57+
58+
template <class Policy>
59+
void operator()(Policy&& policy) {
60+
// simple test
61+
test<4>(policy, {1, 2, 3, 4}, {3, 5, 7}, {1, 1, 1});
62+
// empty range
63+
test<0, 0>(policy, {}, {}, {});
64+
// single element range
65+
test<1>(policy, {1}, {}, {});
66+
// two element range
67+
test<2>(policy, {10, 5}, {15}, {-5});
68+
69+
// Large inputs with generated data
70+
for (auto e : {100, 322, 497, 2048}) {
71+
std::vector<int> input(e);
72+
std::iota(input.begin(), input.end(), 0);
73+
std::vector<int> expected(e - 1);
74+
auto binop = [](int lhs, int rhs) { return lhs + rhs * 3; };
75+
std::adjacent_difference(input.begin(), input.end(), expected.begin(), binop);
76+
std::vector<int> output(e - 1);
77+
std::adjacent_difference(input.begin(), input.end(), output.begin(), binop);
78+
assert(output == expected);
79+
}
80+
81+
{ // ensure that all values are used exactly once
82+
std::array input = {0, 1, 2, 3, 4, 5, 6, 7};
83+
std::array<bool, input.size() - 1> called{};
84+
std::array<int, input.size() - 1> output;
85+
std::adjacent_difference(input.data(), input.data() + input.size(), output.data(), [&](int lhs, int rhs) {
86+
assert(!called[rhs]);
87+
called[rhs] = true;
88+
return rhs - lhs;
89+
});
90+
assert(std::all_of(called.begin(), called.end(), [](bool b) { return b; }));
91+
}
92+
}
93+
};
94+
95+
int main(int, char**) {
96+
types::for_each(types::forward_iterator_list<int*>{}, types::apply_type_identity{[](auto v1) {
97+
using Iter1 = typename decltype(v1)::type;
98+
types::for_each(
99+
types::forward_iterator_list<int*>{},
100+
TestIteratorWithPolicies<types::partial_instantiation<Test, Iter1>::template apply>{});
101+
}});
102+
103+
return 0;
104+
}

0 commit comments

Comments
 (0)