Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ set(files
__pstl/cpu_algos/merge.h
__pstl/cpu_algos/mismatch.h
__pstl/cpu_algos/reverse.h
__pstl/cpu_algos/search.h
__pstl/cpu_algos/stable_sort.h
__pstl/cpu_algos/transform.h
__pstl/cpu_algos/transform_reduce.h
Expand Down
48 changes: 48 additions & 0 deletions libcxx/include/__algorithm/pstl.h
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,54 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator rotate_copy(
std::move(__result));
}

template <class _ExecutionPolicy,
class _ForwardIterator1,
class _ForwardIterator2,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator1
search(_ExecutionPolicy&& __policy,
_ForwardIterator1 __first1,
_ForwardIterator1 __last1,
_ForwardIterator2 __first2,
_ForwardIterator2 __last2) {
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "search requires ForwardIterators");
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "search requires ForwardIterators");
using _Implementation = __pstl::__dispatch<__pstl::__search, __pstl::__current_configuration, _RawPolicy>;
return __pstl::__handle_exception<_Implementation>(
std::forward<_ExecutionPolicy>(__policy),
std::move(__first1),
std::move(__last1),
std::move(__first2),
std::move(__last2),
equal_to<>{});
}

template <class _ExecutionPolicy,
class _ForwardIterator1,
class _ForwardIterator2,
class _BinaryPredicate,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator1
search(_ExecutionPolicy&& __policy,
_ForwardIterator1 __first1,
_ForwardIterator1 __last1,
_ForwardIterator2 __first2,
_ForwardIterator2 __last2,
_BinaryPredicate __pred) {
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "search requires ForwardIterators");
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "search requires ForwardIterators");
using _Implementation = __pstl::__dispatch<__pstl::__search, __pstl::__current_configuration, _RawPolicy>;
return __pstl::__handle_exception<_Implementation>(
std::forward<_ExecutionPolicy>(__policy),
std::move(__first1),
std::move(__last1),
std::move(__first2),
std::move(__last2),
std::move(__pred));
}

template <class _ExecutionPolicy,
class _RandomAccessIterator,
class _Comp,
Expand Down
7 changes: 7 additions & 0 deletions libcxx/include/__pstl/backend_fwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ struct __fill_n;
// optional<__empty>
// operator()(_Policy&&, _ForwardIterator __first, _Size __n, _Tp const& __value) const noexcept;

template <class _Backend, class _ExecutionPolicy>
struct __search;
// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
// optional<_ForwardIterator1>
// operator()(_Policy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
// _ForwardIterator2 __first2, _ForwardIterator2 __last2, _BinaryPredicate __pred) const noexcept;

template <class _Backend, class _ExecutionPolicy>
struct __replace;
// template <class _Policy, class _ForwardIterator, class _Tp>
Expand Down
4 changes: 4 additions & 0 deletions libcxx/include/__pstl/backends/default.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ namespace __pstl {
// ------------
// No other algorithms based on reverse
//
// search family
// ------------
// No other algorithms based on search
//
// stable_sort family
// ------------------
// - sort
Expand Down
5 changes: 5 additions & 0 deletions libcxx/include/__pstl/backends/libdispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <__pstl/cpu_algos/merge.h>
#include <__pstl/cpu_algos/mismatch.h>
#include <__pstl/cpu_algos/reverse.h>
#include <__pstl/cpu_algos/search.h>
#include <__pstl/cpu_algos/stable_sort.h>
#include <__pstl/cpu_algos/transform.h>
#include <__pstl/cpu_algos/transform_reduce.h>
Expand Down Expand Up @@ -380,6 +381,10 @@ template <class _ExecutionPolicy>
struct __reverse<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_reverse<__libdispatch_backend_tag, _ExecutionPolicy> {};

template <class _ExecutionPolicy>
struct __search<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_search<__libdispatch_backend_tag, _ExecutionPolicy> {};

template <class _ExecutionPolicy>
struct __stable_sort<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_stable_sort<__libdispatch_backend_tag, _ExecutionPolicy> {};
Expand Down
16 changes: 16 additions & 0 deletions libcxx/include/__pstl/backends/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <__algorithm/merge.h>
#include <__algorithm/mismatch.h>
#include <__algorithm/reverse.h>
#include <__algorithm/search.h>
#include <__algorithm/stable_sort.h>
#include <__algorithm/transform.h>
#include <__config>
Expand Down Expand Up @@ -117,6 +118,21 @@ struct __reverse<__serial_backend_tag, _ExecutionPolicy> {
}
};

