mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-26 04:25:51 +08:00
4cbc9d8b34
This is a correct fix for the incorrect cppcheck suggestion to make these parameters const. In order to that, the dereference operators need to be const. The conversions to the underlying iterator can be const too. PR c/92472 * include/parallel/multiway_merge.h (_GuardedIterator::operator*) (_GuardedIterator::operator _RAIter, _UnguardedIterator::operator*) (_UnguardedIterator::operator _RAIter): Add const qualifier. (operator<(_GuardedIterator&, _GuardedIterator&) (operator<=(_GuardedIterator&, _GuardedIterator&) (operator<(_UnguardedIterator&, _UnguardedIterator&) (operator<=(_UnguardedIterator&, _UnguardedIterator&): Change parameters to const references.
2073 lines
69 KiB
C++
2073 lines
69 KiB
C++
// -*- C++ -*-
|
|
|
|
// Copyright (C) 2007-2020 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>
|
|
#include <parallel/multiseq_selection.h>
|
|
#if _GLIBCXX_PARALLEL_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
|
|
{
|
|
template<typename _RAIter1, typename _RAIter2, typename _OutputIterator,
|
|
typename _DifferenceTp, typename _Compare>
|
|
_OutputIterator
|
|
__merge_advance(_RAIter1&, _RAIter1, _RAIter2&, _RAIter2,
|
|
_OutputIterator, _DifferenceTp, _Compare);
|
|
|
|
/** @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 _RAIter is not possible since
|
|
* _RAIter need not be a class.
|
|
*/
|
|
template<typename _RAIter, typename _Compare>
|
|
class _GuardedIterator
|
|
{
|
|
private:
|
|
/** @brief Current iterator __position. */
|
|
_RAIter _M_current;
|
|
|
|
/** @brief End iterator of the sequence. */
|
|
_RAIter _M_end;
|
|
|
|
/** @brief _Compare. */
|
|
_Compare& __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. */
|
|
_GuardedIterator(_RAIter __begin, _RAIter __end, _Compare& __comp)
|
|
: _M_current(__begin), _M_end(__end), __comp(__comp)
|
|
{ }
|
|
|
|
/** @brief Pre-increment operator.
|
|
* @return This. */
|
|
_GuardedIterator<_RAIter, _Compare>&
|
|
operator++()
|
|
{
|
|
++_M_current;
|
|
return *this;
|
|
}
|
|
|
|
/** @brief Dereference operator.
|
|
* @return Referenced element. */
|
|
typename std::iterator_traits<_RAIter>::value_type&
|
|
operator*() const
|
|
{ return *_M_current; }
|
|
|
|
/** @brief Convert to wrapped iterator.
|
|
* @return Wrapped iterator. */
|
|
operator _RAIter() const
|
|
{ return _M_current; }
|
|
|
|
/** @brief Compare two elements referenced by guarded iterators.
|
|
* @param __bi1 First iterator.
|
|
* @param __bi2 Second iterator.
|
|
* @return @c true if less. */
|
|
friend bool
|
|
operator<(const _GuardedIterator<_RAIter, _Compare>& __bi1,
|
|
const _GuardedIterator<_RAIter, _Compare>& __bi2)
|
|
{
|
|
if (__bi1._M_current == __bi1._M_end) // __bi1 is sup
|
|
return __bi2._M_current == __bi2._M_end; // __bi2 is not sup
|
|
if (__bi2._M_current == __bi2._M_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. */
|
|
friend bool
|
|
operator<=(const _GuardedIterator<_RAIter, _Compare>& __bi1,
|
|
const _GuardedIterator<_RAIter, _Compare>& __bi2)
|
|
{
|
|
if (__bi2._M_current == __bi2._M_end) // __bi1 is sup
|
|
return __bi1._M_current != __bi1._M_end; // __bi2 is not sup
|
|
if (__bi1._M_current == __bi1._M_end) // __bi2 is sup
|
|
return false;
|
|
return !(__bi1.__comp)(*__bi2, *__bi1); // normal compare
|
|
}
|
|
};
|
|
|
|
template<typename _RAIter, typename _Compare>
|
|
class _UnguardedIterator
|
|
{
|
|
private:
|
|
/** @brief Current iterator __position. */
|
|
_RAIter _M_current;
|
|
/** @brief _Compare. */
|
|
_Compare& __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. */
|
|
_UnguardedIterator(_RAIter __begin,
|
|
_RAIter /* __end */, _Compare& __comp)
|
|
: _M_current(__begin), __comp(__comp)
|
|
{ }
|
|
|
|
/** @brief Pre-increment operator.
|
|
* @return This. */
|
|
_UnguardedIterator<_RAIter, _Compare>&
|
|
operator++()
|
|
{
|
|
++_M_current;
|
|
return *this;
|
|
}
|
|
|
|
/** @brief Dereference operator.
|
|
* @return Referenced element. */
|
|
typename std::iterator_traits<_RAIter>::value_type&
|
|
operator*() const
|
|
{ return *_M_current; }
|
|
|
|
/** @brief Convert to wrapped iterator.
|
|
* @return Wrapped iterator. */
|
|
operator _RAIter() const
|
|
{ return _M_current; }
|
|
|
|
/** @brief Compare two elements referenced by unguarded iterators.
|
|
* @param __bi1 First iterator.
|
|
* @param __bi2 Second iterator.
|
|
* @return @c true if less. */
|
|
friend bool
|
|
operator<(const _UnguardedIterator<_RAIter, _Compare>& __bi1,
|
|
const _UnguardedIterator<_RAIter, _Compare>& __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. */
|
|
friend bool
|
|
operator<=(const _UnguardedIterator<_RAIter, _Compare>& __bi1,
|
|
const _UnguardedIterator<_RAIter, _Compare>& __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 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 @a not 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 of 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 _Cp> class iterator,
|
|
typename _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIter3
|
|
multiway_merge_3_variant(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{
|
|
_GLIBCXX_CALL(__length);
|
|
|
|
typedef _DifferenceTp _DifferenceType;
|
|
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename std::iterator_traits<_RAIter1>::value_type
|
|
_ValueType;
|
|
|
|
if (__length == 0)
|
|
return __target;
|
|
|
|
#if _GLIBCXX_PARALLEL_ASSERTIONS
|
|
_DifferenceTp __orig_length = __length;
|
|
#endif
|
|
|
|
iterator<_RAIter1, _Compare>
|
|
__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_PARALLEL_ASSERTIONS
|
|
_GLIBCXX_PARALLEL_ASSERT(
|
|
((_RAIter1)__seq0 - __seqs_begin[0].first) +
|
|
((_RAIter1)__seq1 - __seqs_begin[1].first) +
|
|
((_RAIter1)__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 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 @a not 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 of 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 _Cp> class iterator,
|
|
typename _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIter3
|
|
multiway_merge_4_variant(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{
|
|
_GLIBCXX_CALL(__length);
|
|
typedef _DifferenceTp _DifferenceType;
|
|
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename std::iterator_traits<_RAIter1>::value_type
|
|
_ValueType;
|
|
|
|
iterator<_RAIter1, _Compare>
|
|
__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 of 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 _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIter3
|
|
multiway_merge_loser_tree(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{
|
|
_GLIBCXX_CALL(__length)
|
|
|
|
typedef _DifferenceTp _DifferenceType;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::difference_type _SeqNumber;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename std::iterator_traits<_RAIter1>::value_type
|
|
_ValueType;
|
|
|
|
_SeqNumber __k = static_cast<_SeqNumber>(__seqs_end - __seqs_begin);
|
|
|
|
_LT __lt(__k, __comp);
|
|
|
|
// Default value for potentially non-default-constructible types.
|
|
_ValueType* __arbitrary_element = 0;
|
|
|
|
for (_SeqNumber __t = 0; __t < __k; ++__t)
|
|
{
|
|
if(!__arbitrary_element
|
|
&& _GLIBCXX_PARALLEL_LENGTH(__seqs_begin[__t]) > 0)
|
|
__arbitrary_element = &(*__seqs_begin[__t].first);
|
|
}
|
|
|
|
for (_SeqNumber __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();
|
|
|
|
_SeqNumber __source;
|
|
|
|
for (_DifferenceType __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 of 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 _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp, typename _Compare>
|
|
_RAIter3
|
|
multiway_merge_loser_tree_unguarded(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
const typename std::iterator_traits<typename std::iterator_traits<
|
|
_RAIterIterator>::value_type::first_type>::value_type&
|
|
__sentinel,
|
|
_DifferenceTp __length,
|
|
_Compare __comp)
|
|
{
|
|
_GLIBCXX_CALL(__length)
|
|
typedef _DifferenceTp _DifferenceType;
|
|
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::difference_type _SeqNumber;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename std::iterator_traits<_RAIter1>::value_type
|
|
_ValueType;
|
|
|
|
_SeqNumber __k = __seqs_end - __seqs_begin;
|
|
|
|
_LT __lt(__k, __sentinel, __comp);
|
|
|
|
for (_SeqNumber __t = 0; __t < __k; ++__t)
|
|
{
|
|
#if _GLIBCXX_PARALLEL_ASSERTIONS
|
|
_GLIBCXX_PARALLEL_ASSERT(__seqs_begin[__t].first
|
|
!= __seqs_begin[__t].second);
|
|
#endif
|
|
__lt.__insert_start(*__seqs_begin[__t].first, __t, false);
|
|
}
|
|
|
|
__lt.__init();
|
|
|
|
_SeqNumber __source;
|
|
|
|
#if _GLIBCXX_PARALLEL_ASSERTIONS
|
|
_DifferenceType __i = 0;
|
|
#endif
|
|
|
|
_RAIter3 __target_end = __target + __length;
|
|
while (__target < __target_end)
|
|
{
|
|
// Take out.
|
|
__source = __lt.__get_min_source();
|
|
|
|
#if _GLIBCXX_PARALLEL_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_PARALLEL_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.
|
|
*
|
|
* @tparam _UnguardedLoserTree Loser Tree variant to use for the unguarded
|
|
* 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 of 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 _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIter3
|
|
multiway_merge_loser_tree_sentinel(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
const typename std::iterator_traits<typename std::iterator_traits<
|
|
_RAIterIterator>::value_type::first_type>::value_type&
|
|
__sentinel,
|
|
_DifferenceTp __length,
|
|
_Compare __comp)
|
|
{
|
|
_GLIBCXX_CALL(__length)
|
|
|
|
typedef _DifferenceTp _DifferenceType;
|
|
typedef std::iterator_traits<_RAIterIterator> _TraitsType;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename std::iterator_traits<_RAIter1>::value_type
|
|
_ValueType;
|
|
|
|
_RAIter3 __target_end;
|
|
|
|
for (_RAIterIterator __s = __seqs_begin; __s != __seqs_end; ++__s)
|
|
// Move the sequence ends to the sentinel. 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_PARALLEL_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 (_RAIterIterator __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 "_M_use_pointer" is used to determine whether to use pointers
|
|
* in he 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 _LoserTreeTraits<int>
|
|
* { static const bool _M_use_pointer = false; };
|
|
*
|
|
* template<>
|
|
* struct _LoserTreeTraits<heavyweight_type>
|
|
* { static const bool _M_use_pointer = true; };
|
|
*
|
|
* @param _Tp type to give the loser tree traits for.
|
|
*/
|
|
template <typename _Tp>
|
|
struct _LoserTreeTraits
|
|
{
|
|
/**
|
|
* @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 _M_use_pointer = (sizeof(_Tp) > 4 * sizeof(_Tp*));
|
|
};
|
|
|
|
/**
|
|
* @brief Switch for 3-way merging with __sentinels turned off.
|
|
*
|
|
* Note that 3-way merging is always stable!
|
|
*/
|
|
template<bool __sentinels /*default == false*/,
|
|
typename _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
struct __multiway_merge_3_variant_sentinel_switch
|
|
{
|
|
_RAIter3
|
|
operator()(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{ return multiway_merge_3_variant<_GuardedIterator>
|
|
(__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 _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
struct __multiway_merge_3_variant_sentinel_switch<true, _RAIterIterator,
|
|
_RAIter3, _DifferenceTp,
|
|
_Compare>
|
|
{
|
|
_RAIter3
|
|
operator()(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{ return multiway_merge_3_variant<_UnguardedIterator>
|
|
(__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 _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
struct __multiway_merge_4_variant_sentinel_switch
|
|
{
|
|
_RAIter3
|
|
operator()(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{ return multiway_merge_4_variant<_GuardedIterator>
|
|
(__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 _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
struct __multiway_merge_4_variant_sentinel_switch<true, _RAIterIterator,
|
|
_RAIter3, _DifferenceTp,
|
|
_Compare>
|
|
{
|
|
_RAIter3
|
|
operator()(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{ return multiway_merge_4_variant<_UnguardedIterator>
|
|
(__seqs_begin, __seqs_end, __target, __length, __comp); }
|
|
};
|
|
|
|
/**
|
|
* @brief Switch for k-way merging with __sentinels turned on.
|
|
*/
|
|
template<bool __sentinels,
|
|
bool __stable,
|
|
typename _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
struct __multiway_merge_k_variant_sentinel_switch
|
|
{
|
|
_RAIter3
|
|
operator()(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
const typename std::iterator_traits<typename std::iterator_traits<
|
|
_RAIterIterator>::value_type::first_type>::value_type&
|
|
__sentinel,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename std::iterator_traits<_RAIter1>::value_type
|
|
_ValueType;
|
|
|
|
return multiway_merge_loser_tree_sentinel<
|
|
typename __gnu_cxx::__conditional_type<
|
|
_LoserTreeTraits<_ValueType>::_M_use_pointer,
|
|
_LoserTreePointerUnguarded<__stable, _ValueType, _Compare>,
|
|
_LoserTreeUnguarded<__stable, _ValueType, _Compare>
|
|
>::__type>
|
|
(__seqs_begin, __seqs_end, __target, __sentinel, __length, __comp);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Switch for k-way merging with __sentinels turned off.
|
|
*/
|
|
template<bool __stable,
|
|
typename _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
struct __multiway_merge_k_variant_sentinel_switch<false, __stable,
|
|
_RAIterIterator,
|
|
_RAIter3, _DifferenceTp,
|
|
_Compare>
|
|
{
|
|
_RAIter3
|
|
operator()(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
const typename std::iterator_traits<typename std::iterator_traits<
|
|
_RAIterIterator>::value_type::first_type>::value_type&
|
|
__sentinel,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename std::iterator_traits<_RAIter1>::value_type
|
|
_ValueType;
|
|
|
|
return multiway_merge_loser_tree<
|
|
typename __gnu_cxx::__conditional_type<
|
|
_LoserTreeTraits<_ValueType>::_M_use_pointer,
|
|
_LoserTreePointer<__stable, _ValueType, _Compare>,
|
|
_LoserTree<__stable, _ValueType, _Compare>
|
|
>::__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 of output sequence.
|
|
* @param __comp Comparator.
|
|
* @param __length Maximum length to merge, possibly larger than the
|
|
* number of elements available.
|
|
* @param __sentinel The sequences have __a __sentinel element.
|
|
* @return End iterator of output sequence. */
|
|
template<bool __stable,
|
|
bool __sentinels,
|
|
typename _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIter3
|
|
__sequential_multiway_merge(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
const typename std::iterator_traits<typename std::iterator_traits<
|
|
_RAIterIterator>::value_type::first_type>::value_type&
|
|
__sentinel,
|
|
_DifferenceTp __length, _Compare __comp)
|
|
{
|
|
_GLIBCXX_CALL(__length)
|
|
|
|
typedef _DifferenceTp _DifferenceType;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::difference_type _SeqNumber;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename std::iterator_traits<_RAIter1>::value_type
|
|
_ValueType;
|
|
|
|
#if _GLIBCXX_PARALLEL_ASSERTIONS
|
|
for (_RAIterIterator __s = __seqs_begin; __s != __seqs_end; ++__s)
|
|
{
|
|
_GLIBCXX_PARALLEL_ASSERT(__is_sorted((*__s).first,
|
|
(*__s).second, __comp));
|
|
}
|
|
#endif
|
|
|
|
_DifferenceTp __total_length = 0;
|
|
for (_RAIterIterator __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;
|
|
|
|
_RAIter3 __return_target = __target;
|
|
_SeqNumber __k = static_cast<_SeqNumber>(__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, _RAIterIterator, _RAIter3, _DifferenceTp, _Compare>()
|
|
(__seqs_begin, __seqs_end, __target, __length, __comp);
|
|
break;
|
|
case 4:
|
|
__return_target = __multiway_merge_4_variant_sentinel_switch
|
|
<__sentinels, _RAIterIterator, _RAIter3, _DifferenceTp, _Compare>()
|
|
(__seqs_begin, __seqs_end, __target, __length, __comp);
|
|
break;
|
|
default:
|
|
__return_target = __multiway_merge_k_variant_sentinel_switch
|
|
<__sentinels, __stable, _RAIterIterator, _RAIter3, _DifferenceTp,
|
|
_Compare>()
|
|
(__seqs_begin, __seqs_end, __target, __sentinel, __length, __comp);
|
|
break;
|
|
}
|
|
#if _GLIBCXX_PARALLEL_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 _RAIter, class _StrictWeakOrdering>
|
|
struct _SamplingSorter
|
|
{
|
|
void
|
|
operator()(_RAIter __first, _RAIter __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 _RAIter, class _StrictWeakOrdering>
|
|
struct _SamplingSorter<false, _RAIter, _StrictWeakOrdering>
|
|
{
|
|
void
|
|
operator()(_RAIter __first, _RAIter __last, _StrictWeakOrdering __comp)
|
|
{ __gnu_sequential::sort(__first, __last, __comp); }
|
|
};
|
|
|
|
/**
|
|
* @brief Sampling based splitting for parallel multiway-merge routine.
|
|
*/
|
|
template<bool __stable,
|
|
typename _RAIterIterator,
|
|
typename _Compare,
|
|
typename _DifferenceType>
|
|
void
|
|
multiway_merge_sampling_splitting(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_DifferenceType __length,
|
|
_DifferenceType __total_length,
|
|
_Compare __comp,
|
|
std::vector<std::pair<_DifferenceType, _DifferenceType> > *__pieces)
|
|
{
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::difference_type _SeqNumber;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename std::iterator_traits<_RAIter1>::value_type
|
|
_ValueType;
|
|
|
|
// __k sequences.
|
|
const _SeqNumber __k
|
|
= static_cast<_SeqNumber>(__seqs_end - __seqs_begin);
|
|
|
|
const _ThreadIndex __num_threads = omp_get_num_threads();
|
|
|
|
const _DifferenceType __num_samples =
|
|
__gnu_parallel::_Settings::get().merge_oversampling * __num_threads;
|
|
|
|
_ValueType* __samples = static_cast<_ValueType*>
|
|
(::operator new(sizeof(_ValueType) * __k * __num_samples));
|
|
// Sample.
|
|
for (_SeqNumber __s = 0; __s < __k; ++__s)
|
|
for (_DifferenceType __i = 0; __i < __num_samples; ++__i)
|
|
{
|
|
_DifferenceType sample_index = static_cast<_DifferenceType>
|
|
(_GLIBCXX_PARALLEL_LENGTH(__seqs_begin[__s])
|
|
* (double(__i + 1) / (__num_samples + 1))
|
|
* (double(__length) / __total_length));
|
|
new(&(__samples[__s * __num_samples + __i]))
|
|
_ValueType(__seqs_begin[__s].first[sample_index]);
|
|
}
|
|
|
|
// Sort stable or non-stable, depending on value of template parameter
|
|
// "__stable".
|
|
_SamplingSorter<__stable, _ValueType*, _Compare>()
|
|
(__samples, __samples + (__num_samples * __k), __comp);
|
|
|
|
for (_ThreadIndex __slab = 0; __slab < __num_threads; ++__slab)
|
|
// For each slab / processor.
|
|
for (_SeqNumber __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]);
|
|
}
|
|
|
|
for (_SeqNumber __s = 0; __s < __k; ++__s)
|
|
for (_DifferenceType __i = 0; __i < __num_samples; ++__i)
|
|
__samples[__s * __num_samples + __i].~_ValueType();
|
|
::operator delete(__samples);
|
|
}
|
|
|
|
/**
|
|
* @brief Exact splitting for parallel multiway-merge routine.
|
|
*
|
|
* None of the passed sequences may be empty.
|
|
*/
|
|
template<bool __stable,
|
|
typename _RAIterIterator,
|
|
typename _Compare,
|
|
typename _DifferenceType>
|
|
void
|
|
multiway_merge_exact_splitting(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_DifferenceType __length,
|
|
_DifferenceType __total_length,
|
|
_Compare __comp,
|
|
std::vector<std::pair<_DifferenceType, _DifferenceType> > *__pieces)
|
|
{
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::difference_type _SeqNumber;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
|
|
const bool __tight = (__total_length == __length);
|
|
|
|
// __k sequences.
|
|
const _SeqNumber __k = __seqs_end - __seqs_begin;
|
|
|
|
const _ThreadIndex __num_threads = omp_get_num_threads();
|
|
|
|
// (Settings::multiway_merge_splitting
|
|
// == __gnu_parallel::_Settings::EXACT).
|
|
std::vector<_RAIter1>* __offsets =
|
|
new std::vector<_RAIter1>[__num_threads];
|
|
std::vector<std::pair<_RAIter1, _RAIter1> > __se(__k);
|
|
|
|
copy(__seqs_begin, __seqs_end, __se.begin());
|
|
|
|
_DifferenceType* __borders =
|
|
new _DifferenceType[__num_threads + 1];
|
|
__equally_split(__length, __num_threads, __borders);
|
|
|
|
for (_ThreadIndex __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(),
|
|
_DifferenceType(__length),
|
|
__offsets[__num_threads - 1].begin(),
|
|
__comp);
|
|
}
|
|
}
|
|
delete[] __borders;
|
|
|
|
for (_ThreadIndex __slab = 0; __slab < __num_threads; ++__slab)
|
|
{
|
|
// For each slab / processor.
|
|
for (_SeqNumber __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.
|
|
*
|
|
* @tparam _Splitter functor to split input (either __exact or sampling based)
|
|
* @tparam __stable Stable merging incurs a performance penalty.
|
|
* @tparam __sentinel Ignored.
|
|
*
|
|
* @param __seqs_begin Begin iterator of iterator pair input sequence.
|
|
* @param __seqs_end End iterator of iterator pair input sequence.
|
|
* @param __target Begin iterator of output sequence.
|
|
* @param __comp Comparator.
|
|
* @param __length Maximum length to merge, possibly larger than the
|
|
* number of elements available.
|
|
* @return End iterator of output sequence.
|
|
*/
|
|
template<bool __stable,
|
|
bool __sentinels,
|
|
typename _RAIterIterator,
|
|
typename _RAIter3,
|
|
typename _DifferenceTp,
|
|
typename _Splitter,
|
|
typename _Compare>
|
|
_RAIter3
|
|
parallel_multiway_merge(_RAIterIterator __seqs_begin,
|
|
_RAIterIterator __seqs_end,
|
|
_RAIter3 __target,
|
|
_Splitter __splitter,
|
|
_DifferenceTp __length,
|
|
_Compare __comp,
|
|
_ThreadIndex __num_threads)
|
|
{
|
|
#if _GLIBCXX_PARALLEL_ASSERTIONS
|
|
_GLIBCXX_PARALLEL_ASSERT(__seqs_end - __seqs_begin > 1);
|
|
#endif
|
|
|
|
_GLIBCXX_CALL(__length)
|
|
|
|
typedef _DifferenceTp _DifferenceType;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::difference_type _SeqNumber;
|
|
typedef typename std::iterator_traits<_RAIterIterator>
|
|
::value_type::first_type
|
|
_RAIter1;
|
|
typedef typename
|
|
std::iterator_traits<_RAIter1>::value_type _ValueType;
|
|
|
|
// Leave only non-empty sequences.
|
|
typedef std::pair<_RAIter1, _RAIter1> seq_type;
|
|
seq_type* __ne_seqs = new seq_type[__seqs_end - __seqs_begin];
|
|
_SeqNumber __k = 0;
|
|
_DifferenceType __total_length = 0;
|
|
for (_RAIterIterator __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<_DifferenceType, _DifferenceType> >* __pieces;
|
|
|
|
__num_threads = static_cast<_ThreadIndex>
|
|
(std::min<_DifferenceType>(__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<_DifferenceType, _DifferenceType> >[__num_threads];
|
|
for (_ThreadIndex __s = 0; __s < __num_threads; ++__s)
|
|
__pieces[__s].resize(__k);
|
|
|
|
_DifferenceType __num_samples =
|
|
__gnu_parallel::_Settings::get().merge_oversampling
|
|
* __num_threads;
|
|
|
|
__splitter(__ne_seqs, __ne_seqs + __k, __length, __total_length,
|
|
__comp, __pieces);
|
|
} //single
|
|
|
|
_ThreadIndex __iam = omp_get_thread_num();
|
|
|
|
_DifferenceType __target_position = 0;
|
|
|
|
for (_SeqNumber __c = 0; __c < __k; ++__c)
|
|
__target_position += __pieces[__iam][__c].first;
|
|
|
|
seq_type* __chunks = new seq_type[__k];
|
|
|
|
for (_SeqNumber __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_PARALLEL_ASSERTIONS
|
|
_GLIBCXX_PARALLEL_ASSERT(
|
|
__is_sorted(__target, __target + __length, __comp));
|
|
#endif
|
|
|
|
__k = 0;
|
|
// Update ends of sequences.
|
|
for (_RAIterIterator __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 _M_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).
|
|
*
|
|
* @tparam _RAIterPairIterator iterator over sequence
|
|
* of pairs of iterators
|
|
* @tparam _RAIterOut iterator over target sequence
|
|
* @tparam _DifferenceTp difference type for the sequence
|
|
* @tparam _Compare strict weak ordering type to compare elements
|
|
* in sequences
|
|
*
|
|
* @param __seqs_begin __begin of sequence __sequence
|
|
* @param __seqs_end _M_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 _M_end iterator of output sequence
|
|
*/
|
|
// multiway_merge
|
|
// public interface
|
|
template<typename _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
__gnu_parallel::sequential_tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
__gnu_parallel::exact_tag __tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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)
|
|
&& ((_SequenceIndex)__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<_RAIterPairIterator>
|
|
::value_type*, _Compare, _DifferenceTp>,
|
|
static_cast<_DifferenceType>(__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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
__gnu_parallel::sampling_tag __tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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)
|
|
&& ((_SequenceIndex)__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<_RAIterPairIterator>
|
|
::value_type*, _Compare, _DifferenceTp>,
|
|
static_cast<_DifferenceType>(__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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
__gnu_parallel::sequential_tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
__gnu_parallel::exact_tag __tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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)
|
|
&& ((_SequenceIndex)__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<_RAIterPairIterator>
|
|
::value_type*, _Compare, _DifferenceTp>,
|
|
static_cast<_DifferenceType>(__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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
sampling_tag __tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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)
|
|
&& ((_SequenceIndex)__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<_RAIterPairIterator>
|
|
::value_type*, _Compare, _DifferenceTp>,
|
|
static_cast<_DifferenceType>(__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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __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 _M_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 _M_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
|
|
*
|
|
* @tparam _RAIterPairIterator iterator over sequence
|
|
* of pairs of iterators
|
|
* @tparam _RAIterOut iterator over target sequence
|
|
* @tparam _DifferenceTp difference type for the sequence
|
|
* @tparam _Compare strict weak ordering type to compare elements
|
|
* in sequences
|
|
*
|
|
* @param __seqs_begin __begin of sequence __sequence
|
|
* @param __seqs_end _M_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 _M_end iterator of output sequence
|
|
*/
|
|
// multiway_merge_sentinels
|
|
// public interface
|
|
template<typename _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
__gnu_parallel::sequential_tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
__gnu_parallel::exact_tag __tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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)
|
|
&& ((_SequenceIndex)__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<_RAIterPairIterator>
|
|
::value_type*, _Compare, _DifferenceTp>,
|
|
static_cast<_DifferenceType>(__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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
sampling_tag __tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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)
|
|
&& ((_SequenceIndex)__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<_RAIterPairIterator>
|
|
::value_type*, _Compare, _DifferenceTp>,
|
|
static_cast<_DifferenceType>(__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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
__gnu_parallel::sequential_tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __comp,
|
|
__gnu_parallel::exact_tag __tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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)
|
|
&& ((_SequenceIndex)__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<_RAIterPairIterator>
|
|
::value_type*, _Compare, _DifferenceTp>,
|
|
static_cast<_DifferenceType>(__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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length,
|
|
_Compare __comp,
|
|
sampling_tag __tag)
|
|
{
|
|
typedef _DifferenceTp _DifferenceType;
|
|
_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)
|
|
&& ((_SequenceIndex)__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<_RAIterPairIterator>
|
|
::value_type*, _Compare, _DifferenceTp>,
|
|
static_cast<_DifferenceType>(__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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length,
|
|
_Compare __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 _RAIterPairIterator,
|
|
typename _RAIterOut,
|
|
typename _DifferenceTp,
|
|
typename _Compare>
|
|
_RAIterOut
|
|
stable_multiway_merge_sentinels(_RAIterPairIterator __seqs_begin,
|
|
_RAIterPairIterator __seqs_end,
|
|
_RAIterOut __target,
|
|
_DifferenceTp __length, _Compare __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 */
|