Skip to content

Commit 48a9370

Browse files
committed
Separate seq_fwd from variant_policy, make both independent headers
1 parent ccfe7fd commit 48a9370

File tree

4 files changed

+230
-57
lines changed

4 files changed

+230
-57
lines changed

include/poolstl/seq_fwd.hpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright (C) 2023 Adam Lugowski. All rights reserved.
2+
// Use of this source code is governed by:
3+
// the BSD 2-clause license, the MIT license, or at your choosing the BSL-1.0 license found in the LICENSE.*.txt files.
4+
// SPDX-License-Identifier: BSD-2-Clause OR MIT OR BSL-1.0
5+
6+
#ifndef POOLSTL_VARIANT_POLICY_HPP
7+
#define POOLSTL_VARIANT_POLICY_HPP
8+
9+
#include <algorithm>
10+
#include <numeric>
11+
12+
/* INDEPENDENT FILE. DOES NOT REQUIRE REST OF POOLSTL.
13+
*
14+
* An execution policy that simply forwards to the basic non-policy (sequential) standard library functions.
15+
*
16+
* Allows writing code in the parallel style even if tooling does not support doing so.
17+
*
18+
* The sequential policy will be poolstl::seq_fwd.
19+
* You may override by defining POOLSTL_SEQ_FWD_POLICY to be the policy you'd prefer instead.
20+
*/
21+
22+
23+
#ifndef POOLSTL_SEQ_FWD_POLICY
24+
namespace poolstl {
25+
namespace execution {
26+
struct seq_fwd_policy {
27+
};
28+
29+
constexpr seq_fwd_policy seq_fwd;
30+
}
31+
using execution::seq_fwd;
32+
}
33+
#define POOLSTL_SEQ_FWD_POLICY poolstl::execution::seq_fwd_policy
34+
#endif
35+
36+
#if (__cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)) && \
37+
(!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 9)
38+
#define POOLSTL_SEQ_FWD_HAVE_CXX17_LIB 1
39+
#else
40+
#define POOLSTL_SEQ_FWD_HAVE_CXX17_LIB 0
41+
#endif
42+
43+
namespace poolstl {
44+
namespace internal {
45+
/**
46+
* To enable/disable seq_fwd overload resolution
47+
*/
48+
template <class ExecPolicy, class Tp>
49+
using enable_if_seq_fwd =
50+
typename std::enable_if<
51+
std::is_same<POOLSTL_SEQ_FWD_POLICY,
52+
typename std::remove_cv<typename std::remove_reference<ExecPolicy>::type>::type>::value,
53+
Tp>::type;
54+
}
55+
}
56+
57+
/*
58+
* Forward a specified policy to the native sequential (no policy) method.
59+
*/
60+
61+
#define POOLSTL_DEFINE_SEQ_FWD(NS, FNAME) \
62+
template<class EP, typename...ARGS> \
63+
auto FNAME(EP&&, ARGS&&...args) -> \
64+
poolstl::internal::enable_if_seq_fwd<EP, decltype(NS::FNAME(std::forward<ARGS>(args)...))> { \
65+
return NS::FNAME(std::forward<ARGS>(args)...); \
66+
}
67+
68+
#define POOLSTL_DEFINE_SEQ_FWD_VOID(NS, FNAME) \
69+
template<class EP, typename...ARGS> \
70+
poolstl::internal::enable_if_seq_fwd<EP, void> FNAME(EP&&, ARGS&&... args) { \
71+
NS::FNAME(std::forward<ARGS>(args)...); \
72+
}
73+
74+
75+
namespace std {
76+
// <algorithm>
77+
78+
POOLSTL_DEFINE_SEQ_FWD(std, all_of)
79+
POOLSTL_DEFINE_SEQ_FWD(std, any_of)
80+
POOLSTL_DEFINE_SEQ_FWD(std, none_of)
81+
82+
POOLSTL_DEFINE_SEQ_FWD(std, count)
83+
POOLSTL_DEFINE_SEQ_FWD(std, count_if)
84+
85+
POOLSTL_DEFINE_SEQ_FWD(std, copy)
86+
POOLSTL_DEFINE_SEQ_FWD(std, copy_n)
87+
88+
POOLSTL_DEFINE_SEQ_FWD_VOID(std, fill)
89+
POOLSTL_DEFINE_SEQ_FWD(std, fill_n)
90+
91+
POOLSTL_DEFINE_SEQ_FWD(std, find)
92+
POOLSTL_DEFINE_SEQ_FWD(std, find_if)
93+
POOLSTL_DEFINE_SEQ_FWD(std, find_if_not)
94+
95+
POOLSTL_DEFINE_SEQ_FWD_VOID(std, for_each)
96+
#if POOLSTL_SEQ_FWD_HAVE_CXX17_LIB
97+
POOLSTL_DEFINE_SEQ_FWD(std, for_each_n)
98+
#endif
99+
100+
POOLSTL_DEFINE_SEQ_FWD(std, transform)
101+
102+
// <numeric>
103+
104+
#if POOLSTL_SEQ_FWD_HAVE_CXX17_LIB
105+
POOLSTL_DEFINE_SEQ_FWD(std, exclusive_scan)
106+
POOLSTL_DEFINE_SEQ_FWD(std, reduce)
107+
POOLSTL_DEFINE_SEQ_FWD(std, transform_reduce)
108+
#endif
109+
}
110+
111+
#ifdef POOLSTL_VERSION_MAJOR
112+
namespace poolstl {
113+
// <poolstl/algorithm>
114+
115+
POOLSTL_DEFINE_SEQ_FWD_VOID(poolstl, for_each_chunk)
116+
}
117+
#endif
118+
119+
#endif

