diff --git a/include/oneapi/dpl/pstl/glue_algorithm_ranges_defs.h b/include/oneapi/dpl/pstl/glue_algorithm_ranges_defs.h index 618c18e2b39..edf08e78e24 100644 --- a/include/oneapi/dpl/pstl/glue_algorithm_ranges_defs.h +++ b/include/oneapi/dpl/pstl/glue_algorithm_ranges_defs.h @@ -41,6 +41,8 @@ struct __none_of_fn; struct __adjacent_find_fn; struct __search_fn; struct __search_n_fn; +struct __contains_fn; +struct __contains_subrange_fn; struct __count_if_fn; struct __count_fn; struct __equal_fn; diff --git a/include/oneapi/dpl/pstl/glue_algorithm_ranges_impl.h b/include/oneapi/dpl/pstl/glue_algorithm_ranges_impl.h index 6e9104d9a8f..f943e9e867c 100644 --- a/include/oneapi/dpl/pstl/glue_algorithm_ranges_impl.h +++ b/include/oneapi/dpl/pstl/glue_algorithm_ranges_impl.h @@ -336,6 +336,45 @@ struct __internal::__search_n_fn }; //__search_n_fn inline constexpr __internal::__search_n_fn search_n; +// [alg.contains] + +struct __internal::__contains_fn +{ + template , _Proj>> + requires oneapi::dpl::is_execution_policy_v> && + std::ranges::sized_range<_R> && + std::indirect_binary_predicate, _Proj>, const _T*> + bool + operator()(_ExecutionPolicy&& __exec, _R&& __r, const _T& __value, _Proj __proj = {}) const + { + // To ensure no dangling iterator is returned, __r may not be forwarded + return oneapi::dpl::ranges::find(std::forward<_ExecutionPolicy>(__exec), __r, __value, __proj) + != std::ranges::end(__r); + } +}; +inline constexpr __internal::__contains_fn contains; + +struct __internal::__contains_subrange_fn +{ + template + requires oneapi::dpl::is_execution_policy_v> && + std::ranges::sized_range<_R1> && std::ranges::sized_range<_R2> && + std::indirectly_comparable, std::ranges::iterator_t<_R2>, + _Pred, _Proj1, _Proj2> + bool + operator()(_ExecutionPolicy&& __exec, _R1&& __r1, _R2&& __r2, _Pred __pred = {}, _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const + { + // To ensure no dangling subrange is returned, __r1 may not be forwarded + return std::ranges::empty(__r2) || !(oneapi::dpl::ranges::search(std::forward<_ExecutionPolicy>(__exec), __r1, __r2, + __pred, __proj1, __proj2).empty()); + } +}; +inline constexpr __internal::__contains_subrange_fn contains_subrange; + // [alg.count] struct __internal::__count_if_fn diff --git a/test/parallel_api/ranges/std_ranges_contains.pass.cpp b/test/parallel_api/ranges/std_ranges_contains.pass.cpp new file mode 100644 index 00000000000..ca7720df445 --- /dev/null +++ b/test/parallel_api/ranges/std_ranges_contains.pass.cpp @@ -0,0 +1,45 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) 2026 UXL Foundation Contributors +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "std_ranges_test.h" + +#if _ENABLE_STD_RANGES_TESTING +#if __cpp_lib_ranges_contains >= 202207L + auto contains_checker = TEST_PREPARE_CALLABLE(std::ranges::contains); +#else + struct { + template + bool operator()(R&& r, V value, Proj proj = {}) + { + auto last = std::ranges::end(r); + return std::ranges::find(std::ranges::begin(r), last, value, proj) != last; + } + } contains_checker; +#endif +#endif + +std::int32_t +main() +{ +#if _ENABLE_STD_RANGES_TESTING + using namespace test_std_ranges; + namespace dpl_ranges = oneapi::dpl::ranges; + + // expected to be found + test_range_algo<0>{big_sz}(dpl_ranges::contains, contains_checker, small_size - 19); + test_range_algo<1>{}(dpl_ranges::contains, contains_checker, proj(small_size/2 + 28), proj); + test_range_algo<2, P2>{}(dpl_ranges::contains, contains_checker, 137, &P2::x); + + // expected to be absent + test_range_algo<3, P2>{}(dpl_ranges::contains, contains_checker, -27, &P2::proj); + test_range_algo<4>{big_sz}(dpl_ranges::contains, contains_checker, -43); +#endif //_ENABLE_STD_RANGES_TESTING + + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +} diff --git a/test/parallel_api/ranges/std_ranges_contains_subrange.pass.cpp b/test/parallel_api/ranges/std_ranges_contains_subrange.pass.cpp new file mode 100644 index 00000000000..5cf5aff335c --- /dev/null +++ b/test/parallel_api/ranges/std_ranges_contains_subrange.pass.cpp @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright (C) 2026 UXL Foundation Contributors +// +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "std_ranges_test.h" + +#if _ENABLE_STD_RANGES_TESTING + template + using launcher = test_std_ranges::test_range_algo; +#if __cpp_lib_ranges_contains >= 202207L + auto checker = TEST_PREPARE_CALLABLE(std::ranges::contains_subrange); +#else + struct { + template + bool operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) + { + if (std::ranges::begin(r2) == std::ranges::end(r2)) + return true; + auto&& result = std::ranges::search(r1, r2, pred, proj1, proj2); + return !result.empty(); + } + } checker; +#endif +#endif + +std::int32_t +main() +{ +#if _ENABLE_STD_RANGES_TESTING + using namespace test_std_ranges; + namespace dpl_ranges = oneapi::dpl::ranges; + + auto shift = [](auto i) { return i + 371; }; + using data_gen_shifted = decltype(shift); + + // Sizes of both sequences vary in the test, so each call might test both successful and unsuccessful searches + launcher<0, int>{big_sz}(dpl_ranges::contains_subrange, checker, binary_pred_const); + launcher<1, int>{}(dpl_ranges::contains_subrange, checker); + launcher<2, int>{}(dpl_ranges::contains_subrange, checker, binary_pred, dpl::identity{}); + launcher<3, int, data_gen_shifted>{big_sz}(dpl_ranges::contains_subrange, checker, binary_pred, proj, proj); + launcher<4, P3, data_gen_shifted>{}(dpl_ranges::contains_subrange, checker, binary_pred_const, &P3::x, &P3::proj); + launcher<5, P3>{}(dpl_ranges::contains_subrange, checker, std::equal_to<>{}, &P3::proj, &P3::y); +#endif //_ENABLE_STD_RANGES_TESTING + + return TestUtils::done(_ENABLE_STD_RANGES_TESTING); +}