diff --git a/pstl/include/pstl/internal/algorithm_fwd.h b/pstl/include/pstl/internal/algorithm_fwd.h --- a/pstl/include/pstl/internal/algorithm_fwd.h +++ b/pstl/include/pstl/internal/algorithm_fwd.h @@ -264,15 +264,15 @@ _RandomAccessIterator __brick_find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, /*is_vector=*/std::true_type) noexcept; -template +template _ForwardIterator -__pattern_find_if(_ExecutionPolicy&&, _ForwardIterator, _ForwardIterator, _Predicate, _IsVector, - /*is_parallel=*/std::false_type) noexcept; +__pattern_find_if(_Tag __tag, _ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred) noexcept; -template +template _RandomAccessIterator -__pattern_find_if(_ExecutionPolicy&&, _RandomAccessIterator, _RandomAccessIterator, _Predicate, _IsVector, - /*is_parallel=*/std::true_type); +__pattern_find_if(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& __exec, _RandomAccessIterator __first, + _RandomAccessIterator __last, _Predicate __pred); //------------------------------------------------------------------------ // find_end diff --git a/pstl/include/pstl/internal/algorithm_impl.h b/pstl/include/pstl/internal/algorithm_impl.h --- a/pstl/include/pstl/internal/algorithm_impl.h +++ b/pstl/include/pstl/internal/algorithm_impl.h @@ -508,26 +508,26 @@ [&__pred](_RandomAccessIterator __it, _SizeType __i) { return __pred(__it[__i]); }); } -template +template _ForwardIterator -__pattern_find_if(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, - _IsVector __is_vector, - /*is_parallel=*/std::false_type) noexcept +__pattern_find_if(_Tag __tag, _ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred) noexcept { - return __internal::__brick_find_if(__first, __last, __pred, __is_vector); + return __internal::__brick_find_if(__first, __last, __pred, typename _Tag::__is_vector{}); } -template +template _RandomAccessIterator -__pattern_find_if(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last, - _Predicate __pred, _IsVector __is_vector, - /*is_parallel=*/std::true_type) +__pattern_find_if(__parallel_tag<_IsVector> __tag, _ExecutionPolicy&& __exec, _RandomAccessIterator __first, + _RandomAccessIterator __last, _Predicate __pred) { + using __backend_tag = typename decltype(__tag)::__backend_tag; + return __internal::__except_handler([&]() { return __internal::__parallel_find( - std::forward<_ExecutionPolicy>(__exec), __first, __last, - [__pred, __is_vector](_RandomAccessIterator __i, _RandomAccessIterator __j) { - return __internal::__brick_find_if(__i, __j, __pred, __is_vector); + __backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __first, __last, + [__pred](_RandomAccessIterator __i, _RandomAccessIterator __j) { + return __internal::__brick_find_if(__i, __j, __pred, _IsVector{}); }, std::less::difference_type>(), /*is_first=*/true); diff --git a/pstl/include/pstl/internal/execution_defs.h b/pstl/include/pstl/internal/execution_defs.h --- a/pstl/include/pstl/internal/execution_defs.h +++ b/pstl/include/pstl/internal/execution_defs.h @@ -153,6 +153,12 @@ using __enable_if_execution_policy = typename std::enable_if<__pstl::execution::is_execution_policy::type>::value, T>::type; + +template +struct __serial_tag; +template +struct __parallel_tag; + } // namespace __internal } // namespace __pstl diff --git a/pstl/include/pstl/internal/execution_impl.h b/pstl/include/pstl/internal/execution_impl.h --- a/pstl/include/pstl/internal/execution_impl.h +++ b/pstl/include/pstl/internal/execution_impl.h @@ -25,10 +25,23 @@ using namespace __pstl::execution; -template -struct __is_random_access_iterator - : std::is_same::iterator_category, - std::random_access_iterator_tag> +template +auto +__is_iterator_of(int) -> decltype( + std::conjunction>::iterator_category>...>{}); + +template +auto +__is_iterator_of(...) -> std::false_type; + +template +struct __is_random_access_iterator : decltype(__is_iterator_of(0)) +{ +}; + +template +struct __is_forward_iterator : decltype(__is_iterator_of(0)) { }; @@ -97,6 +110,80 @@ return {}; } +struct __serial_backend +{ +}; +struct __tbb_backend +{ +}; + +using __par_backend_tag = +#ifdef _PSTL_PAR_BACKEND_TBB + __tbb_backend; +#elif _PSTL_PAR_BACKEND_SERIAL + __serial_backend; +#else +# error "A parallel backend must be specified"; +#endif + +template +struct __serial_tag +{ + using __is_vector = _IsVector; +}; + +template +struct __parallel_tag +{ + using __is_vector = _IsVector; + // backend tag can be change depending on + // TBB availability in the environment + using __backend_tag = __par_backend_tag; +}; + +struct __parallel_forward_tag +{ + using __is_vector = std::false_type; + // backend tag can be change depending on + // TBB availability in the environment + using __backend_tag = __par_backend_tag; +}; + +template +using __tag_type = + typename std::conditional<__internal::__is_random_access_iterator<_IteratorTypes...>::value, + __parallel_tag<_IsVector>, + typename std::conditional<__is_forward_iterator<_IteratorTypes...>::value, + __parallel_forward_tag, __serial_tag<_IsVector>>::type>::type; + +template +__serial_tag +__select_backend(std::execution::sequenced_policy, _IteratorTypes&&...) +{ + return {}; +} + +template +__serial_tag<__internal::__is_random_access_iterator<_IteratorTypes...>> +__select_backend(std::execution::unsequenced_policy, _IteratorTypes&&...) +{ + return {}; +} + +template +__tag_type +__select_backend(std::execution::parallel_policy, _IteratorTypes&&...) +{ + return {}; +} + +template +__tag_type<__internal::__is_random_access_iterator<_IteratorTypes...>, _IteratorTypes...> +__select_backend(std::execution::parallel_unsequenced_policy, _IteratorTypes&&...) +{ + return {}; +} + } // namespace __internal } // namespace __pstl diff --git a/pstl/include/pstl/internal/glue_algorithm_impl.h b/pstl/include/pstl/internal/glue_algorithm_impl.h --- a/pstl/include/pstl/internal/glue_algorithm_impl.h +++ b/pstl/include/pstl/internal/glue_algorithm_impl.h @@ -84,10 +84,10 @@ __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator> find_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - return __pstl::__internal::__pattern_find_if( - std::forward<_ExecutionPolicy>(__exec), __first, __last, __pred, - __pstl::__internal::__is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec), - __pstl::__internal::__is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec)); + auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first); + + return __pstl::__internal::__pattern_find_if(__dispatch_tag, std::forward<_ExecutionPolicy>(__exec), __first, + __last, __pred); } template diff --git a/pstl/include/pstl/internal/parallel_backend_serial.h b/pstl/include/pstl/internal/parallel_backend_serial.h --- a/pstl/include/pstl/internal/parallel_backend_serial.h +++ b/pstl/include/pstl/internal/parallel_backend_serial.h @@ -59,6 +59,13 @@ __f(__first, __last); } +template +void +__parallel_for(__pstl::__internal::__serial_backend, _ExecutionPolicy&&, _Index __first, _Index __last, _Fp __f) +{ + __f(__first, __last); +} + template _Value __parallel_reduce(_ExecutionPolicy&&, _Index __first, _Index __last, const _Value& __identity, diff --git a/pstl/include/pstl/internal/parallel_backend_tbb.h b/pstl/include/pstl/internal/parallel_backend_tbb.h --- a/pstl/include/pstl/internal/parallel_backend_tbb.h +++ b/pstl/include/pstl/internal/parallel_backend_tbb.h @@ -102,7 +102,7 @@ // wrapper over tbb::parallel_for template void -__parallel_for(_ExecutionPolicy&&, _Index __first, _Index __last, _Fp __f) +__parallel_for(__tbb_backend, _ExecutionPolicy&&, _Index __first, _Index __last, _Fp __f) { tbb::this_task_arena::isolate([=]() { tbb::parallel_for(tbb::blocked_range<_Index>(__first, __last), __parallel_for_body<_Index, _Fp>(__f)); diff --git a/pstl/include/pstl/internal/parallel_impl.h b/pstl/include/pstl/internal/parallel_impl.h --- a/pstl/include/pstl/internal/parallel_impl.h +++ b/pstl/include/pstl/internal/parallel_impl.h @@ -28,16 +28,17 @@ //----------------------------------------------------------------------- /** Return extremum value returned by brick f[i,j) for subranges [i,j) of [first,last) Each f[i,j) must return a value in [i,j). */ -template +template _Index -__parallel_find(_ExecutionPolicy&& __exec, _Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) +__parallel_find(_BackendTag __tag, _ExecutionPolicy&& __exec, _Index __first, _Index __last, _Brick __f, + _Compare __comp, bool __b_first) { typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType; const _DifferenceType __n = __last - __first; _DifferenceType __initial_dist = __b_first ? __n : -1; std::atomic<_DifferenceType> __extremum(__initial_dist); // TODO: find out what is better here: parallel_for or parallel_reduce - __par_backend::__parallel_for(std::forward<_ExecutionPolicy>(__exec), __first, __last, + __par_backend::__parallel_for(__tag, std::forward<_ExecutionPolicy>(__exec), __first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) { // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of // why using a shared variable scales fairly well in this situation.