3 // Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the terms
7 // of the GNU General Public License as published by the Free Software
8 // Foundation; either version 3, or (at your option) any later
11 // This library is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 /** @file parallel/multiway_merge.h
26 * @brief Implementation of sequential and parallel multiway merge.
28 * Explanations on the high-speed merging routines in the appendix of
31 * Fast priority queues for cached memory.
32 * ACM Journal of Experimental Algorithmics, 5, 2000.
34 * This file is a GNU parallel extension to the Standard C++ Library.
37 // Written by Johannes Singler and Manuel Holtgrewe.
39 #ifndef _GLIBCXX_PARALLEL_MULTIWAY_MERGE_H
40 #define _GLIBCXX_PARALLEL_MULTIWAY_MERGE_H
44 #include <bits/stl_algo.h>
45 #include <parallel/features.h>
46 #include <parallel/parallel.h>
47 #include <parallel/losertree.h>
48 #if _GLIBCXX_ASSERTIONS
49 #include <parallel/checkers.h>
52 /** @brief Length of a sequence described by a pair of iterators. */
53 #define _GLIBCXX_PARALLEL_LENGTH(s) ((s).second - (s).first)
55 namespace __gnu_parallel
58 // Announce guarded and unguarded iterator.
60 template<typename RandomAccessIterator, typename Comparator>
61 class guarded_iterator;
63 // Making the arguments const references seems to dangerous,
64 // the user-defined comparator might not be const.
65 template<typename RandomAccessIterator, typename Comparator>
67 operator<(guarded_iterator<RandomAccessIterator, Comparator>& bi1,
68 guarded_iterator<RandomAccessIterator, Comparator>& bi2);
70 template<typename RandomAccessIterator, typename Comparator>
72 operator<=(guarded_iterator<RandomAccessIterator, Comparator>& bi1,
73 guarded_iterator<RandomAccessIterator, Comparator>& bi2);
75 /** @brief Iterator wrapper supporting an implicit supremum at the end
76 * of the sequence, dominating all comparisons.
78 * The implicit supremum comes with a performance cost.
80 * Deriving from RandomAccessIterator is not possible since
81 * RandomAccessIterator need not be a class.
83 template<typename RandomAccessIterator, typename Comparator>
84 class guarded_iterator
87 /** @brief Current iterator position. */
88 RandomAccessIterator current;
90 /** @brief End iterator of the sequence. */
91 RandomAccessIterator end;
93 /** @brief Comparator. */
97 /** @brief Constructor. Sets iterator to beginning of sequence.
98 * @param begin Begin iterator of sequence.
99 * @param end End iterator of sequence.
100 * @param comp Comparator provided for associated overloaded
101 * compare operators. */
102 guarded_iterator(RandomAccessIterator begin,
103 RandomAccessIterator end, Comparator& comp)
104 : current(begin), end(end), comp(comp)
107 /** @brief Pre-increment operator.
109 guarded_iterator<RandomAccessIterator, Comparator>&
116 /** @brief Dereference operator.
117 * @return Referenced element. */
118 typename std::iterator_traits<RandomAccessIterator>::value_type&
122 /** @brief Convert to wrapped iterator.
123 * @return Wrapped iterator. */
124 operator RandomAccessIterator()
128 operator< <RandomAccessIterator, Comparator>(
129 guarded_iterator<RandomAccessIterator, Comparator>& bi1,
130 guarded_iterator<RandomAccessIterator, Comparator>& bi2);
133 operator<= <RandomAccessIterator, Comparator>(
134 guarded_iterator<RandomAccessIterator, Comparator>& bi1,
135 guarded_iterator<RandomAccessIterator, Comparator>& bi2);
138 /** @brief Compare two elements referenced by guarded iterators.
139 * @param bi1 First iterator.
140 * @param bi2 Second iterator.
141 * @return @c True if less. */
142 template<typename RandomAccessIterator, typename Comparator>
144 operator<(guarded_iterator<RandomAccessIterator, Comparator>& bi1,
145 guarded_iterator<RandomAccessIterator, Comparator>& bi2)
147 if (bi1.current == bi1.end) //bi1 is sup
148 return bi2.current == bi2.end; //bi2 is not sup
149 if (bi2.current == bi2.end) //bi2 is sup
151 return (bi1.comp)(*bi1, *bi2); //normal compare
154 /** @brief Compare two elements referenced by guarded iterators.
155 * @param bi1 First iterator.
156 * @param bi2 Second iterator.
157 * @return @c True if less equal. */
158 template<typename RandomAccessIterator, typename Comparator>
160 operator<=(guarded_iterator<RandomAccessIterator, Comparator>& bi1,
161 guarded_iterator<RandomAccessIterator, Comparator>& bi2)
163 if (bi2.current == bi2.end) //bi1 is sup
164 return bi1.current != bi1.end; //bi2 is not sup
165 if (bi1.current == bi1.end) //bi2 is sup
167 return !(bi1.comp)(*bi2, *bi1); //normal compare
170 template<typename RandomAccessIterator, typename Comparator>
171 class unguarded_iterator;
173 template<typename RandomAccessIterator, typename Comparator>
175 operator<(unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
176 unguarded_iterator<RandomAccessIterator, Comparator>& bi2);
178 template<typename RandomAccessIterator, typename Comparator>
180 operator<=(unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
181 unguarded_iterator<RandomAccessIterator, Comparator>& bi2);
183 template<typename RandomAccessIterator, typename Comparator>
184 class unguarded_iterator
187 /** @brief Current iterator position. */
188 RandomAccessIterator current;
189 /** @brief Comparator. */
190 mutable Comparator& comp;
193 /** @brief Constructor. Sets iterator to beginning of sequence.
194 * @param begin Begin iterator of sequence.
195 * @param end Unused, only for compatibility.
196 * @param comp Unused, only for compatibility. */
197 unguarded_iterator(RandomAccessIterator begin,
198 RandomAccessIterator end, Comparator& comp)
199 : current(begin), comp(comp)
202 /** @brief Pre-increment operator.
204 unguarded_iterator<RandomAccessIterator, Comparator>&
211 /** @brief Dereference operator.
212 * @return Referenced element. */
213 typename std::iterator_traits<RandomAccessIterator>::value_type&
217 /** @brief Convert to wrapped iterator.
218 * @return Wrapped iterator. */
219 operator RandomAccessIterator()
223 operator< <RandomAccessIterator, Comparator>(
224 unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
225 unguarded_iterator<RandomAccessIterator, Comparator>& bi2);
228 operator<= <RandomAccessIterator, Comparator>(
229 unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
230 unguarded_iterator<RandomAccessIterator, Comparator>& bi2);
233 /** @brief Compare two elements referenced by unguarded iterators.
234 * @param bi1 First iterator.
235 * @param bi2 Second iterator.
236 * @return @c True if less. */
237 template<typename RandomAccessIterator, typename Comparator>
239 operator<(unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
240 unguarded_iterator<RandomAccessIterator, Comparator>& bi2)
243 return (bi1.comp)(*bi1, *bi2);
246 /** @brief Compare two elements referenced by unguarded iterators.
247 * @param bi1 First iterator.
248 * @param bi2 Second iterator.
249 * @return @c True if less equal. */
250 template<typename RandomAccessIterator, typename Comparator>
252 operator<=(unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
253 unguarded_iterator<RandomAccessIterator, Comparator>& bi2)
256 return !(bi1.comp)(*bi2, *bi1);
259 /** @brief Highly efficient 3-way merging procedure.
261 * Merging is done with the algorithm implementation described by Peter
262 * Sanders. Basically, the idea is to minimize the number of necessary
263 * comparison after merging out an element. The implementation trick
264 * that makes this fast is that the order of the sequences is stored
265 * in the instruction pointer (translated into labels in C++).
267 * This works well for merging up to 4 sequences.
269 * Note that making the merging stable does <em>not</em> come at a
272 * Whether the merging is done guarded or unguarded is selected by the
273 * used iterator class.
275 * @param seqs_begin Begin iterator of iterator pair input sequence.
276 * @param seqs_end End iterator of iterator pair input sequence.
277 * @param target Begin iterator out output sequence.
278 * @param comp Comparator.
279 * @param length Maximum length to merge, less equal than the
280 * total number of elements available.
282 * @return End iterator of output sequence.
284 template<template<typename RAI, typename C> class iterator,
285 typename RandomAccessIteratorIterator,
286 typename RandomAccessIterator3,
287 typename _DifferenceTp,
289 RandomAccessIterator3
290 multiway_merge_3_variant(
291 RandomAccessIteratorIterator seqs_begin,
292 RandomAccessIteratorIterator seqs_end,
293 RandomAccessIterator3 target,
294 _DifferenceTp length, Comparator comp)
296 _GLIBCXX_CALL(length);
298 typedef _DifferenceTp difference_type;
300 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
301 ::value_type::first_type
302 RandomAccessIterator1;
303 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
309 #if _GLIBCXX_ASSERTIONS
310 _DifferenceTp orig_length = length;
313 iterator<RandomAccessIterator1, Comparator>
314 seq0(seqs_begin[0].first, seqs_begin[0].second, comp),
315 seq1(seqs_begin[1].first, seqs_begin[1].second, comp),
316 seq2(seqs_begin[2].first, seqs_begin[2].second, comp);
340 #define _GLIBCXX_PARALLEL_MERGE_3_CASE(a,b,c,c0,c1) \
342 *target = *seq ## a; \
346 if (length == 0) goto finish; \
347 if (seq ## a c0 seq ## b) goto s ## a ## b ## c; \
348 if (seq ## a c1 seq ## c) goto s ## b ## a ## c; \
349 goto s ## b ## c ## a;
351 _GLIBCXX_PARALLEL_MERGE_3_CASE(0, 1, 2, <=, <=);
352 _GLIBCXX_PARALLEL_MERGE_3_CASE(1, 2, 0, <=, < );
353 _GLIBCXX_PARALLEL_MERGE_3_CASE(2, 0, 1, < , < );
354 _GLIBCXX_PARALLEL_MERGE_3_CASE(1, 0, 2, < , <=);
355 _GLIBCXX_PARALLEL_MERGE_3_CASE(0, 2, 1, <=, <=);
356 _GLIBCXX_PARALLEL_MERGE_3_CASE(2, 1, 0, < , < );
358 #undef _GLIBCXX_PARALLEL_MERGE_3_CASE
363 #if _GLIBCXX_ASSERTIONS
364 _GLIBCXX_PARALLEL_ASSERT(
365 ((RandomAccessIterator1)seq0 - seqs_begin[0].first) +
366 ((RandomAccessIterator1)seq1 - seqs_begin[1].first) +
367 ((RandomAccessIterator1)seq2 - seqs_begin[2].first)
371 seqs_begin[0].first = seq0;
372 seqs_begin[1].first = seq1;
373 seqs_begin[2].first = seq2;
379 * @brief Highly efficient 4-way merging procedure.
381 * Merging is done with the algorithm implementation described by Peter
382 * Sanders. Basically, the idea is to minimize the number of necessary
383 * comparison after merging out an element. The implementation trick
384 * that makes this fast is that the order of the sequences is stored
385 * in the instruction pointer (translated into goto labels in C++).
387 * This works well for merging up to 4 sequences.
389 * Note that making the merging stable does <em>not</em> come at a
392 * Whether the merging is done guarded or unguarded is selected by the
393 * used iterator class.
395 * @param seqs_begin Begin iterator of iterator pair input sequence.
396 * @param seqs_end End iterator of iterator pair input sequence.
397 * @param target Begin iterator out output sequence.
398 * @param comp Comparator.
399 * @param length Maximum length to merge, less equal than the
400 * total number of elements available.
402 * @return End iterator of output sequence.
404 template<template<typename RAI, typename C> class iterator,
405 typename RandomAccessIteratorIterator,
406 typename RandomAccessIterator3,
407 typename _DifferenceTp,
409 RandomAccessIterator3
410 multiway_merge_4_variant(RandomAccessIteratorIterator seqs_begin,
411 RandomAccessIteratorIterator seqs_end,
412 RandomAccessIterator3 target,
413 _DifferenceTp length, Comparator comp)
415 _GLIBCXX_CALL(length);
416 typedef _DifferenceTp difference_type;
418 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
419 ::value_type::first_type
420 RandomAccessIterator1;
421 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
424 iterator<RandomAccessIterator1, Comparator>
425 seq0(seqs_begin[0].first, seqs_begin[0].second, comp),
426 seq1(seqs_begin[1].first, seqs_begin[1].second, comp),
427 seq2(seqs_begin[2].first, seqs_begin[2].second, comp),
428 seq3(seqs_begin[3].first, seqs_begin[3].second, comp);
430 #define _GLIBCXX_PARALLEL_DECISION(a,b,c,d) { \
431 if (seq ## d < seq ## a) goto s ## d ## a ## b ## c; \
432 if (seq ## d < seq ## b) goto s ## a ## d ## b ## c; \
433 if (seq ## d < seq ## c) goto s ## a ## b ## d ## c; \
434 goto s ## a ## b ## c ## d; }
439 _GLIBCXX_PARALLEL_DECISION(0,1,2,3)
442 _GLIBCXX_PARALLEL_DECISION(2,0,1,3)
444 _GLIBCXX_PARALLEL_DECISION(0,2,1,3)
451 _GLIBCXX_PARALLEL_DECISION(1,0,2,3)
453 _GLIBCXX_PARALLEL_DECISION(1,2,0,3)
456 _GLIBCXX_PARALLEL_DECISION(2,1,0,3)
459 #define _GLIBCXX_PARALLEL_MERGE_4_CASE(a,b,c,d,c0,c1,c2) \
460 s ## a ## b ## c ## d: \
461 if (length == 0) goto finish; \
462 *target = *seq ## a; \
466 if (seq ## a c0 seq ## b) goto s ## a ## b ## c ## d; \
467 if (seq ## a c1 seq ## c) goto s ## b ## a ## c ## d; \
468 if (seq ## a c2 seq ## d) goto s ## b ## c ## a ## d; \
469 goto s ## b ## c ## d ## a;
471 _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 1, 2, 3, <=, <=, <=);
472 _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 1, 3, 2, <=, <=, <=);
473 _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 2, 1, 3, <=, <=, <=);
474 _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 2, 3, 1, <=, <=, <=);
475 _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 3, 1, 2, <=, <=, <=);
476 _GLIBCXX_PARALLEL_MERGE_4_CASE(0, 3, 2, 1, <=, <=, <=);
477 _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 0, 2, 3, < , <=, <=);
478 _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 0, 3, 2, < , <=, <=);
479 _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 2, 0, 3, <=, < , <=);
480 _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 2, 3, 0, <=, <=, < );
481 _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 3, 0, 2, <=, < , <=);
482 _GLIBCXX_PARALLEL_MERGE_4_CASE(1, 3, 2, 0, <=, <=, < );
483 _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 0, 1, 3, < , < , <=);
484 _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 0, 3, 1, < , <=, < );
485 _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 1, 0, 3, < , < , <=);
486 _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 1, 3, 0, < , <=, < );
487 _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 3, 0, 1, <=, < , < );
488 _GLIBCXX_PARALLEL_MERGE_4_CASE(2, 3, 1, 0, <=, < , < );
489 _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 0, 1, 2, < , < , < );
490 _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 0, 2, 1, < , < , < );
491 _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 1, 0, 2, < , < , < );
492 _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 1, 2, 0, < , < , < );
493 _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 2, 0, 1, < , < , < );
494 _GLIBCXX_PARALLEL_MERGE_4_CASE(3, 2, 1, 0, < , < , < );
496 #undef _GLIBCXX_PARALLEL_MERGE_4_CASE
497 #undef _GLIBCXX_PARALLEL_DECISION
502 seqs_begin[0].first = seq0;
503 seqs_begin[1].first = seq1;
504 seqs_begin[2].first = seq2;
505 seqs_begin[3].first = seq3;
510 /** @brief Multi-way merging procedure for a high branching factor,
513 * This merging variant uses a LoserTree class as selected by <tt>LT</tt>.
515 * Stability is selected through the used LoserTree class <tt>LT</tt>.
517 * At least one non-empty sequence is required.
519 * @param seqs_begin Begin iterator of iterator pair input sequence.
520 * @param seqs_end End iterator of iterator pair input sequence.
521 * @param target Begin iterator out output sequence.
522 * @param comp Comparator.
523 * @param length Maximum length to merge, less equal than the
524 * total number of elements available.
526 * @return End iterator of output sequence.
528 template<typename LT,
529 typename RandomAccessIteratorIterator,
530 typename RandomAccessIterator3,
531 typename _DifferenceTp,
533 RandomAccessIterator3
534 multiway_merge_loser_tree(RandomAccessIteratorIterator seqs_begin,
535 RandomAccessIteratorIterator seqs_end,
536 RandomAccessIterator3 target,
537 _DifferenceTp length, Comparator comp)
539 _GLIBCXX_CALL(length)
541 typedef _DifferenceTp difference_type;
542 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
543 ::value_type::first_type
544 RandomAccessIterator1;
545 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
548 int k = static_cast<int>(seqs_end - seqs_begin);
552 // Default value for potentially non-default-constructible types.
553 value_type* arbitrary_element = NULL;
555 for (int t = 0; t < k; ++t)
557 if(arbitrary_element == NULL
558 && _GLIBCXX_PARALLEL_LENGTH(seqs_begin[t]) > 0)
559 arbitrary_element = &(*seqs_begin[t].first);
562 for (int t = 0; t < k; ++t)
564 if (seqs_begin[t].first == seqs_begin[t].second)
565 lt.insert_start(*arbitrary_element, t, true);
567 lt.insert_start(*seqs_begin[t].first, t, false);
574 for (difference_type i = 0; i < length; ++i)
577 source = lt.get_min_source();
579 *(target++) = *(seqs_begin[source].first++);
582 if (seqs_begin[source].first == seqs_begin[source].second)
583 lt.delete_min_insert(*arbitrary_element, true);
585 // Replace from same source.
586 lt.delete_min_insert(*seqs_begin[source].first, false);
592 /** @brief Multi-way merging procedure for a high branching factor,
595 * Merging is done using the LoserTree class <tt>LT</tt>.
597 * Stability is selected by the used LoserTrees.
599 * @pre No input will run out of elements during the merge.
601 * @param seqs_begin Begin iterator of iterator pair input sequence.
602 * @param seqs_end End iterator of iterator pair input sequence.
603 * @param target Begin iterator out output sequence.
604 * @param comp Comparator.
605 * @param length Maximum length to merge, less equal than the
606 * total number of elements available.
608 * @return End iterator of output sequence.
610 template<typename LT,
611 typename RandomAccessIteratorIterator,
612 typename RandomAccessIterator3,
613 typename _DifferenceTp, typename Comparator>
614 RandomAccessIterator3
615 multiway_merge_loser_tree_unguarded(
616 RandomAccessIteratorIterator seqs_begin,
617 RandomAccessIteratorIterator seqs_end,
618 RandomAccessIterator3 target,
619 const typename std::iterator_traits<typename std::iterator_traits<
620 RandomAccessIteratorIterator>::value_type::first_type>::value_type&
622 _DifferenceTp length,
625 _GLIBCXX_CALL(length)
626 typedef _DifferenceTp difference_type;
628 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
629 ::value_type::first_type
630 RandomAccessIterator1;
631 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
634 int k = seqs_end - seqs_begin;
636 LT lt(k, sentinel, comp);
638 for (int t = 0; t < k; ++t)
640 #if _GLIBCXX_ASSERTIONS
641 _GLIBCXX_PARALLEL_ASSERT(seqs_begin[t].first != seqs_begin[t].second);
643 lt.insert_start(*seqs_begin[t].first, t, false);
650 #if _GLIBCXX_ASSERTIONS
651 difference_type i = 0;
654 RandomAccessIterator3 target_end = target + length;
655 while (target < target_end)
658 source = lt.get_min_source();
660 #if _GLIBCXX_ASSERTIONS
661 _GLIBCXX_PARALLEL_ASSERT(0 <= source && source < k);
662 _GLIBCXX_PARALLEL_ASSERT(i == 0
663 || !comp(*(seqs_begin[source].first), *(target - 1)));
667 *(target++) = *(seqs_begin[source].first++);
669 #if _GLIBCXX_ASSERTIONS
672 // Replace from same source.
673 lt.delete_min_insert(*seqs_begin[source].first, false);
680 /** @brief Multi-way merging procedure for a high branching factor,
681 * requiring sentinels to exist.
683 * @param stable The value must the same as for the used LoserTrees.
684 * @param UnguardedLoserTree Loser Tree variant to use for the unguarded
686 * @param GuardedLoserTree Loser Tree variant to use for the guarded
689 * @param seqs_begin Begin iterator of iterator pair input sequence.
690 * @param seqs_end End iterator of iterator pair input sequence.
691 * @param target Begin iterator out output sequence.
692 * @param comp Comparator.
693 * @param length Maximum length to merge, less equal than the
694 * total number of elements available.
696 * @return End iterator of output sequence.
699 typename UnguardedLoserTree,
700 typename RandomAccessIteratorIterator,
701 typename RandomAccessIterator3,
702 typename _DifferenceTp,
704 RandomAccessIterator3
705 multiway_merge_loser_tree_sentinel(
706 RandomAccessIteratorIterator seqs_begin,
707 RandomAccessIteratorIterator seqs_end,
708 RandomAccessIterator3 target,
709 const typename std::iterator_traits<typename std::iterator_traits<
710 RandomAccessIteratorIterator>::value_type::first_type>::value_type&
712 _DifferenceTp length,
715 _GLIBCXX_CALL(length)
717 typedef _DifferenceTp difference_type;
718 typedef std::iterator_traits<RandomAccessIteratorIterator> traits_type;
719 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
720 ::value_type::first_type
721 RandomAccessIterator1;
722 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
725 RandomAccessIterator3 target_end;
727 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s)
728 // Move the sequends end behind the sentinel spots. This has the
729 // effect that the sentinel appears to be within the sequence. Then,
730 // we can use the unguarded variant if we merge out as many
731 // non-sentinel elements as we have.
734 target_end = multiway_merge_loser_tree_unguarded
736 (seqs_begin, seqs_end, target, sentinel, length, comp);
738 #if _GLIBCXX_ASSERTIONS
739 _GLIBCXX_PARALLEL_ASSERT(target_end == target + length);
740 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp));
743 // Restore the sequence ends so the sentinels are not contained in the
744 // sequence any more (see comment in loop above).
745 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s)
752 * @brief Traits for determining whether the loser tree should
753 * use pointers or copies.
755 * The field "use_pointer" is used to determine whether to use pointers in
756 * the loser trees or whether to copy the values into the loser tree.
758 * The default behavior is to use pointers if the data type is 4 times as
759 * big as the pointer to it.
761 * Specialize for your data type to customize the behavior.
766 * struct loser_tree_traits<int>
767 * { static const bool use_pointer = false; };
770 * struct loser_tree_traits<heavyweight_type>
771 * { static const bool use_pointer = true; };
773 * @param T type to give the loser tree traits for.
775 template <typename T>
776 struct loser_tree_traits
779 * @brief True iff to use pointers instead of values in loser trees.
781 * The default behavior is to use pointers if the data type is four
782 * times as big as the pointer to it.
784 static const bool use_pointer = (sizeof(T) > 4 * sizeof(T*));
788 * @brief Switch for 3-way merging with sentinels turned off.
790 * Note that 3-way merging is always stable!
793 bool sentinels /*default == false*/,
794 typename RandomAccessIteratorIterator,
795 typename RandomAccessIterator3,
796 typename _DifferenceTp,
798 struct multiway_merge_3_variant_sentinel_switch
800 RandomAccessIterator3 operator()(
801 RandomAccessIteratorIterator seqs_begin,
802 RandomAccessIteratorIterator seqs_end,
803 RandomAccessIterator3 target,
804 _DifferenceTp length, Comparator comp)
806 return multiway_merge_3_variant<guarded_iterator>(
807 seqs_begin, seqs_end, target, length, comp);
812 * @brief Switch for 3-way merging with sentinels turned on.
814 * Note that 3-way merging is always stable!
817 typename RandomAccessIteratorIterator,
818 typename RandomAccessIterator3,
819 typename _DifferenceTp,
821 struct multiway_merge_3_variant_sentinel_switch
822 <true, RandomAccessIteratorIterator, RandomAccessIterator3,
823 _DifferenceTp, Comparator>
825 RandomAccessIterator3 operator()(
826 RandomAccessIteratorIterator seqs_begin,
827 RandomAccessIteratorIterator seqs_end,
828 RandomAccessIterator3 target,
829 _DifferenceTp length, Comparator comp)
831 return multiway_merge_3_variant<unguarded_iterator>(
832 seqs_begin, seqs_end, target, length, comp);
837 * @brief Switch for 4-way merging with sentinels turned off.
839 * Note that 4-way merging is always stable!
842 bool sentinels /*default == false*/,
843 typename RandomAccessIteratorIterator,
844 typename RandomAccessIterator3,
845 typename _DifferenceTp,
847 struct multiway_merge_4_variant_sentinel_switch
849 RandomAccessIterator3 operator()(
850 RandomAccessIteratorIterator seqs_begin,
851 RandomAccessIteratorIterator seqs_end,
852 RandomAccessIterator3 target,
853 _DifferenceTp length, Comparator comp)
855 return multiway_merge_4_variant<guarded_iterator>(
856 seqs_begin, seqs_end, target, length, comp);
861 * @brief Switch for 4-way merging with sentinels turned on.
863 * Note that 4-way merging is always stable!
866 typename RandomAccessIteratorIterator,
867 typename RandomAccessIterator3,
868 typename _DifferenceTp,
870 struct multiway_merge_4_variant_sentinel_switch
871 <true, RandomAccessIteratorIterator, RandomAccessIterator3,
872 _DifferenceTp, Comparator>
874 RandomAccessIterator3 operator()(
875 RandomAccessIteratorIterator seqs_begin,
876 RandomAccessIteratorIterator seqs_end,
877 RandomAccessIterator3 target,
878 _DifferenceTp length, Comparator comp)
880 return multiway_merge_4_variant<unguarded_iterator>(
881 seqs_begin, seqs_end, target, length, comp);
886 * @brief Switch for k-way merging with sentinels turned on.
891 typename RandomAccessIteratorIterator,
892 typename RandomAccessIterator3,
893 typename _DifferenceTp,
895 struct multiway_merge_k_variant_sentinel_switch
897 RandomAccessIterator3 operator()(
898 RandomAccessIteratorIterator seqs_begin,
899 RandomAccessIteratorIterator seqs_end,
900 RandomAccessIterator3 target,
901 const typename std::iterator_traits<typename std::iterator_traits<
902 RandomAccessIteratorIterator>::value_type::first_type>::value_type&
904 _DifferenceTp length, Comparator comp)
906 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
907 ::value_type::first_type
908 RandomAccessIterator1;
909 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
912 return multiway_merge_loser_tree_sentinel<
913 typename __gnu_cxx::__conditional_type<
914 loser_tree_traits<value_type>::use_pointer
915 , LoserTreePointerUnguarded<stable, value_type, Comparator>
916 , LoserTreeUnguarded<stable, value_type, Comparator>
917 >::__type>(seqs_begin, seqs_end, target, sentinel, length, comp);
922 * @brief Switch for k-way merging with sentinels turned off.
926 typename RandomAccessIteratorIterator,
927 typename RandomAccessIterator3,
928 typename _DifferenceTp,
930 struct multiway_merge_k_variant_sentinel_switch
931 <false, stable, RandomAccessIteratorIterator, RandomAccessIterator3,
932 _DifferenceTp, Comparator>
934 RandomAccessIterator3 operator()(
935 RandomAccessIteratorIterator seqs_begin,
936 RandomAccessIteratorIterator seqs_end,
937 RandomAccessIterator3 target,
938 const typename std::iterator_traits<typename std::iterator_traits<
939 RandomAccessIteratorIterator>::value_type::first_type>::value_type&
941 _DifferenceTp length, Comparator comp)
943 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
944 ::value_type::first_type
945 RandomAccessIterator1;
946 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
949 return multiway_merge_loser_tree<
950 typename __gnu_cxx::__conditional_type<
951 loser_tree_traits<value_type>::use_pointer
952 , LoserTreePointer<stable, value_type, Comparator>
953 , LoserTree<stable, value_type, Comparator>
954 >::__type >(seqs_begin, seqs_end, target, length, comp);
958 /** @brief Sequential multi-way merging switch.
960 * The _GLIBCXX_PARALLEL_DECISION is based on the branching factor and
962 * @param seqs_begin Begin iterator of iterator pair input sequence.
963 * @param seqs_end End iterator of iterator pair input sequence.
964 * @param target Begin iterator out output sequence.
965 * @param comp Comparator.
966 * @param length Maximum length to merge, possibly larger than the
967 * number of elements available.
968 * @param stable Stable merging incurs a performance penalty.
969 * @param sentinel The sequences have a sentinel element.
970 * @return End iterator of output sequence. */
974 typename RandomAccessIteratorIterator,
975 typename RandomAccessIterator3,
976 typename _DifferenceTp,
978 RandomAccessIterator3
979 sequential_multiway_merge(
980 RandomAccessIteratorIterator seqs_begin,
981 RandomAccessIteratorIterator seqs_end,
982 RandomAccessIterator3 target,
983 const typename std::iterator_traits<typename std::iterator_traits<
984 RandomAccessIteratorIterator>::value_type::first_type>::value_type&
986 _DifferenceTp length, Comparator comp)
988 _GLIBCXX_CALL(length)
990 typedef _DifferenceTp difference_type;
991 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
992 ::value_type::first_type
993 RandomAccessIterator1;
994 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
997 #if _GLIBCXX_ASSERTIONS
998 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s)
1000 _GLIBCXX_PARALLEL_ASSERT(is_sorted((*s).first, (*s).second, comp));
1004 _DifferenceTp total_length = 0;
1005 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s)
1006 total_length += _GLIBCXX_PARALLEL_LENGTH(*s);
1008 length = std::min<_DifferenceTp>(length, total_length);
1013 RandomAccessIterator3 return_target = target;
1014 int k = static_cast<int>(seqs_end - seqs_begin);
1021 return_target = std::copy(seqs_begin[0].first,
1022 seqs_begin[0].first + length,
1024 seqs_begin[0].first += length;
1027 return_target = merge_advance(seqs_begin[0].first,
1028 seqs_begin[0].second,
1029 seqs_begin[1].first,
1030 seqs_begin[1].second,
1031 target, length, comp);
1034 return_target = multiway_merge_3_variant_sentinel_switch<
1036 , RandomAccessIteratorIterator
1037 , RandomAccessIterator3
1039 , Comparator>()(seqs_begin, seqs_end, target, length, comp);
1042 return_target = multiway_merge_4_variant_sentinel_switch<
1044 , RandomAccessIteratorIterator
1045 , RandomAccessIterator3
1047 , Comparator>()(seqs_begin, seqs_end, target, length, comp);
1050 return_target = multiway_merge_k_variant_sentinel_switch<
1053 , RandomAccessIteratorIterator
1054 , RandomAccessIterator3
1056 , Comparator>()(seqs_begin, seqs_end, target, sentinel, length, comp);
1059 #if _GLIBCXX_ASSERTIONS
1060 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target + length, comp));
1063 return return_target;
1067 * @brief Stable sorting functor.
1069 * Used to reduce code instanciation in multiway_merge_sampling_splitting.
1071 template<bool stable, class RandomAccessIterator, class StrictWeakOrdering>
1072 struct sampling_sorter
1074 void operator()(RandomAccessIterator first, RandomAccessIterator last,
1075 StrictWeakOrdering comp)
1076 { __gnu_sequential::stable_sort(first, last, comp); }
1080 * @brief Non-stable sorting functor.
1082 * Used to reduce code instantiation in multiway_merge_sampling_splitting.
1084 template<class RandomAccessIterator, class StrictWeakOrdering>
1085 struct sampling_sorter<false, RandomAccessIterator, StrictWeakOrdering>
1087 void operator()(RandomAccessIterator first, RandomAccessIterator last,
1088 StrictWeakOrdering comp)
1089 { __gnu_sequential::sort(first, last, comp); }
1093 * @brief Sampling based splitting for parallel multiway-merge routine.
1097 , typename RandomAccessIteratorIterator
1098 , typename Comparator
1099 , typename difference_type>
1100 void multiway_merge_sampling_splitting(
1101 RandomAccessIteratorIterator seqs_begin,
1102 RandomAccessIteratorIterator seqs_end,
1103 difference_type length, difference_type total_length, Comparator comp,
1104 std::vector<std::pair<difference_type, difference_type> > *pieces)
1106 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
1107 ::value_type::first_type
1108 RandomAccessIterator1;
1109 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
1113 int k = static_cast<int>(seqs_end - seqs_begin);
1115 int num_threads = omp_get_num_threads();
1117 difference_type num_samples =
1118 __gnu_parallel::_Settings::get().merge_oversampling * num_threads;
1120 value_type* samples = static_cast<value_type*>(
1121 ::operator new(sizeof(value_type) * k * num_samples));
1123 for (int s = 0; s < k; ++s)
1124 for (difference_type i = 0; i < num_samples; ++i)
1126 difference_type sample_index =
1127 static_cast<difference_type>(
1128 _GLIBCXX_PARALLEL_LENGTH(seqs_begin[s])
1129 * (double(i + 1) / (num_samples + 1))
1130 * (double(length) / total_length));
1131 new(&(samples[s * num_samples + i]))
1132 value_type(seqs_begin[s].first[sample_index]);
1135 // Sort stable or non-stable, depending on value of template parameter
1137 sampling_sorter<stable, value_type*, Comparator>()(
1138 samples, samples + (num_samples * k), comp);
1140 for (int slab = 0; slab < num_threads; ++slab)
1141 // For each slab / processor.
1142 for (int seq = 0; seq < k; ++seq)
1144 // For each sequence.
1146 pieces[slab][seq].first =
1148 seqs_begin[seq].first,
1149 seqs_begin[seq].second,
1150 samples[num_samples * k * slab / num_threads],
1152 - seqs_begin[seq].first;
1154 // Absolute beginning.
1155 pieces[slab][seq].first = 0;
1156 if ((slab + 1) < num_threads)
1157 pieces[slab][seq].second =
1159 seqs_begin[seq].first,
1160 seqs_begin[seq].second,
1161 samples[num_samples * k * (slab + 1) /
1163 - seqs_begin[seq].first;
1166 pieces[slab][seq].second = _GLIBCXX_PARALLEL_LENGTH(seqs_begin[seq]);
1168 ::operator delete(samples);
1172 * @brief Exact splitting for parallel multiway-merge routine.
1174 * None of the passed sequences may be empty.
1178 , typename RandomAccessIteratorIterator
1179 , typename Comparator
1180 , typename difference_type>
1181 void multiway_merge_exact_splitting(
1182 RandomAccessIteratorIterator seqs_begin,
1183 RandomAccessIteratorIterator seqs_end,
1184 difference_type length, difference_type total_length, Comparator comp,
1185 std::vector<std::pair<difference_type, difference_type> > *pieces)
1187 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
1188 ::value_type::first_type
1189 RandomAccessIterator1;
1191 const bool tight = (total_length == length);
1194 const int k = static_cast<int>(seqs_end - seqs_begin);
1196 const int num_threads = omp_get_num_threads();
1198 // (Settings::multiway_merge_splitting == __gnu_parallel::_Settings::EXACT).
1199 std::vector<RandomAccessIterator1>* offsets =
1200 new std::vector<RandomAccessIterator1>[num_threads];
1202 std::pair<RandomAccessIterator1, RandomAccessIterator1>
1205 copy(seqs_begin, seqs_end, se.begin());
1207 difference_type* borders =
1208 new difference_type[num_threads + 1];
1209 equally_split(length, num_threads, borders);
1211 for (int s = 0; s < (num_threads - 1); ++s)
1213 offsets[s].resize(k);
1215 se.begin(), se.end(), borders[s + 1],
1216 offsets[s].begin(), comp);
1218 // Last one also needed and available.
1221 offsets[num_threads - 1].resize(k);
1222 multiseq_partition(se.begin(), se.end(),
1223 difference_type(length),
1224 offsets[num_threads - 1].begin(), comp);
1229 for (int slab = 0; slab < num_threads; ++slab)
1231 // For each slab / processor.
1232 for (int seq = 0; seq < k; ++seq)
1234 // For each sequence.
1237 // Absolute beginning.
1238 pieces[slab][seq].first = 0;
1241 pieces[slab][seq].first =
1242 pieces[slab - 1][seq].second;
1243 if (!tight || slab < (num_threads - 1))
1244 pieces[slab][seq].second =
1245 offsets[slab][seq] - seqs_begin[seq].first;
1248 // slab == num_threads - 1
1249 pieces[slab][seq].second =
1250 _GLIBCXX_PARALLEL_LENGTH(seqs_begin[seq]);
1257 /** @brief Parallel multi-way merge routine.
1259 * The _GLIBCXX_PARALLEL_DECISION is based on the branching factor
1260 * and runtime settings.
1262 * Must not be called if the number of sequences is 1.
1264 * @param Splitter functor to split input (either exact or sampling based)
1266 * @param seqs_begin Begin iterator of iterator pair input sequence.
1267 * @param seqs_end End iterator of iterator pair input sequence.
1268 * @param target Begin iterator out output sequence.
1269 * @param comp Comparator.
1270 * @param length Maximum length to merge, possibly larger than the
1271 * number of elements available.
1272 * @param stable Stable merging incurs a performance penalty.
1273 * @param sentinel Ignored.
1274 * @return End iterator of output sequence.
1279 typename RandomAccessIteratorIterator,
1280 typename RandomAccessIterator3,
1281 typename _DifferenceTp,
1285 RandomAccessIterator3
1286 parallel_multiway_merge(RandomAccessIteratorIterator seqs_begin,
1287 RandomAccessIteratorIterator seqs_end,
1288 RandomAccessIterator3 target,
1290 _DifferenceTp length,
1292 thread_index_t num_threads)
1294 #if _GLIBCXX_ASSERTIONS
1295 _GLIBCXX_PARALLEL_ASSERT(seqs_end - seqs_begin > 1);
1298 _GLIBCXX_CALL(length)
1300 typedef _DifferenceTp difference_type;
1301 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
1302 ::value_type::first_type
1303 RandomAccessIterator1;
1305 std::iterator_traits<RandomAccessIterator1>::value_type value_type;
1307 // Leave only non-empty sequences.
1308 std::pair<RandomAccessIterator1, RandomAccessIterator1>* ne_seqs =
1309 static_cast<std::pair<RandomAccessIterator1, RandomAccessIterator1>*>(
1311 sizeof(std::pair<RandomAccessIterator1, RandomAccessIterator1>)
1312 * (seqs_end - seqs_begin)));
1314 difference_type total_length = 0;
1315 for (RandomAccessIteratorIterator raii = seqs_begin;
1316 raii != seqs_end; ++raii)
1318 _DifferenceTp seq_length = _GLIBCXX_PARALLEL_LENGTH(*raii);
1321 total_length += seq_length;
1322 //ne_seqs[k] = *raii;
1323 new(&(ne_seqs[k++]))
1324 std::pair<RandomAccessIterator1, RandomAccessIterator1>(*raii);
1328 _GLIBCXX_CALL(total_length)
1330 length = std::min<_DifferenceTp>(length, total_length);
1332 if (total_length == 0 || k == 0)
1334 ::operator delete(ne_seqs);
1338 std::vector<std::pair<difference_type, difference_type> >* pieces;
1340 num_threads = static_cast<thread_index_t>
1341 (std::min<difference_type>(num_threads, total_length));
1343 # pragma omp parallel num_threads (num_threads)
1347 num_threads = omp_get_num_threads();
1348 // Thread t will have to merge pieces[iam][0..k - 1]
1349 pieces = new std::vector<
1350 std::pair<difference_type, difference_type> >[num_threads];
1351 for (int s = 0; s < num_threads; ++s)
1352 pieces[s].resize(k);
1354 difference_type num_samples =
1355 __gnu_parallel::_Settings::get().merge_oversampling *
1358 splitter(ne_seqs, ne_seqs + k, length, total_length,
1362 thread_index_t iam = omp_get_thread_num();
1364 difference_type target_position = 0;
1366 for (int c = 0; c < k; ++c)
1367 target_position += pieces[iam][c].first;
1369 std::pair<RandomAccessIterator1, RandomAccessIterator1>* chunks
1370 = new std::pair<RandomAccessIterator1, RandomAccessIterator1>[k];
1372 for (int s = 0; s < k; ++s)
1374 chunks[s] = std::make_pair(
1375 ne_seqs[s].first + pieces[iam][s].first,
1376 ne_seqs[s].first + pieces[iam][s].second);
1379 if(length > target_position)
1380 sequential_multiway_merge<stable, sentinels>(
1381 chunks, chunks + k, target + target_position,
1382 *(seqs_begin->second), length - target_position, comp);
1387 #if _GLIBCXX_ASSERTIONS
1388 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target + length, comp));
1392 // Update ends of sequences.
1393 for (RandomAccessIteratorIterator raii = seqs_begin;
1394 raii != seqs_end; ++raii)
1396 _DifferenceTp length = _GLIBCXX_PARALLEL_LENGTH(*raii);
1398 (*raii).first += pieces[num_threads - 1][k++].second;
1403 return target + length;
1407 * @brief Multiway Merge Frontend.
1409 * Merge the sequences specified by seqs_begin and seqs_end into
1410 * target. seqs_begin and seqs_end must point to a sequence of
1411 * pairs. These pairs must contain an iterator to the beginning
1412 * of a sequence in their first entry and an iterator the end of
1413 * the same sequence in their second entry.
1415 * Ties are broken arbitrarily. See stable_multiway_merge for a variant
1416 * that breaks ties by sequence number but is slower.
1418 * The first entries of the pairs (i.e. the begin iterators) will be moved
1421 * The output sequence has to provide enough space for all elements
1422 * that are written to it.
1424 * This function will merge the input sequences:
1427 * - parallel, depending on the input size and Settings
1428 * - using sampling for splitting
1429 * - not using sentinels
1434 * int sequences[10][10];
1435 * for (int i = 0; i < 10; ++i)
1436 * for (int j = 0; i < 10; ++j)
1437 * sequences[i][j] = j;
1440 * std::vector<std::pair<int*> > seqs;
1441 * for (int i = 0; i < 10; ++i)
1442 * { seqs.push(std::make_pair<int*>(sequences[i], sequences[i] + 10)) }
1444 * multiway_merge(seqs.begin(), seqs.end(), target, std::less<int>(), 33);
1447 * @see stable_multiway_merge
1449 * @pre All input sequences must be sorted.
1450 * @pre Target must provide enough space to merge out length elements or
1451 * the number of elements in all sequences, whichever is smaller.
1453 * @post [target, return value) contains merged elements from the
1455 * @post return value - target = min(length, number of elements in all
1458 * @param RandomAccessIteratorPairIterator iterator over sequence
1459 * of pairs of iterators
1460 * @param RandomAccessIteratorOut iterator over target sequence
1461 * @param _DifferenceTp difference type for the sequence
1462 * @param Comparator strict weak ordering type to compare elements
1465 * @param seqs_begin begin of sequence sequence
1466 * @param seqs_end end of sequence sequence
1467 * @param target target sequence to merge to.
1468 * @param comp strict weak ordering to use for element comparison.
1469 * @param length Maximum length to merge, possibly larger than the
1470 * number of elements available.
1472 * @return end iterator of output sequence
1477 typename RandomAccessIteratorPairIterator
1478 , typename RandomAccessIteratorOut
1479 , typename _DifferenceTp
1480 , typename Comparator>
1481 RandomAccessIteratorOut
1482 multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1483 , RandomAccessIteratorPairIterator seqs_end
1484 , RandomAccessIteratorOut target
1485 , _DifferenceTp length, Comparator comp
1486 , __gnu_parallel::sequential_tag)
1488 typedef _DifferenceTp difference_type;
1489 _GLIBCXX_CALL(seqs_end - seqs_begin)
1491 // catch special case: no sequences
1492 if (seqs_begin == seqs_end)
1495 // Execute multiway merge *sequentially*.
1496 return sequential_multiway_merge
1497 </* stable = */ false, /* sentinels = */ false>
1498 (seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp);
1503 typename RandomAccessIteratorPairIterator
1504 , typename RandomAccessIteratorOut
1505 , typename _DifferenceTp
1506 , typename Comparator>
1507 RandomAccessIteratorOut
1508 multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1509 , RandomAccessIteratorPairIterator seqs_end
1510 , RandomAccessIteratorOut target
1511 , _DifferenceTp length, Comparator comp
1512 , __gnu_parallel::exact_tag tag)
1514 typedef _DifferenceTp difference_type;
1515 _GLIBCXX_CALL(seqs_end - seqs_begin)
1517 // catch special case: no sequences
1518 if (seqs_begin == seqs_end)
1521 // Execute merge; maybe parallel, depending on the number of merged
1522 // elements and the number of sequences and global thresholds in
1524 if ((seqs_end - seqs_begin > 1) &&
1525 _GLIBCXX_PARALLEL_CONDITION(
1526 ((seqs_end - seqs_begin) >=
1527 __gnu_parallel::_Settings::get().multiway_merge_minimal_k)
1528 && ((sequence_index_t)length >=
1529 __gnu_parallel::_Settings::get().multiway_merge_minimal_n)))
1530 return parallel_multiway_merge
1531 </* stable = */ false, /* sentinels = */ false>(
1532 seqs_begin, seqs_end, target,
1533 multiway_merge_exact_splitting</* stable = */ false,
1534 typename std::iterator_traits<RandomAccessIteratorPairIterator>
1535 ::value_type*, Comparator, _DifferenceTp>,
1536 static_cast<difference_type>(length), comp, tag.get_num_threads());
1538 return sequential_multiway_merge
1539 </* stable = */ false, /* sentinels = */ false>(
1540 seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp);
1545 typename RandomAccessIteratorPairIterator
1546 , typename RandomAccessIteratorOut
1547 , typename _DifferenceTp
1548 , typename Comparator>
1549 RandomAccessIteratorOut
1550 multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1551 , RandomAccessIteratorPairIterator seqs_end
1552 , RandomAccessIteratorOut target
1553 , _DifferenceTp length, Comparator comp
1554 , __gnu_parallel::sampling_tag tag)
1556 typedef _DifferenceTp difference_type;
1557 _GLIBCXX_CALL(seqs_end - seqs_begin)
1559 // catch special case: no sequences
1560 if (seqs_begin == seqs_end)
1563 // Execute merge; maybe parallel, depending on the number of merged
1564 // elements and the number of sequences and global thresholds in
1566 if ((seqs_end - seqs_begin > 1) &&
1567 _GLIBCXX_PARALLEL_CONDITION(
1568 ((seqs_end - seqs_begin) >=
1569 __gnu_parallel::_Settings::get().multiway_merge_minimal_k)
1570 && ((sequence_index_t)length >=
1571 __gnu_parallel::_Settings::get().multiway_merge_minimal_n)))
1572 return parallel_multiway_merge
1573 </* stable = */ false, /* sentinels = */ false>(
1574 seqs_begin, seqs_end,
1576 multiway_merge_exact_splitting</* stable = */ false,
1577 typename std::iterator_traits<RandomAccessIteratorPairIterator>
1578 ::value_type*, Comparator, _DifferenceTp>,
1579 static_cast<difference_type>(length), comp, tag.get_num_threads());
1581 return sequential_multiway_merge
1582 </* stable = */ false, /* sentinels = */ false>(
1583 seqs_begin, seqs_end,
1584 target, *(seqs_begin->second), length, comp);
1589 typename RandomAccessIteratorPairIterator
1590 , typename RandomAccessIteratorOut
1591 , typename _DifferenceTp
1592 , typename Comparator>
1593 RandomAccessIteratorOut
1594 multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1595 , RandomAccessIteratorPairIterator seqs_end
1596 , RandomAccessIteratorOut target
1597 , _DifferenceTp length, Comparator comp
1598 , parallel_tag tag = parallel_tag(0))
1600 return multiway_merge(seqs_begin, seqs_end, target, length, comp,
1601 exact_tag(tag.get_num_threads()));
1606 typename RandomAccessIteratorPairIterator
1607 , typename RandomAccessIteratorOut
1608 , typename _DifferenceTp
1609 , typename Comparator>
1610 RandomAccessIteratorOut
1611 multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1612 , RandomAccessIteratorPairIterator seqs_end
1613 , RandomAccessIteratorOut target
1614 , _DifferenceTp length, Comparator comp
1615 , default_parallel_tag tag)
1617 return multiway_merge(seqs_begin, seqs_end, target, length, comp,
1618 exact_tag(tag.get_num_threads()));
1621 // stable_multiway_merge
1624 typename RandomAccessIteratorPairIterator
1625 , typename RandomAccessIteratorOut
1626 , typename _DifferenceTp
1627 , typename Comparator>
1628 RandomAccessIteratorOut
1629 stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1630 , RandomAccessIteratorPairIterator seqs_end
1631 , RandomAccessIteratorOut target
1632 , _DifferenceTp length, Comparator comp
1633 , __gnu_parallel::sequential_tag)
1635 typedef _DifferenceTp difference_type;
1636 _GLIBCXX_CALL(seqs_end - seqs_begin)
1638 // catch special case: no sequences
1639 if (seqs_begin == seqs_end)
1642 // Execute multiway merge *sequentially*.
1643 return sequential_multiway_merge
1644 </* stable = */ true, /* sentinels = */ false>
1645 (seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp);
1650 typename RandomAccessIteratorPairIterator
1651 , typename RandomAccessIteratorOut
1652 , typename _DifferenceTp
1653 , typename Comparator>
1654 RandomAccessIteratorOut
1655 stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1656 , RandomAccessIteratorPairIterator seqs_end
1657 , RandomAccessIteratorOut target
1658 , _DifferenceTp length, Comparator comp
1659 , __gnu_parallel::exact_tag tag)
1661 typedef _DifferenceTp difference_type;
1662 _GLIBCXX_CALL(seqs_end - seqs_begin)
1664 // catch special case: no sequences
1665 if (seqs_begin == seqs_end)
1668 // Execute merge; maybe parallel, depending on the number of merged
1669 // elements and the number of sequences and global thresholds in
1671 if ((seqs_end - seqs_begin > 1) &&
1672 _GLIBCXX_PARALLEL_CONDITION(
1673 ((seqs_end - seqs_begin) >=
1674 __gnu_parallel::_Settings::get().multiway_merge_minimal_k)
1675 && ((sequence_index_t)length >=
1676 __gnu_parallel::_Settings::get().multiway_merge_minimal_n)))
1677 return parallel_multiway_merge
1678 </* stable = */ true, /* sentinels = */ false>(
1679 seqs_begin, seqs_end,
1681 multiway_merge_exact_splitting</* stable = */ true,
1682 typename std::iterator_traits<RandomAccessIteratorPairIterator>
1683 ::value_type*, Comparator, _DifferenceTp>,
1684 static_cast<difference_type>(length), comp, tag.get_num_threads());
1686 return sequential_multiway_merge</* stable = */ true,
1687 /* sentinels = */ false>(
1688 seqs_begin, seqs_end,
1689 target, *(seqs_begin->second), length, comp);
1694 typename RandomAccessIteratorPairIterator
1695 , typename RandomAccessIteratorOut
1696 , typename _DifferenceTp
1697 , typename Comparator>
1698 RandomAccessIteratorOut
1699 stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1700 , RandomAccessIteratorPairIterator seqs_end
1701 , RandomAccessIteratorOut target
1702 , _DifferenceTp length, Comparator comp
1705 typedef _DifferenceTp difference_type;
1706 _GLIBCXX_CALL(seqs_end - seqs_begin)
1708 // catch special case: no sequences
1709 if (seqs_begin == seqs_end)
1712 // Execute merge; maybe parallel, depending on the number of merged
1713 // elements and the number of sequences and global thresholds in
1715 if ((seqs_end - seqs_begin > 1) &&
1716 _GLIBCXX_PARALLEL_CONDITION(
1717 ((seqs_end - seqs_begin) >=
1718 __gnu_parallel::_Settings::get().multiway_merge_minimal_k)
1719 && ((sequence_index_t)length >=
1720 __gnu_parallel::_Settings::get().multiway_merge_minimal_n)))
1721 return parallel_multiway_merge
1722 </* stable = */ true, /* sentinels = */ false>(
1723 seqs_begin, seqs_end,
1725 multiway_merge_sampling_splitting</* stable = */ true,
1726 typename std::iterator_traits<RandomAccessIteratorPairIterator>
1727 ::value_type*, Comparator, _DifferenceTp>,
1728 static_cast<difference_type>(length), comp, tag.get_num_threads());
1730 return sequential_multiway_merge
1731 </* stable = */ true, /* sentinels = */ false>(
1732 seqs_begin, seqs_end,
1733 target, *(seqs_begin->second), length, comp);
1739 typename RandomAccessIteratorPairIterator
1740 , typename RandomAccessIteratorOut
1741 , typename _DifferenceTp
1742 , typename Comparator>
1743 RandomAccessIteratorOut
1744 stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1745 , RandomAccessIteratorPairIterator seqs_end
1746 , RandomAccessIteratorOut target
1747 , _DifferenceTp length, Comparator comp
1748 , parallel_tag tag = parallel_tag(0))
1750 return stable_multiway_merge(seqs_begin, seqs_end, target, length, comp,
1751 exact_tag(tag.get_num_threads()));
1756 typename RandomAccessIteratorPairIterator
1757 , typename RandomAccessIteratorOut
1758 , typename _DifferenceTp
1759 , typename Comparator>
1760 RandomAccessIteratorOut
1761 stable_multiway_merge(RandomAccessIteratorPairIterator seqs_begin
1762 , RandomAccessIteratorPairIterator seqs_end
1763 , RandomAccessIteratorOut target
1764 , _DifferenceTp length, Comparator comp
1765 , default_parallel_tag tag)
1767 return stable_multiway_merge(seqs_begin, seqs_end, target, length, comp,
1768 exact_tag(tag.get_num_threads()));
1772 * @brief Multiway Merge Frontend.
1774 * Merge the sequences specified by seqs_begin and seqs_end into
1775 * target. seqs_begin and seqs_end must point to a sequence of
1776 * pairs. These pairs must contain an iterator to the beginning
1777 * of a sequence in their first entry and an iterator the end of
1778 * the same sequence in their second entry.
1780 * Ties are broken arbitrarily. See stable_multiway_merge for a variant
1781 * that breaks ties by sequence number but is slower.
1783 * The first entries of the pairs (i.e. the begin iterators) will be moved
1784 * forward accordingly.
1786 * The output sequence has to provide enough space for all elements
1787 * that are written to it.
1789 * This function will merge the input sequences:
1792 * - parallel, depending on the input size and Settings
1793 * - using sampling for splitting
1796 * You have to take care that the element the end iterator points to is
1797 * readable and contains a value that is greater than any other non-sentinel
1798 * value in all sequences.
1803 * int sequences[10][11];
1804 * for (int i = 0; i < 10; ++i)
1805 * for (int j = 0; i < 11; ++j)
1806 * sequences[i][j] = j; // last one is sentinel!
1809 * std::vector<std::pair<int*> > seqs;
1810 * for (int i = 0; i < 10; ++i)
1811 * { seqs.push(std::make_pair<int*>(sequences[i], sequences[i] + 10)) }
1813 * multiway_merge(seqs.begin(), seqs.end(), target, std::less<int>(), 33);
1816 * @pre All input sequences must be sorted.
1817 * @pre Target must provide enough space to merge out length elements or
1818 * the number of elements in all sequences, whichever is smaller.
1819 * @pre For each @c i, @c seqs_begin[i].second must be the end
1820 * marker of the sequence, but also reference the one more sentinel
1823 * @post [target, return value) contains merged elements from the
1825 * @post return value - target = min(length, number of elements in all
1828 * @see stable_multiway_merge_sentinels
1830 * @param RandomAccessIteratorPairIterator iterator over sequence
1831 * of pairs of iterators
1832 * @param RandomAccessIteratorOut iterator over target sequence
1833 * @param _DifferenceTp difference type for the sequence
1834 * @param Comparator strict weak ordering type to compare elements
1837 * @param seqs_begin begin of sequence sequence
1838 * @param seqs_end end of sequence sequence
1839 * @param target target sequence to merge to.
1840 * @param comp strict weak ordering to use for element comparison.
1841 * @param length Maximum length to merge, possibly larger than the
1842 * number of elements available.
1844 * @return end iterator of output sequence
1846 // multiway_merge_sentinels
1849 typename RandomAccessIteratorPairIterator
1850 , typename RandomAccessIteratorOut
1851 , typename _DifferenceTp
1852 , typename Comparator>
1853 RandomAccessIteratorOut
1854 multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
1855 , RandomAccessIteratorPairIterator seqs_end
1856 , RandomAccessIteratorOut target
1857 , _DifferenceTp length, Comparator comp
1858 , __gnu_parallel::sequential_tag)
1860 typedef _DifferenceTp difference_type;
1861 _GLIBCXX_CALL(seqs_end - seqs_begin)
1863 // catch special case: no sequences
1864 if (seqs_begin == seqs_end)
1867 // Execute multiway merge *sequentially*.
1868 return sequential_multiway_merge
1869 </* stable = */ false, /* sentinels = */ true>
1870 (seqs_begin, seqs_end,
1871 target, *(seqs_begin->second), length, comp);
1876 typename RandomAccessIteratorPairIterator
1877 , typename RandomAccessIteratorOut
1878 , typename _DifferenceTp
1879 , typename Comparator>
1880 RandomAccessIteratorOut
1881 multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
1882 , RandomAccessIteratorPairIterator seqs_end
1883 , RandomAccessIteratorOut target
1884 , _DifferenceTp length, Comparator comp
1885 , __gnu_parallel::exact_tag tag)
1887 typedef _DifferenceTp difference_type;
1888 _GLIBCXX_CALL(seqs_end - seqs_begin)
1890 // catch special case: no sequences
1891 if (seqs_begin == seqs_end)
1894 // Execute merge; maybe parallel, depending on the number of merged
1895 // elements and the number of sequences and global thresholds in
1897 if ((seqs_end - seqs_begin > 1) &&
1898 _GLIBCXX_PARALLEL_CONDITION(
1899 ((seqs_end - seqs_begin) >=
1900 __gnu_parallel::_Settings::get().multiway_merge_minimal_k)
1901 && ((sequence_index_t)length >=
1902 __gnu_parallel::_Settings::get().multiway_merge_minimal_n)))
1903 return parallel_multiway_merge
1904 </* stable = */ false, /* sentinels = */ true>(
1905 seqs_begin, seqs_end,
1907 multiway_merge_exact_splitting</* stable = */ false,
1908 typename std::iterator_traits<RandomAccessIteratorPairIterator>
1909 ::value_type*, Comparator, _DifferenceTp>,
1910 static_cast<difference_type>(length), comp, tag.get_num_threads());
1912 return sequential_multiway_merge
1913 </* stable = */ false, /* sentinels = */ true>(
1914 seqs_begin, seqs_end,
1915 target, *(seqs_begin->second), length, comp);
1920 typename RandomAccessIteratorPairIterator
1921 , typename RandomAccessIteratorOut
1922 , typename _DifferenceTp
1923 , typename Comparator>
1924 RandomAccessIteratorOut
1925 multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
1926 , RandomAccessIteratorPairIterator seqs_end
1927 , RandomAccessIteratorOut target
1928 , _DifferenceTp length, Comparator comp
1931 typedef _DifferenceTp difference_type;
1932 _GLIBCXX_CALL(seqs_end - seqs_begin)
1934 // catch special case: no sequences
1935 if (seqs_begin == seqs_end)
1938 // Execute merge; maybe parallel, depending on the number of merged
1939 // elements and the number of sequences and global thresholds in
1941 if ((seqs_end - seqs_begin > 1) &&
1942 _GLIBCXX_PARALLEL_CONDITION(
1943 ((seqs_end - seqs_begin) >=
1944 __gnu_parallel::_Settings::get().multiway_merge_minimal_k)
1945 && ((sequence_index_t)length >=
1946 __gnu_parallel::_Settings::get().multiway_merge_minimal_n)))
1947 return parallel_multiway_merge
1948 </* stable = */ false, /* sentinels = */ true>
1949 (seqs_begin, seqs_end, target,
1950 multiway_merge_sampling_splitting</* stable = */ false,
1951 typename std::iterator_traits<RandomAccessIteratorPairIterator>
1952 ::value_type*, Comparator, _DifferenceTp>,
1953 static_cast<difference_type>(length), comp, tag.get_num_threads());
1955 return sequential_multiway_merge
1956 </* stable = */false, /* sentinels = */ true>(
1957 seqs_begin, seqs_end,
1958 target, *(seqs_begin->second), length, comp);
1963 typename RandomAccessIteratorPairIterator
1964 , typename RandomAccessIteratorOut
1965 , typename _DifferenceTp
1966 , typename Comparator>
1967 RandomAccessIteratorOut
1968 multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
1969 , RandomAccessIteratorPairIterator seqs_end
1970 , RandomAccessIteratorOut target
1971 , _DifferenceTp length, Comparator comp
1972 , parallel_tag tag = parallel_tag(0))
1974 return multiway_merge_sentinels(seqs_begin, seqs_end, target, length, comp,
1975 exact_tag(tag.get_num_threads()));
1980 typename RandomAccessIteratorPairIterator
1981 , typename RandomAccessIteratorOut
1982 , typename _DifferenceTp
1983 , typename Comparator>
1984 RandomAccessIteratorOut
1985 multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
1986 , RandomAccessIteratorPairIterator seqs_end
1987 , RandomAccessIteratorOut target
1988 , _DifferenceTp length, Comparator comp
1989 , default_parallel_tag tag)
1991 return multiway_merge_sentinels(seqs_begin, seqs_end, target, length, comp,
1992 exact_tag(tag.get_num_threads()));
1995 // stable_multiway_merge_sentinels
1998 typename RandomAccessIteratorPairIterator
1999 , typename RandomAccessIteratorOut
2000 , typename _DifferenceTp
2001 , typename Comparator>
2002 RandomAccessIteratorOut
2003 stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
2004 , RandomAccessIteratorPairIterator seqs_end
2005 , RandomAccessIteratorOut target
2006 , _DifferenceTp length, Comparator comp
2007 , __gnu_parallel::sequential_tag)
2009 typedef _DifferenceTp difference_type;
2010 _GLIBCXX_CALL(seqs_end - seqs_begin)
2012 // catch special case: no sequences
2013 if (seqs_begin == seqs_end)
2016 // Execute multiway merge *sequentially*.
2017 return sequential_multiway_merge
2018 </* stable = */ true, /* sentinels = */ true>
2019 (seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp);
2024 typename RandomAccessIteratorPairIterator
2025 , typename RandomAccessIteratorOut
2026 , typename _DifferenceTp
2027 , typename Comparator>
2028 RandomAccessIteratorOut
2029 stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
2030 , RandomAccessIteratorPairIterator seqs_end
2031 , RandomAccessIteratorOut target
2032 , _DifferenceTp length, Comparator comp
2033 , __gnu_parallel::exact_tag tag)
2035 typedef _DifferenceTp difference_type;
2036 _GLIBCXX_CALL(seqs_end - seqs_begin)
2038 // catch special case: no sequences
2039 if (seqs_begin == seqs_end)
2042 // Execute merge; maybe parallel, depending on the number of merged
2043 // elements and the number of sequences and global thresholds in
2045 if ((seqs_end - seqs_begin > 1) &&
2046 _GLIBCXX_PARALLEL_CONDITION(
2047 ((seqs_end - seqs_begin) >=
2048 __gnu_parallel::_Settings::get().multiway_merge_minimal_k)
2049 && ((sequence_index_t)length >=
2050 __gnu_parallel::_Settings::get().multiway_merge_minimal_n)))
2051 return parallel_multiway_merge
2052 </* stable = */ true, /* sentinels = */ true>(
2053 seqs_begin, seqs_end,
2055 multiway_merge_exact_splitting</* stable = */ true,
2056 typename std::iterator_traits<RandomAccessIteratorPairIterator>
2057 ::value_type*, Comparator, _DifferenceTp>,
2058 static_cast<difference_type>(length), comp, tag.get_num_threads());
2060 return sequential_multiway_merge
2061 </* stable = */ true, /* sentinels = */ true>(
2062 seqs_begin, seqs_end, target, *(seqs_begin->second), length, comp);
2067 typename RandomAccessIteratorPairIterator
2068 , typename RandomAccessIteratorOut
2069 , typename _DifferenceTp
2070 , typename Comparator>
2071 RandomAccessIteratorOut
2072 stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
2073 , RandomAccessIteratorPairIterator seqs_end
2074 , RandomAccessIteratorOut target
2075 , _DifferenceTp length, Comparator comp
2078 typedef _DifferenceTp difference_type;
2079 _GLIBCXX_CALL(seqs_end - seqs_begin)
2081 // catch special case: no sequences
2082 if (seqs_begin == seqs_end)
2085 // Execute merge; maybe parallel, depending on the number of merged
2086 // elements and the number of sequences and global thresholds in
2088 if ((seqs_end - seqs_begin > 1) &&
2089 _GLIBCXX_PARALLEL_CONDITION(
2090 ((seqs_end - seqs_begin) >=
2091 __gnu_parallel::_Settings::get().multiway_merge_minimal_k)
2092 && ((sequence_index_t)length >=
2093 __gnu_parallel::_Settings::get().multiway_merge_minimal_n)))
2094 return parallel_multiway_merge
2095 </* stable = */ true, /* sentinels = */ true>(
2096 seqs_begin, seqs_end,
2098 multiway_merge_sampling_splitting</* stable = */ true,
2099 typename std::iterator_traits<RandomAccessIteratorPairIterator>
2100 ::value_type*, Comparator, _DifferenceTp>,
2101 static_cast<difference_type>(length), comp, tag.get_num_threads());
2103 return sequential_multiway_merge
2104 </* stable = */ true, /* sentinels = */ true>(
2105 seqs_begin, seqs_end,
2106 target, *(seqs_begin->second), length, comp);
2111 typename RandomAccessIteratorPairIterator
2112 , typename RandomAccessIteratorOut
2113 , typename _DifferenceTp
2114 , typename Comparator>
2115 RandomAccessIteratorOut
2116 stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
2117 , RandomAccessIteratorPairIterator seqs_end
2118 , RandomAccessIteratorOut target
2119 , _DifferenceTp length, Comparator comp
2120 , parallel_tag tag = parallel_tag(0))
2122 return stable_multiway_merge_sentinels(seqs_begin, seqs_end, target, length, comp,
2123 exact_tag(tag.get_num_threads()));
2128 typename RandomAccessIteratorPairIterator
2129 , typename RandomAccessIteratorOut
2130 , typename _DifferenceTp
2131 , typename Comparator>
2132 RandomAccessIteratorOut
2133 stable_multiway_merge_sentinels(RandomAccessIteratorPairIterator seqs_begin
2134 , RandomAccessIteratorPairIterator seqs_end
2135 , RandomAccessIteratorOut target
2136 , _DifferenceTp length, Comparator comp
2137 , default_parallel_tag tag)
2139 return stable_multiway_merge_sentinels(seqs_begin, seqs_end, target, length, comp,
2140 exact_tag(tag.get_num_threads()));
2143 }; // namespace __gnu_parallel
2145 #endif /* _GLIBCXX_PARALLEL_MULTIWAY_MERGE_H */