#ifndef PLS_PARALLEL_FOR_IMPL_H #define PLS_PARALLEL_FOR_IMPL_H #include "pls/internal/scheduling/scheduler.h" #include "pls/internal/scheduling/thread_state.h" #include "pls/internal/helpers/range.h" namespace pls { namespace algorithm { namespace internal { template void for_each(const RandomIt first, const RandomIt last, const Function function, const long min_elements) { using namespace ::pls::internal::scheduling; const long num_elements = std::distance(first, last); if (num_elements <= min_elements) { // calculate last elements in loop to avoid overhead for (auto current = first; current != last; current++) { function(*current); } } else { // Cut in half recursively const long middle_index = num_elements / 2; scheduler::spawn([first, middle_index, last, &function, min_elements] { return internal::for_each(first, first + middle_index, function, min_elements); }); scheduler::spawn([first, middle_index, last, &function, min_elements] { return internal::for_each(first + middle_index, last, function, min_elements); }); scheduler::sync(); } } } class dynamic_strategy { public: explicit dynamic_strategy(const unsigned int tasks_per_thread = 4) : tasks_per_thread_{tasks_per_thread} {}; long calculate_min_elements(long num_elements) const { const long num_threads = pls::internal::scheduling::thread_state::get().get_scheduler().num_threads(); return num_elements / (num_threads * tasks_per_thread_); } private: unsigned const int tasks_per_thread_; }; class fixed_strategy { public: explicit fixed_strategy(const long min_elements_per_task) : min_elements_per_task_{min_elements_per_task} {}; long calculate_min_elements(long /*num_elements*/) const { return min_elements_per_task_; } private: const long min_elements_per_task_; }; template void for_each(RandomIt first, RandomIt last, const Function &function, ExecutionStrategy execution_strategy) { long num_elements = std::distance(first, last); return internal::for_each(first, last, function, execution_strategy.calculate_min_elements(num_elements)); } template void for_each(RandomIt first, RandomIt last, const Function &function) { return for_each(first, last, function, dynamic_strategy{4}); } template void for_each_range(unsigned long first, unsigned long last, const Function &function, ExecutionStrategy execution_strategy) { auto range = pls::internal::helpers::range(first, last); return for_each(range.begin(), range.end(), function, execution_strategy); } template void for_each_range(unsigned long first, unsigned long last, const Function &function) { auto range = pls::internal::helpers::range(first, last); return for_each(range.begin(), range.end(), function); } } } #endif //PLS_INVOKE_PARALLEL_IMPL_H