Skip to content

Commit

Permalink
Contains and contains_subrange parallel algorithm implementaion
Browse files Browse the repository at this point in the history
  • Loading branch information
Zak-K-Abdi committed Jun 15, 2024
1 parent ba8f05f commit 54b3d7a
Show file tree
Hide file tree
Showing 8 changed files with 693 additions and 0 deletions.
1 change: 1 addition & 0 deletions .circleci/tests.unit1.algorithms
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ tests.unit.modules.algorithms.algorithms.adjacentfind
tests.unit.modules.algorithms.algorithms.adjacentfind_binary
tests.unit.modules.algorithms.algorithms.all_of
tests.unit.modules.algorithms.algorithms.any_of
tests.unit.modules.algorithms.algorithms.contains
tests.unit.modules.algorithms.algorithms.copy
tests.unit.modules.algorithms.algorithms.copyif_random
tests.unit.modules.algorithms.algorithms.copyif_forward
Expand Down
2 changes: 2 additions & 0 deletions libs/core/algorithms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(algorithms_headers
hpx/parallel/algorithms/adjacent_difference.hpp
hpx/parallel/algorithms/adjacent_find.hpp
hpx/parallel/algorithms/all_any_none.hpp
hpx/parallel/algorithms/contains.hpp
hpx/parallel/algorithms/copy.hpp
hpx/parallel/algorithms/count.hpp
hpx/parallel/algorithms/destroy.hpp
Expand All @@ -23,6 +24,7 @@ set(algorithms_headers
hpx/parallel/algorithms/detail/accumulate.hpp
hpx/parallel/algorithms/detail/advance_and_get_distance.hpp
hpx/parallel/algorithms/detail/advance_to_sentinel.hpp
hpx/parallel/algorithms/detail/contains.hpp
hpx/parallel/algorithms/detail/dispatch.hpp
hpx/parallel/algorithms/detail/distance.hpp
hpx/parallel/algorithms/detail/equal.hpp
Expand Down
1 change: 1 addition & 0 deletions libs/core/algorithms/include/hpx/parallel/algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// Parallelism TS V1
#include <hpx/parallel/algorithms/adjacent_find.hpp>
#include <hpx/parallel/algorithms/all_any_none.hpp>
#include <hpx/parallel/algorithms/contains.hpp>
#include <hpx/parallel/algorithms/copy.hpp>
#include <hpx/parallel/algorithms/count.hpp>
#include <hpx/parallel/algorithms/equal.hpp>
Expand Down
132 changes: 132 additions & 0 deletions libs/core/algorithms/include/hpx/parallel/algorithms/contains.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright (c) 2024 Zakaria Abdi
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#pragma once

#include <hpx/config.hpp>
#include <hpx/coroutines/thread_enums.hpp>
#include <hpx/execution/algorithms/detail/predicates.hpp>
#include <hpx/executors/execution_policy.hpp>
#include <hpx/iterator_support/traits/is_iterator.hpp>
#include <hpx/parallel/algorithms/detail/contains.hpp>
#include <hpx/parallel/algorithms/detail/dispatch.hpp>
#include <hpx/parallel/algorithms/detail/distance.hpp>
#include <hpx/parallel/util/adapt_placement_mode.hpp>
#include <hpx/parallel/util/cancellation_token.hpp>
#include <hpx/parallel/util/detail/algorithm_result.hpp>
#include <hpx/parallel/util/loop.hpp>
#include <hpx/parallel/util/partitioner.hpp>
#include <hpx/parallel/util/zip_iterator.hpp>
#include <hpx/type_support/identity.hpp>

#include <algorithm>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include <utility>

namespace hpx::parallel { namespace detail {
struct contains : public algorithm<contains, bool>
{
constexpr contains() noexcept
: algorithm("contains")
{
}

template <typename ExPolicy, typename Iterator, typename Sentinel,
typename T, typename Proj>
static constexpr bool sequential(
ExPolicy, Iterator first, Sentinel last, const T& val, Proj&& proj)
{
return sequential_contains<std::decay<ExPolicy>>(
first, last, val, HPX_FORWARD(Proj, proj));
}

template <typename ExPolicy, typename Iterator, typename Sentinel,
typename T, typename Proj>
static util::detail::algorithm_result_t<ExPolicy, bool> parallel(
ExPolicy&& orgpolicy, Iterator first, Sentinel last, const T& val,
Proj&& proj)
{
using difference_type =
typename std::iterator_traits<Iterator>::difference_type;
difference_type count = detail::distance(first, last);
if (count <= 0)
return util::detail::algorithm_result<ExPolicy, bool>::get(
false);

decltype(auto) policy = parallel::util::adapt_placement_mode(
HPX_FORWARD(ExPolicy, orgpolicy),
hpx::threads::thread_placement_hint::breadth_first);

using policy_type = std::decay_t<decltype(policy)>;
util::cancellation_token<> tok;
auto f1 = [val, tok, proj](Iterator first, std::size_t count) {
sequential_contains<policy_type>(first, val, count, tok, proj);
return tok.was_cancelled();
};

auto f2 = [](auto&& results) {
return std::any_of(hpx::util::begin(results),
hpx::util::end(results),
[](hpx::future<bool>& val) { return val.get(); });
};

return util::partitioner<policy_type, bool>::call(
HPX_FORWARD(decltype(policy), policy), first, count,
HPX_MOVE(f1), HPX_MOVE(f2));
}
};
}} // namespace hpx::parallel::detail
namespace hpx {

inline constexpr struct contains_t final
: hpx::functional::detail::tag_fallback<contains_t>
{
private:
template <typename Iterator, typename Sentinel, typename T,
typename Proj = hpx::identity,
HPX_CONCEPT_REQUIRES_(hpx::traits::is_iterator_v<Iterator>&& hpx::
traits::is_iterator_v<Iterator>&& hpx::is_invocable_v<Proj,
typename std::iterator_traits<Iterator>::value_type>)>

friend bool tag_fallback_invoke(hpx::contains_t, Iterator first,
Sentinel last, const T& val, Proj&& proj = Proj())
{
static_assert(hpx::traits::is_input_iterator_v<Iterator>,
"Required at least input iterator.");

static_assert(hpx::traits::is_input_iterator_v<Sentinel>,
"Required at least input iterator.");

return hpx::parallel::detail::contains().call(
hpx::execution::seq, first, last, val, proj);
}

template <typename ExPolicy, typename Iterator, typename Sentinel,
typename T, typename Proj = hpx::identity,
HPX_CONCEPT_REQUIRES_(hpx::is_execution_policy_v<
ExPolicy>&& hpx::traits::is_iterator_v<Iterator>&& hpx::traits::
is_iterator_v<Iterator>&& hpx::is_invocable_v<Proj,
typename std::iterator_traits<Iterator>::value_type>)>

friend typename parallel::util::detail::algorithm_result<ExPolicy,
bool>::type
tag_fallback_invoke(hpx::contains_t, ExPolicy&& policy, Iterator first,
Sentinel last, T const& val, Proj&& proj = Proj())
{
static_assert(hpx::traits::is_iterator_v<Iterator>,
"Required at least iterator.");

static_assert(hpx::traits::is_iterator_v<Sentinel>,
"Required at least iterator.");

return hpx::parallel::detail::contains().call(
HPX_FORWARD(ExPolicy, policy), first, last, val,
HPX_FORWARD(Proj, proj));
}

} contains{};
} // namespace hpx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) 2024 Zakaria Abdi
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#pragma once

#include <hpx/config.hpp>
#include <hpx/functional/detail/tag_fallback_invoke.hpp>
#include <hpx/functional/invoke.hpp>
#include <hpx/parallel/util/loop.hpp>

#include <algorithm>
#include <cstddef>
#include <type_traits>
#include <utility>

namespace hpx::parallel::detail {

template <typename ExPolicy>
struct sequential_contains_t final
: hpx::functional::detail::tag_fallback<sequential_contains_t<ExPolicy>>
{
private:
template <typename Iterator, typename Sentinel, typename T,
typename Proj>
friend constexpr bool tag_fallback_invoke(sequential_contains_t,
Iterator first, Sentinel last, const T& val, Proj&& proj)
{
using difference_type =
typename std::iterator_traits<Iterator>::difference_type;
difference_type distance = detail::distance(first, last);
if (distance <= 0)
return false;

const auto itr =
util::loop_pred<std::decay_t<hpx::execution::sequenced_policy>>(
first, last, [&val, &proj](const auto& cur) {
return HPX_INVOKE(proj, *cur) == val;
});

return itr != last;
}

template <typename Iterator, typename T, typename Token, typename Proj>
friend constexpr void tag_fallback_invoke(sequential_contains_t,
Iterator first, T const& val, std::size_t count, Token& tok,
Proj&& proj)
{
util::loop_n<ExPolicy>(
first, count, tok, [&val, &tok, &proj](const auto& cur) {
if (HPX_INVOKE(proj, *cur) == val)
{
tok.cancel();
return;
}
});
}
};
template <typename ExPolicy>
inline constexpr sequential_contains_t<ExPolicy> sequential_contains =
sequential_contains_t<ExPolicy>{};
} //namespace hpx::parallel::detail
1 change: 1 addition & 0 deletions libs/core/algorithms/tests/unit/algorithms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ set(tests
adjacentfind_binary
all_of
any_of
contains
copy
copyif_random
copyif_forward
Expand Down
110 changes: 110 additions & 0 deletions libs/core/algorithms/tests/unit/algorithms/contains.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (c) 2024 Zakaria Abdi
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <iostream>
#include <string>
#include <vector>

#include <hpx/init.hpp>
#include "contains_tests.hpp"

////////////////////////////////////////////////////////////////////////////
template <typename IteratorTag>
void test_contains()
{
using namespace hpx::execution;

test_contains(IteratorTag());

test_contains(seq, IteratorTag());
test_contains(par, IteratorTag());
test_contains(par_unseq, IteratorTag());

test_contains_async(seq(task), IteratorTag());
test_contains_async(par(task), IteratorTag());
test_contains_async(par_unseq(task), IteratorTag());
}

void contains_test()
{
test_contains<std::random_access_iterator_tag>();
test_contains<std::forward_iterator_tag>();
}

////////////////////////////////////////////////////////////////////////////
template <typename IteratorTag>
void test_contains_exception()
{
using namespace hpx::execution;

test_contains_exception(IteratorTag());

test_contains_exception(seq, IteratorTag());
test_contains_exception(par, IteratorTag());

test_contains_exception_async(seq(task), IteratorTag());
test_contains_exception_async(par(task), IteratorTag());
}

void contains_exception_test()
{
test_contains_exception<std::random_access_iterator_tag>();
test_contains_exception<std::forward_iterator_tag>();
}

////////////////////////////////////////////////////////////////////////////
template <typename IteratorTag>
void test_contains_bad_alloc()
{
using namespace hpx::execution;

test_contains_bad_alloc(seq, IteratorTag());
test_contains_bad_alloc(par, IteratorTag());

test_contains_bad_alloc_async(seq(task), IteratorTag());
test_contains_bad_alloc_async(par(task), IteratorTag());
}

void contains_bad_alloc_test()
{
test_contains_bad_alloc<std::random_access_iterator_tag>();
test_contains_bad_alloc<std::forward_iterator_tag>();
}

int hpx_main(hpx::program_options::variables_map& vm)
{
if (vm.count("seed"))
seed = vm["seed"].as<unsigned int>();

std::cout << "Using seed as: " << seed << std::endl;
gen.seed(seed);

contains_test();
contains_exception_test();
contains_bad_alloc_test();

return hpx::local::finalize();
}

int main(int argc, char* argv[])
{
using namespace hpx::program_options;
options_description desc_commandline(
"Usage" HPX_APPLICATION_STRING " [options]");

desc_commandline.add_options()("seed,s", value<unsigned int>(),
" the random number generator to use for this run");

std::vector<std::string> cfg = {"hpx.os_threads=all"};

hpx::local::init_params init_args;
init_args.desc_cmdline = desc_commandline;
init_args.cfg = cfg;

HPX_TEST_EQ_MSG(hpx::local::init(hpx_main, argc, argv, init_args), 0,
"HPX main exited with non-zero status");

return hpx::util::report_errors();
}
Loading

0 comments on commit 54b3d7a

Please sign in to comment.