libstdc++
|
00001 // -*- C++ -*- 00002 00003 // Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc. 00004 // 00005 // This file is part of the GNU ISO C++ Library. This library is free 00006 // software; you can redistribute it and/or modify it under the terms 00007 // of the GNU General Public License as published by the Free Software 00008 // Foundation; either version 3, or (at your option) any later 00009 // version. 00010 00011 // This library is distributed in the hope that it will be useful, but 00012 // WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 // General Public License for more details. 00015 00016 // Under Section 7 of GPL version 3, you are granted additional 00017 // permissions described in the GCC Runtime Library Exception, version 00018 // 3.1, as published by the Free Software Foundation. 00019 00020 // You should have received a copy of the GNU General Public License and 00021 // a copy of the GCC Runtime Library Exception along with this program; 00022 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00023 // <http://www.gnu.org/licenses/>. 00024 00025 /** @file parallel/multiseq_selection.h 00026 * @brief Functions to find elements of a certain global __rank in 00027 * multiple sorted sequences. Also serves for splitting such 00028 * sequence sets. 00029 * 00030 * The algorithm description can be found in 00031 * 00032 * P. J. Varman, S. D. Scheufler, B. R. Iyer, and G. R. Ricard. 00033 * Merging Multiple Lists on Hierarchical-Memory Multiprocessors. 00034 * Journal of Parallel and Distributed Computing, 12(2):171–177, 1991. 00035 * 00036 * This file is a GNU parallel extension to the Standard C++ Library. 00037 */ 00038 00039 // Written by Johannes Singler. 00040 00041 #ifndef _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H 00042 #define _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H 1 00043 00044 #include <vector> 00045 #include <queue> 00046 00047 #include <bits/stl_algo.h> 00048 00049 #include <parallel/sort.h> 00050 00051 namespace __gnu_parallel 00052 { 00053 /** @brief Compare __a pair of types lexicographically, ascending. */ 00054 template<typename _T1, typename _T2, typename _Compare> 00055 class _Lexicographic 00056 : public std::binary_function<std::pair<_T1, _T2>, 00057 std::pair<_T1, _T2>, bool> 00058 { 00059 private: 00060 _Compare& _M_comp; 00061 00062 public: 00063 _Lexicographic(_Compare& __comp) : _M_comp(__comp) { } 00064 00065 bool 00066 operator()(const std::pair<_T1, _T2>& __p1, 00067 const std::pair<_T1, _T2>& __p2) const 00068 { 00069 if (_M_comp(__p1.first, __p2.first)) 00070 return true; 00071 00072 if (_M_comp(__p2.first, __p1.first)) 00073 return false; 00074 00075 // Firsts are equal. 00076 return __p1.second < __p2.second; 00077 } 00078 }; 00079 00080 /** @brief Compare __a pair of types lexicographically, descending. */ 00081 template<typename _T1, typename _T2, typename _Compare> 00082 class _LexicographicReverse : public std::binary_function<_T1, _T2, bool> 00083 { 00084 private: 00085 _Compare& _M_comp; 00086 00087 public: 00088 _LexicographicReverse(_Compare& __comp) : _M_comp(__comp) { } 00089 00090 bool 00091 operator()(const std::pair<_T1, _T2>& __p1, 00092 const std::pair<_T1, _T2>& __p2) const 00093 { 00094 if (_M_comp(__p2.first, __p1.first)) 00095 return true; 00096 00097 if (_M_comp(__p1.first, __p2.first)) 00098 return false; 00099 00100 // Firsts are equal. 00101 return __p2.second < __p1.second; 00102 } 00103 }; 00104 00105 /** 00106 * @brief Splits several sorted sequences at a certain global __rank, 00107 * resulting in a splitting point for each sequence. 00108 * The sequences are passed via a sequence of random-access 00109 * iterator pairs, none of the sequences may be empty. If there 00110 * are several equal elements across the split, the ones on the 00111 * __left side will be chosen from sequences with smaller number. 00112 * @param __begin_seqs Begin of the sequence of iterator pairs. 00113 * @param __end_seqs End of the sequence of iterator pairs. 00114 * @param __rank The global rank to partition at. 00115 * @param __begin_offsets A random-access __sequence __begin where the 00116 * __result will be stored in. Each element of the sequence is an 00117 * iterator that points to the first element on the greater part of 00118 * the respective __sequence. 00119 * @param __comp The ordering functor, defaults to std::less<_Tp>. 00120 */ 00121 template<typename _RanSeqs, typename _RankType, typename _RankIterator, 00122 typename _Compare> 00123 void 00124 multiseq_partition(_RanSeqs __begin_seqs, _RanSeqs __end_seqs, 00125 _RankType __rank, 00126 _RankIterator __begin_offsets, 00127 _Compare __comp = std::less< 00128 typename std::iterator_traits<typename 00129 std::iterator_traits<_RanSeqs>::value_type:: 00130 first_type>::value_type>()) // std::less<_Tp> 00131 { 00132 _GLIBCXX_CALL(__end_seqs - __begin_seqs) 00133 00134 typedef typename std::iterator_traits<_RanSeqs>::value_type::first_type 00135 _It; 00136 typedef typename std::iterator_traits<_RanSeqs>::difference_type 00137 _SeqNumber; 00138 typedef typename std::iterator_traits<_It>::difference_type 00139 _DifferenceType; 00140 typedef typename std::iterator_traits<_It>::value_type _ValueType; 00141 00142 _Lexicographic<_ValueType, _SeqNumber, _Compare> __lcomp(__comp); 00143 _LexicographicReverse<_ValueType, _SeqNumber, _Compare> __lrcomp(__comp); 00144 00145 // Number of sequences, number of elements in total (possibly 00146 // including padding). 00147 _DifferenceType __m = std::distance(__begin_seqs, __end_seqs), __nn = 0, 00148 __nmax, __n, __r; 00149 00150 for (_SeqNumber __i = 0; __i < __m; __i++) 00151 { 00152 __nn += std::distance(__begin_seqs[__i].first, 00153 __begin_seqs[__i].second); 00154 _GLIBCXX_PARALLEL_ASSERT( 00155 std::distance(__begin_seqs[__i].first, 00156 __begin_seqs[__i].second) > 0); 00157 } 00158 00159 if (__rank == __nn) 00160 { 00161 for (_SeqNumber __i = 0; __i < __m; __i++) 00162 __begin_offsets[__i] = __begin_seqs[__i].second; // Very end. 00163 // Return __m - 1; 00164 return; 00165 } 00166 00167 _GLIBCXX_PARALLEL_ASSERT(__m != 0); 00168 _GLIBCXX_PARALLEL_ASSERT(__nn != 0); 00169 _GLIBCXX_PARALLEL_ASSERT(__rank >= 0); 00170 _GLIBCXX_PARALLEL_ASSERT(__rank < __nn); 00171 00172 _DifferenceType* __ns = new _DifferenceType[__m]; 00173 _DifferenceType* __a = new _DifferenceType[__m]; 00174 _DifferenceType* __b = new _DifferenceType[__m]; 00175 _DifferenceType __l; 00176 00177 __ns[0] = std::distance(__begin_seqs[0].first, __begin_seqs[0].second); 00178 __nmax = __ns[0]; 00179 for (_SeqNumber __i = 0; __i < __m; __i++) 00180 { 00181 __ns[__i] = std::distance(__begin_seqs[__i].first, 00182 __begin_seqs[__i].second); 00183 __nmax = std::max(__nmax, __ns[__i]); 00184 } 00185 00186 __r = __rd_log2(__nmax) + 1; 00187 00188 // Pad all lists to this length, at least as long as any ns[__i], 00189 // equality iff __nmax = 2^__k - 1. 00190 __l = (1ULL << __r) - 1; 00191 00192 for (_SeqNumber __i = 0; __i < __m; __i++) 00193 { 00194 __a[__i] = 0; 00195 __b[__i] = __l; 00196 } 00197 __n = __l / 2; 00198 00199 // Invariants: 00200 // 0 <= __a[__i] <= __ns[__i], 0 <= __b[__i] <= __l 00201 00202 #define __S(__i) (__begin_seqs[__i].first) 00203 00204 // Initial partition. 00205 std::vector<std::pair<_ValueType, _SeqNumber> > __sample; 00206 00207 for (_SeqNumber __i = 0; __i < __m; __i++) 00208 if (__n < __ns[__i]) //__sequence long enough 00209 __sample.push_back(std::make_pair(__S(__i)[__n], __i)); 00210 __gnu_sequential::sort(__sample.begin(), __sample.end(), __lcomp); 00211 00212 for (_SeqNumber __i = 0; __i < __m; __i++) //conceptual infinity 00213 if (__n >= __ns[__i]) //__sequence too short, conceptual infinity 00214 __sample.push_back( 00215 std::make_pair(__S(__i)[0] /*__dummy element*/, __i)); 00216 00217 _DifferenceType __localrank = __rank / __l; 00218 00219 _SeqNumber __j; 00220 for (__j = 0; 00221 __j < __localrank && ((__n + 1) <= __ns[__sample[__j].second]); 00222 ++__j) 00223 __a[__sample[__j].second] += __n + 1; 00224 for (; __j < __m; __j++) 00225 __b[__sample[__j].second] -= __n + 1; 00226 00227 // Further refinement. 00228 while (__n > 0) 00229 { 00230 __n /= 2; 00231 00232 _SeqNumber __lmax_seq = -1; // to avoid warning 00233 const _ValueType* __lmax = 0; // impossible to avoid the warning? 00234 for (_SeqNumber __i = 0; __i < __m; __i++) 00235 { 00236 if (__a[__i] > 0) 00237 { 00238 if (!__lmax) 00239 { 00240 __lmax = &(__S(__i)[__a[__i] - 1]); 00241 __lmax_seq = __i; 00242 } 00243 else 00244 { 00245 // Max, favor rear sequences. 00246 if (!__comp(__S(__i)[__a[__i] - 1], *__lmax)) 00247 { 00248 __lmax = &(__S(__i)[__a[__i] - 1]); 00249 __lmax_seq = __i; 00250 } 00251 } 00252 } 00253 } 00254 00255 _SeqNumber __i; 00256 for (__i = 0; __i < __m; __i++) 00257 { 00258 _DifferenceType __middle = (__b[__i] + __a[__i]) / 2; 00259 if (__lmax && __middle < __ns[__i] && 00260 __lcomp(std::make_pair(__S(__i)[__middle], __i), 00261 std::make_pair(*__lmax, __lmax_seq))) 00262 __a[__i] = std::min(__a[__i] + __n + 1, __ns[__i]); 00263 else 00264 __b[__i] -= __n + 1; 00265 } 00266 00267 _DifferenceType __leftsize = 0; 00268 for (_SeqNumber __i = 0; __i < __m; __i++) 00269 __leftsize += __a[__i] / (__n + 1); 00270 00271 _DifferenceType __skew = __rank / (__n + 1) - __leftsize; 00272 00273 if (__skew > 0) 00274 { 00275 // Move to the left, find smallest. 00276 std::priority_queue<std::pair<_ValueType, _SeqNumber>, 00277 std::vector<std::pair<_ValueType, _SeqNumber> >, 00278 _LexicographicReverse<_ValueType, _SeqNumber, _Compare> > 00279 __pq(__lrcomp); 00280 00281 for (_SeqNumber __i = 0; __i < __m; __i++) 00282 if (__b[__i] < __ns[__i]) 00283 __pq.push(std::make_pair(__S(__i)[__b[__i]], __i)); 00284 00285 for (; __skew != 0 && !__pq.empty(); --__skew) 00286 { 00287 _SeqNumber __source = __pq.top().second; 00288 __pq.pop(); 00289 00290 __a[__source] 00291 = std::min(__a[__source] + __n + 1, __ns[__source]); 00292 __b[__source] += __n + 1; 00293 00294 if (__b[__source] < __ns[__source]) 00295 __pq.push( 00296 std::make_pair(__S(__source)[__b[__source]], __source)); 00297 } 00298 } 00299 else if (__skew < 0) 00300 { 00301 // Move to the right, find greatest. 00302 std::priority_queue<std::pair<_ValueType, _SeqNumber>, 00303 std::vector<std::pair<_ValueType, _SeqNumber> >, 00304 _Lexicographic<_ValueType, _SeqNumber, _Compare> > 00305 __pq(__lcomp); 00306 00307 for (_SeqNumber __i = 0; __i < __m; __i++) 00308 if (__a[__i] > 0) 00309 __pq.push(std::make_pair(__S(__i)[__a[__i] - 1], __i)); 00310 00311 for (; __skew != 0; ++__skew) 00312 { 00313 _SeqNumber __source = __pq.top().second; 00314 __pq.pop(); 00315 00316 __a[__source] -= __n + 1; 00317 __b[__source] -= __n + 1; 00318 00319 if (__a[__source] > 0) 00320 __pq.push(std::make_pair( 00321 __S(__source)[__a[__source] - 1], __source)); 00322 } 00323 } 00324 } 00325 00326 // Postconditions: 00327 // __a[__i] == __b[__i] in most cases, except when __a[__i] has been 00328 // clamped because of having reached the boundary 00329 00330 // Now return the result, calculate the offset. 00331 00332 // Compare the keys on both edges of the border. 00333 00334 // Maximum of left edge, minimum of right edge. 00335 _ValueType* __maxleft = 0; 00336 _ValueType* __minright = 0; 00337 for (_SeqNumber __i = 0; __i < __m; __i++) 00338 { 00339 if (__a[__i] > 0) 00340 { 00341 if (!__maxleft) 00342 __maxleft = &(__S(__i)[__a[__i] - 1]); 00343 else 00344 { 00345 // Max, favor rear sequences. 00346 if (!__comp(__S(__i)[__a[__i] - 1], *__maxleft)) 00347 __maxleft = &(__S(__i)[__a[__i] - 1]); 00348 } 00349 } 00350 if (__b[__i] < __ns[__i]) 00351 { 00352 if (!__minright) 00353 __minright = &(__S(__i)[__b[__i]]); 00354 else 00355 { 00356 // Min, favor fore sequences. 00357 if (__comp(__S(__i)[__b[__i]], *__minright)) 00358 __minright = &(__S(__i)[__b[__i]]); 00359 } 00360 } 00361 } 00362 00363 _SeqNumber __seq = 0; 00364 for (_SeqNumber __i = 0; __i < __m; __i++) 00365 __begin_offsets[__i] = __S(__i) + __a[__i]; 00366 00367 delete[] __ns; 00368 delete[] __a; 00369 delete[] __b; 00370 } 00371 00372 00373 /** 00374 * @brief Selects the element at a certain global __rank from several 00375 * sorted sequences. 00376 * 00377 * The sequences are passed via a sequence of random-access 00378 * iterator pairs, none of the sequences may be empty. 00379 * @param __begin_seqs Begin of the sequence of iterator pairs. 00380 * @param __end_seqs End of the sequence of iterator pairs. 00381 * @param __rank The global rank to partition at. 00382 * @param __offset The rank of the selected element in the global 00383 * subsequence of elements equal to the selected element. If the 00384 * selected element is unique, this number is 0. 00385 * @param __comp The ordering functor, defaults to std::less. 00386 */ 00387 template<typename _Tp, typename _RanSeqs, typename _RankType, 00388 typename _Compare> 00389 _Tp 00390 multiseq_selection(_RanSeqs __begin_seqs, _RanSeqs __end_seqs, 00391 _RankType __rank, 00392 _RankType& __offset, _Compare __comp = std::less<_Tp>()) 00393 { 00394 _GLIBCXX_CALL(__end_seqs - __begin_seqs) 00395 00396 typedef typename std::iterator_traits<_RanSeqs>::value_type::first_type 00397 _It; 00398 typedef typename std::iterator_traits<_RanSeqs>::difference_type 00399 _SeqNumber; 00400 typedef typename std::iterator_traits<_It>::difference_type 00401 _DifferenceType; 00402 00403 _Lexicographic<_Tp, _SeqNumber, _Compare> __lcomp(__comp); 00404 _LexicographicReverse<_Tp, _SeqNumber, _Compare> __lrcomp(__comp); 00405 00406 // Number of sequences, number of elements in total (possibly 00407 // including padding). 00408 _DifferenceType __m = std::distance(__begin_seqs, __end_seqs); 00409 _DifferenceType __nn = 0; 00410 _DifferenceType __nmax, __n, __r; 00411 00412 for (_SeqNumber __i = 0; __i < __m; __i++) 00413 __nn += std::distance(__begin_seqs[__i].first, 00414 __begin_seqs[__i].second); 00415 00416 if (__m == 0 || __nn == 0 || __rank < 0 || __rank >= __nn) 00417 { 00418 // result undefined if there is no data or __rank is outside bounds 00419 throw std::exception(); 00420 } 00421 00422 00423 _DifferenceType* __ns = new _DifferenceType[__m]; 00424 _DifferenceType* __a = new _DifferenceType[__m]; 00425 _DifferenceType* __b = new _DifferenceType[__m]; 00426 _DifferenceType __l; 00427 00428 __ns[0] = std::distance(__begin_seqs[0].first, __begin_seqs[0].second); 00429 __nmax = __ns[0]; 00430 for (_SeqNumber __i = 0; __i < __m; ++__i) 00431 { 00432 __ns[__i] = std::distance(__begin_seqs[__i].first, 00433 __begin_seqs[__i].second); 00434 __nmax = std::max(__nmax, __ns[__i]); 00435 } 00436 00437 __r = __rd_log2(__nmax) + 1; 00438 00439 // Pad all lists to this length, at least as long as any ns[__i], 00440 // equality iff __nmax = 2^__k - 1 00441 __l = __round_up_to_pow2(__r) - 1; 00442 00443 for (_SeqNumber __i = 0; __i < __m; ++__i) 00444 { 00445 __a[__i] = 0; 00446 __b[__i] = __l; 00447 } 00448 __n = __l / 2; 00449 00450 // Invariants: 00451 // 0 <= __a[__i] <= __ns[__i], 0 <= __b[__i] <= __l 00452 00453 #define __S(__i) (__begin_seqs[__i].first) 00454 00455 // Initial partition. 00456 std::vector<std::pair<_Tp, _SeqNumber> > __sample; 00457 00458 for (_SeqNumber __i = 0; __i < __m; __i++) 00459 if (__n < __ns[__i]) 00460 __sample.push_back(std::make_pair(__S(__i)[__n], __i)); 00461 __gnu_sequential::sort(__sample.begin(), __sample.end(), 00462 __lcomp, sequential_tag()); 00463 00464 // Conceptual infinity. 00465 for (_SeqNumber __i = 0; __i < __m; __i++) 00466 if (__n >= __ns[__i]) 00467 __sample.push_back( 00468 std::make_pair(__S(__i)[0] /*__dummy element*/, __i)); 00469 00470 _DifferenceType __localrank = __rank / __l; 00471 00472 _SeqNumber __j; 00473 for (__j = 0; 00474 __j < __localrank && ((__n + 1) <= __ns[__sample[__j].second]); 00475 ++__j) 00476 __a[__sample[__j].second] += __n + 1; 00477 for (; __j < __m; ++__j) 00478 __b[__sample[__j].second] -= __n + 1; 00479 00480 // Further refinement. 00481 while (__n > 0) 00482 { 00483 __n /= 2; 00484 00485 const _Tp* __lmax = 0; 00486 for (_SeqNumber __i = 0; __i < __m; ++__i) 00487 { 00488 if (__a[__i] > 0) 00489 { 00490 if (!__lmax) 00491 __lmax = &(__S(__i)[__a[__i] - 1]); 00492 else 00493 { 00494 if (__comp(*__lmax, __S(__i)[__a[__i] - 1])) //max 00495 __lmax = &(__S(__i)[__a[__i] - 1]); 00496 } 00497 } 00498 } 00499 00500 _SeqNumber __i; 00501 for (__i = 0; __i < __m; __i++) 00502 { 00503 _DifferenceType __middle = (__b[__i] + __a[__i]) / 2; 00504 if (__lmax && __middle < __ns[__i] 00505 && __comp(__S(__i)[__middle], *__lmax)) 00506 __a[__i] = std::min(__a[__i] + __n + 1, __ns[__i]); 00507 else 00508 __b[__i] -= __n + 1; 00509 } 00510 00511 _DifferenceType __leftsize = 0; 00512 for (_SeqNumber __i = 0; __i < __m; ++__i) 00513 __leftsize += __a[__i] / (__n + 1); 00514 00515 _DifferenceType __skew = __rank / (__n + 1) - __leftsize; 00516 00517 if (__skew > 0) 00518 { 00519 // Move to the left, find smallest. 00520 std::priority_queue<std::pair<_Tp, _SeqNumber>, 00521 std::vector<std::pair<_Tp, _SeqNumber> >, 00522 _LexicographicReverse<_Tp, _SeqNumber, _Compare> > 00523 __pq(__lrcomp); 00524 00525 for (_SeqNumber __i = 0; __i < __m; ++__i) 00526 if (__b[__i] < __ns[__i]) 00527 __pq.push(std::make_pair(__S(__i)[__b[__i]], __i)); 00528 00529 for (; __skew != 0 && !__pq.empty(); --__skew) 00530 { 00531 _SeqNumber __source = __pq.top().second; 00532 __pq.pop(); 00533 00534 __a[__source] 00535 = std::min(__a[__source] + __n + 1, __ns[__source]); 00536 __b[__source] += __n + 1; 00537 00538 if (__b[__source] < __ns[__source]) 00539 __pq.push( 00540 std::make_pair(__S(__source)[__b[__source]], __source)); 00541 } 00542 } 00543 else if (__skew < 0) 00544 { 00545 // Move to the right, find greatest. 00546 std::priority_queue<std::pair<_Tp, _SeqNumber>, 00547 std::vector<std::pair<_Tp, _SeqNumber> >, 00548 _Lexicographic<_Tp, _SeqNumber, _Compare> > __pq(__lcomp); 00549 00550 for (_SeqNumber __i = 0; __i < __m; ++__i) 00551 if (__a[__i] > 0) 00552 __pq.push(std::make_pair(__S(__i)[__a[__i] - 1], __i)); 00553 00554 for (; __skew != 0; ++__skew) 00555 { 00556 _SeqNumber __source = __pq.top().second; 00557 __pq.pop(); 00558 00559 __a[__source] -= __n + 1; 00560 __b[__source] -= __n + 1; 00561 00562 if (__a[__source] > 0) 00563 __pq.push(std::make_pair( 00564 __S(__source)[__a[__source] - 1], __source)); 00565 } 00566 } 00567 } 00568 00569 // Postconditions: 00570 // __a[__i] == __b[__i] in most cases, except when __a[__i] has been 00571 // clamped because of having reached the boundary 00572 00573 // Now return the result, calculate the offset. 00574 00575 // Compare the keys on both edges of the border. 00576 00577 // Maximum of left edge, minimum of right edge. 00578 bool __maxleftset = false, __minrightset = false; 00579 00580 // Impossible to avoid the warning? 00581 _Tp __maxleft, __minright; 00582 for (_SeqNumber __i = 0; __i < __m; ++__i) 00583 { 00584 if (__a[__i] > 0) 00585 { 00586 if (!__maxleftset) 00587 { 00588 __maxleft = __S(__i)[__a[__i] - 1]; 00589 __maxleftset = true; 00590 } 00591 else 00592 { 00593 // Max. 00594 if (__comp(__maxleft, __S(__i)[__a[__i] - 1])) 00595 __maxleft = __S(__i)[__a[__i] - 1]; 00596 } 00597 } 00598 if (__b[__i] < __ns[__i]) 00599 { 00600 if (!__minrightset) 00601 { 00602 __minright = __S(__i)[__b[__i]]; 00603 __minrightset = true; 00604 } 00605 else 00606 { 00607 // Min. 00608 if (__comp(__S(__i)[__b[__i]], __minright)) 00609 __minright = __S(__i)[__b[__i]]; 00610 } 00611 } 00612 } 00613 00614 // Minright is the __splitter, in any case. 00615 00616 if (!__maxleftset || __comp(__minright, __maxleft)) 00617 { 00618 // Good luck, everything is split unambiguously. 00619 __offset = 0; 00620 } 00621 else 00622 { 00623 // We have to calculate an offset. 00624 __offset = 0; 00625 00626 for (_SeqNumber __i = 0; __i < __m; ++__i) 00627 { 00628 _DifferenceType lb 00629 = std::lower_bound(__S(__i), __S(__i) + __ns[__i], 00630 __minright, 00631 __comp) - __S(__i); 00632 __offset += __a[__i] - lb; 00633 } 00634 } 00635 00636 delete[] __ns; 00637 delete[] __a; 00638 delete[] __b; 00639 00640 return __minright; 00641 } 00642 } 00643 00644 #undef __S 00645 00646 #endif /* _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H */