Skip to content

Commit

Permalink
Separate seq_fwd from variant_policy, make both independent headers
Browse files Browse the repository at this point in the history
  • Loading branch information
alugowski committed Dec 18, 2023
1 parent ccfe7fd commit 48a9370
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 57 deletions.
119 changes: 119 additions & 0 deletions include/poolstl/seq_fwd.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright (C) 2023 Adam Lugowski. All rights reserved.
// Use of this source code is governed by:
// the BSD 2-clause license, the MIT license, or at your choosing the BSL-1.0 license found in the LICENSE.*.txt files.
// SPDX-License-Identifier: BSD-2-Clause OR MIT OR BSL-1.0

#ifndef POOLSTL_VARIANT_POLICY_HPP
#define POOLSTL_VARIANT_POLICY_HPP

#include <algorithm>
#include <numeric>

/* INDEPENDENT FILE. DOES NOT REQUIRE REST OF POOLSTL.
*
* An execution policy that simply forwards to the basic non-policy (sequential) standard library functions.
*
* Allows writing code in the parallel style even if tooling does not support doing so.
*
* The sequential policy will be poolstl::seq_fwd.
* You may override by defining POOLSTL_SEQ_FWD_POLICY to be the policy you'd prefer instead.
*/


#ifndef POOLSTL_SEQ_FWD_POLICY
namespace poolstl {
namespace execution {
struct seq_fwd_policy {
};

constexpr seq_fwd_policy seq_fwd;
}
using execution::seq_fwd;
}
#define POOLSTL_SEQ_FWD_POLICY poolstl::execution::seq_fwd_policy
#endif

#if (__cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)) && \
(!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 9)
#define POOLSTL_SEQ_FWD_HAVE_CXX17_LIB 1
#else
#define POOLSTL_SEQ_FWD_HAVE_CXX17_LIB 0
#endif

namespace poolstl {
namespace internal {
/**
* To enable/disable seq_fwd overload resolution
*/
template <class ExecPolicy, class Tp>
using enable_if_seq_fwd =
typename std::enable_if<
std::is_same<POOLSTL_SEQ_FWD_POLICY,
typename std::remove_cv<typename std::remove_reference<ExecPolicy>::type>::type>::value,
Tp>::type;
}
}

/*
* Forward a specified policy to the native sequential (no policy) method.
*/

#define POOLSTL_DEFINE_SEQ_FWD(NS, FNAME) \
template<class EP, typename...ARGS> \
auto FNAME(EP&&, ARGS&&...args) -> \
poolstl::internal::enable_if_seq_fwd<EP, decltype(NS::FNAME(std::forward<ARGS>(args)...))> { \
return NS::FNAME(std::forward<ARGS>(args)...); \
}

#define POOLSTL_DEFINE_SEQ_FWD_VOID(NS, FNAME) \
template<class EP, typename...ARGS> \
poolstl::internal::enable_if_seq_fwd<EP, void> FNAME(EP&&, ARGS&&... args) { \
NS::FNAME(std::forward<ARGS>(args)...); \
}


namespace std {
// <algorithm>

POOLSTL_DEFINE_SEQ_FWD(std, all_of)
POOLSTL_DEFINE_SEQ_FWD(std, any_of)
POOLSTL_DEFINE_SEQ_FWD(std, none_of)

POOLSTL_DEFINE_SEQ_FWD(std, count)
POOLSTL_DEFINE_SEQ_FWD(std, count_if)

POOLSTL_DEFINE_SEQ_FWD(std, copy)
POOLSTL_DEFINE_SEQ_FWD(std, copy_n)

POOLSTL_DEFINE_SEQ_FWD_VOID(std, fill)
POOLSTL_DEFINE_SEQ_FWD(std, fill_n)

POOLSTL_DEFINE_SEQ_FWD(std, find)
POOLSTL_DEFINE_SEQ_FWD(std, find_if)
POOLSTL_DEFINE_SEQ_FWD(std, find_if_not)

POOLSTL_DEFINE_SEQ_FWD_VOID(std, for_each)
#if POOLSTL_SEQ_FWD_HAVE_CXX17_LIB
POOLSTL_DEFINE_SEQ_FWD(std, for_each_n)
#endif

POOLSTL_DEFINE_SEQ_FWD(std, transform)

// <numeric>

#if POOLSTL_SEQ_FWD_HAVE_CXX17_LIB
POOLSTL_DEFINE_SEQ_FWD(std, exclusive_scan)
POOLSTL_DEFINE_SEQ_FWD(std, reduce)
POOLSTL_DEFINE_SEQ_FWD(std, transform_reduce)
#endif
}

