- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

# parallel_sort.h

    00001 /*
    00002     Copyright 2005-2012 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
    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 &comp;
    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             // The k-1 is never out-of-range because the first chunk starts at begin+serial_cutoff+1
    00133             if ( comp( *(k), *(k-1) ) ) {
    00134                 my_task.cancel_group_execution();
    00135                 break;
    00136             }
    00137         }
    00138     }
    00139
    00140 };
    00141 #endif /* __TBB_TASK_GROUP_CONTEXT */
    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         //SerialQuickSort( range.begin, range.size, range.comp );
    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 /* __TBB_TASK_GROUP_CONTEXT */
    00177         parallel_for( quick_sort_range<RandomAccessIterator,Compare>(begin, end-begin, comp ),
    00178                       quick_sort_body<RandomAccessIterator,Compare>(),
    00179                       auto_partitioner() );
    00180 }
    00181
    00182 } // namespace internal
    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 } // namespace tbb
    00229
    00230 #endif
    00231

Copyright © 2005-2012 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.