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
00106 #if __TBB_TASK_GROUP_CONTEXT
00108
00109 template<typename RandomAccessIterator, typename Compare>
00110 class quick_sort_pretest_body : internal::no_assign {
00111 const Compare ∁
00112
00113 public:
00114 quick_sort_pretest_body(const Compare &_comp) : comp(_comp) {}
00115
00116 void operator()( const blocked_range<RandomAccessIterator>& range ) const {
00117 task &my_task = task::self();
00118 RandomAccessIterator my_end = range.end();
00119
00120 int i = 0;
00121 for (RandomAccessIterator k = range.begin(); k != my_end; ++k, ++i) {
00122 if ( i%64 == 0 && my_task.is_cancelled() ) break;
00123
00124
00125 if ( comp( *(k), *(k-1) ) ) {
00126 my_task.cancel_group_execution();
00127 break;
00128 }
00129 }
00130 }
00131
00132 };
00133 #endif
00134
00136
00137 template<typename RandomAccessIterator, typename Compare>
00138 struct quick_sort_body {
00139 void operator()( const quick_sort_range<RandomAccessIterator,Compare>& range ) const {
00140
00141 std::sort( range.begin, range.begin + range.size, range.comp );
00142 }
00143 };
00144
00146
00147 template<typename RandomAccessIterator, typename Compare>
00148 void parallel_quick_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp ) {
00149 #if __TBB_TASK_GROUP_CONTEXT
00150 task_group_context my_context;
00151 const int serial_cutoff = 9;
00152
00153 __TBB_ASSERT( begin + serial_cutoff < end, "min_parallel_size is smaller than serial cutoff?" );
00154 RandomAccessIterator k;
00155 for ( k = begin ; k != begin + serial_cutoff; ++k ) {
00156 if ( comp( *(k+1), *k ) ) {
00157 goto do_parallel_quick_sort;
00158 }
00159 }
00160
00161 parallel_for( blocked_range<RandomAccessIterator>(k+1, end),
00162 quick_sort_pretest_body<RandomAccessIterator,Compare>(comp),
00163 auto_partitioner(),
00164 my_context);
00165
00166 if (my_context.is_group_execution_cancelled())
00167 do_parallel_quick_sort:
00168 #endif
00169 parallel_for( quick_sort_range<RandomAccessIterator,Compare>(begin, end-begin, comp ),
00170 quick_sort_body<RandomAccessIterator,Compare>(),
00171 auto_partitioner() );
00172 }
00173
00174 }
00176
00187
00189
00192 template<typename RandomAccessIterator, typename Compare>
00193 void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp) {
00194 const int min_parallel_size = 500;
00195 if( end > begin ) {
00196 if (end - begin < min_parallel_size) {
00197 std::sort(begin, end, comp);
00198 } else {
00199 internal::parallel_quick_sort(begin, end, comp);
00200 }
00201 }
00202 }
00203
00205
00206 template<typename RandomAccessIterator>
00207 inline void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end ) {
00208 parallel_sort( begin, end, std::less< typename std::iterator_traits<RandomAccessIterator>::value_type >() );
00209 }
00210
00212
00213 template<typename T>
00214 inline void parallel_sort( T * begin, T * end ) {
00215 parallel_sort( begin, end, std::less< T >() );
00216 }
00218
00219
00220 }
00221
00222 #endif
00223