xref: /oneTBB/include/oneapi/tbb/parallel_reduce.h (revision a088cfa0)
149e08aacStbbdev /*
20cf592bdSAndrew Corrigan     Copyright (c) 2005-2023 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_reduce_H
1849e08aacStbbdev #define __TBB_parallel_reduce_H
1949e08aacStbbdev 
2049e08aacStbbdev #include <new>
2149e08aacStbbdev #include "detail/_namespace_injection.h"
2249e08aacStbbdev #include "detail/_task.h"
2349e08aacStbbdev #include "detail/_aligned_space.h"
2449e08aacStbbdev #include "detail/_small_object_pool.h"
25478de5b1Stbbdev #include "detail/_range_common.h"
2649e08aacStbbdev 
2749e08aacStbbdev #include "task_group.h" // task_group_context
2849e08aacStbbdev #include "partitioner.h"
2949e08aacStbbdev #include "profiling.h"
3049e08aacStbbdev 
3149e08aacStbbdev namespace tbb {
3249e08aacStbbdev namespace detail {
33478de5b1Stbbdev #if __TBB_CPP20_CONCEPTS_PRESENT
34478de5b1Stbbdev inline namespace d0 {
35478de5b1Stbbdev 
36478de5b1Stbbdev template <typename Body, typename Range>
37478de5b1Stbbdev concept parallel_reduce_body = splittable<Body> &&
requires(Body & body,const Range & range,Body & rhs)38478de5b1Stbbdev                                requires( Body& body, const Range& range, Body& rhs ) {
39478de5b1Stbbdev                                    body(range);
40478de5b1Stbbdev                                    body.join(rhs);
41478de5b1Stbbdev                                };
42478de5b1Stbbdev 
43478de5b1Stbbdev template <typename Function, typename Range, typename Value>
44*a088cfa0SKonstantin Boyarinov concept parallel_reduce_function = std::invocable<const std::remove_reference_t<Function>&,
45*a088cfa0SKonstantin Boyarinov                                                   const Range&, const Value&> &&
46*a088cfa0SKonstantin Boyarinov                                    std::convertible_to<std::invoke_result_t<const std::remove_reference_t<Function>&,
47*a088cfa0SKonstantin Boyarinov                                                                             const Range&, const Value&>,
48*a088cfa0SKonstantin Boyarinov                                                         Value>;
49478de5b1Stbbdev 
50478de5b1Stbbdev template <typename Combine, typename Value>
51*a088cfa0SKonstantin Boyarinov concept parallel_reduce_combine = std::invocable<const std::remove_reference_t<Combine>&,
52*a088cfa0SKonstantin Boyarinov                                                  const Value&, const Value&> &&
53*a088cfa0SKonstantin Boyarinov                                   std::convertible_to<std::invoke_result_t<const std::remove_reference_t<Combine>&,
54*a088cfa0SKonstantin Boyarinov                                                                            const Value&, const Value&>,
55*a088cfa0SKonstantin Boyarinov                                                       Value>;
56478de5b1Stbbdev 
57478de5b1Stbbdev } // namespace d0
58478de5b1Stbbdev #endif // __TBB_CPP20_CONCEPTS_PRESENT
5949e08aacStbbdev namespace d1 {
6049e08aacStbbdev 
6149e08aacStbbdev //! Tree node type for parallel_reduce.
6249e08aacStbbdev /** @ingroup algorithms */
6349e08aacStbbdev //TODO: consider folding tree via bypass execution(instead of manual folding)
6449e08aacStbbdev // for better cancellation and critical tasks handling (performance measurements required).
6549e08aacStbbdev template<typename Body>
6649e08aacStbbdev struct reduction_tree_node : public tree_node {
6749e08aacStbbdev     tbb::detail::aligned_space<Body> zombie_space;
6849e08aacStbbdev     Body& left_body;
6949e08aacStbbdev     bool has_right_zombie{false};
7049e08aacStbbdev 
reduction_tree_nodereduction_tree_node7149e08aacStbbdev     reduction_tree_node(node* parent, int ref_count, Body& input_left_body, small_object_allocator& alloc) :
7249e08aacStbbdev         tree_node{parent, ref_count, alloc},
7349e08aacStbbdev         left_body(input_left_body) /* gcc4.8 bug - braced-initialization doesn't work for class members of reference type */
7449e08aacStbbdev     {}
7549e08aacStbbdev 
joinreduction_tree_node7649e08aacStbbdev     void join(task_group_context* context) {
7749e08aacStbbdev         if (has_right_zombie && !context->is_group_execution_cancelled())
7849e08aacStbbdev             left_body.join(*zombie_space.begin());
7949e08aacStbbdev     }
8049e08aacStbbdev 
~reduction_tree_nodereduction_tree_node8149e08aacStbbdev     ~reduction_tree_node() {
8249e08aacStbbdev         if( has_right_zombie ) zombie_space.begin()->~Body();
8349e08aacStbbdev     }
8449e08aacStbbdev };
8549e08aacStbbdev 
8649e08aacStbbdev //! Task type used to split the work of parallel_reduce.
8749e08aacStbbdev /** @ingroup algorithms */
8849e08aacStbbdev template<typename Range, typename Body, typename Partitioner>
8949e08aacStbbdev struct start_reduce : public task {
9049e08aacStbbdev     Range my_range;
9149e08aacStbbdev     Body* my_body;
9249e08aacStbbdev     node* my_parent;
9349e08aacStbbdev 
9449e08aacStbbdev     typename Partitioner::task_partition_type my_partition;
9549e08aacStbbdev     small_object_allocator my_allocator;
9649e08aacStbbdev     bool is_right_child;
9749e08aacStbbdev 
9849e08aacStbbdev     task* execute(execution_data&) override;
9949e08aacStbbdev     task* cancel(execution_data&) override;
10049e08aacStbbdev     void finalize(const execution_data&);
10149e08aacStbbdev 
10249e08aacStbbdev     using tree_node_type = reduction_tree_node<Body>;
10349e08aacStbbdev 
10449e08aacStbbdev     //! Constructor reduce root task.
start_reducestart_reduce10549e08aacStbbdev     start_reduce( const Range& range, Body& body, Partitioner& partitioner, small_object_allocator& alloc ) :
10649e08aacStbbdev         my_range(range),
10749e08aacStbbdev         my_body(&body),
108f2af7473Skboyarinov         my_parent(nullptr),
10949e08aacStbbdev         my_partition(partitioner),
11049e08aacStbbdev         my_allocator(alloc),
11149e08aacStbbdev         is_right_child(false) {}
11249e08aacStbbdev     //! Splitting constructor used to generate children.
11349e08aacStbbdev     /** parent_ becomes left child. Newly constructed object is right child. */
start_reducestart_reduce11449e08aacStbbdev     start_reduce( start_reduce& parent_, typename Partitioner::split_type& split_obj, small_object_allocator& alloc ) :
11549e08aacStbbdev         my_range(parent_.my_range, get_range_split_object<Range>(split_obj)),
11649e08aacStbbdev         my_body(parent_.my_body),
117f2af7473Skboyarinov         my_parent(nullptr),
11849e08aacStbbdev         my_partition(parent_.my_partition, split_obj),
11949e08aacStbbdev         my_allocator(alloc),
12049e08aacStbbdev         is_right_child(true)
12149e08aacStbbdev     {
12249e08aacStbbdev         parent_.is_right_child = false;
12349e08aacStbbdev     }
12449e08aacStbbdev     //! Construct right child from the given range as response to the demand.
12549e08aacStbbdev     /** parent_ remains left child. Newly constructed object is right child. */
start_reducestart_reduce12649e08aacStbbdev     start_reduce( start_reduce& parent_, const Range& r, depth_t d, small_object_allocator& alloc ) :
12749e08aacStbbdev         my_range(r),
12849e08aacStbbdev         my_body(parent_.my_body),
129f2af7473Skboyarinov         my_parent(nullptr),
13049e08aacStbbdev         my_partition(parent_.my_partition, split()),
13149e08aacStbbdev         my_allocator(alloc),
13249e08aacStbbdev         is_right_child(true)
13349e08aacStbbdev     {
13449e08aacStbbdev         my_partition.align_depth( d );
13549e08aacStbbdev         parent_.is_right_child = false;
13649e08aacStbbdev     }
runstart_reduce13749e08aacStbbdev     static void run(const Range& range, Body& body, Partitioner& partitioner, task_group_context& context) {
13849e08aacStbbdev         if ( !range.empty() ) {
13949e08aacStbbdev             wait_node wn;
14049e08aacStbbdev             small_object_allocator alloc{};
14149e08aacStbbdev             auto reduce_task = alloc.new_object<start_reduce>(range, body, partitioner, alloc);
14249e08aacStbbdev             reduce_task->my_parent = &wn;
14349e08aacStbbdev             execute_and_wait(*reduce_task, context, wn.m_wait, context);
14449e08aacStbbdev         }
14549e08aacStbbdev     }
runstart_reduce14649e08aacStbbdev     static void run(const Range& range, Body& body, Partitioner& partitioner) {
14749e08aacStbbdev         // Bound context prevents exceptions from body to affect nesting or sibling algorithms,
14849e08aacStbbdev         // and allows users to handle exceptions safely by wrapping parallel_reduce in the try-block.
14949e08aacStbbdev         task_group_context context(PARALLEL_REDUCE);
15049e08aacStbbdev         run(range, body, partitioner, context);
15149e08aacStbbdev     }
15249e08aacStbbdev     //! Run body for range, serves as callback for partitioner
run_bodystart_reduce15349e08aacStbbdev     void run_body( Range &r ) {
154*a088cfa0SKonstantin Boyarinov         tbb::detail::invoke(*my_body, r);
15549e08aacStbbdev     }
15649e08aacStbbdev 
15749e08aacStbbdev     //! spawn right task, serves as callback for partitioner
offer_workstart_reduce15849e08aacStbbdev     void offer_work(typename Partitioner::split_type& split_obj, execution_data& ed) {
15949e08aacStbbdev         offer_work_impl(ed, *this, split_obj);
16049e08aacStbbdev     }
16149e08aacStbbdev     //! spawn right task, serves as callback for partitioner
offer_workstart_reduce16249e08aacStbbdev     void offer_work(const Range& r, depth_t d, execution_data& ed) {
16349e08aacStbbdev         offer_work_impl(ed, *this, r, d);
16449e08aacStbbdev     }
16549e08aacStbbdev 
16649e08aacStbbdev private:
16749e08aacStbbdev     template <typename... Args>
offer_work_implstart_reduce16849e08aacStbbdev     void offer_work_impl(execution_data& ed, Args&&... args) {
16949e08aacStbbdev         small_object_allocator alloc{};
17049e08aacStbbdev         // New right child
17149e08aacStbbdev         auto right_child = alloc.new_object<start_reduce>(ed, std::forward<Args>(args)..., alloc);
17249e08aacStbbdev 
17349e08aacStbbdev         // New root node as a continuation and ref count. Left and right child attach to the new parent.
17449e08aacStbbdev         right_child->my_parent = my_parent = alloc.new_object<tree_node_type>(ed, my_parent, 2, *my_body, alloc);
17549e08aacStbbdev 
17649e08aacStbbdev         // Spawn the right sibling
17749e08aacStbbdev         right_child->spawn_self(ed);
17849e08aacStbbdev     }
17949e08aacStbbdev 
spawn_selfstart_reduce18049e08aacStbbdev     void spawn_self(execution_data& ed) {
18149e08aacStbbdev         my_partition.spawn_task(*this, *context(ed));
18249e08aacStbbdev     }
18349e08aacStbbdev };
18449e08aacStbbdev 
18549e08aacStbbdev //! fold the tree and deallocate the task
18649e08aacStbbdev template<typename Range, typename Body, typename Partitioner>
finalize(const execution_data & ed)18749e08aacStbbdev void start_reduce<Range, Body, Partitioner>::finalize(const execution_data& ed) {
18849e08aacStbbdev     // Get the current parent and wait object before an object destruction
18949e08aacStbbdev     node* parent = my_parent;
19049e08aacStbbdev     auto allocator = my_allocator;
19149e08aacStbbdev     // Task execution finished - destroy it
19249e08aacStbbdev     this->~start_reduce();
19349e08aacStbbdev     // Unwind the tree decrementing the parent`s reference count
19449e08aacStbbdev     fold_tree<tree_node_type>(parent, ed);
19549e08aacStbbdev     allocator.deallocate(this, ed);
19649e08aacStbbdev }
19749e08aacStbbdev 
19849e08aacStbbdev //! Execute parallel_reduce task
19949e08aacStbbdev template<typename Range, typename Body, typename Partitioner>
execute(execution_data & ed)20049e08aacStbbdev task* start_reduce<Range,Body,Partitioner>::execute(execution_data& ed) {
20149e08aacStbbdev     if (!is_same_affinity(ed)) {
20249e08aacStbbdev         my_partition.note_affinity(execution_slot(ed));
20349e08aacStbbdev     }
20449e08aacStbbdev     my_partition.check_being_stolen(*this, ed);
20549e08aacStbbdev 
206d86ed7fbStbbdev     // The acquire barrier synchronizes the data pointed with my_body if the left
207d86ed7fbStbbdev     // task has already finished.
208f2af7473Skboyarinov     __TBB_ASSERT(my_parent, nullptr);
209d86ed7fbStbbdev     if( is_right_child && my_parent->m_ref_count.load(std::memory_order_acquire) == 2 ) {
21049e08aacStbbdev         tree_node_type* parent_ptr = static_cast<tree_node_type*>(my_parent);
2110cf592bdSAndrew Corrigan         my_body = static_cast<Body*>(new( parent_ptr->zombie_space.begin() ) Body(*my_body, split()));
21249e08aacStbbdev         parent_ptr->has_right_zombie = true;
21349e08aacStbbdev     }
21449e08aacStbbdev     __TBB_ASSERT(my_body != nullptr, "Incorrect body value");
21549e08aacStbbdev 
21649e08aacStbbdev     my_partition.execute(*this, my_range, ed);
21749e08aacStbbdev 
21849e08aacStbbdev     finalize(ed);
21949e08aacStbbdev     return nullptr;
22049e08aacStbbdev }
22149e08aacStbbdev 
22249e08aacStbbdev //! Cancel parallel_reduce task
22349e08aacStbbdev template<typename Range, typename Body, typename Partitioner>
cancel(execution_data & ed)22449e08aacStbbdev task* start_reduce<Range, Body, Partitioner>::cancel(execution_data& ed) {
22549e08aacStbbdev     finalize(ed);
22649e08aacStbbdev     return nullptr;
22749e08aacStbbdev }
22849e08aacStbbdev 
22949e08aacStbbdev //! Tree node type for parallel_deterministic_reduce.
23049e08aacStbbdev /** @ingroup algorithms */
23149e08aacStbbdev template<typename Body>
23249e08aacStbbdev struct deterministic_reduction_tree_node : public tree_node {
23349e08aacStbbdev     Body right_body;
23449e08aacStbbdev     Body& left_body;
23549e08aacStbbdev 
deterministic_reduction_tree_nodedeterministic_reduction_tree_node23649e08aacStbbdev     deterministic_reduction_tree_node(node* parent, int ref_count, Body& input_left_body, small_object_allocator& alloc) :
23749e08aacStbbdev         tree_node{parent, ref_count, alloc},
23849e08aacStbbdev         right_body{input_left_body, detail::split()},
23949e08aacStbbdev         left_body(input_left_body)
24049e08aacStbbdev     {}
24149e08aacStbbdev 
joindeterministic_reduction_tree_node24249e08aacStbbdev     void join(task_group_context* context) {
24349e08aacStbbdev         if (!context->is_group_execution_cancelled())
24449e08aacStbbdev             left_body.join(right_body);
24549e08aacStbbdev     }
24649e08aacStbbdev };
24749e08aacStbbdev 
24849e08aacStbbdev //! Task type used to split the work of parallel_deterministic_reduce.
24949e08aacStbbdev /** @ingroup algorithms */
25049e08aacStbbdev template<typename Range, typename Body, typename Partitioner>
25149e08aacStbbdev struct start_deterministic_reduce : public task {
25249e08aacStbbdev     Range my_range;
25349e08aacStbbdev     Body& my_body;
25449e08aacStbbdev     node* my_parent;
25549e08aacStbbdev 
25649e08aacStbbdev     typename Partitioner::task_partition_type my_partition;
25749e08aacStbbdev     small_object_allocator my_allocator;
25849e08aacStbbdev 
25949e08aacStbbdev     task* execute(execution_data&) override;
26049e08aacStbbdev     task* cancel(execution_data&) override;
26149e08aacStbbdev     void finalize(const execution_data&);
26249e08aacStbbdev 
26349e08aacStbbdev     using tree_node_type = deterministic_reduction_tree_node<Body>;
26449e08aacStbbdev 
26549e08aacStbbdev     //! Constructor deterministic_reduce root task.
start_deterministic_reducestart_deterministic_reduce26649e08aacStbbdev     start_deterministic_reduce( const Range& range, Partitioner& partitioner, Body& body, small_object_allocator& alloc ) :
26749e08aacStbbdev         my_range(range),
26849e08aacStbbdev         my_body(body),
269f2af7473Skboyarinov         my_parent(nullptr),
27049e08aacStbbdev         my_partition(partitioner),
27149e08aacStbbdev         my_allocator(alloc) {}
27249e08aacStbbdev     //! Splitting constructor used to generate children.
27349e08aacStbbdev     /** parent_ becomes left child.  Newly constructed object is right child. */
start_deterministic_reducestart_deterministic_reduce27449e08aacStbbdev     start_deterministic_reduce( start_deterministic_reduce& parent_, typename Partitioner::split_type& split_obj, Body& body,
27549e08aacStbbdev                                 small_object_allocator& alloc ) :
27649e08aacStbbdev         my_range(parent_.my_range, get_range_split_object<Range>(split_obj)),
27749e08aacStbbdev         my_body(body),
278f2af7473Skboyarinov         my_parent(nullptr),
27949e08aacStbbdev         my_partition(parent_.my_partition, split_obj),
28049e08aacStbbdev         my_allocator(alloc) {}
runstart_deterministic_reduce28149e08aacStbbdev     static void run(const Range& range, Body& body, Partitioner& partitioner, task_group_context& context) {
28249e08aacStbbdev         if ( !range.empty() ) {
28349e08aacStbbdev             wait_node wn;
28449e08aacStbbdev             small_object_allocator alloc{};
28549e08aacStbbdev             auto deterministic_reduce_task =
28649e08aacStbbdev                 alloc.new_object<start_deterministic_reduce>(range, partitioner, body, alloc);
28749e08aacStbbdev             deterministic_reduce_task->my_parent = &wn;
28849e08aacStbbdev             execute_and_wait(*deterministic_reduce_task, context, wn.m_wait, context);
28949e08aacStbbdev         }
29049e08aacStbbdev     }
runstart_deterministic_reduce29149e08aacStbbdev     static void run(const Range& range, Body& body, Partitioner& partitioner) {
29249e08aacStbbdev         // Bound context prevents exceptions from body to affect nesting or sibling algorithms,
29349e08aacStbbdev         // and allows users to handle exceptions safely by wrapping parallel_deterministic_reduce
29449e08aacStbbdev         // in the try-block.
29549e08aacStbbdev         task_group_context context(PARALLEL_REDUCE);
29649e08aacStbbdev         run(range, body, partitioner, context);
29749e08aacStbbdev     }
29849e08aacStbbdev     //! Run body for range, serves as callback for partitioner
run_bodystart_deterministic_reduce29949e08aacStbbdev     void run_body( Range &r ) {
300*a088cfa0SKonstantin Boyarinov         tbb::detail::invoke(my_body, r);
30149e08aacStbbdev     }
30249e08aacStbbdev     //! Spawn right task, serves as callback for partitioner
offer_workstart_deterministic_reduce30349e08aacStbbdev     void offer_work(typename Partitioner::split_type& split_obj, execution_data& ed) {
30449e08aacStbbdev         offer_work_impl(ed, *this, split_obj);
30549e08aacStbbdev     }
30649e08aacStbbdev private:
30749e08aacStbbdev     template <typename... Args>
offer_work_implstart_deterministic_reduce30849e08aacStbbdev     void offer_work_impl(execution_data& ed, Args&&... args) {
30949e08aacStbbdev         small_object_allocator alloc{};
31049e08aacStbbdev         // New root node as a continuation and ref count. Left and right child attach to the new parent. Split the body.
31149e08aacStbbdev         auto new_tree_node = alloc.new_object<tree_node_type>(ed, my_parent, 2, my_body, alloc);
31249e08aacStbbdev 
31349e08aacStbbdev         // New right child
31449e08aacStbbdev         auto right_child = alloc.new_object<start_deterministic_reduce>(ed, std::forward<Args>(args)..., new_tree_node->right_body, alloc);
31549e08aacStbbdev 
31649e08aacStbbdev         right_child->my_parent = my_parent = new_tree_node;
31749e08aacStbbdev 
31849e08aacStbbdev         // Spawn the right sibling
31949e08aacStbbdev         right_child->spawn_self(ed);
32049e08aacStbbdev     }
32149e08aacStbbdev 
spawn_selfstart_deterministic_reduce32249e08aacStbbdev     void spawn_self(execution_data& ed) {
32349e08aacStbbdev         my_partition.spawn_task(*this, *context(ed));
32449e08aacStbbdev     }
32549e08aacStbbdev };
32649e08aacStbbdev 
32749e08aacStbbdev //! Fold the tree and deallocate the task
32849e08aacStbbdev template<typename Range, typename Body, typename Partitioner>
finalize(const execution_data & ed)32949e08aacStbbdev void start_deterministic_reduce<Range, Body, Partitioner>::finalize(const execution_data& ed) {
33049e08aacStbbdev     // Get the current parent and wait object before an object destruction
33149e08aacStbbdev     node* parent = my_parent;
33249e08aacStbbdev 
33349e08aacStbbdev     auto allocator = my_allocator;
33449e08aacStbbdev     // Task execution finished - destroy it
33549e08aacStbbdev     this->~start_deterministic_reduce();
33649e08aacStbbdev     // Unwind the tree decrementing the parent`s reference count
33749e08aacStbbdev     fold_tree<tree_node_type>(parent, ed);
33849e08aacStbbdev     allocator.deallocate(this, ed);
33949e08aacStbbdev }
34049e08aacStbbdev 
34149e08aacStbbdev //! Execute parallel_deterministic_reduce task
34249e08aacStbbdev template<typename Range, typename Body, typename Partitioner>
execute(execution_data & ed)34349e08aacStbbdev task* start_deterministic_reduce<Range,Body,Partitioner>::execute(execution_data& ed) {
34449e08aacStbbdev     if (!is_same_affinity(ed)) {
34549e08aacStbbdev         my_partition.note_affinity(execution_slot(ed));
34649e08aacStbbdev     }
34749e08aacStbbdev     my_partition.check_being_stolen(*this, ed);
34849e08aacStbbdev 
34949e08aacStbbdev     my_partition.execute(*this, my_range, ed);
35049e08aacStbbdev 
35149e08aacStbbdev     finalize(ed);
35257f524caSIlya Isaev     return nullptr;
35349e08aacStbbdev }
35449e08aacStbbdev 
35549e08aacStbbdev //! Cancel parallel_deterministic_reduce task
35649e08aacStbbdev template<typename Range, typename Body, typename Partitioner>
cancel(execution_data & ed)35749e08aacStbbdev task* start_deterministic_reduce<Range, Body, Partitioner>::cancel(execution_data& ed) {
35849e08aacStbbdev     finalize(ed);
35957f524caSIlya Isaev     return nullptr;
36049e08aacStbbdev }
36149e08aacStbbdev 
36249e08aacStbbdev 
36349e08aacStbbdev //! Auxiliary class for parallel_reduce; for internal use only.
36449e08aacStbbdev /** The adaptor class that implements \ref parallel_reduce_body_req "parallel_reduce Body"
36549e08aacStbbdev     using given \ref parallel_reduce_lambda_req "anonymous function objects".
36649e08aacStbbdev  **/
36749e08aacStbbdev /** @ingroup algorithms */
36849e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
36949e08aacStbbdev class lambda_reduce_body {
37049e08aacStbbdev //TODO: decide if my_real_body, my_reduction, and my_identity_element should be copied or referenced
37149e08aacStbbdev //       (might require some performance measurements)
37249e08aacStbbdev 
37349e08aacStbbdev     const Value&     my_identity_element;
37449e08aacStbbdev     const RealBody&  my_real_body;
37549e08aacStbbdev     const Reduction& my_reduction;
37649e08aacStbbdev     Value            my_value;
37749e08aacStbbdev     lambda_reduce_body& operator= ( const lambda_reduce_body& other );
37849e08aacStbbdev public:
lambda_reduce_body(const Value & identity,const RealBody & body,const Reduction & reduction)37949e08aacStbbdev     lambda_reduce_body( const Value& identity, const RealBody& body, const Reduction& reduction )
38049e08aacStbbdev         : my_identity_element(identity)
38149e08aacStbbdev         , my_real_body(body)
38249e08aacStbbdev         , my_reduction(reduction)
38349e08aacStbbdev         , my_value(identity)
38449e08aacStbbdev     { }
38549e08aacStbbdev     lambda_reduce_body( const lambda_reduce_body& other ) = default;
lambda_reduce_body(lambda_reduce_body & other,tbb::split)38649e08aacStbbdev     lambda_reduce_body( lambda_reduce_body& other, tbb::split )
38749e08aacStbbdev         : my_identity_element(other.my_identity_element)
38849e08aacStbbdev         , my_real_body(other.my_real_body)
38949e08aacStbbdev         , my_reduction(other.my_reduction)
39049e08aacStbbdev         , my_value(other.my_identity_element)
39149e08aacStbbdev     { }
operator()39249e08aacStbbdev     void operator()(Range& range) {
393*a088cfa0SKonstantin Boyarinov         my_value = tbb::detail::invoke(my_real_body, range, const_cast<const Value&>(my_value));
39449e08aacStbbdev     }
join(lambda_reduce_body & rhs)39549e08aacStbbdev     void join( lambda_reduce_body& rhs ) {
396*a088cfa0SKonstantin Boyarinov         my_value = tbb::detail::invoke(my_reduction, const_cast<const Value&>(my_value),
397*a088cfa0SKonstantin Boyarinov                                                      const_cast<const Value&>(rhs.my_value));
39849e08aacStbbdev     }
result()39949e08aacStbbdev     Value result() const {
40049e08aacStbbdev         return my_value;
40149e08aacStbbdev     }
40249e08aacStbbdev };
40349e08aacStbbdev 
40449e08aacStbbdev 
40549e08aacStbbdev // Requirements on Range concept are documented in blocked_range.h
40649e08aacStbbdev 
40749e08aacStbbdev /** \page parallel_reduce_body_req Requirements on parallel_reduce body
40849e08aacStbbdev     Class \c Body implementing the concept of parallel_reduce body must define:
40949e08aacStbbdev     - \code Body::Body( Body&, split ); \endcode        Splitting constructor.
41049e08aacStbbdev                                                         Must be able to run concurrently with operator() and method \c join
41149e08aacStbbdev     - \code Body::~Body(); \endcode                     Destructor
41249e08aacStbbdev     - \code void Body::operator()( Range& r ); \endcode Function call operator applying body to range \c r
41349e08aacStbbdev                                                         and accumulating the result
41449e08aacStbbdev     - \code void Body::join( Body& b ); \endcode        Join results.
41549e08aacStbbdev                                                         The result in \c b should be merged into the result of \c this
41649e08aacStbbdev **/
41749e08aacStbbdev 
41849e08aacStbbdev /** \page parallel_reduce_lambda_req Requirements on parallel_reduce anonymous function objects (lambda functions)
41949e08aacStbbdev     TO BE DOCUMENTED
42049e08aacStbbdev **/
42149e08aacStbbdev 
42249e08aacStbbdev /** \name parallel_reduce
42349e08aacStbbdev     See also requirements on \ref range_req "Range" and \ref parallel_reduce_body_req "parallel_reduce Body". **/
42449e08aacStbbdev //@{
42549e08aacStbbdev 
42649e08aacStbbdev //! Parallel iteration with reduction and default partitioner.
42749e08aacStbbdev /** @ingroup algorithms **/
42849e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)4294a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
43049e08aacStbbdev void parallel_reduce( const Range& range, Body& body ) {
43149e08aacStbbdev     start_reduce<Range,Body, const __TBB_DEFAULT_PARTITIONER>::run( range, body, __TBB_DEFAULT_PARTITIONER() );
43249e08aacStbbdev }
43349e08aacStbbdev 
43449e08aacStbbdev //! Parallel iteration with reduction and simple_partitioner
43549e08aacStbbdev /** @ingroup algorithms **/
43649e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)4374a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
43849e08aacStbbdev void parallel_reduce( const Range& range, Body& body, const simple_partitioner& partitioner ) {
43949e08aacStbbdev     start_reduce<Range,Body,const simple_partitioner>::run( range, body, partitioner );
44049e08aacStbbdev }
44149e08aacStbbdev 
44249e08aacStbbdev //! Parallel iteration with reduction and auto_partitioner
44349e08aacStbbdev /** @ingroup algorithms **/
44449e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)4454a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
44649e08aacStbbdev void parallel_reduce( const Range& range, Body& body, const auto_partitioner& partitioner ) {
44749e08aacStbbdev     start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner );
44849e08aacStbbdev }
44949e08aacStbbdev 
45049e08aacStbbdev //! Parallel iteration with reduction and static_partitioner
45149e08aacStbbdev /** @ingroup algorithms **/
45249e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)4534a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
45449e08aacStbbdev void parallel_reduce( const Range& range, Body& body, const static_partitioner& partitioner ) {
45549e08aacStbbdev     start_reduce<Range,Body,const static_partitioner>::run( range, body, partitioner );
45649e08aacStbbdev }
45749e08aacStbbdev 
45849e08aacStbbdev //! Parallel iteration with reduction and affinity_partitioner
45949e08aacStbbdev /** @ingroup algorithms **/
46049e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)4614a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
46249e08aacStbbdev void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner ) {
46349e08aacStbbdev     start_reduce<Range,Body,affinity_partitioner>::run( range, body, partitioner );
46449e08aacStbbdev }
46549e08aacStbbdev 
46649e08aacStbbdev //! Parallel iteration with reduction, default partitioner and user-supplied context.
46749e08aacStbbdev /** @ingroup algorithms **/
46849e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)4694a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
47049e08aacStbbdev void parallel_reduce( const Range& range, Body& body, task_group_context& context ) {
47149e08aacStbbdev     start_reduce<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run( range, body, __TBB_DEFAULT_PARTITIONER(), context );
47249e08aacStbbdev }
47349e08aacStbbdev 
47449e08aacStbbdev //! Parallel iteration with reduction, simple partitioner and user-supplied context.
47549e08aacStbbdev /** @ingroup algorithms **/
47649e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)4774a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
47849e08aacStbbdev void parallel_reduce( const Range& range, Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
47949e08aacStbbdev     start_reduce<Range,Body,const simple_partitioner>::run( range, body, partitioner, context );
48049e08aacStbbdev }
48149e08aacStbbdev 
48249e08aacStbbdev //! Parallel iteration with reduction, auto_partitioner and user-supplied context
48349e08aacStbbdev /** @ingroup algorithms **/
48449e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)4854a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
48649e08aacStbbdev void parallel_reduce( const Range& range, Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
48749e08aacStbbdev     start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner, context );
48849e08aacStbbdev }
48949e08aacStbbdev 
49049e08aacStbbdev //! Parallel iteration with reduction, static_partitioner and user-supplied context
49149e08aacStbbdev /** @ingroup algorithms **/
49249e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)4934a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
49449e08aacStbbdev void parallel_reduce( const Range& range, Body& body, const static_partitioner& partitioner, task_group_context& context ) {
49549e08aacStbbdev     start_reduce<Range,Body,const static_partitioner>::run( range, body, partitioner, context );
49649e08aacStbbdev }
49749e08aacStbbdev 
49849e08aacStbbdev //! Parallel iteration with reduction, affinity_partitioner and user-supplied context
49949e08aacStbbdev /** @ingroup algorithms **/
50049e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)5014a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
50249e08aacStbbdev void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
50349e08aacStbbdev     start_reduce<Range,Body,affinity_partitioner>::run( range, body, partitioner, context );
50449e08aacStbbdev }
50549e08aacStbbdev /** parallel_reduce overloads that work with anonymous function objects
50649e08aacStbbdev     (see also \ref parallel_reduce_lambda_req "requirements on parallel_reduce anonymous function objects"). **/
50749e08aacStbbdev 
50849e08aacStbbdev //! Parallel iteration with reduction and default partitioner.
50949e08aacStbbdev /** @ingroup algorithms **/
51049e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)5114a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
512478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
51349e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction ) {
51449e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
51549e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,const __TBB_DEFAULT_PARTITIONER>
51649e08aacStbbdev                           ::run(range, body, __TBB_DEFAULT_PARTITIONER() );
51749e08aacStbbdev     return body.result();
51849e08aacStbbdev }
51949e08aacStbbdev 
52049e08aacStbbdev //! Parallel iteration with reduction and simple_partitioner.
52149e08aacStbbdev /** @ingroup algorithms **/
52249e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)5234a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
524478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
52549e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
52649e08aacStbbdev                        const simple_partitioner& partitioner ) {
52749e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
52849e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,const simple_partitioner>
52949e08aacStbbdev                           ::run(range, body, partitioner );
53049e08aacStbbdev     return body.result();
53149e08aacStbbdev }
53249e08aacStbbdev 
53349e08aacStbbdev //! Parallel iteration with reduction and auto_partitioner
53449e08aacStbbdev /** @ingroup algorithms **/
53549e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)5364a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
537478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
53849e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
53949e08aacStbbdev                        const auto_partitioner& partitioner ) {
54049e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
54149e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,const auto_partitioner>
54249e08aacStbbdev                           ::run( range, body, partitioner );
54349e08aacStbbdev     return body.result();
54449e08aacStbbdev }
54549e08aacStbbdev 
54649e08aacStbbdev //! Parallel iteration with reduction and static_partitioner
54749e08aacStbbdev /** @ingroup algorithms **/
54849e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)5494a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
550478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
55149e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
55249e08aacStbbdev                        const static_partitioner& partitioner ) {
55349e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
55449e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,const static_partitioner>
55549e08aacStbbdev                                         ::run( range, body, partitioner );
55649e08aacStbbdev     return body.result();
55749e08aacStbbdev }
55849e08aacStbbdev 
55949e08aacStbbdev //! Parallel iteration with reduction and affinity_partitioner
56049e08aacStbbdev /** @ingroup algorithms **/
56149e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)5624a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
563478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
56449e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
56549e08aacStbbdev                        affinity_partitioner& partitioner ) {
56649e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
56749e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,affinity_partitioner>
56849e08aacStbbdev                                         ::run( range, body, partitioner );
56949e08aacStbbdev     return body.result();
57049e08aacStbbdev }
57149e08aacStbbdev 
57249e08aacStbbdev //! Parallel iteration with reduction, default partitioner and user-supplied context.
57349e08aacStbbdev /** @ingroup algorithms **/
57449e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)5754a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
576478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
57749e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
57849e08aacStbbdev                        task_group_context& context ) {
57949e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
58049e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,const __TBB_DEFAULT_PARTITIONER>
58149e08aacStbbdev                           ::run( range, body, __TBB_DEFAULT_PARTITIONER(), context );
58249e08aacStbbdev     return body.result();
58349e08aacStbbdev }
58449e08aacStbbdev 
58549e08aacStbbdev //! Parallel iteration with reduction, simple partitioner and user-supplied context.
58649e08aacStbbdev /** @ingroup algorithms **/
58749e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)5884a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
589478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
59049e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
59149e08aacStbbdev                        const simple_partitioner& partitioner, task_group_context& context ) {
59249e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
59349e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,const simple_partitioner>
59449e08aacStbbdev                           ::run( range, body, partitioner, context );
59549e08aacStbbdev     return body.result();
59649e08aacStbbdev }
59749e08aacStbbdev 
59849e08aacStbbdev //! Parallel iteration with reduction, auto_partitioner and user-supplied context
59949e08aacStbbdev /** @ingroup algorithms **/
60049e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)6014a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
602478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
60349e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
60449e08aacStbbdev                        const auto_partitioner& partitioner, task_group_context& context ) {
60549e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
60649e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,const auto_partitioner>
60749e08aacStbbdev                           ::run( range, body, partitioner, context );
60849e08aacStbbdev     return body.result();
60949e08aacStbbdev }
61049e08aacStbbdev 
61149e08aacStbbdev //! Parallel iteration with reduction, static_partitioner and user-supplied context
61249e08aacStbbdev /** @ingroup algorithms **/
61349e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)6144a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
615478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
61649e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
61749e08aacStbbdev                        const static_partitioner& partitioner, task_group_context& context ) {
61849e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
61949e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,const static_partitioner>
62049e08aacStbbdev                                         ::run( range, body, partitioner, context );
62149e08aacStbbdev     return body.result();
62249e08aacStbbdev }
62349e08aacStbbdev 
62449e08aacStbbdev //! Parallel iteration with reduction, affinity_partitioner and user-supplied context
62549e08aacStbbdev /** @ingroup algorithms **/
62649e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)6274a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
628478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
62949e08aacStbbdev Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
63049e08aacStbbdev                        affinity_partitioner& partitioner, task_group_context& context ) {
63149e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
63249e08aacStbbdev     start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,affinity_partitioner>
63349e08aacStbbdev                                         ::run( range, body, partitioner, context );
63449e08aacStbbdev     return body.result();
63549e08aacStbbdev }
63649e08aacStbbdev 
63749e08aacStbbdev //! Parallel iteration with deterministic reduction and default simple partitioner.
63849e08aacStbbdev /** @ingroup algorithms **/
63949e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)6404a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
64149e08aacStbbdev void parallel_deterministic_reduce( const Range& range, Body& body ) {
64249e08aacStbbdev     start_deterministic_reduce<Range, Body, const simple_partitioner>::run(range, body, simple_partitioner());
64349e08aacStbbdev }
64449e08aacStbbdev 
64549e08aacStbbdev //! Parallel iteration with deterministic reduction and simple partitioner.
64649e08aacStbbdev /** @ingroup algorithms **/
64749e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)6484a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
64949e08aacStbbdev void parallel_deterministic_reduce( const Range& range, Body& body, const simple_partitioner& partitioner ) {
65049e08aacStbbdev     start_deterministic_reduce<Range, Body, const simple_partitioner>::run(range, body, partitioner);
65149e08aacStbbdev }
65249e08aacStbbdev 
65349e08aacStbbdev //! Parallel iteration with deterministic reduction and static partitioner.
65449e08aacStbbdev /** @ingroup algorithms **/
65549e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)6564a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
65749e08aacStbbdev void parallel_deterministic_reduce( const Range& range, Body& body, const static_partitioner& partitioner ) {
65849e08aacStbbdev     start_deterministic_reduce<Range, Body, const static_partitioner>::run(range, body, partitioner);
65949e08aacStbbdev }
66049e08aacStbbdev 
66149e08aacStbbdev //! Parallel iteration with deterministic reduction, default simple partitioner and user-supplied context.
66249e08aacStbbdev /** @ingroup algorithms **/
66349e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)6644a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
66549e08aacStbbdev void parallel_deterministic_reduce( const Range& range, Body& body, task_group_context& context ) {
66649e08aacStbbdev     start_deterministic_reduce<Range,Body, const simple_partitioner>::run( range, body, simple_partitioner(), context );
66749e08aacStbbdev }
66849e08aacStbbdev 
66949e08aacStbbdev //! Parallel iteration with deterministic reduction, simple partitioner and user-supplied context.
67049e08aacStbbdev /** @ingroup algorithms **/
67149e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)6724a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
67349e08aacStbbdev void parallel_deterministic_reduce( const Range& range, Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
67449e08aacStbbdev     start_deterministic_reduce<Range, Body, const simple_partitioner>::run(range, body, partitioner, context);
67549e08aacStbbdev }
67649e08aacStbbdev 
67749e08aacStbbdev //! Parallel iteration with deterministic reduction, static partitioner and user-supplied context.
67849e08aacStbbdev /** @ingroup algorithms **/
67949e08aacStbbdev template<typename Range, typename Body>
__TBB_requires(tbb_range<Range> && parallel_reduce_body<Body,Range>)6804a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_body<Body, Range>)
68149e08aacStbbdev void parallel_deterministic_reduce( const Range& range, Body& body, const static_partitioner& partitioner, task_group_context& context ) {
68249e08aacStbbdev     start_deterministic_reduce<Range, Body, const static_partitioner>::run(range, body, partitioner, context);
68349e08aacStbbdev }
68449e08aacStbbdev 
68549e08aacStbbdev /** parallel_reduce overloads that work with anonymous function objects
68649e08aacStbbdev     (see also \ref parallel_reduce_lambda_req "requirements on parallel_reduce anonymous function objects"). **/
68749e08aacStbbdev 
68849e08aacStbbdev //! Parallel iteration with deterministic reduction and default simple partitioner.
68949e08aacStbbdev // TODO: consider making static_partitioner the default
69049e08aacStbbdev /** @ingroup algorithms **/
69149e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)6924a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
693478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
69449e08aacStbbdev Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction ) {
69549e08aacStbbdev     return parallel_deterministic_reduce(range, identity, real_body, reduction, simple_partitioner());
69649e08aacStbbdev }
69749e08aacStbbdev 
69849e08aacStbbdev //! Parallel iteration with deterministic reduction and simple partitioner.
69949e08aacStbbdev /** @ingroup algorithms **/
70049e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)7014a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
702478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
70349e08aacStbbdev Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction, const simple_partitioner& partitioner ) {
70449e08aacStbbdev     lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
70549e08aacStbbdev     start_deterministic_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>, const simple_partitioner>
70649e08aacStbbdev                           ::run(range, body, partitioner);
70749e08aacStbbdev     return body.result();
70849e08aacStbbdev }
70949e08aacStbbdev 
71049e08aacStbbdev //! Parallel iteration with deterministic reduction and static partitioner.
71149e08aacStbbdev /** @ingroup algorithms **/
71249e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)7134a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
714478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
71549e08aacStbbdev Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction, const static_partitioner& partitioner ) {
71649e08aacStbbdev     lambda_reduce_body<Range, Value, RealBody, Reduction> body(identity, real_body, reduction);
71749e08aacStbbdev     start_deterministic_reduce<Range, lambda_reduce_body<Range, Value, RealBody, Reduction>, const static_partitioner>
71849e08aacStbbdev         ::run(range, body, partitioner);
71949e08aacStbbdev     return body.result();
72049e08aacStbbdev }
72149e08aacStbbdev 
72249e08aacStbbdev //! Parallel iteration with deterministic reduction, default simple partitioner and user-supplied context.
72349e08aacStbbdev /** @ingroup algorithms **/
72449e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)7254a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
726478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
72749e08aacStbbdev Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
72849e08aacStbbdev     task_group_context& context ) {
72949e08aacStbbdev     return parallel_deterministic_reduce(range, identity, real_body, reduction, simple_partitioner(), context);
73049e08aacStbbdev }
73149e08aacStbbdev 
73249e08aacStbbdev //! Parallel iteration with deterministic reduction, simple partitioner and user-supplied context.
73349e08aacStbbdev /** @ingroup algorithms **/
73449e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)7354a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
736478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
73749e08aacStbbdev Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
73849e08aacStbbdev     const simple_partitioner& partitioner, task_group_context& context ) {
73949e08aacStbbdev     lambda_reduce_body<Range, Value, RealBody, Reduction> body(identity, real_body, reduction);
74049e08aacStbbdev     start_deterministic_reduce<Range, lambda_reduce_body<Range, Value, RealBody, Reduction>, const simple_partitioner>
74149e08aacStbbdev         ::run(range, body, partitioner, context);
74249e08aacStbbdev     return body.result();
74349e08aacStbbdev }
74449e08aacStbbdev 
74549e08aacStbbdev //! Parallel iteration with deterministic reduction, static partitioner and user-supplied context.
74649e08aacStbbdev /** @ingroup algorithms **/
74749e08aacStbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody,Range,Value> && parallel_reduce_combine<Reduction,Value>)7484a23d002Skboyarinov     __TBB_requires(tbb_range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
749478de5b1Stbbdev                    parallel_reduce_combine<Reduction, Value>)
75049e08aacStbbdev Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
75149e08aacStbbdev     const static_partitioner& partitioner, task_group_context& context ) {
75249e08aacStbbdev     lambda_reduce_body<Range, Value, RealBody, Reduction> body(identity, real_body, reduction);
75349e08aacStbbdev     start_deterministic_reduce<Range, lambda_reduce_body<Range, Value, RealBody, Reduction>, const static_partitioner>
75449e08aacStbbdev         ::run(range, body, partitioner, context);
75549e08aacStbbdev     return body.result();
75649e08aacStbbdev }
75749e08aacStbbdev //@}
75849e08aacStbbdev 
75949e08aacStbbdev } // namespace d1
76049e08aacStbbdev } // namespace detail
76149e08aacStbbdev 
76249e08aacStbbdev inline namespace v1 {
76349e08aacStbbdev using detail::d1::parallel_reduce;
76449e08aacStbbdev using detail::d1::parallel_deterministic_reduce;
76549e08aacStbbdev // Split types
76649e08aacStbbdev using detail::split;
76749e08aacStbbdev using detail::proportional_split;
76849e08aacStbbdev } // namespace v1
76949e08aacStbbdev 
77049e08aacStbbdev } // namespace tbb
77149e08aacStbbdev #endif /* __TBB_parallel_reduce_H */
772