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