Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][PSTL] Implement adjacent_difference #102431

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

philnik777
Copy link
Contributor

No description provided.

@philnik777 philnik777 force-pushed the pstl_adjacent_difference branch 2 times, most recently from 19744c9 to 522dd60 Compare August 8, 2024 14:41
@philnik777 philnik777 added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Aug 15, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 15, 2024

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/102431.diff

5 Files Affected:

  • (modified) libcxx/docs/Status/PSTLPaper.csv (+1-1)
  • (modified) libcxx/include/__numeric/pstl.h (+35)
  • (modified) libcxx/include/__pstl/backend_fwd.h (+8)
  • (modified) libcxx/include/__pstl/backends/default.h (+19)
  • (added) libcxx/test/std/numerics/numeric.ops/adjacent.difference/pstl.adjacent_difference.pass.cpp (+104)
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;
+}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants