Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5fd7338
[parallel] Fix hpx::nth_element to correctly support projections and …
dasaneek007-cpu Apr 16, 2026
181ec0a
Apply clang-format fixes
dasaneek007-cpu Apr 16, 2026
f895d19
Merge branch 'master' into fix/nth-element-projections-sentinels
aneek22112007-tech Apr 16, 2026
b0ebd62
Remove <iostream> inclusion to fix hpxinspect failure
dasaneek007-cpu Apr 16, 2026
9740280
Revert hpx::nth_element to standard compliance, move projections/sent…
dasaneek007-cpu Apr 16, 2026
e58f6aa
Address maintainer feedback: consolidate wrapped_comp_type and use st…
dasaneek007-cpu Apr 16, 2026
8199058
Apply clang-format fixes
dasaneek007-cpu Apr 16, 2026
5590bc1
Fix macOS CI: avoid detail::min_element type-matching issue with proj…
dasaneek007-cpu Apr 17, 2026
891e829
Merge branch 'master' into fix/nth-element-projections-sentinels
aneek22112007-tech Apr 17, 2026
5f9a80b
Fix type deduction in minmax.hpp and remove workaround in nth_element…
dasaneek007-cpu Apr 17, 2026
e61e974
Apply clang-format corrections to minmax.hpp
dasaneek007-cpu Apr 17, 2026
3ad02be
Fix clang-format in minmax.hpp after CI failure
dasaneek007-cpu Apr 17, 2026
c860663
Fix clang-format in minmax.hpp (final attempt)
dasaneek007-cpu Apr 17, 2026
e993817
Automated clang-format fix using opt/homebrew/bin/clang-format
dasaneek007-cpu Apr 17, 2026
30cf465
Refine element_type deduction to handle HPX proxies using proxy_value_t
dasaneek007-cpu Apr 18, 2026
0e2e53e
Remove redundant typename keywords as requested by maintainer
dasaneek007-cpu Apr 19, 2026
865d418
Restore typename keywords (strictly required for CI builds)
dasaneek007-cpu Apr 19, 2026
a4b4a86
Separate core fix into independent PR and restore temporary workaround
dasaneek007-cpu Apr 19, 2026
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
33 changes: 20 additions & 13 deletions libs/core/algorithms/include/hpx/parallel/algorithms/minmax.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,8 @@ namespace hpx::parallel {
return it;

using element_type = hpx::traits::proxy_value_t<
typename std::iterator_traits<FwdIter>::value_type>;
std::decay_t<hpx::util::invoke_result_t<Proj,
typename std::iterator_traits<FwdIter>::reference>>>;
Comment thread
hkaiser marked this conversation as resolved.
Outdated

auto smallest = it;

Expand Down Expand Up @@ -442,9 +443,9 @@ namespace hpx::parallel {

auto smallest = *it;

using element_type =
hpx::traits::proxy_value_t<typename std::iterator_traits<
decltype(smallest)>::value_type>;
using element_type = hpx::traits::proxy_value_t<
std::decay_t<hpx::util::invoke_result_t<Proj,
typename std::iterator_traits<Iter>::reference>>>;

element_type value = HPX_INVOKE(proj, *smallest);
util::loop_n<std::decay_t<ExPolicy>>(
Expand Down Expand Up @@ -474,7 +475,8 @@ namespace hpx::parallel {
return first;

using element_type = hpx::traits::proxy_value_t<
typename std::iterator_traits<FwdIter>::value_type>;
std::decay_t<hpx::util::invoke_result_t<Proj,
typename std::iterator_traits<FwdIter>::reference>>>;

auto smallest = first;

Expand Down Expand Up @@ -557,7 +559,8 @@ namespace hpx::parallel {
return it;

using element_type = hpx::traits::proxy_value_t<
typename std::iterator_traits<FwdIter>::value_type>;
std::decay_t<hpx::util::invoke_result_t<Proj,
typename std::iterator_traits<FwdIter>::reference>>>;

auto largest = it;

Expand Down Expand Up @@ -594,9 +597,9 @@ namespace hpx::parallel {

auto largest = *it;

using element_type =
hpx::traits::proxy_value_t<typename std::iterator_traits<
decltype(largest)>::value_type>;
using element_type = hpx::traits::proxy_value_t<
std::decay_t<hpx::util::invoke_result_t<Proj,
typename std::iterator_traits<Iter>::reference>>>;

element_type value = HPX_INVOKE(proj, *largest);
util::loop_n<std::decay_t<ExPolicy>>(
Expand Down Expand Up @@ -626,7 +629,8 @@ namespace hpx::parallel {
return first;

using element_type = hpx::traits::proxy_value_t<
typename std::iterator_traits<FwdIter>::value_type>;
std::decay_t<hpx::util::invoke_result_t<Proj,
typename std::iterator_traits<FwdIter>::reference>>>;

auto largest = first;

Expand Down Expand Up @@ -711,7 +715,8 @@ namespace hpx::parallel {
return result;

using element_type = hpx::traits::proxy_value_t<
typename std::iterator_traits<FwdIter>::value_type>;
std::decay_t<hpx::util::invoke_result_t<Proj,
typename std::iterator_traits<FwdIter>::reference>>>;

element_type min_value = HPX_INVOKE(proj, *it);
element_type max_value = min_value;
Expand Down Expand Up @@ -752,7 +757,8 @@ namespace hpx::parallel {
return *it;

using element_type = hpx::traits::proxy_value_t<
typename std::iterator_traits<Iter>::value_type>;
std::decay_t<hpx::util::invoke_result_t<Proj,
typename std::iterator_traits<Iter>::reference>>>;

auto result = *it;

Expand Down Expand Up @@ -800,7 +806,8 @@ namespace hpx::parallel {
}

using element_type = hpx::traits::proxy_value_t<
typename std::iterator_traits<FwdIter>::value_type>;
std::decay_t<hpx::util::invoke_result_t<Proj,
typename std::iterator_traits<FwdIter>::reference>>>;

element_type min_value = HPX_INVOKE(proj, *min);
element_type max_value = HPX_INVOKE(proj, *max);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,14 @@ namespace hpx {
#include <hpx/modules/executors.hpp>
#include <hpx/modules/functional.hpp>
#include <hpx/modules/iterator_support.hpp>
#include <hpx/parallel/algorithms/detail/advance_to_sentinel.hpp>
#include <hpx/parallel/algorithms/detail/dispatch.hpp>
#include <hpx/parallel/algorithms/detail/pivot.hpp>
#include <hpx/parallel/algorithms/make_heap.hpp>
#include <hpx/parallel/algorithms/minmax.hpp>
#include <hpx/parallel/algorithms/partial_sort.hpp>
#include <hpx/parallel/algorithms/partition.hpp>
#include <hpx/parallel/util/compare_projected.hpp>
#include <hpx/parallel/util/detail/algorithm_result.hpp>
#include <hpx/parallel/util/detail/sender_util.hpp>

Expand Down Expand Up @@ -180,6 +183,10 @@ namespace hpx::parallel {
constexpr void nth_element_seq(RandomIt first, RandomIt nth,
RandomIt end, std::uint32_t level, Compare&& comp, Proj&& proj)
{
using wrapped_comp_type =
hpx::parallel::util::compare_projected<std::decay_t<Compare>,
std::decay_t<Proj>>;

constexpr std::uint32_t nmin_sort = 24;
auto nelem = end - first;

Expand All @@ -206,13 +213,13 @@ namespace hpx::parallel {
}
if (level == 0)
{
std::make_heap(first, end, comp);
std::sort_heap(first, nth, comp);
std::make_heap(first, end, wrapped_comp_type(comp, proj));
std::sort_heap(first, nth, wrapped_comp_type(comp, proj));
return;
}

// Filter the range and check which part contains the nth element
RandomIt c_last = filter(first, end, comp);
RandomIt c_last = filter(first, end, wrapped_comp_type(comp, proj));

if (c_last == nth)
return;
Expand Down Expand Up @@ -263,9 +270,6 @@ namespace hpx::parallel {
parallel(ExPolicy&& policy, RandomIt first, RandomIt nth, Sent last,
Pred&& pred, Proj&& proj)
{
using value_type =
typename std::iterator_traits<RandomIt>::value_type;

RandomIt partition_iter, return_last;

if (first == last)
Expand All @@ -288,17 +292,21 @@ namespace hpx::parallel {

while (first != last_iter)
{
detail::pivot9(first, last_iter, pred);
detail::pivot9(first, last_iter,
hpx::parallel::util::compare_projected<
std::decay_t<Pred>, std::decay_t<Proj>>(
pred, proj));

partition_iter =
hpx::parallel::detail::partition<RandomIt>().call(
policy(hpx::execution::non_task), first + 1,
last_iter,
[val = HPX_INVOKE(proj, *first), &pred](
value_type const& elem) {
return HPX_INVOKE(pred, elem, val);
[val = HPX_INVOKE(proj, *first), &pred, &proj](
auto const& elem) {
return HPX_INVOKE(
pred, HPX_INVOKE(proj, elem), val);
},
proj);
hpx::identity_v);

--partition_iter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@

#include "test_utils.hpp"

struct S
{
std::size_t val;
};

////////////////////////////////////////////////////////////////////////////
#define SIZE 10007

Expand Down Expand Up @@ -198,6 +203,65 @@ void test_nth_element_async(ExPolicy policy, IteratorTag)
}
}

template <typename ExPolicy>
void test_nth_element_projection(ExPolicy policy)
{
static_assert(hpx::is_execution_policy<ExPolicy>::value,
"hpx::is_execution_policy<ExPolicy>::value");

std::vector<S> c(SIZE);
for (std::size_t i = 0; i < SIZE; ++i)
c[i].val = SIZE - i;

auto rand_index = std::rand() % SIZE;
auto nth = std::begin(c) + rand_index;

hpx::ranges::nth_element(policy, c, nth, std::less<std::size_t>{}, &S::val);

for (int k = 0; k < rand_index; k++)
{
HPX_TEST(c[k].val <= c[rand_index].val);
}

for (int k = rand_index + 1; k < SIZE; k++)
{
HPX_TEST(c[k].val >= c[rand_index].val);
}
}

template <typename ExPolicy, typename IteratorTag>
void test_nth_element_sent_projection(ExPolicy policy, IteratorTag)
{
static_assert(hpx::is_execution_policy<ExPolicy>::value,
"hpx::is_execution_policy<ExPolicy>::value");

using base_iterator = std::vector<S>::iterator;
using iterator = test::test_iterator<base_iterator, IteratorTag>;
using sentinel = test::sentinel_from_iterator<iterator>;

std::vector<S> c(SIZE);
for (std::size_t i = 0; i < SIZE; ++i)
c[i].val = SIZE - i;

auto rand_index = std::rand() % SIZE;

auto result = hpx::ranges::nth_element(policy, iterator(std::begin(c)),
iterator(std::begin(c) + rand_index),
sentinel(iterator(std::end(c) - 1)), std::less<std::size_t>{}, &S::val);

HPX_TEST(result == iterator(std::end(c) - 1));

for (int k = 0; k < rand_index; k++)
{
HPX_TEST(c[k].val <= c[rand_index].val);
}

for (int k = rand_index + 1; k < SIZE - 1; k++)
{
HPX_TEST(c[k].val >= c[rand_index].val);
}
}

template <typename IteratorTag>
void test_nth_element()
{
Expand All @@ -215,6 +279,14 @@ void test_nth_element()
test_nth_element_sent(seq, IteratorTag());
test_nth_element_sent(par, IteratorTag());
test_nth_element_sent(par_unseq, IteratorTag());

test_nth_element_projection(seq);
test_nth_element_projection(par);
test_nth_element_projection(par_unseq);

test_nth_element_sent_projection(seq, IteratorTag());
test_nth_element_sent_projection(par, IteratorTag());
test_nth_element_sent_projection(par_unseq, IteratorTag());
}

void nth_element_test()
Expand Down
Loading