You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							508 lines
						
					
					
						
							18 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							508 lines
						
					
					
						
							18 KiB
						
					
					
				
								/*
							 | 
						|
								    Copyright 2005-2014 Intel Corporation.  All Rights Reserved.
							 | 
						|
								
							 | 
						|
								    This file is part of Threading Building Blocks.
							 | 
						|
								
							 | 
						|
								    Threading Building Blocks is free software; you can redistribute it
							 | 
						|
								    and/or modify it under the terms of the GNU General Public License
							 | 
						|
								    version 2 as published by the Free Software Foundation.
							 | 
						|
								
							 | 
						|
								    Threading Building Blocks is distributed in the hope that it will be
							 | 
						|
								    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
							 | 
						|
								    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						|
								    GNU General Public License for more details.
							 | 
						|
								
							 | 
						|
								    You should have received a copy of the GNU General Public License
							 | 
						|
								    along with Threading Building Blocks; if not, write to the Free Software
							 | 
						|
								    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
							 | 
						|
								
							 | 
						|
								    As a special exception, you may use this file as part of a free software
							 | 
						|
								    library without restriction.  Specifically, if other files instantiate
							 | 
						|
								    templates or use macros or inline functions from this file, or you compile
							 | 
						|
								    this file and link it with other files to produce an executable, this
							 | 
						|
								    file does not by itself cause the resulting executable to be covered by
							 | 
						|
								    the GNU General Public License.  This exception does not however
							 | 
						|
								    invalidate any other reasons why the executable file might be covered by
							 | 
						|
								    the GNU General Public License.
							 | 
						|
								*/
							 | 
						|
								
							 | 
						|
								#ifndef __TBB_parallel_do_H
							 | 
						|
								#define __TBB_parallel_do_H
							 | 
						|
								
							 | 
						|
								#include "task.h"
							 | 
						|
								#include "aligned_space.h"
							 | 
						|
								#include <iterator>
							 | 
						|
								
							 | 
						|
								namespace tbb {
							 | 
						|
								
							 | 
						|
								//! @cond INTERNAL
							 | 
						|
								namespace internal {
							 | 
						|
								    template<typename Body, typename Item> class parallel_do_feeder_impl;
							 | 
						|
								    template<typename Body> class do_group_task;
							 | 
						|
								
							 | 
						|
								    //! Strips its template type argument from 'cv' and '&' qualifiers
							 | 
						|
								    template<typename T>
							 | 
						|
								    struct strip { typedef T type; };
							 | 
						|
								    template<typename T>
							 | 
						|
								    struct strip<T&> { typedef T type; };
							 | 
						|
								    template<typename T>
							 | 
						|
								    struct strip<const T&> { typedef T type; };
							 | 
						|
								    template<typename T>
							 | 
						|
								    struct strip<volatile T&> { typedef T type; };
							 | 
						|
								    template<typename T>
							 | 
						|
								    struct strip<const volatile T&> { typedef T type; };
							 | 
						|
								    // Most of the compilers remove cv-qualifiers from non-reference function argument types. 
							 | 
						|
								    // But unfortunately there are those that don't.
							 | 
						|
								    template<typename T>
							 | 
						|
								    struct strip<const T> { typedef T type; };
							 | 
						|
								    template<typename T>
							 | 
						|
								    struct strip<volatile T> { typedef T type; };
							 | 
						|
								    template<typename T>
							 | 
						|
								    struct strip<const volatile T> { typedef T type; };
							 | 
						|
								} // namespace internal
							 | 
						|
								//! @endcond
							 | 
						|
								
							 | 
						|
								//! Class the user supplied algorithm body uses to add new tasks
							 | 
						|
								/** \param Item Work item type **/
							 | 
						|
								template<typename Item>
							 | 
						|
								class parallel_do_feeder: internal::no_copy
							 | 
						|
								{
							 | 
						|
								    parallel_do_feeder() {}
							 | 
						|
								    virtual ~parallel_do_feeder () {}
							 | 
						|
								    virtual void internal_add( const Item& item ) = 0;
							 | 
						|
								    template<typename Body_, typename Item_> friend class internal::parallel_do_feeder_impl;
							 | 
						|
								public:
							 | 
						|
								    //! Add a work item to a running parallel_do.
							 | 
						|
								    void add( const Item& item ) {internal_add(item);}
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								//! @cond INTERNAL
							 | 
						|
								namespace internal {
							 | 
						|
								    //! For internal use only.
							 | 
						|
								    /** Selects one of the two possible forms of function call member operator.
							 | 
						|
								        @ingroup algorithms **/
							 | 
						|
								    template<class Body, typename Item>
							 | 
						|
								    class parallel_do_operator_selector
							 | 
						|
								    {
							 | 
						|
								        typedef parallel_do_feeder<Item> Feeder;
							 | 
						|
								        template<typename A1, typename A2, typename CvItem >
							 | 
						|
								        static void internal_call( const Body& obj, A1& arg1, A2&, void (Body::*)(CvItem) const ) {
							 | 
						|
								            obj(arg1);
							 | 
						|
								        }
							 | 
						|
								        template<typename A1, typename A2, typename CvItem >
							 | 
						|
								        static void internal_call( const Body& obj, A1& arg1, A2& arg2, void (Body::*)(CvItem, parallel_do_feeder<Item>&) const ) {
							 | 
						|
								            obj(arg1, arg2);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								    public:
							 | 
						|
								        template<typename A1, typename A2 >
							 | 
						|
								        static void call( const Body& obj, A1& arg1, A2& arg2 )
							 | 
						|
								        {
							 | 
						|
								            internal_call( obj, arg1, arg2, &Body::operator() );
							 | 
						|
								        }
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								    //! For internal use only.
							 | 
						|
								    /** Executes one iteration of a do.
							 | 
						|
								        @ingroup algorithms */
							 | 
						|
								    template<typename Body, typename Item>
							 | 
						|
								    class do_iteration_task: public task
							 | 
						|
								    {
							 | 
						|
								        typedef parallel_do_feeder_impl<Body, Item> feeder_type;
							 | 
						|
								
							 | 
						|
								        Item my_value;
							 | 
						|
								        feeder_type& my_feeder;
							 | 
						|
								
							 | 
						|
								        do_iteration_task( const Item& value, feeder_type& feeder ) : 
							 | 
						|
								            my_value(value), my_feeder(feeder)
							 | 
						|
								        {}
							 | 
						|
								
							 | 
						|
								        /*override*/ 
							 | 
						|
								        task* execute()
							 | 
						|
								        {
							 | 
						|
								            parallel_do_operator_selector<Body, Item>::call(*my_feeder.my_body, my_value, my_feeder);
							 | 
						|
								            return NULL;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        template<typename Body_, typename Item_> friend class parallel_do_feeder_impl;
							 | 
						|
								    }; // class do_iteration_task
							 | 
						|
								
							 | 
						|
								    template<typename Iterator, typename Body, typename Item>
							 | 
						|
								    class do_iteration_task_iter: public task
							 | 
						|
								    {
							 | 
						|
								        typedef parallel_do_feeder_impl<Body, Item> feeder_type;
							 | 
						|
								
							 | 
						|
								        Iterator my_iter;
							 | 
						|
								        feeder_type& my_feeder;
							 | 
						|
								
							 | 
						|
								        do_iteration_task_iter( const Iterator& iter, feeder_type& feeder ) : 
							 | 
						|
								            my_iter(iter), my_feeder(feeder)
							 | 
						|
								        {}
							 | 
						|
								
							 | 
						|
								        /*override*/ 
							 | 
						|
								        task* execute()
							 | 
						|
								        {
							 | 
						|
								            parallel_do_operator_selector<Body, Item>::call(*my_feeder.my_body, *my_iter, my_feeder);
							 | 
						|
								            return NULL;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        template<typename Iterator_, typename Body_, typename Item_> friend class do_group_task_forward;    
							 | 
						|
								        template<typename Body_, typename Item_> friend class do_group_task_input;    
							 | 
						|
								        template<typename Iterator_, typename Body_, typename Item_> friend class do_task_iter;    
							 | 
						|
								    }; // class do_iteration_task_iter
							 | 
						|
								
							 | 
						|
								    //! For internal use only.
							 | 
						|
								    /** Implements new task adding procedure.
							 | 
						|
								        @ingroup algorithms **/
							 | 
						|
								    template<class Body, typename Item>
							 | 
						|
								    class parallel_do_feeder_impl : public parallel_do_feeder<Item>
							 | 
						|
								    {
							 | 
						|
								        /*override*/ 
							 | 
						|
								        void internal_add( const Item& item )
							 | 
						|
								        {
							 | 
						|
								            typedef do_iteration_task<Body, Item> iteration_type;
							 | 
						|
								
							 | 
						|
								            iteration_type& t = *new (task::allocate_additional_child_of(*my_barrier)) iteration_type(item, *this);
							 | 
						|
								
							 | 
						|
								            t.spawn( t );
							 | 
						|
								        }
							 | 
						|
								    public:
							 | 
						|
								        const Body* my_body;
							 | 
						|
								        empty_task* my_barrier;
							 | 
						|
								
							 | 
						|
								        parallel_do_feeder_impl()
							 | 
						|
								        {
							 | 
						|
								            my_barrier = new( task::allocate_root() ) empty_task();
							 | 
						|
								            __TBB_ASSERT(my_barrier, "root task allocation failed");
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								        parallel_do_feeder_impl(tbb::task_group_context &context)
							 | 
						|
								        {
							 | 
						|
								            my_barrier = new( task::allocate_root(context) ) empty_task();
							 | 
						|
								            __TBB_ASSERT(my_barrier, "root task allocation failed");
							 | 
						|
								        }
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								        ~parallel_do_feeder_impl()
							 | 
						|
								        {
							 | 
						|
								            my_barrier->destroy(*my_barrier);
							 | 
						|
								        }
							 | 
						|
								    }; // class parallel_do_feeder_impl
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    //! For internal use only
							 | 
						|
								    /** Unpacks a block of iterations.
							 | 
						|
								        @ingroup algorithms */
							 | 
						|
								    
							 | 
						|
								    template<typename Iterator, typename Body, typename Item>
							 | 
						|
								    class do_group_task_forward: public task
							 | 
						|
								    {
							 | 
						|
								        static const size_t max_arg_size = 4;         
							 | 
						|
								
							 | 
						|
								        typedef parallel_do_feeder_impl<Body, Item> feeder_type;
							 | 
						|
								
							 | 
						|
								        feeder_type& my_feeder;
							 | 
						|
								        Iterator my_first;
							 | 
						|
								        size_t my_size;
							 | 
						|
								        
							 | 
						|
								        do_group_task_forward( Iterator first, size_t size, feeder_type& feeder ) 
							 | 
						|
								            : my_feeder(feeder), my_first(first), my_size(size)
							 | 
						|
								        {}
							 | 
						|
								
							 | 
						|
								        /*override*/ task* execute()
							 | 
						|
								        {
							 | 
						|
								            typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
							 | 
						|
								            __TBB_ASSERT( my_size>0, NULL );
							 | 
						|
								            task_list list;
							 | 
						|
								            task* t; 
							 | 
						|
								            size_t k=0; 
							 | 
						|
								            for(;;) {
							 | 
						|
								                t = new( allocate_child() ) iteration_type( my_first, my_feeder );
							 | 
						|
								                ++my_first;
							 | 
						|
								                if( ++k==my_size ) break;
							 | 
						|
								                list.push_back(*t);
							 | 
						|
								            }
							 | 
						|
								            set_ref_count(int(k+1));
							 | 
						|
								            spawn(list);
							 | 
						|
								            spawn_and_wait_for_all(*t);
							 | 
						|
								            return NULL;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        template<typename Iterator_, typename Body_, typename _Item> friend class do_task_iter;
							 | 
						|
								    }; // class do_group_task_forward
							 | 
						|
								
							 | 
						|
								    template<typename Body, typename Item>
							 | 
						|
								    class do_group_task_input: public task
							 | 
						|
								    {
							 | 
						|
								        static const size_t max_arg_size = 4;         
							 | 
						|
								        
							 | 
						|
								        typedef parallel_do_feeder_impl<Body, Item> feeder_type;
							 | 
						|
								
							 | 
						|
								        feeder_type& my_feeder;
							 | 
						|
								        size_t my_size;
							 | 
						|
								        aligned_space<Item, max_arg_size> my_arg;
							 | 
						|
								
							 | 
						|
								        do_group_task_input( feeder_type& feeder ) 
							 | 
						|
								            : my_feeder(feeder), my_size(0)
							 | 
						|
								        {}
							 | 
						|
								
							 | 
						|
								        /*override*/ task* execute()
							 | 
						|
								        {
							 | 
						|
								            typedef do_iteration_task_iter<Item*, Body, Item> iteration_type;
							 | 
						|
								            __TBB_ASSERT( my_size>0, NULL );
							 | 
						|
								            task_list list;
							 | 
						|
								            task* t; 
							 | 
						|
								            size_t k=0; 
							 | 
						|
								            for(;;) {
							 | 
						|
								                t = new( allocate_child() ) iteration_type( my_arg.begin() + k, my_feeder );
							 | 
						|
								                if( ++k==my_size ) break;
							 | 
						|
								                list.push_back(*t);
							 | 
						|
								            }
							 | 
						|
								            set_ref_count(int(k+1));
							 | 
						|
								            spawn(list);
							 | 
						|
								            spawn_and_wait_for_all(*t);
							 | 
						|
								            return NULL;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        ~do_group_task_input(){
							 | 
						|
								            for( size_t k=0; k<my_size; ++k)
							 | 
						|
								                (my_arg.begin() + k)->~Item();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        template<typename Iterator_, typename Body_, typename Item_> friend class do_task_iter;
							 | 
						|
								    }; // class do_group_task_input
							 | 
						|
								    
							 | 
						|
								    //! For internal use only.
							 | 
						|
								    /** Gets block of iterations and packages them into a do_group_task.
							 | 
						|
								        @ingroup algorithms */
							 | 
						|
								    template<typename Iterator, typename Body, typename Item>
							 | 
						|
								    class do_task_iter: public task
							 | 
						|
								    {
							 | 
						|
								        typedef parallel_do_feeder_impl<Body, Item> feeder_type;
							 | 
						|
								
							 | 
						|
								    public:
							 | 
						|
								        do_task_iter( Iterator first, Iterator last , feeder_type& feeder ) : 
							 | 
						|
								            my_first(first), my_last(last), my_feeder(feeder)
							 | 
						|
								        {}
							 | 
						|
								
							 | 
						|
								    private:
							 | 
						|
								        Iterator my_first;
							 | 
						|
								        Iterator my_last;
							 | 
						|
								        feeder_type& my_feeder;
							 | 
						|
								
							 | 
						|
								        /* Do not merge run(xxx) and run_xxx() methods. They are separated in order
							 | 
						|
								            to make sure that compilers will eliminate unused argument of type xxx
							 | 
						|
								            (that is will not put it on stack). The sole purpose of this argument 
							 | 
						|
								            is overload resolution.
							 | 
						|
								            
							 | 
						|
								            An alternative could be using template functions, but explicit specialization 
							 | 
						|
								            of member function templates is not supported for non specialized class 
							 | 
						|
								            templates. Besides template functions would always fall back to the least 
							 | 
						|
								            efficient variant (the one for input iterators) in case of iterators having 
							 | 
						|
								            custom tags derived from basic ones. */
							 | 
						|
								        /*override*/ task* execute()
							 | 
						|
								        {
							 | 
						|
								            typedef typename std::iterator_traits<Iterator>::iterator_category iterator_tag;
							 | 
						|
								            return run( (iterator_tag*)NULL );
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /** This is the most restricted variant that operates on input iterators or
							 | 
						|
								            iterators with unknown tags (tags not derived from the standard ones). **/
							 | 
						|
								        inline task* run( void* ) { return run_for_input_iterator(); }
							 | 
						|
								        
							 | 
						|
								        task* run_for_input_iterator() {
							 | 
						|
								            typedef do_group_task_input<Body, Item> block_type;
							 | 
						|
								
							 | 
						|
								            block_type& t = *new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(my_feeder);
							 | 
						|
								            size_t k=0; 
							 | 
						|
								            while( !(my_first == my_last) ) {
							 | 
						|
								                new (t.my_arg.begin() + k) Item(*my_first);
							 | 
						|
								                ++my_first;
							 | 
						|
								                if( ++k==block_type::max_arg_size ) {
							 | 
						|
								                    if ( !(my_first == my_last) )
							 | 
						|
								                        recycle_to_reexecute();
							 | 
						|
								                    break;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            if( k==0 ) {
							 | 
						|
								                destroy(t);
							 | 
						|
								                return NULL;
							 | 
						|
								            } else {
							 | 
						|
								                t.my_size = k;
							 | 
						|
								                return &t;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        inline task* run( std::forward_iterator_tag* ) { return run_for_forward_iterator(); }
							 | 
						|
								
							 | 
						|
								        task* run_for_forward_iterator() {
							 | 
						|
								            typedef do_group_task_forward<Iterator, Body, Item> block_type;
							 | 
						|
								
							 | 
						|
								            Iterator first = my_first;
							 | 
						|
								            size_t k=0; 
							 | 
						|
								            while( !(my_first==my_last) ) {
							 | 
						|
								                ++my_first;
							 | 
						|
								                if( ++k==block_type::max_arg_size ) {
							 | 
						|
								                    if ( !(my_first==my_last) )
							 | 
						|
								                        recycle_to_reexecute();
							 | 
						|
								                    break;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            return k==0 ? NULL : new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(first, k, my_feeder);
							 | 
						|
								        }
							 | 
						|
								        
							 | 
						|
								        inline task* run( std::random_access_iterator_tag* ) { return run_for_random_access_iterator(); }
							 | 
						|
								
							 | 
						|
								        task* run_for_random_access_iterator() {
							 | 
						|
								            typedef do_group_task_forward<Iterator, Body, Item> block_type;
							 | 
						|
								            typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
							 | 
						|
								            
							 | 
						|
								            size_t k = static_cast<size_t>(my_last-my_first); 
							 | 
						|
								            if( k > block_type::max_arg_size ) {
							 | 
						|
								                Iterator middle = my_first + k/2;
							 | 
						|
								
							 | 
						|
								                empty_task& c = *new( allocate_continuation() ) empty_task;
							 | 
						|
								                do_task_iter& b = *new( c.allocate_child() ) do_task_iter(middle, my_last, my_feeder);
							 | 
						|
								                recycle_as_child_of(c);
							 | 
						|
								
							 | 
						|
								                my_last = middle;
							 | 
						|
								                c.set_ref_count(2);
							 | 
						|
								                c.spawn(b);
							 | 
						|
								                return this;
							 | 
						|
								            }else if( k != 0 ) {
							 | 
						|
								                task_list list;
							 | 
						|
								                task* t; 
							 | 
						|
								                size_t k1=0; 
							 | 
						|
								                for(;;) {
							 | 
						|
								                    t = new( allocate_child() ) iteration_type(my_first, my_feeder);
							 | 
						|
								                    ++my_first;
							 | 
						|
								                    if( ++k1==k ) break;
							 | 
						|
								                    list.push_back(*t);
							 | 
						|
								                }
							 | 
						|
								                set_ref_count(int(k+1));
							 | 
						|
								                spawn(list);
							 | 
						|
								                spawn_and_wait_for_all(*t);
							 | 
						|
								            }
							 | 
						|
								            return NULL;
							 | 
						|
								        }
							 | 
						|
								    }; // class do_task_iter
							 | 
						|
								
							 | 
						|
								    //! For internal use only.
							 | 
						|
								    /** Implements parallel iteration over a range.
							 | 
						|
								        @ingroup algorithms */
							 | 
						|
								    template<typename Iterator, typename Body, typename Item> 
							 | 
						|
								    void run_parallel_do( Iterator first, Iterator last, const Body& body
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								        , task_group_context& context
							 | 
						|
								#endif
							 | 
						|
								        )
							 | 
						|
								    {
							 | 
						|
								        typedef do_task_iter<Iterator, Body, Item> root_iteration_task;
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								        parallel_do_feeder_impl<Body, Item> feeder(context);
							 | 
						|
								#else
							 | 
						|
								        parallel_do_feeder_impl<Body, Item> feeder;
							 | 
						|
								#endif
							 | 
						|
								        feeder.my_body = &body;
							 | 
						|
								
							 | 
						|
								        root_iteration_task &t = *new( feeder.my_barrier->allocate_child() ) root_iteration_task(first, last, feeder);
							 | 
						|
								
							 | 
						|
								        feeder.my_barrier->set_ref_count(2);
							 | 
						|
								        feeder.my_barrier->spawn_and_wait_for_all(t);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! For internal use only.
							 | 
						|
								    /** Detects types of Body's operator function arguments.
							 | 
						|
								        @ingroup algorithms **/
							 | 
						|
								    template<typename Iterator, typename Body, typename Item> 
							 | 
						|
								    void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item) const
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								        , task_group_context& context 
							 | 
						|
								#endif // __TBB_TASK_GROUP_CONTEXT 
							 | 
						|
								        )
							 | 
						|
								    {
							 | 
						|
								        run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								            , context
							 | 
						|
								#endif // __TBB_TASK_GROUP_CONTEXT 
							 | 
						|
								            );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! For internal use only.
							 | 
						|
								    /** Detects types of Body's operator function arguments.
							 | 
						|
								        @ingroup algorithms **/
							 | 
						|
								    template<typename Iterator, typename Body, typename Item, typename _Item> 
							 | 
						|
								    void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item, parallel_do_feeder<_Item>&) const
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								        , task_group_context& context 
							 | 
						|
								#endif // __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								        )
							 | 
						|
								    {
							 | 
						|
								        run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								            , context
							 | 
						|
								#endif // __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								            );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								} // namespace internal
							 | 
						|
								//! @endcond
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/** \page parallel_do_body_req Requirements on parallel_do body
							 | 
						|
								    Class \c Body implementing the concept of parallel_do body must define:
							 | 
						|
								    - \code 
							 | 
						|
								        B::operator()( 
							 | 
						|
								                cv_item_type item,
							 | 
						|
								                parallel_do_feeder<item_type>& feeder
							 | 
						|
								        ) const
							 | 
						|
								        
							 | 
						|
								        OR
							 | 
						|
								
							 | 
						|
								        B::operator()( cv_item_type& item ) const
							 | 
						|
								      \endcode                                                      Process item. 
							 | 
						|
								                                                                    May be invoked concurrently  for the same \c this but different \c item.
							 | 
						|
								                                                        
							 | 
						|
								    - \code item_type( const item_type& ) \endcode 
							 | 
						|
								                                                                    Copy a work item.
							 | 
						|
								    - \code ~item_type() \endcode                            Destroy a work item
							 | 
						|
								**/
							 | 
						|
								
							 | 
						|
								/** \name parallel_do
							 | 
						|
								    See also requirements on \ref parallel_do_body_req "parallel_do Body". **/
							 | 
						|
								//@{
							 | 
						|
								//! Parallel iteration over a range, with optional addition of more work.
							 | 
						|
								/** @ingroup algorithms */
							 | 
						|
								template<typename Iterator, typename Body> 
							 | 
						|
								void parallel_do( Iterator first, Iterator last, const Body& body )
							 | 
						|
								{
							 | 
						|
								    if ( first == last )
							 | 
						|
								        return;
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								    task_group_context context;
							 | 
						|
								#endif // __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								    internal::select_parallel_do( first, last, body, &Body::operator()
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								        , context
							 | 
						|
								#endif // __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								        );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								//! Parallel iteration over a range, with optional addition of more work and user-supplied context
							 | 
						|
								/** @ingroup algorithms */
							 | 
						|
								template<typename Iterator, typename Body> 
							 | 
						|
								void parallel_do( Iterator first, Iterator last, const Body& body, task_group_context& context  )
							 | 
						|
								{
							 | 
						|
								    if ( first == last )
							 | 
						|
								        return;
							 | 
						|
								    internal::select_parallel_do( first, last, body, &Body::operator(), context );
							 | 
						|
								}
							 | 
						|
								#endif // __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								
							 | 
						|
								//@}
							 | 
						|
								
							 | 
						|
								} // namespace 
							 | 
						|
								
							 | 
						|
								#endif /* __TBB_parallel_do_H */
							 |