#ifdef POOLSTL_VERSION_MAJOR
namespace poolstl {
// <poolstl/algorithm>

POOLSTL_DEFINE_SEQ_FWD_VOID(poolstl, for_each_chunk)
}
#endif

#endif
98 changes: 41 additions & 57 deletions include/poolstl/variant_policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@
#ifndef POOLSTL_VARIANT_POLICY_HPP
#define POOLSTL_VARIANT_POLICY_HPP

#include "execution"

#include <algorithm>
#include <numeric>
#include <variant>

#if (__cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)) && \
(!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 9)
#define POOLSTL_VARIANT_HAVE_CXX17_LIB 1
#else
#define POOLSTL_VARIANT_HAVE_CXX17_LIB 0
#endif

namespace poolstl {
namespace execution {
/**
Expand All @@ -24,9 +31,12 @@ namespace poolstl {
};

namespace internal {
// Example variant definition
/*
using poolstl_policy_variant = std::variant<
poolstl::execution::parallel_policy,
poolstl::execution::sequenced_policy>;
*/
}
}

Expand All @@ -52,25 +62,6 @@ namespace poolstl {
}
}

/*
* Forward poolstl::seq to the native sequential (no policy) method.
*/

#define POOLSTL_DEFINE_SEQ_FWD(NS, FNAME) \
template<class EP, typename...ARGS> \
auto FNAME(EP&&, ARGS&&...args) -> \
poolstl::internal::enable_if_seq<EP, decltype(NS::FNAME(std::forward<ARGS>(args)...))> { \
return NS::FNAME(std::forward<ARGS>(args)...); \
}

#define POOLSTL_DEFINE_SEQ_FWD_VOID(NS, FNAME) \
template<class EP, typename...ARGS> \
poolstl::internal::enable_if_seq<EP, void> FNAME(EP&&, ARGS&&... args) { \
NS::FNAME(std::forward<ARGS>(args)...); \
}

#if POOLSTL_HAVE_CXX17

/*
* Dynamically choose policy from a std::variant.
* Useful to choose between parallel and sequential policies at runtime via par_if.
Expand All @@ -89,55 +80,48 @@ namespace poolstl {
return std::visit([&](auto&& pol) { return NS::FNAME(pol, std::forward<ARGS>(args)...); }, policy.var); \
}

#else
#define POOLSTL_DEFINE_PAR_IF_FWD_VOID(NS, FNAME)
#define POOLSTL_DEFINE_PAR_IF_FWD(NS, FNAME)
#endif
/*
* Define both the sequential forward and dynamic chooser.
*/
#define POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(NS, FNAME) \
POOLSTL_DEFINE_SEQ_FWD(NS, FNAME) \
POOLSTL_DEFINE_PAR_IF_FWD(NS, FNAME)

#define POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF_VOID(NS, FNAME) \
POOLSTL_DEFINE_SEQ_FWD_VOID(NS, FNAME) \
POOLSTL_DEFINE_PAR_IF_FWD_VOID(NS, FNAME)

namespace std {
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, all_of)
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, any_of)
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, none_of)
// <algorithm>

POOLSTL_DEFINE_PAR_IF_FWD(std, all_of)
POOLSTL_DEFINE_PAR_IF_FWD(std, any_of)
POOLSTL_DEFINE_PAR_IF_FWD(std, none_of)

POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, count)
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, count_if)
POOLSTL_DEFINE_PAR_IF_FWD(std, count)
POOLSTL_DEFINE_PAR_IF_FWD(std, count_if)

POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, copy)
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, copy_n)
POOLSTL_DEFINE_PAR_IF_FWD(std, copy)
POOLSTL_DEFINE_PAR_IF_FWD(std, copy_n)

POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF_VOID(std, fill)
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, fill_n)
POOLSTL_DEFINE_PAR_IF_FWD_VOID(std, fill)
POOLSTL_DEFINE_PAR_IF_FWD(std, fill_n)

POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, find)
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, find_if)
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, find_if_not)
POOLSTL_DEFINE_PAR_IF_FWD(std, find)
POOLSTL_DEFINE_PAR_IF_FWD(std, find_if)
POOLSTL_DEFINE_PAR_IF_FWD(std, find_if_not)

POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF_VOID(std, for_each)
#if POOLSTL_HAVE_CXX17_LIB
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, for_each_n)
POOLSTL_DEFINE_PAR_IF_FWD_VOID(std, for_each)
#if POOLSTL_VARIANT_HAVE_CXX17_LIB
POOLSTL_DEFINE_PAR_IF_FWD(std, for_each_n)
#endif

POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, transform)
POOLSTL_DEFINE_PAR_IF_FWD(std, transform)

// <numeric>

#if POOLSTL_HAVE_CXX17_LIB
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, exclusive_scan)
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, reduce)
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, transform_reduce)
#if POOLSTL_VARIANT_HAVE_CXX17_LIB
POOLSTL_DEFINE_PAR_IF_FWD(std, exclusive_scan)
POOLSTL_DEFINE_PAR_IF_FWD(std, reduce)
POOLSTL_DEFINE_PAR_IF_FWD(std, transform_reduce)
#endif
}

#ifdef POOLSTL_VERSION_MAJOR
namespace poolstl {
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF_VOID(poolstl, for_each_chunk)
// <poolstl/algorithm>

POOLSTL_DEFINE_PAR_IF_FWD_VOID(poolstl, for_each_chunk)
}
#endif

#endif
8 changes: 8 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ add_executable(cpp11_test cpp11_test.cpp)
target_link_libraries(cpp11_test PUBLIC poolSTL::poolSTL)
target_compile_features(cpp11_test PUBLIC cxx_std_11)

# Test seq_fwd policy
add_executable(seq_fwd_test seq_fwd_test.cpp)
target_link_libraries(seq_fwd_test PRIVATE Catch2::Catch2WithMain poolSTL::poolSTL)
target_compile_definitions(seq_fwd_test PRIVATE CATCH_CONFIG_FAST_COMPILE)
target_compile_features(seq_fwd_test PUBLIC cxx_std_17)
catch_discover_tests(seq_fwd_test)


# Test std::execution supplementation.
# The test code uses only std::execution::par, seq, and par_unseq.
# On compilers with support poolSTL does nothing, else poolSTL aliases poolstl::par to the std::execution policies.
Expand Down
62 changes: 62 additions & 0 deletions tests/seq_fwd_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (C) 2023 Adam Lugowski. All rights reserved.
// Use of this source code is governed by:
// the BSD 2-clause license, the MIT license, or at your choosing the BSL-1.0 license found in the LICENSE.*.txt files.
// SPDX-License-Identifier: BSD-2-Clause OR MIT OR BSL-1.0


#include <algorithm>
#include <atomic>

#include <catch2/catch_test_macros.hpp>

#if __has_include(<poolstl/seq_fwd.hpp>)
// seq_fwd not included in the poolSTL amalgam, so skip these tests on CI steps that test the amalgam.

#include <poolstl/seq_fwd.hpp>

#include "utils.hpp"


TEST_CASE("fwd_count", "[alg][algorithm][seq_fwd]") {
for (auto vec_size : test_arr_sizes) {
auto haystack = iota_vector(vec_size);

{
int needle = 5;
auto seq = std::count( haystack.cbegin(), haystack.cend(), needle);
auto par = std::count(poolstl::seq_fwd, haystack.cbegin(), haystack.cend(), needle);
REQUIRE(seq == par);
}
{
auto pred = [&](auto x) { return x % 2 == 0; };
auto seq = std::count_if( haystack.cbegin(), haystack.cend(), pred);
auto par = std::count_if(poolstl::seq_fwd, haystack.cbegin(), haystack.cend(), pred);
REQUIRE(seq == par);
}
}
}

TEST_CASE("fwd_for_each", "[alg][algorithm][seq_fwd]") {
std::atomic<int> sum{0};
for (auto num_iters : test_arr_sizes) {
auto v = iota_vector(num_iters);

for (auto which_impl : {0, 1}) {
sum = 0;
auto f = [&](auto) { ++sum; };
switch (which_impl) {
case 0:
std::for_each(v.cbegin(), v.cend(), f);
break;
case 1:
std::for_each(poolstl::seq_fwd, v.cbegin(), v.cend(), f);
break;
default: break;
}
REQUIRE(sum == num_iters);
}
}
}

std::mt19937 rng{1};
#endif

0 comments on commit 48a9370

Please sign in to comment.