149e08aacStbbdev /*
2*b15aabb3Stbbdev     Copyright (c) 2005-2021 Intel Corporation
349e08aacStbbdev 
449e08aacStbbdev     Licensed under the Apache License, Version 2.0 (the "License");
549e08aacStbbdev     you may not use this file except in compliance with the License.
649e08aacStbbdev     You may obtain a copy of the License at
749e08aacStbbdev 
849e08aacStbbdev         http://www.apache.org/licenses/LICENSE-2.0
949e08aacStbbdev 
1049e08aacStbbdev     Unless required by applicable law or agreed to in writing, software
1149e08aacStbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1249e08aacStbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1349e08aacStbbdev     See the License for the specific language governing permissions and
1449e08aacStbbdev     limitations under the License.
1549e08aacStbbdev */
1649e08aacStbbdev 
1749e08aacStbbdev #ifndef __TBB_parallel_for_each_H
1849e08aacStbbdev #define __TBB_parallel_for_each_H
1949e08aacStbbdev 
2049e08aacStbbdev #include "detail/_config.h"
2149e08aacStbbdev #include "detail/_namespace_injection.h"
2249e08aacStbbdev #include "detail/_exception.h"
2349e08aacStbbdev #include "detail/_task.h"
2449e08aacStbbdev #include "detail/_aligned_space.h"
2549e08aacStbbdev #include "detail/_small_object_pool.h"
2649e08aacStbbdev 
2749e08aacStbbdev #include "parallel_for.h"
2849e08aacStbbdev #include "task_group.h" // task_group_context
2949e08aacStbbdev 
3049e08aacStbbdev #include <iterator>
3149e08aacStbbdev #include <type_traits>
3249e08aacStbbdev 
3349e08aacStbbdev namespace tbb {
3449e08aacStbbdev namespace detail {
35*b15aabb3Stbbdev namespace d2 {
3649e08aacStbbdev template<typename Body, typename Item> class feeder_impl;
37*b15aabb3Stbbdev } // namespace d2
3849e08aacStbbdev 
39*b15aabb3Stbbdev namespace d1 {
4049e08aacStbbdev //! Class the user supplied algorithm body uses to add new tasks
4149e08aacStbbdev template<typename Item>
4249e08aacStbbdev class feeder {
4349e08aacStbbdev     feeder() {}
4449e08aacStbbdev     feeder(const feeder&) = delete;
4549e08aacStbbdev     void operator=( const feeder&) = delete;
4649e08aacStbbdev 
4749e08aacStbbdev     virtual ~feeder () {}
4849e08aacStbbdev     virtual void internal_add_copy(const Item& item) = 0;
4949e08aacStbbdev     virtual void internal_add_move(Item&& item) = 0;
5049e08aacStbbdev 
51*b15aabb3Stbbdev     template<typename Body_, typename Item_> friend class detail::d2::feeder_impl;
5249e08aacStbbdev public:
5349e08aacStbbdev     //! Add a work item to a running parallel_for_each.
5449e08aacStbbdev     void add(const Item& item) {internal_add_copy(item);}
5549e08aacStbbdev     void add(Item&& item) {internal_add_move(std::move(item));}
5649e08aacStbbdev };
5749e08aacStbbdev 
58*b15aabb3Stbbdev } // namespace d1
59*b15aabb3Stbbdev 
60*b15aabb3Stbbdev namespace d2 {
61*b15aabb3Stbbdev using namespace tbb::detail::d1;
6249e08aacStbbdev /** Selects one of the two possible forms of function call member operator.
6349e08aacStbbdev     @ingroup algorithms **/
64*b15aabb3Stbbdev template<class Body>
65*b15aabb3Stbbdev struct parallel_for_each_operator_selector {
6649e08aacStbbdev public:
6749e08aacStbbdev     template<typename ItemArg, typename FeederArg>
68*b15aabb3Stbbdev     static auto call(const Body& body, ItemArg&& item, FeederArg*)
6949e08aacStbbdev     -> decltype(body(std::forward<ItemArg>(item)), void()) {
7049e08aacStbbdev         #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
7149e08aacStbbdev         // Suppression of Microsoft non-standard extension warnings
7249e08aacStbbdev         #pragma warning (push)
7349e08aacStbbdev         #pragma warning (disable: 4239)
7449e08aacStbbdev         #endif
7549e08aacStbbdev 
7649e08aacStbbdev         body(std::forward<ItemArg>(item));
7749e08aacStbbdev 
7849e08aacStbbdev         #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
7949e08aacStbbdev         #pragma warning (push)
8049e08aacStbbdev         #endif
8149e08aacStbbdev     }
8249e08aacStbbdev 
8349e08aacStbbdev     template<typename ItemArg, typename FeederArg>
84*b15aabb3Stbbdev     static auto call(const Body& body, ItemArg&& item, FeederArg* feeder)
85*b15aabb3Stbbdev     -> decltype(body(std::forward<ItemArg>(item), *feeder), void()) {
8649e08aacStbbdev         #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
8749e08aacStbbdev         // Suppression of Microsoft non-standard extension warnings
8849e08aacStbbdev         #pragma warning (push)
8949e08aacStbbdev         #pragma warning (disable: 4239)
9049e08aacStbbdev         #endif
91*b15aabb3Stbbdev         __TBB_ASSERT(feeder, "Feeder was not created but should be");
9249e08aacStbbdev 
93*b15aabb3Stbbdev         body(std::forward<ItemArg>(item), *feeder);
9449e08aacStbbdev 
9549e08aacStbbdev         #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
9649e08aacStbbdev         #pragma warning (push)
9749e08aacStbbdev         #endif
9849e08aacStbbdev     }
9949e08aacStbbdev };
10049e08aacStbbdev 
10149e08aacStbbdev template<typename Body, typename Item>
10249e08aacStbbdev struct feeder_item_task: public task {
10349e08aacStbbdev     using feeder_type = feeder_impl<Body, Item>;
10449e08aacStbbdev 
10549e08aacStbbdev     template <typename ItemType>
10649e08aacStbbdev     feeder_item_task(ItemType&& input_item, feeder_type& feeder, small_object_allocator& alloc) :
10749e08aacStbbdev         item(std::forward<ItemType>(input_item)),
10849e08aacStbbdev         my_feeder(feeder),
10949e08aacStbbdev         my_allocator(alloc)
11049e08aacStbbdev     {}
11149e08aacStbbdev 
11249e08aacStbbdev     void finalize(const execution_data& ed) {
11349e08aacStbbdev         my_feeder.my_wait_context.release();
11449e08aacStbbdev         my_allocator.delete_object(this, ed);
11549e08aacStbbdev     }
11649e08aacStbbdev 
117*b15aabb3Stbbdev     //! Hack for resolve ambiguity between calls to the body with and without moving the stored copy
118*b15aabb3Stbbdev     //! Executing body with moving the copy should have higher priority
119*b15aabb3Stbbdev     using first_priority = int;
120*b15aabb3Stbbdev     using second_priority = double;
121*b15aabb3Stbbdev 
122*b15aabb3Stbbdev     template <typename BodyType, typename ItemType, typename FeederType>
123*b15aabb3Stbbdev     static auto call(const BodyType& call_body, ItemType& call_item, FeederType& call_feeder, first_priority)
124*b15aabb3Stbbdev     -> decltype(parallel_for_each_operator_selector<Body>::call(call_body, std::move(call_item), &call_feeder), void())
125*b15aabb3Stbbdev     {
126*b15aabb3Stbbdev         parallel_for_each_operator_selector<Body>::call(call_body, std::move(call_item), &call_feeder);
127*b15aabb3Stbbdev     }
128*b15aabb3Stbbdev 
129*b15aabb3Stbbdev     template <typename BodyType, typename ItemType, typename FeederType>
130*b15aabb3Stbbdev     static void call(const BodyType& call_body, ItemType& call_item, FeederType& call_feeder, second_priority) {
131*b15aabb3Stbbdev         parallel_for_each_operator_selector<Body>::call(call_body, call_item, &call_feeder);
132*b15aabb3Stbbdev     }
133*b15aabb3Stbbdev 
13449e08aacStbbdev     task* execute(execution_data& ed) override {
135*b15aabb3Stbbdev         call(my_feeder.my_body, item, my_feeder, first_priority{});
13649e08aacStbbdev         finalize(ed);
13749e08aacStbbdev         return nullptr;
13849e08aacStbbdev     }
13949e08aacStbbdev 
14049e08aacStbbdev     task* cancel(execution_data& ed) override {
14149e08aacStbbdev         finalize(ed);
14249e08aacStbbdev         return nullptr;
14349e08aacStbbdev     }
14449e08aacStbbdev 
14549e08aacStbbdev     Item item;
14649e08aacStbbdev     feeder_type& my_feeder;
14749e08aacStbbdev     small_object_allocator my_allocator;
14849e08aacStbbdev }; // class feeder_item_task
14949e08aacStbbdev 
15049e08aacStbbdev /** Implements new task adding procedure.
15149e08aacStbbdev     @ingroup algorithms **/
152*b15aabb3Stbbdev template<typename Body, typename Item>
15349e08aacStbbdev class feeder_impl : public feeder<Item> {
15449e08aacStbbdev     // Avoiding use of copy constructor in a virtual method if the type does not support it
15549e08aacStbbdev     void internal_add_copy_impl(std::true_type, const Item& item) {
15649e08aacStbbdev         using feeder_task = feeder_item_task<Body, Item>;
15749e08aacStbbdev         small_object_allocator alloc;
15849e08aacStbbdev         auto task = alloc.new_object<feeder_task>(item, *this, alloc);
15949e08aacStbbdev 
16049e08aacStbbdev         my_wait_context.reserve();
16149e08aacStbbdev         spawn(*task, my_execution_context);
16249e08aacStbbdev     }
16349e08aacStbbdev 
16449e08aacStbbdev     void internal_add_copy_impl(std::false_type, const Item&) {
16549e08aacStbbdev         __TBB_ASSERT(false, "Overloading for r-value reference doesn't work or it's not movable and not copyable object");
16649e08aacStbbdev     }
16749e08aacStbbdev 
16849e08aacStbbdev     void internal_add_copy(const Item& item) override {
16949e08aacStbbdev         internal_add_copy_impl(typename std::is_copy_constructible<Item>::type(), item);
17049e08aacStbbdev     }
17149e08aacStbbdev 
17249e08aacStbbdev     void internal_add_move(Item&& item) override {
17349e08aacStbbdev         using feeder_task = feeder_item_task<Body, Item>;
17449e08aacStbbdev         small_object_allocator alloc{};
17549e08aacStbbdev         auto task = alloc.new_object<feeder_task>(std::move(item), *this, alloc);
17649e08aacStbbdev 
17749e08aacStbbdev         my_wait_context.reserve();
17849e08aacStbbdev         spawn(*task, my_execution_context);
17949e08aacStbbdev     }
18049e08aacStbbdev public:
181*b15aabb3Stbbdev     feeder_impl(const Body& body, wait_context& w_context, task_group_context &context)
182*b15aabb3Stbbdev       : my_body(body),
183*b15aabb3Stbbdev         my_wait_context(w_context)
18449e08aacStbbdev       , my_execution_context(context)
18549e08aacStbbdev     {}
18649e08aacStbbdev 
18749e08aacStbbdev     const Body& my_body;
188*b15aabb3Stbbdev     wait_context& my_wait_context;
18949e08aacStbbdev     task_group_context& my_execution_context;
19049e08aacStbbdev }; // class feeder_impl
19149e08aacStbbdev 
19249e08aacStbbdev /** Execute computation under one element of the range
19349e08aacStbbdev     @ingroup algorithms **/
19449e08aacStbbdev template<typename Iterator, typename Body, typename Item>
19549e08aacStbbdev struct for_each_iteration_task: public task {
19649e08aacStbbdev     using feeder_type = feeder_impl<Body, Item>;
19749e08aacStbbdev 
198*b15aabb3Stbbdev     for_each_iteration_task(Iterator input_item_ptr, const Body& body, feeder_impl<Body, Item>* feeder_ptr, wait_context& wait_context) :
199*b15aabb3Stbbdev         item_ptr(input_item_ptr), my_body(body), my_feeder_ptr(feeder_ptr), parent_wait_context(wait_context)
20049e08aacStbbdev     {}
20149e08aacStbbdev 
20249e08aacStbbdev     void finalize() {
20349e08aacStbbdev         parent_wait_context.release();
20449e08aacStbbdev     }
20549e08aacStbbdev 
20649e08aacStbbdev     task* execute(execution_data&) override {
207*b15aabb3Stbbdev         parallel_for_each_operator_selector<Body>::call(my_body, *item_ptr, my_feeder_ptr);
20849e08aacStbbdev         finalize();
20949e08aacStbbdev         return nullptr;
21049e08aacStbbdev     }
21149e08aacStbbdev 
21249e08aacStbbdev     task* cancel(execution_data&) override {
21349e08aacStbbdev         finalize();
21449e08aacStbbdev         return nullptr;
21549e08aacStbbdev     }
21649e08aacStbbdev 
21749e08aacStbbdev     Iterator item_ptr;
218*b15aabb3Stbbdev     const Body& my_body;
219*b15aabb3Stbbdev     feeder_impl<Body, Item>* my_feeder_ptr;
22049e08aacStbbdev     wait_context& parent_wait_context;
221*b15aabb3Stbbdev }; // class for_each_iteration_task
222*b15aabb3Stbbdev 
223*b15aabb3Stbbdev // Helper to get the type of the iterator to the internal sequence of copies
224*b15aabb3Stbbdev // If the element can be passed to the body as an rvalue - this iterator should be move_iterator
225*b15aabb3Stbbdev template <typename Body, typename Item, typename = void>
226*b15aabb3Stbbdev struct input_iteration_task_iterator_helper {
227*b15aabb3Stbbdev     // For input iterators we pass const lvalue reference to the body
228*b15aabb3Stbbdev     // It is prohibited to take non-constant lvalue references for input iterators
229*b15aabb3Stbbdev     using type = const Item*;
230*b15aabb3Stbbdev };
231*b15aabb3Stbbdev 
232*b15aabb3Stbbdev template <typename Body, typename Item>
233*b15aabb3Stbbdev struct input_iteration_task_iterator_helper<Body, Item,
234*b15aabb3Stbbdev     tbb::detail::void_t<decltype(parallel_for_each_operator_selector<Body>::call(std::declval<const Body&>(),
235*b15aabb3Stbbdev                                                                                  std::declval<Item&&>(),
236*b15aabb3Stbbdev                                                                                  std::declval<feeder_impl<Body, Item>*>()))>>
237*b15aabb3Stbbdev {
238*b15aabb3Stbbdev     using type = std::move_iterator<Item*>;
239*b15aabb3Stbbdev };
24049e08aacStbbdev 
24149e08aacStbbdev /** Split one block task to several(max_block_size) iteration tasks for input iterators
24249e08aacStbbdev     @ingroup algorithms **/
24349e08aacStbbdev template <typename Body, typename Item>
24449e08aacStbbdev struct input_block_handling_task : public task {
24549e08aacStbbdev     static constexpr size_t max_block_size = 4;
24649e08aacStbbdev 
24749e08aacStbbdev     using feeder_type = feeder_impl<Body, Item>;
248*b15aabb3Stbbdev     using iteration_task_iterator_type = typename input_iteration_task_iterator_helper<Body, Item>::type;
249*b15aabb3Stbbdev     using iteration_task = for_each_iteration_task<iteration_task_iterator_type, Body, Item>;
25049e08aacStbbdev 
251*b15aabb3Stbbdev     input_block_handling_task(wait_context& root_wait_context, task_group_context& e_context,
252*b15aabb3Stbbdev                               const Body& body, feeder_impl<Body, Item>* feeder_ptr, small_object_allocator& alloc)
253*b15aabb3Stbbdev         :my_size(0), my_wait_context(0), my_root_wait_context(root_wait_context),
254*b15aabb3Stbbdev          my_execution_context(e_context), my_allocator(alloc)
25549e08aacStbbdev     {
256*b15aabb3Stbbdev         auto item_it = block_iteration_space.begin();
25749e08aacStbbdev         for (auto* it = task_pool.begin(); it != task_pool.end(); ++it) {
258*b15aabb3Stbbdev             new (it) iteration_task(iteration_task_iterator_type(item_it++), body, feeder_ptr, my_wait_context);
25949e08aacStbbdev         }
26049e08aacStbbdev     }
26149e08aacStbbdev 
26249e08aacStbbdev     void finalize(const execution_data& ed) {
263*b15aabb3Stbbdev         my_root_wait_context.release();
26449e08aacStbbdev         my_allocator.delete_object(this, ed);
26549e08aacStbbdev     }
26649e08aacStbbdev 
26749e08aacStbbdev     task* execute(execution_data& ed) override {
26849e08aacStbbdev         __TBB_ASSERT( my_size > 0, "Negative size was passed to task");
26949e08aacStbbdev         for (std::size_t counter = 1; counter < my_size; ++counter) {
27049e08aacStbbdev             my_wait_context.reserve();
271*b15aabb3Stbbdev             spawn(*(task_pool.begin() + counter), my_execution_context);
27249e08aacStbbdev         }
27349e08aacStbbdev         my_wait_context.reserve();
274*b15aabb3Stbbdev         execute_and_wait(*task_pool.begin(), my_execution_context,
275*b15aabb3Stbbdev                          my_wait_context,    my_execution_context);
27649e08aacStbbdev 
27749e08aacStbbdev         // deallocate current task after children execution
27849e08aacStbbdev         finalize(ed);
27949e08aacStbbdev         return nullptr;
28049e08aacStbbdev     }
28149e08aacStbbdev 
28249e08aacStbbdev     task* cancel(execution_data& ed) override {
28349e08aacStbbdev         finalize(ed);
28449e08aacStbbdev         return nullptr;
28549e08aacStbbdev     }
28649e08aacStbbdev 
28749e08aacStbbdev     ~input_block_handling_task() {
28849e08aacStbbdev         for(std::size_t counter = 0; counter < max_block_size; ++counter) {
28949e08aacStbbdev             (task_pool.begin() + counter)->~iteration_task();
29049e08aacStbbdev             (block_iteration_space.begin() + counter)->~Item();
29149e08aacStbbdev         }
29249e08aacStbbdev     }
29349e08aacStbbdev 
29449e08aacStbbdev     aligned_space<Item, max_block_size> block_iteration_space;
29549e08aacStbbdev     aligned_space<iteration_task, max_block_size> task_pool;
29649e08aacStbbdev     std::size_t my_size;
29749e08aacStbbdev     wait_context my_wait_context;
298*b15aabb3Stbbdev     wait_context& my_root_wait_context;
299*b15aabb3Stbbdev     task_group_context& my_execution_context;
30049e08aacStbbdev     small_object_allocator my_allocator;
301*b15aabb3Stbbdev }; // class input_block_handling_task
30249e08aacStbbdev 
30349e08aacStbbdev /** Split one block task to several(max_block_size) iteration tasks for forward iterators
30449e08aacStbbdev     @ingroup algorithms **/
30549e08aacStbbdev template <typename Iterator, typename Body, typename Item>
30649e08aacStbbdev struct forward_block_handling_task : public task {
30749e08aacStbbdev     static constexpr size_t max_block_size = 4;
30849e08aacStbbdev 
30949e08aacStbbdev     using iteration_task = for_each_iteration_task<Iterator, Body, Item>;
31049e08aacStbbdev 
311*b15aabb3Stbbdev     forward_block_handling_task(Iterator first, std::size_t size,
312*b15aabb3Stbbdev                                 wait_context& w_context, task_group_context& e_context,
313*b15aabb3Stbbdev                                 const Body& body, feeder_impl<Body, Item>* feeder_ptr,
314*b15aabb3Stbbdev                                 small_object_allocator& alloc)
315*b15aabb3Stbbdev         : my_size(size), my_wait_context(0), my_root_wait_context(w_context),
316*b15aabb3Stbbdev           my_execution_context(e_context), my_allocator(alloc)
31749e08aacStbbdev     {
31849e08aacStbbdev         auto* task_it = task_pool.begin();
31949e08aacStbbdev         for (std::size_t i = 0; i < size; i++) {
320*b15aabb3Stbbdev             new (task_it++) iteration_task(first, body, feeder_ptr, my_wait_context);
32149e08aacStbbdev             ++first;
32249e08aacStbbdev         }
32349e08aacStbbdev     }
32449e08aacStbbdev 
32549e08aacStbbdev     void finalize(const execution_data& ed) {
326*b15aabb3Stbbdev         my_root_wait_context.release();
32749e08aacStbbdev         my_allocator.delete_object(this, ed);
32849e08aacStbbdev     }
32949e08aacStbbdev 
33049e08aacStbbdev     task* execute(execution_data& ed) override {
33149e08aacStbbdev         __TBB_ASSERT( my_size > 0, "Negative size was passed to task");
33249e08aacStbbdev         for(std::size_t counter = 1; counter < my_size; ++counter) {
33349e08aacStbbdev             my_wait_context.reserve();
334*b15aabb3Stbbdev             spawn(*(task_pool.begin() + counter), my_execution_context);
33549e08aacStbbdev         }
33649e08aacStbbdev         my_wait_context.reserve();
337*b15aabb3Stbbdev         execute_and_wait(*task_pool.begin(), my_execution_context,
338*b15aabb3Stbbdev                          my_wait_context,    my_execution_context);
33949e08aacStbbdev 
34049e08aacStbbdev         // deallocate current task after children execution
34149e08aacStbbdev         finalize(ed);
34249e08aacStbbdev         return nullptr;
34349e08aacStbbdev     }
34449e08aacStbbdev 
34549e08aacStbbdev     task* cancel(execution_data& ed) override {
34649e08aacStbbdev         finalize(ed);
34749e08aacStbbdev         return nullptr;
34849e08aacStbbdev     }
34949e08aacStbbdev 
35049e08aacStbbdev     ~forward_block_handling_task() {
35149e08aacStbbdev         for(std::size_t counter = 0; counter < my_size; ++counter) {
35249e08aacStbbdev             (task_pool.begin() + counter)->~iteration_task();
35349e08aacStbbdev         }
35449e08aacStbbdev     }
35549e08aacStbbdev 
35649e08aacStbbdev     aligned_space<iteration_task, max_block_size> task_pool;
35749e08aacStbbdev     std::size_t my_size;
35849e08aacStbbdev     wait_context my_wait_context;
359*b15aabb3Stbbdev     wait_context& my_root_wait_context;
360*b15aabb3Stbbdev     task_group_context& my_execution_context;
36149e08aacStbbdev     small_object_allocator my_allocator;
36249e08aacStbbdev }; // class forward_block_handling_task
36349e08aacStbbdev 
36449e08aacStbbdev /** Body for parallel_for algorithm.
36549e08aacStbbdev   * Allows to redirect operations under random access iterators range to the parallel_for algorithm.
36649e08aacStbbdev     @ingroup algorithms **/
36749e08aacStbbdev template <typename Iterator, typename Body, typename Item>
36849e08aacStbbdev class parallel_for_body_wrapper {
36949e08aacStbbdev     Iterator my_first;
370*b15aabb3Stbbdev     const Body& my_body;
371*b15aabb3Stbbdev     feeder_impl<Body, Item>* my_feeder_ptr;
37249e08aacStbbdev public:
373*b15aabb3Stbbdev     parallel_for_body_wrapper(Iterator first, const Body& body, feeder_impl<Body, Item>* feeder_ptr)
374*b15aabb3Stbbdev         : my_first(first), my_body(body), my_feeder_ptr(feeder_ptr) {}
37549e08aacStbbdev 
37649e08aacStbbdev     void operator()(tbb::blocked_range<std::size_t> range) const {
37749e08aacStbbdev #if __INTEL_COMPILER
37849e08aacStbbdev #pragma ivdep
37949e08aacStbbdev #endif
38049e08aacStbbdev         for (std::size_t count = range.begin(); count != range.end(); count++) {
381*b15aabb3Stbbdev             parallel_for_each_operator_selector<Body>::call(my_body, *(my_first + count),
382*b15aabb3Stbbdev                                                             my_feeder_ptr);
38349e08aacStbbdev         }
38449e08aacStbbdev     }
38549e08aacStbbdev }; // class parallel_for_body_wrapper
38649e08aacStbbdev 
38749e08aacStbbdev 
38849e08aacStbbdev /** Helper for getting iterators tag including inherited custom tags
38949e08aacStbbdev     @ingroup algorithms */
39049e08aacStbbdev template<typename It>
39149e08aacStbbdev using tag = typename std::iterator_traits<It>::iterator_category;
39249e08aacStbbdev 
39349e08aacStbbdev template<typename It>
39449e08aacStbbdev using iterator_tag_dispatch = typename
39549e08aacStbbdev     std::conditional<
39649e08aacStbbdev         std::is_base_of<std::random_access_iterator_tag, tag<It>>::value,
39749e08aacStbbdev         std::random_access_iterator_tag,
39849e08aacStbbdev         typename std::conditional<
39949e08aacStbbdev             std::is_base_of<std::forward_iterator_tag, tag<It>>::value,
40049e08aacStbbdev             std::forward_iterator_tag,
40149e08aacStbbdev             std::input_iterator_tag
40249e08aacStbbdev         >::type
40349e08aacStbbdev     >::type;
40449e08aacStbbdev 
405*b15aabb3Stbbdev template <typename Body, typename Iterator, typename Item>
406*b15aabb3Stbbdev using feeder_is_required = tbb::detail::void_t<decltype(std::declval<const Body>()(std::declval<typename std::iterator_traits<Iterator>::reference>(),
407*b15aabb3Stbbdev                                                                                    std::declval<feeder<Item>&>()))>;
408*b15aabb3Stbbdev 
409*b15aabb3Stbbdev // Creates feeder object only if the body can accept it
410*b15aabb3Stbbdev template <typename Iterator, typename Body, typename Item, typename = void>
411*b15aabb3Stbbdev struct feeder_holder {
412*b15aabb3Stbbdev     feeder_holder( wait_context&, task_group_context&, const Body& ) {}
413*b15aabb3Stbbdev 
414*b15aabb3Stbbdev     feeder_impl<Body, Item>* feeder_ptr() { return nullptr; }
415*b15aabb3Stbbdev }; // class feeder_holder
416*b15aabb3Stbbdev 
417*b15aabb3Stbbdev template <typename Iterator, typename Body, typename Item>
418*b15aabb3Stbbdev class feeder_holder<Iterator, Body, Item, feeder_is_required<Body, Iterator, Item>> {
419*b15aabb3Stbbdev public:
420*b15aabb3Stbbdev     feeder_holder( wait_context& w_context, task_group_context& context, const Body& body )
421*b15aabb3Stbbdev         : my_feeder(body, w_context, context) {}
422*b15aabb3Stbbdev 
423*b15aabb3Stbbdev     feeder_impl<Body, Item>* feeder_ptr() { return &my_feeder; }
424*b15aabb3Stbbdev private:
425*b15aabb3Stbbdev     feeder_impl<Body, Item> my_feeder;
426*b15aabb3Stbbdev }; // class feeder_holder
427*b15aabb3Stbbdev 
428*b15aabb3Stbbdev template <typename Iterator, typename Body, typename Item>
429*b15aabb3Stbbdev class for_each_root_task_base : public task {
430*b15aabb3Stbbdev public:
431*b15aabb3Stbbdev     for_each_root_task_base(Iterator first, Iterator last, const Body& body, wait_context& w_context, task_group_context& e_context)
432*b15aabb3Stbbdev         : my_first(first), my_last(last), my_wait_context(w_context), my_execution_context(e_context),
433*b15aabb3Stbbdev           my_body(body), my_feeder_holder(my_wait_context, my_execution_context, my_body)
434*b15aabb3Stbbdev     {
435*b15aabb3Stbbdev         my_wait_context.reserve();
436*b15aabb3Stbbdev     }
437*b15aabb3Stbbdev private:
438*b15aabb3Stbbdev     task* cancel(execution_data&) override {
439*b15aabb3Stbbdev         this->my_wait_context.release();
440*b15aabb3Stbbdev         return nullptr;
441*b15aabb3Stbbdev     }
442*b15aabb3Stbbdev protected:
443*b15aabb3Stbbdev     Iterator my_first;
444*b15aabb3Stbbdev     Iterator my_last;
445*b15aabb3Stbbdev     wait_context& my_wait_context;
446*b15aabb3Stbbdev     task_group_context& my_execution_context;
447*b15aabb3Stbbdev     const Body& my_body;
448*b15aabb3Stbbdev     feeder_holder<Iterator, Body, Item> my_feeder_holder;
449*b15aabb3Stbbdev }; // class for_each_root_task_base
450*b15aabb3Stbbdev 
45149e08aacStbbdev /** parallel_for_each algorithm root task - most generic version
45249e08aacStbbdev   * Splits input range to blocks
45349e08aacStbbdev     @ingroup algorithms **/
45449e08aacStbbdev template <typename Iterator, typename Body, typename Item, typename IteratorTag = iterator_tag_dispatch<Iterator>>
455*b15aabb3Stbbdev class for_each_root_task : public for_each_root_task_base<Iterator, Body, Item>
45649e08aacStbbdev {
457*b15aabb3Stbbdev     using base_type = for_each_root_task_base<Iterator, Body, Item>;
458*b15aabb3Stbbdev public:
459*b15aabb3Stbbdev     using base_type::base_type;
46049e08aacStbbdev private:
46149e08aacStbbdev     task* execute(execution_data& ed) override {
46249e08aacStbbdev         using block_handling_type = input_block_handling_task<Body, Item>;
46349e08aacStbbdev 
464*b15aabb3Stbbdev         if (this->my_first == this->my_last) {
465*b15aabb3Stbbdev             this->my_wait_context.release();
46649e08aacStbbdev             return nullptr;
46749e08aacStbbdev         }
46849e08aacStbbdev 
469*b15aabb3Stbbdev         this->my_wait_context.reserve();
47049e08aacStbbdev         small_object_allocator alloc{};
471*b15aabb3Stbbdev         auto block_handling_task = alloc.new_object<block_handling_type>(ed, this->my_wait_context, this->my_execution_context,
472*b15aabb3Stbbdev                                                                          this->my_body, this->my_feeder_holder.feeder_ptr(),
473*b15aabb3Stbbdev                                                                          alloc);
47449e08aacStbbdev 
47549e08aacStbbdev         auto* block_iterator = block_handling_task->block_iteration_space.begin();
476*b15aabb3Stbbdev         for (; !(this->my_first == this->my_last) && block_handling_task->my_size < block_handling_type::max_block_size; ++this->my_first) {
47749e08aacStbbdev             // Move semantics are automatically used when supported by the iterator
478*b15aabb3Stbbdev             new (block_iterator++) Item(*this->my_first);
47949e08aacStbbdev             ++block_handling_task->my_size;
48049e08aacStbbdev         }
48149e08aacStbbdev 
48249e08aacStbbdev         // Do not access this after spawn to avoid races
483*b15aabb3Stbbdev         spawn(*this, this->my_execution_context);
48449e08aacStbbdev         return block_handling_task;
48549e08aacStbbdev     }
48649e08aacStbbdev }; // class for_each_root_task - most generic implementation
48749e08aacStbbdev 
48849e08aacStbbdev /** parallel_for_each algorithm root task - forward iterator based specialization
48949e08aacStbbdev   * Splits input range to blocks
49049e08aacStbbdev     @ingroup algorithms **/
49149e08aacStbbdev template <typename Iterator, typename Body, typename Item>
492*b15aabb3Stbbdev class for_each_root_task<Iterator, Body, Item, std::forward_iterator_tag>
493*b15aabb3Stbbdev     : public for_each_root_task_base<Iterator, Body, Item>
49449e08aacStbbdev {
495*b15aabb3Stbbdev     using base_type = for_each_root_task_base<Iterator, Body, Item>;
496*b15aabb3Stbbdev public:
497*b15aabb3Stbbdev     using base_type::base_type;
49849e08aacStbbdev private:
49949e08aacStbbdev     task* execute(execution_data& ed) override {
50049e08aacStbbdev         using block_handling_type = forward_block_handling_task<Iterator, Body, Item>;
501*b15aabb3Stbbdev         if (this->my_first == this->my_last) {
502*b15aabb3Stbbdev             this->my_wait_context.release();
50349e08aacStbbdev             return nullptr;
50449e08aacStbbdev         }
50549e08aacStbbdev 
50649e08aacStbbdev         std::size_t block_size{0};
507*b15aabb3Stbbdev         Iterator first_block_element = this->my_first;
508*b15aabb3Stbbdev         for (; !(this->my_first == this->my_last) && block_size < block_handling_type::max_block_size; ++this->my_first) {
50949e08aacStbbdev             ++block_size;
51049e08aacStbbdev         }
51149e08aacStbbdev 
512*b15aabb3Stbbdev         this->my_wait_context.reserve();
51349e08aacStbbdev         small_object_allocator alloc{};
514*b15aabb3Stbbdev         auto block_handling_task = alloc.new_object<block_handling_type>(ed, first_block_element, block_size,
515*b15aabb3Stbbdev                                                                          this->my_wait_context, this->my_execution_context,
516*b15aabb3Stbbdev                                                                          this->my_body, this->my_feeder_holder.feeder_ptr(), alloc);
51749e08aacStbbdev 
51849e08aacStbbdev         // Do not access this after spawn to avoid races
519*b15aabb3Stbbdev         spawn(*this, this->my_execution_context);
52049e08aacStbbdev         return block_handling_task;
52149e08aacStbbdev     }
52249e08aacStbbdev }; // class for_each_root_task - forward iterator based specialization
52349e08aacStbbdev 
52449e08aacStbbdev /** parallel_for_each algorithm root task - random access iterator based specialization
52549e08aacStbbdev   * Splits input range to blocks
52649e08aacStbbdev     @ingroup algorithms **/
52749e08aacStbbdev template <typename Iterator, typename Body, typename Item>
528*b15aabb3Stbbdev class for_each_root_task<Iterator, Body, Item, std::random_access_iterator_tag>
529*b15aabb3Stbbdev     : public for_each_root_task_base<Iterator, Body, Item>
53049e08aacStbbdev {
531*b15aabb3Stbbdev     using base_type = for_each_root_task_base<Iterator, Body, Item>;
532*b15aabb3Stbbdev public:
533*b15aabb3Stbbdev     using base_type::base_type;
53449e08aacStbbdev private:
53549e08aacStbbdev     task* execute(execution_data&) override {
53649e08aacStbbdev         tbb::parallel_for(
537*b15aabb3Stbbdev             tbb::blocked_range<std::size_t>(0, std::distance(this->my_first, this->my_last)),
538*b15aabb3Stbbdev             parallel_for_body_wrapper<Iterator, Body, Item>(this->my_first, this->my_body, this->my_feeder_holder.feeder_ptr())
539*b15aabb3Stbbdev             , this->my_execution_context
54049e08aacStbbdev         );
54149e08aacStbbdev 
542*b15aabb3Stbbdev         this->my_wait_context.release();
54349e08aacStbbdev         return nullptr;
54449e08aacStbbdev     }
54549e08aacStbbdev }; // class for_each_root_task - random access iterator based specialization
54649e08aacStbbdev 
54749e08aacStbbdev /** Helper for getting item type. If item type can be deduced from feeder - got it from feeder,
54849e08aacStbbdev     if feeder is generic - got item type from range.
54949e08aacStbbdev     @ingroup algorithms */
55049e08aacStbbdev template<typename Body, typename Item, typename FeederArg>
55149e08aacStbbdev auto feeder_argument_parser(void (Body::*)(Item, feeder<FeederArg>&) const) -> FeederArg;
55249e08aacStbbdev 
55349e08aacStbbdev template<typename Body, typename>
55449e08aacStbbdev decltype(feeder_argument_parser<Body>(&Body::operator())) get_item_type_impl(int); // for (T, feeder<T>)
55549e08aacStbbdev template<typename Body, typename Item> Item get_item_type_impl(...); // stub
55649e08aacStbbdev 
55749e08aacStbbdev template <typename Body, typename Item>
55849e08aacStbbdev using get_item_type = decltype(get_item_type_impl<Body, Item>(0));
55949e08aacStbbdev 
56049e08aacStbbdev /** Implements parallel iteration over a range.
56149e08aacStbbdev     @ingroup algorithms */
56249e08aacStbbdev template<typename Iterator, typename Body>
56349e08aacStbbdev void run_parallel_for_each( Iterator first, Iterator last, const Body& body, task_group_context& context)
56449e08aacStbbdev {
56549e08aacStbbdev     if (!(first == last)) {
566*b15aabb3Stbbdev         using ItemType = get_item_type<Body, typename std::iterator_traits<Iterator>::value_type>;
567*b15aabb3Stbbdev         wait_context w_context(0);
56849e08aacStbbdev 
569*b15aabb3Stbbdev         for_each_root_task<Iterator, Body, ItemType> root_task(first, last, body, w_context, context);
57049e08aacStbbdev 
571*b15aabb3Stbbdev         execute_and_wait(root_task, context, w_context, context);
57249e08aacStbbdev     }
57349e08aacStbbdev }
57449e08aacStbbdev 
57549e08aacStbbdev /** \page parallel_for_each_body_req Requirements on parallel_for_each body
57649e08aacStbbdev     Class \c Body implementing the concept of parallel_for_each body must define:
57749e08aacStbbdev     - \code
57849e08aacStbbdev         B::operator()(
57949e08aacStbbdev                 cv_item_type item,
58049e08aacStbbdev                 feeder<item_type>& feeder
58149e08aacStbbdev         ) const
58249e08aacStbbdev 
58349e08aacStbbdev         OR
58449e08aacStbbdev 
58549e08aacStbbdev         B::operator()( cv_item_type& item ) const
58649e08aacStbbdev       \endcode                                               Process item.
58749e08aacStbbdev                                                              May be invoked concurrently  for the same \c this but different \c item.
58849e08aacStbbdev 
58949e08aacStbbdev     - \code item_type( const item_type& ) \endcode
59049e08aacStbbdev                                                              Copy a work item.
59149e08aacStbbdev     - \code ~item_type() \endcode                            Destroy a work item
59249e08aacStbbdev **/
59349e08aacStbbdev 
59449e08aacStbbdev /** \name parallel_for_each
59549e08aacStbbdev     See also requirements on \ref parallel_for_each_body_req "parallel_for_each Body". **/
59649e08aacStbbdev //@{
59749e08aacStbbdev //! Parallel iteration over a range, with optional addition of more work.
59849e08aacStbbdev /** @ingroup algorithms */
59949e08aacStbbdev template<typename Iterator, typename Body>
60049e08aacStbbdev void parallel_for_each(Iterator first, Iterator last, const Body& body) {
60149e08aacStbbdev     task_group_context context(PARALLEL_FOR_EACH);
60249e08aacStbbdev     run_parallel_for_each<Iterator, Body>(first, last, body, context);
60349e08aacStbbdev }
60449e08aacStbbdev 
60549e08aacStbbdev template<typename Range, typename Body>
60649e08aacStbbdev void parallel_for_each(Range& rng, const Body& body) {
60749e08aacStbbdev     parallel_for_each(std::begin(rng), std::end(rng), body);
60849e08aacStbbdev }
60949e08aacStbbdev 
61049e08aacStbbdev template<typename Range, typename Body>
61149e08aacStbbdev void parallel_for_each(const Range& rng, const Body& body) {
61249e08aacStbbdev     parallel_for_each(std::begin(rng), std::end(rng), body);
61349e08aacStbbdev }
61449e08aacStbbdev 
61549e08aacStbbdev //! Parallel iteration over a range, with optional addition of more work and user-supplied context
61649e08aacStbbdev /** @ingroup algorithms */
61749e08aacStbbdev template<typename Iterator, typename Body>
61849e08aacStbbdev void parallel_for_each(Iterator first, Iterator last, const Body& body, task_group_context& context) {
61949e08aacStbbdev     run_parallel_for_each<Iterator, Body>(first, last, body, context);
62049e08aacStbbdev }
62149e08aacStbbdev 
62249e08aacStbbdev template<typename Range, typename Body>
62349e08aacStbbdev void parallel_for_each(Range& rng, const Body& body, task_group_context& context) {
62449e08aacStbbdev     parallel_for_each(std::begin(rng), std::end(rng), body, context);
62549e08aacStbbdev }
62649e08aacStbbdev 
62749e08aacStbbdev template<typename Range, typename Body>
62849e08aacStbbdev void parallel_for_each(const Range& rng, const Body& body, task_group_context& context) {
62949e08aacStbbdev     parallel_for_each(std::begin(rng), std::end(rng), body, context);
63049e08aacStbbdev }
63149e08aacStbbdev 
632*b15aabb3Stbbdev } // namespace d2
63349e08aacStbbdev } // namespace detail
63449e08aacStbbdev //! @endcond
63549e08aacStbbdev //@}
63649e08aacStbbdev 
63749e08aacStbbdev inline namespace v1 {
638*b15aabb3Stbbdev using detail::d2::parallel_for_each;
63949e08aacStbbdev using detail::d1::feeder;
64049e08aacStbbdev } // namespace v1
64149e08aacStbbdev 
64249e08aacStbbdev } // namespace tbb
64349e08aacStbbdev 
64449e08aacStbbdev #endif /* __TBB_parallel_for_each_H */
645