37#include <gtest/gtest.h>
81 auto result =
pmaps(pool, small_vec, [](
int x) {
return x * x; });
83 EXPECT_EQ(result, (std::vector<int>{1, 4, 9, 16, 25}));
88 auto result =
pmaps<double>(pool, small_vec, [](
int x) {
return x * 1.5; });
96 auto result =
pmaps(pool, small_vec, [](
int x) {
return std::to_string(x); });
104 auto result =
pmaps(pool, empty_vec, [](
int x) {
return x * 2; });
110 auto result =
pmaps(pool, single_vec, [](
int x) {
return x * 2; });
117 auto result =
pmaps(pool, large_vec, [](
int x) {
return x * 2; });
119 for (
size_t i = 0; i < result.size(); ++i)
120 EXPECT_EQ(result[i],
static_cast<int>((i + 1) * 2));
125 std::list<int>
lst = {1, 2, 3, 4, 5};
126 auto result =
pmaps(pool,
lst, [](
int x) {
return x * x; });
127 EXPECT_EQ(result, (std::vector<int>{1, 4, 9, 16, 25}));
132 auto result =
pmaps(pool, large_vec, [](
int x) {
return x; });
133 for (
size_t i = 0; i < result.size(); ++i)
134 EXPECT_EQ(result[i],
static_cast<int>(i + 1));
141 options.min_size = large_vec.size() + 1;
145 auto result =
pmaps(large_vec, [](
int x) {
return x + 1; },
options);
146 ASSERT_EQ(result.size(), large_vec.size());
157 auto result =
pfilter(pool, small_vec, [](
int x) {
return x % 2 == 0; });
158 EXPECT_EQ(result, (std::vector<int>{2, 4}));
163 auto result =
pfilter(pool, small_vec, [](
int x) {
return x % 2 != 0; });
164 EXPECT_EQ(result, (std::vector<int>{1, 3, 5}));
169 auto result =
pfilter(pool, small_vec, [](
int x) {
return x > 100; });
175 auto result =
pfilter(pool, small_vec, [](
int x) {
return x > 0; });
181 auto result =
pfilter(pool, empty_vec, [](
int) {
return true; });
187 std::vector<int>
nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
188 auto result =
pfilter(pool,
nums, [](
int x) {
return x % 3 == 0; });
189 EXPECT_EQ(result, (std::vector<int>{3, 6, 9}));
194 auto result =
pfilter(pool, large_vec, [](
int x) {
return x % 100 == 0; });
224 int sum =
pfoldl(pool, small_vec, 0, std::plus<int>());
230 int product =
pfoldl(pool, small_vec, 1, std::multiplies<int>());
237 [](
int a,
int b) {
return std::max(a, b); });
243 int result =
pfoldl(pool, empty_vec, 42, std::plus<int>());
250 [](
long long a,
int b) {
return a + b; });
261 std::vector<int> data = {1, 2, 3, 4, 5};
262 pfor_each(pool, data, [](
int& x) { x *= 2; });
263 EXPECT_EQ(data, (std::vector<int>{2, 4, 6, 8, 10}));
268 std::atomic<int>
count{0};
270 if (x % 2 == 0) ++
count;
277 std::atomic<int>
count{0};
284 std::vector<int> data = {1, 2, 3, 4};
290 EXPECT_EQ(data, (std::vector<int>{6, 7, 8, 9}));
299 bool result =
pall(pool, small_vec, [](
int x) {
return x > 0; });
305 bool result =
pall(pool, small_vec, [](
int x) {
return x > 3; });
311 bool result =
pall(pool, empty_vec, [](
int) {
return false; });
317 bool result =
pexists(pool, small_vec, [](
int x) {
return x == 3; });
323 bool result =
pexists(pool, small_vec, [](
int x) {
return x > 100; });
329 bool result =
pexists(pool, empty_vec, [](
int) {
return true; });
335 bool result =
pnone(pool, small_vec, [](
int x) {
return x < 0; });
341 bool result =
pnone(pool, small_vec, [](
int x) {
return x == 3; });
351 size_t count =
pcount_if(pool, small_vec, [](
int x) {
return x % 2 == 0; });
357 size_t count =
pcount_if(pool, large_vec, [](
int x) {
return x % 100 == 0; });
363 size_t count =
pcount_if(pool, small_vec, [](
int x) {
return x > 0; });
369 size_t count =
pcount_if(pool, small_vec, [](
int x) {
return x > 100; });
375 size_t count =
pcount_if(pool, large_vec, [](
int x) {
return x % 7 == 0; });
385 auto idx =
pfind(pool, small_vec, [](
int x) {
return x == 3; });
392 auto idx =
pfind(pool, small_vec, [](
int x) {
return x == 100; });
398 std::vector<int> data = {1, 2, 3, 3, 3, 4, 5};
399 auto idx =
pfind(pool, data, [](
int x) {
return x == 3; });
406 auto idx =
pfind(pool, empty_vec, [](
int) {
return true; });
417 auto idx =
pfind(large_vec, [](
int x) {
return x == 7777; },
options);
424 std::vector<std::string> words = {
"apple",
"banana",
"cherry"};
426 [](
const std::string& s) {
return s.length() > 5; });
437 auto sum =
psum(pool, small_vec);
443 auto sum =
psum(pool, small_vec, 100);
449 auto sum =
psum(pool, empty_vec);
477 auto min_val =
pmin(pool, small_vec);
484 auto max_val =
pmax(pool, small_vec);
491 auto min_val =
pmin(pool, empty_vec);
497 auto max_val =
pmax(pool, empty_vec);
503 auto result =
pminmax(pool, small_vec);
511 std::vector<int> data = {5, 1, 3, 2, 4};
512 auto result =
pminmax(pool, data);
520 auto result =
pminmax(pool, large_vec);
532 std::vector<int> data = {5, 2, 8, 1, 9, 3, 7, 4, 6};
534 EXPECT_EQ(data, (std::vector<int>{1, 2, 3, 4, 5, 6, 7, 8, 9}));
539 std::vector<int> data = {5, 2, 8, 1, 9, 3, 7, 4, 6};
540 psort(pool, data, std::greater<int>());
541 EXPECT_EQ(data, (std::vector<int>{9, 8, 7, 6, 5, 4, 3, 2, 1}));
546 std::vector<int> data;
553 std::vector<int> data = {42};
560 std::vector<int> data = {1, 2, 3, 4, 5};
562 EXPECT_EQ(data, (std::vector<int>{1, 2, 3, 4, 5}));
567 std::vector<int> data = large_vec;
568 std::mt19937
rng(42);
569 std::shuffle(data.begin(), data.end(),
rng);
571 for (
size_t i = 0; i < data.size(); ++i)
572 EXPECT_EQ(data[i],
static_cast<int>(i + 1));
577 std::vector<int> data = {7, 1, 5, 9, 3, 2};
583 EXPECT_EQ(data, (std::vector<int>{1, 2, 3, 5, 7, 9}));
588 std::vector<int> data(4096);
589 std::iota(data.begin(), data.end(), 0);
590 std::mt19937
rng(77);
591 std::shuffle(data.begin(), data.end(),
rng);
610 std::vector<int> a = {1, 2, 3};
611 std::vector<int> b = {4, 5, 6};
612 std::atomic<int>
sum{0};
620 std::vector<int> a = {1, 2, 3, 4, 5};
621 std::vector<int> b = {10, 20, 30};
622 std::atomic<int>
sum{0};
631 std::vector<int> b = {1, 2, 3};
632 std::atomic<int>
count{0};
644 std::vector<int> a = {1, 2, 3};
645 std::vector<int> b = {4, 5, 6};
647 auto result =
pzip_maps(pool, a, b, [](
int x,
int y) {
return x *
y; });
648 EXPECT_EQ(result, (std::vector<int>{4, 10, 18}));
653 std::vector<int> a = {1, 2, 3};
654 std::vector<double> b = {1.5, 2.5, 3.5};
656 auto result =
pzip_maps(pool, a, b, [](
int x,
double y) {
return x +
y; });
664 std::vector<int> a = {1, 2, 3, 4};
665 std::vector<int> b = {10, 20, 30, 40};
678 std::atomic<int>
visits{0};
696 auto [
yes,
no] =
ppartition(pool, small_vec, [](
int x) {
return x > 0; });
703 auto [
yes,
no] =
ppartition(pool, small_vec, [](
int x) {
return x < 0; });
710 auto [
yes,
no] =
ppartition(pool, empty_vec, [](
int) {
return true; });
717 std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
729 std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8};
749 std::vector<NoDefault> data;
750 for (
int i = 1; i <= 6; ++i)
751 data.emplace_back(i);
776 std::vector<int> data(512, 1);
795 std::vector<NoDefault> data;
796 for (
int i = 1; i <= 8; ++i)
797 data.emplace_back(i);
800 return x.value % 2 == 0;
816 std::vector<int> data(256);
817 std::iota(data.begin(), data.end(), 1);
818 std::vector<int>
expected(data.size());
819 std::partial_sum(data.begin(), data.end(),
expected.begin());
821 auto result =
pscan(pool, data, std::plus<int>{});
827 std::vector<int> data = {1, 2, 3, 4, 5};
829 EXPECT_EQ(result, (std::vector<int>{0, 1, 3, 6, 10}));
838 std::vector<int> data = {3, 1, 4, 1, 5, 9};
843 EXPECT_EQ(exclusive, (std::vector<int>{10, 13, 14, 18, 19, 24}));
845 std::vector<int> left = {1, 3, 5, 7};
846 std::vector<int> right = {2, 4, 6, 8};
847 auto merged =
pmerge(left, right, std::less<int>{},
options);
848 EXPECT_EQ(merged, (std::vector<int>{1, 2, 3, 4, 5, 6, 7, 8}));
860 std::vector<int> data(512, 1);
865 std::vector<int> left(256), right(256);
866 std::iota(left.begin(), left.end(), 0);
867 std::iota(right.begin(), right.end(), 0);
886 std::vector<NoDefault> data;
887 for (
int i = 1; i <= 4; ++i)
888 data.emplace_back(i);
910 std::vector<NoDefault> left, right;
911 left.emplace_back(1);
912 left.emplace_back(3);
913 left.emplace_back(5);
914 right.emplace_back(2);
915 right.emplace_back(4);
916 right.emplace_back(6);
918 auto merged =
pmerge(left, right,
920 return a.value < b.value;
923 for (
size_t i = 0; i < merged.size(); ++i)
924 EXPECT_EQ(merged[i].value,
static_cast<int>(i + 1));
935 for (
int x : large_vec)
939 auto par_result =
pmaps(pool, large_vec, [](
int x) {
return x * 2 + 1; });
948 for (
int x : large_vec)
962 for (
int x : large_vec)
967 [](
long long a,
int b) {
return a + b; });
980 return std::getenv(
"ALEPH_RUN_PARALLEL_BENCHMARKS") !=
nullptr;
987 GTEST_SKIP() <<
"Skipping timing-sensitive parallel benchmarks; "
988 <<
"set ALEPH_RUN_PARALLEL_BENCHMARKS=1 to enable";
990 std::vector<int> data(1000000);
991 std::iota(data.begin(), data.end(), 0);
994 auto seq_start = std::chrono::high_resolution_clock::now();
999 auto seq_end = std::chrono::high_resolution_clock::now();
1000 auto seq_duration = std::chrono::duration_cast<std::chrono::microseconds>(
1004 auto par_start = std::chrono::high_resolution_clock::now();
1005 auto par_result =
pmaps(pool, data, [](
int x) {
return x * x + 2 * x + 1; });
1006 auto par_end = std::chrono::high_resolution_clock::now();
1007 auto par_duration = std::chrono::duration_cast<std::chrono::microseconds>(
1013 std::cout <<
"\n=== Benchmark: pmaps ===\n";
1014 std::cout <<
"Data size: 1M elements\n";
1015 std::cout <<
"Sequential: " <<
seq_duration <<
" μs\n";
1017 std::cout <<
"Speedup: " <<
speedup <<
"x\n";
1018 std::cout <<
"========================\n\n";
1024 if (pool.num_threads() > 1)
1031 GTEST_SKIP() <<
"Skipping timing-sensitive parallel benchmarks; "
1032 <<
"set ALEPH_RUN_PARALLEL_BENCHMARKS=1 to enable";
1034 std::vector<int> data(1000000);
1035 std::iota(data.begin(), data.end(), 0);
1037 auto pred = [](
int x) {
return x % 7 == 0 || x % 11 == 0; };
1040 auto seq_start = std::chrono::high_resolution_clock::now();
1045 auto seq_end = std::chrono::high_resolution_clock::now();
1046 auto seq_duration = std::chrono::duration_cast<std::chrono::microseconds>(
1050 auto par_start = std::chrono::high_resolution_clock::now();
1052 auto par_end = std::chrono::high_resolution_clock::now();
1053 auto par_duration = std::chrono::duration_cast<std::chrono::microseconds>(
1059 std::cout <<
"\n=== Benchmark: pfilter ===\n";
1060 std::cout <<
"Data size: 1M elements\n";
1061 std::cout <<
"Sequential: " <<
seq_duration <<
" μs\n";
1063 std::cout <<
"Speedup: " <<
speedup <<
"x\n";
1064 std::cout <<
"==========================\n\n";
1070 GTEST_SKIP() <<
"Skipping timing-sensitive parallel benchmarks; "
1071 <<
"set ALEPH_RUN_PARALLEL_BENCHMARKS=1 to enable";
1073 std::vector<int> data(100000);
1074 std::iota(data.begin(), data.end(), 0);
1075 std::mt19937
rng(123);
1076 std::shuffle(data.begin(), data.end(),
rng);
1081 auto seq_start = std::chrono::high_resolution_clock::now();
1082 std::sort(data.begin(), data.end());
1083 auto seq_end = std::chrono::high_resolution_clock::now();
1084 auto seq_duration = std::chrono::duration_cast<std::chrono::microseconds>(
1088 auto par_start = std::chrono::high_resolution_clock::now();
1090 auto par_end = std::chrono::high_resolution_clock::now();
1091 auto par_duration = std::chrono::duration_cast<std::chrono::microseconds>(
1097 std::cout <<
"\n=== Benchmark: psort ===\n";
1098 std::cout <<
"Data size: 100K elements\n";
1099 std::cout <<
"std::sort: " <<
seq_duration <<
" μs\n";
1101 std::cout <<
"Speedup: " <<
speedup <<
"x\n";
1102 std::cout <<
"========================\n\n";
1112 auto future1 = std::async(std::launch::async, [
this]() {
1113 return pmaps(pool, large_vec, [](
int x) {
return x * 2; });
1116 auto future2 = std::async(std::launch::async, [
this]() {
1117 return pfilter(pool, large_vec, [](
int x) {
return x % 2 == 0; });
1120 auto future3 = std::async(std::launch::async, [
this]() {
1142 EXPECT_EQ(result, (std::vector<int>{1, 4, 9, 16, 25}));
1149 auto result =
pmaps(
many_pool, small_vec, [](
int x) {
return x * x; });
1150 EXPECT_EQ(result, (std::vector<int>{1, 4, 9, 16, 25}));
1155 std::vector<int>
huge(100000);
1156 std::iota(
huge.begin(),
huge.end(), 0);
1169 std::vector<int> a = {1, 2, 3};
1170 std::vector<int> b = {4, 5, 6};
1171 std::vector<int> c = {7, 8, 9};
1172 std::atomic<int>
sum{0};
1183 std::vector<int> a = {1, 2};
1184 std::vector<int> b = {3, 4};
1185 std::vector<int> c = {5, 6};
1186 std::vector<int> d = {7, 8};
1187 std::atomic<int>
sum{0};
1190 sum +=
w * x *
y * z;
1198 std::vector<int> a = {1, 2, 3, 4, 5};
1199 std::vector<int> b = {10, 20, 30};
1200 std::vector<int> c = {100, 200, 300, 400};
1201 std::atomic<int>
count{0};
1212 std::vector<int> a = {1, 2, 3};
1213 std::vector<int> b = {4, 5, 6};
1214 std::vector<int> c = {7, 8, 9};
1216 auto result =
pzip_maps_n(pool, [](
int x,
int y,
int z) {
1220 EXPECT_EQ(result, (std::vector<int>{12, 15, 18}));
1226 std::vector<int> b = {1, 2, 3};
1237 std::vector<int> a = {1, 2, 3};
1238 std::vector<int> b = {4, 5, 6};
1242 [](
int acc,
int x,
int y) {
return acc + x *
y; },
1251 std::vector<int> a = {1, 2, 3};
1252 std::vector<int> b = {2, 3, 4};
1253 std::vector<int> c = {3, 4, 5};
1255 bool result =
pzip_all_n(pool, [](
int x,
int y,
int z) {
1256 return x <
y &&
y < z;
1264 std::vector<int> a = {1, 2, 3};
1265 std::vector<int> b = {2, 3, 4};
1266 std::vector<int> c = {3, 2, 5};
1268 bool result =
pzip_all_n(pool, [](
int x,
int y,
int z) {
1269 return x <
y &&
y < z;
1277 std::vector<int> a = {1, 2, 3};
1278 std::vector<int> b = {4, 2, 6};
1289 std::vector<int> a = {1, 2, 3};
1290 std::vector<int> b = {4, 5, 6};
1301 std::vector<int> a = {1, 2, 3, 4, 5};
1302 std::vector<int> b = {5, 4, 3, 2, 1};
1313 std::vector<int> a = {1, 2, 3, 4, 5};
1314 std::vector<int> b = {1, 2, 3, 4, 5};
1317 return x ==
y && x % 2 == 0;
1325 std::vector<int> a = {1, 2, 3};
1326 std::vector<int> b = {4, 5, 6};
1327 std::vector<int> c = {7, 8, 9};
1337 [](
int acc,
int x,
int y,
int z) {
1338 return acc + x +
y + z;
1359 std::vector<int> data(100, 0);
1362 x =
static_cast<int>(i * 2);
1365 for (
size_t i = 0; i < data.size(); ++i)
1366 EXPECT_EQ(data[i],
static_cast<int>(i * 2));
1371 const std::vector<int> data = {10, 20, 30, 40, 50};
1384 std::vector<std::string> words = {
"a",
"bb",
"ccc"};
1387 [](
size_t i,
const std::string& s) {
1388 return std::to_string(i) +
":" + s;
1398 std::vector<int> empty;
1401 [](
size_t i,
int x) {
return static_cast<int>(i + x); });
1408 std::vector<int> data(6, 0);
1414 x =
static_cast<int>(i + 10);
1416 EXPECT_EQ(data, (std::vector<int>{10, 11, 12, 13, 14, 15}));
1419 return std::to_string(i) +
"=" + std::to_string(x);
1427 std::vector<int> a(256, 1), b(256, 2), c(256, 3);
1441 return static_cast<int>(i) + x;
1452 std::vector<int> a(10000), b(10000), c(10000);
1453 std::iota(a.begin(), a.end(), 0);
1454 std::iota(b.begin(), b.end(), 10000);
1455 std::iota(c.begin(), c.end(), 20000);
1457 std::atomic<long long>
sum{0};
1472 std::vector<int> a(10000), b(10000);
1473 std::iota(a.begin(), a.end(), 0);
1474 std::iota(b.begin(), b.end(), 0);
1480 for (
size_t i = 0; i < result.size(); ++i)
1481 EXPECT_EQ(result[i],
static_cast<int>(i * i));
1486 std::vector<int> a(1000), b(1000), c(1000);
1487 std::iota(a.begin(), a.end(), 0);
1488 std::iota(b.begin(), b.end(), 1000);
1489 std::iota(c.begin(), c.end(), 2000);
1493 for (
size_t i = 0; i < a.size(); ++i)
1506 ::testing::InitGoogleTest(&
argc,
argv);
Parallel functional programming operations using ThreadPool.
TEST_F(ParallelTest, PmapsSquare)
Cooperative cancellation source paired with CancellationToken.
CancellationToken token() const noexcept
Return a token observing this source.
void request_cancel() noexcept
Request cancellation for all derived tokens.
A reusable thread pool for efficient parallel task execution.
Exception thrown when cooperative cancellation is observed.
std::vector< int > single_vec
std::vector< int > empty_vec
std::vector< int > small_vec
std::vector< int > large_vec
Freq_Node * pred
Predecessor node in level-order traversal.
Main namespace for Aleph-w library functions.
bool pall(ThreadPool &pool, const Container &c, Pred pred, size_t chunk_size=0)
Parallel all predicate (short-circuit).
bool pnone(ThreadPool &pool, const Container &c, Pred pred, size_t chunk_size=0)
Parallel none predicate.
auto pmaps(ThreadPool &pool, const Container &c, Op op, size_t chunk_size=0)
Parallel map operation.
auto pmin(ThreadPool &pool, const Container &c, size_t chunk_size=0)
Parallel minimum element.
T pzip_foldl_n(ThreadPool &pool, T init, Op op, Combiner combiner, const Containers &... cs)
Parallel fold/reduce over N zipped containers (variadic).
T pzip_foldl(ThreadPool &pool, const Container1 &c1, const Container2 &c2, T init, Op op, size_t chunk_size=0)
Parallel zip + fold.
void pzip_for_each(ThreadPool &pool, const Container1 &c1, const Container2 &c2, Op op, size_t chunk_size=0)
Parallel zip + for_each.
auto penumerate_maps(ThreadPool &pool, const Container &c, Op op, size_t chunk_size=0)
Parallel enumerate with map.
void penumerate_for_each(ThreadPool &pool, Container &c, Op op, size_t chunk_size=0)
Parallel for_each with index (enumerate).
bool pzip_all_n(ThreadPool &pool, Pred pred, const Containers &... cs)
Parallel all predicate over N zipped containers (variadic).
size_t pcount_if(ThreadPool &pool, const Container &c, Pred pred, size_t chunk_size=0)
Parallel count_if operation.
auto pexclusive_scan(ThreadPool &pool, const Container &c, T init, BinaryOp op, size_t chunk_size=0)
Parallel exclusive scan over a container.
std::optional< size_t > pfind(ThreadPool &pool, const Container &c, Pred pred, size_t chunk_size=0)
Parallel find operation (returns index).
bool pzip_exists_n(ThreadPool &pool, Pred pred, const Containers &... cs)
Parallel exists predicate over N zipped containers (variadic).
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
void psort(ThreadPool &pool, Container &c, Compare cmp=Compare{}, const size_t min_parallel_size=1024)
Parallel sort (in-place).
void pfor_each(ThreadPool &pool, Container &c, Op op, size_t chunk_size=0)
Parallel for_each operation.
auto pfilter(ThreadPool &pool, const Container &c, Pred pred, size_t chunk_size=0)
Parallel filter operation.
auto ppartition(ThreadPool &pool, const Container &c, Pred pred, size_t chunk_size=0)
Parallel partition (stable).
auto pmerge(ThreadPool &pool, const Container1 &c1, const Container2 &c2, Compare comp=Compare{}, size_t chunk_size=0)
Parallel merge of two sorted containers.
T pproduct(ThreadPool &pool, const Container &c, T init=T{1}, size_t chunk_size=0)
Parallel product of elements.
T product(const Container &container, const T &init=T{1})
Compute product of all elements.
auto pmax(ThreadPool &pool, const Container &c, size_t chunk_size=0)
Parallel maximum element.
void pzip_for_each_n(ThreadPool &pool, Op op, const Containers &... cs)
Parallel for_each over N zipped containers (variadic).
auto pzip_maps_n(ThreadPool &pool, Op op, const Containers &... cs)
Parallel map over N zipped containers (variadic).
auto pscan(ThreadPool &pool, const Container &c, BinaryOp op, size_t chunk_size=0)
Parallel inclusive scan over a container.
T pfoldl(ThreadPool &pool, const Container &c, T init, BinaryOp op, size_t chunk_size=0)
Parallel left fold (reduce).
auto pfind_value(ThreadPool &pool, const Container &c, Pred pred, size_t chunk_size=0)
Parallel find with value return.
auto pzip_maps(ThreadPool &pool, const Container1 &c1, const Container2 &c2, Op op, size_t chunk_size=0)
Parallel zip + map.
T psum(ThreadPool &pool, const Container &c, T init=T{}, size_t chunk_size=0)
Parallel sum of elements.
auto pminmax(ThreadPool &pool, const Container &c, size_t chunk_size=0)
Parallel min and max elements.
size_t pzip_count_if_n(ThreadPool &pool, Pred pred, const Containers &... cs)
Parallel count over N zipped containers (variadic).
bool pexists(ThreadPool &pool, const Container &c, Pred pred, size_t chunk_size=0)
Parallel exists predicate (short-circuit).
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
static struct argp_option options[]
Common configuration object for parallel algorithms.
size_t chunk_size
Elements per chunk (0 = auto).
ThreadPool * pool
Executor to use (nullptr = default_pool()).