70void for_each_n(TaskSetT& tasks, Iter start,
size_t n, F&& f,
ForEachOptions options = {}) {
73 if (!n || !options.maxThreads || detail::PerPoolPerThreadInfo::isParForRecursive(&tasks.pool())) {
74 for (
size_t i = 0; i < n; ++i) {
85 int32_t maxThreads = std::max<int32_t>(options.maxThreads, 1);
87 ssize_t numThreads = std::min<ssize_t>(tasks.numPoolThreads() + options.wait, maxThreads);
89 numThreads = std::min<ssize_t>(numThreads, n);
91 auto chunking = detail::staticChunkSize(n, numThreads);
92 size_t chunkSize = chunking.ceilChunkSize;
94 bool perfectlyChunked = chunking.transitionTaskIndex == numThreads;
97 ssize_t firstLoopLen = chunking.transitionTaskIndex - perfectlyChunked;
100 for (t = 0; t < firstLoopLen; ++t) {
102 std::advance(next, chunkSize);
103 tasks.schedule([start, next, f]() {
104 auto recurseInfo = detail::PerPoolPerThreadInfo::parForRecurse();
105 for (Iter it = start; it != next; ++it) {
113 chunkSize -= !perfectlyChunked;
115 for (; t < numThreads - 1; ++t) {
117 std::advance(next, chunkSize);
118 tasks.schedule([start, next, f]() {
119 auto recurseInfo = detail::PerPoolPerThreadInfo::parForRecurse();
120 for (Iter it = start; it != next; ++it) {
128 std::advance(end, chunkSize);
131 for (Iter it = start; it != end; ++it) {
138 auto recurseInfo = detail::PerPoolPerThreadInfo::parForRecurse();
139 for (Iter it = start; it != end; ++it) {
161 TaskSet taskSet(globalThreadPool());
163 for_each_n(taskSet, start, n, std::forward<F>(f), options);
179void for_each(TaskSetT& tasks, Iter start, Iter end, F&& f,
ForEachOptions options = {}) {
180 for_each_n(tasks, start, std::distance(start, end), std::forward<F>(f), options);