246inline std::pair<Merger*,Merger*>
build_cache_(Diff run_size, MAlloc& malloc, TAlloc& talloc)
248 Merger *begin_cache, *end_cache;
250 for( Diff d=run_size; d>
static_cast<Diff
>(Splitter::switch_to_cache_aware()); d=run_size_<Splitter>(d), ++rec_calls );
251 begin_cache = end_cache = malloc.allocate(rec_calls);
252 for( Diff d=run_size; d>
static_cast<Diff
>(Splitter::switch_to_cache_aware()); d=run_size_<Splitter>(d), ++end_cache )
253 new(end_cache) Merger(Splitter::prefered_order_output(d), talloc);
254 return make_pair(begin_cache,end_cache);
261inline void sort_streams_(MPtr cache, It begin,
size_t order,
size_t run_size,
size_t big_runs, Alloc alloc)
263 typedef typename std::iterator_traits<It>::value_type T;
264 typename Alloc::template rebind<T>::other talloc(alloc);
265 typedef typename Alloc::template rebind<T>::other::pointer TPtr;
266 TPtr tmp = talloc.allocate((
size_t)(run_size));
271 merge_sort_<Merger,Splitter>(last, last+run_size, std::raw_storage_iterator<TPtr,T>(tmp), cache, alloc);
272 for( i=1, last+=run_size; i!=big_runs; i++, last+=run_size )
273 merge_sort_<Merger,Splitter>(last, last+run_size, last-run_size, cache, alloc);
275 for( ; i!=order; i++, last+=run_size )
276 merge_sort_<Merger,Splitter>(last, last+run_size, last-run_size-1, cache, alloc);
281 merge_sort_<Merger,Splitter>(last, last+run_size, tmp, cache, alloc);
282 for( --order, last+=run_size; order; --order, last+=run_size )
283 merge_sort_<Merger,Splitter>(last, last+run_size, last-run_size, cache, alloc);
285 std::copy(tmp, tmp+run_size, last-run_size);
286 for( TPtr p=tmp+run_size-1; p>=tmp; --p )
288 talloc.deallocate(tmp,
static_cast<size_t>(run_size));
296 merger->add_stream(end-run_size, end);
298 --run_size, --big_runs;
299 for( --order; order!=big_runs; --order, end-=run_size )
300 merger->add_stream(end-run_size, end);
302 for( ; order; --order, end-=run_size )
303 merger->add_stream(end-run_size, end);
306 for( ; order; --order, end-=run_size )
307 merger->add_stream(end-run_size, end);
311inline void add_streams_(MPtr merger, It begin,
size_t order,
size_t run_size,
size_t big_runs, Pred comp)
314 for( i=0; i!=order-big_runs; ++i, begin+=run_size )
317 for( ; i!=order; ++i, begin+=run_size )
320 for( ; i!=order-big_runs; --i, begin-=run_size )
321 merger->add_stream(begin-run_size, begin);
323 for( ; i; --i, begin-=run_size )
324 merger->add_stream(begin-run_size, begin);
328void merge_sort_(It begin, It end, OutIt dest, Merger* cache, Alloc alloc)
330 typedef typename std::iterator_traits<It>::value_type T;
331 typedef typename std::iterator_traits<It>::difference_type ItDiff;
332 typedef typename Merger::stream Stream;
334 order_t order = Splitter::prefered_order_output(end-begin);
336 throw std::logic_error(
"Splitter::prefered_order_output returned less than two");
337 ItDiff run_size = (end-begin)/order;
338 size_t rem = (size_t)((end-begin) % order);
339 run_size += rem/order;
340 size_t big_runs = rem % order;
343 if( run_size >
static_cast<ItDiff
>(Splitter::switch_to_cache_aware()) )
347 sort_streams_<Merger,Splitter>(cache+1,begin,order,run_size,big_runs,alloc);
351 add_streams_(cache,begin,order,run_size,big_runs,
typename Merger::predicate());
356inline void merge_sort(It begin, It end, OutIt dest,
const typename Merger::allocator& alloc)
358 typedef typename std::iterator_traits<It>::difference_type ItDiff;
359 if( end-begin >
static_cast<ItDiff
>(Splitter::switch_to_cache_aware()) )
361 order_t order = Splitter::prefered_order_output(end-begin);
363 throw std::logic_error(
"Splitter::prefered_order_output returned less than two");
364 ItDiff run_size = (end-begin)/order;
365 size_t rem = (size_t)((end-begin) % order);
366 run_size += rem/order;
367 size_t big_runs = rem % order;
368 if( run_size >
static_cast<ItDiff
>(Splitter::switch_to_cache_aware()) )
372 typename Merger::allocator::template rebind<Merger>::other malloc(alloc);
373 std::pair<Merger*,Merger*> cache = build_cache_<Merger,Splitter>(run_size, malloc, alloc);
374 sort_streams_<Merger,Splitter>(cache.first, begin, order, run_size, big_runs, alloc);
375 for( Merger *pm=cache.second-1; pm>=cache.first; --pm )
377 malloc.deallocate(cache.first, cache.second-cache.first);
379 Merger merger(order,alloc);
380 if( run_size >
static_cast<ItDiff
>(Splitter::switch_to_cache_aware()) )
383 add_streams_(&merger, begin, order, run_size, big_runs,
typename Merger::predicate());
385 OutIt e = merger(dest, dest+(end-begin));
386 merger.empty(dest, dest+(end-begin));
388 for(
typename Merger::stream_iterator i=merger.begin(); i!=merger.end(); ++i )
389 N += (*i).end()-(*i).begin();
390 assert( e == dest+(end-begin) );
398 std::copy(begin, end, dest);