6#ifndef _CPG_PARALLEL_HPP
7#define _CPG_PARALLEL_HPP
23 template<
typename OperationType,
typename... ContainerTypes>
24 requires ( cgt::vector_c<ContainerTypes> && ... ) || ( cgt::std_array_flat_c<ContainerTypes> && ... )
27 auto Vs = std::tuple{ containers... };
29 constexpr auto N =
sizeof...(ContainerTypes);
33 using return_t =
decltype(operation( std::get<i>(Vs)[0] ...));
35 if constexpr(cgt::valid_type_c<return_t>)
36 return operation( std::get<i>(Vs)[0] ...);
42 template<
typename OperationType,
43 cgt::vector_c ContainerType, cgt::std_array_flat_c... ArrayTypes>
45 ContainerType&& container, ArrayTypes&&... arrays)
47 auto Vs = std::tuple{ arrays... };
49 constexpr auto N =
sizeof...(ArrayTypes);
54 {
return operation( container[0], std::get<i>(Vs) ... ); }));
56 if constexpr(cgt::valid_type_c<result_t>)
59 return operation( container[0], std::get<i>(Vs) ... );
66 using result_t =
decltype(operation( container[0] ));
68 if constexpr(cgt::valid_type_c<result_t>)
69 return operation( container[0] );
78 Dimension dim, Dimensions... dims)
80 constexpr auto N =
sizeof...(Dimensions) + 1;
81 std::array<long long, N> indices{};
85 using result_t =
decltype(operation( indices[i]... ));
87 if constexpr( cgt::valid_type_c<result_t> )
88 return operation( indices[i]... );
125 template<
template<
typename,
typename...>
class ContainerType,
126 typename ExecutionPolicy,
typename OperationType,
129 OperationType&& operation, RangeType head, RangeTypes... tails)
noexcept
132 { operation(head, tails...) } noexcept ;
135 constexpr long long rank =
sizeof...(RangeTypes) + 1;
137 using rank_array_t = std::array<long long, rank>;
140 dimensions{
static_cast<long long>(head),
static_cast<long long>(tails)... };
142 rank_array_t multipliers{1};
144 for(
size_t n = rank-1; n >= 1; --n)
146 multipliers[n] = multipliers[0];
147 multipliers[0] *= dimensions[n];
150 auto compute_index = [&multipliers](
auto n)
152 rank_array_t indices;
154 for(
long long r = 0; r < rank; ++r)
156 indices[r] = n / multipliers[r];
163 long long total = (head * ... * tails);
168 if constexpr(cgt::valid_type_c<element_t>)
170 using container_t = ContainerType<element_t>;
172 container_t Result(total);
174 auto parallel_task = [&Result, &compute_index, &operation](
auto i)
176 auto indices = compute_index(i);
178 cgt::for_stallion<rank>( [&]<
auto...k >
181 Result[i] = operation( indices[k]... );
193 auto parallel_task = [&compute_index, &operation](
auto i)
195 auto indices = compute_index(i);
197 cgt::for_stallion<rank>( [&]<
auto...k >
200 operation( indices[k]... );
213 RangeType head, RangeTypes... tails)
noexcept requires requires
215 { operation(head, tails... ) }
noexcept;
218 return go_std_parallel<std::vector>(std::execution::par_unseq,
219 std::forward<OperationType>(operation), head, tails...);
222 template<
template<
typename,
typename...>
class ContainerType,
223 typename ExecutionPolicy,
typename OperationType,
226 OperationType&& operation, RangeType head, RangeTypes... tails)
229 constexpr long long rank =
sizeof...(RangeTypes) + 1;
231 using rank_array_t = std::array<long long, rank>;
234 dimensions{
static_cast<long long>(head),
static_cast<long long>(tails)... };
236 rank_array_t multipliers{1};
238 for(
size_t n = rank-1; n >= 1; --n)
240 multipliers[n] = multipliers[0];
241 multipliers[0] *= dimensions[n];
244 auto compute_index = [&multipliers](
auto n)
246 rank_array_t indices;
248 for(
long long r = 0; r < rank; ++r)
250 indices[r] = n / multipliers[r];
257 long long total = (head * ... * tails);
262 std::atomic<bool> report_exception{};
264 std::exception_ptr work_exception;
266 using container_t = ContainerType<element_t>;
268 container_t Result(total);
270 auto parallel_task = [&report_exception, &
mutex, &work_exception,
271 &Result, &compute_index, &operation](
auto i)
273 static thread_local bool exception_occurred{};
275 if(exception_occurred)
return;
276 else if(report_exception)
278 exception_occurred =
true;
return;
283 auto indices = compute_index(i);
285 cgt::for_stallion<rank>( [&]<
auto...k >
288 Result[i] = operation( indices[k]... );
293 if(report_exception ==
false)
295 std::scoped_lock lock{
mutex};
298 work_exception = std::current_exception();
300 report_exception =
true;
303 exception_occurred =
true;
312 std::rethrow_exception(work_exception);
317 template<
template<
typename,
typename...>
class ContainerType,
318 typename ExecutionPolicy,
typename OperationType,
321 OperationType&& operation, RangeType head, RangeTypes... tails)
324 constexpr long long rank =
sizeof...(RangeTypes) + 1;
326 using rank_array_t = std::array<long long, rank>;
329 dimensions{
static_cast<long long>(head),
static_cast<long long>(tails)... };
331 rank_array_t multipliers{1};
333 for(
size_t n = rank-1; n >= 1; --n)
335 multipliers[n] = multipliers[0];
336 multipliers[0] *= dimensions[n];
339 auto compute_index = [&multipliers](
auto n)
341 rank_array_t indices;
343 for(
long long r = 0; r < rank; ++r)
345 indices[r] = n / multipliers[r];
352 long long total = (head * ... * tails);
354 std::atomic<bool> report_exception{};
356 std::exception_ptr work_exception;
359 [&report_exception, &
mutex, &work_exception,
360 &compute_index, &operation](
auto i)
362 thread_local bool exception_occurred{};
364 if(exception_occurred)
366 else if(report_exception)
368 exception_occurred =
true;
return;
373 auto indices = compute_index(i);
375 cgt::for_stallion<rank>( [&]<
auto...k >
378 operation( indices[k]... );
383 if(report_exception ==
false)
385 std::scoped_lock lock{
mutex};
388 work_exception = std::current_exception();
391 exception_occurred =
true;
392 report_exception =
true;
401 std::rethrow_exception(work_exception);
408 RangeType head, RangeTypes... tails)
410 return go_std_parallel_exception_safe<std::vector>(std::execution::par_unseq,
411 std::forward<OperationType>(operation), head, tails...);
415 template<
template<
typename, auto>
class ContainerType = std::array,
417 typename OperationType =
cgt::no_type,
auto head = 1,
auto... tails>
421 constexpr long long rank =
sizeof...(tails) + 1;
423 std::array<long long, rank>
424 dimensions{
static_cast<long long>(head),
425 static_cast<long long>(tails)... };
427 std::array<long long, rank> multipliers{1};
429 for(
size_t n = rank-1; n >=1; --n)
431 multipliers[n] = multipliers[0];
432 multipliers[0] *= dimensions[n];
435 auto compute_index = [&multipliers](
auto n)
437 std::array<long long, rank> indices{};
439 for(
long long r = 0; r < rank; ++r)
441 indices[r] = n / multipliers[r];
448 auto total = dimensions[0] * multipliers[0];
452 constexpr std::size_t N = (head * ... * tails);
454 if constexpr(cgt::valid_type_c<element_t>)
456 using container_t = ContainerType<element_t, N>;
460 auto parallel_task =[&R, &compute_index, &operation](
auto i)
462 auto indices = compute_index(i);
466 R[i] = operation(indices[k]... );
470 std::for_each(execution_policy,
480 template<
typename ExecutionPolicy,
typename OperationType,
481 cgt::vector_c ContainerType, cgt::std_array_flat_c... ArrayTypes>
483 OperationType&& operation, ContainerType&& container, ArrayTypes&&...arrays)
485 std::remove_cvref_t<ArrayTypes>{}...))
487 auto Vs = std::forward_as_tuple(arrays...);
492 if constexpr(cgt::valid_type_c<element_t>)
494 using vector_t = std::vector<element_t>;
497 auto parallel_task = [&](
auto i)
499 constexpr auto N =
sizeof...(ArrayTypes);
508 R[i] = operation(container[i]);
509 else if constexpr(N == 1)
510 R[i] = operation(container[i], std::get<0>(Vs) );
511 else if constexpr(N == 2)
512 R[i] = operation(container[i],
513 std::get<0>(Vs), std::get<1>(Vs));
514 else if constexpr(N == 3)
515 R[i] = operation(container[i],
516 std::get<0>(Vs), std::get<1>(Vs), std::get<2>(Vs));
517 else if constexpr(N == 4)
518 R[i] = operation(container[i],
519 std::get<0>(Vs), std::get<1>(Vs), std::get<2>(Vs), std::get<3>(Vs));
522 {
return operation(container[i], std::get<k>(Vs)... ); });
535 template<
typename ExecutionPolicy,
typename OperationType,
536 cgt::vector_c... ContainerTypes>
requires (
sizeof...(ContainerTypes) > 1)
538 OperationType&& operation, ContainerTypes&&... containers)
540 auto Vs = std::forward_as_tuple(containers...);
542 auto A_size = std::get<0>(Vs).size();
544 auto all_element_counts_are_the_same =
547 assert(all_element_counts_are_the_same);
552 if constexpr(cgt::valid_type_c<element_t>)
554 using vector_t = std::vector<element_t>;
558 auto parallel_task = [&](
auto i)
560 constexpr auto N =
sizeof...(ContainerTypes);
564 return operation( std::get<k>(Vs)[i] ... );
579 template<
typename ExecutionPolicy,
typename OperationType,
580 cgt::std_array_flat_c... ContainerTypes>
requires (
sizeof...(ContainerTypes) > 0)
582 OperationType&& operation, ContainerTypes&&... containers)
585 auto Vs = std::forward_as_tuple(containers...);
587 using Vs_t =
decltype(Vs);
588 using A_t = std::remove_cvref_t< std::tuple_element_t<0, Vs_t> >;
589 constexpr auto A_size = std::tuple_size_v< A_t >;
594 if constexpr(cgt::valid_type_c<element_t>)
596 using array_t = std::array<element_t, A_size>; array_t R;
598 auto parallel_task = [&](
auto i)
600 constexpr auto N =
sizeof...(ContainerTypes);
608 R[i] = operation( std::get<0>(Vs)[i] );
609 else if constexpr(N == 2)
610 R[i] = operation( std::get<0>(Vs)[i], std::get<1>(Vs)[i] );
611 else if constexpr(N == 3)
612 R[i] = operation( std::get<0>(Vs)[i], std::get<1>(Vs)[i], std::get<2>(Vs)[i] );
613 else if constexpr(N == 4)
614 R[i] = operation( std::get<0>(Vs)[i], std::get<1>(Vs)[i],
615 std::get<2>(Vs)[i], std::get<3>(Vs)[i]);
616 else if constexpr(N == 5)
617 R[i] = operation( std::get<0>(Vs)[i], std::get<1>(Vs)[i],
618 std::get<2>(Vs)[i], std::get<3>(Vs)[i], std::get<4>(Vs)[i]);
622 return operation( std::get<k>(Vs)[i] ... );
std::vector< Type > vector_t
BoundType integral(FuncType &&f, std::tuple< BoundType, BoundType > bound)
constexpr auto resultant_element_type(OperationType &&operation, ContainerTypes &&... containers)
decltype(auto) go_std_parallel_exception_safe(ExecutionPolicy &&execution_policy, OperationType &&operation, RangeType head, RangeTypes... tails)
constexpr decltype(auto) counting_iterator(IndexType idx=IndexType{})
constexpr decltype(auto) go_std_parallel(ExecutionPolicy &&execution_policy, OperationType &&operation, RangeType head, RangeTypes... tails) noexcept
constexpr auto element_counts_are_the_same(ContainerTypes &&... containers)
typename hidden::st_first_element< std::remove_cvref_t< T > >::type first_type_t
std::integer_sequence< std::common_type_t< std::remove_cvref_t< decltype(Indices)>... >, Indices... > sequence