Skip to content

Commit

Permalink
set_symmetric_difference and set_union adaptations for C++20
Browse files Browse the repository at this point in the history
- fixing set_operations to use projections
- fixing includes (lower_bound/upper_bound use projections)
- fixing return values for all set operations
  • Loading branch information
hkaiser committed Sep 21, 2020
1 parent 7cb87ae commit f26037c
Show file tree
Hide file tree
Showing 22 changed files with 3,321 additions and 496 deletions.
6 changes: 3 additions & 3 deletions docs/sphinx/api/public_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ Functions
- :cpp:func:`hpx::parallel::v1::rotate_copy`
- :cpp:func:`hpx::parallel::v1::search`
- :cpp:func:`hpx::parallel::v1::search_n`
- :cpp:func:`hpx::parallel::v1::set_difference`
- :cpp:func:`hpx::set_difference`
- :cpp:func:`hpx::set_intersection`
- :cpp:func:`hpx::parallel::v1::set_symmetric_difference`
- :cpp:func:`hpx::parallel::v1::set_union`
- :cpp:func:`hpx::set_symmetric_difference`
- :cpp:func:`hpx::set_union`
- :cpp:func:`hpx::parallel::v1::sort`
- :cpp:func:`hpx::parallel::v1::stable_partition`
- :cpp:func:`hpx::parallel::v1::stable_sort`
Expand Down
6 changes: 3 additions & 3 deletions docs/sphinx/manual/writing_single_node_hpx_applications.rst
Original file line number Diff line number Diff line change
Expand Up @@ -549,19 +549,19 @@ Parallel algorithms
* Returns true if one set is a subset of another.
* ``<hpx/algorithm.hpp>``
* :cppreference-algorithm:`includes`
* * :cpp:func:`hpx::parallel::v1::set_difference`
* * :cpp:func:`hpx::set_difference`
* Computes the difference between two sets.
* ``<hpx/algorithm.hpp>``
* :cppreference-algorithm:`set_difference`
* * :cpp:func:`hpx::set_intersection`
* Computes the intersection of two sets.
* ``<hpx/algorithm.hpp>``
* :cppreference-algorithm:`set_intersection`
* * :cpp:func:`hpx::parallel::v1::set_symmetric_difference`
* * :cpp:func:`hpx::set_symmetric_difference`
* Computes the symmetric difference between two sets.
* ``<hpx/algorithm.hpp>``
* :cppreference-algorithm:`set_symmetric_difference`
* * :cpp:func:`hpx::parallel::v1::set_union`
* * :cpp:func:`hpx::set_union`
* Computes the union of two sets.
* ``<hpx/algorithm.hpp>``
* :cppreference-algorithm:`set_union`
Expand Down
2 changes: 0 additions & 2 deletions libs/full/include/include/hpx/algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ namespace hpx {
using hpx::parallel::rotate_copy;
using hpx::parallel::search;
using hpx::parallel::search_n;
using hpx::parallel::set_symmetric_difference;
using hpx::parallel::set_union;
using hpx::parallel::sort;
using hpx::parallel::stable_partition;
using hpx::parallel::stable_sort;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
#include <hpx/parallel/container_algorithms/includes.hpp>
#include <hpx/parallel/container_algorithms/set_difference.hpp>
#include <hpx/parallel/container_algorithms/set_intersection.hpp>
#include <hpx/parallel/container_algorithms/set_symmetric_difference.hpp>
#include <hpx/parallel/container_algorithms/set_union.hpp>
3 changes: 3 additions & 0 deletions libs/parallelism/algorithms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ set(algorithms_headers
hpx/parallel/algorithms/detail/set_operation.hpp
hpx/parallel/algorithms/detail/spin_sort.hpp
hpx/parallel/algorithms/detail/transfer.hpp
hpx/parallel/algorithms/detail/upper_lower_bound.hpp
hpx/parallel/algorithms/equal.hpp
hpx/parallel/algorithms/exclusive_scan.hpp
hpx/parallel/algorithms/fill.hpp
Expand Down Expand Up @@ -107,6 +108,8 @@ set(algorithms_headers
hpx/parallel/container_algorithms/search.hpp
hpx/parallel/container_algorithms/set_difference.hpp
hpx/parallel/container_algorithms/set_intersection.hpp
hpx/parallel/container_algorithms/set_symmetric_difference.hpp
hpx/parallel/container_algorithms/set_union.hpp
hpx/parallel/container_algorithms/sort.hpp
hpx/parallel/container_algorithms/stable_sort.hpp
hpx/parallel/container_algorithms/transform.hpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <hpx/execution/executors/execution_information.hpp>
#include <hpx/executors/execution_policy.hpp>
#include <hpx/parallel/algorithms/detail/distance.hpp>
#include <hpx/parallel/algorithms/detail/upper_lower_bound.hpp>
#include <hpx/parallel/util/detail/algorithm_result.hpp>
#include <hpx/parallel/util/foreach_partitioner.hpp>
#include <hpx/parallel/util/partitioner.hpp>
Expand All @@ -22,6 +23,7 @@
#include <memory>
#endif

#include <algorithm>
#include <cstddef>
#include <type_traits>
#include <utility>
Expand Down Expand Up @@ -75,16 +77,22 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail {
std::size_t start = std::size_t(-1);
std::size_t len = std::size_t(-1);
std::size_t start_index = std::size_t(-1);
std::size_t first1 = std::size_t(-1);
std::size_t first2 = std::size_t(-1);
};

///////////////////////////////////////////////////////////////////////////
template <typename ExPolicy, typename Iter1, typename Sent1, typename Iter2,
typename Sent2, typename Iter3, typename F, typename Combiner,
typename SetOp>
typename util::detail::algorithm_result<ExPolicy, Iter3>::type
set_operation(ExPolicy policy, Iter1 first1, Sent1 last1, Iter2 first2,
Sent2 last2, Iter3 dest, F&& f, Combiner&& combiner, SetOp&& setop)
typename Sent2, typename Iter3, typename F, typename Proj1,
typename Proj2, typename Combiner, typename SetOp>
typename util::detail::algorithm_result<ExPolicy,
util::in_in_out_result<Iter1, Iter2, Iter3>>::type
set_operation(ExPolicy&& policy, Iter1 first1, Sent1 last1, Iter2 first2,
Sent2 last2, Iter3 dest, F&& f, Proj1&& proj1, Proj2&& proj2,
Combiner&& combiner, SetOp&& setop)
{
using result_type = util::in_in_out_result<Iter1, Iter2, Iter3>;

using difference_type1 =
typename std::iterator_traits<Iter1>::difference_type;
using difference_type2 =
Expand All @@ -94,7 +102,7 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail {
difference_type1 len1 = detail::distance(first1, last1);
difference_type2 len2 = detail::distance(first2, last2);

typedef typename set_operations_buffer<Iter3>::type buffer_type;
using buffer_type = typename set_operations_buffer<Iter3>::type;

std::size_t cores = execution::processing_units_count(
policy.parameters(), policy.executor());
Expand All @@ -121,71 +129,111 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail {
std::size_t end1 = (std::min)(start1 + step, std::size_t(len1));

if (start1 >= end1)
{
return;
}

bool first_partition = (start1 == 0);
bool last_partition = (end1 == std::size_t(len1));

auto start_value = hpx::util::invoke(proj1, first1[start1]);
auto end_value = hpx::util::invoke(proj1, first1[end1]);

// all but the last chunk require special handling
if (!last_partition)
{
// this chunk will be handled by the next one if all
// elements of this partition are equal
if (!f(first1[start1], first1[end1]))
if (!hpx::util::invoke(f, start_value, end_value))
{
return;
}

// move backwards to find earliest element which is equal to
// the last element of the current chunk
while (end1 != 0 && !f(first1[end1 - 1], first1[end1]))
--end1;
if (end1 != 0)
{
auto end_value1 =
hpx::util::invoke(proj1, first1[end1 - 1]);

while (!hpx::util::invoke(f, end_value1, end_value) &&
--end1 != 0)
{
end_value = std::move(end_value1);
end_value1 = hpx::util::invoke(proj1, first1[end1 - 1]);
}
}
}

// move backwards to find earliest element which is equal to
// the first element of the current chunk
while (start1 != 0 && !f(first1[start1 - 1], first1[start1]))
--start1;
if (start1 != 0)
{
auto start_value1 =
hpx::util::invoke(proj1, first1[start1 - 1]);

while (!hpx::util::invoke(f, start_value1, start_value) &&
--start1 != 0)
{
start_value = std::move(start_value1);
start_value1 = hpx::util::invoke(proj1, first1[start1 - 1]);
}
}

// find start and end in sequence 2
std::size_t start2 = 0;
if (!first_partition)
{
start2 =
std::lower_bound(first2, first2 + len2, first1[start1], f) -
start2 = detail::lower_bound(
first2, first2 + len2, start_value, f, proj2) -
first2;
}

std::size_t end2 = len2;
if (!last_partition)
{
end2 = std::lower_bound(
first2 + start2, first2 + len2, first1[end1], f) -
end2 = detail::lower_bound(first2 + start2, first2 + len2,
end_value, f, proj2) -
first2;
}

// perform requested set-operation into the proper place of the
// intermediate buffer
curr_chunk->start = combiner(start1, start2);
auto buffer_dest = buffer.get() + curr_chunk->start;
curr_chunk->len =
setop(first1 + start1, first1 + end1, first2 + start2,
first2 + end2, buffer_dest, f) -
buffer_dest;
auto op_result = setop(first1 + start1, first1 + end1,
first2 + start2, first2 + end2, buffer_dest, f);
curr_chunk->first1 = op_result.in1 - first1;
curr_chunk->first2 = op_result.in2 - first2;
curr_chunk->len = op_result.out - buffer_dest;
};

// second step, is executed after all partitions are done running

// different versions of clang-format produce different formatting
// clang-format off
auto f2 = [buffer, chunks, cores, dest](
std::vector<future<void>>&&) -> Iter3 {
auto f2 = [buffer, chunks, cores, first1, first2, dest](
std::vector<future<void>>&&) -> result_type {
// clang-format on
// accumulate real length

// accumulate real length and rightmost positions in input sequences
std::size_t first1_pos = 0;
std::size_t first2_pos = 0;

set_chunk_data* chunk = chunks.get();
chunk->start_index = 0;
for (size_t i = 1; i != cores; ++i)
{
set_chunk_data* curr_chunk = chunk++;
chunk->start_index = curr_chunk->start_index + curr_chunk->len;
if (curr_chunk->first1 != std::size_t(-1))
{
first1_pos = (std::max)(first1_pos, curr_chunk->first1);
}
if (curr_chunk->first2 != std::size_t(-1))
{
first2_pos = (std::max)(first2_pos, curr_chunk->first2);
}
}

// finally, copy data to destination
Expand All @@ -194,11 +242,12 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail {
hpx::execution::par, chunks.get(), cores,
[buffer, dest](
set_chunk_data* chunk, std::size_t, std::size_t) {
if (chunk->start == (size_t)(-1) ||
chunk->start_index == (size_t)(-1) ||
chunk->len == (size_t)(-1))
if (chunk->start == std::size_t(-1) ||
chunk->start_index == std::size_t(-1) ||
chunk->len == std::size_t(-1))
{
return;

}
std::copy(buffer.get() + chunk->start,
buffer.get() + chunk->start + chunk->len,
dest + chunk->start_index);
Expand All @@ -207,11 +256,13 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail {
return last;
});

return dest;
return {std::next(first1, first1_pos),
std::next(first2, first2_pos),
std::next(dest, chunk->start_index + chunk->len)};
};

// fill the buffer piecewise
return parallel::util::partitioner<ExPolicy, Iter3, void>::call(
return parallel::util::partitioner<ExPolicy, result_type, void>::call(
policy, chunks.get(), cores, std::move(f1), std::move(f2));
}

Expand Down
Loading

0 comments on commit f26037c

Please sign in to comment.