diff --git a/CHANGES b/CHANGES index 0eba4f74d49..c7872689cf0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,19 @@ ------------------------------------------------------------------------ The list of most significant changes made over time in Parallel STL. +Parallel STL 20180329 release +PSTL_VERSION == 104 + +Features / APIs: + +- More algorithms support parallel and vector execution policies: + find_first_of, is_heap, is_heap_until, replace, replace_if. +- More algorithms support vector execution policies: + remove, remove_if. +- More algorithms support parallel execution policies: + partial_sort. + +------------------------------------------------------------------------ Parallel STL release within Intel(R) Parallel Studio XE 2018 Update 2 PSTL_VERSION == 103 diff --git a/README.md b/README.md index 0ed2511e188..a12f0bf9595 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Parallel STL -[![Stable release](https://img.shields.io/badge/version-20180322-green.svg)](https://github.com/intel/parallelstl/releases/tag/20180322) +[![Stable release](https://img.shields.io/badge/version-20180329-green.svg)](https://github.com/intel/parallelstl/releases/tag/20180329) [![Apache License Version 2.0](https://img.shields.io/badge/license-Apache_2.0-green.svg)](LICENSE) Parallel STL is an implementation of the C++ standard library algorithms with support for execution policies, diff --git a/build/Makefile.common b/build/Makefile.common index 9adbcc7df4b..cbfd370683d 100644 --- a/build/Makefile.common +++ b/build/Makefile.common @@ -98,6 +98,7 @@ OPTIMIZATION_DISABLED_FLAGS += $(XHOST_FLAG) ifeq ($(cfg), debug) TBB_LIB_NAME = tbb_debug BACKEND_MACRO += -DTBB_USE_DEBUG=1 + DEBUG_MACRO += -DPSTL_USE_DEBUG OPTIMIZATION_KEYS = $(OPTIMIZATION_DISABLED_FLAGS) else OPTIMIZATION_KEYS = $(OPTIMIZATION_ENABLED_FLAGS) @@ -108,6 +109,7 @@ DYN_LDFLAGS += $(PSTL_ARCH) CPLUS_FLAGS += $(TEST_MACRO) CPLUS_FLAGS += $(INCLUDES) CPLUS_FLAGS += $(BACKEND_MACRO) +CPLUS_FLAGS += $(DEBUG_MACRO) CPLUS_FLAGS += $(CXXFLAGS) CPLUS_FLAGS += $(OPTIMIZATION_KEYS) diff --git a/examples/gamma_correction/gamma_correction.cpp b/examples/gamma_correction/gamma_correction.cpp index f59cebb729d..2be4100136a 100644 --- a/examples/gamma_correction/gamma_correction.cpp +++ b/examples/gamma_correction/gamma_correction.cpp @@ -66,9 +66,9 @@ void applyGamma(Rows& image, double g) { typedef decltype(image[0][0]) Pixel; const int w = image[1] - image[0]; - //execution STL algorithms with execution policies - std::execution::par and std::execution::unseq - std::for_each(std::execution::par, image.begin(), image.end(), [g, w](Row& r) { - std::transform(std::execution::unseq, r, r+w, r, [g](Pixel& p) { + //execution STL algorithms with execution policies - pstl::execution::par and pstl::execution::unseq + std::for_each(pstl::execution::par, image.begin(), image.end(), [g, w](Row& r) { + std::transform(pstl::execution::unseq, r, r+w, r, [g](Pixel& p) { double v = 0.3*p.bgra[2] + 0.59*p.bgra[1] + 0.11*p.bgra[0]; //RGB Luminance value assert(v > 0); double res = pow(v, g); diff --git a/include/pstl/algorithm b/include/pstl/algorithm index 340a8df2a27..8c4048ec41d 100644 --- a/include/pstl/algorithm +++ b/include/pstl/algorithm @@ -18,8 +18,8 @@ */ -#ifndef __PSTL_algorithm_H -#define __PSTL_algorithm_H +#ifndef __PSTL_algorithm +#define __PSTL_algorithm #include @@ -80,27 +80,27 @@ for_each_n(ExecutionPolicy&& exec, InputIterator first, Size n, Function f) { // [alg.find] -template -pstl::internal::enable_if_execution_policy -find_if(ExecutionPolicy&& exec, InputIterator first, InputIterator last, Predicate pred) { +template +pstl::internal::enable_if_execution_policy +find_if(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred) { using namespace pstl::internal; return pattern_find_if( first, last, pred, - is_vectorization_preferred(exec), - is_parallelization_preferred(exec)); + is_vectorization_preferred(exec), + is_parallelization_preferred(exec)); } -template -pstl::internal::enable_if_execution_policy -find_if_not(ExecutionPolicy&& exec, InputIterator first, InputIterator last, +template +pstl::internal::enable_if_execution_policy +find_if_not(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred) { - return find_if(exec, first, last, pstl::internal::not_pred(pred)); + return find_if(std::forward(exec), first, last, pstl::internal::not_pred(pred)); } -template -pstl::internal::enable_if_execution_policy -find(ExecutionPolicy&& exec, InputIterator first, InputIterator last, +template +pstl::internal::enable_if_execution_policy +find(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& value) { - return find_if(exec, first, last, pstl::internal::equal_value(value)); + return find_if(std::forward(exec), first, last, pstl::internal::equal_value(value)); } // [alg.find.end] @@ -116,32 +116,31 @@ find_end(ExecutionPolicy &&exec, ForwardIterator1 first, ForwardIterator1 last, template pstl::internal::enable_if_execution_policy find_end(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 s_first, ForwardIterator2 s_last) { - return find_end(exec, first, last, s_first, s_last, std::equal_to::value_type>()); + return find_end(std::forward(exec), first, last, s_first, s_last, pstl::internal::pstl_equal()); } // [alg.find_first_of] -template -pstl::internal::enable_if_execution_policy -find_first_of(ExecutionPolicy&& exec, InputIterator first, InputIterator last, ForwardIterator s_first, ForwardIterator s_last, BinaryPredicate pred) { +template +pstl::internal::enable_if_execution_policy +find_first_of(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 s_first, ForwardIterator2 s_last, BinaryPredicate pred) { using namespace pstl::internal; return pattern_find_first_of(first, last, s_first, s_last, pred, - is_vectorization_preferred(exec), - is_parallelization_preferred(exec)); + is_vectorization_preferred(exec), + is_parallelization_preferred(exec)); } -template -pstl::internal::enable_if_execution_policy -find_first_of(ExecutionPolicy&& exec, InputIterator first, InputIterator last, ForwardIterator s_first, ForwardIterator s_last) { - return find_first_of(exec, first, last, s_first, s_last, std::equal_to::value_type>()); +template +pstl::internal::enable_if_execution_policy +find_first_of(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 s_first, ForwardIterator2 s_last) { + return find_first_of(std::forward(exec), first, last, s_first, s_last, pstl::internal::pstl_equal()); } // [alg.adjacent_find] template< class ExecutionPolicy, class ForwardIt > pstl::internal::enable_if_execution_policy adjacent_find(ExecutionPolicy&& exec, ForwardIt first, ForwardIt last) { - typedef typename iterator_traits::value_type value_type; using namespace pstl::internal; - return pattern_adjacent_find(first, last, std::equal_to(), + return pattern_adjacent_find(first, last, pstl::internal::pstl_equal(), is_parallelization_preferred(exec), is_vectorization_preferred(exec), /*first_semantic*/ false); } @@ -160,23 +159,23 @@ adjacent_find(ExecutionPolicy&& exec, ForwardIt first, ForwardIt last, BinaryPre // Implementation note: count and count_if call the pattern directly instead of calling std::transform_reduce // so that we do not have to include . -template -pstl::internal::enable_if_execution_policy::difference_type> -count(ExecutionPolicy&& exec, InputIterator first, InputIterator last, const T& value) { - typedef typename iterator_traits::value_type value_type; +template +pstl::internal::enable_if_execution_policy::difference_type> +count(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& value) { + typedef typename iterator_traits::reference value_type; using namespace pstl::internal; - return pattern_count(first, last, [&value](value_type x) {return value==x;}, - is_parallelization_preferred(exec), - is_vectorization_preferred(exec)); + return pattern_count(first, last, [&value](const value_type x) {return value==x;}, + is_parallelization_preferred(exec), + is_vectorization_preferred(exec)); } -template -pstl::internal::enable_if_execution_policy::difference_type> -count_if(ExecutionPolicy&& exec, InputIterator first, InputIterator last, Predicate pred) { +template +pstl::internal::enable_if_execution_policy::difference_type> +count_if(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Predicate pred) { using namespace pstl::internal; return pattern_count(first, last, pred, - is_parallelization_preferred(exec), - is_vectorization_preferred(exec)); + is_parallelization_preferred(exec), + is_vectorization_preferred(exec)); } // [alg.search] @@ -193,9 +192,7 @@ search(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, Fo template pstl::internal::enable_if_execution_policy search(ExecutionPolicy&& exec, ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 s_first, ForwardIterator2 s_last) { - typedef typename iterator_traits::value_type value_type; - - return search(exec, first, last, s_first, s_last, std::equal_to()); + return search(std::forward(exec), first, last, s_first, s_last, pstl::internal::pstl_equal()); } template @@ -210,7 +207,7 @@ search_n(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Si template pstl::internal::enable_if_execution_policy search_n(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Size count, const T& value) { - return search_n(exec, first, last, count, value, std::equal_to::value_type>()); + return search_n(std::forward(exec), first, last, count, value, pstl::internal::pstl_equal()); } // [alg.copy] @@ -265,11 +262,11 @@ swap_ranges(ExecutionPolicy&& exec, ForwardIterator1 first1, ForwardIterator1 la template pstl::internal::enable_if_execution_policy transform( ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op ) { - typedef typename iterator_traits::value_type input_type; - typedef typename iterator_traits::value_type output_type; + typedef typename iterator_traits::reference input_type; + typedef typename iterator_traits::reference output_type; using namespace pstl::internal; return pattern_walk2(first, last, result, - [op](input_type x, output_type& y ) mutable { y = op(x);}, + [op](input_type x, output_type y ) mutable { y = op(x);}, is_vectorization_preferred(exec), is_parallelization_preferred(exec)); } @@ -277,11 +274,11 @@ transform( ExecutionPolicy&& exec, InputIterator first, InputIterator last, Outp template pstl::internal::enable_if_execution_policy transform( ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryOperation op ) { - typedef typename iterator_traits::value_type input1_type; - typedef typename iterator_traits::value_type input2_type; - typedef typename iterator_traits::value_type output_type; + typedef typename iterator_traits::reference input1_type; + typedef typename iterator_traits::reference input2_type; + typedef typename iterator_traits::reference output_type; using namespace pstl::internal; - return pattern_walk3(first1, last1, first2, result, [op]( input1_type x, input2_type y, output_type& z ) mutable {z = op(x,y);}, + return pattern_walk3(first1, last1, first2, result, [op](input1_type x, input2_type y, output_type z ) mutable {z = op(x,y);}, is_vectorization_preferred(exec), is_parallelization_preferred(exec)); } @@ -292,7 +289,12 @@ template replace_if(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, UnaryPredicate pred, const T& new_value) { using namespace pstl::internal; - pattern_replace_if(first, last, pred, new_value, + typedef typename iterator_traits::reference element_type; + pattern_walk1(first, last, [&pred, &new_value] (element_type elem) { + if (pred(elem)) { + elem = new_value; + } + }, is_vectorization_preferred(exec), is_parallelization_preferred(exec)); } @@ -300,18 +302,18 @@ replace_if(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, template pstl::internal::enable_if_execution_policy replace(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value) { - replace_if(exec, first, last, pstl::internal::equal_value(old_value), new_value); + replace_if(std::forward(exec), first, last, pstl::internal::equal_value(old_value), new_value); } template pstl::internal::enable_if_execution_policy replace_copy_if(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result, UnaryPredicate pred, const T& new_value) { - typedef typename iterator_traits::value_type input_type; - typedef typename iterator_traits::value_type output_type; + typedef typename iterator_traits::reference input_type; + typedef typename iterator_traits::reference output_type; using namespace pstl::internal; return pattern_walk2( first, last, result, - [pred, &new_value](input_type x, output_type& y) mutable { y = pred(x) ? new_value : x; }, + [pred, &new_value](input_type x, output_type y) mutable { y = pred(x) ? new_value : x; }, is_vectorization_preferred(exec), is_parallelization_preferred(exec)); } @@ -319,7 +321,7 @@ replace_copy_if(ExecutionPolicy&& exec, InputIterator first, InputIterator last, template pstl::internal::enable_if_execution_policy replace_copy(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value) { - return replace_copy_if(exec, first, last, result, pstl::internal::equal_value(old_value), new_value); + return replace_copy_if(std::forward(exec), first, last, result, pstl::internal::equal_value(old_value), new_value); } // [alg.fill] @@ -372,13 +374,13 @@ generate_n( ExecutionPolicy&& exec, OutputIterator first, Size count, Generator template pstl::internal::enable_if_execution_policy remove_copy_if(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result, Predicate pred) { - return copy_if( exec, first, last, result, pstl::internal::not_pred(pred)); + return copy_if(std::forward(exec), first, last, result, pstl::internal::not_pred(pred)); } template pstl::internal::enable_if_execution_policy remove_copy(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result, const T& value) { - return copy_if( exec, first, last, result, pstl::internal::not_equal_value(value)); + return copy_if(std::forward(exec), first, last, result, pstl::internal::not_equal_value(value)); } template @@ -393,7 +395,7 @@ remove_if(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, U template pstl::internal::enable_if_execution_policy remove(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, const T& value) { - return remove_if(exec, first, last, pstl::internal::equal_value(value)); + return remove_if(std::forward(exec), first, last, pstl::internal::equal_value(value)); } // [alg.unique] @@ -410,7 +412,7 @@ unique(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, Bina template pstl::internal::enable_if_execution_policy unique(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { - return unique(exec, first, last, pstl::internal::pstl_equal()); + return unique(std::forward(exec), first, last, pstl::internal::pstl_equal()); } template @@ -425,7 +427,7 @@ unique_copy(ExecutionPolicy&& exec, InputIterator first, InputIterator last, Out template pstl::internal::enable_if_execution_policy unique_copy(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result) { - return unique_copy( exec, first, last, result, pstl::internal::pstl_equal() ); + return unique_copy(std::forward(exec), first, last, result, pstl::internal::pstl_equal() ); } // [alg.reverse] @@ -522,8 +524,7 @@ sort(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator la template pstl::internal::enable_if_execution_policy sort(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { - typedef typename iterator_traits::value_type input_type; - sort(exec, first, last, std::less()); + sort(std::forward(exec), first, last, pstl::internal::pstl_less()); } // [stable.sort] @@ -531,7 +532,6 @@ sort(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator la template pstl::internal::enable_if_execution_policy stable_sort(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last, Compare comp) { - typedef typename iterator_traits::value_type input_type; using namespace pstl::internal; return pattern_stable_sort(first, last, comp, is_vectorization_preferred(exec), @@ -541,8 +541,7 @@ stable_sort(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIter template pstl::internal::enable_if_execution_policy stable_sort(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { - typedef typename iterator_traits::value_type input_type; - stable_sort(exec, first, last, std::less()); + stable_sort(std::forward(exec), first, last, pstl::internal::pstl_less()); } // [mismatch] @@ -559,20 +558,19 @@ mismatch(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, In template< class ExecutionPolicy, class InputIterator1, class InputIterator2, class BinaryPredicate > pstl::internal::enable_if_execution_policy> mismatch(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, BinaryPredicate pred) { - return mismatch(exec, first1, last1, first2, std::next(first2, std::distance(first1, last1)), pred); + return mismatch(std::forward(exec), first1, last1, first2, std::next(first2, std::distance(first1, last1)), pred); } template< class ExecutionPolicy, class InputIterator1, class InputIterator2 > pstl::internal::enable_if_execution_policy> mismatch(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { - typedef typename iterator_traits::value_type value_type; - return mismatch(exec, first1, last1, first2, last2, std::equal_to()); + return mismatch(std::forward(exec), first1, last1, first2, last2, pstl::internal::pstl_equal()); } template< class ExecutionPolicy, class InputIterator1, class InputIterator2 > pstl::internal::enable_if_execution_policy> mismatch(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2) { - return mismatch(exec, first1, last1, first2, std::next(first2, std::distance(first1, last1))); + return mismatch(std::forward(exec), first1, last1, first2, std::next(first2, std::distance(first1, last1))); } // [alg.equal] @@ -590,7 +588,7 @@ equal(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, Input template pstl::internal::enable_if_execution_policy equal(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2) { - return equal(exec, first1, last1, first2, pstl::internal::pstl_equal()); + return equal(std::forward(exec), first1, last1, first2, pstl::internal::pstl_equal()); } template @@ -634,8 +632,7 @@ partial_sort(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIte template pstl::internal::enable_if_execution_policy partial_sort(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) { - typedef typename iterator_traits::value_type input_type; - partial_sort(exec, first, middle, last, std::less()); + partial_sort(std::forward(exec), first, middle, last, pstl::internal::pstl_less()); } // [partial.sort.copy] @@ -652,8 +649,7 @@ partial_sort_copy(ExecutionPolicy&& exec, InputIterator first, InputIterator las template pstl::internal::enable_if_execution_policy partial_sort_copy(ExecutionPolicy&& exec, InputIterator first, InputIterator last, RandomAccessIterator d_first, RandomAccessIterator d_last) { - typedef typename iterator_traits::value_type input_type; - return partial_sort_copy(exec, first, last, d_first, d_last, std::less()); + return partial_sort_copy(std::forward(exec), first, last, d_first, d_last, pstl::internal::pstl_less()); } // [is.sorted] @@ -670,8 +666,7 @@ is_sorted_until(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator l template pstl::internal::enable_if_execution_policy is_sorted_until(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { - typedef typename iterator_traits::value_type input_type; - return is_sorted_until(exec, first, last, std::less()); + return is_sorted_until(std::forward(exec), first, last, pstl::internal::pstl_less()); } template @@ -686,8 +681,7 @@ is_sorted(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, C template pstl::internal::enable_if_execution_policy is_sorted(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { - typedef typename iterator_traits::value_type input_type; - return is_sorted(exec, first, last, std::less()); + return is_sorted(std::forward(exec), first, last, pstl::internal::pstl_less()); } // [alg.nth.element] @@ -704,8 +698,7 @@ nth_element(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIter template pstl::internal::enable_if_execution_policy nth_element(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last) { - typedef typename iterator_traits::value_type input_type; - nth_element(exec, first, nth, last, std::less()); + nth_element(std::forward(exec), first, nth, last, pstl::internal::pstl_less()); } // [alg.merge] @@ -721,8 +714,7 @@ merge(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, Input template< class ExecutionPolicy, class InputIterator1, class InputIterator2, class OutputIterator> pstl::internal::enable_if_execution_policy merge(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator d_first) { - typedef typename iterator_traits::value_type value_type; - return merge(exec, first1, last1, first2, last2, d_first, std::less()); + return merge(std::forward(exec), first1, last1, first2, last2, d_first, pstl::internal::pstl_less()); } template< class ExecutionPolicy, class BidirectionalIterator, class Compare> @@ -737,8 +729,7 @@ inplace_merge(ExecutionPolicy&& exec, BidirectionalIterator first, Bidirectional template< class ExecutionPolicy, class BidirectionalIterator> pstl::internal::enable_if_execution_policy inplace_merge(ExecutionPolicy&& exec, BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) { - typedef typename iterator_traits::value_type input_type; - inplace_merge(exec, first, middle, last, std::less()); + inplace_merge(std::forward(exec), first, middle, last, pstl::internal::pstl_less()); } // [includes] @@ -755,8 +746,7 @@ includes(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, In template< class ExecutionPolicy, class InputIterator1, class InputIterator2> pstl::internal::enable_if_execution_policy includes(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { - typedef typename iterator_traits::value_type value_type; - return includes(exec, first1, last1, first2, last2, std::less()); + return includes(std::forward(exec), first1, last1, first2, last2, pstl::internal::pstl_less()); } // [set.union] @@ -774,8 +764,7 @@ template set_union(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) { - typedef typename iterator_traits::value_type value_type; - return set_union(exec, first1, last1, first2, last2, result, std::less()); + return set_union(std::forward(exec), first1, last1, first2, last2, result, pstl::internal::pstl_less()); } // [set.intersection] @@ -792,8 +781,7 @@ set_intersection(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 l template pstl::internal::enable_if_execution_policy set_intersection(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) { - typedef typename iterator_traits::value_type value_type; - return set_intersection(exec, first1, last1, first2, last2, result, std::less()); + return set_intersection(std::forward(exec), first1, last1, first2, last2, result, pstl::internal::pstl_less()); } // [set.difference] @@ -810,8 +798,7 @@ set_difference(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 las template pstl::internal::enable_if_execution_policy set_difference(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) { - typedef typename iterator_traits::value_type value_type; - return set_difference(exec, first1, last1, first2, last2, result, std::less()); + return set_difference(std::forward(exec), first1, last1, first2, last2, result, pstl::internal::pstl_less()); } // [set.symmetric.difference] @@ -828,11 +815,13 @@ set_symmetric_difference(ExecutionPolicy&& exec, InputIterator1 first1, InputIte template pstl::internal::enable_if_execution_policy set_symmetric_difference(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) { - typedef typename iterator_traits::value_type value_type; - return set_symmetric_difference(exec, first1, last1, first2, last2, result, std::less()); + return set_symmetric_difference(std::forward(exec), first1, last1, first2, last2, result, pstl::internal::pstl_less()); } // [is.heap] +// According to standard: +// A heap is a particular organization of elements in a range between two random access iterators +// [a, b) such that with N = b - a, for all i, 0 < i < N, comp(a[(i-1)/2], a[i]) is false template< class ExecutionPolicy, class RandomAccessIterator, class Compare > pstl::internal::enable_if_execution_policy is_heap_until(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last, Compare comp) { @@ -845,21 +834,22 @@ is_heap_until(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIt template< class ExecutionPolicy, class RandomAccessIterator > pstl::internal::enable_if_execution_policy is_heap_until(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { - typedef typename iterator_traits::value_type input_type; - return is_heap_until(exec, first, last, std::less()); + return is_heap_until(std::forward(exec), first, last, pstl::internal::pstl_less()); } template< class ExecutionPolicy, class RandomAccessIterator, class Compare > pstl::internal::enable_if_execution_policy is_heap(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last, Compare comp) { - return is_heap_until(exec, first, last, comp) == last; + using namespace pstl::internal; + return pattern_is_heap_until(first, last, comp, + is_vectorization_preferred(exec), + is_parallelization_preferred(exec)) == last; } template< class ExecutionPolicy, class RandomAccessIterator > pstl::internal::enable_if_execution_policy is_heap(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { - typedef typename iterator_traits::value_type input_type; - return is_heap(exec, first, last, std::less()); + return is_heap(std::forward(exec), first, last, pstl::internal::pstl_less()); } // [alg.min.max] @@ -876,8 +866,7 @@ min_element(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, template< class ExecutionPolicy, class ForwardIterator > pstl::internal::enable_if_execution_policy min_element(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { - typedef typename iterator_traits::value_type input_type; - return min_element(exec, first, last, std::less()); + return min_element(std::forward(exec), first, last, pstl::internal::pstl_less()); } template< class ExecutionPolicy, class ForwardIterator, class Compare > @@ -892,8 +881,8 @@ max_element(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, template< class ExecutionPolicy, class ForwardIterator > pstl::internal::enable_if_execution_policy max_element(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { - typedef typename iterator_traits::value_type input_type; - return min_element(exec, first, last, pstl::internal::reorder_pred >(std::less())); + using namespace pstl::internal; + return min_element(std::forward(exec), first, last, reorder_pred(pstl_less())); } template< class ExecutionPolicy, class ForwardIterator, class Compare > @@ -908,8 +897,7 @@ minmax_element(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator la template< class ExecutionPolicy, class ForwardIterator > pstl::internal::enable_if_execution_policy> minmax_element(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { - typedef typename iterator_traits::value_type value_type; - return minmax_element(exec, first, last, std::less()); + return minmax_element(std::forward(exec), first, last, pstl::internal::pstl_less()); } // [alg.lex.comparison] @@ -925,11 +913,10 @@ lexicographical_compare(ExecutionPolicy&& exec, InputIterator1 first1, InputIter template< class ExecutionPolicy, class InputIterator1, class InputIterator2 > pstl::internal::enable_if_execution_policy -lexicographical_compare(ExecutionPolicy&& policy, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { - typedef typename iterator_traits::value_type value_type; - return lexicographical_compare(policy, first1, last1, first2, last2, std::less()); +lexicographical_compare(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { + return lexicographical_compare(std::forward(exec), first1, last1, first2, last2, pstl::internal::pstl_less()); } } // namespace std -#endif /* __PSTL_algorithm_H */ +#endif /* __PSTL_algorithm */ diff --git a/include/pstl/execution b/include/pstl/execution index 4f589765126..e51c9b53c11 100644 --- a/include/pstl/execution +++ b/include/pstl/execution @@ -18,8 +18,8 @@ */ -#ifndef __PSTL_execution_policy_H -#define __PSTL_execution_policy_H +#ifndef __PSTL_execution_policy +#define __PSTL_execution_policy #include #include "internal/pstl_config.h" @@ -129,4 +129,4 @@ namespace std { __PSTL_PRAGMA_MESSAGE_POLICIES("The execution policies are injected into the standard namespace std::execution") #endif -#endif /* __PSTL_execution_policy_H */ +#endif /* __PSTL_execution_policy */ diff --git a/include/pstl/internal/algorithm_impl.h b/include/pstl/internal/algorithm_impl.h index ad8f4eb9ffb..38e8c30cc7e 100644 --- a/include/pstl/internal/algorithm_impl.h +++ b/include/pstl/internal/algorithm_impl.h @@ -440,28 +440,30 @@ bool pattern_equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 f //------------------------------------------------------------------------ // find_if //------------------------------------------------------------------------ -template -InputIterator brick_find_if(InputIterator first, InputIterator last, Predicate pred, /*is_vector=*/std::false_type) noexcept { +template +ForwardIterator brick_find_if(ForwardIterator first, ForwardIterator last, Predicate pred, /*is_vector=*/std::false_type) noexcept { return std::find_if(first, last, pred); } -template -InputIterator brick_find_if(InputIterator first, InputIterator last, Predicate pred, /*is_vector=*/std::true_type) noexcept { - return unseq_backend::simd_first(first, last-first, pred); +template +ForwardIterator brick_find_if(ForwardIterator first, ForwardIterator last, Predicate pred, /*is_vector=*/std::true_type) noexcept { + typedef typename std::iterator_traits::difference_type size_type; + return unseq_backend::simd_first(first, size_type(0), last - first, + [&pred](ForwardIterator it, size_type i) {return pred(it[i]); }); } -template -InputIterator pattern_find_if( InputIterator first, InputIterator last, Predicate pred, IsVector is_vector, /*is_parallel=*/std::false_type ) noexcept { +template +ForwardIterator pattern_find_if(ForwardIterator first, ForwardIterator last, Predicate pred, IsVector is_vector, /*is_parallel=*/std::false_type ) noexcept { return brick_find_if(first,last,pred,is_vector); } -template -InputIterator pattern_find_if(InputIterator first, InputIterator last, Predicate pred, IsVector is_vector, /*is_parallel=*/std::true_type) { +template +ForwardIterator pattern_find_if(ForwardIterator first, ForwardIterator last, Predicate pred, IsVector is_vector, /*is_parallel=*/std::true_type) { return except_handler([=]() { - return internal::parallel_find(first, last, [pred, is_vector](InputIterator i, InputIterator j) { + return internal::parallel_find(first, last, [pred, is_vector](ForwardIterator i, ForwardIterator j) { return brick_find_if(i, j, pred, is_vector); }, - std::less::difference_type>(), /*is_first=*/true); + std::less::difference_type>(), /*is_first=*/true); }); } @@ -476,33 +478,39 @@ template::value_type value_type; + typedef typename std::iterator_traits::value_type value_type; auto n2 = s_last - s_first; - if (n2 < 1) + if (n2 < 1) { return b_first ? first : last; + } auto n1 = global_last - first; - if (n1 < n2) + if (n1 < n2) { return last; + } auto cur = last; while (first != last && (global_last - first >= n2)) { // find position of *s_first in [first, last) (it can be start of subsequence) first = brick_find_if(first, last, - [&s_first, &pred](const value_type& val) {return pred(val, *s_first); }, is_vector); + equal_value_by_pred(*s_first, pred), is_vector); // if position that was found previously is the start of subsequence // then we can exit the loop (b_first == true) or keep the position // (b_first == false) if (first != last && (global_last - first >= n2) && brick_equal(s_first + 1, s_last, first + 1, pred, is_vector)) { - if (b_first) + if (b_first) { return first; - else + } + else { cur = first; + } } - else if (first == last) + else if (first == last) { break; + } + else {} // in case of b_first == false we try to find new start position // for the next subsequence @@ -515,11 +523,12 @@ templatebool {return pred(val, value); }; + auto unary_pred = equal_value_by_pred(value, pred); while (first != last && (global_last - first >= count)) { first = brick_find_if(first, last, unary_pred, is_vector); @@ -528,10 +537,12 @@ ForwardIterator find_subrange(ForwardIterator first, ForwardIterator last, !brick_any_of(first + 1, first + count, not_pred(unary_pred), is_vector)) { return first; } - else if (first == last) + else if (first == last) { break; - else + } + else { ++first; + } } return last; } @@ -570,26 +581,29 @@ ForwardIterator1 pattern_find_end(ForwardIterator1 first, ForwardIterator1 last, //------------------------------------------------------------------------ // find_first_of //------------------------------------------------------------------------ -template -InputIterator brick_find_first_of(InputIterator first, InputIterator last, ForwardIterator s_first, ForwardIterator s_last, BinaryPredicate pred, /*is_vector=*/std::false_type) noexcept { +template +ForwardIterator1 brick_find_first_of(ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 s_first, ForwardIterator2 s_last, BinaryPredicate pred, /*is_vector=*/std::false_type) noexcept { return std::find_first_of(first, last, s_first, s_last, pred); } -template -InputIterator brick_find_first_of(InputIterator first, InputIterator last, ForwardIterator s_first, ForwardIterator s_last, BinaryPredicate pred, /*is_vector=*/std::true_type) noexcept { - __PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial"); - return std::find_first_of(first, last, s_first, s_last, pred); +template +ForwardIterator1 brick_find_first_of(ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 s_first, ForwardIterator2 s_last, BinaryPredicate pred, /*is_vector=*/std::true_type) noexcept { + return unseq_backend::simd_find_first_of(first, last, s_first, s_last, pred); } -template -InputIterator pattern_find_first_of(InputIterator first, InputIterator last, ForwardIterator s_first, ForwardIterator s_last, BinaryPredicate pred, IsVector is_vector, /*is_parallel=*/std::false_type) noexcept { +template +ForwardIterator1 pattern_find_first_of(ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 s_first, ForwardIterator2 s_last, BinaryPredicate pred, IsVector is_vector, /*is_parallel=*/std::false_type) noexcept { return brick_find_first_of(first, last, s_first, s_last, pred, is_vector); } -template -InputIterator pattern_find_first_of(InputIterator first, InputIterator last, ForwardIterator s_first, ForwardIterator s_last, BinaryPredicate pred, IsVector is_vector, /*is_parallel=*/std::true_type) noexcept { - __PSTL_PRAGMA_MESSAGE("Parallel algorithm unimplemented, redirected to serial"); - return brick_find_first_of(first, last, s_first, s_last, pred, is_vector); +template +ForwardIterator1 pattern_find_first_of(ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 s_first, ForwardIterator2 s_last, BinaryPredicate pred, IsVector is_vector, /*is_parallel=*/std::true_type) noexcept { + return except_handler([=]() { + return internal::parallel_find(first, last, [s_first, s_last, pred, is_vector](ForwardIterator1 i, ForwardIterator1 j) { + return brick_find_first_of(i, j, s_first, s_last, pred, is_vector); + }, + std::less::difference_type>(), /*is_first=*/true); + }); } //------------------------------------------------------------------------ @@ -971,32 +985,6 @@ ForwardIterator2 pattern_swap_ranges(ForwardIterator1 first1, ForwardIterator1 l return brick_swap_ranges(first1, last1, first2, is_vector); } -//------------------------------------------------------------------------ -// replace -//------------------------------------------------------------------------ - -template -void brick_replace_if(ForwardIterator first, ForwardIterator last, UnaryPredicate pred, const T& new_value, /*is_vector=*/std::false_type) noexcept { - std::replace_if(first, last, pred, new_value); -} - -template -void brick_replace_if(ForwardIterator first, ForwardIterator last, UnaryPredicate pred, const T& new_value, /*is_vector=*/std::true_type) noexcept { - __PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial"); - brick_replace_if(first, last, pred, new_value, std::false_type()); -} - -template -void pattern_replace_if(ForwardIterator first, ForwardIterator last, UnaryPredicate pred, const T& new_value, IsVector is_vector, /*parallel=*/std::false_type) noexcept { - brick_replace_if(first, last, pred, new_value, is_vector); -} - -template -void pattern_replace_if(ForwardIterator first, ForwardIterator last, UnaryPredicate pred, const T& new_value, IsVector is_vector, /*parallel=*/std::true_type) noexcept { - __PSTL_PRAGMA_MESSAGE("Parallel algorithm unimplemented, redirected to serial"); - brick_replace_if(first, last, pred, new_value, is_vector); -} - //------------------------------------------------------------------------ // reverse //------------------------------------------------------------------------ @@ -1293,26 +1281,14 @@ void pattern_stable_sort(RandomAccessIterator first, RandomAccessIterator last, // partial_sort //------------------------------------------------------------------------ -template -void brick_partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare comp, /*is_vector=*/std::false_type) noexcept { - std::partial_sort(first, middle, last, comp); -} - -template -void brick_partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare comp, /*is_vector=*/std::true_type) noexcept { - __PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial"); - std::partial_sort(first, middle, last, comp); -} - template -void pattern_partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare comp, IsVector is_vector, /*is_parallel=*/std::false_type) noexcept { - brick_partial_sort(first, middle, last, comp, is_vector); +void pattern_partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare comp, IsVector, /*is_parallel=*/std::false_type) noexcept { + std::partial_sort(first, middle, last, comp); } template -void pattern_partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare comp, IsVector is_vector, /*is_parallel=*/std::true_type) noexcept { - __PSTL_PRAGMA_MESSAGE("Parallel algorithm unimplemented, redirected to serial"); - brick_partial_sort(first, middle, last, comp, is_vector); +void pattern_partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare comp, IsVector, /*is_parallel=*/std::true_type) noexcept { + par_backend::parallel_partial_sort(first, middle, last, comp); } //------------------------------------------------------------------------ @@ -1344,31 +1320,31 @@ RandomAccessIterator pattern_partial_sort_copy(InputIterator first, InputIterato //------------------------------------------------------------------------ // count //------------------------------------------------------------------------ -template -typename std::iterator_traits::difference_type -brick_count(InputIterator first, InputIterator last, Predicate pred, /* is_vector = */ std::true_type) noexcept { +template +typename std::iterator_traits::difference_type +brick_count(ForwardIterator first, ForwardIterator last, Predicate pred, /* is_vector = */ std::true_type) noexcept { return unseq_backend::simd_count(first, last-first, pred); } -template -typename std::iterator_traits::difference_type -brick_count(InputIterator first, InputIterator last, Predicate pred, /* is_vector = */ std::false_type) noexcept { +template +typename std::iterator_traits::difference_type +brick_count(ForwardIterator first, ForwardIterator last, Predicate pred, /* is_vector = */ std::false_type) noexcept { return std::count_if(first, last, pred); } -template -typename std::iterator_traits::difference_type -pattern_count(InputIterator first, InputIterator last, Predicate pred, /* is_parallel */ std::false_type, IsVector vec) noexcept { +template +typename std::iterator_traits::difference_type +pattern_count(ForwardIterator first, ForwardIterator last, Predicate pred, /* is_parallel */ std::false_type, IsVector vec) noexcept { return brick_count(first, last, pred, vec); } -template -typename std::iterator_traits::difference_type -pattern_count(InputIterator first, InputIterator last, Predicate pred, /* is_parallel */ std::true_type, IsVector vec) { - typedef typename std::iterator_traits::difference_type size_type; +template +typename std::iterator_traits::difference_type +pattern_count(ForwardIterator first, ForwardIterator last, Predicate pred, /* is_parallel */ std::true_type, IsVector vec) { + typedef typename std::iterator_traits::difference_type size_type; return except_handler([=]() { return par_backend::parallel_reduce(first, last, size_type(0), - [pred, vec](InputIterator begin, InputIterator end, size_type value)->size_type { + [pred, vec](ForwardIterator begin, ForwardIterator end, size_type value)->size_type { return value + brick_count(begin, end, pred, vec); }, std::plus() @@ -1561,8 +1537,7 @@ ForwardIterator brick_remove_if(ForwardIterator first, ForwardIterator last, Una template ForwardIterator brick_remove_if(ForwardIterator first, ForwardIterator last, UnaryPredicate pred, /* is_vector = */ std::true_type) noexcept { - __PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial"); - return std::remove_if(first, last, pred); + return unseq_backend::simd_remove_if(first, last - first, pred); } template @@ -1764,26 +1739,60 @@ OutputIterator pattern_set_symmetric_difference(InputIterator1 first1, InputIter //------------------------------------------------------------------------ template -RandomAccessIterator brick_is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare comp, /* is_vector = */ std::false_type) noexcept { +RandomAccessIterator brick_is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare comp, + /* is_vector = */ std::false_type) noexcept { return std::is_heap_until(first, last, comp); } - template -RandomAccessIterator brick_is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare comp, /* is_vector = */ std::true_type) noexcept { - __PSTL_PRAGMA_MESSAGE("Vectorized algorithm unimplemented, redirected to serial"); - return std::is_heap_until(first, last, comp); +RandomAccessIterator brick_is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare comp, + /* is_vector = */ std::true_type) noexcept { + if (last - first < 2) + return last; + typedef typename std::iterator_traits::difference_type size_type; + return unseq_backend::simd_first(first, size_type(0), last - first, + [&comp](RandomAccessIterator it, size_type i) {return comp(it[(i - 1) / 2], it[i]); }); } template -RandomAccessIterator pattern_is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare comp, IsVector vec, /* is_parallel = */ std::false_type) noexcept { +RandomAccessIterator pattern_is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare comp, + IsVector vec, /* is_parallel = */ std::false_type) noexcept { return brick_is_heap_until(first, last, comp, vec); } +template +RandomAccessIterator is_heap_until_local(RandomAccessIterator first, DifferenceType begin, DifferenceType end, Compare comp, + /* is_vector = */ std::false_type) noexcept { + DifferenceType i = begin; + for (; i < end; ++i) { + if (comp(first[(i - 1) / 2], first[i])) { + break; + } + } + return first + i; +} + +template +RandomAccessIterator is_heap_until_local(RandomAccessIterator first, DifferenceType begin, DifferenceType end, Compare comp, + /* is_vector = */ std::true_type) noexcept { + return unseq_backend::simd_first(first, begin, end, + [&comp](RandomAccessIterator it, DifferenceType i) {return comp(it[(i - 1) / 2], it[i]); }); +} + template -RandomAccessIterator pattern_is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare comp, IsVector vec, /* is_parallel = */ std::true_type) noexcept { - __PSTL_PRAGMA_MESSAGE("Parallel algorithm unimplemented, redirected to serial"); - return brick_is_heap_until(first, last, comp, vec); +RandomAccessIterator pattern_is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare comp, + IsVector vec, /* is_parallel = */ std::true_type) noexcept { + if (last - first < 2) + return last; + + return except_handler([=]() { + return internal::parallel_find(first, last, [first, last, comp, vec](RandomAccessIterator i, RandomAccessIterator j) { + return is_heap_until_local(first, i - first, j - first, comp, vec); + }, + std::less::difference_type>(), /*is_first=*/true); + + }); + } //------------------------------------------------------------------------ @@ -1902,7 +1911,7 @@ std::pair pattern_mismatch(InputIterator1 first1 auto result = internal::parallel_find(first1, first1 + n, [first1, first2, pred, is_vector](InputIterator1 i, InputIterator1 j) { return brick_mismatch(i, j, first2 + (i - first1), first2 + (j - first1), pred, is_vector).first; }, - std::less::difference_type>(), /*is_first=*/true); + std::less::difference_type>(), /*is_first=*/true); return std::make_pair(result, first2 + (result - first1)); }); } diff --git a/include/pstl/internal/parallel_backend_tbb.h b/include/pstl/internal/parallel_backend_tbb.h index 7d8d968c09f..b8fcf38efca 100644 --- a/include/pstl/internal/parallel_backend_tbb.h +++ b/include/pstl/internal/parallel_backend_tbb.h @@ -21,6 +21,8 @@ #ifndef __PSTL_parallel_backend_tbb_H #define __PSTL_parallel_backend_tbb_H +#include + #include "parallel_backend_utils.h" // Bring in minimal required subset of Intel TBB @@ -125,8 +127,7 @@ struct par_trans_red_body { brick_reduce(r_), u(u_), combine(c_), - has_sum(true) - { + has_sum(true) { new(sum_storage) T(init); } par_trans_red_body( par_trans_red_body& left, tbb::split ) : @@ -137,9 +138,8 @@ struct par_trans_red_body { {} ~par_trans_red_body() { // 17.6.5.12 tells us to not worry about catching exceptions from destructors. - if( has_sum ) { + if( has_sum ) sum().~T(); - } } void join(par_trans_red_body& rhs) { sum() = combine(sum(), rhs.sum()); @@ -187,8 +187,7 @@ class trans_scan_body { u(u_), combine(combine_), scan(scan_), - has_sum(true) - { + has_sum(true) { new(sum_storage) T(init); } @@ -197,14 +196,12 @@ class trans_scan_body { u(b.u), combine(b.combine), scan(b.scan), - has_sum(false) - {} + has_sum(false) {} ~trans_scan_body() { // 17.6.5.12 tells us to not worry about catching exceptions from destructors. - if( has_sum ) { + if( has_sum ) sum().~T(); - } } T& sum() const { @@ -246,16 +243,15 @@ class trans_scan_body { template T parallel_transform_scan(Index n, U u, T init, C combine, R brick_reduce, S scan) { - if(n) { - trans_scan_body body(u, init, combine, brick_reduce, scan); - auto range = tbb::blocked_range(0, n); - tbb::this_task_arena::isolate([range, &body]() { - tbb::parallel_scan(range, body); - }); - return body.sum(); - } - else + if (n <= 0) return init; + + trans_scan_body body(u, init, combine, brick_reduce, scan); + auto range = tbb::blocked_range(0, n); + tbb::this_task_arena::isolate([range, &body]() { + tbb::parallel_scan(range, body); + }); + return body.sum(); } template @@ -272,31 +268,31 @@ Index split(Index m) { template void upsweep(Index i, Index m, Index tilesize, T* r, Index lastsize, R reduce, C combine) { - if( m==1 ) - r[0] = reduce(i*tilesize, lastsize); - else { - Index k = split(m); - tbb::parallel_invoke( - [=]{upsweep( i, k, tilesize, r, tilesize, reduce, combine );}, - [=]{upsweep( i+k, m-k, tilesize, r+k, lastsize, reduce, combine );} - ); - if( m==2*k ) - r[m-1] = combine(r[k-1], r[m-1]); - } + if (m == 1) + r[0] = reduce(i*tilesize, lastsize); + else { + Index k = split(m); + tbb::parallel_invoke( + [=] {upsweep(i, k, tilesize, r, tilesize, reduce, combine); }, + [=] {upsweep(i + k, m - k, tilesize, r + k, lastsize, reduce, combine); } + ); + if (m == 2 * k) + r[m - 1] = combine(r[k - 1], r[m - 1]); + } } template void downsweep(Index i, Index m, Index tilesize, T* r, Index lastsize, T initial, C combine, S scan) { - if( m==1 ) { - scan(i*tilesize, lastsize, initial ); - } else { - Index k = split(m); - tbb::parallel_invoke( - [=]{downsweep(i, k, tilesize, r, tilesize, initial, combine, scan);}, - // Assumes that combine never throws. - [=]{downsweep(i+k, m-k, tilesize, r+k, lastsize, combine(initial, r[k-1]), combine, scan);} - ); - } + if (m == 1) + scan(i*tilesize, lastsize, initial); + else { + const Index k = split(m); + tbb::parallel_invoke( + [=] {downsweep(i, k, tilesize, r, tilesize, initial, combine, scan); }, + // Assumes that combine never throws. + [=] {downsweep(i + k, m - k, tilesize, r + k, lastsize, combine(initial, r[k - 1]), combine, scan); } + ); + } } // Adapted from Intel(R) Cilk(TM) version from cilkpub. @@ -314,36 +310,36 @@ void downsweep(Index i, Index m, Index tilesize, T* r, Index lastsize, T initial // For example, it's useful for allocating a buffer used by scan but whose size is the sum of all reduction values. // T must have a trivial constructor and destructor. template -void parallel_strict_scan( Index n, T initial, R reduce, C combine, S scan, A apex ) { - tbb::this_task_arena::isolate([=](){ - if( n>1 ) { +void parallel_strict_scan(Index n, T initial, R reduce, C combine, S scan, A apex) { + tbb::this_task_arena::isolate([=]() { + if (n > 1) { Index p = tbb::this_task_arena::max_concurrency(); const Index slack = 4; - Index tilesize = (n-1)/(slack*p) + 1; - Index m = (n-1)/tilesize; - buffer buf(m+1); - if( buf ) { + Index tilesize = (n - 1) / (slack*p) + 1; + Index m = (n - 1) / tilesize; + buffer buf(m + 1); + if (buf) { T* r = buf.get(); - upsweep(Index(0), Index(m+1), tilesize, r, n-m*tilesize, reduce, combine); + upsweep(Index(0), Index(m + 1), tilesize, r, n - m*tilesize, reduce, combine); // When apex is a no-op and combine has no side effects, a good optimizer // should be able to eliminate all code between here and apex. // Alternatively, provide a default value for apex that can be // recognized by metaprogramming that conditionlly executes the following. - size_t k = m+1; - T t = r[k-1]; - while( (k&=k-1) ) - t = combine(r[k-1],t); - apex(combine(initial,t)); - downsweep(Index(0), Index(m+1), tilesize, r, n-m*tilesize, initial, combine, scan); + size_t k = m + 1; + T t = r[k - 1]; + while ((k &= k - 1)) + t = combine(r[k - 1], t); + apex(combine(initial, t)); + downsweep(Index(0), Index(m + 1), tilesize, r, n - m*tilesize, initial, combine, scan); return; } } // Fewer than 2 elements in sequence, or out of memory. Handle has single block. T sum = initial; - if(n) + if (n) sum = combine(sum, reduce(Index(0), n)); apex(sum); - if(n) + if (n) scan(Index(0), n, initial); }); } @@ -437,7 +433,7 @@ tbb::task* stable_sort_task -void parallel_stable_sort( RandomAccessIterator xs, RandomAccessIterator xe, Compare comp, LeafSort leaf_sort ) { - tbb::this_task_arena::isolate([=](){ +void parallel_stable_sort(RandomAccessIterator xs, RandomAccessIterator xe, Compare comp, LeafSort leaf_sort) { + tbb::this_task_arena::isolate([=]() { //sorting based on task tree and parallel merge typedef typename std::iterator_traits::value_type T; - if( xe-xs > STABLE_SORT_CUT_OFF ) { - buffer buf(xe-xs); - if( buf ) { + if (xe - xs > STABLE_SORT_CUT_OFF) { + buffer buf(xe - xs); + if (buf) { using tbb::task; typedef typename std::iterator_traits::value_type T; - task::spawn_root_and_wait(*new( task::allocate_root() ) stable_sort_task( xs, xe, (T*)buf.get(), 2, comp, leaf_sort )); + task::spawn_root_and_wait(*new(task::allocate_root()) stable_sort_task(xs, xe, (T*)buf.get(), 2, comp, leaf_sort)); return; } } // Not enough memory available or sort too small - fall back on serial sort - leaf_sort( xs, xe, comp ); + leaf_sort(xs, xe, comp); }); } @@ -485,17 +481,178 @@ void parallel_stable_sort( RandomAccessIterator xs, RandomAccessIterator xe, Com template void parallel_merge(RandomAccessIterator1 xs, RandomAccessIterator1 xe, RandomAccessIterator2 ys, RandomAccessIterator2 ye, RandomAccessIterator3 zs, Compare comp, LeafMerge leaf_merge) { - tbb::this_task_arena::isolate([=]() { - typedef typename std::iterator_traits::value_type T; - if ((xe - xs) + (ye - ys) <= MERGE_CUT_OFF) { - // Fall back on serial merge - leaf_merge(xs, xe, ys, ye, zs, comp); - } - else { + if ((xe - xs) + (ye - ys) <= MERGE_CUT_OFF) { + // Fall back on serial merge + leaf_merge(xs, xe, ys, ye, zs, comp); + } + else { + tbb::this_task_arena::isolate([=]() { using tbb::task; task::spawn_root_and_wait(*new(task::allocate_root()) merge_task(xs, xe, ys, ye, zs, comp, binary_no_op(), leaf_merge)); + }); + } +} + +template +struct partial_sort_range { + DifferenceType beg, end; + bool buf_flag; + IteratorType buf_0; + typename std::iterator_traits::value_type* buf_1; + DifferenceType mid; +}; + +template +struct partial_ranges { + RandomAccessIterator1 xs, xe; + RandomAccessIterator2 ys, ye; + RandomAccessIterator3 zs; + RandomAccessIterator1 xm; + RandomAccessIterator2 ym; +}; + +template +struct range_move_t { + DifferenceType xs, xe; + DifferenceType zs; +}; + +//partial sorting based on parallel reduce and parallel merge +template +void parallel_partial_sort(RandomAccessIterator xs, RandomAccessIterator xm, RandomAccessIterator xe, Compare comp) { + + //assumption that parallelization overhead affects till number of sorting elements up to 1000 + const size_t sort_cut_off = 1000; + + const auto n = xe - xs; + + //partial sorting cut off + if (n <= sort_cut_off*2) { + std::partial_sort(xs, xm, xe, comp); + return; + } + + //trying to request additional memory + typedef typename std::iterator_traits::value_type T; + buffer buf(n); + if (!buf) { + std::partial_sort(xs, xm, xe, comp); + return; + } + + //prepare subranges to call partial_sort in parallel mode + typedef typename std::iterator_traits::difference_type DifferenceType; + typedef partial_sort_range range_t; + typedef range_move_t rmove_t; + + const auto n1 = xm - xs; + const auto n2 = xe - xm; + + assert(n1 + n2 == n); + + const auto m = std::max(n1, n2); + const auto n_range = m / sort_cut_off; + + assert(n_range >= 1); + + const double fpart = 1. / n_range; + const double fpart1 = fpart * n1; + const double fpart2 = fpart * n2; + + RandomAccessIterator a = xs; //a - source container + T* b = buf.get(); //b - buffer for merging partial sorted arrays + + //calculation indices for doing subranges for parallel partial sorting + stack > ranges(n_range); + stack > ranges_move(n_range * 2); + + DifferenceType x1 = 0, y1 = n1, z = 0, z1 = 0, z2 = 0, zm = 0; + for (DifferenceType i = 1; i <= n_range; ++i) { + + //create subrange indices for dividing original arrays into a couple of range sets + const DifferenceType x2 = i < n_range ? fpart1 * i : n1; + const DifferenceType y2 = i < n_range ? n1 + fpart2 * i : n1 + n2; + z1 = z; + ranges_move.push(rmove_t{x1, x2, z }); + z += x2-x1; + zm = z; + ranges_move.push(rmove_t{y1, y2, z }); + z += y2-y1; + z2 = z; + x1 = x2, y1 = y2; + + //create subrange indices for partial sort + ranges.push(range_t{ z1, z2, true, a, b, zm}); + } + + assert(z2 == n1 + n2); + + //init buffer -moving from two array into one + pstl::par_backend::parallel_for(ranges_move.buffer().get(), ranges_move.buffer().get() + ranges_move.size(), + [&a, &b](rmove_t* i, rmove_t* j) { + for (; i < j; ++i) { + const auto& r = *i; + init_buf(a + r.xs, a + r.xe, b + r.zs, true); + } } - }); + ); + + auto res_range = tbb::parallel_deterministic_reduce(tbb::blocked_range(ranges.buffer().get(), ranges.buffer().get() + ranges.size(), 1), range_t{ 0, 0, false , a, b, 0}, + [a, b, &comp](tbb::blocked_range& r, const range_t&)-> range_t { + assert(r.end() - r.begin() == 1); + + auto& sr = *r.begin(); + std::partial_sort(b + sr.beg, b + sr.mid, b + sr.end, comp); + return sr; + }, + [&comp](range_t l, range_t r) -> range_t { + + assert(l.end - l.beg > 0); + assert(r.end - r.beg > 0); + assert(l.end == r.beg); + + //move the subrange to the paired buffer and revert the buffer flag + if (l.buf_flag != r.buf_flag) { + if (l.buf_flag) { + std::move(l.buf_1 + l.beg, l.buf_1 + l.end, l.buf_0 + l.beg); + l.buf_flag = false; + } + else { + assert(r.buf_flag); + + std::move(r.buf_1 + r.beg, r.buf_1 + r.end, r.buf_0 + r.beg); + r.buf_flag = false; + } + } + + assert(l.buf_flag == r.buf_flag); + + //merge two partial sorted ranges + const auto n1 = l.mid - l.beg; + const auto n2 = r.mid - r.beg; + const auto res = range_t{ l.beg, r.end, !l.buf_flag, l.buf_0, l.buf_1, l.beg + n1 + n2}; //get new range and switch memory buffer + if (l.buf_flag) { + pstl::par_backend::parallel_merge(l.buf_1 + l.beg, l.buf_1 + l.mid, r.buf_1 + r.beg, r.buf_1 + r.mid, res.buf_0 + res.beg, comp, serial_move_merge()); + auto res_it = std::move(l.buf_1 + l.mid, l.buf_1 + l.end, res.buf_0 + res.beg + n1 + n2); //moving left unsorted subrange + std::move(r.buf_1 + r.mid, r.buf_1 + r.end, res_it); //moving right unsorted subrange + } + else { + pstl::par_backend::parallel_merge(l.buf_0 + l.beg, l.buf_0 + l.mid, r.buf_0 + r.beg, r.buf_0 + r.mid, res.buf_1 + res.beg, comp, serial_move_merge()); + auto res_it = std::move(l.buf_0 + l.mid, l.buf_0 + l.end, res.buf_1 + res.beg + n1 + n2);//moving left unsorted subrange + std::move(r.buf_0 + r.mid, r.buf_0 + r.end, res_it); //moving right unsorted subrange + } + + return res; + }, + tbb::simple_partitioner() + ); + + //move the result into source container + if (res_range.buf_flag) { + std::move(b, b + n, a); + } + + serial_destroy()(b, b + n); //cleanup } } // namespace par_backend diff --git a/include/pstl/internal/parallel_backend_utils.h b/include/pstl/internal/parallel_backend_utils.h index f9affb43d92..d64970bcb94 100644 --- a/include/pstl/internal/parallel_backend_utils.h +++ b/include/pstl/internal/parallel_backend_utils.h @@ -69,19 +69,58 @@ struct serial_move_merge { }; template -void merge_sort_init_temp_buf(RandomAccessIterator1 xs, RandomAccessIterator1 xe, RandomAccessIterator2 zs, bool inplace) { +void init_buf(RandomAccessIterator1 xs, RandomAccessIterator1 xe, RandomAccessIterator2 zs, bool bMove) { const RandomAccessIterator2 ze = zs + (xe - xs); typedef typename std::iterator_traits::value_type T; - if (inplace) - // Initialize the temporary buffer - for (; zs != ze; ++zs) - new(&*zs) T; - else + if (bMove) { // Initialize the temporary buffer and move keys to it. for (; zs != ze; ++xs, ++zs) new(&*zs) T(std::move(*xs)); + } + else { + // Initialize the temporary buffer + for (; zs != ze; ++zs) + new(&*zs) T; + } } +template +class stack { + typedef typename std::iterator_traits::value_type T; + typedef typename std::iterator_traits::difference_type difference_type; + + Buf my_buf; + T* my_ptr; + difference_type my_maxsize; + + stack(const stack&) = delete; + void operator=(const stack&) = delete; +public: + stack(difference_type max_size): my_buf(max_size), my_maxsize(max_size) { my_ptr = my_buf.get(); } + ~stack() { + assert(size() <= my_maxsize); + while(!empty()) + pop(); + } + + const Buf& buffer() const { return my_buf; } + size_t size() const { + assert(my_ptr - my_buf.get() <= my_maxsize); + assert(my_ptr - my_buf.get() >= 0); + return my_ptr - my_buf.get(); + } + bool empty() const { assert(my_ptr >= my_buf.get()); return my_ptr == my_buf.get();} + void push(const T& v) { + assert(size() < my_maxsize); + new (my_ptr) T(v); ++my_ptr; + } + const T& top() const { return *(my_ptr-1); } + void pop() { + assert(my_ptr > my_buf.get()); + --my_ptr; (*my_ptr).~T(); + } +}; + } // namespace par_backend } // namespace pstl diff --git a/include/pstl/internal/pstl_config.h b/include/pstl/internal/pstl_config.h index da68350ed69..a288439c928 100644 --- a/include/pstl/internal/pstl_config.h +++ b/include/pstl/internal/pstl_config.h @@ -21,7 +21,7 @@ #ifndef __PSTL_config_H #define __PSTL_config_H -#define PSTL_VERSION 103 +#define PSTL_VERSION 104 #define PSTL_VERSION_MAJOR (PSTL_VERSION/100) #define PSTL_VERSION_MINOR (PSTL_VERSION - PSTL_VERSION_MAJOR * 100) @@ -57,6 +57,11 @@ // the actual GCC version on the system. #define __PSTL_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if __clang__ + // according to clang documentation, version can be vendor specific + #define __PSTL_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#endif + // Enable SIMD for compilers that support OpenMP 4.0 #if (_OPENMP >= 201307) || (__INTEL_COMPILER >= 1600) || (__PSTL_GCC_VERSION >= 40900) #define __PSTL_PRAGMA_SIMD __PSTL_PRAGMA(omp simd) diff --git a/include/pstl/internal/unseq_backend_simd.h b/include/pstl/internal/unseq_backend_simd.h index c481a125cfd..d667052129e 100644 --- a/include/pstl/internal/unseq_backend_simd.h +++ b/include/pstl/internal/unseq_backend_simd.h @@ -62,6 +62,7 @@ template bool simd_or(Index first, DifferenceType n, Pred pred) noexcept { #if __PSTL_EARLYEXIT_PRESENT DifferenceType i; +__PSTL_PRAGMA_VECTOR_UNALIGNED __PSTL_PRAGMA_SIMD_EARLYEXIT for(i = 0; i < n; ++i) if(pred(first[i])) @@ -92,49 +93,52 @@ __PSTL_PRAGMA_SIMD_REDUCTION(&:flag) #endif } -template -Index simd_first(Index first, DifferenceType n, Pred pred) noexcept { +template +Index simd_first(Index first, DifferenceType begin, DifferenceType end, Compare comp) noexcept { #if __PSTL_EARLYEXIT_PRESENT - DifferenceType i = 0; + DifferenceType i = begin; +__PSTL_PRAGMA_VECTOR_UNALIGNED // Do not generate peel loop part __PSTL_PRAGMA_SIMD_EARLYEXIT - for(;i < n; ++i) - if(pred(*(first+i))) + for (; i < end; ++i) { + if (comp(first, i)) { break; - + } + } return first + i; #else - const Index last = first + n; // Experiments show good block sizes like this const DifferenceType block_size = 8; - alignas(64) DifferenceType lane[block_size] = {0}; - while ( last - first >= block_size ) { + alignas(64) DifferenceType lane[block_size] = { 0 }; + while (end - begin >= block_size) { DifferenceType found = 0; __PSTL_PRAGMA_VECTOR_UNALIGNED // Do not generate peel loop part -__PSTL_PRAGMA_SIMD_REDUCTION(|:found) - for ( DifferenceType i = 0; i < block_size; ++i ) { - // To improve SIMD vectorization - const DifferenceType t = (pred(*(first + i))); - lane[i] = t; +__PSTL_PRAGMA_SIMD_REDUCTION(| :found) + for (DifferenceType i = begin; i < begin + block_size; ++i) { + const DifferenceType t = comp(first, i); + lane[i - begin] = t; found |= t; } - if ( found ) { + if (found) { DifferenceType i; // This will vectorize - for ( i = 0; i < block_size; ++i ) { - if ( lane[i] ) break; + for (i = 0; i < block_size; ++i) { + if (lane[i]) { + break; + } } - return first + i; + return first + begin + i; } - first += block_size; + begin += block_size; } + //Keep remainder scalar - while ( last != first ) { - if ( pred(*(first)) ) { - return first; + while (begin != end) { + if (comp(first, begin)) { + return first + begin; } - ++first; + ++begin; } - return last; + return first + end; #endif //__PSTL_EARLYEXIT_PRESENT } @@ -142,6 +146,7 @@ template std::pair simd_first(Index1 first1, DifferenceType n, Index2 first2, Pred pred) noexcept { #if __PSTL_EARLYEXIT_PRESENT DifferenceType i = 0; +__PSTL_PRAGMA_VECTOR_UNALIGNED __PSTL_PRAGMA_SIMD_EARLYEXIT for(;i < n; ++i) if(pred(first1[i], first2[i])) @@ -321,6 +326,7 @@ Index simd_adjacent_find(Index first, Index last, BinaryPredicate pred, bool or_ #if __PSTL_EARLYEXIT_PRESENT //Some compiler versions fail to compile the following loop when iterators are used. Indices are used instead const difference_type n = last-first-1; +__PSTL_PRAGMA_VECTOR_UNALIGNED __PSTL_PRAGMA_SIMD_EARLYEXIT for(; i < n; ++i) if(pred(first[i], first[i+1])) @@ -419,6 +425,67 @@ __PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC_2ARGS(cnt_true:1, cnt_false : 1) } return std::make_pair(out_true + cnt_true, out_false + cnt_false); } + +template +ForwardIterator1 simd_find_first_of(ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 s_first, ForwardIterator2 s_last, BinaryPredicate pred) noexcept { + typedef typename std::iterator_traits::difference_type difference_type; + + const difference_type n1 = last - first; + const difference_type n2 = s_last - s_first; + if (n1 == 0 || n2 == 0) { + return last; // according to the standard + } + + // Common case + // If first sequence larger than second then we'll run simd_first with parameters of first sequence. + // Otherwise, vice versa. + if (n1 < n2) + { + for (; first != last; ++first) { + if (simd_or(s_first, n2, + internal::equal_value_by_pred(*first, pred))) { + return first; + } + } + } + else { + for (; s_first != s_last; ++s_first) { + const auto result = simd_first(first, difference_type(0), n1, + [s_first, &pred](ForwardIterator1 it, difference_type i) {return pred(it[i], *s_first); }); + if (result != last) { + return result; + } + } + } + return last; +} + +template +ForwardIterator simd_remove_if(ForwardIterator first, DifferenceType n, UnaryPredicate pred) noexcept { + // find first element we need to remove + auto current = simd_first(first, DifferenceType(0), n, [&pred](ForwardIterator it, DifferenceType i) {return pred(it[i]); }); + n -= current - first; + + // if we have in sequence only one element that pred(current[1]) != false we can exit the function + if (n < 2) { + return current; + } + +#if __PSTL_MONOTONIC_PRESENT + DifferenceType cnt = 0; + __PSTL_PRAGMA_SIMD + for (DifferenceType i = 1; i < n; ++i) { + __PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC(cnt:1) + if (!pred(current[i])) { + current[cnt] = std::move(current[i]); + ++cnt; + } + } + return current + cnt; +#else + return std::remove_if(current, current + n, pred); +#endif +} } // namespace unseq_backend } // namespace pstl diff --git a/include/pstl/internal/utils.h b/include/pstl/internal/utils.h index b88fd86e3bb..a8ca36bda11 100644 --- a/include/pstl/internal/utils.h +++ b/include/pstl/internal/utils.h @@ -109,6 +109,27 @@ class pstl_equal { bool operator()( X&& x, Y&& y ) const { return std::forward(x)==std::forward(y); } }; +//! "<" comparison. +class pstl_less { +public: + explicit pstl_less() {} + + template + bool operator()(X&& x, Y&& y) const { return std::forward(x) < std::forward(y); } +}; + +//! Like a polymorphic lambda for pred(...,value) +template +class equal_value_by_pred { + const T& value; + Predicate pred; +public: + equal_value_by_pred(const T& value_, Predicate pred_) : value(value_), pred(pred_) {} + + template + bool operator()(Arg&& arg) { return pred(std::forward(arg), value); } +}; + //! Like a polymorphic lambda for ==value template class equal_value { diff --git a/include/pstl/numeric b/include/pstl/numeric index fe212d38fea..d687bda6bbb 100644 --- a/include/pstl/numeric +++ b/include/pstl/numeric @@ -18,8 +18,8 @@ */ -#ifndef __PSTL_numeric_H -#define __PSTL_numeric_H +#ifndef __PSTL_numeric +#define __PSTL_numeric #include @@ -34,20 +34,20 @@ namespace std { template pstl::internal::enable_if_execution_policy reduce(ExecutionPolicy&& exec, InputIterator first, InputIterator last, T init, BinaryOperation binary_op) { - return transform_reduce(exec, first, last, init, binary_op, pstl::internal::no_op()); + return transform_reduce(std::forward(exec), first, last, init, binary_op, pstl::internal::no_op()); } template pstl::internal::enable_if_execution_policy reduce(ExecutionPolicy&& exec, InputIterator first, InputIterator last, T init) { - return transform_reduce(exec, first, last, init, std::plus(), pstl::internal::no_op()); + return transform_reduce(std::forward(exec), first, last, init, std::plus(), pstl::internal::no_op()); } template pstl::internal::enable_if_execution_policy::value_type> reduce(ExecutionPolicy&& exec, InputIterator first, InputIterator last) { - typedef typename decay::value_type>::type T; - return transform_reduce(exec, first, last, T{}, std::plus(), pstl::internal::no_op()); + typedef typename iterator_traits::value_type T; + return transform_reduce(std::forward(exec), first, last, T{}, std::plus(), pstl::internal::no_op()); } // [transform.reduce] @@ -57,7 +57,7 @@ pstl::internal::enable_if_execution_policy transform_reduce(ExecutionPolicy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init) { typedef typename iterator_traits::value_type input_type; using namespace pstl::internal; - return pattern_transform_reduce(first1, last1, first2, init, std::plus(), std::multiplies(), + return pattern_transform_reduce(first1, last1, first2, init, std::plus(), std::multiplies(), is_vectorization_preferred(exec), is_parallelization_preferred(exec)); } @@ -85,12 +85,12 @@ transform_reduce(ExecutionPolicy&& exec, InputIterator first, InputIterator last template pstl::internal::enable_if_execution_policy exclusive_scan(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result, T init) { - return transform_exclusive_scan(exec, first, last, result, init, std::plus(), pstl::internal::no_op()); + return transform_exclusive_scan(std::forward(exec), first, last, result, init, std::plus(), pstl::internal::no_op()); } template OutputIterator exclusive_scan(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result, T init, BinaryOperation binary_op) { - return transform_exclusive_scan(exec, first, last, result, init, binary_op, pstl::internal::no_op()); + return transform_exclusive_scan(std::forward(exec), first, last, result, init, binary_op, pstl::internal::no_op()); } // [inclusive.scan] @@ -99,19 +99,19 @@ template pstl::internal::enable_if_execution_policy inclusive_scan(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result) { typedef typename iterator_traits::value_type input_type; - return transform_inclusive_scan(exec, first, last, result, std::plus(), pstl::internal::no_op()); + return transform_inclusive_scan(std::forward(exec), first, last, result, std::plus(), pstl::internal::no_op()); } template pstl::internal::enable_if_execution_policy inclusive_scan(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op) { - return transform_inclusive_scan(exec, first, last, result, binary_op, pstl::internal::no_op()); + return transform_inclusive_scan(std::forward(exec), first, last, result, binary_op, pstl::internal::no_op()); } template pstl::internal::enable_if_execution_policy inclusive_scan(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op, T init) { - return transform_inclusive_scan(exec, first, last, result, binary_op, pstl::internal::no_op(), init); + return transform_inclusive_scan(std::forward(exec), first, last, result, binary_op, pstl::internal::no_op(), init); } // [transform.exclusive.scan] @@ -146,7 +146,7 @@ transform_inclusive_scan(ExecutionPolicy&& exec, InputIterator first, InputIter if( first!=last ) { auto tmp = unary_op(*first); *result = tmp; - return transform_inclusive_scan(exec, ++first, last, ++result, binary_op, unary_op, tmp); + return transform_inclusive_scan(std::forward(exec), ++first, last, ++result, binary_op, unary_op, tmp); } else { return result; } @@ -167,9 +167,9 @@ template pstl::internal::enable_if_execution_policy adjacent_difference(ExecutionPolicy&& exec, InputIterator first, InputIterator last, OutputIterator d_first) { typedef typename iterator_traits::value_type value_type; - return adjacent_difference(exec, first, last, d_first, std::minus()); + return adjacent_difference(std::forward(exec), first, last, d_first, std::minus()); } } -#endif /* __PSTL_numeric_H */ +#endif /* __PSTL_numeric */ diff --git a/test/pstl_test_config.h b/test/pstl_test_config.h index ce719f21c96..baaa0dea9ce 100644 --- a/test/pstl_test_config.h +++ b/test/pstl_test_config.h @@ -28,10 +28,12 @@ #define __PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN (__x86_64 && !_DEBUG && __INTEL_COMPILER && __INTEL_COMPILER <= 1700 && !__APPLE__) #define __PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN (!_DEBUG && __INTEL_COMPILER && (__INTEL_COMPILER < 1800 || (__INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE < 1))) #define __PSTL_ICC_1800_TEST_MONOTONIC_RELEASE_64_BROKEN (__x86_64 && !_DEBUG && __INTEL_COMPILER && __INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE < 1) -#define __PSTL_TEST_ICC_17_IA32_RELEASE_MAC_BROKEN (__i386__ && !_DEBUG && __INTEL_COMPILER >= 1700 && __INTEL_COMPILER < 1800 && __APPLE__) -#define __PSTL_TEST_SIMD_LAMBDA_ICC_17_VC141_DEBUG_32_BROKEN (_M_IX86 && _DEBUG && __INTEL_COMPILER >= 1700 && __INTEL_COMPILER < 1800 && _MSC_VER == 1910) -#define __PSTL_TEST_SIMD_LAMBDA_ICC_16_VC14_DEBUG_32_BROKEN (_M_IX86 && _DEBUG && __INTEL_COMPILER >= 1600 && __INTEL_COMPILER < 1700 && _MSC_VER == 1900) -#define __PSTL_TEST_PAR_TBB_RT_ICC_16_VC14_RELEASE_64_BROKEN (__PSTL_USE_PAR_POLICIES && _M_X64 && !_DEBUG && __INTEL_COMPILER < 1700 && _MSC_VER == 1900) -#define __PSTL_TEST_ICC_16_17_64_TIMEOUT (__x86_64 && __INTEL_COMPILER && __INTEL_COMPILER < 1800 && !__APPLE__) +#define __PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN (__i386__ && !_DEBUG && __INTEL_COMPILER >= 1700 && __INTEL_COMPILER < 1800 && __APPLE__) +#define __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN (_M_IX86 && _DEBUG && __INTEL_COMPILER >= 1700 && __INTEL_COMPILER < 1800 && _MSC_VER == 1910) +#define __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN (_M_IX86 && _DEBUG && __INTEL_COMPILER >= 1600 && __INTEL_COMPILER < 1700 && _MSC_VER == 1900) +#define __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN (__PSTL_USE_PAR_POLICIES && _M_X64 && !_DEBUG && __INTEL_COMPILER < 1700 && _MSC_VER == 1900) +#define __PSTL_ICC_16_17_TEST_64_TIMEOUT (__x86_64 && __INTEL_COMPILER && __INTEL_COMPILER < 1800 && !__APPLE__) +#define __PSTL_ICC_18_TEST_EARLY_EXIT_MONOTONIC_RELEASE_BROKEN (!_DEBUG && __INTEL_COMPILER && __INTEL_COMPILER == 1800) +#define __PSTL_CLANG_TEST_BIG_OBJ_DEBUG_32_BROKEN (__i386__ && PSTL_USE_DEBUG && __clang__ && __PSTL_CLANG_VERSION <= 90000) #endif /* __PSTL_TEST_config_H */ diff --git a/test/test_algorithm.cpp b/test/test_algorithm.cpp index 57029528a6f..b93f160520b 100644 --- a/test/test_algorithm.cpp +++ b/test/test_algorithm.cpp @@ -31,6 +31,15 @@ using namespace TestUtils; auto is_even = [](double v) { unsigned int i = (unsigned int)v; return i % 2 == 0; }; +template +static void invoke_if(Policy&& p, F f) { + #if __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN + pstl::internal::invoke_if_not(pstl::internal::allow_unsequenced(), f); + #else + f(); + #endif +} + //Testing with random-access iterator only struct run_rnd { template @@ -41,15 +50,17 @@ struct run_rnd { //usage of "non_const" adapter - we pass empty container due to just compilation checks - //is_heap - is_heap(exec, b1, e1); - is_heap(exec, b1, e1, std::less()); - is_heap(exec, b1, b1, non_const(std::less())); + invoke_if(exec, [&]() { + //is_heap + is_heap(exec, b1, e1); + is_heap(exec, b1, e1, std::less()); + is_heap(exec, b1, b1, non_const(std::less())); - //is_heap_until - is_heap_until(exec, b1, e1); - is_heap_until(exec, b1, e1, std::less()); - is_heap_until(exec, b1, b1, non_const(std::less())); + //is_heap_until + is_heap_until(exec, b1, e1); + is_heap_until(exec, b1, e1, std::less()); + is_heap_until(exec, b1, b1, non_const(std::less())); + }); //nth_element auto middle = b1 + (e1 - b1) / 2; @@ -125,6 +136,8 @@ struct run_rnd_fw { Iterator out = b1; auto n = distance(b1, e1); + Iterator cmiddle = b1; + std::advance(cmiddle, n/2); //usage of "non_const" adapter - we pass empty container due to just compilation checks //all_of @@ -140,20 +153,20 @@ struct run_rnd_fw { any_of(exec, b1, e1, is_even); any_of(exec, b1, b1, non_const(is_even)); - //copy -#if __PSTL_TEST_SIMD_LAMBDA_ICC_16_VC14_DEBUG_32_BROKEN || __PSTL_TEST_SIMD_LAMBDA_ICC_17_VC141_DEBUG_32_BROKEN - pstl::internal::invoke_if_not(pstl::internal::allow_unsequenced(), [&]() { copy(exec, b1, e1, out); copy_n(exec, b1, n, out); }); -#else - copy(exec, b1, e1, out); - copy_n(exec, b1, n, out); -#endif + invoke_if(exec, [&]() { + //copy + copy(exec, b1, e1, out); + copy_n(exec, b1, n, out); + }); //copy_if copy_if(exec, b1, e1, out, is_even); copy_if(exec, b1, b1, out, non_const(is_even)); - //count - count(exec, b1, e1, T(0)); + invoke_if(exec, [&]() { + //count + count(exec, b1, e1, T(0)); + }); //count_if count_if(exec, b1, e1, is_even); @@ -172,35 +185,37 @@ struct run_rnd_fw { //fill_n fill_n(exec, b1, n, T(0)); - //find - find(exec, b1, e1, T(0)); + invoke_if(exec, [&]() { + //find + find(exec, b1, e1, T(0)); - //find_end - find_end(exec, b1, e1, b2, e2); - find_end(exec, b1, e1, b2, e2, std::equal_to()); - find_end(exec, b1, b1, b2, b2, non_const(std::equal_to())); + //find_end + find_end(exec, b1, e1, b2, e2); + find_end(exec, b1, e1, b2, e2, std::equal_to()); + find_end(exec, b1, b1, b2, b2, non_const(std::equal_to())); - //find_first_of - find_first_of(exec, b1, e1, b2, e2); - find_first_of(exec, b1, e1, b2, e2, std::equal_to()); - find_first_of(exec, b1, b1, b2, b2, non_const(std::equal_to())); + //find_first_of + find_first_of(exec, b1, e1, b2, e2); + find_first_of(exec, b1, e1, b2, e2, std::equal_to()); + find_first_of(exec, b1, b1, b2, b2, non_const(std::equal_to())); - //find_if - find_if(exec, b1, e1, is_even); - find_if(exec, b1, b1, non_const(is_even)); + //find_if + find_if(exec, b1, e1, is_even); + find_if(exec, b1, b1, non_const(is_even)); - //find_if_not - find_if_not(exec, b1, e1, is_even); - find_if_not(exec, b1, b1, non_const(is_even)); + //find_if_not + find_if_not(exec, b1, e1, is_even); + find_if_not(exec, b1, b1, non_const(is_even)); - //for_each - auto f = [](T& x) { x = x+1; }; - for_each(exec, b1, e1, f); - for_each(exec, b1, b1, non_const(f)); + //for_each + auto f = [](typename iterator_traits::reference x) { x = x+1; }; + for_each(exec, b1, e1, f); + for_each(exec, b1, b1, non_const(f)); - //for_each_n - for_each_n(exec, b1, n, f); - for_each_n(exec, b1, 0, non_const(f)); + //for_each_n + for_each_n(exec, b1, n, f); + for_each_n(exec, b1, 0, non_const(f)); + }); //generate auto gen = [](){return T(0);}; @@ -241,8 +256,6 @@ struct run_rnd_fw { max_element(exec, b1, b1, non_const(std::less())); //merge - Iterator cmiddle = b1; - std::advance(cmiddle, n/2); merge(exec, b1, cmiddle, cmiddle, e1, out); merge(exec, b1, cmiddle, cmiddle, e1, out, std::less()); merge(exec, b1, b1, b1, b1, out, non_const(std::less())); @@ -264,14 +277,12 @@ struct run_rnd_fw { minmax_element(exec, b1, e1, std::less()); minmax_element(exec, b1, b1, non_const(std::less())); - //move -#if __PSTL_TEST_SIMD_LAMBDA_ICC_16_VC14_DEBUG_32_BROKEN || __PSTL_TEST_SIMD_LAMBDA_ICC_17_VC141_DEBUG_32_BROKEN - pstl::internal::invoke_if_not(pstl::internal::allow_unsequenced(), [&]() { move(exec, b1, e1, out); }); -#else - move(exec, b1, e1, out); -#endif + invoke_if(exec, [&]() { + //move + move(exec, b1, e1, out); + }); - //nome_of + //none_of none_of(exec, b1, e1, is_even); none_of(exec, b1, b1, non_const(is_even)); @@ -282,34 +293,35 @@ struct run_rnd_fw { //partition_copy partition_copy(exec, b1, e1, out, out, is_even); partition_copy(exec, b1, b1, out, out, non_const(is_even)); + invoke_if(exec, [&]() { + //remove + remove(exec, b1, e1, T(0)); - //remove - remove(exec, b1, e1, T(0)); + //remove_copy + remove_copy(exec, b1, e1, out, T(0)); - //remove_copy - remove_copy(exec, b1, e1, out, T(0)); + //remove_copy_if + remove_copy_if(exec, b1, e1, out, is_even); + remove_copy_if(exec, b1, b1, out, non_const(is_even)); - //remove_copy_if - remove_copy_if(exec, b1, e1, out, is_even); - remove_copy_if(exec, b1, b1, out, non_const(is_even)); + //remove_if + remove_if(exec, b1, e1, is_even); + remove_if(exec, b1, b1, non_const(is_even)); - //remove_if - remove_if(exec, b1, e1, is_even); - remove_if(exec, b1, b1, non_const(is_even)); + //replace + replace(exec, b1, e1, T(1), T(0)); - //replace - replace(exec, b1, e1, T(1), T(0)); + //replace_copy + replace_copy(exec, b1, e1, out, T(1), T(0)); - //replace_copy - replace_copy(exec, b1, e1, out, T(1), T(0)); + //replace_copy_if + replace_copy_if(exec, b1, e1, out, is_even, T(0)); + replace_copy_if(exec, b1, b1, out, non_const(is_even), T(0)); - //replace_copy_if - replace_copy_if(exec, b1, e1, out, is_even, T(0)); - replace_copy_if(exec, b1, b1, out, non_const(is_even), T(0)); - - //replace_if - replace_if(exec, b1, e1, is_even, T(0)); - replace_if(exec, b1, b1, non_const(is_even), T(0)); + //replace_if + replace_if(exec, b1, e1, is_even, T(0)); + replace_if(exec, b1, b1, non_const(is_even), T(0)); + }); //rotate rotate(exec, b1, b1, e1); @@ -317,15 +329,17 @@ struct run_rnd_fw { //rotate_copy rotate_copy(exec, b1, b1, e1, out); - //search - search(exec, b1, e1, b2, e2); - search(exec, b1, e1, b2, e2, std::equal_to()); - search(exec, b1, b1, b2, b2, non_const(std::equal_to())); + invoke_if(exec, [&]() { + //search + search(exec, b1, e1, b2, e2); + search(exec, b1, e1, b2, e2, std::equal_to()); + search(exec, b1, b1, b2, b2, non_const(std::equal_to())); - //search_n - search_n(exec, b1, e1, 2, T(0)); - search_n(exec, b1, e1, 2, T(0), std::equal_to()); - search_n(exec, b1, b1, 0, T(0), non_const(std::equal_to())); + //search_n + search_n(exec, b1, e1, 2, T(0)); + search_n(exec, b1, e1, 2, T(0), std::equal_to()); + search_n(exec, b1, b1, 0, T(0), non_const(std::equal_to())); + }); //set_difference set_difference(exec, b1, cmiddle, cmiddle, e1, out); @@ -350,12 +364,14 @@ struct run_rnd_fw { //swap_ranges swap_ranges(exec, b1, e1, b2); - //transform - transform(exec, b1, e1, out, std::negate()); - transform(exec, b1, b1, out, non_const(std::negate())); + invoke_if(exec, [&]() { + //transform + transform(exec, b1, e1, out, std::negate()); + transform(exec, b1, b1, out, non_const(std::negate())); - transform(exec, b1, e1, b2, out, std::plus()); - transform(exec, b1, b1, b2, out, non_const(std::plus())); + transform(exec, b1, e1, b2, out, std::plus()); + transform(exec, b1, b1, b2, out, non_const(std::plus())); + }); //unique unique(exec, b1, e1); @@ -385,7 +401,10 @@ void test_algo_by_type() { int32_t main() { test_algo_by_type(); +#if !__PSTL_CLANG_TEST_BIG_OBJ_DEBUG_32_BROKEN test_algo_by_type(); + test_algo_by_type(); +#endif std::cout< void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size n, Predicate pred, T trash) { + OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, Predicate pred, T trash) { // Cleaning std::fill_n(expected_first, n, trash); std::fill_n(out_first, n, trash); @@ -75,13 +73,13 @@ void test(T trash, Predicate pred, Convert convert, bool check_weakness = true) Sequence out(count, [=](size_t){return trash;}); Sequence expected(count, [=](size_t){return trash;}); - auto expected_result = copy_if( in.cfbegin(), in.cfend(), expected.begin(), pred ); if (check_weakness) { + auto expected_result = copy_if(in.cfbegin(), in.cfend(), expected.begin(), pred); size_t m = expected_result - expected.begin(); EXPECT_TRUE(n / 4 <= m && m <= 3 * (n + 1) / 4, "weak test for copy_if"); } - invoke_on_all_policies(run_copy_if(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), count, pred, trash); - invoke_on_all_policies(run_copy_if(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), count, pred, trash); + invoke_on_all_policies(run_copy_if(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), expected.end(), count, pred, trash); + invoke_on_all_policies(run_copy_if(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), expected.end(), count, pred, trash); } } @@ -94,7 +92,7 @@ int32_t main( ) { [](const int32_t& x) {return x!=42;}, [](size_t j){return ((j+1)%5&2)!=0? int32_t(j+1) : 42;}); -#if !__PSTL_TEST_ICC_17_IA32_RELEASE_MAC_BROKEN +#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN test( Number(42,OddTag()), IsMultiple(3,OddTag()), [](int32_t j){return Number(j,OddTag());}); diff --git a/test/test_copy_move.cpp b/test/test_copy_move.cpp index adc68008364..66597a74087 100644 --- a/test/test_copy_move.cpp +++ b/test/test_copy_move.cpp @@ -28,23 +28,21 @@ using namespace TestUtils; -const size_t GuardSize = 5; - struct run_copy { -#if __PSTL_TEST_SIMD_LAMBDA_ICC_17_VC141_DEBUG_32_BROKEN || __PSTL_TEST_SIMD_LAMBDA_ICC_16_VC14_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration template void operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size size, Size n, T trash) {} + OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, Size n, T trash) {} template void operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size size, Size n, T trash) {} + OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, Size n, T trash) {} #endif template void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size size, Size n, T trash) { + OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, Size n, T trash) { // Cleaning std::fill_n(expected_first, size, trash); std::fill_n(out_first, size, trash); @@ -71,19 +69,19 @@ struct run_copy { template struct run_move { -#if __PSTL_TEST_SIMD_LAMBDA_ICC_17_VC141_DEBUG_32_BROKEN || __PSTL_TEST_SIMD_LAMBDA_ICC_16_VC14_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration template void operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size size, Size n, T trash) {} + OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, Size n, T trash) {} template void operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size size, Size n, T trash) {} + OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, Size n, T trash) {} #endif template void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size size, Size n, T trash) { + OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, Size n, T trash) { // Cleaning std::fill_n(expected_first, size, trash); std::fill_n(out_first, size, trash); @@ -101,19 +99,19 @@ struct run_move { template struct run_move> { -#if __PSTL_TEST_SIMD_LAMBDA_ICC_17_VC141_DEBUG_32_BROKEN || __PSTL_TEST_SIMD_LAMBDA_ICC_16_VC14_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration template void operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size size, Size n, Wrapper trash) {} + OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, Size n, Wrapper trash) {} template void operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size size, Size n, Wrapper trash) {} + OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, Size n, Wrapper trash) {} #endif template void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size size, Size n, Wrapper trash) { + OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, Size n, Wrapper trash) { // Cleaning std::fill_n(out_first, size, trash); Wrapper::SetMoveCount(0); @@ -138,12 +136,12 @@ void test(T trash, Convert convert) { return val; }); - size_t outN = n + GuardSize; + const size_t outN = n + GuardSize; Sequence out(outN, [=](size_t) {return trash; }); Sequence expected(outN, [=](size_t) {return trash; }); - invoke_on_all_policies(run_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), outN, n, trash); - invoke_on_all_policies(run_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), outN, n, trash); - invoke_on_all_policies(run_move(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), n, n, trash); + invoke_on_all_policies(run_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), expected.end(), outN, n, trash); + invoke_on_all_policies(run_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), expected.end(), outN, n, trash); + invoke_on_all_policies(run_move(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), expected.end(), n, n, trash); // For this test const iterator isn't suitable // because const rvalue-reference call copy assignment operator @@ -156,7 +154,7 @@ int32_t main() { test>(Wrapper(-666.0), [](int32_t j) { return Wrapper(j); }); -#if !__PSTL_TEST_ICC_16_17_64_TIMEOUT +#if !__PSTL_ICC_16_17_TEST_64_TIMEOUT test(-666.0, [](size_t j) {return float64_t(j); }); test(Number(42, OddTag()), diff --git a/test/test_find.cpp b/test/test_find.cpp index 000a2d48fd8..01c5f9468f3 100644 --- a/test/test_find.cpp +++ b/test/test_find.cpp @@ -19,6 +19,7 @@ */ // Tests for find +#include "test/pstl_test_config.h" #include "pstl/execution" #include "pstl/algorithm" @@ -27,6 +28,13 @@ using namespace TestUtils; struct test_find { +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration + template + void operator()(pstl::execution::unsequenced_policy, Iterator first, Iterator last, Value value) { } + template + void operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Value value) { } +#endif + template void operator()( Policy&& exec, Iterator first, Iterator last, Value value ) { auto i = std::find(first, last, value); diff --git a/test/test_find_end.cpp b/test/test_find_end.cpp index 2a238e81319..34e922ade03 100644 --- a/test/test_find_end.cpp +++ b/test/test_find_end.cpp @@ -27,8 +27,15 @@ using namespace TestUtils; struct test_one_policy { +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration + template + void operator()(pstl::execution::unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) { } + template + void operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) { } +#endif + template - void body(ExecutionPolicy&& exec, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) { + void operator()(ExecutionPolicy&& exec, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) { using namespace std; // For find_end { @@ -50,11 +57,6 @@ struct test_one_policy { EXPECT_TRUE(actual == expected, "wrong return result from search with a predicate"); } } - - template - void operator()(ExecutionPolicy&& exec, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) { - body(exec, b, e, bsub, esub, pred); - } }; template diff --git a/test/test_find_first_of.cpp b/test/test_find_first_of.cpp new file mode 100644 index 00000000000..cb0dc1bd273 --- /dev/null +++ b/test/test_find_first_of.cpp @@ -0,0 +1,84 @@ +/* + Copyright (c) 2017-2018 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + +*/ + +#include "test/pstl_test_config.h" + +#include "pstl/execution" +#include "pstl/algorithm" +#include "test/utils.h" + +using namespace TestUtils; + +struct test_one_policy { +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration + template + void operator()(pstl::execution::unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) { } + template + void operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) { } +#endif + + template + void operator()(ExecutionPolicy&& exec, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) { + using namespace std; + Iterator1 expected = find_first_of(b, e, bsub, esub, pred); + Iterator1 actual = find_first_of(exec, b, e, bsub, esub, pred); + EXPECT_TRUE(actual == expected, "wrong return result from find_first_of with a predicate"); + + expected = find_first_of(b, e, bsub, esub); + actual = find_first_of(exec, b, e, bsub, esub); + EXPECT_TRUE(actual == expected, "wrong return result from find_first_of"); + } +}; + +template +void test(Predicate pred) { + + const std::size_t max_n1 = 1000; + const std::size_t max_n2 = (max_n1 * 10) / 8; + Sequence in1(max_n1, [](std::size_t k) {return T(1); }); + Sequence in2(max_n2, [](std::size_t k) {return T(0); }); + for (std::size_t n1 = 0; n1 <= max_n1; n1 = n1 <= 16 ? n1 + 1 : size_t(3.1415 * n1)) { + std::size_t sub_n[] = { 0, 1, n1 / 3, n1, (n1 * 10) / 8 }; + for(const auto n2 : sub_n) { + bool not_0 = n2 != 0; + invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.data(), in2.data() + n2, pred); + + in2[n2 / 2] = T(1); + invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + n1, in2.data(), in2.data() + n2, pred); + + if (n2 >= 3) { + in2[2 * n2 / 3] = T(1); + invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + n1, in2.begin(), in2.begin() + n2, pred); + in2[2 * n2 / 3] = T(0); + } + in2[n2 / 2] = T(0); + } + } + invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + max_n1 / 10, in1.data(), in1.data() + max_n1 / 10, pred); +} + +int32_t main() { + test(std::equal_to()); + test(std::not_equal_to()); + test([](const float64_t x, const float64_t y) {return x*x == y*y; }); + + std::cout << done() << std::endl; + return 0; +} diff --git a/test/test_find_if.cpp b/test/test_find_if.cpp index b049d1419c1..23cb4d3e3cf 100644 --- a/test/test_find_if.cpp +++ b/test/test_find_if.cpp @@ -19,6 +19,7 @@ */ // Tests for find_if and find_if_not +#include "test/pstl_test_config.h" #include "pstl/execution" #include "pstl/algorithm" @@ -27,6 +28,13 @@ using namespace TestUtils; struct test_find_if { +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration + template + void operator()(pstl::execution::unsequenced_policy, Iterator first, Iterator last, Predicate pred, NotPredicate not_pred) { } + template + void operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Predicate pred, NotPredicate not_pred) { } +#endif + template void operator()( Policy&& exec, Iterator first, Iterator last, Predicate pred, NotPredicate not_pred ) { auto i = std::find_if(first, last, pred); @@ -60,10 +68,12 @@ void test(Predicate pred, Hit hit, Miss miss) { } int32_t main( ) { +#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN // Note that the "hit" and "miss" functions here avoid overflow issues. test( IsMultiple(5,OddTag()), [](int32_t j){return Number(j-j%5,OddTag());}, // hit [](int32_t j){return Number(j%5==0 ? j^1 : j,OddTag());}); // miss +#endif // Try type for which algorithm can really be vectorized. test([](float32_t x) {return x>=0;}, diff --git a/test/test_is_heap.cpp b/test/test_is_heap.cpp new file mode 100644 index 00000000000..812ffc4d1cc --- /dev/null +++ b/test/test_is_heap.cpp @@ -0,0 +1,120 @@ +/* + Copyright (c) 2017-2018 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + +*/ + +// Tests for is_heap, is_heap_until +#include "test/pstl_test_config.h" + +#include "pstl/execution" +#include "pstl/algorithm" +#include "test/utils.h" +#include + +using namespace TestUtils; + +struct WithCmpOp { + int32_t _first; + int32_t _second; + WithCmpOp() : _first(0), _second(0) { }; + explicit WithCmpOp(int32_t x) : _first(x), _second(x) { }; + bool operator < (const WithCmpOp& rhs) const { + return this->_first < rhs._first; + } +}; + +struct test_is_heap { +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration + template + typename std::enable_if::value, void>::type + operator()(pstl::execution::unsequenced_policy, Iterator first, Iterator last, Predicate pred) { } + template + typename std::enable_if::value, void>::type + operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Predicate pred) { } +#endif + + template + typename std::enable_if::value, void>::type + operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred) { + using namespace std; + // is_heap + { + bool expected = is_heap(first, last); + bool actual = is_heap(exec, first, last); + EXPECT_TRUE(expected == actual, "wrong return value from is_heap"); + } + // is_heap with predicate + { + bool expected = is_heap(first, last, pred); + bool actual = is_heap(exec, first, last, pred); + EXPECT_TRUE(expected == actual, "wrong return value from is_heap with predicate"); + } + // is_heap_until + { + Iterator expected = is_heap_until(first, last); + Iterator actual = is_heap_until(exec, first, last); + EXPECT_TRUE(expected == actual, "wrong return value from is_heap_until"); + } + // is_heap_until with predicate + { + const Iterator expected = is_heap_until(first, last, pred); + const auto y = std::distance(first, expected); + const Iterator actual = is_heap_until(exec, first, last, pred); + const auto x = std::distance(first, actual); + EXPECT_TRUE(expected == actual, "wrong return value from is_heap_until with predicate"); + } + } + + // is_heap, is_heap_until works only with random access iterators + template + typename std::enable_if::value, void>::type + operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred) { } +}; + +template +void test_is_heap_by_type(Comp comp) { + using namespace std; + + const size_t max_size = 100000; + for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) { + Sequence in(n, [](size_t v)->T { return T(v); }); + + invoke_on_all_policies(test_is_heap(), in.begin(), in.end(), comp); + + std::make_heap(in.begin(), in.begin() + n / 4, comp); + invoke_on_all_policies(test_is_heap(), in.cbegin(), in.cend(), comp); + + std::make_heap(in.begin(), in.begin() + n / 3, comp); + invoke_on_all_policies(test_is_heap(), in.begin(), in.end(), comp); + + std::make_heap(in.begin(), in.end(), comp); + invoke_on_all_policies(test_is_heap(), in.cbegin(), in.cend(), comp); + } + + Sequence in(max_size/10, [](size_t v)->T { return T(1); }); + invoke_on_all_policies(test_is_heap(), in.begin(), in.end(), comp); +} + +int32_t main() { + test_is_heap_by_type(std::greater()); + test_is_heap_by_type(std::less()); + test_is_heap_by_type([](uint64_t x, uint64_t y) {return x % 100 < y % 100; }); + + std::cout < void operator()(pstl::execution::parallel_policy, InputIterator inBegin, InputIterator inEnd, OutputIterator outBegin, OutputIterator outEnd) {} template void operator()(pstl::execution::parallel_unsequenced_policy, InputIterator inBegin, InputIterator inEnd, OutputIterator outBegin, OutputIterator outEnd) {} #endif -#if __PSTL_TEST_SIMD_LAMBDA_ICC_17_VC141_DEBUG_32_BROKEN || __PSTL_TEST_SIMD_LAMBDA_ICC_16_VC14_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration template void operator()(pstl::execution::unsequenced_policy, InputIterator inBegin, InputIterator inEnd, OutputIterator outBegin, OutputIterator outEnd) {} template diff --git a/test/test_merge.cpp b/test/test_merge.cpp index 8dde5cb9a86..fd43a28ef19 100644 --- a/test/test_merge.cpp +++ b/test/test_merge.cpp @@ -18,40 +18,50 @@ */ +#include "test/pstl_test_config.h" + #include #include #include "pstl/execution" #include "pstl/algorithm" -#include "pstl/numeric" -#include "pstl/memory" #include "test/utils.h" using namespace TestUtils; struct test_merge { - template - void operator()(Policy&& exec, Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2, - Iterator3 first3, Compare comp) { + template + void operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, + OutputIterator out_first, OutputIterator out_last, Compare comp) { using namespace std; - const auto dist1 = distance(first1, last1); - const auto dist2 = distance(first2, last2); - const auto expected = std::next(first3, (dist1 + dist2)); { - const auto res = merge(exec, first1, last1, first2, last2, first3, comp); - EXPECT_TRUE(res == expected, "wrong return result from merge with predicate"); - EXPECT_TRUE(is_sorted(first3, res, comp), "wrong result from merge with predicate"); - EXPECT_TRUE(includes(first3, res, first1, last1, comp), "first sequence is not a part of result"); - EXPECT_TRUE(includes(first3, res, first2, last2, comp), "second sequence is not a part of result"); + const auto res = merge(exec, first1, last1, first2, last2, out_first, comp); + EXPECT_TRUE(res == out_last, "wrong return result from merge with predicate"); + EXPECT_TRUE(is_sorted(out_first, res, comp), "wrong result from merge with predicate"); + EXPECT_TRUE(includes(out_first, res, first1, last1, comp), "first sequence is not a part of result"); + EXPECT_TRUE(includes(out_first, res, first2, last2, comp), "second sequence is not a part of result"); } { - const auto res = merge(exec, first1, last1, first2, last2, first3); - EXPECT_TRUE(res == expected, "wrong return result from merge"); - EXPECT_TRUE(is_sorted(first3, res), "wrong result from merge"); + const auto res = merge(exec, first1, last1, first2, last2, out_first); + EXPECT_TRUE(res == out_last, "wrong return result from merge"); + EXPECT_TRUE(is_sorted(out_first, res), "wrong result from merge"); } } - template - void operator()(Policy&& exec, std::reverse_iterator first1, std::reverse_iterator last1, std::reverse_iterator first2, std::reverse_iterator last2, std::reverse_iterator first3, Compare comp) { } + + // for reverse iterators + template + void operator()(Policy&& exec, std::reverse_iterator first1, std::reverse_iterator last1, + std::reverse_iterator first2, std::reverse_iterator last2, + std::reverse_iterator out_first, std::reverse_iterator out_last, Compare comp) { + using namespace std; + typedef typename std::iterator_traits>::value_type T; + const auto res = merge(exec, first1, last1, first2, last2, out_first, std::greater()); + + EXPECT_TRUE(res == out_last, "wrong return result from merge with predicate"); + EXPECT_TRUE(is_sorted(out_first, res, std::greater()), "wrong result from merge with predicate"); + EXPECT_TRUE(includes(out_first, res, first1, last1, std::greater()), "first sequence is not a part of result"); + EXPECT_TRUE(includes(out_first, res, first2, last2, std::greater()), "second sequence is not a part of result"); + } }; template @@ -60,26 +70,27 @@ void test_merge_by_type(Generator1 generator1, Generator2 generator2) { size_t max_size = 100000; Sequence in1(max_size, generator1); Sequence in2(max_size / 2, generator2); - Sequence in3(in1.size() + in2.size()); + Sequence out(in1.size() + in2.size()); std::sort(in1.begin(), in1.end()); std::sort(in2.begin(), in2.end()); for (size_t size = 0; size <= max_size; size = size <= 16 ? size + 1 : size_t(3.1415 * size)) { - invoke_on_all_policies(test_merge(), in1.begin(), in1.begin() + size, in2.begin(), in2.begin() + size / 2, in3.begin(), std::less()); - invoke_on_all_policies(test_merge(), in1.cbegin(), in1.cbegin() + size, in2.cbegin(), in2.cbegin() + size / 2, in3.begin(), std::less()); + invoke_on_all_policies(test_merge(), in1.cbegin(), in1.cbegin() + size, in2.data(), in2.data() + size / 2, out.begin(), out.begin() + 1.5 * size, std::less()); + invoke_on_all_policies(test_merge(), in1.data(), in1.data() + size, in2.cbegin(), in2.cbegin() + size / 2, out.begin(), out.begin() + 3 * size/2, std::less()); } - } int32_t main( ) { - test_merge_by_type([](size_t v) { return (v % 2 == 0 ? v : -v) * 3; }, [](size_t v) { return v * 2; }); test_merge_by_type([](size_t v) { return float64_t(v); }, [](size_t v) { return float64_t(v - 100); }); + +#if !__PSTL_ICC_16_17_TEST_64_TIMEOUT test_merge_by_type>([](size_t v) { return Wrapper(v % 100); }, [](size_t v) { return Wrapper(v % 10); }); +#endif std::cout << done() << std::endl; return 0; diff --git a/test/test_minmax_element.cpp b/test/test_minmax_element.cpp index 30d4981a204..c43391daa5b 100644 --- a/test/test_minmax_element.cpp +++ b/test/test_minmax_element.cpp @@ -136,7 +136,7 @@ void test_by_type(std::size_t n){ // should provide minimal requirements only struct OnlyLessCompare { int32_t val; - OnlyLessCompare() {} + OnlyLessCompare() : val(0) {} OnlyLessCompare(int32_t val_) : val(val_) {} bool operator<(const OnlyLessCompare& other) const { return val < other.val; diff --git a/test/test_numeric.cpp b/test/test_numeric.cpp index a13a8083534..48a9a733400 100644 --- a/test/test_numeric.cpp +++ b/test/test_numeric.cpp @@ -67,16 +67,16 @@ struct test_reduce { void operator()(Policy&& exec, Iterator begin, Iterator end, UnaryOperation unary_op) { typedef typename Iterator::value_type T; auto zero = T(); - std::reduce(exec, begin, end); - std::reduce(exec, begin, end, zero); - std::reduce(exec, begin, end, zero, std::plus()); + T result = std::reduce(exec, begin, end); + result += std::reduce(exec, begin, end, zero); + result += std::reduce(exec, begin, end, zero, std::plus()); auto f = [](const T & a, const T &b) {return a + b; }; - std::reduce(exec, begin, end, zero, f); - std::reduce(exec, begin, begin, zero, non_const(std::plus())); + result += std::reduce(exec, begin, end, zero, f); + result += std::reduce(exec, begin, begin, zero, non_const(std::plus())); - std::transform_reduce(exec, begin, end, zero, std::plus(), unary_op); - std::transform_reduce(exec, begin, end, zero, f, unary_op); - std::transform_reduce(exec, begin, begin, zero, non_const(f), non_const(unary_op)); + result += std::transform_reduce(exec, begin, end, zero, std::plus(), unary_op); + result += std::transform_reduce(exec, begin, end, zero, f, unary_op); + result += std::transform_reduce(exec, begin, begin, zero, non_const(f), non_const(unary_op)); } }; @@ -98,11 +98,11 @@ struct test_inner_product { void operator()(Policy&& exec, InputIterator inBegin, InputIterator inEnd, OutputIterator outBegin, T init, BinaryOperation1 op1, BinaryOperation2 op2) { - std::transform_reduce(exec, inBegin, inEnd, outBegin, init); - std::transform_reduce(exec, inBegin, inEnd, outBegin, init, op1, op2); + T result = std::transform_reduce(exec, inBegin, inEnd, outBegin, init); + result += std::transform_reduce(exec, inBegin, inEnd, outBegin, init, op1, op2); //usage of "non_const" adapter below - we pass empty container due to just compilation checks - std::transform_reduce(exec, inBegin, inEnd, outBegin, init, non_const(op1), non_const(op2)); + result += std::transform_reduce(exec, inBegin, inEnd, outBegin, init, non_const(op1), non_const(op2)); } }; @@ -117,17 +117,16 @@ void test_algo_by_type() { Sequence out(n, [](size_t v)->T { return T(v); }); //fill 0..n invoke_on_all_policies( test_adjacent_difference(), in.begin(), in.end(), out.begin()); - typedef std::ptrdiff_t U; - invoke_on_all_policies( test_transform_scan(), in.begin(), in.end(), out.begin(), std::plus(), UnaryOp(), U()); - invoke_on_all_policies( test_transform_scan(), in.begin(), in.end(), out.begin(), [](const U & a, const U &b) {return a + b; }, [](const T& x) { return U(x); }, U()); + invoke_on_all_policies( test_transform_scan(), in.begin(), in.end(), out.begin(), std::plus(), UnaryOp(), T()); + invoke_on_all_policies( test_transform_scan(), in.begin(), in.end(), out.begin(), [](const T & a, const T &b) {return a + b; }, [](const T& x) { return T(x); }, T()); - invoke_on_all_policies( test_scan(), in.begin(), in.end(), out.begin(), std::plus(), U()); - invoke_on_all_policies( test_scan(), in.begin(), in.end(), out.begin(), [](const U & a, const U &b) {return a + b; }, U()); + invoke_on_all_policies( test_scan(), in.begin(), in.end(), out.begin(), std::plus(), T()); + invoke_on_all_policies( test_scan(), in.begin(), in.end(), out.begin(), [](const T & a, const T &b) {return a + b; }, T()); - invoke_on_all_policies( test_inner_product(), in.begin(), in.end(), out.begin(), T(), std::plus(), std::plus()); - invoke_on_all_policies( test_inner_product(), in.begin(), in.end(), out.begin(), T(), [](const U & a, const U &b) {return a + b; }, std::multiplies()); - invoke_on_all_policies( test_inner_product(), in.begin(), in.end(), out.begin(), T(), std::plus(), [](const U & a, const U &b) {return a + b; }); - invoke_on_all_policies( test_inner_product(), in.begin(), in.end(), out.begin(), T(), [](const U & a, const U &b) {return a + b; }, [](const U & a, const U &b) {return a + b; }); + invoke_on_all_policies( test_inner_product(), in.begin(), in.end(), out.begin(), T(), std::plus(), std::plus()); + invoke_on_all_policies( test_inner_product(), in.begin(), in.end(), out.begin(), T(), [](const T & a, const T &b) {return a + b; }, std::multiplies()); + invoke_on_all_policies( test_inner_product(), in.begin(), in.end(), out.begin(), T(), std::plus(), [](const T & a, const T &b) {return a + b; }); + invoke_on_all_policies( test_inner_product(), in.begin(), in.end(), out.begin(), T(), [](const T & a, const T &b) {return a + b; }, [](const T & a, const T &b) {return a + b; }); } } diff --git a/test/test_partial_sort.cpp b/test/test_partial_sort.cpp new file mode 100644 index 00000000000..c704096a95a --- /dev/null +++ b/test/test_partial_sort.cpp @@ -0,0 +1,115 @@ +/* + Copyright (c) 2017-2018 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + +*/ + +// Tests for partial_sort + +#include + +#include "pstl/execution" +#include "pstl/algorithm" +#include "test/utils.h" + +using namespace TestUtils; + +static std::atomic count_val; +static std::atomic count_comp; + +template +struct Num { + T val; + + Num() { ++count_val; } + Num(T v): val(v) { ++count_val; } + Num(const Num& v): val(v.val) { ++count_val; } + Num(Num&& v): val(v.val) { ++count_val; } + ~Num() { --count_val; } + Num& operator=(const Num& v) { val = v.val; return *this; } + operator T() const { return val; } + bool operator<(const Num& v) const { + ++count_comp; + return val < v.val; + } +}; + +struct test_brick_partial_sort { + template + typename std::enable_if::value, void>::type + operator()(Policy&& exec, InputIterator first, InputIterator last, Compare compare) { + + typedef typename std::iterator_traits::value_type T; + + // The rand()%(2*n+1) encourages generation of some duplicates. + std::srand(42); + const std::size_t n = last - first; + for (std::size_t k = 0; k < n; ++k) { + first[k] = T(rand() % (2 * n + 1)); + } + + for (std::size_t p = 0; p < n; p = p <= 16 ? p + 1 : std::size_t(31.415 * p)) { + auto m = first + p; + + count_comp = 0; + std::partial_sort(exec, first, m, last, compare); + + //checking upper bound number of comparisons; O(p*(last-first)log(middle-first)); where p - number of threads; + if (m - first > 1) { + auto complex = std::ceil(n * std::log(float32_t(m - first))); +#if __PSTL_USE_PAR_POLICIES + auto p = tbb::this_task_arena::max_concurrency(); +#else + auto p = 1; +#endif + EXPECT_TRUE(count_comp < complex*p, "bad complexity"); + } + + EXPECT_TRUE(std::is_sorted(first, m, compare), "bad partial sort: first - middle"); + + //10 is a kind of cut_off to avoid sorted (or occasionally sorted) the range [middle, end) at small values of n. + EXPECT_TRUE(!std::is_sorted(m, last, compare) || last - m < 10, "bad partial sort: middle - end"); + } + } + + template + typename std::enable_if::value, void>::type + operator()(Policy&& exec, InputIterator first, InputIterator end, Compare compare) {} +}; + +template +void test_partial_sort(Compare compare) { + + const std::size_t n_max = 100000; + Sequence in(n_max); + for (std::size_t n = 0; n < n_max; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) { + invoke_on_all_policies(test_brick_partial_sort(), in.begin(), in.begin() + n, compare); + } +} + +int32_t main() { + count_val = 0; + + test_partial_sort>([](Num x, Num y) {return x < y; }); + + EXPECT_TRUE(count_val == 0, "cleanup error"); + + test_partial_sort([](int32_t x, int32_t y) {return x > y; }); // Reversed so accidental use of < will be detected. + + std::cout << done() << std::endl; + return 0; +} diff --git a/test/test_partition_copy.cpp b/test/test_partition_copy.cpp index 12e077dc6e4..f05b2f76ad0 100644 --- a/test/test_partition_copy.cpp +++ b/test/test_partition_copy.cpp @@ -33,7 +33,7 @@ using namespace TestUtils; struct test_partition_copy { template void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator true_first, OutputIterator true_last, - OutputIterator2 false_first, UnaryOp unary_op) { + OutputIterator2 false_first, OutputIterator2 false_last, UnaryOp unary_op) { auto actual_ret = std::partition_copy(exec, first, last, true_first, false_first, unary_op); @@ -48,29 +48,30 @@ struct test_partition_copy { template void operator()(pstl::execution::unsequenced_policy, std::reverse_iterator first, std::reverse_iterator last, std::reverse_iterator true_first, std::reverse_iterator true_last, - std::reverse_iterator false_first, UnaryOp unary_op) { } + std::reverse_iterator false_first, OutputIterator2 false_last, UnaryOp unary_op) { } template void operator()(pstl::execution::parallel_unsequenced_policy, std::reverse_iterator first, std::reverse_iterator last, std::reverse_iterator true_first, std::reverse_iterator true_last, - std::reverse_iterator false_first, UnaryOp unary_op) { } + std::reverse_iterator false_first, OutputIterator2 false_last, UnaryOp unary_op) { } #endif }; template void test( UnaryPred pred) { - for (std::size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : std::size_t(3.1415 * n)) { - Sequence in(n, [](std::size_t v)->T { return T(v); }); - Sequence actual_true(n); - Sequence actual_false(n); + const std::size_t max_size = 100000; + Sequence in(max_size, [](std::size_t v)->T { return T(v); }); + Sequence actual_true(max_size); + Sequence actual_false(max_size); + for (std::size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : std::size_t(3.1415 * n)) { // for non-const input iterators - invoke_on_all_policies(test_partition_copy(), in.begin(), in.end(), - actual_true.begin(), actual_true.end(), actual_false.begin(), pred); + invoke_on_all_policies(test_partition_copy(), in.begin(), in.begin() + n, + actual_true.begin(), actual_true.begin() + n, actual_false.begin(), actual_false.begin() + n, pred); // for const input iterators - invoke_on_all_policies(test_partition_copy(), in.cbegin(), in.cend(), - actual_true.begin(), actual_true.end(), actual_false.begin(), pred); + invoke_on_all_policies(test_partition_copy(), in.cbegin(), in.cbegin() + n, + actual_true.begin(), actual_true.begin() + n, actual_false.begin(), actual_false.begin() + n, pred); } } diff --git a/test/test_reduce.cpp b/test/test_reduce.cpp index ef228b0eb9e..09d7714f944 100644 --- a/test/test_reduce.cpp +++ b/test/test_reduce.cpp @@ -18,6 +18,8 @@ */ +#include "test/pstl_test_config.h" + #include "pstl/execution" #include "pstl/numeric" #include "test/utils.h" @@ -56,14 +58,22 @@ void test_long_form(T init, BinaryOp binary_op, F f) { } struct test_two_short_forms { + +#if __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN //dummy specialization by policy type, in case of broken configuration + template + void operator()(pstl::execution::parallel_policy, Iterator first, Iterator last, Sum init, Sum expected) { } + template + void operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Sum init, Sum expected) { } +#endif + template void operator()(Policy&& exec, Iterator first, Iterator last, Sum init, Sum expected) { using namespace std; - auto r0 = init + reduce(exec, first, last); + Sum r0 = init + reduce(exec, first, last); EXPECT_EQ(expected, r0, "bad result from reduce(exec, first, last)"); - auto r1 = reduce(exec, first, last, init); + Sum r1 = reduce(exec, first, last, init); EXPECT_EQ(expected, r1, "bad result from reduce(exec, first, last, init)"); } }; diff --git a/test/test_remove.cpp b/test/test_remove.cpp new file mode 100644 index 00000000000..df296105223 --- /dev/null +++ b/test/test_remove.cpp @@ -0,0 +1,115 @@ +/* + Copyright (c) 2017-2018 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + +*/ + +// Test for remove, remove_if +#include "test/pstl_test_config.h" + +#include "pstl/execution" +#include "pstl/algorithm" +#include "test/utils.h" + +using namespace TestUtils; + +struct run_remove { +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration + template + void operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, + OutputIterator expected_first, OutputIterator expected_last, Size n, const T& value) { } + template + void operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, + OutputIterator expected_first, OutputIterator expected_last, Size n, const T& value) { } +#endif + + template + void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, + OutputIterator expected_first, OutputIterator expected_last, Size n, const T& value) { + // Cleaning + std::copy(first, last, expected_first); + std::copy(first, last, out_first); + + // Run remove + OutputIterator i = remove(expected_first, expected_last, value); + OutputIterator k = remove(exec, out_first, out_last, value); + EXPECT_EQ_N(expected_first, out_first, n, "wrong remove effect"); + EXPECT_TRUE(std::distance(expected_first, i) == std::distance(out_first, k), "wrong return value from remove"); + } +}; + +struct run_remove_if { +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration + template + void operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, + OutputIterator expected_first, OutputIterator expected_last, Size n, Predicate pred) { } + template + void operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, + OutputIterator expected_first, OutputIterator expected_last, Size n, Predicate pred) { } +#endif + + template + void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, + OutputIterator expected_first, OutputIterator expected_last, Size n, Predicate pred) { + // Cleaning + std::copy(first, last, expected_first); + std::copy(first, last, out_first); + + // Run remove_if + OutputIterator i = remove_if(expected_first, expected_last, pred); + OutputIterator k = remove_if(exec, out_first, out_last, pred); + EXPECT_EQ_N(expected_first, out_first, n, "wrong remove_if effect"); + EXPECT_TRUE(std::distance(expected_first, i) == std::distance(out_first, k), "wrong return value from remove_if"); + } +}; + +template +void test(T trash, const T& value, Predicate pred, Convert convert) { + const std::size_t max_size = 100000; + Sequence out(max_size, [trash](size_t) {return trash; }); + Sequence expected(max_size, [trash](size_t) {return trash; }); + + for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n) ) { + Sequence data(n, [&](size_t k) -> T {return convert(k); }); + + invoke_on_all_policies(run_remove(), data.begin(), data.end(), out.begin(), out.begin() + n, + expected.begin(), expected.begin() + n, n, value); + invoke_on_all_policies(run_remove_if(), data.begin(), data.end(), out.begin(), out.begin() + n, + expected.begin(), expected.begin() + n, n, pred); + } +} + +int32_t main( ) { +#if !__PSTL_ICC_18_TEST_EARLY_EXIT_MONOTONIC_RELEASE_BROKEN + test(666, 42, [](int32_t val) {return true; }, + [](size_t j) {return j; }); +#endif + + test(666, 2001, [](const int32_t& val) {return val != 2001; }, + [](size_t j) {return ((j + 1) % 5 & 2) != 0 ? 2001 : -1 - int32_t(j); }); + test(-666.0, 8.5, [](const float64_t& val) {return val != 8.5; }, + [](size_t j) {return ((j + 1) % 7 & 2) != 0 ? 8.5 : float64_t(j % 32 + j); }); + +#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN + test(Number(-666, OddTag()), Number(42, OddTag()), + IsMultiple(3, OddTag()), + [](int32_t j) {return Number(j, OddTag()); }); +#endif + + std::cout << done() << std::endl; + return 0; +} diff --git a/test/test_remove_copy.cpp b/test/test_remove_copy.cpp index d892e6e4a08..2288edb0282 100644 --- a/test/test_remove_copy.cpp +++ b/test/test_remove_copy.cpp @@ -26,11 +26,10 @@ using namespace TestUtils; -const size_t GuardSize = 5; struct run_remove_copy { template void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size n, const T& value, T trash) { + OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, const T& value, T trash) { // Cleaning std::fill_n(expected_first, n, trash); std::fill_n(out_first, n, trash); @@ -62,13 +61,13 @@ void test(T trash, const T& value, Convert convert, bool check_weakness = true) Sequence out(count, [=](size_t){return trash;}); Sequence expected(count, [=](size_t){return trash;}); - auto expected_result = remove_copy( in.cfbegin(), in.cfend(), expected.begin(), value ); if (check_weakness) { + auto expected_result = remove_copy(in.cfbegin(), in.cfend(), expected.begin(), value); size_t m = expected_result - expected.begin(); EXPECT_TRUE(n / 4 <= m && m <= 3 * (n + 1) / 4, "weak test for remove_copy"); } - invoke_on_all_policies(run_remove_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), count, value, trash); - invoke_on_all_policies(run_remove_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), count, value, trash); + invoke_on_all_policies(run_remove_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), expected.end(), count, value, trash); + invoke_on_all_policies(run_remove_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), expected.end(), count, value, trash); } } diff --git a/test/test_replace.cpp b/test/test_replace.cpp new file mode 100644 index 00000000000..6ff1595d39d --- /dev/null +++ b/test/test_replace.cpp @@ -0,0 +1,132 @@ +/* + Copyright (c) 2017-2018 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + +*/ + +#include "test/pstl_test_config.h" + +#include "pstl/execution" +#include "pstl/algorithm" +#include "test/utils.h" + +using namespace TestUtils; + +// This class is needed to check the self-copying +struct copy_int { + int32_t value; + int32_t copied_times = 0; + explicit copy_int(int32_t val = 0) { + value = val; + } + + copy_int& operator=(const copy_int& other) { + if (&other == this) + copied_times++; + else { + value = other.value; + copied_times = other.copied_times; + } + return *this; + } + + bool operator==(const copy_int& other) const { + return (value == other.value); + } +}; + +template +struct test_one_policy { + std::size_t len; + Iterator data_b; + Iterator data_e; + test_one_policy(Iterator data_, std::size_t len_) { + len = len_; + data_b = data_; + data_e = std::next(data_b, len); + } + template + void operator()(ExecutionPolicy&& exec, Iterator1 expected_b, Iterator1 expected_e, Iterator2 actual_b, Iterator2 actual_e, Predicate pred, const T& value, const T& old_value) { + using namespace std; + + copy(data_b, data_e, expected_b); + copy(data_b, data_e, actual_b); + + replace(expected_b, expected_e, old_value, value); + replace(exec, actual_b, actual_e, old_value, value); + + EXPECT_TRUE((check(actual_b, actual_e)), "wrong result of self assignment check"); + EXPECT_TRUE(equal(expected_b, expected_e, actual_b), "wrong result of replace"); + + copy(data_b, data_e, expected_b); + copy(data_b, data_e, actual_b); + + replace_if(expected_b, expected_e, pred, value); + replace_if(exec, actual_b, actual_e, pred, value); + EXPECT_TRUE(equal(expected_b, expected_e, actual_b), "wrong result of replace_if"); + } + + template + bool check(Iterator1 b, Iterator1 e) { + return true; + } + + template + typename std::enable_if::value, bool>::type_t check(Iterator1 b, Iterator1 e) { + return std::all_of(b, e, [](const copy_int& elem) { return elem.copied_times == 0; }); + } +}; + +template +void test(Pred pred) { + typedef typename Sequence::iterator iterator_type; + + const std::size_t max_len = 100000; + + const T1 value = T1(0); + const T1 new_value = T1(666); + + Sequence expected(max_len); + Sequence actual(max_len); + + Sequence data(max_len, [&value](std::size_t i) { + if (i % 3 == 2) { + return T1(i); + } else { + return value; + } + }); + + for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len)) { + test_one_policy temp(data.begin(), len); + + invoke_on_all_policies(temp, + expected.begin(), expected.begin() + len, + actual.begin(), actual.begin() + len, + pred, new_value, value); + } +} + +int32_t main() { + test (pstl::internal::equal_value(666)); + test ([](const uint16_t& elem) { return elem % 3 < 2; }); + test([](const float64_t& elem) { return elem * elem - 3.5 * elem > 10; }); + test ([](const copy_int& val) { return val.value / 5 > 2; }); + + std::cout << done() << std::endl; + return 0; +} diff --git a/test/test_replace_copy.cpp b/test/test_replace_copy.cpp index a8ced1224e4..eb0106404df 100644 --- a/test/test_replace_copy.cpp +++ b/test/test_replace_copy.cpp @@ -20,6 +20,8 @@ // Tests for replace_copy and replace_copy_if +#include "test/pstl_test_config.h" + #include "pstl/execution" #include "pstl/algorithm" #include "test/utils.h" @@ -29,7 +31,7 @@ using namespace TestUtils; struct test_replace_copy { template void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size n, Predicate pred, const T& old_value, const T& new_value, T trash) { + OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, Predicate pred, const T& old_value, const T& new_value, T trash) { // Cleaning std::fill_n(expected_first, n, trash); std::fill_n(out_first, n, trash); @@ -60,8 +62,8 @@ void test(T trash, const T& old_value, const T& new_value, Predicate pred, Conve Sequence out(n, [=](size_t) {return trash; }); Sequence expected(n, [=](size_t) {return trash; }); - invoke_on_all_policies(test_replace_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), out.size(), pred, old_value, new_value, trash); - invoke_on_all_policies(test_replace_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), out.size(), pred, old_value, new_value, trash); + invoke_on_all_policies(test_replace_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), expected.end(), out.size(), pred, old_value, new_value, trash); + invoke_on_all_policies(test_replace_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), expected.end(), out.size(), pred, old_value, new_value, trash); } } @@ -79,11 +81,13 @@ int32_t main( ) { [](const int32_t& x) {return x != 42; }, [](size_t j){return ((j+1)%5&2)!=0? 42 : -1- int32_t(j);}); +#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN test( Number(42,OddTag()), Number(2001,OddTag()), Number(2017, OddTag()), IsMultiple(3, OddTag()), [](int32_t j){return ((j+1)%3&2)!=0? Number(2001,OddTag()) : Number(j,OddTag());}); +#endif std::cout << "done" << std::endl; return 0; } diff --git a/test/test_scan.cpp b/test/test_scan.cpp index f19e29daa91..9d5c2ff910f 100644 --- a/test/test_scan.cpp +++ b/test/test_scan.cpp @@ -86,7 +86,7 @@ void check_and_reset( const Sequence& in, Sequence& out, Sequence& expe struct test_scan_with_plus { template - void operator()( Policy&& exec, Iterator1 in_first, Iterator1 in_last, Iterator2 out_first, Iterator2 out_last, Iterator3 expected_first, Size n, T init, T trash ) { + void operator()( Policy&& exec, Iterator1 in_first, Iterator1 in_last, Iterator2 out_first, Iterator2 out_last, Iterator3 expected_first, Iterator3 expected_last, Size n, T init, T trash ) { using namespace std; auto orr1 = inclusive ? @@ -110,14 +110,15 @@ void test_with_plus( T init, T trash, Convert convert ) { Sequence expected(in); Sequence out(n, [&](int32_t) {return trash;}); - invoke_on_all_policies(test_scan_with_plus(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), in.size(), init, trash); - invoke_on_all_policies(test_scan_with_plus(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), in.size(), init, trash); + invoke_on_all_policies(test_scan_with_plus(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), expected.end(), in.size(), init, trash); + invoke_on_all_policies(test_scan_with_plus(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), expected.end(), in.size(), init, trash); } } struct test_scan_with_binary_op { template typename std::enable_if::value, void>::type - operator()(Policy&& exec, Iterator1 in_first, Iterator1 in_last, Iterator2 out_first, Iterator2 out_last, Iterator3 expected_first, Size n, T init, BinaryOp binary_op, T trash) { + operator()(Policy&& exec, Iterator1 in_first, Iterator1 in_last, Iterator2 out_first, Iterator2 out_last, + Iterator3 expected_first, Iterator3 expected_last, Size n, T init, BinaryOp binary_op, T trash) { using namespace std; auto orr1 = inclusive ? @@ -133,7 +134,8 @@ struct test_scan_with_binary_op { template typename std::enable_if::value, void>::type - operator()(Policy&& exec, Iterator1 in_first, Iterator1 in_last, Iterator2 out_first, Iterator2 out_last, Iterator3 expected_first, Size n, T init, BinaryOp binary_op, T trash) { + operator()(Policy&& exec, Iterator1 in_first, Iterator1 in_last, Iterator2 out_first, Iterator2 out_last, + Iterator3 expected_first, Iterator3 expected_last, Size n, T init, BinaryOp binary_op, T trash) { } }; @@ -144,8 +146,8 @@ void test_with_binary_op(T init, BinaryOp binary_op, T trash, Convert convert) { Sequence expected(in); Sequence out(n, [&](int32_t k) {return trash; }); - invoke_on_all_policies(test_scan_with_binary_op(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), in.size(), init, binary_op, trash); - invoke_on_all_policies(test_scan_with_binary_op(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), in.size(), init, binary_op, trash); + invoke_on_all_policies(test_scan_with_binary_op(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), expected.end(), in.size(), init, binary_op, trash); + invoke_on_all_policies(test_scan_with_binary_op(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), expected.end(), in.size(), init, binary_op, trash); } } diff --git a/test/test_search_n.cpp b/test/test_search_n.cpp index ee2cf6aeac7..977065940e7 100644 --- a/test/test_search_n.cpp +++ b/test/test_search_n.cpp @@ -27,6 +27,13 @@ using namespace TestUtils; struct test_one_policy { +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN//dummy specialization by policy type, in case of broken configuration + template + void operator()(pstl::execution::unsequenced_policy, Iterator b, Iterator e, Size count, const T& value, Predicate pred) { } + template + void operator()(pstl::execution::parallel_unsequenced_policy, Iterator b, Iterator e, Size count, const T& value, Predicate pred) { } +#endif + template void operator()(ExecutionPolicy&& exec, Iterator b, Iterator e, Size count, const T& value, Predicate pred) { using namespace std; @@ -40,7 +47,7 @@ struct test_one_policy { }; template -void test(const std::size_t bits) { +void test() { const std::size_t max_n1 = 100000; const T value = T(1); @@ -49,10 +56,11 @@ void test(const std::size_t bits) { std::size_t res[] = { 0, 1, n1 / 2, n1 }; for(auto n2 : sub_n) { // Some of standard libraries return "first" in this case. We return "last" according to the standard - if (n2 == 0) + if (n2 == 0) { continue; + } for(auto r : res) { - Sequence in(n1, [n1, bits](std::size_t k) {return T(0); }); + Sequence in(n1, [n1](std::size_t k) {return T(0); }); std::size_t i = r, isub = 0; for(; i < n1 & isub < n2; ++i, ++isub) in[i] = value; @@ -65,11 +73,11 @@ void test(const std::size_t bits) { } int32_t main( ) { - test(8*sizeof(int32_t)); - test(8*sizeof(uint16_t)); - test(53); + test(); + test(); + test(); #if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN - test(1); + test(); #endif std::cout << done() << std::endl; diff --git a/test/test_sort.cpp b/test/test_sort.cpp index ed775fb27ea..5571faf97d1 100644 --- a/test/test_sort.cpp +++ b/test/test_sort.cpp @@ -138,7 +138,7 @@ struct test_sort_with_compare { template typename std::enable_if::value, void>::type operator()(Policy&& exec, OutputIterator tmp_first, OutputIterator tmp_last, OutputIterator2 expected_first, OutputIterator2 expected_last, - InputIterator first, Size n, Compare compare) { + InputIterator first, InputIterator last, Size n, Compare compare) { using namespace std; copy_n(first, n, expected_first); copy_n(first, n, tmp_first); @@ -162,7 +162,7 @@ struct test_sort_with_compare { template typename std::enable_if::value, void>::type operator()(Policy&& exec, OutputIterator tmp_first, OutputIterator tmp_last, OutputIterator2 expected_first, OutputIterator2 expected_last, - InputIterator first, Size n, Compare compare) { } + InputIterator first, InputIterator last, Size n, Compare compare) { } }; template @@ -174,7 +174,7 @@ void test_sort( Compare compare, Convert convert ) { Sequence in( n+2, [=](size_t k) {return convert(k,rand()%(2*n+1));} ); Sequence expected(in); Sequence tmp(in); - invoke_on_all_policies( test_sort_with_compare(), tmp.begin(), tmp.end(), expected.begin(), expected.end(), in.begin(), in.size(), compare ); + invoke_on_all_policies( test_sort_with_compare(), tmp.begin(), tmp.end(), expected.begin(), expected.end(), in.begin(), in.end(), in.size(), compare ); } } diff --git a/test/test_transform_binary.cpp b/test/test_transform_binary.cpp index 1f2a25cdf92..24b89180218 100644 --- a/test/test_transform_binary.cpp +++ b/test/test_transform_binary.cpp @@ -53,46 +53,34 @@ void check_and_reset(InputIterator1 first1, InputIterator1 last1, InputIterator2 struct test_one_policy { template void operator()( Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, - OutputIterator out_first, BinaryOp op) { + OutputIterator out_first, OutputIterator out_last, BinaryOp op) { auto orrr = std::transform( exec, first1, last1, first2, out_first, op ); -// EXPECT_TRUE( orrr==out.end(), "transform returned wrong iterator" ); check_and_reset(first1, last1, first2, out_first); } }; -template -void test() { +template +void test(Predicate pred) { for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) { - Sequence in1(n, [](size_t k) { - return k%5!=1 ? 3*k-7 : 0; - }); - Sequence in2(n, [](size_t k) { - return k%7!=2 ? 5*k-5 : 0; - }); - - Sequence out( n, [](size_t k){return -1;} ); - - //const operator() - auto flip_const = TheOperation(Out(1.5)); - invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.begin(), in2.end(), out.begin(), flip_const); - invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cend(), in2.cbegin(), in2.cend(), out.begin(), flip_const); - - //non-const operator() - invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.begin(), in2.end(), out.begin(), non_const(flip_const)); - invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cend(), in2.cbegin(), in2.cend(), out.begin(), non_const(flip_const)); - - //lambda - invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.begin(), in2.end(), out.begin(), [](const In1 x, In2& y) {return Out(Out(1.5) + x - y); }); - invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cend(), in2.cbegin(), in2.cend(), out.begin(), [](const In1 x, In2& y) {return Out(Out(1.5) + x - y); }); + Sequence in1(n, [](size_t k) { return k%5!=1 ? 3*k-7 : 0; }); + Sequence in2(n, [](size_t k) { return k%7!=2 ? 5*k-5 : 0; }); + + Sequence out(n, [](size_t k) { return -1; }); + + invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.begin(), in2.end(), out.begin(), out.end(), pred); + invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cend(), in2.cbegin(), in2.cend(), out.begin(), out.end(), pred); } } int32_t main( ) { - test(); - test(); - test(); - test(); - test(); + //const operator() + test(TheOperation(1)); + test(TheOperation(1.5)); + //non-const operator() + test(non_const(TheOperation(1.5))); + test(non_const(TheOperation(1.5))); + //lambda + test([](const int8_t& x, const float64_t& y) {return int8_t(int8_t(1.5) + x - y); }); std::cout << "done" << std::endl; return 0; } diff --git a/test/test_transform_scan.cpp b/test/test_transform_scan.cpp index 356a18ad69b..70a7f24c603 100644 --- a/test/test_transform_scan.cpp +++ b/test/test_transform_scan.cpp @@ -40,7 +40,7 @@ struct test_transform_scan { template typename std::enable_if::value, void>::type operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator expected_first, Size n, UnaryOp unary_op, T init, BinaryOp binary_op, T trash ) { + OutputIterator expected_first, OutputIterator expected_last, Size n, UnaryOp unary_op, T init, BinaryOp binary_op, T trash ) { using namespace std; auto orr1 = inclusive ? @@ -64,7 +64,7 @@ struct test_transform_scan { template typename std::enable_if::value, void>::type operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator expected_first, Size n, UnaryOp unary_op, T init, BinaryOp binary_op, T trash) { + OutputIterator expected_first, OutputIterator expected_last, Size n, UnaryOp unary_op, T init, BinaryOp binary_op, T trash) { } }; @@ -96,8 +96,8 @@ void test( UnaryOp unary_op, Out init, BinaryOp binary_op, Out trash ) { pstl::internal::brick_transform_scan(in.cbegin(), in.cend(), out.fbegin(), unary_op, init, binary_op, std::false_type()/*exclusive*/); check_and_reset( expected.begin(), out.begin(), out.size(), trash ); - invoke_on_all_policies(test_transform_scan(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), in.size(), unary_op, init, binary_op, trash); - invoke_on_all_policies(test_transform_scan(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), in.size(), unary_op, init, binary_op, trash); + invoke_on_all_policies(test_transform_scan(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), expected.end(), in.size(), unary_op, init, binary_op, trash); + invoke_on_all_policies(test_transform_scan(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), expected.end(), in.size(), unary_op, init, binary_op, trash); } } diff --git a/test/test_uninitialized_construct.cpp b/test/test_uninitialized_construct.cpp index 8f11900ff49..920c9b083f3 100644 --- a/test/test_uninitialized_construct.cpp +++ b/test/test_uninitialized_construct.cpp @@ -103,7 +103,7 @@ void test_uninit_construct_by_type() { int32_t main() { // for user-defined types -#if !__PSTL_TEST_PAR_TBB_RT_ICC_16_VC14_RELEASE_64_BROKEN +#if !__PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN test_uninit_construct_by_type>(); test_uninit_construct_by_type>>(); #endif diff --git a/test/test_uninitialized_copy_move.cpp b/test/test_uninitialized_copy_move.cpp index 5cce8245ac5..04be25ecf2e 100644 --- a/test/test_uninitialized_copy_move.cpp +++ b/test/test_uninitialized_copy_move.cpp @@ -74,7 +74,7 @@ struct test_uninitialized_copy_move { std::destroy_n(exec, out_first, n); } -#if __PSTL_TEST_SIMD_LAMBDA_ICC_17_VC141_DEBUG_32_BROKEN || __PSTL_TEST_SIMD_LAMBDA_ICC_16_VC14_DEBUG_32_BROKEN +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN template void operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, size_t n, /*is_trivial=*/std::true_type) {} @@ -123,7 +123,7 @@ int32_t main() { test_uninitialized_copy_move_by_type(); // for user-defined types -#if !__PSTL_TEST_SIMD_LAMBDA_ICC_17_VC141_DEBUG_32_BROKEN && !__PSTL_TEST_SIMD_LAMBDA_ICC_16_VC14_DEBUG_32_BROKEN && !__PSTL_TEST_PAR_TBB_RT_ICC_16_VC14_RELEASE_64_BROKEN +#if !__PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN && !__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN && !__PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN test_uninitialized_copy_move_by_type>(); #endif diff --git a/test/test_unique_copy_equal.cpp b/test/test_unique_copy_equal.cpp index 1257e0e0f79..18326b37a9d 100644 --- a/test/test_unique_copy_equal.cpp +++ b/test/test_unique_copy_equal.cpp @@ -27,12 +27,10 @@ using namespace TestUtils; -const size_t GuardSize = 5; - struct run_unique_copy { template void operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, OutputIterator out_last, - OutputIterator2 expected_first, Size n, Predicate pred, T trash) { + OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, Predicate pred, T trash) { // Cleaning std::fill_n(expected_first, n, trash); std::fill_n(out_first, n, trash); @@ -75,12 +73,12 @@ void test(T trash, BinaryPredicate pred, Convert convert, bool check_weakness = count += k == 0 || !pred(in[k], in[k - 1]) ? 1 : 0; Sequence out(count, [=](size_t) {return trash; }); Sequence expected(count, [=](size_t) {return trash; }); - auto expected_result = unique_copy(in.cfbegin(), in.cfend(), expected.begin(), pred); if (check_weakness) { + auto expected_result = unique_copy(in.begin(), in.end(), expected.begin(), pred); size_t m = expected_result - expected.begin(); EXPECT_TRUE(n / (n<10000 ? 4 : 6) <= m && m <= (3 * n + 1) / 4, "weak test for unique_copy"); } - invoke_on_all_policies(run_unique_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), count, pred, trash); + invoke_on_all_policies(run_unique_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), expected.end(), count, pred, trash); } } diff --git a/test/utils.h b/test/utils.h index 7b1bda3279c..6eecbf97dfb 100644 --- a/test/utils.h +++ b/test/utils.h @@ -232,6 +232,7 @@ class Sequence { bidirectional_iterator biend() { return bidirectional_iterator(m_storage.end()); } std::size_t size() const { return m_storage.size(); } + const T* data() const { return m_storage.data(); } typename std::vector::reference operator[]( size_t j ) { return m_storage[j]; } const T& operator[]( size_t j ) const { return m_storage[j]; } @@ -463,8 +464,13 @@ struct MakeIterator { } }; + +// Useful constant variables +constexpr std::size_t GuardSize = 5; +constexpr std::size_t sizeLimit = 1000; + template // local iterator_traits for non-iterators -struct iterator_traits_ {}; +struct iterator_traits_ { }; template // For iterators struct iterator_traits_::value, @@ -481,18 +487,17 @@ struct iterator_traits_{ template using is_same_iterator_category = std::is_same::iterator_category, Tag>; -const std::size_t sizeLimit = 1000; // if we run with reverse or const iterators we shouldn't test the large range template struct invoke_if_ { template - void operator()(bool is_allow, Op op, Rest... rest) { - if (is_allow) op(rest...); + void operator()(bool is_allow, Op op, Rest&&... rest) { + if (is_allow) op(std::forward(rest)...); }}; template < > struct invoke_if_ { template - void operator()(bool is_allow, Op op, Rest... rest) { op(rest...); } + void operator()(bool is_allow, Op op, Rest&&... rest) { op(std::forward(rest)...); } }; // Invoker for different types of iterators. @@ -507,50 +512,43 @@ struct iterator_invoker { template typename std::enable_if::value, void>::type - operator()(Policy&& exec, Op op, Iterator begin, Size n, Rest... rest) { - invoke_if()(n <= sizeLimit, op, exec, make_iterator()(begin), n, rest...); + operator()(Policy&& exec, Op op, Iterator begin, Size n, Rest&&... rest) { + invoke_if()(n <= sizeLimit, op, exec, make_iterator()(begin), n, std::forward(rest)...); } template typename std::enable_if::value, void>::type - operator()(Policy&& exec, Op op, Iterator inputBegin, Iterator inputEnd, Rest... rest) { + operator()(Policy&& exec, Op op, Iterator inputBegin, Iterator inputEnd, Rest&&... rest) { invoke_if()(std::distance(inputBegin, inputEnd) <= sizeLimit, op, exec, - make_iterator()(inputBegin), make_iterator()(inputEnd), rest...); + make_iterator()(inputBegin), make_iterator()(inputEnd), std::forward(rest)...); } template typename std::enable_if::value, void>::type operator()(Policy&& exec, Op op, InputIterator inputBegin, InputIterator inputEnd, - OutputIterator outputBegin, Rest... rest) { + OutputIterator outputBegin, Rest&&... rest) { invoke_if()(std::distance(inputBegin, inputEnd) <= sizeLimit, op, exec, make_iterator()(inputBegin), make_iterator()(inputEnd), - make_iterator()(outputBegin), rest...); - } - - template - typename std::enable_if::value, void>::type - operator()(Policy&& exec, Op op, InputIterator inputBegin, Size n, OutputIterator outputBegin, Rest... rest) { - invoke_if()(n <= sizeLimit, op, exec, make_iterator()(inputBegin), n, - make_iterator()(outputBegin), rest...); + make_iterator()(outputBegin), std::forward(rest)...); } template typename std::enable_if::value, void>::type operator()(Policy&& exec, Op op, InputIterator inputBegin, InputIterator inputEnd, - OutputIterator outputBegin, OutputIterator outputEnd, Rest... rest) { + OutputIterator outputBegin, OutputIterator outputEnd, Rest&&... rest) { invoke_if()(std::distance(inputBegin, inputEnd) <= sizeLimit, op, exec, make_iterator()(inputBegin), make_iterator()(inputEnd), - make_iterator()(outputBegin), make_iterator()(outputEnd), rest...); + make_iterator()(outputBegin), make_iterator()(outputEnd), std::forward(rest)...); } template typename std::enable_if::value, void>::type operator()(Policy&& exec, Op op, InputIterator1 inputBegin1, InputIterator1 inputEnd1, InputIterator2 inputBegin2, InputIterator2 inputEnd2, - OutputIterator outputBegin, Rest... rest) { + OutputIterator outputBegin, OutputIterator outputEnd, Rest&&... rest) { invoke_if()(std::distance(inputBegin1, inputEnd1) <= sizeLimit, op, exec, make_iterator()(inputBegin1), make_iterator()(inputEnd1), make_iterator()(inputBegin2), make_iterator()(inputEnd2), - make_iterator()(outputBegin), rest...); + make_iterator()(outputBegin), make_iterator()(outputEnd), std::forward(rest)...); } }; @@ -564,53 +562,44 @@ struct iterator_invoker { template typename std::enable_if::value, void>::type - operator()(Policy&& exec, Op op, Iterator begin, Size n, Rest... rest) { + operator()(Policy&& exec, Op op, Iterator begin, Size n, Rest&&... rest) { if(n <= sizeLimit) - op(exec, make_iterator()(begin + n), n, rest...); + op(exec, make_iterator()(begin + n), n, std::forward(rest)...); } template typename std::enable_if::value, void>::type - operator()(Policy&& exec, Op op, Iterator inputBegin, Iterator inputEnd, Rest... rest) { + operator()(Policy&& exec, Op op, Iterator inputBegin, Iterator inputEnd, Rest&&... rest) { if(std::distance(inputBegin, inputEnd) <= sizeLimit) - op(exec, make_iterator()(inputEnd), make_iterator()(inputBegin), rest...); + op(exec, make_iterator()(inputEnd), make_iterator()(inputBegin), std::forward(rest)...); } template typename std::enable_if::value, void>::type operator()(Policy&& exec, Op op, InputIterator inputBegin, InputIterator inputEnd, - OutputIterator outputBegin, Rest... rest) { + OutputIterator outputBegin, Rest&&... rest) { if (std::distance(inputBegin, inputEnd) <= sizeLimit) op(exec, make_iterator()(inputEnd), make_iterator()(inputBegin), - make_iterator()(outputBegin + (inputEnd - inputBegin)), rest...); - } - - template - typename std::enable_if::value, void>::type - operator()(Policy&& exec, Op op, InputIterator inputBegin, Size n, - OutputIterator outputBegin, Rest... rest) { - if (n <= sizeLimit) - op(exec, make_iterator()(inputBegin + n), n, - make_iterator()(outputBegin + n), rest...); + make_iterator()(outputBegin + (inputEnd - inputBegin)), std::forward(rest)...); } template typename std::enable_if::value, void>::type operator()(Policy&& exec, Op op, InputIterator inputBegin, InputIterator inputEnd, - OutputIterator outputBegin, OutputIterator outputEnd, Rest... rest) { + OutputIterator outputBegin, OutputIterator outputEnd, Rest&&... rest) { if (std::distance(inputBegin, inputEnd) <= sizeLimit) op(exec, make_iterator()(inputEnd), make_iterator()(inputBegin), - make_iterator()(outputEnd), make_iterator()(outputBegin), rest...); + make_iterator()(outputEnd), make_iterator()(outputBegin), std::forward(rest)...); } template typename std::enable_if::value, void>::type operator()(Policy&& exec, Op op, InputIterator1 inputBegin1, InputIterator1 inputEnd1, InputIterator2 inputBegin2, InputIterator2 inputEnd2, - OutputIterator outputBegin, Rest... rest) { + OutputIterator outputBegin, OutputIterator outputEnd, Rest&&... rest) { if (std::distance(inputBegin1, inputEnd1) <= sizeLimit) op(exec, make_iterator()(inputEnd1), make_iterator()(inputBegin1), make_iterator()(inputEnd2), make_iterator()(inputBegin2), - make_iterator()(outputBegin + (inputEnd2 - inputBegin2)), rest...); + make_iterator()(outputEnd), make_iterator()(outputBegin), std::forward(rest)...); } }; @@ -618,44 +607,44 @@ struct iterator_invoker { template <> struct iterator_invoker { template - void operator()(Rest... rest) {} + void operator()(Rest&&... rest) {} }; template struct reverse_invoker { template - void operator()(Rest... rest) { + void operator()(Rest&&... rest) { // Random-access iterator - iterator_invoker()(rest...); + iterator_invoker()(std::forward(rest)...); // Forward iterator - iterator_invoker()(rest...); + iterator_invoker()(std::forward(rest)...); // Bidirectional iterator - iterator_invoker()(rest...); + iterator_invoker()(std::forward(rest)...); } }; struct invoke_on_all_iterator_types { template - void operator()(Rest... rest) { - reverse_invoker< /* IsReverse = */ std::false_type>()(rest...); - reverse_invoker< /* IsReverse = */ std::true_type>()(rest...); + void operator()(Rest&&... rest) { + reverse_invoker< /* IsReverse = */ std::false_type>()(std::forward(rest)...); + reverse_invoker< /* IsReverse = */ std::true_type>()(std::forward(rest)...); } }; //============================================================================ // Invoke op(policy,rest...) for each possible policy. template -void invoke_on_all_policies(Op op, T... rest) { +void invoke_on_all_policies(Op op, T&&... rest) { using namespace pstl::execution; // Try static execution policies - invoke_on_all_iterator_types()(seq, op, rest...); - invoke_on_all_iterator_types()(unseq, op, rest...); + invoke_on_all_iterator_types()(seq, op, std::forward(rest)...); + invoke_on_all_iterator_types()(unseq, op, std::forward(rest)...); #if __PSTL_USE_PAR_POLICIES - invoke_on_all_iterator_types()(par, op, rest...); - invoke_on_all_iterator_types()(par_unseq, op, rest...); + invoke_on_all_iterator_types()(par, op, std::forward(rest)...); + invoke_on_all_iterator_types()(par_unseq, op, std::forward(rest)...); #endif } @@ -666,7 +655,9 @@ struct NonConstAdapter { NonConstAdapter(const F& f): my_f(f) {} template - auto operator()(Types&&... args) -> decltype(std::declval().operator()(std::forward(args)...)) {return my_f(std::forward(args)...);} + auto operator()(Types&&... args) -> decltype(std::declval().operator()(std::forward(args)...)) { + return my_f(std::forward(args)...); + } }; template @@ -709,13 +700,17 @@ class Wrapper { bool operator<(const Wrapper& input) const { return *my_field < *input.my_field; } + bool operator>(const Wrapper& input) const { + return *my_field > *input.my_field; + } friend std::ostream& operator<<(std::ostream& stream, const Wrapper& input) { return stream << *(input.my_field); } ~Wrapper() { --my_count; - if (move_count > 0) + if (move_count > 0) { --move_count; + } } T* get_my_field() const { return my_field.get(); }; static size_t Count() { return my_count; }