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