File indexing completed on 2025-01-18 10:12:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
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
0037 namespace internal {
0038
0039 using tbb::internal::no_assign;
0040
0041
0042
0043
0044
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
0072 for(;;) {
0073 __TBB_ASSERT( i<j, NULL );
0074
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
0089 iter_swap( array+j, key0 );
0090
0091
0092
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 ∁
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
0116
0117 , begin(range.begin+range.size+1) {}
0118 };
0119
0120 #if __TBB_TASK_GROUP_CONTEXT
0121
0122
0123 template<typename RandomAccessIterator, typename Compare>
0124 class quick_sort_pretest_body : no_assign {
0125 const Compare ∁
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
0139 if ( comp( *(k), *(k-1) ) ) {
0140 my_task.cancel_group_execution();
0141 break;
0142 }
0143 }
0144 }
0145
0146 };
0147 #endif
0148
0149
0150
0151 template<typename RandomAccessIterator, typename Compare>
0152 struct quick_sort_body {
0153 void operator()( const quick_sort_range<RandomAccessIterator,Compare>& range ) const {
0154
0155 std::sort( range.begin, range.begin + range.size, range.comp );
0156 }
0157 };
0158
0159
0160
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
0183 parallel_for( quick_sort_range<RandomAccessIterator,Compare>(begin, end-begin, comp ),
0184 quick_sort_body<RandomAccessIterator,Compare>(),
0185 auto_partitioner() );
0186 }
0187
0188 }
0189
0190 }
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
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
0222
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
0229
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
0236
0237 template<typename Range>
0238 void parallel_sort(Range& rng) {
0239 parallel_sort(tbb::internal::first(rng), tbb::internal::last(rng));
0240 }
0241
0242
0243
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 }
0252
0253 #include "internal/_warning_suppress_disable_notice.h"
0254 #undef __TBB_parallel_sort_H_include_area
0255
0256 #endif
0257