/
usr
/
include
/
c++
/
4.4.4
/
parallel
/
/usr/include/c++/4.4.4/parallel
mkdir
upload
Name
Size
Mode
Actions
algo.h
104807
0644
edit
dl
rm
algobase.h
11140
0644
edit
dl
rm
algorithm
1385
0644
edit
dl
rm
algorithmfwd.h
30167
0644
edit
dl
rm
balanced_quicksort.h
16157
0644
edit
dl
rm
base.h
12313
0644
edit
dl
rm
basic_iterator.h
1606
0644
edit
dl
rm
checkers.h
4605
0644
edit
dl
rm
compatibility.h
10301
0644
edit
dl
rm
compiletime_settings.h
2818
0644
edit
dl
rm
equally_split.h
3191
0644
edit
dl
rm
features.h
3580
0644
edit
dl
rm
find.h
14295
0644
edit
dl
rm
find_selectors.h
7092
0644
edit
dl
rm
for_each.h
3666
0644
edit
dl
rm
for_each_selectors.h
9804
0644
edit
dl
rm
iterator.h
5270
0644
edit
dl
rm
list_partition.h
5929
0644
edit
dl
rm
losertree.h
25725
0644
edit
dl
rm
merge.h
9549
0644
edit
dl
rm
multiseq_selection.h
16706
0644
edit
dl
rm
multiway_merge.h
72745
0644
edit
dl
rm
multiway_mergesort.h
15478
0644
edit
dl
rm
numeric
19494
0644
edit
dl
rm
numericfwd.h
6934
0644
edit
dl
rm
omp_loop.h
3996
0644
edit
dl
rm
omp_loop_static.h
4037
0644
edit
dl
rm
parallel.h
1577
0644
edit
dl
rm
partial_sum.h
7042
0644
edit
dl
rm
partition.h
14909
0644
edit
dl
rm
par_loop.h
4541
0644
edit
dl
rm
queue.h
4904
0644
edit
dl
rm
quicksort.h
5914
0644
edit
dl
rm
random_number.h
3808
0644
edit
dl
rm
random_shuffle.h
17696
0644
edit
dl
rm
search.h
5598
0644
edit
dl
rm
settings.h
10987
0644
edit
dl
rm
set_operations.h
14472
0644
edit
dl
rm
sort.h
7421
0644
edit
dl
rm
tags.h
6103
0644
edit
dl
rm
types.h
4116
0644
edit
dl
rm
unique_copy.h
5811
0644
edit
dl
rm
workstealing.h
10088
0644
edit
dl
rm
Edit:
/usr/include/c++/4.4.4/parallel/multiway_merge.h
(72745B)
// -*- C++ -*- // Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the terms // of the GNU General Public License as published by the Free Software // Foundation; either version 3, or (at your option) any later // version. // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. /** @file parallel/multiway_merge.h * @brief Implementation of sequential and parallel multiway merge. * * Explanations on the high-speed merging routines in the appendix of * * P. Sanders. * Fast priority queues for cached memory. * ACM Journal of Experimental Algorithmics, 5, 2000. * * This file is a GNU parallel extension to the Standard C++ Library. */ // Written by Johannes Singler and Manuel Holtgrewe. #ifndef _GLIBCXX_PARALLEL_MULTIWAY_MERGE_H #define _GLIBCXX_PARALLEL_MULTIWAY_MERGE_H #include <vector> #include <bits/stl_algo.h> #include <parallel/features.h> #include <parallel/parallel.h> #include <parallel/losertree.h> #if _GLIBCXX_ASSERTIONS #include <parallel/checkers.h> #endif /** @brief Length of a sequence described by a pair of iterators. */ #define _GLIBCXX_PARALLEL_LENGTH(s) ((s).second - (s).first) namespace __gnu_parallel { // Announce guarded and unguarded iterator. template<typename RandomAccessIterator, typename Comparator> class guarded_iterator; // Making the arguments const references seems to dangerous, // the user-defined comparator might not be const. template<typename RandomAccessIterator, typename Comparator> inline bool operator<(guarded_iterator<RandomAccessIterator, Comparator>& bi1, guarded_iterator<RandomAccessIterator, Comparator>& bi2); template<typename RandomAccessIterator, typename Comparator> inline bool operator<=(guarded_iterator<RandomAccessIterator, Comparator>& bi1, guarded_iterator<RandomAccessIterator, Comparator>& bi2); /** @brief Iterator wrapper supporting an implicit supremum at the end * of the sequence, dominating all comparisons. * * The implicit supremum comes with a performance cost. * * Deriving from RandomAccessIterator is not possible since * RandomAccessIterator need not be a class. */ template<typename RandomAccessIterator, typename Comparator> class guarded_iterator { private: /** @brief Current iterator position. */ RandomAccessIterator current; /** @brief End iterator of the sequence. */ RandomAccessIterator end; /** @brief Comparator. */ Comparator& comp; public: /** @brief Constructor. Sets iterator to beginning of sequence. * @param begin Begin iterator of sequence. * @param end End iterator of sequence. * @param comp Comparator provided for associated overloaded * compare operators. */ guarded_iterator(RandomAccessIterator begin, RandomAccessIterator end, Comparator& comp) : current(begin), end(end), comp(comp) { } /** @brief Pre-increment operator. * @return This. */ guarded_iterator<RandomAccessIterator, Comparator>& operator++() { ++current; return *this; } /** @brief Dereference operator. * @return Referenced element. */ typename std::iterator_traits<RandomAccessIterator>::value_type& operator*() { return *current; } /** @brief Convert to wrapped iterator. * @return Wrapped iterator. */ operator RandomAccessIterator() { return current; } friend bool operator< <RandomAccessIterator, Comparator>( guarded_iterator<RandomAccessIterator, Comparator>& bi1, guarded_iterator<RandomAccessIterator, Comparator>& bi2); friend bool operator<= <RandomAccessIterator, Comparator>( guarded_iterator<RandomAccessIterator, Comparator>& bi1, guarded_iterator<RandomAccessIterator, Comparator>& bi2); }; /** @brief Compare two elements referenced by guarded iterators. * @param bi1 First iterator. * @param bi2 Second iterator. * @return @c True if less. */ template<typename RandomAccessIterator, typename Comparator> inline bool operator<(guarded_iterator<RandomAccessIterator, Comparator>& bi1, guarded_iterator<RandomAccessIterator, Comparator>& bi2) { if (bi1.current == bi1.end) //bi1 is sup return bi2.current == bi2.end; //bi2 is not sup if (bi2.current == bi2.end) //bi2 is sup return true; return (bi1.comp)(*bi1, *bi2); //normal compare } /** @brief Compare two elements referenced by guarded iterators. * @param bi1 First iterator. * @param bi2 Second iterator. * @return @c True if less equal. */ template<typename RandomAccessIterator, typename Comparator> inline bool operator<=(guarded_iterator<RandomAccessIterator, Comparator>& bi1, guarded_iterator<RandomAccessIterator, Comparator>& bi2) { if (bi2.current == bi2.end) //bi1 is sup return bi1.current != bi1.end; //bi2 is not sup if (bi1.current == bi1.end) //bi2 is sup return false; return !(bi1.comp)(*bi2, *bi1); //normal compare } template<typename RandomAccessIterator, typename Comparator> class unguarded_iterator; template<typename RandomAccessIterator, typename Comparator> inline bool operator<(unguarded_iterator<RandomAccessIterator, Comparator>& bi1, unguarded_iterator<RandomAccessIterator, Comparator>& bi2); template<typename RandomAccessIterator, typename Comparator> inline bool operator<=(unguarded_iterator<RandomAccessIterator, Comparator>& bi1, unguarded_iterator<RandomAccessIterator, Comparator>& bi2); template<typename RandomAccessIterator, typename Comparator> class unguarded_iterator { private: /** @brief Current iterator position. */ RandomAccessIterator current; /** @brief Comparator. */ mutable Comparator& comp; public: /** @brief Constructor. Sets iterator to beginning of sequence. * @param begin Begin iterator of sequence. * @param end Unused, only for compatibility. * @param comp Unused, only for compatibility. */ unguarded_iterator(RandomAccessIterator begin, RandomAccessIterator end, Comparator& comp) : current(begin), comp(comp) { } /** @brief Pre-increment operator. * @return This. */ unguarded_iterator<RandomAccessIterator, Comparator>& operator++() { ++current; return *this; } /** @brief Dereference operator. * @return Referenced element. */ typename std::iterator_traits<RandomAccessIterator>::value_type& operator*() { return *current; } /** @brief Convert to wrapped iterator. * @return Wrapped iterator. */ operator RandomAccessIterator() { return current; } friend bool operator< <RandomAccessIterator, Comparator>( unguarded_iterator<RandomAccessIterator, Comparator>& bi1, unguarded_iterator<RandomAccessIterator, Comparator>& bi2); friend bool operator<= <RandomAccessIterator, Comparator>( unguarded_iterator<RandomAccessIterator, Comparator>& bi1, unguarded_iterator<RandomAccessIterator, Comparator>& bi2); }; /** @brief Compare two elements referenced by unguarded iterators. * @param bi1 First iterator. * @param bi2 Second iterator. * @return @c True if less. */ template<typename RandomAccessIterator, typename Comparator> inline bool operator<(unguarded_iterator<RandomAccessIterator, Comparator>& bi1, unguarded_iterator<RandomAccessIterator, Comparator>& bi2) { // Normal compare. return (bi1.comp)(*bi1, *bi2); } /** @brief Compare two elements referenced by unguarded iterators. * @param bi1 First iterator. * @param bi2 Second iterator. * @return @c True if less equal. */ template<typename RandomAccessIterator, typename Comparator> inline bool operator<=(unguarded_iterator<RandomAccessIterator, Comparator>& bi1, unguarded_iterator<RandomAccessIterator, Comparator>& bi2) { // Normal compare. return !(bi1.comp)(*bi2, *bi1); } /** @brief Highly efficient 3-way merging procedure. * * Merging is done with the algorithm implementation described by Peter * Sanders. Basically, the idea is to minimize the number of necessary * comparison after merging out an element. The implementation trick * that makes this fast is that the order of the sequences is stored * in the instruction pointer (translated into labels in C++). * * This works well for merging up to 4 sequences. * * Note that making the merging stable does <em>not</em> come at a * performance hit. * * Whether the merging is done guarded or unguarded is selected by the * used iterator class. * * @param seqs_begin Begin iterator of iterator pair input sequence. * @param seqs_end End iterator of iterator pair input sequence. * @param target Begin iterator out output sequence. * @param comp Comparator. * @param length Maximum length to merge, less equal than the * total number of elements available. * * @return End iterator of output sequence. */ template<template<typename RAI, typename C> class iterator, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> RandomAccessIterator3 multiway_merge_3_variant( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, _DifferenceTp length, Comparator comp) { _GLIBCXX_CALL(length); typedef _DifferenceTp difference_type; typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; if (length == 0) return target; #if _GLIBCXX_ASSERTIONS _DifferenceTp orig_length = length; #endif iterator<RandomAccessIterator1, Comparator> seq0(seqs_begin[0].first, seqs_begin[0].second, comp), seq1(seqs_begin[1].first, seqs_begin[1].second, comp), seq2(seqs_begin[2].first, seqs_begin[2].second, comp); if (seq0 <= seq1) { if (seq1 <= seq2) goto s012; else if (seq2 < seq0) goto s201; else goto s021; } else { if (seq1 <= seq2) { if (seq0 <= seq2) goto s102; else goto s120; } else goto s210; } #define _GLIBCXX_PARALLEL_MERGE_3_CASE(a,b,c,c0,c1) \ s ## a ## b ## c : \ *target = *seq ## a; \ ++target; \ --length; \ ++seq ## a; \ if (length == 0) goto finish; \ if (seq ## a c0 seq ## b) goto s ## a ## b ## c; \ if (seq ## a c1 seq ## c) goto s ## b ## a ## c; \ goto s ## b ## c ## a; _GLIBCXX_PARALLEL_MERGE_3_CASE(0, 1, 2, <=, <=); _GLIBCXX_PARALLEL_MERGE_3_CASE(1, 2, 0, <=, < ); _GLIBCXX_PARALLEL_MERGE_3_CASE(2, 0, 1, < , < ); _GLIBCXX_PARALLEL_MERGE_3_CASE(1, 0, 2, < , <=); _GLIBCXX_PARALLEL_MERGE_3_CASE(0, 2, 1, <=, <=); _GLIBCXX_PARALLEL_MERGE_3_CASE(2, 1, 0, < , < ); #undef _GLIBCXX_PARALLEL_MERGE_3_CASE finish: ; #if _GLIBCXX_ASSERTIONS _GLIBCXX_PARALLEL_ASSERT( ((RandomAccessIterator1)seq0 - seqs_begin[0].first) + ((RandomAccessIterator1)seq1 - seqs_begin[1].first) + ((RandomAccessIterator1)seq2 - seqs_begin[2].first) == orig_length); #endif seqs_begin[0].first = seq0; seqs_begin[1].first = seq1; seqs_begin[2].first = seq2; return target; } /** * @brief Highly efficient 4-way merging procedure. * * Merging is done with the algorithm implementation described by Peter * Sanders. Basically, the idea is to minimize the number of necessary * comparison after merging out an element. The implementation trick * that makes this fast is that the order of the sequences is stored * in the instruction pointer (translated into goto labels in C++). * * This works well for merging up to 4 sequences. * * Note that making the merging stable does <em>not</em> come at a * performance hit. * * Whether the merging is done guarded or unguarded is selected by the * used iterator class. * * @param seqs_begin Begin iterator of iterator pair input sequence. * @param seqs_end End iterator of iterator pair input sequence. * @param target Begin iterator out output sequence. * @param comp Comparator. * @param length Maximum length to merge, less equal than the * total number of elements available. * * @return End iterator of output sequence. */ template<template<typename RAI, typename C> class iterator, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> RandomAccessIterator3 multiway_merge_4_variant(RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, _DifferenceTp length, Comparator comp) { _GLIBCXX_CALL(length); typedef _DifferenceTp difference_type; typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; iterator<RandomAccessIterator1, Comparator> seq0(seqs_begin[0].first, seqs_begin[0].second, comp), seq1(seqs_begin[1].first, seqs_begin[1].second, comp), seq2(seqs_begin[2].first, seqs_begin[2].second, comp), seq3(seqs_begin[3].first, seqs_begin[3].second, comp); #define _GLIBCXX_PARALLEL_DECISION(a,b,c,d) { \ if (seq ## d < seq ## a) goto s ## d ## a ## b ## c; \ if (seq ## d < seq ## b) goto s ## a ## d ## b ## c; \ if (seq ## d < seq ## c) goto s ## a ## b ## d ## c; \ goto s ## a ## b ## c ## d; } if (seq0 <= seq1) { if (seq1 <= seq2) _GLIBCXX_PARALLEL_DECISION(0,1,2,3) else if (seq2 < seq0) _GLIBCXX_PARALLEL_DECISION(2,0,1,3) else _GLIBCXX_PARALLEL_DECISION(0,2,1,3) } else { if (seq1 <= seq2) { if (seq0 <= seq2) _GLIBCXX_PARALLEL_DECISION(1,0,2,3) else _GLIBCXX_PARALLEL_DECISION(1,2,0,3) } else _GLIBCXX_PARALLEL_DECISION(2,1,0,3) } #define _GLIBCXX_PARALLEL_MERGE_4_CASE(a,b,c,d,c0,c1,c2) \ s ## a ## b ## c ## d: \ if (length == 0) goto finish; \ *target = *seq ## a; \ ++target; \ --length; \ ++seq ## a; \ if (seq ## a c0 seq ## b) goto s ## a ## b ## c ## d; \ if (seq ## a c1 seq ## c) goto s ## b ## a ## c ## d; \ if (seq ## a c2 seq ## d) goto s ## b ## c ## a ## d; \ goto s ## b ## c ## d ## a; _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 1, 2, 3, <=, <=, <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 1, 3, 2, <=, <=, <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 2, 1, 3, <=, <=, <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 2, 3, 1, <=, <=, <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 3, 1, 2, <=, <=, <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 3, 2, 1, <=, <=, <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 0, 2, 3, < , <=, <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 0, 3, 2, < , <=, <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 2, 0, 3, <=, < , <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 2, 3, 0, <=, <=, < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 3, 0, 2, <=, < , <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 3, 2, 0, <=, <=, < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 0, 1, 3, < , < , <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 0, 3, 1, < , <=, < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 1, 0, 3, < , < , <=); _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 1, 3, 0, < , <=, < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 3, 0, 1, <=, < , < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 3, 1, 0, <=, < , < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 0, 1, 2, < , < , < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 0, 2, 1, < , < , < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 1, 0, 2, < , < , < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 1, 2, 0, < , < , < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 2, 0, 1, < , < , < ); _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 2, 1, 0, < , < , < ); #undef _GLIBCXX_PARALLEL_MERGE_4_CASE #undef _GLIBCXX_PARALLEL_DECISION finish: ; seqs_begin[0].first = seq0; seqs_begin[1].first = seq1; seqs_begin[2].first = seq2; seqs_begin[3].first = seq3; return target; } /** @brief Multi-way merging procedure for a high branching factor, * guarded case. * * This merging variant uses a LoserTree class as selected by <tt>LT</tt>. * * Stability is selected through the used LoserTree class <tt>LT</tt>. * * At least one non-empty sequence is required. * * @param seqs_begin Begin iterator of iterator pair input sequence. * @param seqs_end End iterator of iterator pair input sequence. * @param target Begin iterator out output sequence. * @param comp Comparator. * @param length Maximum length to merge, less equal than the * total number of elements available. * * @return End iterator of output sequence. */ template<typename LT, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> RandomAccessIterator3 multiway_merge_loser_tree(RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, _DifferenceTp length, Comparator comp) { _GLIBCXX_CALL(length) typedef _DifferenceTp difference_type; typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; int k = static_cast<int>(seqs_end - seqs_begin); LT lt(k, comp); // Default value for potentially non-default-constructible types. value_type* arbitrary_element = NULL; for (int t = 0; t < k; ++t) { if(arbitrary_element == NULL && _GLIBCXX_PARALLEL_LENGTH(seqs_begin[t]) > 0) arbitrary_element = &(*seqs_begin[t].first); } for (int t = 0; t < k; ++t) { if (seqs_begin[t].first == seqs_begin[t].second) lt.insert_start(*arbitrary_element, t, true); else lt.insert_start(*seqs_begin[t].first, t, false); } lt.init(); int source; for (difference_type i = 0; i < length; ++i) { //take out source = lt.get_min_source(); *(target++) = *(seqs_begin[source].first++); // Feed. if (seqs_begin[source].first == seqs_begin[source].second) lt.delete_min_insert(*arbitrary_element, true); else // Replace from same source. lt.delete_min_insert(*seqs_begin[source].first, false); } return target; } /** @brief Multi-way merging procedure for a high branching factor, * unguarded case. * * Merging is done using the LoserTree class <tt>LT</tt>. * * Stability is selected by the used LoserTrees. * * @pre No input will run out of elements during the merge. * * @param seqs_begin Begin iterator of iterator pair input sequence. * @param seqs_end End iterator of iterator pair input sequence. * @param target Begin iterator out output sequence. * @param comp Comparator. * @param length Maximum length to merge, less equal than the * total number of elements available. * * @return End iterator of output sequence. */ template<typename LT, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> RandomAccessIterator3 multiway_merge_loser_tree_unguarded( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, const typename std::iterator_traits<typename std::iterator_traits< RandomAccessIteratorIterator>::value_type::first_type>::value_type& sentinel, _DifferenceTp length, Comparator comp) { _GLIBCXX_CALL(length) typedef _DifferenceTp difference_type; typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; int k = seqs_end - seqs_begin; LT lt(k, sentinel, comp); for (int t = 0; t < k; ++t) { #if _GLIBCXX_ASSERTIONS _GLIBCXX_PARALLEL_ASSERT(seqs_begin[t].first != seqs_begin[t].second); #endif lt.insert_start(*seqs_begin[t].first, t, false); } lt.init(); int source; #if _GLIBCXX_ASSERTIONS difference_type i = 0; #endif RandomAccessIterator3 target_end = target + length; while (target < target_end) { // Take out. source = lt.get_min_source(); #if _GLIBCXX_ASSERTIONS _GLIBCXX_PARALLEL_ASSERT(0 <= source && source < k); _GLIBCXX_PARALLEL_ASSERT(i == 0 || !comp(*(seqs_begin[source].first), *(target - 1))); #endif // Feed. *(target++) = *(seqs_begin[source].first++); #if _GLIBCXX_ASSERTIONS ++i; #endif // Replace from same source. lt.delete_min_insert(*seqs_begin[source].first, false); } return target; } /** @brief Multi-way merging procedure for a high branching factor, * requiring sentinels to exist. * * @param stable The value must the same as for the used LoserTrees. * @param UnguardedLoserTree Loser Tree variant to use for the unguarded * merging. * @param GuardedLoserTree Loser Tree variant to use for the guarded * merging. * * @param seqs_begin Begin iterator of iterator pair input sequence. * @param seqs_end End iterator of iterator pair input sequence. * @param target Begin iterator out output sequence. * @param comp Comparator. * @param length Maximum length to merge, less equal than the * total number of elements available. * * @return End iterator of output sequence. */ template< typename UnguardedLoserTree, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> RandomAccessIterator3 multiway_merge_loser_tree_sentinel( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, const typename std::iterator_traits<typename std::iterator_traits< RandomAccessIteratorIterator>::value_type::first_type>::value_type& sentinel, _DifferenceTp length, Comparator comp) { _GLIBCXX_CALL(length) typedef _DifferenceTp difference_type; typedef std::iterator_traits<RandomAccessIteratorIterator> traits_type; typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; RandomAccessIterator3 target_end; for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s) // Move the sequends end behind the sentinel spots. This has the // effect that the sentinel appears to be within the sequence. Then, // we can use the unguarded variant if we merge out as many // non-sentinel elements as we have. ++((*s).second); target_end = multiway_merge_loser_tree_unguarded <UnguardedLoserTree> (seqs_begin, seqs_end, target, sentinel, length, comp); #if _GLIBCXX_ASSERTIONS _GLIBCXX_PARALLEL_ASSERT(target_end == target + length); _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp)); #endif // Restore the sequence ends so the sentinels are not contained in the // sequence any more (see comment in loop above). for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s) --((*s).second); return target_end; } /** * @brief Traits for determining whether the loser tree should * use pointers or copies. * * The field "use_pointer" is used to determine whether to use pointers in * the loser trees or whether to copy the values into the loser tree. * * The default behavior is to use pointers if the data type is 4 times as * big as the pointer to it. * * Specialize for your data type to customize the behavior. * * Example: * * template<> * struct loser_tree_traits<int> * { static const bool use_pointer = false; }; * * template<> * struct loser_tree_traits<heavyweight_type> * { static const bool use_pointer = true; }; * * @param T type to give the loser tree traits for. */ template <typename T> struct loser_tree_traits { /** * @brief True iff to use pointers instead of values in loser trees. * * The default behavior is to use pointers if the data type is four * times as big as the pointer to it. */ static const bool use_pointer = (sizeof(T) > 4 * sizeof(T*)); }; /** * @brief Switch for 3-way merging with sentinels turned off. * * Note that 3-way merging is always stable! */ template< bool sentinels /*default == false*/, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> struct multiway_merge_3_variant_sentinel_switch { RandomAccessIterator3 operator()( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, _DifferenceTp length, Comparator comp) { return multiway_merge_3_variant<guarded_iterator>( seqs_begin, seqs_end, target, length, comp); } }; /** * @brief Switch for 3-way merging with sentinels turned on. * * Note that 3-way merging is always stable! */ template< typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> struct multiway_merge_3_variant_sentinel_switch <true, RandomAccessIteratorIterator, RandomAccessIterator3, _DifferenceTp, Comparator> { RandomAccessIterator3 operator()( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, _DifferenceTp length, Comparator comp) { return multiway_merge_3_variant<unguarded_iterator>( seqs_begin, seqs_end, target, length, comp); } }; /** * @brief Switch for 4-way merging with sentinels turned off. * * Note that 4-way merging is always stable! */ template< bool sentinels /*default == false*/, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> struct multiway_merge_4_variant_sentinel_switch { RandomAccessIterator3 operator()( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, _DifferenceTp length, Comparator comp) { return multiway_merge_4_variant<guarded_iterator>( seqs_begin, seqs_end, target, length, comp); } }; /** * @brief Switch for 4-way merging with sentinels turned on. * * Note that 4-way merging is always stable! */ template< typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> struct multiway_merge_4_variant_sentinel_switch <true, RandomAccessIteratorIterator, RandomAccessIterator3, _DifferenceTp, Comparator> { RandomAccessIterator3 operator()( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, _DifferenceTp length, Comparator comp) { return multiway_merge_4_variant<unguarded_iterator>( seqs_begin, seqs_end, target, length, comp); } }; /** * @brief Switch for k-way merging with sentinels turned on. */ template< bool sentinels, bool stable, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> struct multiway_merge_k_variant_sentinel_switch { RandomAccessIterator3 operator()( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, const typename std::iterator_traits<typename std::iterator_traits< RandomAccessIteratorIterator>::value_type::first_type>::value_type& sentinel, _DifferenceTp length, Comparator comp) { typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; return multiway_merge_loser_tree_sentinel< typename __gnu_cxx::__conditional_type< loser_tree_traits<value_type>::use_pointer , LoserTreePointerUnguarded<stable, value_type, Comparator> , LoserTreeUnguarded<stable, value_type, Comparator> >::__type>(seqs_begin, seqs_end, target, sentinel, length, comp); } }; /** * @brief Switch for k-way merging with sentinels turned off. */ template< bool stable, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> struct multiway_merge_k_variant_sentinel_switch <false, stable, RandomAccessIteratorIterator, RandomAccessIterator3, _DifferenceTp, Comparator> { RandomAccessIterator3 operator()( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, const typename std::iterator_traits<typename std::iterator_traits< RandomAccessIteratorIterator>::value_type::first_type>::value_type& sentinel, _DifferenceTp length, Comparator comp) { typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; return multiway_merge_loser_tree< typename __gnu_cxx::__conditional_type< loser_tree_traits<value_type>::use_pointer , LoserTreePointer<stable, value_type, Comparator> , LoserTree<stable, value_type, Comparator> >::__type >(seqs_begin, seqs_end, target, length, comp); } }; /** @brief Sequential multi-way merging switch. * * The _GLIBCXX_PARALLEL_DECISION is based on the branching factor and * runtime settings. * @param seqs_begin Begin iterator of iterator pair input sequence. * @param seqs_end End iterator of iterator pair input sequence. * @param target Begin iterator out output sequence. * @param comp Comparator. * @param length Maximum length to merge, possibly larger than the * number of elements available. * @param stable Stable merging incurs a performance penalty. * @param sentinel The sequences have a sentinel element. * @return End iterator of output sequence. */ template< bool stable, bool sentinels, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Comparator> RandomAccessIterator3 sequential_multiway_merge( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, const typename std::iterator_traits<typename std::iterator_traits< RandomAccessIteratorIterator>::value_type::first_type>::value_type& sentinel, _DifferenceTp length, Comparator comp) { _GLIBCXX_CALL(length) typedef _DifferenceTp difference_type; typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; #if _GLIBCXX_ASSERTIONS for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s) { _GLIBCXX_PARALLEL_ASSERT(is_sorted((*s).first, (*s).second, comp)); } #endif _DifferenceTp total_length = 0; for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s) total_length += _GLIBCXX_PARALLEL_LENGTH(*s); length = std::min<_DifferenceTp>(length, total_length); if(length == 0) return target; RandomAccessIterator3 return_target = target; int k = static_cast<int>(seqs_end - seqs_begin); switch (k) { case 0: break; case 1: return_target = std::copy(seqs_begin[0].first, seqs_begin[0].first + length, target); seqs_begin[0].first += length; break; case 2: return_target = merge_advance(seqs_begin[0].first, seqs_begin[0].second, seqs_begin[1].first, seqs_begin[1].second, target, length, comp); break; case 3: return_target = multiway_merge_3_variant_sentinel_switch< sentinels , RandomAccessIteratorIterator , RandomAccessIterator3 , _DifferenceTp , Comparator>()(seqs_begin, seqs_end, target, length, comp); break; case 4: return_target = multiway_merge_4_variant_sentinel_switch< sentinels , RandomAccessIteratorIterator , RandomAccessIterator3 , _DifferenceTp , Comparator>()(seqs_begin, seqs_end, target, length, comp); break; default: return_target = multiway_merge_k_variant_sentinel_switch< sentinels , stable , RandomAccessIteratorIterator , RandomAccessIterator3 , _DifferenceTp , Comparator>()(seqs_begin, seqs_end, target, sentinel, length, comp); break; } #if _GLIBCXX_ASSERTIONS _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target + length, comp)); #endif return return_target; } /** * @brief Stable sorting functor. * * Used to reduce code instanciation in multiway_merge_sampling_splitting. */ template<bool stable, class RandomAccessIterator, class StrictWeakOrdering> struct sampling_sorter { void operator()(RandomAccessIterator first, RandomAccessIterator last, StrictWeakOrdering comp) { __gnu_sequential::stable_sort(first, last, comp); } }; /** * @brief Non-stable sorting functor. * * Used to reduce code instantiation in multiway_merge_sampling_splitting. */ template<class RandomAccessIterator, class StrictWeakOrdering> struct sampling_sorter<false, RandomAccessIterator, StrictWeakOrdering> { void operator()(RandomAccessIterator first, RandomAccessIterator last, StrictWeakOrdering comp) { __gnu_sequential::sort(first, last, comp); } }; /** * @brief Sampling based splitting for parallel multiway-merge routine. */ template< bool stable , typename RandomAccessIteratorIterator , typename Comparator , typename difference_type> void multiway_merge_sampling_splitting( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, difference_type length, difference_type total_length, Comparator comp, std::vector<std::pair<difference_type, difference_type> > *pieces) { typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; // k sequences. int k = static_cast<int>(seqs_end - seqs_begin); int num_threads = omp_get_num_threads(); difference_type num_samples = __gnu_parallel::_Settings::get().merge_oversampling * num_threads; value_type* samples = static_cast<value_type*>( ::operator new(sizeof(value_type) * k * num_samples)); // Sample. for (int s = 0; s < k; ++s) for (difference_type i = 0; i < num_samples; ++i) { difference_type sample_index = static_cast<difference_type>( _GLIBCXX_PARALLEL_LENGTH(seqs_begin[s]) * (double(i + 1) / (num_samples + 1)) * (double(length) / total_length)); new(&(samples[s * num_samples + i])) value_type(seqs_begin[s].first[sample_index]); } // Sort stable or non-stable, depending on value of template parameter // "stable". sampling_sorter<stable, value_type*, Comparator>()( samples, samples + (num_samples * k), comp); for (int slab = 0; slab < num_threads; ++slab) // For each slab / processor. for (int seq = 0; seq < k; ++seq) { // For each sequence. if (slab > 0) pieces[slab][seq].first = std::upper_bound( seqs_begin[seq].first, seqs_begin[seq].second, samples[num_samples * k * slab / num_threads], comp) - seqs_begin[seq].first; else // Absolute beginning. pieces[slab][seq].first = 0; if ((slab + 1) < num_threads) pieces[slab][seq].second = std::upper_bound( seqs_begin[seq].first, seqs_begin[seq].second, samples[num_samples * k * (slab + 1) / num_threads], comp) - seqs_begin[seq].first; else // Absolute end. pieces[slab][seq].second = _GLIBCXX_PARALLEL_LENGTH(seqs_begin[seq]); } ::operator delete(samples); } /** * @brief Exact splitting for parallel multiway-merge routine. * * None of the passed sequences may be empty. */ template< bool stable , typename RandomAccessIteratorIterator , typename Comparator , typename difference_type> void multiway_merge_exact_splitting( RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, difference_type length, difference_type total_length, Comparator comp, std::vector<std::pair<difference_type, difference_type> > *pieces) { typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; const bool tight = (total_length == length); // k sequences. const int k = static_cast<int>(seqs_end - seqs_begin); const int num_threads = omp_get_num_threads(); // (Settings::multiway_merge_splitting == __gnu_parallel::_Settings::EXACT). std::vector<RandomAccessIterator1>* offsets = new std::vector<RandomAccessIterator1>[num_threads]; std::vector< std::pair<RandomAccessIterator1, RandomAccessIterator1> > se(k); copy(seqs_begin, seqs_end, se.begin()); difference_type* borders = new difference_type[num_threads + 1]; equally_split(length, num_threads, borders); for (int s = 0; s < (num_threads - 1); ++s) { offsets[s].resize(k); multiseq_partition( se.begin(), se.end(), borders[s + 1], offsets[s].begin(), comp); // Last one also needed and available. if (!tight) { offsets[num_threads - 1].resize(k); multiseq_partition(se.begin(), se.end(), difference_type(length), offsets[num_threads - 1].begin(), comp); } } delete[] borders; for (int slab = 0; slab < num_threads; ++slab) { // For each slab / processor. for (int seq = 0; seq < k; ++seq) { // For each sequence. if (slab == 0) { // Absolute beginning. pieces[slab][seq].first = 0; } else pieces[slab][seq].first = pieces[slab - 1][seq].second; if (!tight || slab < (num_threads - 1)) pieces[slab][seq].second = offsets[slab][seq] - seqs_begin[seq].first; else { // slab == num_threads - 1 pieces[slab][seq].second = _GLIBCXX_PARALLEL_LENGTH(seqs_begin[seq]); } } } delete[] offsets; } /** @brief Parallel multi-way merge routine. * * The _GLIBCXX_PARALLEL_DECISION is based on the branching factor * and runtime settings. * * Must not be called if the number of sequences is 1. * * @param Splitter functor to split input (either exact or sampling based) * * @param seqs_begin Begin iterator of iterator pair input sequence. * @param seqs_end End iterator of iterator pair input sequence. * @param target Begin iterator out output sequence. * @param comp Comparator. * @param length Maximum length to merge, possibly larger than the * number of elements available. * @param stable Stable merging incurs a performance penalty. * @param sentinel Ignored. * @return End iterator of output sequence. */ template< bool stable, bool sentinels, typename RandomAccessIteratorIterator, typename RandomAccessIterator3, typename _DifferenceTp, typename Splitter, typename Comparator > RandomAccessIterator3 parallel_multiway_merge(RandomAccessIteratorIterator seqs_begin, RandomAccessIteratorIterator seqs_end, RandomAccessIterator3 target, Splitter splitter, _DifferenceTp length, Comparator comp, thread_index_t num_threads) { #if _GLIBCXX_ASSERTIONS _GLIBCXX_PARALLEL_ASSERT(seqs_end - seqs_begin > 1); #endif _GLIBCXX_CALL(length) typedef _DifferenceTp difference_type; typedef typename std::iterator_traits<RandomAccessIteratorIterator> ::value_type::first_type RandomAccessIterator1; typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type; // Leave only non-empty sequences. typedef std::pair<RandomAccessIterator1, RandomAccessIterator1> seq_type; seq_type* ne_seqs = new seq_type[seqs_end - seqs_begin]; int k = 0; difference_type total_length = 0; for (RandomAccessIteratorIterator raii = seqs_begin; raii != seqs_end; ++raii) { _DifferenceTp seq_length = _GLIBCXX_PARALLEL_LENGTH(*raii); if(seq_length > 0) { total_length += seq_length; ne_seqs[k++] = *raii; } } _GLIBCXX_CALL(total_length) length = std::min<_DifferenceTp>(length, total_length); if (total_length == 0 || k == 0) { delete[] ne_seqs; return target; } std::vector<std::pair<difference_type, difference_type> >* pieces; num_threads = static_cast<thread_index_t> (std::min<difference_type>(num_threads, total_length)); # pragma omp parallel num_threads (num_threads) { # pragma omp single { num_threads = omp_get_num_threads(); // Thread t will have to merge pieces[iam][0..k - 1] pieces = new std::vector< std::pair<difference_type, difference_type> >[num_threads]; for (int s = 0; s < num_threads; ++s) pieces[s].resize(k); difference_type num_samples = __gnu_parallel::_Settings::get().merge_oversampling * num_threads; splitter(ne_seqs, ne_seqs + k, length, total_length, comp, pieces); } //single thread_index_t iam = omp_get_thread_num(); difference_type target_position = 0; for (int c = 0; c < k; ++c) target_position += pieces[iam][c].first; seq_type* chunks = new seq_type[k]; for (int s = 0; s < k; ++s) { chunks[s] = std::make_pair( ne_seqs[s].first + pieces[iam][s].first, ne_seqs[s].first + pieces[iam][s].second); } if(length > target_position) sequential_multiway_merge<stable, sentinels>( chunks, chunks + k, target + target_position, *(seqs_begin->second), length - target_position, comp); delete[] chunks; } // parallel #if _GLIBCXX_ASSERTIONS _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target + length, comp)); #endif k = 0; // Update ends of sequences. for (RandomAccessIteratorIterator raii = seqs_begin; raii != seqs_end; ++raii) { _DifferenceTp length = _GLIBCXX_PARALLEL_LENGTH(*raii); if(length > 0) (*raii).first += pieces[num_threads - 1][k++].second; } delete[] pieces; delete[] ne_seqs; return target + length; } /** * @brief Multiway Merge Frontend. * * Merge the sequences specified by seqs_begin and seqs_end into * target. seqs_begin and seqs_end must point to a sequence of * pairs. These pairs must contain an iterator to the beginning * of a sequence in their first entry and an iterator the end of * the same sequence in their second entry. * * Ties are broken arbitrarily. See stable_multiway_merge for a variant * that breaks ties by sequence number but is slower. * * The first entries of the pairs (i.e. the begin iterators) will be moved * forward. * * The output sequence has to provide enough space for all elements * that are written to it. * * This function will merge the input sequences: * * - not stable * - parallel, depending on the input size and Settings * - using sampling for splitting * - not using sentinels * * Example: * * <pre> * int sequences[10][10]; * for (int i = 0; i < 10; ++i) * for (int j = 0; i < 10; ++j) * sequences[i][j] = j; * * int out[33]; * std::vector<std::pair<int*> > seqs; * for (int i = 0; i < 10; ++i) * { seqs.push(std::make_pair<int*>(sequences[i], sequences[i] + 10)) } * * multiway_merge(seqs.begin(), seqs.end(), target, std::less<int>(), 33); * </pre> * * @see stable_multiway_merge * * @pre All input sequences must be sorted. * @pre Target must provide enough space to merge out length elements or * the number of elements in all sequences, whichever is smaller. * * @post [target, return value) contains merged elements from the * input sequences. * @post return value - target = min(length, number of elements in all * sequences). * * @param RandomAccessIteratorPairIterator iterator over sequence * of pairs of iterators * @param RandomAccessIteratorOut iterator over target sequence * @param _DifferenceTp difference type for the sequence * @param Comparator strict weak ordering type to compare elements * in sequences * * @param seqs_begin begin of sequence sequence * @param seqs_end end of sequence sequence * @param target target sequence to merge to. * @param comp strict weak ordering to use for element comparison. * @param length Maximum length to merge, possibly larger than the * number of elements available. * * @return end iterator of output sequence */ // multiway_merge // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , __gnu_parallel::sequential_tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute multiway merge *sequentially*. return sequential_multiway_merge </* stable = */ false, /* sentinels = */ false> (seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , __gnu_parallel::exact_tag tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute merge; maybe parallel, depending on the number of merged // elements and the number of sequences and global thresholds in // Settings. if ((seqs_end - seqs_begin > 1) && _GLIBCXX_PARALLEL_CONDITION( ((seqs_end - seqs_begin) >= __gnu_parallel::_Settings::get().multiway_merge_minimal_k) && ((sequence_index_t)length >= __gnu_parallel::_Settings::get().multiway_merge_minimal_n))) return parallel_multiway_merge </* stable = */ false, /* sentinels = */ false>( seqs_begin, seqs_end, target, multiway_merge_exact_splitting</* stable = */ false, typename std::iterator_traits<RandomAccessIteratorPairIterator> ::value_type*, Comparator, _DifferenceTp>, static_cast<difference_type>(length), comp, tag.get_num_threads()); else return sequential_multiway_merge </* stable = */ false, /* sentinels = */ false>( seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , __gnu_parallel::sampling_tag tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute merge; maybe parallel, depending on the number of merged // elements and the number of sequences and global thresholds in // Settings. if ((seqs_end - seqs_begin > 1) && _GLIBCXX_PARALLEL_CONDITION( ((seqs_end - seqs_begin) >= __gnu_parallel::_Settings::get().multiway_merge_minimal_k) && ((sequence_index_t)length >= __gnu_parallel::_Settings::get().multiway_merge_minimal_n))) return parallel_multiway_merge </* stable = */ false, /* sentinels = */ false>( seqs_begin, seqs_end, target, multiway_merge_exact_splitting</* stable = */ false, typename std::iterator_traits<RandomAccessIteratorPairIterator> ::value_type*, Comparator, _DifferenceTp>, static_cast<difference_type>(length), comp, tag.get_num_threads()); else return sequential_multiway_merge </* stable = */ false, /* sentinels = */ false>( seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , parallel_tag tag = parallel_tag(0)) { return multiway_merge(seqs_begin, seqs_end, target, length, comp, exact_tag(tag.get_num_threads())); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , default_parallel_tag tag) { return multiway_merge(seqs_begin, seqs_end, target, length, comp, exact_tag(tag.get_num_threads())); } // stable_multiway_merge // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , __gnu_parallel::sequential_tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute multiway merge *sequentially*. return sequential_multiway_merge </* stable = */ true, /* sentinels = */ false> (seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , __gnu_parallel::exact_tag tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute merge; maybe parallel, depending on the number of merged // elements and the number of sequences and global thresholds in // Settings. if ((seqs_end - seqs_begin > 1) && _GLIBCXX_PARALLEL_CONDITION( ((seqs_end - seqs_begin) >= __gnu_parallel::_Settings::get().multiway_merge_minimal_k) && ((sequence_index_t)length >= __gnu_parallel::_Settings::get().multiway_merge_minimal_n))) return parallel_multiway_merge </* stable = */ true, /* sentinels = */ false>( seqs_begin, seqs_end, target, multiway_merge_exact_splitting</* stable = */ true, typename std::iterator_traits<RandomAccessIteratorPairIterator> ::value_type*, Comparator, _DifferenceTp>, static_cast<difference_type>(length), comp, tag.get_num_threads()); else return sequential_multiway_merge</* stable = */ true, /* sentinels = */ false>( seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , sampling_tag tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute merge; maybe parallel, depending on the number of merged // elements and the number of sequences and global thresholds in // Settings. if ((seqs_end - seqs_begin > 1) && _GLIBCXX_PARALLEL_CONDITION( ((seqs_end - seqs_begin) >= __gnu_parallel::_Settings::get().multiway_merge_minimal_k) && ((sequence_index_t)length >= __gnu_parallel::_Settings::get().multiway_merge_minimal_n))) return parallel_multiway_merge </* stable = */ true, /* sentinels = */ false>( seqs_begin, seqs_end, target, multiway_merge_sampling_splitting</* stable = */ true, typename std::iterator_traits<RandomAccessIteratorPairIterator> ::value_type*, Comparator, _DifferenceTp>, static_cast<difference_type>(length), comp, tag.get_num_threads()); else return sequential_multiway_merge </* stable = */ true, /* sentinels = */ false>( seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , parallel_tag tag = parallel_tag(0)) { return stable_multiway_merge(seqs_begin, seqs_end, target, length, comp, exact_tag(tag.get_num_threads())); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , default_parallel_tag tag) { return stable_multiway_merge(seqs_begin, seqs_end, target, length, comp, exact_tag(tag.get_num_threads())); } /** * @brief Multiway Merge Frontend. * * Merge the sequences specified by seqs_begin and seqs_end into * target. seqs_begin and seqs_end must point to a sequence of * pairs. These pairs must contain an iterator to the beginning * of a sequence in their first entry and an iterator the end of * the same sequence in their second entry. * * Ties are broken arbitrarily. See stable_multiway_merge for a variant * that breaks ties by sequence number but is slower. * * The first entries of the pairs (i.e. the begin iterators) will be moved * forward accordingly. * * The output sequence has to provide enough space for all elements * that are written to it. * * This function will merge the input sequences: * * - not stable * - parallel, depending on the input size and Settings * - using sampling for splitting * - using sentinels * * You have to take care that the element the end iterator points to is * readable and contains a value that is greater than any other non-sentinel * value in all sequences. * * Example: * * <pre> * int sequences[10][11]; * for (int i = 0; i < 10; ++i) * for (int j = 0; i < 11; ++j) * sequences[i][j] = j; // last one is sentinel! * * int out[33]; * std::vector<std::pair<int*> > seqs; * for (int i = 0; i < 10; ++i) * { seqs.push(std::make_pair<int*>(sequences[i], sequences[i] + 10)) } * * multiway_merge(seqs.begin(), seqs.end(), target, std::less<int>(), 33); * </pre> * * @pre All input sequences must be sorted. * @pre Target must provide enough space to merge out length elements or * the number of elements in all sequences, whichever is smaller. * @pre For each @c i, @c seqs_begin[i].second must be the end * marker of the sequence, but also reference the one more sentinel * element. * * @post [target, return value) contains merged elements from the * input sequences. * @post return value - target = min(length, number of elements in all * sequences). * * @see stable_multiway_merge_sentinels * * @param RandomAccessIteratorPairIterator iterator over sequence * of pairs of iterators * @param RandomAccessIteratorOut iterator over target sequence * @param _DifferenceTp difference type for the sequence * @param Comparator strict weak ordering type to compare elements * in sequences * * @param seqs_begin begin of sequence sequence * @param seqs_end end of sequence sequence * @param target target sequence to merge to. * @param comp strict weak ordering to use for element comparison. * @param length Maximum length to merge, possibly larger than the * number of elements available. * * @return end iterator of output sequence */ // multiway_merge_sentinels // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , __gnu_parallel::sequential_tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute multiway merge *sequentially*. return sequential_multiway_merge </* stable = */ false, /* sentinels = */ true> (seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , __gnu_parallel::exact_tag tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute merge; maybe parallel, depending on the number of merged // elements and the number of sequences and global thresholds in // Settings. if ((seqs_end - seqs_begin > 1) && _GLIBCXX_PARALLEL_CONDITION( ((seqs_end - seqs_begin) >= __gnu_parallel::_Settings::get().multiway_merge_minimal_k) && ((sequence_index_t)length >= __gnu_parallel::_Settings::get().multiway_merge_minimal_n))) return parallel_multiway_merge </* stable = */ false, /* sentinels = */ true>( seqs_begin, seqs_end, target, multiway_merge_exact_splitting</* stable = */ false, typename std::iterator_traits<RandomAccessIteratorPairIterator> ::value_type*, Comparator, _DifferenceTp>, static_cast<difference_type>(length), comp, tag.get_num_threads()); else return sequential_multiway_merge </* stable = */ false, /* sentinels = */ true>( seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , sampling_tag tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute merge; maybe parallel, depending on the number of merged // elements and the number of sequences and global thresholds in // Settings. if ((seqs_end - seqs_begin > 1) && _GLIBCXX_PARALLEL_CONDITION( ((seqs_end - seqs_begin) >= __gnu_parallel::_Settings::get().multiway_merge_minimal_k) && ((sequence_index_t)length >= __gnu_parallel::_Settings::get().multiway_merge_minimal_n))) return parallel_multiway_merge </* stable = */ false, /* sentinels = */ true> (seqs_begin, seqs_end, target, multiway_merge_sampling_splitting</* stable = */ false, typename std::iterator_traits<RandomAccessIteratorPairIterator> ::value_type*, Comparator, _DifferenceTp>, static_cast<difference_type>(length), comp, tag.get_num_threads()); else return sequential_multiway_merge </* stable = */false, /* sentinels = */ true>( seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , parallel_tag tag = parallel_tag(0)) { return multiway_merge_sentinels(seqs_begin, seqs_end, target, length, comp, exact_tag(tag.get_num_threads())); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , default_parallel_tag tag) { return multiway_merge_sentinels(seqs_begin, seqs_end, target, length, comp, exact_tag(tag.get_num_threads())); } // stable_multiway_merge_sentinels // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , __gnu_parallel::sequential_tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute multiway merge *sequentially*. return sequential_multiway_merge </* stable = */ true, /* sentinels = */ true> (seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , __gnu_parallel::exact_tag tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute merge; maybe parallel, depending on the number of merged // elements and the number of sequences and global thresholds in // Settings. if ((seqs_end - seqs_begin > 1) && _GLIBCXX_PARALLEL_CONDITION( ((seqs_end - seqs_begin) >= __gnu_parallel::_Settings::get().multiway_merge_minimal_k) && ((sequence_index_t)length >= __gnu_parallel::_Settings::get().multiway_merge_minimal_n))) return parallel_multiway_merge </* stable = */ true, /* sentinels = */ true>( seqs_begin, seqs_end, target, multiway_merge_exact_splitting</* stable = */ true, typename std::iterator_traits<RandomAccessIteratorPairIterator> ::value_type*, Comparator, _DifferenceTp>, static_cast<difference_type>(length), comp, tag.get_num_threads()); else return sequential_multiway_merge </* stable = */ true, /* sentinels = */ true>( seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , sampling_tag tag) { typedef _DifferenceTp difference_type; _GLIBCXX_CALL(seqs_end - seqs_begin) // catch special case: no sequences if (seqs_begin == seqs_end) return target; // Execute merge; maybe parallel, depending on the number of merged // elements and the number of sequences and global thresholds in // Settings. if ((seqs_end - seqs_begin > 1) && _GLIBCXX_PARALLEL_CONDITION( ((seqs_end - seqs_begin) >= __gnu_parallel::_Settings::get().multiway_merge_minimal_k) && ((sequence_index_t)length >= __gnu_parallel::_Settings::get().multiway_merge_minimal_n))) return parallel_multiway_merge </* stable = */ true, /* sentinels = */ true>( seqs_begin, seqs_end, target, multiway_merge_sampling_splitting</* stable = */ true, typename std::iterator_traits<RandomAccessIteratorPairIterator> ::value_type*, Comparator, _DifferenceTp>, static_cast<difference_type>(length), comp, tag.get_num_threads()); else return sequential_multiway_merge </* stable = */ true, /* sentinels = */ true>( seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , parallel_tag tag = parallel_tag(0)) { return stable_multiway_merge_sentinels(seqs_begin, seqs_end, target, length, comp, exact_tag(tag.get_num_threads())); } // public interface template< typename RandomAccessIteratorPairIterator , typename RandomAccessIteratorOut , typename _DifferenceTp , typename Comparator> RandomAccessIteratorOut stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin , RandomAccessIteratorPairIterator seqs_end , RandomAccessIteratorOut target , _DifferenceTp length, Comparator comp , default_parallel_tag tag) { return stable_multiway_merge_sentinels(seqs_begin, seqs_end, target, length, comp, exact_tag(tag.get_num_threads())); } }; // namespace __gnu_parallel #endif /* _GLIBCXX_PARALLEL_MULTIWAY_MERGE_H */
Save
cmd:
run