Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -614,13 +614,14 @@ namespace hpx::parallel {
});
};

auto f4 = [first, dest, flags](std::vector<std::size_t>&& items,
auto f4 = [first, count, dest, flags](
std::vector<std::size_t>&& items,
std::vector<hpx::future<void>>&& data) mutable
-> util::in_out_result<FwdIter1, FwdIter3> {
HPX_UNUSED(flags);

auto dist = items.back();
std::advance(first, dist);
std::advance(first, count);
std::advance(dest, dist);

// make sure iterators embedded in function object that is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,13 +382,10 @@ namespace hpx::parallel {
parallel(ExPolicy&& policy, FwdIter1 first, Sent last,
FwdIter2 dest, F&& f, Proj&& proj)
{
using value_type =
typename std::iterator_traits<FwdIter1>::value_type;

return copy_if<IterPair>().call(
HPX_FORWARD(ExPolicy, policy), first, last, dest,
[f = HPX_FORWARD(F, f)](value_type const& a) -> bool {
return !HPX_INVOKE(f, a);
[f = HPX_FORWARD(F, f)](auto&& a) -> bool {
return !HPX_INVOKE(f, HPX_FORWARD(decltype(a), a));
},
HPX_FORWARD(Proj, proj));
}
Expand Down Expand Up @@ -444,10 +441,12 @@ namespace hpx {
>
)
// clang-format on
// clang-format off
friend typename parallel::util::detail::algorithm_result<ExPolicy,
FwdIter2>::type
tag_fallback_invoke(hpx::remove_copy_if_t, ExPolicy&& policy,
FwdIter1 first, FwdIter1 last, FwdIter2 dest, Pred pred)
// clang-format on
{
static_assert(std::forward_iterator<FwdIter1>,
"Required at least forward iterator.");
Expand Down Expand Up @@ -503,10 +502,12 @@ namespace hpx {
hpx::traits::is_iterator_v<FwdIter2>
)
// clang-format on
// clang-format off
friend typename parallel::util::detail::algorithm_result<ExPolicy,
FwdIter2>::type
tag_fallback_invoke(hpx::remove_copy_t, ExPolicy&& policy,
FwdIter1 first, FwdIter1 last, FwdIter2 dest, T const& value)
// clang-format on
{
static_assert(std::forward_iterator<FwdIter1>,
"Required at least forward iterator.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,11 @@ namespace hpx::parallel {
if (first == last)
return first;

using element_type =
typename std::iterator_traits<FwdIter>::value_type;
using projected_type = std::decay_t<std::invoke_result_t<Proj,
typename std::iterator_traits<FwdIter>::reference>>;

FwdIter result = first;
element_type result_projected = HPX_INVOKE(proj, *result);
projected_type result_projected = HPX_INVOKE(proj, *result);
while (++first != last)
{
if (!HPX_INVOKE(
Expand Down Expand Up @@ -500,12 +500,12 @@ namespace hpx::parallel {
HPX_MOVE(first), HPX_MOVE(dest)};
}

using element_type =
typename std::iterator_traits<FwdIter>::value_type;
using projected_type = std::decay_t<std::invoke_result_t<Proj,
typename std::iterator_traits<FwdIter>::reference>>;

FwdIter base = first;
*dest++ = *first;
element_type base_projected = HPX_INVOKE(proj, *base);
projected_type base_projected = HPX_INVOKE(proj, *base);

while (++first != last)
{
Expand Down Expand Up @@ -533,8 +533,10 @@ namespace hpx::parallel {

using element_type =
typename std::iterator_traits<InIter>::value_type;
using projected_type = std::decay_t<std::invoke_result_t<Proj,
typename std::iterator_traits<InIter>::reference>>;
element_type base_val = *first;
element_type base_projected = HPX_INVOKE(proj, base_val);
projected_type base_projected = HPX_INVOKE(proj, base_val);

*dest++ = base_val;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -614,8 +614,9 @@ namespace hpx::ranges {
hpx::parallel::traits::is_projected_v<Proj, I> &&
std::sentinel_for<Sent, I> &&
hpx::traits::is_iterator_v<O> &&
hpx::is_invocable_v<Pred,
typename std::iterator_traits<I>::value_type
hpx::parallel::traits::is_indirect_callable_v<
hpx::execution::sequenced_policy, Pred,
hpx::parallel::traits::projected<Proj, I>
>
)
// clang-format on
Expand All @@ -638,12 +639,11 @@ namespace hpx::ranges {
typename Proj = hpx::identity>
// clang-format off
requires(
std::ranges::range<Rng>&&
hpx::parallel::traits::is_projected_range_v<Proj,Rng> &&
hpx::is_invocable_v<Pred,
typename std::iterator_traits<
std::ranges::iterator_t<Rng>
>::value_type
std::ranges::range<Rng> &&
hpx::parallel::traits::is_projected_range_v<Proj, Rng> &&
hpx::parallel::traits::is_indirect_callable_v<
hpx::execution::sequenced_policy, Pred,
hpx::parallel::traits::projected_range<Proj, Rng>
>
)
// clang-format on
Expand All @@ -664,13 +664,14 @@ namespace hpx::ranges {
typename Pred, typename Proj = hpx::identity>
// clang-format off
requires(
hpx::is_execution_policy_v<ExPolicy>&&
hpx::is_execution_policy_v<ExPolicy> &&
hpx::traits::is_iterator_v<I> &&
std::sentinel_for<Sent, I> &&
hpx::traits::is_iterator_v<O> &&
hpx::parallel::traits::is_projected_v<Proj, I> &&
hpx::is_invocable_v<Pred,
typename std::iterator_traits<I>::value_type
hpx::parallel::traits::is_indirect_callable_v<
ExPolicy, Pred,
hpx::parallel::traits::projected<Proj, I>
>
)
// clang-format on
Expand Down Expand Up @@ -698,10 +699,9 @@ namespace hpx::ranges {
hpx::is_execution_policy_v<ExPolicy> &&
std::ranges::range<Rng> &&
hpx::parallel::traits::is_projected_range_v<Proj, Rng> &&
hpx::is_invocable_v<Pred,
typename std::iterator_traits<
std::ranges::iterator_t<Rng>
>::value_type
hpx::parallel::traits::is_indirect_callable_v<
ExPolicy, Pred,
hpx::parallel::traits::projected_range<Proj, Rng>
>
)
// clang-format on
Expand Down Expand Up @@ -745,11 +745,9 @@ namespace hpx::ranges {
static_assert(
std::input_iterator<I>, "Required at least input iterator.");

using type = typename std::iterator_traits<I>::value_type;

return hpx::ranges::remove_copy_if(
first, last, dest,
[value](type const& a) -> bool { return value == a; },
[value](T const& a) -> bool { return value == a; },
HPX_MOVE(proj));
}

Expand All @@ -769,12 +767,9 @@ namespace hpx::ranges {
static_assert(std::input_iterator<std::ranges::iterator_t<Rng>>,
"Required at input forward iterator.");

using type = typename std::iterator_traits<
std::ranges::iterator_t<Rng>>::value_type;

return hpx::ranges::remove_copy_if(
HPX_FORWARD(Rng, rng), dest,
[value](type const& a) -> bool { return value == a; },
[value](T const& a) -> bool { return value == a; },
HPX_MOVE(proj));
}

Expand All @@ -799,11 +794,9 @@ namespace hpx::ranges {
static_assert(std::forward_iterator<I>,
"Required at least forward iterator.");

using type = typename std::iterator_traits<I>::value_type;

return hpx::ranges::remove_copy_if(
HPX_FORWARD(ExPolicy, policy), first, last, dest,
[value](type const& a) -> bool { return value == a; },
[value](T const& a) -> bool { return value == a; },
HPX_MOVE(proj));
}

Expand All @@ -826,12 +819,9 @@ namespace hpx::ranges {
static_assert(std::forward_iterator<std::ranges::iterator_t<Rng>>,
"Required at least forward iterator.");

using type = typename std::iterator_traits<
std::ranges::iterator_t<Rng>>::value_type;

return hpx::ranges::remove_copy_if(
HPX_FORWARD(ExPolicy, policy), HPX_FORWARD(Rng, rng), dest,
[value](type const& a) -> bool { return value == a; },
[value](T const& a) -> bool { return value == a; },
HPX_MOVE(proj));
}
} remove_copy{};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,150 @@ void test_partition_copy()
test_partition_copy_sent(par_unseq);
}

////////////////////////////////////////////////////////////////////////////
// Projection tests: project on the 'val' field of user_defined_type and
// apply a simple integer threshold predicate, distinct from the name-aware
// operator<(int) used by the existing tests.
void test_partition_copy_projection()
{
using DataType = user_defined_type;
using hpx::get;

std::size_t const size = 10007;
int rand_base = std::rand();

// pred operates on the projected int value
auto proj = [](DataType const& t) -> int { return t.val; };
auto pred = [rand_base](int v) -> bool { return v < rand_base; };
// oracle: apply proj then pred inline
auto std_pred = [rand_base, &proj](DataType const& e) -> bool {
return proj(e) < rand_base;
};

// No-policy (sequential) - range form
{
std::vector<DataType> c(size), d_true(size), d_false(size), t_sol(size),
f_sol(size);
std::generate(
std::begin(c), std::end(c), random_fill(rand_base, size / 10));

auto res = hpx::ranges::partition_copy(
c, std::begin(d_true), std::begin(d_false), pred, proj);
auto sol = std::partition_copy(std::begin(c), std::end(c),
std::begin(t_sol), std::begin(f_sol), std_pred);

HPX_TEST(res.in == std::end(c));
HPX_TEST(test::equal(
std::begin(d_true), res.out1, std::begin(t_sol), sol.first));
HPX_TEST(test::equal(
std::begin(d_false), res.out2, std::begin(f_sol), sol.second));
}

// seq policy
{
std::vector<DataType> c(size), d_true(size), d_false(size), t_sol(size),
f_sol(size);
std::generate(
std::begin(c), std::end(c), random_fill(rand_base, size / 10));

auto res = hpx::ranges::partition_copy(hpx::execution::seq, c,
std::begin(d_true), std::begin(d_false), pred, proj);
auto sol = std::partition_copy(std::begin(c), std::end(c),
std::begin(t_sol), std::begin(f_sol), std_pred);

HPX_TEST(res.in == std::end(c));
HPX_TEST(test::equal(
std::begin(d_true), res.out1, std::begin(t_sol), sol.first));
HPX_TEST(test::equal(
std::begin(d_false), res.out2, std::begin(f_sol), sol.second));
}

// par policy
{
std::vector<DataType> c(size), d_true(size), d_false(size), t_sol(size),
f_sol(size);
std::generate(
std::begin(c), std::end(c), random_fill(rand_base, size / 10));

auto res = hpx::ranges::partition_copy(hpx::execution::par, c,
std::begin(d_true), std::begin(d_false), pred, proj);
auto sol = std::partition_copy(std::begin(c), std::end(c),
std::begin(t_sol), std::begin(f_sol), std_pred);

HPX_TEST(res.in == std::end(c));
HPX_TEST(test::equal(
std::begin(d_true), res.out1, std::begin(t_sol), sol.first));
HPX_TEST(test::equal(
std::begin(d_false), res.out2, std::begin(f_sol), sol.second));
}

// par_unseq policy
{
std::vector<DataType> c(size), d_true(size), d_false(size), t_sol(size),
f_sol(size);
std::generate(
std::begin(c), std::end(c), random_fill(rand_base, size / 10));

auto res = hpx::ranges::partition_copy(hpx::execution::par_unseq, c,
std::begin(d_true), std::begin(d_false), pred, proj);
auto sol = std::partition_copy(std::begin(c), std::end(c),
std::begin(t_sol), std::begin(f_sol), std_pred);

HPX_TEST(res.in == std::end(c));
HPX_TEST(test::equal(
std::begin(d_true), res.out1, std::begin(t_sol), sol.first));
HPX_TEST(test::equal(
std::begin(d_false), res.out2, std::begin(f_sol), sol.second));
}

// seq(task) - async
{
std::vector<DataType> c(size), d_true(size), d_false(size), t_sol(size),
f_sol(size);
std::generate(
std::begin(c), std::end(c), random_fill(rand_base, size / 10));

auto f = hpx::ranges::partition_copy(
hpx::execution::seq(hpx::execution::task), c, std::begin(d_true),
std::begin(d_false), pred, proj);
auto sol = std::partition_copy(std::begin(c), std::end(c),
std::begin(t_sol), std::begin(f_sol), std_pred);
auto res = f.get();

HPX_TEST(res.in == std::end(c));
HPX_TEST(test::equal(
std::begin(d_true), res.out1, std::begin(t_sol), sol.first));
HPX_TEST(test::equal(
std::begin(d_false), res.out2, std::begin(f_sol), sol.second));
}

// par(task) - async
{
std::vector<DataType> c(size), d_true(size), d_false(size), t_sol(size),
f_sol(size);
std::generate(
std::begin(c), std::end(c), random_fill(rand_base, size / 10));

auto f = hpx::ranges::partition_copy(
hpx::execution::par(hpx::execution::task), c, std::begin(d_true),
std::begin(d_false), pred, proj);
auto sol = std::partition_copy(std::begin(c), std::end(c),
std::begin(t_sol), std::begin(f_sol), std_pred);
auto res = f.get();

HPX_TEST(res.in == std::end(c));
HPX_TEST(test::equal(
std::begin(d_true), res.out1, std::begin(t_sol), sol.first));
HPX_TEST(test::equal(
std::begin(d_false), res.out2, std::begin(f_sol), sol.second));
}
}

void test_partition_copy()
{
test_partition_copy<int>();
test_partition_copy<user_defined_type>();
test_partition_copy_projection();
}

int hpx_main(hpx::program_options::variables_map& vm)
Expand Down
Loading
Loading