![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 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 // Partition interval [i+1,j-1] with key *key0. 00086 for(;;) { 00087 __TBB_ASSERT( i<j, NULL ); 00088 // Loop must terminate since array[l]==*key0. 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 // Put the partition key were it belongs 00103 std::swap( array[j], *key0 ); 00104 // array[l..j) is less or equal to key. 00105 // array(j..r) is greater or equal to key. 00106 // array[j] is equal to key 00107 i=j+1; 00108 begin = array+i; 00109 size = range.size-i; 00110 range.size = j; 00111 } 00112 }; 00113 00115 00116 template<typename RandomAccessIterator, typename Compare> 00117 class quick_sort_pretest_body : internal::no_assign { 00118 const Compare ∁ 00119 00120 public: 00121 quick_sort_pretest_body(const Compare &_comp) : comp(_comp) {} 00122 00123 void operator()( const blocked_range<RandomAccessIterator>& range ) const { 00124 task &my_task = task::self(); 00125 RandomAccessIterator my_end = range.end(); 00126 00127 int i = 0; 00128 for (RandomAccessIterator k = range.begin(); k != my_end; ++k, ++i) { 00129 if ( i%64 == 0 && my_task.is_cancelled() ) break; 00130 00131 // The k-1 is never out-of-range because the first chunk starts at begin+serial_cutoff+1 00132 if ( comp( *(k), *(k-1) ) ) { 00133 my_task.cancel_group_execution(); 00134 break; 00135 } 00136 } 00137 } 00138 00139 }; 00140 00142 00143 template<typename RandomAccessIterator, typename Compare> 00144 struct quick_sort_body { 00145 void operator()( const quick_sort_range<RandomAccessIterator,Compare>& range ) const { 00146 //SerialQuickSort( range.begin, range.size, range.comp ); 00147 std::sort( range.begin, range.begin + range.size, range.comp ); 00148 } 00149 }; 00150 00152 00153 template<typename RandomAccessIterator, typename Compare> 00154 void parallel_quick_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp ) { 00155 task_group_context my_context; 00156 const int serial_cutoff = 9; 00157 00158 __TBB_ASSERT( begin + serial_cutoff < end, "min_parallel_size is smaller than serial cutoff?" ); 00159 RandomAccessIterator k; 00160 for ( k = begin ; k != begin + serial_cutoff; ++k ) { 00161 if ( comp( *(k+1), *k ) ) { 00162 goto do_parallel_quick_sort; 00163 } 00164 } 00165 00166 parallel_for( blocked_range<RandomAccessIterator>(k+1, end), 00167 quick_sort_pretest_body<RandomAccessIterator,Compare>(comp), 00168 auto_partitioner(), 00169 my_context); 00170 00171 if (my_context.is_group_execution_cancelled()) 00172 do_parallel_quick_sort: 00173 parallel_for( quick_sort_range<RandomAccessIterator,Compare>(begin, end-begin, comp ), 00174 quick_sort_body<RandomAccessIterator,Compare>(), 00175 auto_partitioner() ); 00176 } 00177 00178 } // namespace internal 00180 00191 00193 00196 template<typename RandomAccessIterator, typename Compare> 00197 void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp) { 00198 const int min_parallel_size = 500; 00199 if( end > begin ) { 00200 if (end - begin < min_parallel_size) { 00201 std::sort(begin, end, comp); 00202 } else { 00203 internal::parallel_quick_sort(begin, end, comp); 00204 } 00205 } 00206 } 00207 00209 00210 template<typename RandomAccessIterator> 00211 inline void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end ) { 00212 parallel_sort( begin, end, std::less< typename std::iterator_traits<RandomAccessIterator>::value_type >() ); 00213 } 00214 00216 00217 template<typename T> 00218 inline void parallel_sort( T * begin, T * end ) { 00219 parallel_sort( begin, end, std::less< T >() ); 00220 } 00222 00223 00224 } // namespace tbb 00225 00226 #endif 00227
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.