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