mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			645 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			645 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
| // -*- C++ -*-
 | ||
| 
 | ||
| // Copyright (C) 2007-2017 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/multiseq_selection.h
 | ||
|  *  @brief Functions to find elements of a certain global __rank in
 | ||
|  *  multiple sorted sequences.  Also serves for splitting such
 | ||
|  *  sequence sets.
 | ||
|  *
 | ||
|  *  The algorithm description can be found in 
 | ||
|  *
 | ||
|  *  P. J. Varman, S. D. Scheufler, B. R. Iyer, and G. R. Ricard.
 | ||
|  *  Merging Multiple Lists on Hierarchical-Memory Multiprocessors.
 | ||
|  *  Journal of Parallel and Distributed Computing, 12(2):171–177, 1991.
 | ||
|  *
 | ||
|  *  This file is a GNU parallel extension to the Standard C++ Library.
 | ||
|  */
 | ||
| 
 | ||
| // Written by Johannes Singler.
 | ||
| 
 | ||
| #ifndef _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H
 | ||
| #define _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H 1
 | ||
| 
 | ||
| #include <vector>
 | ||
| #include <queue>
 | ||
| 
 | ||
| #include <bits/stl_algo.h>
 | ||
| 
 | ||
| namespace __gnu_parallel
 | ||
