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