Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:12:58

0001 /*
0002     Copyright (c) 2005-2020 Intel Corporation
0003 
0004     Licensed under the Apache License, Version 2.0 (the "License");
0005     you may not use this file except in compliance with the License.
0006     You may obtain a copy of the License at
0007 
0008         http://www.apache.org/licenses/LICENSE-2.0
0009 
0010     Unless required by applicable law or agreed to in writing, software
0011     distributed under the License is distributed on an "AS IS" BASIS,
0012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013     See the License for the specific language governing permissions and
0014     limitations under the License.
0015 */
0016 
0017 #ifndef __TBB_parallel_sort_H
0018 #define __TBB_parallel_sort_H
0019 
0020 #define __TBB_parallel_sort_H_include_area
0021 #include "internal/_warning_suppress_enable_notice.h"
0022 
0023 #include "parallel_for.h"
0024 #include "blocked_range.h"
0025 #include "internal/_range_iterator.h"
0026 #include <algorithm>
0027 #include <iterator>
0028 #include <functional>
0029 #if __TBB_TASK_GROUP_CONTEXT
0030     #include "tbb_profiling.h"
0031 #endif
0032 
0033 namespace tbb {
0034 
0035 namespace interface9 {
0036 //! @cond INTERNAL
0037 namespace internal {
0038 
0039 using tbb::internal::no_assign;
0040 
0041 //! Range used in quicksort to split elements into subranges based on a value.
0042 /** The split operation selects a splitter and places all elements less than or equal
0043     to the value in the first range and the remaining elements in the second range.
0044     @ingroup algorithms */
0045 template<typename RandomAccessIterator, typename Compare>
0046 class quick_sort_range: private no_assign {
0047 
0048     inline size_t median_of_three(const RandomAccessIterator &array, size_t l, size_t m, size_t r) const {
0049         return comp(array[l], array[m]) ? ( comp(array[m], array[r]) ? m : ( comp( array[l], array[r]) ? r : l ) )
0050                                         : ( comp(array[r], array[m]) ? m : ( comp( array[r], array[l] ) ? r : l ) );
0051     }
0052 
0053     inline size_t pseudo_median_of_nine( const RandomAccessIterator &array, const quick_sort_range &range ) const {
0054         size_t offset = range.size/8u;
0055         return median_of_three(array,
0056                                median_of_three(array, 0, offset, offset*2),
0057                                median_of_three(array, offset*3, offset*4, offset*5),
0058                                median_of_three(array, offset*6, offset*7, range.size - 1) );
0059 
0060     }
0061 
0062     size_t split_range( quick_sort_range& range ) {
0063         using std::iter_swap;
0064         RandomAccessIterator array = range.begin;
0065         RandomAccessIterator key0 = range.begin;
0066         size_t m = pseudo_median_of_nine(array, range);
0067         if (m) iter_swap ( array, array+m );
0068 
0069         size_t i=0;
0070         size_t j=range.size;
0071         // Partition interval [i+1,j-1] with key *key0.
0072         for(;;) {
0073             __TBB_ASSERT( i<j, NULL );
0074             // Loop must terminate since array[l]==*key0.
0075             do {
0076                 --j;
0077                 __TBB_ASSERT( i<=j, "bad ordering relation?" );
0078             } while( comp( *key0, array[j] ));
0079             do {
0080                 __TBB_ASSERT( i<=j, NULL );
0081                 if( i==j ) goto partition;
0082                 ++i;
0083             } while( comp( array[i],*key0 ));
0084             if( i==j ) goto partition;
0085             iter_swap( array+i, array+j );
0086         }
0087 partition:
0088         // Put the partition key were it belongs
0089         iter_swap( array+j, key0 );
0090         // array[l..j) is less or equal to key.
0091         // array(j..r) is greater or equal to key.
0092         // array[j] is equal to key
0093         i=j+1;
0094         size_t new_range_size = range.size-i;
0095         range.size = j;
0096         return new_range_size;
0097     }
0098 
0099 public:
0100 
0101     static const size_t grainsize = 500;
0102     const Compare &comp;
0103     size_t size;
0104     RandomAccessIterator begin;
0105 
0106     quick_sort_range( RandomAccessIterator begin_, size_t size_, const Compare &comp_ ) :
0107         comp(comp_), size(size_), begin(begin_) {}
0108 
0109     bool empty() const {return size==0;}
0110     bool is_divisible() const {return size>=grainsize;}
0111 
0112     quick_sort_range( quick_sort_range& range, split )
0113         : comp(range.comp)
0114         , size(split_range(range))
0115           // +1 accounts for the pivot element, which is at its correct place
0116           // already and, therefore, is not included into subranges.
0117         , begin(range.begin+range.size+1) {}
0118 };
0119 
0120 #if __TBB_TASK_GROUP_CONTEXT
0121 //! Body class used to test if elements in a range are presorted
0122 /** @ingroup algorithms */
0123 template<typename RandomAccessIterator, typename Compare>
0124 class quick_sort_pretest_body : no_assign {
0125     const Compare &comp;
0126 
0127 public:
0128     quick_sort_pretest_body(const Compare &_comp) : comp(_comp) {}
0129 
0130     void operator()( const blocked_range<RandomAccessIterator>& range ) const {
0131         task &my_task = task::self();
0132         RandomAccessIterator my_end = range.end();
0133 
0134         int i = 0;
0135         for (RandomAccessIterator k = range.begin(); k != my_end; ++k, ++i) {
0136             if ( i%64 == 0 && my_task.is_cancelled() ) break;
0137 
0138             // The k-1 is never out-of-range because the first chunk starts at begin+serial_cutoff+1
0139             if ( comp( *(k), *(k-1) ) ) {
0140                 my_task.cancel_group_execution();
0141                 break;
0142             }
0143         }
0144     }
0145 
0146 };
0147 #endif /* __TBB_TASK_GROUP_CONTEXT */
0148 
0149 //! Body class used to sort elements in a range that is smaller than the grainsize.
0150 /** @ingroup algorithms */
0151 template<typename RandomAccessIterator, typename Compare>
0152 struct quick_sort_body {
0153     void operator()( const quick_sort_range<RandomAccessIterator,Compare>& range ) const {
0154         //SerialQuickSort( range.begin, range.size, range.comp );
0155         std::sort( range.begin, range.begin + range.size, range.comp );
0156     }
0157 };
0158 
0159 //! Wrapper method to initiate the sort by calling parallel_for.
0160 /** @ingroup algorithms */
0161 template<typename RandomAccessIterator, typename Compare>
0162 void parallel_quick_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp ) {
0163 #if __TBB_TASK_GROUP_CONTEXT
0164     task_group_context my_context(PARALLEL_SORT);
0165     const int serial_cutoff = 9;
0166 
0167     __TBB_ASSERT( begin + serial_cutoff < end, "min_parallel_size is smaller than serial cutoff?" );
0168     RandomAccessIterator k = begin;
0169     for ( ; k != begin + serial_cutoff; ++k ) {
0170         if ( comp( *(k+1), *k ) ) {
0171             goto do_parallel_quick_sort;
0172         }
0173     }
0174 
0175     parallel_for( blocked_range<RandomAccessIterator>(k+1, end),
0176                   quick_sort_pretest_body<RandomAccessIterator,Compare>(comp),
0177                   auto_partitioner(),
0178                   my_context);
0179 
0180     if (my_context.is_group_execution_cancelled())
0181 do_parallel_quick_sort:
0182 #endif /* __TBB_TASK_GROUP_CONTEXT */
0183         parallel_for( quick_sort_range<RandomAccessIterator,Compare>(begin, end-begin, comp ),
0184                       quick_sort_body<RandomAccessIterator,Compare>(),
0185                       auto_partitioner() );
0186 }
0187 
0188 } // namespace internal
0189 //! @endcond
0190 } // namespace interfaceX
0191 
0192 /** \page parallel_sort_iter_req Requirements on iterators for parallel_sort
0193     Requirements on the iterator type \c It and its value type \c T for \c parallel_sort:
0194 
0195     - \code void iter_swap( It a, It b ) \endcode Swaps the values of the elements the given
0196     iterators \c a and \c b are pointing to. \c It should be a random access iterator.
0197 
0198     - \code bool Compare::operator()( const T& x, const T& y ) \endcode True if x comes before y;
0199 **/
0200 
0201 /** \name parallel_sort
0202     See also requirements on \ref parallel_sort_iter_req "iterators for parallel_sort". **/
0203 //@{
0204 
0205 //! Sorts the data in [begin,end) using the given comparator
0206 /** The compare function object is used for all comparisons between elements during sorting.
0207     The compare object must define a bool operator() function.
0208     @ingroup algorithms **/
0209 template<typename RandomAccessIterator, typename Compare>
0210 void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp) {
0211     const int min_parallel_size = 500;
0212     if( end > begin ) {
0213         if (end - begin < min_parallel_size) {
0214             std::sort(begin, end, comp);
0215         } else {
0216             interface9::internal::parallel_quick_sort(begin, end, comp);
0217         }
0218     }
0219 }
0220 
0221 //! Sorts the data in [begin,end) with a default comparator \c std::less<RandomAccessIterator>
0222 /** @ingroup algorithms **/
0223 template<typename RandomAccessIterator>
0224 inline void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end ) {
0225     parallel_sort( begin, end, std::less< typename std::iterator_traits<RandomAccessIterator>::value_type >() );
0226 }
0227 
0228 //! Sorts the data in rng using the given comparator
0229 /** @ingroup algorithms **/
0230 template<typename Range, typename Compare>
0231 void parallel_sort(Range& rng, const Compare& comp) {
0232     parallel_sort(tbb::internal::first(rng), tbb::internal::last(rng), comp);
0233 }
0234 
0235 //! Sorts the data in rng with a default comparator \c std::less<RandomAccessIterator>
0236 /** @ingroup algorithms **/
0237 template<typename Range>
0238 void parallel_sort(Range& rng) {
0239     parallel_sort(tbb::internal::first(rng), tbb::internal::last(rng));
0240 }
0241 
0242 //! Sorts the data in the range \c [begin,end) with a default comparator \c std::less<T>
0243 /** @ingroup algorithms **/
0244 template<typename T>
0245 inline void parallel_sort( T * begin, T * end ) {
0246     parallel_sort( begin, end, std::less< T >() );
0247 }
0248 //@}
0249 
0250 
0251 } // namespace tbb
0252 
0253 #include "internal/_warning_suppress_disable_notice.h"
0254 #undef __TBB_parallel_sort_H_include_area
0255 
0256 #endif
0257