include/poolstl/variant_policy.hpp

Lines changed: 41 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@
66
#ifndef POOLSTL_VARIANT_POLICY_HPP
77
#define POOLSTL_VARIANT_POLICY_HPP
88

9-
#include "execution"
10-
9+
#include <algorithm>
10+
#include <numeric>
1111
#include <variant>
1212

13+
#if (__cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)) && \
14+
(!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 9)
15+
#define POOLSTL_VARIANT_HAVE_CXX17_LIB 1
16+
#else
17+
#define POOLSTL_VARIANT_HAVE_CXX17_LIB 0
18+
#endif
19+
1320
namespace poolstl {
1421
namespace execution {
1522
/**
@@ -24,9 +31,12 @@ namespace poolstl {
2431
};
2532

2633
namespace internal {
34+
// Example variant definition
35+
/*
2736
using poolstl_policy_variant = std::variant<
2837
poolstl::execution::parallel_policy,
2938
poolstl::execution::sequenced_policy>;
39+
*/
3040
}
3141
}
3242

@@ -52,25 +62,6 @@ namespace poolstl {
5262
}
5363
}
5464

55-
/*
56-
* Forward poolstl::seq to the native sequential (no policy) method.
57-
*/
58-
59-
#define POOLSTL_DEFINE_SEQ_FWD(NS, FNAME) \
60-
template<class EP, typename...ARGS> \
61-
auto FNAME(EP&&, ARGS&&...args) -> \
62-
poolstl::internal::enable_if_seq<EP, decltype(NS::FNAME(std::forward<ARGS>(args)...))> { \
63-
return NS::FNAME(std::forward<ARGS>(args)...); \
64-
}
65-
66-
#define POOLSTL_DEFINE_SEQ_FWD_VOID(NS, FNAME) \
67-
template<class EP, typename...ARGS> \
68-
poolstl::internal::enable_if_seq<EP, void> FNAME(EP&&, ARGS&&... args) { \
69-
NS::FNAME(std::forward<ARGS>(args)...); \
70-
}
71-
72-
#if POOLSTL_HAVE_CXX17
73-
7465
/*
7566
* Dynamically choose policy from a std::variant.
7667
* Useful to choose between parallel and sequential policies at runtime via par_if.
@@ -89,55 +80,48 @@ namespace poolstl {
8980
return std::visit([&](auto&& pol) { return NS::FNAME(pol, std::forward<ARGS>(args)...); }, policy.var); \
9081
}
9182

92-
#else
93-
#define POOLSTL_DEFINE_PAR_IF_FWD_VOID(NS, FNAME)
94-
#define POOLSTL_DEFINE_PAR_IF_FWD(NS, FNAME)
95-
#endif
96-
/*
97-
* Define both the sequential forward and dynamic chooser.
98-
*/
99-
#define POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(NS, FNAME) \
100-
POOLSTL_DEFINE_SEQ_FWD(NS, FNAME) \
101-
POOLSTL_DEFINE_PAR_IF_FWD(NS, FNAME)
102-
103-
#define POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF_VOID(NS, FNAME) \
104-
POOLSTL_DEFINE_SEQ_FWD_VOID(NS, FNAME) \
105-
POOLSTL_DEFINE_PAR_IF_FWD_VOID(NS, FNAME)
106-
10783
namespace std {
108-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, all_of)
109-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, any_of)
110-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, none_of)
84+
// <algorithm>
85+
86+
POOLSTL_DEFINE_PAR_IF_FWD(std, all_of)
87+
POOLSTL_DEFINE_PAR_IF_FWD(std, any_of)
88+
POOLSTL_DEFINE_PAR_IF_FWD(std, none_of)
11189

112-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, count)
113-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, count_if)
90+
POOLSTL_DEFINE_PAR_IF_FWD(std, count)
91+
POOLSTL_DEFINE_PAR_IF_FWD(std, count_if)
11492

115-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, copy)
116-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, copy_n)
93+
POOLSTL_DEFINE_PAR_IF_FWD(std, copy)
94+
POOLSTL_DEFINE_PAR_IF_FWD(std, copy_n)
11795

118-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF_VOID(std, fill)
119-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, fill_n)
96+
POOLSTL_DEFINE_PAR_IF_FWD_VOID(std, fill)
97+
POOLSTL_DEFINE_PAR_IF_FWD(std, fill_n)
12098

121-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, find)
122-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, find_if)
123-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, find_if_not)
99+
POOLSTL_DEFINE_PAR_IF_FWD(std, find)
100+
POOLSTL_DEFINE_PAR_IF_FWD(std, find_if)
101+
POOLSTL_DEFINE_PAR_IF_FWD(std, find_if_not)
124102

