16 #ifndef STXXL_CONTAINERS_PQ_MERGERS_HEADER 
   17 #define STXXL_CONTAINERS_PQ_MERGERS_HEADER 
   29 namespace priority_queue_local {
 
   40 template <
class InputIterator, 
class OutputIterator, 
class CompareType>
 
   42     InputIterator& source0,
 
   43     InputIterator& source1,
 
   44     OutputIterator target, OutputIterator end,
 
   49         if (cmp(*source0, *source1))
 
   69 template <
class InputIterator, 
class OutputIterator,
 
   72     InputIterator& source0,
 
   73     InputIterator& source1,
 
   74     InputIterator& source2,
 
   75     OutputIterator target, OutputIterator end,
 
   78     if (cmp(*source1, *source0)) {
 
   79         if (cmp(*source2, *source1)) {
 
   83             if (cmp(*source0, *source2)) {
 
   92         if (cmp(*source2, *source1)) {
 
   93             if (cmp(*source2, *source0)) {
 
  105 #define Merge3Case(a, b, c)              \ 
  109     *target = *source ## a;              \ 
  112     if (cmp(*source ## b, *source ## a)) \ 
  113         goto s ## a ## b ## c;           \ 
  114     if (cmp(*source ## c, *source ## a)) \ 
  115         goto s ## b ## a ## c;           \ 
  116     goto s ## b ## c ## a; 
  136 template <
class InputIterator, 
class OutputIterator,
 
  139     InputIterator& source0,
 
  140     InputIterator& source1,
 
  141     InputIterator& source2,
 
  142     InputIterator& source3,
 
  143     OutputIterator target, OutputIterator end,
 
  146 #define StartMerge4(a, b, c, d)               \ 
  147     if ((!cmp(*source ## a, *source ## b)) && \ 
  148         (!cmp(*source ## b, *source ## c)) && \ 
  149         (!cmp(*source ## c, *source ## d)))   \ 
  150         goto s ## a ## b ## c ## d; 
  187 #define Merge4Case(a, b, c, d)               \ 
  188     s ## a ## b ## c ## d:                   \ 
  191     *target = *source ## a;                  \ 
  194     if (cmp(*source ## c, *source ## a))     \ 
  196         if (cmp(*source ## b, *source ## a)) \ 
  197             goto s ## a ## b ## c ## d;      \ 
  199             goto s ## b ## a ## c ## d;      \ 
  203         if (cmp(*source ## d, *source ## a)) \ 
  204             goto s ## b ## c ## a ## d;      \ 
  206             goto s ## b ## c ## d ## a;      \ 
  250 template <
class ArraysType, 
class CompareType, 
unsigned Arity>
 
  260     enum { arity = Arity, max_arity = 1UL << (LOG2<Arity>::ceil) };
 
  292     struct Entry entry[max_arity];
 
  299         : cmp(c), k(1), logK(0), arrays(a)
 
  302         assert(!cmp(cmp.min_value(), cmp.min_value()));
 
  310         rebuild_loser_tree();
 
  312         assert(arrays.is_array_empty(0) && !arrays.is_array_allocated(0));
 
  318         return !(cmp(cmp.min_value(), a)); 
 
  325         if (free_slots.
empty()) {
 
  330         assert(!free_slots.
empty());
 
  341         free_slots.
push(slot);
 
  347         return (k < arity) || !free_slots.
empty();
 
  354         entry[0].index = winner;
 
  355         entry[0].key = *arrays.get_array(winner);
 
  365         if (root >= k || root >= max_arity)
 
  373             value_type lk = *arrays.get_array(left);
 
  374             value_type rk = *arrays.get_array(right);
 
  375             assert(root < max_arity);
 
  380                 entry[root].index = right;
 
  381                 entry[root].key = rk;
 
  386                 entry[root].index = left;
 
  387                 entry[root].key = lk;
 
  401                           value_type* winner_key,
 
  409             *winner_key = entry[0].key;
 
  410             *winner_index = entry[0].index;
 
  411             if (cmp(entry[node].key, newKey))
 
  413                 entry[node].key = newKey;
 
  414                 entry[node].index = newIndex;
 
  419             update_on_insert(node >> 1, newKey, newIndex, winner_key, winner_index, mask);
 
  420             value_type loserKey = entry[node].key;
 
  422             if ((*winner_index & *mask) != (newIndex & *mask)) {     
 
  424                 if (cmp(loserKey, newKey)) {
 
  425                     if (cmp(*winner_key, newKey)) {
 
  427                         entry[node].key = *winner_key;
 
  428                         entry[node].index = *winner_index;
 
  432                         entry[node].key = newKey;
 
  433                         entry[node].index = newIndex;
 
  436                 *winner_key = loserKey;
 
  437                 *winner_index = loserIndex;
 
  456         update_on_insert(node, newKey, newIndex,
 
  457                          &dummyKey, &dummyIndex, &dummyMask);
 
  463         STXXL_VERBOSE1(
"double_k (before) k=" << k << 
" logK=" << logK << 
" arity=" << arity << 
" max_arity=" << max_arity << 
" #free=" << free_slots.
size());
 
  466         assert(free_slots.
empty());                    
 
  471             arrays.make_array_sentinel(i);
 
  480         STXXL_VERBOSE1(
"double_k (after)  k=" << k << 
" logK=" << logK << 
" arity=" << arity << 
" max_arity=" << max_arity << 
" #free=" << free_slots.
size());
 
  481         assert(!free_slots.
empty());
 
  482         assert(k <= max_arity);
 
  485         rebuild_loser_tree();
 
  491         STXXL_VERBOSE3(
"compact_tree (before) k=" << k << 
" logK=" << logK << 
" #free=" << free_slots.
size());
 
  498             if (!arrays.is_array_empty(pos))
 
  500                 assert(arrays.is_array_allocated(pos));
 
  501                 if (pos != last_empty)
 
  503                     assert(!arrays.is_array_allocated(last_empty));
 
  504                     arrays.swap_arrays(last_empty, pos);
 
  523         while ((k > 1) && last_empty <= (k / 2))
 
  531         for ( ; last_empty < k; last_empty++)
 
  533             assert(!arrays.is_array_allocated(last_empty));
 
  534             arrays.make_array_sentinel(last_empty);
 
  535             if (last_empty < arity)
 
  536                 free_slots.
push(last_empty);
 
  539         STXXL_VERBOSE3(
"compact_tree (after)  k=" << k << 
" logK=" << logK << 
" #free=" << free_slots.
size());
 
  542         rebuild_loser_tree();
 
  555         STXXL_VERBOSE3(
"int_merger  compact? k=" << k << 
" #used=" << num_segments_used
 
  556                                                  << 
" <= #trigger=" << num_segments_trigger << 
" ==> " 
  557                                                  << ((k > 1 && num_segments_used <= num_segments_trigger) ? 
"yes" : 
"no ")
 
  559                                                  << ((k == 4 && !free_slots.
empty() && !arrays.is_array_empty(3)) ? 
"yes" : 
"no ")
 
  560                                                  << 
" #free=" << free_slots.
size());
 
  562             ((num_segments_used <= num_segments_trigger) ||
 
  563              (k == 4 && !free_slots.
empty() && !arrays.is_array_empty(3))))
 
  570     template <
class OutputIterator>
 
  574         value_type current_key;
 
  577         value_type winner_key = entry[0].key;
 
  582             *begin++ = *arrays.get_array(winner_index);
 
  585             ++(arrays.get_array(winner_index));
 
  587             winner_key = *arrays.get_array(winner_index);
 
  590             if (is_sentinel(winner_key))
 
  591                 arrays.free_array(winner_index);
 
  594             for (
unsigned_type i = (winner_index + k) >> 1; i > 0; i >>= 1)
 
  596                 current_pos = entry + i;
 
  597                 current_key = current_pos->key;
 
  598                 if (cmp(winner_key, current_key))
 
  600                     current_index = current_pos->index;
 
  601                     current_pos->key = winner_key;
 
  602                     current_pos->index = winner_index;
 
  603                     winner_key = current_key;
 
  604                     winner_index = current_index;
 
  608         entry[0].index = winner_index;
 
  609         entry[0].key = winner_key;
 
  612     template <
int LogK, 
typename OutputIterator>
 
  616         value_type winner_key = entry[0].key;
 
  622             *begin++ = *arrays.get_array(winner_index);
 
  625             ++(arrays.get_array(winner_index));
 
  627             winner_key = *arrays.get_array(winner_index);
 
  630             if (is_sentinel(winner_key))
 
  631                 arrays.free_array(winner_index);
 
  634 #define TreeStep(L)                                                        \ 
  635     if (1 << LogK >= 1 << L) {                                             \ 
  636         int pos_shift = ((int(LogK - L) + 1) >= 0) ? ((LogK - L) + 1) : 0; \ 
  637         Entry* pos = entry + ((winner_index + (1 << LogK)) >> pos_shift);  \ 
  638         value_type key = pos->key;                                         \ 
  639         if (cmp(winner_key, key)) {                                        \ 
  640             unsigned_type index = pos->index;                              \ 
  641             pos->key = winner_key;                                         \ 
  642             pos->index = winner_index;                                     \ 
  644             winner_index = index;                                          \ 
  659         entry[0].index = winner_index;
 
  660         entry[0].key = winner_key;
 
  666     template <
class OutputIterator>
 
  671         STXXL_VERBOSE3(
"multi_merge(length=" << length << 
") from sequences k=" << k);
 
  680         arrays.prefetch_arrays();
 
  685             assert(entry[0].index == 0);
 
  686             assert(free_slots.
empty());
 
  691             sequence_type& seq = arrays.get_array(0);
 
  692             for (
int_type i = 0; i < length; ++i, ++seq, ++begin)
 
  696             if (arrays.is_array_empty(0) && arrays.is_array_allocated(0))
 
  697                 arrays.free_array(0);
 
  705             rebuild_loser_tree();
 
  707             if (arrays.is_array_empty(0) && arrays.is_array_allocated(0))
 
  708                 arrays.free_array(0);
 
  710             if (arrays.is_array_empty(1) && arrays.is_array_allocated(1))
 
  711                 arrays.free_array(1);
 
  716             if (arrays.is_array_empty(3))
 
  722                                 arrays.get_array(2), arrays.get_array(3),
 
  725             rebuild_loser_tree();
 
  727             if (arrays.is_array_empty(0) && arrays.is_array_allocated(0))
 
  728                 arrays.free_array(0);
 
  730             if (arrays.is_array_empty(1) && arrays.is_array_allocated(1))
 
  731                 arrays.free_array(1);
 
  733             if (arrays.is_array_empty(2) && arrays.is_array_allocated(2))
 
  734                 arrays.free_array(2);
 
  736             if (arrays.is_array_empty(3) && arrays.is_array_allocated(3))
 
  737                 arrays.free_array(3);
 
  740         case  3: multi_merge_f<3>(begin, end);
 
  742         case  4: multi_merge_f<4>(begin, end);
 
  744         case  5: multi_merge_f<5>(begin, end);
 
  746         case  6: multi_merge_f<6>(begin, end);
 
  748         case  7: multi_merge_f<7>(begin, end);
 
  750         case  8: multi_merge_f<8>(begin, end);
 
  752         case  9: multi_merge_f<9>(begin, end);
 
  754         case 10: multi_merge_f<10>(begin, end);
 
  756         default: multi_merge_k(begin, end);
 
  772 #if STXXL_PARALLEL && (STXXL_PARALLEL_PQ_MULTIWAY_MERGE_EXTERNAL || STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL) 
  780 template <
class ArraysType, 
class CompareType, 
unsigned Arity>
 
  781 class parallel_merger_adapter : 
private noncopyable 
  785     typedef ArraysType arrays_type;
 
  787     typedef CompareType compare_type;
 
  790     enum { arity = Arity, max_arity = 1UL << (LOG2<Arity>::ceil) };
 
  793     typedef typename arrays_type::value_type value_type;
 
  795     typedef typename arrays_type::sequence_type sequence_type;
 
  811     internal_bounded_stack<unsigned_type, arity> free_slots;
 
  814     parallel_merger_adapter(
const compare_type& c, arrays_type& a)
 
  815         : cmp(c), k(1), logK(0), arrays(a)
 
  818         assert(!cmp(cmp.min_value(), cmp.min_value()));
 
  828     bool is_sentinel(
const value_type& a)
 const 
  830         return !(cmp(cmp.min_value(), a)); 
 
  837         if (free_slots.empty()) {
 
  842         assert(!free_slots.empty());
 
  852         free_slots.push(slot);
 
  856     bool is_space_available()
 const 
  858         return (k < arity) || !free_slots.empty();
 
  870         STXXL_VERBOSE1(
"double_k (before) k=" << k << 
" logK=" << logK << 
" arity=" << arity << 
" max_arity=" << max_arity << 
" #free=" << free_slots.size());
 
  873         assert(free_slots.empty());                    
 
  878             arrays.make_array_sentinel(i);
 
  887         STXXL_VERBOSE1(
"double_k (after)  k=" << k << 
" logK=" << logK << 
" arity=" << arity << 
" max_arity=" << max_arity << 
" #free=" << free_slots.size());
 
  888         assert(!free_slots.empty());
 
  889         assert(k <= max_arity);
 
  895         STXXL_VERBOSE3(
"compact_tree (before) k=" << k << 
" logK=" << logK << 
" #free=" << free_slots.size());
 
  902             if (!arrays.is_array_empty(pos))
 
  904                 assert(arrays.is_array_allocated(pos));
 
  905                 if (pos != last_empty)
 
  907                     assert(!arrays.is_array_allocated(last_empty));
 
  908                     arrays.swap_arrays(last_empty, pos);
 
  927         while ((k > 1) && last_empty <= (k / 2))
 
  935         for ( ; last_empty < k; last_empty++)
 
  937             assert(!arrays.is_array_allocated(last_empty));
 
  938             arrays.make_array_sentinel(last_empty);
 
  939             if (last_empty < arity)
 
  940                 free_slots.push(last_empty);
 
  943         STXXL_VERBOSE3(
"compact_tree (after)  k=" << k << 
" logK=" << logK << 
" #free=" << free_slots.size());
 
  949         const unsigned_type num_segments_used = k - free_slots.size();
 
  956         STXXL_VERBOSE3(
"int_merger  compact? k=" << k << 
" #used=" << num_segments_used
 
  957                                                  << 
" <= #trigger=" << num_segments_trigger << 
" ==> " 
  958                                                  << ((k > 1 && num_segments_used <= num_segments_trigger) ? 
"yes" : 
"no ")
 
  960                                                  << ((k == 4 && !free_slots.empty() && !arrays.is_array_empty(3)) ? 
"yes" : 
"no ")
 
  961                                                  << 
" #free=" << free_slots.size());
 
  963             ((num_segments_used <= num_segments_trigger) ||
 
  964              (k == 4 && !free_slots.empty() && !arrays.is_array_empty(3))))
 
  970     void swap(parallel_merger_adapter& obj)
 
  972         std::swap(free_slots, obj.free_slots);
 
  975 #endif // STXXL_PARALLEL && (STXXL_PARALLEL_PQ_MULTIWAY_MERGE_EXTERNAL || STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL) 
  983 #endif // !STXXL_CONTAINERS_PQ_MERGERS_HEADER 
void multi_merge_f(OutputIterator begin, OutputIterator end)
void double_k()
make the tree twice as wide 
arrays_type & arrays
reference to the linked arrays 
#define StartMerge4(a, b, c, d)
bool is_space_available() const 
Whether there is still space for new array. 
void maybe_compact()
compact tree if it got considerably smaller 
arrays_type::sequence_type sequence_type
type of the ordered sequences in the arrays container 
void update_on_insert(unsigned_type node, const value_type &newKey, unsigned_type newIndex)
Initial call to recursive update_on_insert. 
void multi_merge_k(OutputIterator begin, OutputIterator end)
multi-merge for arbitrary K 
void merge3_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, OutputIterator target, OutputIterator end, CompareType &cmp)
void swap_1D_arrays(Type *a, Type *b, unsigned_type size)
arrays_type::value_type value_type
type of values stored in the arrays container 
Loser tree from Knuth, "Sorting and Searching", Section 5.4.1. 
void free_player(unsigned_type slot)
Free a finished player's slot. 
CompareType compare_type
comparator object type 
void merge4_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, InputIterator &source3, OutputIterator target, OutputIterator end, CompareType &cmp)
#define STXXL_VERBOSE3(x)
choose_int_types< my_pointer_size >::int_type int_type
loser_tree(const compare_type &c, arrays_type &a)
void update_on_insert(unsigned_type node, const value_type &newKey, unsigned_type newIndex, value_type *winner_key, unsigned_type *winner_index, unsigned_type *mask)
Update loser tree on insert or decrement of player index first go up the tree all the way to the root...
void push(const value_type &x)
compare_type cmp
the comparator object 
#define STXXL_BEGIN_NAMESPACE
struct Entry entry[max_arity]
levels of loser tree: entry[0] contains the winner info 
#define STXXL_VERBOSE1(x)
unsigned_type index
number of losing segment 
value_type key
Key of Loser element (winner for 0) 
void compact_tree()
compact nonempty segments in the left half of the tree 
type of nodes in the loser tree 
unsigned_type new_player()
Allocate a free slot for a new player. 
unsigned_type init_winner(unsigned_type root)
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
#define Merge4Case(a, b, c, d)
internal_bounded_stack< unsigned_type, MaxArity > free_slots
void multi_merge(OutputIterator begin, OutputIterator end)
extract the (length = end - begin) smallest elements and write them to [begin..end) empty segments ar...
bool is_sentinel(const value_type &a) const 
True if a is the sentinel value. 
void rebuild_loser_tree()
rebuild loser tree information from the values in current 
const value_type & top() const 
#define Merge3Case(a, b, c)
ArraysType arrays_type
type of arrays container linked with loser tree 
internal_bounded_stack< unsigned_type, arity > free_slots
stack of free player indices 
void merge2_iterator(InputIterator &source0, InputIterator &source1, OutputIterator target, OutputIterator end, CompareType &cmp)
void swap(loser_tree &obj)
#define STXXL_END_NAMESPACE