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