| {
 | ||
|   /** @brief Compare __a pair of types lexicographically, ascending. */
 | ||
|   template<typename _T1, typename _T2, typename _Compare>
 | ||
|     class _Lexicographic
 | ||
|     : public std::binary_function<std::pair<_T1, _T2>,
 | ||
| 				  std::pair<_T1, _T2>, bool>
 | ||
|     {
 | ||
|     private:
 | ||
|       _Compare& _M_comp;
 | ||
| 
 | ||
|     public:
 | ||
|       _Lexicographic(_Compare& __comp) : _M_comp(__comp) { }
 | ||
| 
 | ||
|       bool
 | ||
|       operator()(const std::pair<_T1, _T2>& __p1,
 | ||
|                  const std::pair<_T1, _T2>& __p2) const
 | ||
|       {
 | ||
|         if (_M_comp(__p1.first, __p2.first))
 | ||
|           return true;
 | ||
| 
 | ||
|         if (_M_comp(__p2.first, __p1.first))
 | ||
|           return false;
 | ||
| 
 | ||
|         // Firsts are equal.
 | ||
|         return __p1.second < __p2.second;
 | ||
|       }
 | ||
|     };
 | ||
| 
 | ||
|   /** @brief Compare __a pair of types lexicographically, descending. */
 | ||
|   template<typename _T1, typename _T2, typename _Compare>
 | ||
|     class _LexicographicReverse : public std::binary_function<_T1, _T2, bool>
 | ||
|     {
 | ||
|     private:
 | ||
|       _Compare& _M_comp;
 | ||
| 
 | ||
|     public:
 | ||
|       _LexicographicReverse(_Compare& __comp) : _M_comp(__comp) { }
 | ||
| 
 | ||
|       bool
 | ||
|       operator()(const std::pair<_T1, _T2>& __p1,
 | ||
|                  const std::pair<_T1, _T2>& __p2) const
 | ||
|       {
 | ||
|         if (_M_comp(__p2.first, __p1.first))
 | ||
|           return true;
 | ||
| 
 | ||
|         if (_M_comp(__p1.first, __p2.first))
 | ||
|           return false;
 | ||
| 
 | ||
|         // Firsts are equal.
 | ||
|         return __p2.second < __p1.second;
 | ||
|       }
 | ||
|     };
 | ||
| 
 | ||
|   /** 
 | ||
|    *  @brief Splits several sorted sequences at a certain global __rank,
 | ||
|    *  resulting in a splitting point for each sequence.
 | ||
|    *  The sequences are passed via a sequence of random-access
 | ||
|    *  iterator pairs, none of the sequences may be empty.  If there
 | ||
|    *  are several equal elements across the split, the ones on the
 | ||
|    *  __left side will be chosen from sequences with smaller number.
 | ||
|    *  @param __begin_seqs Begin of the sequence of iterator pairs.
 | ||
|    *  @param __end_seqs End of the sequence of iterator pairs.
 | ||
|    *  @param __rank The global rank to partition at.
 | ||
|    *  @param __begin_offsets A random-access __sequence __begin where the
 | ||
|    *  __result will be stored in. Each element of the sequence is an
 | ||
|    *  iterator that points to the first element on the greater part of
 | ||
|    *  the respective __sequence.
 | ||
|    *  @param __comp The ordering functor, defaults to std::less<_Tp>. 
 | ||
|    */
 | ||
|   template<typename _RanSeqs, typename _RankType, typename _RankIterator,
 | ||
|             typename _Compare>
 | ||
|     void
 | ||
|     multiseq_partition(_RanSeqs __begin_seqs, _RanSeqs __end_seqs,
 | ||
|                        _RankType __rank,
 | ||
|                        _RankIterator __begin_offsets,
 | ||
|                        _Compare __comp = std::less<
 | ||
|                        typename std::iterator_traits<typename
 | ||
|                        std::iterator_traits<_RanSeqs>::value_type::
 | ||
|                        first_type>::value_type>()) // std::less<_Tp>
 | ||
|     {
 | ||
|       _GLIBCXX_CALL(__end_seqs - __begin_seqs)
 | ||
| 
 | ||
|       typedef typename std::iterator_traits<_RanSeqs>::value_type::first_type
 | ||
|         _It;
 | ||
|       typedef typename std::iterator_traits<_RanSeqs>::difference_type
 | ||
|         _SeqNumber;
 | ||
|       typedef typename std::iterator_traits<_It>::difference_type
 | ||
|                _DifferenceType;
 | ||
|       typedef typename std::iterator_traits<_It>::value_type _ValueType;
 | ||
| 
 | ||
|       _Lexicographic<_ValueType, _SeqNumber, _Compare> __lcomp(__comp);
 | ||
|       _LexicographicReverse<_ValueType, _SeqNumber, _Compare> __lrcomp(__comp);
 | ||
| 
 | ||
|       // Number of sequences, number of elements in total (possibly
 | ||
|       // including padding).
 | ||
|       _DifferenceType __m = std::distance(__begin_seqs, __end_seqs), __nn = 0,
 | ||
|                       __nmax, __n, __r;
 | ||
| 
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|         {
 | ||
|           __nn += std::distance(__begin_seqs[__i].first,
 | ||
|                                __begin_seqs[__i].second);
 | ||
|           _GLIBCXX_PARALLEL_ASSERT(
 | ||
|             std::distance(__begin_seqs[__i].first,
 | ||
|                           __begin_seqs[__i].second) > 0);
 | ||
|         }
 | ||
| 
 | ||
|       if (__rank == __nn)
 | ||
|         {
 | ||
|           for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|             __begin_offsets[__i] = __begin_seqs[__i].second; // Very end.
 | ||
|           // Return __m - 1;
 | ||
|           return;
 | ||
|         }
 | ||
| 
 | ||
|       _GLIBCXX_PARALLEL_ASSERT(__m != 0);
 | ||
|       _GLIBCXX_PARALLEL_ASSERT(__nn != 0);
 | ||
|       _GLIBCXX_PARALLEL_ASSERT(__rank >= 0);
 | ||
|       _GLIBCXX_PARALLEL_ASSERT(__rank < __nn);
 | ||
| 
 | ||
|       _DifferenceType* __ns = new _DifferenceType[__m];
 | ||
|       _DifferenceType* __a = new _DifferenceType[__m];
 | ||
|       _DifferenceType* __b = new _DifferenceType[__m];
 | ||
|       _DifferenceType __l;
 | ||
| 
 | ||
|       __ns[0] = std::distance(__begin_seqs[0].first, __begin_seqs[0].second);
 | ||
|       __nmax = __ns[0];
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|         {
 | ||
|           __ns[__i] = std::distance(__begin_seqs[__i].first,
 | ||
|                                     __begin_seqs[__i].second);
 | ||
|           __nmax = std::max(__nmax, __ns[__i]);
 | ||
|         }
 | ||
| 
 | ||
|       __r = __rd_log2(__nmax) + 1;
 | ||
| 
 | ||
|       // Pad all lists to this length, at least as long as any ns[__i],
 | ||
|       // equality iff __nmax = 2^__k - 1.
 | ||
|       __l = (1ULL << __r) - 1;
 | ||
| 
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|         {
 | ||
|           __a[__i] = 0;
 | ||
|           __b[__i] = __l;
 | ||
|         }
 | ||
|       __n = __l / 2;
 | ||
| 
 | ||
|       // Invariants:
 | ||
|       // 0 <= __a[__i] <= __ns[__i], 0 <= __b[__i] <= __l
 | ||
| 
 | ||
| #define __S(__i) (__begin_seqs[__i].first)
 | ||
| 
 | ||
|       // Initial partition.
 | ||
|       std::vector<std::pair<_ValueType, _SeqNumber> > __sample;
 | ||
| 
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|         if (__n < __ns[__i])    //__sequence long enough
 | ||
|           __sample.push_back(std::make_pair(__S(__i)[__n], __i));
 | ||
|       __gnu_sequential::sort(__sample.begin(), __sample.end(), __lcomp);
 | ||
| 
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)       //conceptual infinity
 | ||
|         if (__n >= __ns[__i])   //__sequence too short, conceptual infinity
 | ||
|           __sample.push_back(
 | ||
|             std::make_pair(__S(__i)[0] /*__dummy element*/, __i));
 | ||
| 
 | ||
|       _DifferenceType __localrank = __rank / __l;
 | ||
| 
 | ||
|       _SeqNumber __j;
 | ||
|       for (__j = 0;
 | ||
|            __j < __localrank && ((__n + 1) <= __ns[__sample[__j].second]);
 | ||
|            ++__j)
 | ||
|         __a[__sample[__j].second] += __n + 1;
 | ||
|       for (; __j < __m; __j++)
 | ||
|         __b[__sample[__j].second] -= __n + 1;
 | ||
|       
 | ||
|       // Further refinement.
 | ||
|       while (__n > 0)
 | ||
|         {
 | ||
|           __n /= 2;
 | ||
| 
 | ||
|           _SeqNumber __lmax_seq = -1;  // to avoid warning
 | ||
|           const _ValueType* __lmax = 0; // impossible to avoid the warning?
 | ||
|           for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|             {
 | ||
|               if (__a[__i] > 0)
 | ||
|                 {
 | ||
|                   if (!__lmax)
 | ||
|                     {
 | ||
|                       __lmax = &(__S(__i)[__a[__i] - 1]);
 | ||
|                       __lmax_seq = __i;
 | ||
|                     }
 | ||
|                   else
 | ||
|                     {
 | ||
|                       // Max, favor rear sequences.
 | ||
|                       if (!__comp(__S(__i)[__a[__i] - 1], *__lmax))
 | ||
|                         {
 | ||
|                           __lmax = &(__S(__i)[__a[__i] - 1]);
 | ||
|                           __lmax_seq = __i;
 | ||
|                         }
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|           _SeqNumber __i;
 | ||
|           for (__i = 0; __i < __m; __i++)
 | ||
|             {
 | ||
|               _DifferenceType __middle = (__b[__i] + __a[__i]) / 2;
 | ||
|               if (__lmax && __middle < __ns[__i] &&
 | ||
|                   __lcomp(std::make_pair(__S(__i)[__middle], __i),
 | ||
|                         std::make_pair(*__lmax, __lmax_seq)))
 | ||
|                 __a[__i] = std::min(__a[__i] + __n + 1, __ns[__i]);
 | ||
|               else
 | ||
|                 __b[__i] -= __n + 1;
 | ||
|             }
 | ||
| 
 | ||
|           _DifferenceType __leftsize = 0;
 | ||
|           for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|               __leftsize += __a[__i] / (__n + 1);
 | ||
| 
 | ||
|           _DifferenceType __skew = __rank / (__n + 1) - __leftsize;
 | ||
| 
 | ||
|           if (__skew > 0)
 | ||
|             {
 | ||
|               // Move to the left, find smallest.
 | ||
|               std::priority_queue<std::pair<_ValueType, _SeqNumber>,
 | ||
|                 std::vector<std::pair<_ValueType, _SeqNumber> >,
 | ||
|                 _LexicographicReverse<_ValueType, _SeqNumber, _Compare> >
 | ||
|                 __pq(__lrcomp);
 | ||
|               
 | ||
|               for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|                 if (__b[__i] < __ns[__i])
 | ||
|                   __pq.push(std::make_pair(__S(__i)[__b[__i]], __i));
 | ||
| 
 | ||
|               for (; __skew != 0 && !__pq.empty(); --__skew)
 | ||
|                 {
 | ||
|                   _SeqNumber __source = __pq.top().second;
 | ||
|                   __pq.pop();
 | ||
| 
 | ||
|                   __a[__source]
 | ||
|                       = std::min(__a[__source] + __n + 1, __ns[__source]);
 | ||
|                   __b[__source] += __n + 1;
 | ||
| 
 | ||
|                   if (__b[__source] < __ns[__source])
 | ||
|                     __pq.push(
 | ||
|                       std::make_pair(__S(__source)[__b[__source]], __source));
 | ||
|                 }
 | ||
|             }
 | ||
|           else if (__skew < 0)
 | ||
|             {
 | ||
|               // Move to the right, find greatest.
 | ||
|               std::priority_queue<std::pair<_ValueType, _SeqNumber>,
 | ||
|                 std::vector<std::pair<_ValueType, _SeqNumber> >,
 | ||
|                 _Lexicographic<_ValueType, _SeqNumber, _Compare> >
 | ||
|                   __pq(__lcomp);
 | ||
| 
 | ||
|               for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|                 if (__a[__i] > 0)
 | ||
|                   __pq.push(std::make_pair(__S(__i)[__a[__i] - 1], __i));
 | ||
| 
 | ||
|               for (; __skew != 0; ++__skew)
 | ||
|                 {
 | ||
|                   _SeqNumber __source = __pq.top().second;
 | ||
|                   __pq.pop();
 | ||
| 
 | ||
|                   __a[__source] -= __n + 1;
 | ||
|                   __b[__source] -= __n + 1;
 | ||
| 
 | ||
|                   if (__a[__source] > 0)
 | ||
|                     __pq.push(std::make_pair(
 | ||
|                         __S(__source)[__a[__source] - 1], __source));
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|       // Postconditions:
 | ||
|       // __a[__i] == __b[__i] in most cases, except when __a[__i] has been
 | ||
|       // clamped because of having reached the boundary
 | ||
| 
 | ||
|       // Now return the result, calculate the offset.
 | ||
| 
 | ||
|       // Compare the keys on both edges of the border.
 | ||
| 
 | ||
|       // Maximum of left edge, minimum of right edge.
 | ||
|       _ValueType* __maxleft = 0;
 | ||
|       _ValueType* __minright = 0;
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|         {
 | ||
|           if (__a[__i] > 0)
 | ||
|             {
 | ||
|               if (!__maxleft)
 | ||
|                 __maxleft = &(__S(__i)[__a[__i] - 1]);
 | ||
|               else
 | ||
|                 {
 | ||
|                   // Max, favor rear sequences.
 | ||
|                   if (!__comp(__S(__i)[__a[__i] - 1], *__maxleft))
 | ||
|                     __maxleft = &(__S(__i)[__a[__i] - 1]);
 | ||
|                 }
 | ||
|             }
 | ||
|           if (__b[__i] < __ns[__i])
 | ||
|             {
 | ||
|               if (!__minright)
 | ||
|                 __minright = &(__S(__i)[__b[__i]]);
 | ||
|               else
 | ||
|                 {
 | ||
|                   // Min, favor fore sequences.
 | ||
|                   if (__comp(__S(__i)[__b[__i]], *__minright))
 | ||
|                     __minright = &(__S(__i)[__b[__i]]);
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|       _SeqNumber __seq = 0;
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|         __begin_offsets[__i] = __S(__i) + __a[__i];
 | ||
| 
 | ||
|       delete[] __ns;
 | ||
|       delete[] __a;
 | ||
|       delete[] __b;
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|   /** 
 | ||
|    *  @brief Selects the element at a certain global __rank from several
 | ||
|    *  sorted sequences.
 | ||
|    *
 | ||
|    *  The sequences are passed via a sequence of random-access
 | ||
|    *  iterator pairs, none of the sequences may be empty.
 | ||
|    *  @param __begin_seqs Begin of the sequence of iterator pairs.
 | ||
|    *  @param __end_seqs End of the sequence of iterator pairs.
 | ||
|    *  @param __rank The global rank to partition at.
 | ||
|    *  @param __offset The rank of the selected element in the global
 | ||
|    *  subsequence of elements equal to the selected element. If the
 | ||
|    *  selected element is unique, this number is 0.
 | ||
|    *  @param __comp The ordering functor, defaults to std::less. 
 | ||
|    */
 | ||
|   template<typename _Tp, typename _RanSeqs, typename _RankType,
 | ||
|            typename _Compare>
 | ||
|     _Tp
 | ||
|     multiseq_selection(_RanSeqs __begin_seqs, _RanSeqs __end_seqs,
 | ||
|                        _RankType __rank,
 | ||
|                        _RankType& __offset, _Compare __comp = std::less<_Tp>())
 | ||
|     {
 | ||
|       _GLIBCXX_CALL(__end_seqs - __begin_seqs)
 | ||
| 
 | ||
|       typedef typename std::iterator_traits<_RanSeqs>::value_type::first_type
 | ||
|         _It;
 | ||
|       typedef typename std::iterator_traits<_RanSeqs>::difference_type
 | ||
|         _SeqNumber;
 | ||
|       typedef typename std::iterator_traits<_It>::difference_type
 | ||
|         _DifferenceType;
 | ||
| 
 | ||
|       _Lexicographic<_Tp, _SeqNumber, _Compare> __lcomp(__comp);
 | ||
|       _LexicographicReverse<_Tp, _SeqNumber, _Compare> __lrcomp(__comp);
 | ||
| 
 | ||
|       // Number of sequences, number of elements in total (possibly
 | ||
|       // including padding).
 | ||
|       _DifferenceType __m = std::distance(__begin_seqs, __end_seqs);
 | ||
|       _DifferenceType __nn = 0;
 | ||
|       _DifferenceType __nmax, __n, __r;
 | ||
| 
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|         __nn += std::distance(__begin_seqs[__i].first,
 | ||
| 			      __begin_seqs[__i].second);
 | ||
| 
 | ||
|       if (__m == 0 || __nn == 0 || __rank < 0 || __rank >= __nn)
 | ||
|         {
 | ||
|           // result undefined if there is no data or __rank is outside bounds
 | ||
|           throw std::exception();
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|       _DifferenceType* __ns = new _DifferenceType[__m];
 | ||
|       _DifferenceType* __a = new _DifferenceType[__m];
 | ||
|       _DifferenceType* __b = new _DifferenceType[__m];
 | ||
|       _DifferenceType __l;
 | ||
| 
 | ||
|       __ns[0] = std::distance(__begin_seqs[0].first, __begin_seqs[0].second);
 | ||
|       __nmax = __ns[0];
 | ||
|       for (_SeqNumber __i = 0; __i < __m; ++__i)
 | ||
|         {
 | ||
|           __ns[__i] = std::distance(__begin_seqs[__i].first,
 | ||
|                                     __begin_seqs[__i].second);
 | ||
|           __nmax = std::max(__nmax, __ns[__i]);
 | ||
|         }
 | ||
| 
 | ||
|       __r = __rd_log2(__nmax) + 1;
 | ||
| 
 | ||
|       // Pad all lists to this length, at least as long as any ns[__i],
 | ||
|       // equality iff __nmax = 2^__k - 1
 | ||
|       __l = __round_up_to_pow2(__r) - 1;
 | ||
| 
 | ||
|       for (_SeqNumber __i = 0; __i < __m; ++__i)
 | ||
|         {
 | ||
|           __a[__i] = 0;
 | ||
|           __b[__i] = __l;
 | ||
|         }
 | ||
|       __n = __l / 2;
 | ||
| 
 | ||
|       // Invariants:
 | ||
|       // 0 <= __a[__i] <= __ns[__i], 0 <= __b[__i] <= __l
 | ||
| 
 | ||
| #define __S(__i) (__begin_seqs[__i].first)
 | ||
| 
 | ||
|       // Initial partition.
 | ||
|       std::vector<std::pair<_Tp, _SeqNumber> > __sample;
 | ||
| 
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|         if (__n < __ns[__i])
 | ||
|           __sample.push_back(std::make_pair(__S(__i)[__n], __i));
 | ||
|       __gnu_sequential::sort(__sample.begin(), __sample.end(),
 | ||
|                              __lcomp, sequential_tag());
 | ||
| 
 | ||
|       // Conceptual infinity.
 | ||
|       for (_SeqNumber __i = 0; __i < __m; __i++)
 | ||
|         if (__n >= __ns[__i])
 | ||
|           __sample.push_back(
 | ||
|             std::make_pair(__S(__i)[0] /*__dummy element*/, __i));
 | ||
| 
 | ||
|       _DifferenceType __localrank = __rank / __l;
 | ||
| 
 | ||
|       _SeqNumber __j;
 | ||
|       for (__j = 0;
 | ||
|            __j < __localrank && ((__n + 1) <= __ns[__sample[__j].second]);
 | ||
|            ++__j)
 | ||
|         __a[__sample[__j].second] += __n + 1;
 | ||
|       for (; __j < __m; ++__j)
 | ||
|         __b[__sample[__j].second] -= __n + 1;
 | ||
| 
 | ||
|       // Further refinement.
 | ||
|       while (__n > 0)
 | ||
|         {
 | ||
|           __n /= 2;
 | ||
| 
 | ||
|           const _Tp* __lmax = 0;
 | ||
|           for (_SeqNumber __i = 0; __i < __m; ++__i)
 | ||
|             {
 | ||
|               if (__a[__i] > 0)
 | ||
|                 {
 | ||
|                   if (!__lmax)
 | ||
|                     __lmax = &(__S(__i)[__a[__i] - 1]);
 | ||
|                   else
 | ||
|                     {
 | ||
|                       if (__comp(*__lmax, __S(__i)[__a[__i] - 1]))      //max
 | ||
|                         __lmax = &(__S(__i)[__a[__i] - 1]);
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|           _SeqNumber __i;
 | ||
|           for (__i = 0; __i < __m; __i++)
 | ||
|             {
 | ||
|               _DifferenceType __middle = (__b[__i] + __a[__i]) / 2;
 | ||
|               if (__lmax && __middle < __ns[__i]
 | ||
|                   && __comp(__S(__i)[__middle], *__lmax))
 | ||
|                 __a[__i] = std::min(__a[__i] + __n + 1, __ns[__i]);
 | ||
|               else
 | ||
|                 __b[__i] -= __n + 1;
 | ||
|             }
 | ||
| 
 | ||
|           _DifferenceType __leftsize = 0;
 | ||
|           for (_SeqNumber __i = 0; __i < __m; ++__i)
 | ||
|               __leftsize += __a[__i] / (__n + 1);
 | ||
| 
 | ||
|           _DifferenceType __skew = __rank / (__n + 1) - __leftsize;
 | ||
| 
 | ||
|           if (__skew > 0)
 | ||
|             {
 | ||
|               // Move to the left, find smallest.
 | ||
|               std::priority_queue<std::pair<_Tp, _SeqNumber>,
 | ||
|                 std::vector<std::pair<_Tp, _SeqNumber> >,
 | ||
|                 _LexicographicReverse<_Tp, _SeqNumber, _Compare> >
 | ||
|                   __pq(__lrcomp);
 | ||
| 
 | ||
|               for (_SeqNumber __i = 0; __i < __m; ++__i)
 | ||
|                 if (__b[__i] < __ns[__i])
 | ||
|                   __pq.push(std::make_pair(__S(__i)[__b[__i]], __i));
 | ||
| 
 | ||
|               for (; __skew != 0 && !__pq.empty(); --__skew)
 | ||
|                 {
 | ||
|                   _SeqNumber __source = __pq.top().second;
 | ||
|                   __pq.pop();
 | ||
| 
 | ||
|                   __a[__source]
 | ||
|                       = std::min(__a[__source] + __n + 1, __ns[__source]);
 | ||
|                   __b[__source] += __n + 1;
 | ||
| 
 | ||
|                   if (__b[__source] < __ns[__source])
 | ||
|                     __pq.push(
 | ||
|                       std::make_pair(__S(__source)[__b[__source]], __source));
 | ||
|                 }
 | ||
|             }
 | ||
|           else if (__skew < 0)
 | ||
|             {
 | ||
|               // Move to the right, find greatest.
 | ||
|               std::priority_queue<std::pair<_Tp, _SeqNumber>,
 | ||
|                 std::vector<std::pair<_Tp, _SeqNumber> >,
 | ||
|                 _Lexicographic<_Tp, _SeqNumber, _Compare> > __pq(__lcomp);
 | ||
| 
 | ||
|               for (_SeqNumber __i = 0; __i < __m; ++__i)
 | ||
|                 if (__a[__i] > 0)
 | ||
|                   __pq.push(std::make_pair(__S(__i)[__a[__i] - 1], __i));
 | ||
| 
 | ||
|               for (; __skew != 0; ++__skew)
 | ||
|                 {
 | ||
|                   _SeqNumber __source = __pq.top().second;
 | ||
|                   __pq.pop();
 | ||
| 
 | ||
|                   __a[__source] -= __n + 1;
 | ||
|                   __b[__source] -= __n + 1;
 | ||
| 
 | ||
|                   if (__a[__source] > 0)
 | ||
|                     __pq.push(std::make_pair(
 | ||
|                         __S(__source)[__a[__source] - 1], __source));
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|       // Postconditions:
 | ||
|       // __a[__i] == __b[__i] in most cases, except when __a[__i] has been
 | ||
|       // clamped because of having reached the boundary
 | ||
| 
 | ||
|       // Now return the result, calculate the offset.
 | ||
| 
 | ||
|       // Compare the keys on both edges of the border.
 | ||
| 
 | ||
|       // Maximum of left edge, minimum of right edge.
 | ||
|       bool __maxleftset = false, __minrightset = false;
 | ||
| 
 | ||
|       // Impossible to avoid the warning?
 | ||
|       _Tp __maxleft, __minright;
 | ||
|       for (_SeqNumber __i = 0; __i < __m; ++__i)
 | ||
|         {
 | ||
|           if (__a[__i] > 0)
 | ||
|             {
 | ||
|               if (!__maxleftset)
 | ||
|                 {
 | ||
|                   __maxleft = __S(__i)[__a[__i] - 1];
 | ||
|                   __maxleftset = true;
 | ||
|                 }
 | ||
|               else
 | ||
|                 {
 | ||
|                   // Max.
 | ||
|                   if (__comp(__maxleft, __S(__i)[__a[__i] - 1]))
 | ||
|                     __maxleft = __S(__i)[__a[__i] - 1];
 | ||
|                 }
 | ||
|             }
 | ||
|           if (__b[__i] < __ns[__i])
 | ||
|             {
 | ||
|               if (!__minrightset)
 | ||
|                 {
 | ||
|                   __minright = __S(__i)[__b[__i]];
 | ||
|                   __minrightset = true;
 | ||
|                 }
 | ||
|               else
 | ||
|                 {
 | ||
|                   // Min.
 | ||
|                   if (__comp(__S(__i)[__b[__i]], __minright))
 | ||
|                     __minright = __S(__i)[__b[__i]];
 | ||
|                 }
 | ||
|             }
 | ||
|       }
 | ||
| 
 | ||
|       // Minright is the __splitter, in any case.
 | ||
| 
 | ||
|       if (!__maxleftset || __comp(__minright, __maxleft))
 | ||
|         {
 | ||
|           // Good luck, everything is split unambiguously.
 | ||
|           __offset = 0;
 | ||
|         }
 | ||
|       else
 | ||
|         {
 | ||
|           // We have to calculate an offset.
 | ||
|           __offset = 0;
 | ||
| 
 | ||
|           for (_SeqNumber __i = 0; __i < __m; ++__i)
 | ||
|             {
 | ||
|               _DifferenceType lb
 | ||
|                 = std::lower_bound(__S(__i), __S(__i) + __ns[__i],
 | ||
|                                    __minright,
 | ||
|                                    __comp) - __S(__i);
 | ||
|               __offset += __a[__i] - lb;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|       delete[] __ns;
 | ||
|       delete[] __a;
 | ||
|       delete[] __b;
 | ||
| 
 | ||
|       return __minright;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| #undef __S
 | ||
| 
 | ||
| #endif /* _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H */
 |