template <class _ExecutionPolicy>
struct __search<__serial_backend_tag, _ExecutionPolicy> {
template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
_LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
operator()(_Policy&&,
_ForwardIterator1 __first1,
_ForwardIterator1 __last1,
_ForwardIterator2 __first2,
_ForwardIterator2 __last2,
_BinaryPredicate __pred) const noexcept {
return std::search(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
}
};

template <class _ExecutionPolicy>
struct __stable_sort<__serial_backend_tag, _ExecutionPolicy> {
template <class _Policy, class _RandomAccessIterator, class _Comp>
Expand Down
5 changes: 5 additions & 0 deletions libcxx/include/__pstl/backends/std_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <__pstl/cpu_algos/merge.h>
#include <__pstl/cpu_algos/mismatch.h>
#include <__pstl/cpu_algos/reverse.h>
#include <__pstl/cpu_algos/search.h>
#include <__pstl/cpu_algos/stable_sort.h>
#include <__pstl/cpu_algos/transform.h>
#include <__pstl/cpu_algos/transform_reduce.h>
Expand Down Expand Up @@ -111,6 +112,10 @@ template <class _ExecutionPolicy>
struct __reverse<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_reverse<__std_thread_backend_tag, _ExecutionPolicy> {};

template <class _ExecutionPolicy>
struct __search<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_search<__std_thread_backend_tag, _ExecutionPolicy> {};

template <class _ExecutionPolicy>
struct __stable_sort<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_stable_sort<__std_thread_backend_tag, _ExecutionPolicy> {};
Expand Down
102 changes: 102 additions & 0 deletions libcxx/include/__pstl/cpu_algos/search.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//===----------------------------------------------------------------------===//
//
// 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___PSTL_CPU_ALGOS_SEARCH_H
#define _LIBCPP___PSTL_CPU_ALGOS_SEARCH_H

#include <__algorithm/search.h>
#include <__config>
#include <__functional/operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__optional/nullopt_t.h>
#include <__optional/optional.h>
#include <__pstl/backend_fwd.h>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__pstl/cpu_algos/find_if.h>
#include <__type_traits/is_execution_policy.h>
#include <__utility/convert_to_integral.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

#if _LIBCPP_STD_VER >= 17

_LIBCPP_BEGIN_NAMESPACE_STD
namespace __pstl {

template <class _Backend, class _RawExecutionPolicy>
struct __cpu_parallel_search {
template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
_LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
operator()(_Policy&&,
_ForwardIterator1 __first1,
_ForwardIterator1 __last1,
_ForwardIterator2 __first2,
_ForwardIterator2 __last2,
_BinaryPredicate __pred) const noexcept {
if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
__has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
_DifferenceType __size2 = __last2 - __first2; // The length of the needle to search for.
if (__size2 == 0) {
return __first1; // If the needle length is zero, the first iterator is returned.
}
_DifferenceType __size1 = __last1 - __first1;
if (__size1 < __size2) {
return __last1; // The range is too small to contain the requested number of consecutive elements.
}
// Calculate the length of the tail where a potential match cannot start by definition.
_DifferenceType __crop = __size2 - 1;
// We're only interested in the range where a potential match can start: [first, last - crop)
_ForwardIterator1 __last1_cropped = __last1 - __crop;
// Run a parallel chunked find_if, covering the range where a potential match can start.
auto __res = __pstl::__parallel_find<_Backend>(
__first1,
__last1_cropped,
[__first2, __last2, __crop, &__pred](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
// Uncrop the range to allow std::search to find a full match, which can go beyond __brick_last.
_ForwardIterator1 __brick_last_uncropped = __brick_last + __crop;
// Run a serial std::search inside each of the chunks in parallel.
_ForwardIterator1 __ret = std::search(__brick_first, __brick_last_uncropped, __first2, __last2, __pred);
// The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
// __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __parallel_find().
return __ret == __brick_last_uncropped ? __brick_last : __ret;
},
less<>{}, // `less` here means the lowest index among the matches
true // `true` here means we want the first match, not the last
);
if (!__res) {
return std::nullopt; // Failed to run the algorithm, propagate the error.
}
if (*__res == __last1_cropped) {
return __last1; // No match was found in the range.
}
return *__res; // Return the successful match.
} else {
// Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
return std::search(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
}
}
};

} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER >= 17

_LIBCPP_POP_MACROS

#endif // _LIBCPP___PSTL_CPU_ALGOS_SEARCH_H
3 changes: 3 additions & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -2437,6 +2437,9 @@ module std {
module reverse {
header "__pstl/cpu_algos/reverse.h"
}
module search {
header "__pstl/cpu_algos/search.h"
}
module stable_sort {
header "__pstl/cpu_algos/stable_sort.h"
export std_core.utility_core.empty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,14 @@ void f(non_forward_iterator non_fwd,
(void)std::rotate_copy(pol, it, it, it, non_output); // expected-error@*:* {{static assertion failed: rotate_copy}}
}

{
(void)std::search(pol, non_fwd, non_fwd, it, it); // expected-error@*:* {{static assertion failed: search}}
(void)std::search(pol, it, it, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: search}}

(void)std::search(pol, non_fwd, non_fwd, it, it, pred); // expected-error@*:* {{static assertion failed: search}}
(void)std::search(pol, it, it, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: search}}
}

{
(void)std::sort(pol, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: sort}}
(void)std::sort(pol, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: sort}}
Expand Down
4 changes: 4 additions & 0 deletions libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,8 @@ void test() {
std::lexicographical_compare(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b));
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::lexicographical_compare(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b), pred2);
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::search(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b));
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::search(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b), pred2);
}
Loading
Loading