Shadowrun: Awakened 29 September 2011 - Build 871
parallel_sort.h
Go to the documentation of this file.
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 &comp;
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 &comp;
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.

GNU Lesser General Public License 3 Sourceforge.net