125-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF_VOID(std, for_each)
126-
#if POOLSTL_HAVE_CXX17_LIB
127-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, for_each_n)
103+
POOLSTL_DEFINE_PAR_IF_FWD_VOID(std, for_each)
104+
#if POOLSTL_VARIANT_HAVE_CXX17_LIB
105+
POOLSTL_DEFINE_PAR_IF_FWD(std, for_each_n)
128106
#endif
129107

130-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, transform)
108+
POOLSTL_DEFINE_PAR_IF_FWD(std, transform)
109+
110+
// <numeric>
131111

132-
#if POOLSTL_HAVE_CXX17_LIB
133-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, exclusive_scan)
134-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, reduce)
135-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(std, transform_reduce)
112+
#if POOLSTL_VARIANT_HAVE_CXX17_LIB
113+
POOLSTL_DEFINE_PAR_IF_FWD(std, exclusive_scan)
114+
POOLSTL_DEFINE_PAR_IF_FWD(std, reduce)
115+
POOLSTL_DEFINE_PAR_IF_FWD(std, transform_reduce)
136116
#endif
137117
}
138118

119+
#ifdef POOLSTL_VERSION_MAJOR
139120
namespace poolstl {
140-
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF_VOID(poolstl, for_each_chunk)
121+
// <poolstl/algorithm>
122+
123+
POOLSTL_DEFINE_PAR_IF_FWD_VOID(poolstl, for_each_chunk)
141124
}
125+
#endif
142126

143127
#endif

tests/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ add_executable(cpp11_test cpp11_test.cpp)
7171
target_link_libraries(cpp11_test PUBLIC poolSTL::poolSTL)
7272
target_compile_features(cpp11_test PUBLIC cxx_std_11)
7373

74+
# Test seq_fwd policy
75+
add_executable(seq_fwd_test seq_fwd_test.cpp)
76+
target_link_libraries(seq_fwd_test PRIVATE Catch2::Catch2WithMain poolSTL::poolSTL)
77+
target_compile_definitions(seq_fwd_test PRIVATE CATCH_CONFIG_FAST_COMPILE)
78+
target_compile_features(seq_fwd_test PUBLIC cxx_std_17)
79+
catch_discover_tests(seq_fwd_test)
80+
81+
7482
# Test std::execution supplementation.
7583
# The test code uses only std::execution::par, seq, and par_unseq.
7684
# On compilers with support poolSTL does nothing, else poolSTL aliases poolstl::par to the std::execution policies.

tests/seq_fwd_test.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (C) 2023 Adam Lugowski. All rights reserved.
2+
// Use of this source code is governed by:
3+
// the BSD 2-clause license, the MIT license, or at your choosing the BSL-1.0 license found in the LICENSE.*.txt files.
4+
// SPDX-License-Identifier: BSD-2-Clause OR MIT OR BSL-1.0
5+
6+
7+
#include <algorithm>
8+
#include <atomic>
9+
10+
#include <catch2/catch_test_macros.hpp>
11+
12+
#if __has_include(<poolstl/seq_fwd.hpp>)
13+
// seq_fwd not included in the poolSTL amalgam, so skip these tests on CI steps that test the amalgam.
14+
15+
#include <poolstl/seq_fwd.hpp>
16+
17+
#include "utils.hpp"
18+
19+
20+
TEST_CASE("fwd_count", "[alg][algorithm][seq_fwd]") {
21+
for (auto vec_size : test_arr_sizes) {
22+
auto haystack = iota_vector(vec_size);
23+
24+
{
25+
int needle = 5;
26+
auto seq = std::count( haystack.cbegin(), haystack.cend(), needle);
27+
auto par = std::count(poolstl::seq_fwd, haystack.cbegin(), haystack.cend(), needle);
28+
REQUIRE(seq == par);
29+
}
30+
{
31+
auto pred = [&](auto x) { return x % 2 == 0; };
32+
auto seq = std::count_if( haystack.cbegin(), haystack.cend(), pred);
33+
auto par = std::count_if(poolstl::seq_fwd, haystack.cbegin(), haystack.cend(), pred);
34+
REQUIRE(seq == par);
35+
}
36+
}
37+
}
38+
39+
TEST_CASE("fwd_for_each", "[alg][algorithm][seq_fwd]") {
40+
std::atomic<int> sum{0};
41+
for (auto num_iters : test_arr_sizes) {
42+
auto v = iota_vector(num_iters);
43+
44+
for (auto which_impl : {0, 1}) {
45+
sum = 0;
46+
auto f = [&](auto) { ++sum; };
47+
switch (which_impl) {
48+
case 0:
49+
std::for_each(v.cbegin(), v.cend(), f);
50+
break;
51+
case 1:
52+
std::for_each(poolstl::seq_fwd, v.cbegin(), v.cend(), f);
53+
break;
54+
default: break;
55+
}
56+
REQUIRE(sum == num_iters);
57+
}
58+
}
59+
}
60+
61+
std::mt19937 rng{1};
62+
#endif

0 commit comments

Comments
 (0)