00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef __TBB_parallel_sort_H
00022 #define __TBB_parallel_sort_H
00023
00024 #include "parallel_for.h"
00025 #include "blocked_range.h"
00026 #include <algorithm>
00027 #include <iterator>
00028 #include <functional>
00029
00030 namespace tbb {
00031
00033 namespace internal {
00034
00036
00039 template<typename RandomAccessIterator, typename Compare>
00040 class quick_sort_range: private no_assign {
00041
00042 inline size_t median_of_three(const RandomAccessIterator &array, size_t l, size_t m, size_t r) const {
00043 return comp(array[l], array[m]) ? ( comp(array[m], array[r]) ? m : ( comp( array[l], array[r]) ? r : l ) )
00044 : ( comp(array[r], array[m]) ? m : ( comp( array[r], array[l] ) ? r : l ) );
00045 }
00046
00047 inline size_t pseudo_median_of_nine( const RandomAccessIterator &array, const quick_sort_range &range ) const {
00048 size_t offset = range.size/8u;
00049 return median_of_three(array,
00050 median_of_three(array, 0, offset, offset*2),
00051 median_of_three(array, offset*3, offset*4, offset*5),
00052 median_of_three(array, offset*6, offset*7, range.size - 1) );
00053
00054 }
00055
00056 public:
00057
00058 static const size_t grainsize = 500;
00059 const Compare ∁
00060 RandomAccessIterator begin;
00061 size_t size;
00062
00063 quick_sort_range( RandomAccessIterator begin_, size_t size_, const Compare &comp_ ) :
00064 comp(comp_), begin(begin_), size(size_) {}
00065
00066 bool empty() const {return size==0;}
00067 bool is_divisible() const {return size>=grainsize;}
00068
00069 quick_sort_range( quick_sort_range& range, split ) : comp(range.comp) {
00070 RandomAccessIterator array = range.begin;
00071 RandomAccessIterator key0 = range.begin;
00072 size_t m = pseudo_median_of_nine(array, range);
00073 if (m) std::swap ( array[0], array[m] );
00074
00075 size_t i=0;
00076 size_t j=range.size;
00077
00078 for(;;) {
00079 __TBB_ASSERT( i<j, NULL );
00080
00081 do {
00082 --j;
00083 __TBB_ASSERT( i<=j, "bad ordering relation?" );
00084 } while( comp( *key0, array[j] ));
00085 do {
00086 __TBB_ASSERT( i<=j, NULL );
00087 if( i==j ) goto partition;
00088 ++i;
00089 } while( comp( array[i],*key0 ));
00090 if( i==j ) goto partition;
00091 std::swap( array[i], array[j] );
00092 }
00093 partition:
00094
00095 std::swap( array[j], *key0 );
00096
00097
00098
00099 i=j+1;
00100 begin = array+i;
00101 size = range.size-i;
00102 range.size = j;
00103 }
00104 };
00105
00107
00108 template<typename RandomAccessIterator, typename Compare>
00109 class quick_sort_pretest_body : internal::no_assign {
00110 const Compare ∁
00111
00112 public:
00113 quick_sort_pretest_body(const Compare &_comp) : comp(_comp) {}
00114
00115 void operator()( const blocked_range<RandomAccessIterator>& range ) const {
00116 task &my_task = task::self();
00117 RandomAccessIterator my_end = range.end();
00118
00119 int i = 0;
00120 for (RandomAccessIterator k = range.begin(); k != my_end; ++k, ++i) {
00121 if ( i%64 == 0 && my_task.is_cancelled() ) break;
00122
00123
00124 if ( comp( *(k), *(k-1) ) ) {
00125 my_task.cancel_group_execution();
00126 break;
00127 }
00128 }
00129 }
00130
00131 };
00132
00134
00135 template<typename RandomAccessIterator, typename Compare>
00136 struct quick_sort_body {
00137 void operator()( const quick_sort_range<RandomAccessIterator,Compare>& range ) const {
00138
00139 std::sort( range.begin, range.begin + range.size, range.comp );
00140 }
00141 };
00142
00144
00145 template<typename RandomAccessIterator, typename Compare>
00146 void parallel_quick_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp ) {
00147 task_group_context my_context;
00148 const int serial_cutoff = 9;
00149
00150 __TBB_ASSERT( begin + serial_cutoff < end, "min_parallel_size is smaller than serial cutoff?" );
00151 RandomAccessIterator k;
00152 for ( k = begin ; k != begin + serial_cutoff; ++k ) {
00153 if ( comp( *(k+1), *k ) ) {
00154 goto do_parallel_quick_sort;
00155 }
00156 }
00157
00158 parallel_for( blocked_range<RandomAccessIterator>(k+1, end),
00159 quick_sort_pretest_body<RandomAccessIterator,Compare>(comp),
00160 auto_partitioner(),
00161 my_context);
00162
00163 if (my_context.is_group_execution_cancelled())
00164 do_parallel_quick_sort:
00165 parallel_for( quick_sort_range<RandomAccessIterator,Compare>(begin, end-begin, comp ),
00166 quick_sort_body<RandomAccessIterator,Compare>(),
00167 auto_partitioner() );
00168 }
00169
00170 }
00172
00183
00185
00188 template<typename RandomAccessIterator, typename Compare>
00189 void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp) {
00190 const int min_parallel_size = 500;
00191 if( end > begin ) {
00192 if (end - begin < min_parallel_size) {
00193 std::sort(begin, end, comp);
00194 } else {
00195 internal::parallel_quick_sort(begin, end, comp);
00196 }
00197 }
00198 }
00199
00201
00202 template<typename RandomAccessIterator>
00203 inline void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end ) {
00204 parallel_sort( begin, end, std::less< typename std::iterator_traits<RandomAccessIterator>::value_type >() );
00205 }
00206
00208
00209 template<typename T>
00210 inline void parallel_sort( T * begin, T * end ) {
00211 parallel_sort( begin, end, std::less< T >() );
00212 }
00214
00215
00216 }
00217
00218 #endif
00219