Skip to content

Commit c9dcec9

Browse files
committed
Add std::count, std::count_if
1 parent 4abed89 commit c9dcec9

File tree

4 files changed

+63
-9
lines changed

4 files changed

+63
-9
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Algorithms are added on an as-needed basis. If you need one [open an issue](http
2828
### `<algorithm>`
2929
* [all_of](https://en.cppreference.com/w/cpp/algorithm/all_of), [any_of](https://en.cppreference.com/w/cpp/algorithm/any_of), [none_of](https://en.cppreference.com/w/cpp/algorithm/none_of)
3030
* [copy](https://en.cppreference.com/w/cpp/algorithm/copy), [copy_n](https://en.cppreference.com/w/cpp/algorithm/copy_n)
31+
* [count](https://en.cppreference.com/w/cpp/algorithm/count), [count_if](https://en.cppreference.com/w/cpp/algorithm/count_if)
3132
* [fill](https://en.cppreference.com/w/cpp/algorithm/fill), [fill_n](https://en.cppreference.com/w/cpp/algorithm/fill_n)
3233
* [find](https://en.cppreference.com/w/cpp/algorithm/find), [find_if](https://en.cppreference.com/w/cpp/algorithm/find_if), [find_if_not](https://en.cppreference.com/w/cpp/algorithm/find_if_not)
3334
* [for_each](https://en.cppreference.com/w/cpp/algorithm/for_each), [for_each_n](https://en.cppreference.com/w/cpp/algorithm/for_each_n)

include/poolstl/algorithm

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,36 @@ namespace std {
4343
return poolstl::internal::advanced(dest, n);
4444
}
4545

46+
/**
47+
* NOTE: Iterators are expected to be random access.
48+
* See std::count_if https://en.cppreference.com/w/cpp/algorithm/count_if
49+
*/
50+
template <class ExecPolicy, class RandIt, class UnaryPredicate>
51+
poolstl::internal::enable_if_par<ExecPolicy, typename iterator_traits<RandIt>::difference_type>
52+
count_if(ExecPolicy&& policy, RandIt first, RandIt last, UnaryPredicate p) {
53+
using T = typename iterator_traits<RandIt>::difference_type;
54+
55+
auto futures = poolstl::internal::parallel_chunk_for(std::forward<ExecPolicy>(policy), first, last,
56+
[&p](RandIt chunk_first, RandIt chunk_last) {
57+
return std::count_if(chunk_first, chunk_last, p);
58+
});
59+
60+
return poolstl::internal::cpp17::reduce(
61+
poolstl::internal::get_wrap(futures.begin()),
62+
poolstl::internal::get_wrap(futures.end()), 0, std::plus<T>());
63+
}
64+
65+
/**
66+
* NOTE: Iterators are expected to be random access.
67+
* See std::count https://en.cppreference.com/w/cpp/algorithm/count
68+
*/
69+
template <class ExecPolicy, class RandIt, class T>
70+
poolstl::internal::enable_if_par<ExecPolicy, typename iterator_traits<RandIt>::difference_type>
71+
count(ExecPolicy&& policy, RandIt first, RandIt last, const T& value) {
72+
return std::count_if(std::forward<ExecPolicy>(policy), first, last,
73+
[&value](const T& test) { return test == value; });
74+
}
75+
4676
/**
4777
* NOTE: Iterators are expected to be random access.
4878
* See std::fill https://en.cppreference.com/w/cpp/algorithm/fill

include/poolstl/seq_fwd.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ namespace std {
6666
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(any_of)
6767
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(none_of)
6868

69+
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(count)
70+
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(count_if)
71+
6972
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(copy)
7073
POOLSTL_DEFINE_BOTH_SEQ_FWD_AND_PAR_IF(copy_n)
7174

tests/poolstl_test.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,28 @@ TEST_CASE("copy_n", "[alg][algorithm]") {
9090
}
9191
}
9292

93+
TEST_CASE("count", "[alg][algorithm]") {
94+
for (auto num_threads : test_thread_counts) {
95+
ttp::task_thread_pool pool(num_threads);
96+
97+
for (auto vec_size : test_arr_sizes) {
98+
auto haystack = iota_vector(vec_size);
99+
100+
{
101+
int needle = 5;
102+
auto seq = std::count(poolstl::par_if<>(false), haystack.cbegin(), haystack.cend(), needle);
103+
auto par = std::count(poolstl::par_pool(pool), haystack.cbegin(), haystack.cend(), needle);
104+
REQUIRE(seq == par);
105+
}
106+
{
107+
auto pred = [&](auto x) { return x % 2 == 0; };
108+
auto seq = std::count_if(poolstl::par_if<>(false), haystack.cbegin(), haystack.cend(), pred);
109+
auto par = std::count_if(poolstl::par_pool(pool), haystack.cbegin(), haystack.cend(), pred);
110+
REQUIRE(seq == par);
111+
}
112+
}
113+
}
114+
}
93115

94116
TEST_CASE("fill", "[alg][algorithm]") {
95117
for (auto num_threads : test_thread_counts) {
@@ -367,15 +389,13 @@ TEST_CASE("execution_policies", "[execution]") {
367389
ttp::task_thread_pool pool;
368390
std::vector<int> v = {0, 1, 2, 3, 4, 5};
369391

370-
REQUIRE(15 == std::reduce(poolstl::par, v.cbegin(), v.cend()));
371-
REQUIRE(15 == std::reduce(poolstl::par_pool(pool), v.cbegin(), v.cend()));
372-
#if POOLSTL_HAVE_CXX17_LIB
373-
REQUIRE(15 == std::reduce(poolstl::seq, v.cbegin(), v.cend()));
374-
REQUIRE(15 == std::reduce(poolstl::par_if<>(false), v.cbegin(), v.cend()));
375-
REQUIRE(15 == std::reduce(poolstl::par_if<>(true), v.cbegin(), v.cend()));
376-
REQUIRE(15 == std::reduce(poolstl::par_if_pool<>(false, pool), v.cbegin(), v.cend()));
377-
REQUIRE(15 == std::reduce(poolstl::par_if_pool<>(true, pool), v.cbegin(), v.cend()));
378-
#endif
392+
REQUIRE(1 == std::count(poolstl::par, v.cbegin(), v.cend(), 5));
393+
REQUIRE(1 == std::count(poolstl::par_pool(pool), v.cbegin(), v.cend(), 5));
394+
REQUIRE(1 == std::count(poolstl::seq, v.cbegin(), v.cend(), 5));
395+
REQUIRE(1 == std::count(poolstl::par_if<>(false), v.cbegin(), v.cend(), 5));
396+
REQUIRE(1 == std::count(poolstl::par_if<>(true), v.cbegin(), v.cend(), 5));
397+
REQUIRE(1 == std::count(poolstl::par_if_pool<>(false, pool), v.cbegin(), v.cend(), 5));
398+
REQUIRE(1 == std::count(poolstl::par_if_pool<>(true, pool), v.cbegin(), v.cend(), 5));
379399
}
380400

381401
std::mt19937 rng{1};

0 commit comments

Comments
 (0)