3 // Copyright (C) 2007 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 2, 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 // You should have received a copy of the GNU General Public License
17 // along with this library; see the file COPYING. If not, write to
18 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
19 // MA 02111-1307, USA.
21 // As a special exception, you may use this file as part of a free
22 // software library without restriction. Specifically, if other files
23 // instantiate templates or use macros or inline functions from this
24 // file, or you compile this file and link it with other files to
25 // produce an executable, this file does not by itself cause the
26 // resulting executable to be covered by the GNU General Public
27 // License. This exception does not however invalidate any other
28 // reasons why the executable file might be covered by the GNU General
31 /** @file parallel/multiway_merge.h
32 * @brief Implementation of sequential and parallel multiway merge.
34 * Explanations on the high-speed merging routines in the appendix of
37 * Fast priority queues for cached memory.
38 * ACM Journal of Experimental Algorithmics, 5, 2000.
40 * This file is a GNU parallel extension to the Standard C++ Library.
43 // Written by Johannes Singler.
45 #ifndef _GLIBCXX_PARALLEL_MULTIWAY_MERGE_H
46 #define _GLIBCXX_PARALLEL_MULTIWAY_MERGE_H
50 #include <bits/stl_algo.h>
51 #include <parallel/features.h>
52 #include <parallel/parallel.h>
53 #include <parallel/merge.h>
54 #include <parallel/losertree.h>
55 #if _GLIBCXX_ASSERTIONS
56 #include <parallel/checkers.h>
59 /** @brief Length of a sequence described by a pair of iterators. */
60 #define LENGTH(s) ((s).second - (s).first)
62 // XXX need iterator typedefs
63 namespace __gnu_parallel
65 template<typename RandomAccessIterator, typename Comparator>
66 class guarded_iterator;
68 template<typename RandomAccessIterator, typename Comparator>
70 operator<(guarded_iterator<RandomAccessIterator, Comparator>& bi1,
71 guarded_iterator<RandomAccessIterator, Comparator>& bi2);
73 template<typename RandomAccessIterator, typename Comparator>
75 operator<=(guarded_iterator<RandomAccessIterator, Comparator>& bi1,
76 guarded_iterator<RandomAccessIterator, Comparator>& bi2);
78 /** @brief Iterator wrapper supporting an implicit supremum at the end
79 of the sequence, dominating all comparisons.
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 inline guarded_iterator(RandomAccessIterator begin,
103 RandomAccessIterator end, Comparator& comp)
104 : current(begin), end(end), comp(comp)
107 /** @brief Pre-increment operator.
109 inline guarded_iterator<RandomAccessIterator, Comparator>&
116 /** @brief Dereference operator.
117 * @return Referenced element. */
118 inline typename std::iterator_traits<RandomAccessIterator>::value_type
122 /** @brief Convert to wrapped iterator.
123 * @return Wrapped iterator. */
124 inline 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 inline unguarded_iterator(RandomAccessIterator begin,
198 RandomAccessIterator end, Comparator& comp)
199 : current(begin), comp(comp)
202 /** @brief Pre-increment operator.
204 inline unguarded_iterator<RandomAccessIterator, Comparator>&
211 /** @brief Dereference operator.
212 * @return Referenced element. */
213 inline typename std::iterator_traits<RandomAccessIterator>::value_type
217 /** @brief Convert to wrapped iterator.
218 * @return Wrapped iterator. */
220 operator RandomAccessIterator()
224 operator< <RandomAccessIterator, Comparator>(
225 unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
226 unguarded_iterator<RandomAccessIterator, Comparator>& bi2);
229 operator<= <RandomAccessIterator, Comparator>(
230 unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
231 unguarded_iterator<RandomAccessIterator, Comparator>& bi2);
234 /** @brief Compare two elements referenced by unguarded iterators.
235 * @param bi1 First iterator.
236 * @param bi2 Second iterator.
237 * @return @c True if less. */
238 template<typename RandomAccessIterator, typename Comparator>
240 operator<(unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
241 unguarded_iterator<RandomAccessIterator, Comparator>& bi2)
244 return (bi1.comp)(*bi1, *bi2);
247 /** @brief Compare two elements referenced by unguarded iterators.
248 * @param bi1 First iterator.
249 * @param bi2 Second iterator.
250 * @return @c True if less equal. */
251 template<typename RandomAccessIterator, typename Comparator>
253 operator<=(unguarded_iterator<RandomAccessIterator, Comparator>& bi1,
254 unguarded_iterator<RandomAccessIterator, Comparator>& bi2)
257 return !(bi1.comp)(*bi2, *bi1);
260 /** Prepare a set of sequences to be merged without a (end) guard
264 * @param min_sequence
266 * @pre (seqs_end - seqs_begin > 0) */
267 template<typename RandomAccessIteratorIterator, typename Comparator>
268 typename std::iterator_traits<
269 typename std::iterator_traits<RandomAccessIteratorIterator>::value_type
270 ::first_type>::difference_type
271 prepare_unguarded(RandomAccessIteratorIterator seqs_begin,
272 RandomAccessIteratorIterator seqs_end, Comparator comp,
273 int& min_sequence, bool stable)
275 _GLIBCXX_CALL(seqs_end - seqs_begin)
277 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
278 ::value_type::first_type
279 RandomAccessIterator1;
280 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
282 typedef typename std::iterator_traits<RandomAccessIterator1>
286 if ((*seqs_begin).first == (*seqs_begin).second)
288 // Empty sequence found, it's the first one.
293 // Last element in sequence.
294 value_type min = *((*seqs_begin).second - 1);
296 for (RandomAccessIteratorIterator s = seqs_begin + 1; s != seqs_end; s++)
298 if ((*s).first == (*s).second)
300 // Empty sequence found.
301 min_sequence = static_cast<int>(s - seqs_begin);
305 // Last element in sequence.
306 const value_type& v = *((*s).second - 1);
307 if (comp(v, min)) //strictly smaller
310 min_sequence = static_cast<int>(s - seqs_begin);
314 difference_type overhang_size = 0;
317 for (s = 0; s <= min_sequence; s++)
319 RandomAccessIterator1 split;
321 split = std::upper_bound(seqs_begin[s].first, seqs_begin[s].second,
324 split = std::lower_bound(seqs_begin[s].first, seqs_begin[s].second,
327 overhang_size += seqs_begin[s].second - split;
330 for (; s < (seqs_end - seqs_begin); s++)
332 RandomAccessIterator1 split = std::lower_bound(
333 seqs_begin[s].first, seqs_begin[s].second, min, comp);
334 overhang_size += seqs_begin[s].second - split;
337 // So many elements will be left over afterwards.
338 return overhang_size;
341 /** Prepare a set of sequences to be merged with a (end) guard (sentinel)
345 template<typename RandomAccessIteratorIterator, typename Comparator>
346 typename std::iterator_traits<typename std::iterator_traits<
347 RandomAccessIteratorIterator>::value_type::first_type>::difference_type
348 prepare_unguarded_sentinel(RandomAccessIteratorIterator seqs_begin,
349 RandomAccessIteratorIterator seqs_end,
352 _GLIBCXX_CALL(seqs_end - seqs_begin)
354 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
355 ::value_type::first_type
356 RandomAccessIterator1;
357 typedef typename std::iterator_traits<RandomAccessIterator1>
360 typedef typename std::iterator_traits<RandomAccessIterator1>
364 // Last element in sequence.
365 value_type* max = NULL;
366 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; s++)
368 if ((*s).first == (*s).second)
371 // Last element in sequence.
372 value_type& v = *((*s).second - 1);
375 if (!max || comp(*max, v))
379 difference_type overhang_size = 0;
380 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; s++)
382 RandomAccessIterator1 split =
383 std::lower_bound((*s).first, (*s).second, *max, comp);
384 overhang_size += (*s).second - split;
387 *((*s).second) = *max;
390 // So many elements will be left over afterwards.
391 return overhang_size;
394 /** @brief Highly efficient 3-way merging procedure.
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.
400 * @param stable Unused, stable anyway.
401 * @return End iterator of output sequence. */
403 template<typename RAI, typename C> class iterator,
404 typename RandomAccessIteratorIterator,
405 typename RandomAccessIterator3,
406 typename _DifferenceTp,
408 RandomAccessIterator3
409 multiway_merge_3_variant(
410 RandomAccessIteratorIterator seqs_begin,
411 RandomAccessIteratorIterator seqs_end,
412 RandomAccessIterator3 target,
413 Comparator comp, _DifferenceTp length, bool stable)
415 _GLIBCXX_CALL(length);
417 typedef _DifferenceTp difference_type;
419 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
420 ::value_type::first_type
421 RandomAccessIterator1;
422 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
428 iterator<RandomAccessIterator1, Comparator>
429 seq0(seqs_begin[0].first, seqs_begin[0].second, comp),
430 seq1(seqs_begin[1].first, seqs_begin[1].second, comp),
431 seq2(seqs_begin[2].first, seqs_begin[2].second, comp);
456 #define Merge3Case(a,b,c,c0,c1) \
458 *target = *seq ## a; \
462 if (length == 0) goto finish; \
463 if (seq ## a c0 seq ## b) goto s ## a ## b ## c; \
464 if (seq ## a c1 seq ## c) goto s ## b ## a ## c; \
465 goto s ## b ## c ## a;
467 Merge3Case(0, 1, 2, <=, <=);
468 Merge3Case(1, 2, 0, <=, < );
469 Merge3Case(2, 0, 1, < , < );
470 Merge3Case(1, 0, 2, < , <=);
471 Merge3Case(0, 2, 1, <=, <=);
472 Merge3Case(2, 1, 0, < , < );
479 seqs_begin[0].first = seq0;
480 seqs_begin[1].first = seq1;
481 seqs_begin[2].first = seq2;
487 typename RandomAccessIteratorIterator,
488 typename RandomAccessIterator3,
489 typename _DifferenceTp,
491 RandomAccessIterator3
492 multiway_merge_3_combined(RandomAccessIteratorIterator seqs_begin,
493 RandomAccessIteratorIterator seqs_end,
494 RandomAccessIterator3 target,
496 _DifferenceTp length, bool stable)
498 _GLIBCXX_CALL(length);
500 typedef _DifferenceTp difference_type;
501 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
502 ::value_type::first_type
503 RandomAccessIterator1;
504 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
508 RandomAccessIterator3 target_end;
511 difference_type overhang =
512 prepare_unguarded(seqs_begin, seqs_end, comp, min_seq, true);
514 difference_type total_length = 0;
515 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s)
516 total_length += LENGTH(*s);
520 difference_type unguarded_length =
521 std::min(length, total_length - overhang);
522 target_end = multiway_merge_3_variant<unguarded_iterator>
523 (seqs_begin, seqs_end, target, comp, unguarded_length, stable);
524 overhang = length - unguarded_length;
528 // Empty sequence found.
533 #if _GLIBCXX_ASSERTIONS
534 _GLIBCXX_PARALLEL_ASSERT(target_end == target + length - overhang);
535 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp));
541 // Iterators will be advanced accordingly.
542 target_end = merge_advance(seqs_begin[1].first, seqs_begin[1].second,
543 seqs_begin[2].first, seqs_begin[2].second,
544 target_end, overhang, comp);
547 target_end = merge_advance(seqs_begin[0].first, seqs_begin[0].second,
548 seqs_begin[2].first, seqs_begin[2].second,
549 target_end, overhang, comp);
552 target_end = merge_advance(seqs_begin[0].first, seqs_begin[0].second,
553 seqs_begin[1].first, seqs_begin[1].second,
554 target_end, overhang, comp);
557 _GLIBCXX_PARALLEL_ASSERT(false);
560 #if _GLIBCXX_ASSERTIONS
561 _GLIBCXX_PARALLEL_ASSERT(target_end == target + length);
562 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp));
568 /** @brief Highly efficient 4-way merging procedure.
569 * @param seqs_begin Begin iterator of iterator pair input sequence.
570 * @param seqs_end End iterator of iterator pair input sequence.
571 * @param target Begin iterator out output sequence.
572 * @param comp Comparator.
573 * @param length Maximum length to merge.
574 * @param stable Unused, stable anyway.
575 * @return End iterator of output sequence. */
577 template<typename RAI, typename C> class iterator,
578 typename RandomAccessIteratorIterator,
579 typename RandomAccessIterator3,
580 typename _DifferenceTp,
582 RandomAccessIterator3
583 multiway_merge_4_variant(RandomAccessIteratorIterator seqs_begin,
584 RandomAccessIteratorIterator seqs_end,
585 RandomAccessIterator3 target,
586 Comparator comp, _DifferenceTp length, bool stable)
588 _GLIBCXX_CALL(length);
589 typedef _DifferenceTp difference_type;
591 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
592 ::value_type::first_type
593 RandomAccessIterator1;
594 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
597 iterator<RandomAccessIterator1, Comparator>
598 seq0(seqs_begin[0].first, seqs_begin[0].second, comp),
599 seq1(seqs_begin[1].first, seqs_begin[1].second, comp),
600 seq2(seqs_begin[2].first, seqs_begin[2].second, comp),
601 seq3(seqs_begin[3].first, seqs_begin[3].second, comp);
603 #define Decision(a,b,c,d) { \
604 if (seq ## d < seq ## a) goto s ## d ## a ## b ## c; \
605 if (seq ## d < seq ## b) goto s ## a ## d ## b ## c; \
606 if (seq ## d < seq ## c) goto s ## a ## b ## d ## c; \
607 goto s ## a ## b ## c ## d; }
632 #define Merge4Case(a,b,c,d,c0,c1,c2) \
633 s ## a ## b ## c ## d: \
634 if (length == 0) goto finish; \
635 *target = *seq ## a; \
639 if (seq ## a c0 seq ## b) goto s ## a ## b ## c ## d; \
640 if (seq ## a c1 seq ## c) goto s ## b ## a ## c ## d; \
641 if (seq ## a c2 seq ## d) goto s ## b ## c ## a ## d; \
642 goto s ## b ## c ## d ## a;
644 Merge4Case(0, 1, 2, 3, <=, <=, <=);
645 Merge4Case(0, 1, 3, 2, <=, <=, <=);
646 Merge4Case(0, 2, 1, 3, <=, <=, <=);
647 Merge4Case(0, 2, 3, 1, <=, <=, <=);
648 Merge4Case(0, 3, 1, 2, <=, <=, <=);
649 Merge4Case(0, 3, 2, 1, <=, <=, <=);
650 Merge4Case(1, 0, 2, 3, < , <=, <=);
651 Merge4Case(1, 0, 3, 2, < , <=, <=);
652 Merge4Case(1, 2, 0, 3, <=, < , <=);
653 Merge4Case(1, 2, 3, 0, <=, <=, < );
654 Merge4Case(1, 3, 0, 2, <=, < , <=);
655 Merge4Case(1, 3, 2, 0, <=, <=, < );
656 Merge4Case(2, 0, 1, 3, < , < , <=);
657 Merge4Case(2, 0, 3, 1, < , <=, < );
658 Merge4Case(2, 1, 0, 3, < , < , <=);
659 Merge4Case(2, 1, 3, 0, < , <=, < );
660 Merge4Case(2, 3, 0, 1, <=, < , < );
661 Merge4Case(2, 3, 1, 0, <=, < , < );
662 Merge4Case(3, 0, 1, 2, < , < , < );
663 Merge4Case(3, 0, 2, 1, < , < , < );
664 Merge4Case(3, 1, 0, 2, < , < , < );
665 Merge4Case(3, 1, 2, 0, < , < , < );
666 Merge4Case(3, 2, 0, 1, < , < , < );
667 Merge4Case(3, 2, 1, 0, < , < , < );
675 seqs_begin[0].first = seq0;
676 seqs_begin[1].first = seq1;
677 seqs_begin[2].first = seq2;
678 seqs_begin[3].first = seq3;
684 typename RandomAccessIteratorIterator,
685 typename RandomAccessIterator3,
686 typename _DifferenceTp,
688 RandomAccessIterator3
689 multiway_merge_4_combined(RandomAccessIteratorIterator seqs_begin,
690 RandomAccessIteratorIterator seqs_end,
691 RandomAccessIterator3 target,
693 _DifferenceTp length, bool stable)
695 _GLIBCXX_CALL(length);
696 typedef _DifferenceTp difference_type;
698 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
699 ::value_type::first_type
700 RandomAccessIterator1;
701 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
705 RandomAccessIterator3 target_end;
708 difference_type overhang =
709 prepare_unguarded(seqs_begin, seqs_end, comp, min_seq, true);
711 difference_type total_length = 0;
712 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; ++s)
713 total_length += LENGTH(*s);
717 difference_type unguarded_length =
718 std::min(length, total_length - overhang);
719 target_end = multiway_merge_4_variant<unguarded_iterator>
720 (seqs_begin, seqs_end, target, comp, unguarded_length, stable);
721 overhang = length - unguarded_length;
725 // Empty sequence found.
730 #if _GLIBCXX_ASSERTIONS
731 _GLIBCXX_PARALLEL_ASSERT(target_end == target + length - overhang);
732 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp));
735 std::vector<std::pair<RandomAccessIterator1, RandomAccessIterator1> >
736 one_missing(seqs_begin, seqs_end);
737 one_missing.erase(one_missing.begin() + min_seq); //remove
739 target_end = multiway_merge_3_variant<guarded_iterator>(
740 one_missing.begin(), one_missing.end(),
741 target_end, comp, overhang, stable);
743 // Insert back again.
744 one_missing.insert(one_missing.begin() + min_seq, seqs_begin[min_seq]);
745 // Write back modified iterators.
746 copy(one_missing.begin(), one_missing.end(), seqs_begin);
748 #if _GLIBCXX_ASSERTIONS
749 _GLIBCXX_PARALLEL_ASSERT(target_end == target + length);
750 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp));
756 /** @brief Basic multi-way merging procedure.
758 * The head elements are kept in a sorted array, new heads are
760 * @param seqs_begin Begin iterator of iterator pair input sequence.
761 * @param seqs_end End iterator of iterator pair input sequence.
762 * @param target Begin iterator out output sequence.
763 * @param comp Comparator.
764 * @param length Maximum length to merge.
765 * @param stable Stable merging incurs a performance penalty.
766 * @return End iterator of output sequence.
769 typename RandomAccessIteratorIterator,
770 typename RandomAccessIterator3,
771 typename _DifferenceTp,
773 RandomAccessIterator3
774 multiway_merge_bubble(RandomAccessIteratorIterator seqs_begin,
775 RandomAccessIteratorIterator seqs_end,
776 RandomAccessIterator3 target,
777 Comparator comp, _DifferenceTp length, bool stable)
779 _GLIBCXX_CALL(length)
781 typedef _DifferenceTp difference_type;
782 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
783 ::value_type::first_type
784 RandomAccessIterator1;
785 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
788 // Num remaining pieces.
789 int k = static_cast<int>(seqs_end - seqs_begin), nrp;
791 value_type* pl = static_cast<value_type*>(
792 ::operator new(sizeof(value_type) * k));
793 int* source = new int[k];
794 difference_type total_length = 0;
796 #define POS(i) seqs_begin[(i)].first
797 #define STOPS(i) seqs_begin[(i)].second
799 // Write entries into queue.
801 for (int pi = 0; pi < k; pi++)
803 if (STOPS(pi) != POS(pi))
805 pl[nrp] = *(POS(pi));
808 total_length += LENGTH(seqs_begin[pi]);
814 for (int k = 0; k < nrp - 1; k++)
815 for (int pi = nrp - 1; pi > k; pi--)
816 if (comp(pl[pi], pl[pi - 1]) ||
817 (!comp(pl[pi - 1], pl[pi]) && source[pi] < source[pi - 1]))
819 std::swap(pl[pi - 1], pl[pi]);
820 std::swap(source[pi - 1], source[pi]);
825 for (int k = 0; k < nrp - 1; k++)
826 for (int pi = nrp - 1; pi > k; pi--)
827 if (comp(pl[pi], pl[pi-1]))
829 std::swap(pl[pi-1], pl[pi]);
830 std::swap(source[pi-1], source[pi]);
838 while (nrp > 0 && length > 0)
840 if (source[0] < source[1])
843 while ((nrp == 1 || !(comp(pl[1], pl[0]))) && length > 0)
849 if (POS(source[0]) == STOPS(source[0]))
851 // Move everything to the left.
852 for (int s = 0; s < nrp - 1; s++)
855 source[s] = source[s + 1];
861 pl[0] = *(POS(source[0]));
867 while ((nrp == 1 || comp(pl[0], pl[1])) && length > 0)
873 if (POS(source[0]) == STOPS(source[0]))
875 for (int s = 0; s < nrp - 1; s++)
878 source[s] = source[s + 1];
884 pl[0] = *(POS(source[0]));
890 while ((j < nrp) && (comp(pl[j], pl[j - 1]) ||
891 (!comp(pl[j - 1], pl[j])
892 && (source[j] < source[j - 1]))))
894 std::swap(pl[j - 1], pl[j]);
895 std::swap(source[j - 1], source[j]);
903 while (nrp > 0 && length > 0)
906 while (nrp == 1 || (!comp(pl[1], pl[0])) && length > 0)
912 if (POS(source[0]) == STOPS(source[0]))
914 for (int s = 0; s < (nrp - 1); s++)
917 source[s] = source[s + 1];
923 pl[0] = *(POS(source[0]));
928 while ((j < nrp) && comp(pl[j], pl[j - 1]))
930 std::swap(pl[j - 1], pl[j]);
931 std::swap(source[j - 1], source[j]);
943 /** @brief Multi-way merging procedure for a high branching factor,
946 * The head elements are kept in a loser tree.
947 * @param seqs_begin Begin iterator of iterator pair input sequence.
948 * @param seqs_end End iterator of iterator pair input sequence.
949 * @param target Begin iterator out output sequence.
950 * @param comp Comparator.
951 * @param length Maximum length to merge.
952 * @param stable Stable merging incurs a performance penalty.
953 * @return End iterator of output sequence.
957 typename RandomAccessIteratorIterator,
958 typename RandomAccessIterator3,
959 typename _DifferenceTp,
961 RandomAccessIterator3
962 multiway_merge_loser_tree(RandomAccessIteratorIterator seqs_begin,
963 RandomAccessIteratorIterator seqs_end,
964 RandomAccessIterator3 target,
966 _DifferenceTp length, bool stable)
968 _GLIBCXX_CALL(length)
970 typedef _DifferenceTp difference_type;
971 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
972 ::value_type::first_type
973 RandomAccessIterator1;
974 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
977 int k = static_cast<int>(seqs_end - seqs_begin);
981 difference_type total_length = 0;
983 // Default value for potentially non-default-constructible types.
984 value_type* arbitrary_element = NULL;
986 for (int t = 0; t < k; t++)
988 if(arbitrary_element == NULL && LENGTH(seqs_begin[t]) > 0)
989 arbitrary_element = &(*seqs_begin[t].first);
990 total_length += LENGTH(seqs_begin[t]);
993 if(total_length == 0)
996 for (int t = 0; t < k; t++)
1000 if (seqs_begin[t].first == seqs_begin[t].second)
1001 lt.insert_start_stable(*arbitrary_element, t, true);
1003 lt.insert_start_stable(*seqs_begin[t].first, t, false);
1007 if (seqs_begin[t].first == seqs_begin[t].second)
1008 lt.insert_start(*arbitrary_element, t, true);
1010 lt.insert_start(*seqs_begin[t].first, t, false);
1019 total_length = std::min(total_length, length);
1025 for (difference_type i = 0; i < total_length; i++)
1028 source = lt.get_min_source();
1030 *(target++) = *(seqs_begin[source].first++);
1033 if (seqs_begin[source].first == seqs_begin[source].second)
1034 lt.delete_min_insert_stable(*arbitrary_element, true);
1036 // Replace from same source.
1037 lt.delete_min_insert_stable(*seqs_begin[source].first, false);
1043 for (difference_type i = 0; i < total_length; i++)
1046 source = lt.get_min_source();
1048 *(target++) = *(seqs_begin[source].first++);
1051 if (seqs_begin[source].first == seqs_begin[source].second)
1052 lt.delete_min_insert(*arbitrary_element, true);
1054 // Replace from same source.
1055 lt.delete_min_insert(*seqs_begin[source].first, false);
1062 /** @brief Multi-way merging procedure for a high branching factor,
1065 * The head elements are kept in a loser tree.
1066 * @param seqs_begin Begin iterator of iterator pair input sequence.
1067 * @param seqs_end End iterator of iterator pair input sequence.
1068 * @param target Begin iterator out output sequence.
1069 * @param comp Comparator.
1070 * @param length Maximum length to merge.
1071 * @param stable Stable merging incurs a performance penalty.
1072 * @return End iterator of output sequence.
1073 * @pre No input will run out of elements during the merge.
1077 typename RandomAccessIteratorIterator,
1078 typename RandomAccessIterator3,
1079 typename _DifferenceTp, typename Comparator>
1080 RandomAccessIterator3
1081 multiway_merge_loser_tree_unguarded(RandomAccessIteratorIterator seqs_begin,
1082 RandomAccessIteratorIterator seqs_end,
1083 RandomAccessIterator3 target,
1085 _DifferenceTp length, bool stable)
1087 _GLIBCXX_CALL(length)
1088 typedef _DifferenceTp difference_type;
1090 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
1091 ::value_type::first_type
1092 RandomAccessIterator1;
1093 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
1096 int k = seqs_end - seqs_begin;
1100 difference_type total_length = 0;
1102 for (int t = 0; t < k; t++)
1104 #if _GLIBCXX_ASSERTIONS
1105 _GLIBCXX_PARALLEL_ASSERT(seqs_begin[t].first != seqs_begin[t].second);
1108 lt.insert_start_stable(*seqs_begin[t].first, t, false);
1110 lt.insert_start(*seqs_begin[t].first, t, false);
1112 total_length += LENGTH(seqs_begin[t]);
1120 // Do not go past end.
1121 length = std::min(total_length, length);
1125 #if _GLIBCXX_ASSERTIONS
1126 difference_type i = 0;
1131 RandomAccessIterator3 target_end = target + length;
1132 while (target < target_end)
1135 source = lt.get_min_source();
1137 #if _GLIBCXX_ASSERTIONS
1138 _GLIBCXX_PARALLEL_ASSERT(i == 0
1139 || !comp(*(seqs_begin[source].first), *(target - 1)));
1142 *(target++) = *(seqs_begin[source].first++);
1144 #if _GLIBCXX_ASSERTIONS
1145 _GLIBCXX_PARALLEL_ASSERT(
1146 (seqs_begin[source].first != seqs_begin[source].second)
1147 || (i == length - 1));
1151 // Replace from same source.
1152 lt.delete_min_insert_stable(*seqs_begin[source].first, false);
1158 RandomAccessIterator3 target_end = target + length;
1159 while (target < target_end)
1162 source = lt.get_min_source();
1164 #if _GLIBCXX_ASSERTIONS
1165 if (i > 0 && comp(*(seqs_begin[source].first), *(target - 1)))
1166 printf(" %i %i %i\n", length, i, source);
1167 _GLIBCXX_PARALLEL_ASSERT(i == 0
1168 || !comp(*(seqs_begin[source].first), *(target - 1)));
1171 *(target++) = *(seqs_begin[source].first++);
1173 #if _GLIBCXX_ASSERTIONS
1174 if (!((seqs_begin[source].first != seqs_begin[source].second)
1175 || (i >= length - 1)))
1176 printf(" %i %i %i\n", length, i, source);
1177 _GLIBCXX_PARALLEL_ASSERT(
1178 (seqs_begin[source].first != seqs_begin[source].second)
1179 || (i >= length - 1));
1183 // Replace from same source.
1184 lt.delete_min_insert(*seqs_begin[source].first, false);
1192 typename RandomAccessIteratorIterator,
1193 typename RandomAccessIterator3,
1194 typename _DifferenceTp,
1195 typename Comparator>
1196 RandomAccessIterator3
1197 multiway_merge_loser_tree_combined(RandomAccessIteratorIterator seqs_begin,
1198 RandomAccessIteratorIterator seqs_end,
1199 RandomAccessIterator3 target,
1201 _DifferenceTp length, bool stable)
1203 _GLIBCXX_CALL(length)
1205 typedef _DifferenceTp difference_type;
1207 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
1208 ::value_type::first_type
1209 RandomAccessIterator1;
1210 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
1214 RandomAccessIterator3 target_end;
1215 difference_type overhang = prepare_unguarded(seqs_begin, seqs_end,
1216 comp, min_seq, stable);
1218 difference_type total_length = 0;
1219 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; s++)
1220 total_length += LENGTH(*s);
1224 difference_type unguarded_length =
1225 std::min(length, total_length - overhang);
1226 target_end = multiway_merge_loser_tree_unguarded
1227 <typename loser_tree_unguarded_traits<value_type, Comparator>::LT>
1228 (seqs_begin, seqs_end, target, comp, unguarded_length, stable);
1229 overhang = length - unguarded_length;
1233 // Empty sequence found.
1235 target_end = target;
1238 #if _GLIBCXX_ASSERTIONS
1239 _GLIBCXX_PARALLEL_ASSERT(target_end == target + length - overhang);
1240 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp));
1243 target_end = multiway_merge_loser_tree
1244 <typename loser_tree_traits<value_type, Comparator>::LT>
1245 (seqs_begin, seqs_end, target_end, comp, overhang, stable);
1247 #if _GLIBCXX_ASSERTIONS
1248 _GLIBCXX_PARALLEL_ASSERT(target_end == target + length);
1249 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp));
1256 typename RandomAccessIteratorIterator,
1257 typename RandomAccessIterator3,
1258 typename _DifferenceTp,
1259 typename Comparator>
1260 RandomAccessIterator3
1261 multiway_merge_loser_tree_sentinel(RandomAccessIteratorIterator seqs_begin,
1262 RandomAccessIteratorIterator seqs_end,
1263 RandomAccessIterator3 target,
1265 _DifferenceTp length, bool stable)
1267 _GLIBCXX_CALL(length)
1269 typedef _DifferenceTp difference_type;
1270 typedef std::iterator_traits<RandomAccessIteratorIterator> traits_type;
1271 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
1272 ::value_type::first_type
1273 RandomAccessIterator1;
1274 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
1277 RandomAccessIterator3 target_end;
1278 difference_type overhang =
1279 prepare_unguarded_sentinel(seqs_begin, seqs_end, comp);
1281 difference_type total_length = 0;
1282 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; s++)
1284 total_length += LENGTH(*s);
1290 difference_type unguarded_length =
1291 std::min(length, total_length - overhang);
1292 target_end = multiway_merge_loser_tree_unguarded
1293 <typename loser_tree_unguarded_traits<value_type, Comparator>::LT>
1294 (seqs_begin, seqs_end, target, comp, unguarded_length, stable);
1295 overhang = length - unguarded_length;
1297 #if _GLIBCXX_ASSERTIONS
1298 _GLIBCXX_PARALLEL_ASSERT(target_end == target + length - overhang);
1299 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp));
1302 // Copy rest stable.
1303 for (RandomAccessIteratorIterator s = seqs_begin;
1304 s != seqs_end && overhang > 0; s++)
1308 difference_type local_length =
1309 std::min<difference_type>(overhang, LENGTH(*s));
1310 target_end = std::copy((*s).first, (*s).first + local_length,
1312 (*s).first += local_length;
1313 overhang -= local_length;
1316 #if _GLIBCXX_ASSERTIONS
1317 _GLIBCXX_PARALLEL_ASSERT(overhang == 0);
1318 _GLIBCXX_PARALLEL_ASSERT(target_end == target + length);
1319 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target_end, comp));
1325 /** @brief Sequential multi-way merging switch.
1327 * The decision if based on the branching factor and runtime settings.
1328 * @param seqs_begin Begin iterator of iterator pair input sequence.
1329 * @param seqs_end End iterator of iterator pair input sequence.
1330 * @param target Begin iterator out output sequence.
1331 * @param comp Comparator.
1332 * @param length Maximum length to merge.
1333 * @param stable Stable merging incurs a performance penalty.
1334 * @param sentinel The sequences have a sentinel element.
1335 * @return End iterator of output sequence. */
1337 typename RandomAccessIteratorIterator,
1338 typename RandomAccessIterator3,
1339 typename _DifferenceTp,
1340 typename Comparator>
1341 RandomAccessIterator3
1342 multiway_merge(RandomAccessIteratorIterator seqs_begin,
1343 RandomAccessIteratorIterator seqs_end,
1344 RandomAccessIterator3 target,
1345 Comparator comp, _DifferenceTp length,
1346 bool stable, bool sentinel,
1349 _GLIBCXX_CALL(length)
1351 typedef _DifferenceTp difference_type;
1352 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
1353 ::value_type::first_type
1354 RandomAccessIterator1;
1355 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
1358 #if _GLIBCXX_ASSERTIONS
1359 for (RandomAccessIteratorIterator s = seqs_begin; s != seqs_end; s++)
1360 _GLIBCXX_PARALLEL_ASSERT(is_sorted((*s).first, (*s).second, comp));
1363 RandomAccessIterator3 return_target = target;
1364 int k = static_cast<int>(seqs_end - seqs_begin);
1366 Settings::MultiwayMergeAlgorithm mwma =
1367 Settings::multiway_merge_algorithm;
1369 if (!sentinel && mwma == Settings::LOSER_TREE_SENTINEL)
1370 mwma = Settings::LOSER_TREE_COMBINED;
1377 return_target = std::copy(seqs_begin[0].first,
1378 seqs_begin[0].first + length,
1380 seqs_begin[0].first += length;
1383 return_target = merge_advance(seqs_begin[0].first,
1384 seqs_begin[0].second,
1385 seqs_begin[1].first,
1386 seqs_begin[1].second,
1387 target, length, comp);
1392 case Settings::LOSER_TREE_COMBINED:
1393 return_target = multiway_merge_3_combined(seqs_begin,
1396 comp, length, stable);
1398 case Settings::LOSER_TREE_SENTINEL:
1399 return_target = multiway_merge_3_variant<unguarded_iterator>(
1403 comp, length, stable);
1406 return_target = multiway_merge_3_variant<guarded_iterator>(
1410 comp, length, stable);
1417 case Settings::LOSER_TREE_COMBINED:
1418 return_target = multiway_merge_4_combined(
1422 comp, length, stable);
1424 case Settings::LOSER_TREE_SENTINEL:
1425 return_target = multiway_merge_4_variant<unguarded_iterator>(
1429 comp, length, stable);
1432 return_target = multiway_merge_4_variant<guarded_iterator>(
1436 comp, length, stable);
1444 case Settings::BUBBLE:
1445 return_target = multiway_merge_bubble(
1449 comp, length, stable);
1451 #if _GLIBCXX_LOSER_TREE_EXPLICIT
1452 case Settings::LOSER_TREE_EXPLICIT:
1453 return_target = multiway_merge_loser_tree<
1454 LoserTreeExplicit<value_type, Comparator> >(
1458 comp, length, stable);
1461 #if _GLIBCXX_LOSER_TREE
1462 case Settings::LOSER_TREE:
1463 return_target = multiway_merge_loser_tree<
1464 LoserTree<value_type, Comparator> >(
1468 comp, length, stable);
1471 #if _GLIBCXX_LOSER_TREE_COMBINED
1472 case Settings::LOSER_TREE_COMBINED:
1473 return_target = multiway_merge_loser_tree_combined(
1477 comp, length, stable);
1480 #if _GLIBCXX_LOSER_TREE_SENTINEL
1481 case Settings::LOSER_TREE_SENTINEL:
1482 return_target = multiway_merge_loser_tree_sentinel(
1486 comp, length, stable);
1490 // multiway_merge algorithm not implemented.
1491 _GLIBCXX_PARALLEL_ASSERT(0);
1496 #if _GLIBCXX_ASSERTIONS
1497 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target + length, comp));
1500 return return_target;
1503 /** @brief Parallel multi-way merge routine.
1505 * The decision if based on the branching factor and runtime settings.
1506 * @param seqs_begin Begin iterator of iterator pair input sequence.
1507 * @param seqs_end End iterator of iterator pair input sequence.
1508 * @param target Begin iterator out output sequence.
1509 * @param comp Comparator.
1510 * @param length Maximum length to merge.
1511 * @param stable Stable merging incurs a performance penalty.
1512 * @param sentinel Ignored.
1513 * @return End iterator of output sequence.
1516 typename RandomAccessIteratorIterator,
1517 typename RandomAccessIterator3,
1518 typename _DifferenceTp,
1519 typename Comparator>
1520 RandomAccessIterator3
1521 parallel_multiway_merge(RandomAccessIteratorIterator seqs_begin,
1522 RandomAccessIteratorIterator seqs_end,
1523 RandomAccessIterator3 target,
1525 _DifferenceTp length, bool stable, bool sentinel)
1527 _GLIBCXX_CALL(length)
1529 typedef _DifferenceTp difference_type;
1530 typedef typename std::iterator_traits<RandomAccessIteratorIterator>
1531 ::value_type::first_type
1532 RandomAccessIterator1;
1533 typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
1537 int k = static_cast<int>(seqs_end - seqs_begin);
1539 difference_type total_length = 0;
1540 for (RandomAccessIteratorIterator raii = seqs_begin;
1541 raii != seqs_end; raii++)
1542 total_length += LENGTH(*raii);
1544 _GLIBCXX_CALL(total_length)
1546 if (total_length == 0 || k == 0)
1549 bool tight = (total_length == length);
1551 std::vector<std::pair<difference_type, difference_type> >* pieces;
1553 thread_index_t num_threads = static_cast<thread_index_t>(
1554 std::min<difference_type>(get_max_threads(), total_length));
1556 # pragma omp parallel num_threads (num_threads)
1560 num_threads = omp_get_num_threads();
1561 // Thread t will have to merge pieces[iam][0..k - 1]
1562 pieces = new std::vector<
1563 std::pair<difference_type, difference_type> >[num_threads];
1564 for (int s = 0; s < num_threads; s++)
1565 pieces[s].resize(k);
1567 difference_type num_samples =
1568 Settings::merge_oversampling * num_threads;
1570 if (Settings::multiway_merge_splitting == Settings::SAMPLING)
1572 value_type* samples = static_cast<value_type*>(
1573 ::operator new(sizeof(value_type) * k * num_samples));
1575 for (int s = 0; s < k; s++)
1576 for (int i = 0; (difference_type)i < num_samples; i++)
1578 difference_type sample_index =
1579 static_cast<difference_type>(
1580 LENGTH(seqs_begin[s]) * (double(i + 1) /
1581 (num_samples + 1)) * (double(length)
1583 samples[s * num_samples + i] =
1584 seqs_begin[s].first[sample_index];
1588 __gnu_sequential::stable_sort(
1589 samples, samples + (num_samples * k), comp);
1591 __gnu_sequential::sort(
1592 samples, samples + (num_samples * k), comp);
1594 for (int slab = 0; slab < num_threads; slab++)
1595 // For each slab / processor.
1596 for (int seq = 0; seq < k; seq++)
1598 // For each sequence.
1600 pieces[slab][seq].first =
1602 seqs_begin[seq].first,
1603 seqs_begin[seq].second,
1604 samples[num_samples * k * slab / num_threads],
1606 - seqs_begin[seq].first;
1609 // Absolute beginning.
1610 pieces[slab][seq].first = 0;
1612 if ((slab + 1) < num_threads)
1613 pieces[slab][seq].second =
1615 seqs_begin[seq].first,
1616 seqs_begin[seq].second,
1617 samples[num_samples * k * (slab + 1) /
1619 - seqs_begin[seq].first;
1621 pieces[slab][seq].second = LENGTH(seqs_begin[seq]);
1627 // (Settings::multiway_merge_splitting == Settings::EXACT).
1628 std::vector<RandomAccessIterator1>* offsets =
1629 new std::vector<RandomAccessIterator1>[num_threads];
1631 std::pair<RandomAccessIterator1, RandomAccessIterator1>
1634 copy(seqs_begin, seqs_end, se.begin());
1636 difference_type* borders =
1637 new difference_type[num_threads + 1];
1638 equally_split(length, num_threads, borders);
1640 for (int s = 0; s < (num_threads - 1); s++)
1642 offsets[s].resize(k);
1644 se.begin(), se.end(), borders[s + 1],
1645 offsets[s].begin(), comp);
1647 // Last one also needed and available.
1650 offsets[num_threads - 1].resize(k);
1651 multiseq_partition(se.begin(), se.end(),
1652 difference_type(length),
1653 offsets[num_threads - 1].begin(), comp);
1658 for (int slab = 0; slab < num_threads; slab++)
1660 // For each slab / processor.
1661 for (int seq = 0; seq < k; seq++)
1663 // For each sequence.
1666 // Absolute beginning.
1667 pieces[slab][seq].first = 0;
1670 pieces[slab][seq].first =
1671 pieces[slab - 1][seq].second;
1672 if (!tight || slab < (num_threads - 1))
1673 pieces[slab][seq].second =
1674 offsets[slab][seq] - seqs_begin[seq].first;
1677 // slab == num_threads - 1
1678 pieces[slab][seq].second =
1679 LENGTH(seqs_begin[seq]);
1687 thread_index_t iam = omp_get_thread_num();
1689 difference_type target_position = 0;
1691 for (int c = 0; c < k; c++)
1692 target_position += pieces[iam][c].first;
1696 std::pair<RandomAccessIterator1, RandomAccessIterator1>* chunks
1698 std::pair<RandomAccessIterator1, RandomAccessIterator1>[k];
1700 difference_type local_length = 0;
1701 for (int s = 0; s < k; s++)
1703 chunks[s] = std::make_pair(
1704 seqs_begin[s].first + pieces[iam][s].first,
1705 seqs_begin[s].first + pieces[iam][s].second);
1706 local_length += LENGTH(chunks[s]);
1710 chunks, chunks + k, target + target_position, comp,
1711 std::min(local_length, length - target_position),
1712 stable, false, sequential_tag());
1718 RandomAccessIterator1
1719 begin0 = seqs_begin[0].first + pieces[iam][0].first,
1720 begin1 = seqs_begin[1].first + pieces[iam][1].first;
1721 merge_advance(begin0,
1722 seqs_begin[0].first + pieces[iam][0].second,
1724 seqs_begin[1].first + pieces[iam][1].second,
1725 target + target_position,
1726 (pieces[iam][0].second - pieces[iam][0].first) +
1727 (pieces[iam][1].second - pieces[iam][1].first),
1732 #if _GLIBCXX_ASSERTIONS
1733 _GLIBCXX_PARALLEL_ASSERT(is_sorted(target, target + length, comp));
1736 // Update ends of sequences.
1737 for (int s = 0; s < k; s++)
1738 seqs_begin[s].first += pieces[num_threads - 1][s].second;
1742 return target + length;
1746 * @brief Multi-way merging front-end.
1747 * @param seqs_begin Begin iterator of iterator pair input sequence.
1748 * @param seqs_end End iterator of iterator pair input sequence.
1749 * @param target Begin iterator out output sequence.
1750 * @param comp Comparator.
1751 * @param length Maximum length to merge.
1752 * @param stable Stable merging incurs a performance penalty.
1753 * @return End iterator of output sequence.
1756 typename RandomAccessIteratorPairIterator,
1757 typename RandomAccessIterator3,
1758 typename _DifferenceTp,
1759 typename Comparator>
1760 RandomAccessIterator3
1761 multiway_merge(RandomAccessIteratorPairIterator seqs_begin,
1762 RandomAccessIteratorPairIterator seqs_end,
1763 RandomAccessIterator3 target, Comparator comp,
1764 _DifferenceTp length, bool stable)
1766 typedef _DifferenceTp difference_type;
1767 _GLIBCXX_CALL(seqs_end - seqs_begin)
1769 if (seqs_begin == seqs_end)
1772 RandomAccessIterator3 target_end;
1773 if (_GLIBCXX_PARALLEL_CONDITION(
1774 ((seqs_end - seqs_begin) >= Settings::multiway_merge_minimal_k)
1775 && ((sequence_index_t)length >= Settings::multiway_merge_minimal_n)))
1776 target_end = parallel_multiway_merge(
1777 seqs_begin, seqs_end,
1778 target, comp, static_cast<difference_type>(length), stable, false);
1780 target_end = multiway_merge(
1781 seqs_begin, seqs_end,
1782 target, comp, length, stable, false, sequential_tag());
1787 /** @brief Multi-way merging front-end.
1788 * @param seqs_begin Begin iterator of iterator pair input sequence.
1789 * @param seqs_end End iterator of iterator pair input sequence.
1790 * @param target Begin iterator out output sequence.
1791 * @param comp Comparator.
1792 * @param length Maximum length to merge.
1793 * @param stable Stable merging incurs a performance penalty.
1794 * @return End iterator of output sequence.
1795 * @pre For each @c i, @c seqs_begin[i].second must be the end
1796 * marker of the sequence, but also reference the one more sentinel
1799 typename RandomAccessIteratorPairIterator,
1800 typename RandomAccessIterator3,
1801 typename _DifferenceTp,
1802 typename Comparator>
1803 RandomAccessIterator3
1804 multiway_merge_sentinel(RandomAccessIteratorPairIterator seqs_begin,
1805 RandomAccessIteratorPairIterator seqs_end,
1806 RandomAccessIterator3 target,
1808 _DifferenceTp length,
1811 typedef _DifferenceTp difference_type;
1813 if (seqs_begin == seqs_end)
1816 _GLIBCXX_CALL(seqs_end - seqs_begin)
1818 if (_GLIBCXX_PARALLEL_CONDITION(
1819 ((seqs_end - seqs_begin) >= Settings::multiway_merge_minimal_k)
1820 && ((sequence_index_t)length >= Settings::multiway_merge_minimal_n)))
1821 return parallel_multiway_merge(
1822 seqs_begin, seqs_end,
1823 target, comp, static_cast<difference_type>(length), stable, true);
1825 return multiway_merge(
1826 seqs_begin, seqs_end,
1827 target, comp, length, stable, true, sequential_tag());