Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions include/oneapi/dpl/pstl/glue_algorithm_ranges_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ struct __reverse_copy_fn;
struct __mismatch_fn;
struct __remove_if_fn;
struct __remove_fn;
struct __remove_copy_if_fn;
struct __remove_copy_fn;
struct __unique_fn;
struct __unique_copy_fn;
} // namespace ranges::__internal
Expand Down
62 changes: 55 additions & 7 deletions include/oneapi/dpl/pstl/glue_algorithm_ranges_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ struct __internal::__find_fn
std::ranges::borrowed_iterator_t<_R>
operator()(_ExecutionPolicy&& __exec, _R&& __r, const _T& __value, _Proj __proj = {}) const
{
// TODO: make sure std::ranges::equal_to is used for comparison
return oneapi::dpl::ranges::find_if(std::forward<_ExecutionPolicy>(__exec), std::forward<_R>(__r),
oneapi::dpl::__internal::__equal_value<oneapi::dpl::__internal::__ref_or_copy<_ExecutionPolicy,
const _T>>(__value), __proj);
Expand Down Expand Up @@ -365,6 +366,7 @@ struct __internal::__count_fn
operator()(_ExecutionPolicy&& __exec, _R&& __r, const _T& __value, _Proj __proj = {}) const
{
const auto __dispatch_tag = oneapi::dpl::__ranges::__select_backend(__exec);
// TODO: make sure std::ranges::equal_to is used for comparison
return oneapi::dpl::__internal::__ranges::__pattern_count(__dispatch_tag,
std::forward<_ExecutionPolicy>(__exec), std::forward<_R>(__r), __value, __proj);
}
Expand Down Expand Up @@ -912,6 +914,7 @@ struct __internal::__replace_fn
operator()(_ExecutionPolicy&& __exec, _R&& __r, const _T1& __old_value, const _T2& __new_value,
_Proj __proj = {}) const
{
// TODO: make sure std::ranges::equal_to is used for comparison
return oneapi::dpl::ranges::replace_if(
std::forward<_ExecutionPolicy>(__exec), std::forward<_R>(__r),
oneapi::dpl::__internal::__equal_value<oneapi::dpl::__internal::__ref_or_copy<_ExecutionPolicy, const _T1>>(
Expand Down Expand Up @@ -1029,10 +1032,10 @@ inline constexpr __internal::__mismatch_fn mismatch;

struct __internal::__remove_if_fn
{
template<typename _ExecutionPolicy, std::ranges::random_access_range _R, typename _Proj = std::identity,
std::indirect_unary_predicate<std::projected<std::ranges::iterator_t<_R>, _Proj>> _Pred>
template <typename _ExecutionPolicy, std::ranges::random_access_range _R, typename _Proj = std::identity,
std::indirect_unary_predicate<std::projected<std::ranges::iterator_t<_R>, _Proj>> _Pred>
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<_ExecutionPolicy>>
&& std::permutable<std::ranges::iterator_t<_R>> && std::ranges::sized_range<_R>
&& std::ranges::sized_range<_R> && std::permutable<std::ranges::iterator_t<_R>>

std::ranges::borrowed_subrange_t<_R>
operator()(_ExecutionPolicy&& __exec, _R&& __r, _Pred __pred, _Proj __proj = {}) const
Expand All @@ -1046,21 +1049,66 @@ inline constexpr __internal::__remove_if_fn remove_if;

struct __internal::__remove_fn
{
template<typename _ExecutionPolicy, std::ranges::random_access_range _R, typename _Proj = std::identity,
typename _T = oneapi::dpl::projected_value_t<std::ranges::iterator_t<_R>, _Proj>>
template <typename _ExecutionPolicy, std::ranges::random_access_range _R, typename _Proj = std::identity,
typename _T = oneapi::dpl::projected_value_t<std::ranges::iterator_t<_R>, _Proj>>
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<_ExecutionPolicy>>
&& std::permutable<std::ranges::iterator_t<_R>> && std::indirect_binary_predicate<std::ranges::equal_to,
std::projected<std::ranges::iterator_t<_R>, _Proj>, const _T*> && std::ranges::sized_range<_R>
&& std::ranges::sized_range<_R> && std::permutable<std::ranges::iterator_t<_R>>
&& std::indirect_binary_predicate<std::ranges::equal_to,
std::projected<std::ranges::iterator_t<_R>, _Proj>, const _T*>

std::ranges::borrowed_subrange_t<_R>
operator()(_ExecutionPolicy&& __exec, _R&& __r, const _T& __value, _Proj __proj = {}) const
{
// TODO: change lambda to a special functor
return oneapi::dpl::ranges::remove_if(std::forward<_ExecutionPolicy>(__exec), std::forward<_R>(__r),
[__value](auto&& __a) { return std::ranges::equal_to{}(__a, __value);}, __proj);
}
}; //__remove_fn
inline constexpr __internal::__remove_fn remove;

struct __internal::__remove_copy_if_fn
{
template <typename _ExecutionPolicy, std::ranges::random_access_range _R, std::ranges::random_access_range _OutR,
typename _Proj = std::identity,
std::indirect_unary_predicate<std::projected<std::ranges::iterator_t<_R>, _Proj>> _Pred>
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<_ExecutionPolicy>>
&& std::ranges::sized_range<_R> && std::ranges::sized_range<_OutR>
&& std::indirectly_copyable<std::ranges::iterator_t<_R>, std::ranges::iterator_t<_OutR>>

std::ranges::remove_copy_if_result<std::ranges::borrowed_iterator_t<_R>, std::ranges::borrowed_iterator_t<_OutR>>
operator()(_ExecutionPolicy&& __exec, _R&& __r, _OutR&& __out_r, _Pred __pred, _Proj __proj = {}) const
{
return oneapi::dpl::ranges::copy_if(
std::forward<_ExecutionPolicy>(__exec), std::forward<_R>(__r), std::forward<_OutR>(__out_r),
oneapi::dpl::__internal::__not_pred<
oneapi::dpl::__internal::__ref_or_copy<_ExecutionPolicy, _Pred>>(__pred), __proj);
}
}; //__remove_copy_if_fn
inline constexpr __internal::__remove_copy_if_fn remove_copy_if;

struct __internal::__remove_copy_fn
{
template <typename _ExecutionPolicy, std::ranges::random_access_range _R, std::ranges::random_access_range _OutR,
typename _Proj = std::identity,
typename _T = oneapi::dpl::projected_value_t<std::ranges::iterator_t<_R>, _Proj>>
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<_ExecutionPolicy>>
&& std::ranges::sized_range<_R> && std::ranges::sized_range<_OutR>
&& std::indirectly_copyable<std::ranges::iterator_t<_R>, std::ranges::iterator_t<_OutR>>
&& std::indirect_binary_predicate<std::ranges::equal_to,
std::projected<std::ranges::iterator_t<_R>, _Proj>, const _T*>

std::ranges::remove_copy_result<std::ranges::borrowed_iterator_t<_R>, std::ranges::borrowed_iterator_t<_OutR>>
operator()(_ExecutionPolicy&& __exec, _R&& __r, _OutR&& __out_r, const _T& __value, _Proj __proj = {}) const
{
// TODO: make sure std::ranges::equal_to is used for comparison
return oneapi::dpl::ranges::copy_if(
std::forward<_ExecutionPolicy>(__exec), std::forward<_R>(__r), std::forward<_OutR>(__out_r),
oneapi::dpl::__internal::__not_equal_value<
oneapi::dpl::__internal::__ref_or_copy<_ExecutionPolicy, const _T>>(__value), __proj);
}
}; //__remove_copy_fn
inline constexpr __internal::__remove_copy_fn remove_copy;

// [alg.unique]

struct __internal::__unique_fn
Expand Down
120 changes: 120 additions & 0 deletions test/parallel_api/ranges/std_ranges_remove_copy.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Copyright (C) UXL Foundation Contributors
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "std_ranges_test.h"

#if _ENABLE_STD_RANGES_TESTING
#include <initializer_list>

struct
{
template <std::ranges::random_access_range InRange, std::ranges::random_access_range OutRange,
typename V, typename Proj = std::identity>
auto operator()(InRange&& r_in, OutRange&& r_out, const V& value, Proj proj = {})
{
using ret_type = std::ranges::remove_copy_result<std::ranges::borrowed_iterator_t<InRange>,
std::ranges::borrowed_iterator_t<OutRange>>;
auto in = std::ranges::begin(r_in);
auto out = std::ranges::begin(r_out);
std::size_t i = 0, j = 0;
for(; i < std::ranges::size(r_in); ++i)
{
if (!std::ranges::equal_to{}(std::invoke(proj, in[i]), value))
{
if (j < std::ranges::size(r_out))
out[j++] = in[i];
else
break;
}
}
return ret_type{in + i, out + j};
}

void test_self()
{
#if TEST_CPP20_SPAN_PRESENT
int input[10] = {0,0, 1, 2,2, 8, 1,1,1, 8};
int output[9] = {-9, -8, -7, -6, -5, -4, -3, -2, -1};

// Define test cases with expected outputs and expected end positions
struct TestCase {
int in_size;
int out_size;
std::initializer_list<int> expected_output;
int expected_in_end;
int expected_out_end;
} test_cases[] = {
// insz, outsz, expected, instop, outstop
{0, 0, {}, 0, 0}, // Empty ranges
{10, 0, {}, 0, 0}, // Empty output range
{1, 1, {0}, 1, 1}, // One element ranges
{10, 1, {0}, 1, 1}, // One element output range
{10, 5, {0, 0, 2, 2, 8}, 9, 5}, // Output range is not big enough
{10, 6, {0, 0, 2, 2, 8, 8}, 10, 6}, // Output range is just enough
{10, 7, {0, 0, 2, 2, 8, 8}, 10, 6}, // Output range is bigger than needed
};

auto& self = *this;
for (const TestCase& test_case : test_cases) {
constexpr int shift = 1;
std::span<int> in_span(input, test_case.in_size);
std::span<int> out_span(output + shift, test_case.out_size);

auto result = self(in_span, out_span, 1);

// Verify the returned iterators point to the correct end positions
EXPECT_EQ(in_span.begin() + test_case.expected_in_end, result.in, "Checker problem: wrong input stop");
EXPECT_EQ(out_span.begin() + test_case.expected_out_end, result.out, "Checker problem: wrong output stop");

// Verify the output matches the expected result and nothing is overwritten
for (int i = 0; i < 9; ++i)
{
if (i < shift || i >= shift + test_case.expected_out_end)
{
EXPECT_EQ(i - 9, output[i], "Checker problem: out of range modification");
}
else
{
EXPECT_EQ(test_case.expected_output.begin()[i - shift], output[i], "Checker problem: wrong output");
output[i] = i - 9; // Restore the original output data
}
}
}
#endif // TEST_CPP20_SPAN_PRESENT
}
} remove_copy_checker;
#endif // _ENABLE_STD_RANGES_TESTING

std::int32_t
main()
{
#if _ENABLE_STD_RANGES_TESTING
using namespace test_std_ranges;
namespace dpl_ranges = oneapi::dpl::ranges;

auto almost_always_two = [](auto i) {
if (i%7 > 0 && (i - 1)%3 == 0)
return i;
return 2;
};
using many_twos = decltype(almost_always_two);

remove_copy_checker.test_self();

test_range_algo<0, int, data_in_out_lim>{179}(dpl_ranges::remove_copy, remove_copy_checker, 0);
test_range_algo<1, int, data_in_out_lim, many_twos>{1127}(dpl_ranges::remove_copy, remove_copy_checker, 2);
test_range_algo<2, int, data_in_out_lim>{}(dpl_ranges::remove_copy, remove_copy_checker, 1, proj);
test_range_algo<3, P2, data_in_out_lim, many_twos>{}(dpl_ranges::remove_copy, remove_copy_checker, 2, &P2::x);
test_range_algo<4, P2, data_in_out_lim>{}(dpl_ranges::remove_copy, remove_copy_checker, 0, &P2::proj);
test_range_algo<5, int, data_in_out_lim>{big_sz}(dpl_ranges::remove_copy, remove_copy_checker, 1);
test_range_algo<6, int, data_in_out_lim, many_twos>{big_sz}(dpl_ranges::remove_copy, remove_copy_checker, 2);
#endif // _ENABLE_STD_RANGES_TESTING

return TestUtils::done(_ENABLE_STD_RANGES_TESTING);
}
125 changes: 125 additions & 0 deletions test/parallel_api/ranges/std_ranges_remove_copy_if.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Copyright (C) UXL Foundation Contributors
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "std_ranges_test.h"

#if _ENABLE_STD_RANGES_TESTING
#include <initializer_list>

struct
{
template <std::ranges::random_access_range InRange, std::ranges::random_access_range OutRange,
typename Pred, typename Proj = std::identity>
auto operator()(InRange&& r_in, OutRange&& r_out, Pred pred, Proj proj = {})
{
using ret_type = std::ranges::remove_copy_if_result<std::ranges::borrowed_iterator_t<InRange>,
std::ranges::borrowed_iterator_t<OutRange>>;
auto in = std::ranges::begin(r_in);
auto out = std::ranges::begin(r_out);
std::size_t i = 0, j = 0;
for(; i < std::ranges::size(r_in); ++i)
{
if (!std::invoke(pred, std::invoke(proj, in[i])))
{
if (j < std::ranges::size(r_out))
out[j++] = in[i];
else
break;
}
}
return ret_type{in + i, out + j};
}

void test_self()
{
#if TEST_CPP20_SPAN_PRESENT
int input[10] = {0,0, 1, 2,2, 8, 1,1,1, 8};
int output[9] = {-9, -8, -7, -6, -5, -4, -3, -2, -1};

// Define test cases with expected outputs and expected end positions
struct TestCase {
int in_size;
int out_size;
std::initializer_list<int> expected_output;
int expected_in_end;
int expected_out_end;
} test_cases[] = {
// insz, outsz, expected, instop, outstop
{0, 0, {}, 0, 0}, // Empty ranges
{10, 0, {}, 0, 0}, // Empty output range
{1, 1, {0}, 1, 1}, // One element ranges
{10, 1, {0}, 1, 1}, // One element output range
{10, 5, {0, 0, 2, 2, 8}, 9, 5}, // Output range is not big enough
{10, 6, {0, 0, 2, 2, 8, 8}, 10, 6}, // Output range is just enough
{10, 7, {0, 0, 2, 2, 8, 8}, 10, 6}, // Output range is bigger than needed
};

auto& self = *this;
for (const TestCase& test_case : test_cases) {
constexpr int shift = 1;
std::span<int> in_span(input, test_case.in_size);
std::span<int> out_span(output + shift, test_case.out_size);

auto result = self(in_span, out_span, [](int v){ return v == 1; });

// Verify the returned iterators point to the correct end positions
EXPECT_EQ(in_span.begin() + test_case.expected_in_end, result.in, "Checker problem: wrong input stop");
EXPECT_EQ(out_span.begin() + test_case.expected_out_end, result.out, "Checker problem: wrong output stop");

// Verify the output matches the expected result and nothing is overwritten
for (int i = 0; i < 9; ++i)
{
if (i < shift || i >= shift + test_case.expected_out_end)
{
EXPECT_EQ(i - 9, output[i], "Checker problem: out of range modification");
}
else
{
EXPECT_EQ(test_case.expected_output.begin()[i - shift], output[i], "Checker problem: wrong output");
output[i] = i - 9; // Restore the original output data
}
}
}
#endif // TEST_CPP20_SPAN_PRESENT
}
} remove_copy_if_checker;
#endif // _ENABLE_STD_RANGES_TESTING

std::int32_t
main()
{
#if _ENABLE_STD_RANGES_TESTING
using namespace test_std_ranges;
namespace dpl_ranges = oneapi::dpl::ranges;

// input generator with a fair chance of repeating the previous value
auto repeat_sometimes = [](auto i) {
static decltype(i) last = 0;
if (i == 0)
last = 0; // reset
else if (i%7 > 0 && (last + i - 1)%3 == 0)
last = i;
return last;
};
using repeating_gen = decltype(repeat_sometimes);
auto modulo_3_is_1 = [](int val) { return (val % 3) == 1; };

remove_copy_if_checker.test_self();

test_range_algo<0, int, data_in_out_lim>{239}(dpl_ranges::remove_copy_if, remove_copy_if_checker, pred);
test_range_algo<1, int, data_in_out_lim>{1471}(dpl_ranges::remove_copy_if, remove_copy_if_checker, select_many);
test_range_algo<2, int, data_in_out_lim>{}(dpl_ranges::remove_copy_if, remove_copy_if_checker, select_many, proj);
test_range_algo<3, P2, data_in_out_lim, repeating_gen>{}(dpl_ranges::remove_copy_if, remove_copy_if_checker, modulo_3_is_1, &P2::x);
test_range_algo<4, P2, data_in_out_lim>{}(dpl_ranges::remove_copy_if, remove_copy_if_checker, pred, &P2::proj);
test_range_algo<5, int, data_in_out_lim>{big_sz}(dpl_ranges::remove_copy_if, remove_copy_if_checker, pred);
test_range_algo<6, int, data_in_out_lim, repeating_gen>{big_sz}(dpl_ranges::remove_copy_if, remove_copy_if_checker, select_many);
#endif // _ENABLE_STD_RANGES_TESTING

return TestUtils::done(_ENABLE_STD_RANGES_TESTING);
}
3 changes: 2 additions & 1 deletion test/parallel_api/ranges/std_ranges_unique_copy.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include "std_ranges_test.h"

#if _ENABLE_STD_RANGES_TESTING
#include <span>
#include <initializer_list>

struct
Expand Down Expand Up @@ -45,6 +44,7 @@ struct

void test_self()
{
#if TEST_CPP20_SPAN_PRESENT
int input[10] = {0,0, 1, 2,2, 8, 1,1,1, 8};
int output[9] = {-9, -8, -7, -6, -5, -4, -3, -2, -1};

Expand Down Expand Up @@ -92,6 +92,7 @@ struct
}
}
}
#endif // TEST_CPP20_SPAN_PRESENT
}
} unique_copy_checker;
#endif // _ENABLE_STD_RANGES_TESTING
Expand Down
Loading