1 // -*- C++ -*- 2 3 // Copyright (C) 2007-2013 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the terms 7 // of the GNU General Public License as published by the Free Software 8 // Foundation; either version 3, or (at your option) any later 9 // version. 10 11 // This library is distributed in the hope that it will be useful, but 12 // WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 // General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file parallel/losertree.h 26 * @brief Many generic loser tree variants. 27 * This file is a GNU parallel extension to the Standard C++ Library. 28 */ 29 30 // Written by Johannes Singler. 31 32 #ifndef _GLIBCXX_PARALLEL_LOSERTREE_H 33 #define _GLIBCXX_PARALLEL_LOSERTREE_H 1 34 35 #include <bits/stl_algobase.h> 36 #include <bits/stl_function.h> 37 #include <parallel/features.h> 38 #include <parallel/base.h> 39 40 namespace __gnu_parallel 41 { 42 /** 43 * @brief Guarded loser/tournament tree. 44 * 45 * The smallest element is at the top. 46 * 47 * Guarding is done explicitly through one flag _M_sup per element, 48 * inf is not needed due to a better initialization routine. This 49 * is a well-performing variant. 50 * 51 * @param _Tp the element type 52 * @param _Compare the comparator to use, defaults to std::less<_Tp> 53 */ 54 template<typename _Tp, typename _Compare> 55 class _LoserTreeBase 56 { 57 protected: 58 /** @brief Internal representation of a _LoserTree element. */ 59 struct _Loser 60 { 61 /** @brief flag, true iff this is a "maximum" __sentinel. */ 62 bool _M_sup; 63 /** @brief __index of the __source __sequence. */ 64 int _M_source; 65 /** @brief _M_key of the element in the _LoserTree. */ 66 _Tp _M_key; 67 }; 68 69 unsigned int _M_ik, _M_k, _M_offset; 70 71 /** log_2{_M_k} */ 72 unsigned int _M_log_k; 73 74 /** @brief _LoserTree __elements. */ 75 _Loser* _M_losers; 76 77 /** @brief _Compare to use. */ 78 _Compare _M_comp; 79 80 /** 81 * @brief State flag that determines whether the _LoserTree is empty. 82 * 83 * Only used for building the _LoserTree. 84 */ 85 bool _M_first_insert; 86 87 public: 88 /** 89 * @brief The constructor. 90 * 91 * @param __k The number of sequences to merge. 92 * @param __comp The comparator to use. 93 */ 94 _LoserTreeBase(unsigned int __k, _Compare __comp) 95 : _M_comp(__comp) 96 { 97 _M_ik = __k; 98 99 // Compute log_2{_M_k} for the _Loser Tree 100 _M_log_k = __rd_log2(_M_ik - 1) + 1; 101 102 // Next greater power of 2. 103 _M_k = 1 << _M_log_k; 104 _M_offset = _M_k; 105 106 // Avoid default-constructing _M_losers[]._M_key 107 _M_losers = static_cast<_Loser*>(::operator new(2 * _M_k 108 * sizeof(_Loser))); 109 for (unsigned int __i = _M_ik - 1; __i < _M_k; ++__i) 110 _M_losers[__i + _M_k]._M_sup = true; 111 112 _M_first_insert = true; 113 } 114 115 /** 116 * @brief The destructor. 117 */ 118 ~_LoserTreeBase() 119 { 120 for (unsigned int __i = 0; __i < (2 * _M_k); ++__i) 121 _M_losers[__i].~_Loser(); 122 ::operator delete(_M_losers); 123 } 124 125 /** 126 * @brief Initializes the sequence "_M_source" with the element "__key". 127 * 128 * @param __key the element to insert 129 * @param __source __index of the __source __sequence 130 * @param __sup flag that determines whether the value to insert is an 131 * explicit __supremum. 132 */ 133 void 134 __insert_start(const _Tp& __key, int __source, bool __sup) 135 { 136 unsigned int __pos = _M_k + __source; 137 138 if (_M_first_insert) 139 { 140 // Construct all keys, so we can easily destruct them. 141 for (unsigned int __i = 0; __i < (2 * _M_k); ++__i) 142 ::new(&(_M_losers[__i]._M_key)) _Tp(__key); 143 _M_first_insert = false; 144 } 145 else 146 _M_losers[__pos]._M_key = __key; 147 148 _M_losers[__pos]._M_sup = __sup; 149 _M_losers[__pos]._M_source = __source; 150 } 151 152 /** 153 * @return the index of the sequence with the smallest element. 154 */ 155 int __get_min_source() 156 { return _M_losers[0]._M_source; } 157 }; 158 159 /** 160 * @brief Stable _LoserTree variant. 161 * 162 * Provides the stable implementations of insert_start, __init_winner, 163 * __init and __delete_min_insert. 164 * 165 * Unstable variant is done using partial specialisation below. 166 */ 167 template<bool __stable/* default == true */, typename _Tp, 168 typename _Compare> 169 class _LoserTree 170 : public _LoserTreeBase<_Tp, _Compare> 171 { 172 typedef _LoserTreeBase<_Tp, _Compare> _Base; 173 using _Base::_M_k; 174 using _Base::_M_comp; 175 using _Base::_M_losers; 176 using _Base::_M_first_insert; 177 178 public: 179 _LoserTree(unsigned int __k, _Compare __comp) 180 : _Base::_LoserTreeBase(__k, __comp) 181 { } 182 183 unsigned int 184 __init_winner(unsigned int __root) 185 { 186 if (__root >= _M_k) 187 return __root; 188 else 189 { 190 unsigned int __left = __init_winner(2 * __root); 191 unsigned int __right = __init_winner(2 * __root + 1); 192 if (_M_losers[__right]._M_sup 193 || (!_M_losers[__left]._M_sup 194 && !_M_comp(_M_losers[__right]._M_key, 195 _M_losers[__left]._M_key))) 196 { 197 // Left one is less or equal. 198 _M_losers[__root] = _M_losers[__right]; 199 return __left; 200 } 201 else 202 { 203 // Right one is less. 204 _M_losers[__root] = _M_losers[__left]; 205 return __right; 206 } 207 } 208 } 209 210 void __init() 211 { _M_losers[0] = _M_losers[__init_winner(1)]; } 212 213 /** 214 * @brief Delete the smallest element and insert a new element from 215 * the previously smallest element's sequence. 216 * 217 * This implementation is stable. 218 */ 219 // Do not pass a const reference since __key will be used as 220 // local variable. 221 void 222 __delete_min_insert(_Tp __key, bool __sup) 223 { 224 using std::swap; 225 #if _GLIBCXX_ASSERTIONS 226 // no dummy sequence can ever be at the top! 227 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 228 #endif 229 230 int __source = _M_losers[0]._M_source; 231 for (unsigned int __pos = (_M_k + __source) / 2; __pos > 0; 232 __pos /= 2) 233 { 234 // The smaller one gets promoted, ties are broken by _M_source. 235 if ((__sup && (!_M_losers[__pos]._M_sup 236 || _M_losers[__pos]._M_source < __source)) 237 || (!__sup && !_M_losers[__pos]._M_sup 238 && ((_M_comp(_M_losers[__pos]._M_key, __key)) 239 || (!_M_comp(__key, _M_losers[__pos]._M_key) 240 && _M_losers[__pos]._M_source < __source)))) 241 { 242 // The other one is smaller. 243 std::swap(_M_losers[__pos]._M_sup, __sup); 244 std::swap(_M_losers[__pos]._M_source, __source); 245 swap(_M_losers[__pos]._M_key, __key); 246 } 247 } 248 249 _M_losers[0]._M_sup = __sup; 250 _M_losers[0]._M_source = __source; 251 _M_losers[0]._M_key = __key; 252 } 253 }; 254 255 /** 256 * @brief Unstable _LoserTree variant. 257 * 258 * Stability (non-stable here) is selected with partial specialization. 259 */ 260 template<typename _Tp, typename _Compare> 261 class _LoserTree</* __stable == */false, _Tp, _Compare> 262 : public _LoserTreeBase<_Tp, _Compare> 263 { 264 typedef _LoserTreeBase<_Tp, _Compare> _Base; 265 using _Base::_M_log_k; 266 using _Base::_M_k; 267 using _Base::_M_comp; 268 using _Base::_M_losers; 269 using _Base::_M_first_insert; 270 271 public: 272 _LoserTree(unsigned int __k, _Compare __comp) 273 : _Base::_LoserTreeBase(__k, __comp) 274 { } 275 276 /** 277 * Computes the winner of the competition at position "__root". 278 * 279 * Called recursively (starting at 0) to build the initial tree. 280 * 281 * @param __root __index of the "game" to start. 282 */ 283 unsigned int 284 __init_winner(unsigned int __root) 285 { 286 if (__root >= _M_k) 287 return __root; 288 else 289 { 290 unsigned int __left = __init_winner(2 * __root); 291 unsigned int __right = __init_winner(2 * __root + 1); 292 if (_M_losers[__right]._M_sup 293 || (!_M_losers[__left]._M_sup 294 && !_M_comp(_M_losers[__right]._M_key, 295 _M_losers[__left]._M_key))) 296 { 297 // Left one is less or equal. 298 _M_losers[__root] = _M_losers[__right]; 299 return __left; 300 } 301 else 302 { 303 // Right one is less. 304 _M_losers[__root] = _M_losers[__left]; 305 return __right; 306 } 307 } 308 } 309 310 void 311 __init() 312 { _M_losers[0] = _M_losers[__init_winner(1)]; } 313 314 /** 315 * Delete the _M_key smallest element and insert the element __key 316 * instead. 317 * 318 * @param __key the _M_key to insert 319 * @param __sup true iff __key is an explicitly marked supremum 320 */ 321 // Do not pass a const reference since __key will be used as local 322 // variable. 323 void 324 __delete_min_insert(_Tp __key, bool __sup) 325 { 326 using std::swap; 327 #if _GLIBCXX_ASSERTIONS 328 // no dummy sequence can ever be at the top! 329 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 330 #endif 331 332 int __source = _M_losers[0]._M_source; 333 for (unsigned int __pos = (_M_k + __source) / 2; __pos > 0; 334 __pos /= 2) 335 { 336 // The smaller one gets promoted. 337 if (__sup || (!_M_losers[__pos]._M_sup 338 && _M_comp(_M_losers[__pos]._M_key, __key))) 339 { 340 // The other one is smaller. 341 std::swap(_M_losers[__pos]._M_sup, __sup); 342 std::swap(_M_losers[__pos]._M_source, __source); 343 swap(_M_losers[__pos]._M_key, __key); 344 } 345 } 346 347 _M_losers[0]._M_sup = __sup; 348 _M_losers[0]._M_source = __source; 349 _M_losers[0]._M_key = __key; 350 } 351 }; 352 353 /** 354 * @brief Base class of _Loser Tree implementation using pointers. 355 */ 356 template<typename _Tp, typename _Compare> 357 class _LoserTreePointerBase 358 { 359 protected: 360 /** @brief Internal representation of _LoserTree __elements. */ 361 struct _Loser 362 { 363 bool _M_sup; 364 int _M_source; 365 const _Tp* _M_keyp; 366 }; 367 368 unsigned int _M_ik, _M_k, _M_offset; 369 _Loser* _M_losers; 370 _Compare _M_comp; 371 372 public: 373 _LoserTreePointerBase(unsigned int __k, 374 _Compare __comp = std::less<_Tp>()) 375 : _M_comp(__comp) 376 { 377 _M_ik = __k; 378 379 // Next greater power of 2. 380 _M_k = 1 << (__rd_log2(_M_ik - 1) + 1); 381 _M_offset = _M_k; 382 _M_losers = new _Loser[_M_k * 2]; 383 for (unsigned int __i = _M_ik - 1; __i < _M_k; __i++) 384 _M_losers[__i + _M_k]._M_sup = true; 385 } 386 387 ~_LoserTreePointerBase() 388 { delete[] _M_losers; } 389 390 int __get_min_source() 391 { return _M_losers[0]._M_source; } 392 393 void __insert_start(const _Tp& __key, int __source, bool __sup) 394 { 395 unsigned int __pos = _M_k + __source; 396 397 _M_losers[__pos]._M_sup = __sup; 398 _M_losers[__pos]._M_source = __source; 399 _M_losers[__pos]._M_keyp = &__key; 400 } 401 }; 402 403 /** 404 * @brief Stable _LoserTree implementation. 405 * 406 * The unstable variant is implemented using partial instantiation below. 407 */ 408 template<bool __stable/* default == true */, typename _Tp, typename _Compare> 409 class _LoserTreePointer 410 : public _LoserTreePointerBase<_Tp, _Compare> 411 { 412 typedef _LoserTreePointerBase<_Tp, _Compare> _Base; 413 using _Base::_M_k; 414 using _Base::_M_comp; 415 using _Base::_M_losers; 416 417 public: 418 _LoserTreePointer(unsigned int __k, _Compare __comp = std::less<_Tp>()) 419 : _Base::_LoserTreePointerBase(__k, __comp) 420 { } 421 422 unsigned int 423 __init_winner(unsigned int __root) 424 { 425 if (__root >= _M_k) 426 return __root; 427 else 428 { 429 unsigned int __left = __init_winner(2 * __root); 430 unsigned int __right = __init_winner(2 * __root + 1); 431 if (_M_losers[__right]._M_sup 432 || (!_M_losers[__left]._M_sup 433 && !_M_comp(*_M_losers[__right]._M_keyp, 434 *_M_losers[__left]._M_keyp))) 435 { 436 // Left one is less or equal. 437 _M_losers[__root] = _M_losers[__right]; 438 return __left; 439 } 440 else 441 { 442 // Right one is less. 443 _M_losers[__root] = _M_losers[__left]; 444 return __right; 445 } 446 } 447 } 448 449 void __init() 450 { _M_losers[0] = _M_losers[__init_winner(1)]; } 451 452 void __delete_min_insert(const _Tp& __key, bool __sup) 453 { 454 #if _GLIBCXX_ASSERTIONS 455 // no dummy sequence can ever be at the top! 456 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 457 #endif 458 459 const _Tp* __keyp = &__key; 460 int __source = _M_losers[0]._M_source; 461 for (unsigned int __pos = (_M_k + __source) / 2; __pos > 0; 462 __pos /= 2) 463 { 464 // The smaller one gets promoted, ties are broken by __source. 465 if ((__sup && (!_M_losers[__pos]._M_sup 466 || _M_losers[__pos]._M_source < __source)) 467 || (!__sup && !_M_losers[__pos]._M_sup && 468 ((_M_comp(*_M_losers[__pos]._M_keyp, *__keyp)) 469 || (!_M_comp(*__keyp, *_M_losers[__pos]._M_keyp) 470 && _M_losers[__pos]._M_source < __source)))) 471 { 472 // The other one is smaller. 473 std::swap(_M_losers[__pos]._M_sup, __sup); 474 std::swap(_M_losers[__pos]._M_source, __source); 475 std::swap(_M_losers[__pos]._M_keyp, __keyp); 476 } 477 } 478 479 _M_losers[0]._M_sup = __sup; 480 _M_losers[0]._M_source = __source; 481 _M_losers[0]._M_keyp = __keyp; 482 } 483 }; 484 485 /** 486 * @brief Unstable _LoserTree implementation. 487 * 488 * The stable variant is above. 489 */ 490 template<typename _Tp, typename _Compare> 491 class _LoserTreePointer</* __stable == */false, _Tp, _Compare> 492 : public _LoserTreePointerBase<_Tp, _Compare> 493 { 494 typedef _LoserTreePointerBase<_Tp, _Compare> _Base; 495 using _Base::_M_k; 496 using _Base::_M_comp; 497 using _Base::_M_losers; 498 499 public: 500 _LoserTreePointer(unsigned int __k, _Compare __comp = std::less<_Tp>()) 501 : _Base::_LoserTreePointerBase(__k, __comp) 502 { } 503 504 unsigned int 505 __init_winner(unsigned int __root) 506 { 507 if (__root >= _M_k) 508 return __root; 509 else 510 { 511 unsigned int __left = __init_winner(2 * __root); 512 unsigned int __right = __init_winner(2 * __root + 1); 513 if (_M_losers[__right]._M_sup 514 || (!_M_losers[__left]._M_sup 515 && !_M_comp(*_M_losers[__right]._M_keyp, 516 *_M_losers[__left]._M_keyp))) 517 { 518 // Left one is less or equal. 519 _M_losers[__root] = _M_losers[__right]; 520 return __left; 521 } 522 else 523 { 524 // Right one is less. 525 _M_losers[__root] = _M_losers[__left]; 526 return __right; 527 } 528 } 529 } 530 531 void __init() 532 { _M_losers[0] = _M_losers[__init_winner(1)]; } 533 534 void __delete_min_insert(const _Tp& __key, bool __sup) 535 { 536 #if _GLIBCXX_ASSERTIONS 537 // no dummy sequence can ever be at the top! 538 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 539 #endif 540 541 const _Tp* __keyp = &__key; 542 int __source = _M_losers[0]._M_source; 543 for (unsigned int __pos = (_M_k + __source) / 2; __pos > 0; 544 __pos /= 2) 545 { 546 // The smaller one gets promoted. 547 if (__sup || (!_M_losers[__pos]._M_sup 548 && _M_comp(*_M_losers[__pos]._M_keyp, *__keyp))) 549 { 550 // The other one is smaller. 551 std::swap(_M_losers[__pos]._M_sup, __sup); 552 std::swap(_M_losers[__pos]._M_source, __source); 553 std::swap(_M_losers[__pos]._M_keyp, __keyp); 554 } 555 } 556 557 _M_losers[0]._M_sup = __sup; 558 _M_losers[0]._M_source = __source; 559 _M_losers[0]._M_keyp = __keyp; 560 } 561 }; 562 563 /** @brief Base class for unguarded _LoserTree implementation. 564 * 565 * The whole element is copied into the tree structure. 566 * 567 * No guarding is done, therefore not a single input sequence must 568 * run empty. Unused __sequence heads are marked with a sentinel which 569 * is > all elements that are to be merged. 570 * 571 * This is a very fast variant. 572 */ 573 template<typename _Tp, typename _Compare> 574 class _LoserTreeUnguardedBase 575 { 576 protected: 577 struct _Loser 578 { 579 int _M_source; 580 _Tp _M_key; 581 }; 582 583 unsigned int _M_ik, _M_k, _M_offset; 584 _Loser* _M_losers; 585 _Compare _M_comp; 586 587 public: 588 _LoserTreeUnguardedBase(unsigned int __k, const _Tp& __sentinel, 589 _Compare __comp = std::less<_Tp>()) 590 : _M_comp(__comp) 591 { 592 _M_ik = __k; 593 594 // Next greater power of 2. 595 _M_k = 1 << (__rd_log2(_M_ik - 1) + 1); 596 _M_offset = _M_k; 597 // Avoid default-constructing _M_losers[]._M_key 598 _M_losers = static_cast<_Loser*>(::operator new(2 * _M_k 599 * sizeof(_Loser))); 600 601 for (unsigned int __i = 0; __i < _M_k; ++__i) 602 { 603 ::new(&(_M_losers[__i]._M_key)) _Tp(__sentinel); 604 _M_losers[__i]._M_source = -1; 605 } 606 for (unsigned int __i = _M_k + _M_ik - 1; __i < (2 * _M_k); ++__i) 607 { 608 ::new(&(_M_losers[__i]._M_key)) _Tp(__sentinel); 609 _M_losers[__i]._M_source = -1; 610 } 611 } 612 613 ~_LoserTreeUnguardedBase() 614 { 615 for (unsigned int __i = 0; __i < (2 * _M_k); ++__i) 616 _M_losers[__i].~_Loser(); 617 ::operator delete(_M_losers); 618 } 619 620 int 621 __get_min_source() 622 { 623 #if _GLIBCXX_ASSERTIONS 624 // no dummy sequence can ever be at the top! 625 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 626 #endif 627 return _M_losers[0]._M_source; 628 } 629 630 void 631 __insert_start(const _Tp& __key, int __source, bool) 632 { 633 unsigned int __pos = _M_k + __source; 634 635 ::new(&(_M_losers[__pos]._M_key)) _Tp(__key); 636 _M_losers[__pos]._M_source = __source; 637 } 638 }; 639 640 /** 641 * @brief Stable implementation of unguarded _LoserTree. 642 * 643 * Unstable variant is selected below with partial specialization. 644 */ 645 template<bool __stable/* default == true */, typename _Tp, typename _Compare> 646 class _LoserTreeUnguarded 647 : public _LoserTreeUnguardedBase<_Tp, _Compare> 648 { 649 typedef _LoserTreeUnguardedBase<_Tp, _Compare> _Base; 650 using _Base::_M_k; 651 using _Base::_M_comp; 652 using _Base::_M_losers; 653 654 public: 655 _LoserTreeUnguarded(unsigned int __k, const _Tp& __sentinel, 656 _Compare __comp = std::less<_Tp>()) 657 : _Base::_LoserTreeUnguardedBase(__k, __sentinel, __comp) 658 { } 659 660 unsigned int 661 __init_winner(unsigned int __root) 662 { 663 if (__root >= _M_k) 664 return __root; 665 else 666 { 667 unsigned int __left = __init_winner(2 * __root); 668 unsigned int __right = __init_winner(2 * __root + 1); 669 if (!_M_comp(_M_losers[__right]._M_key, 670 _M_losers[__left]._M_key)) 671 { 672 // Left one is less or equal. 673 _M_losers[__root] = _M_losers[__right]; 674 return __left; 675 } 676 else 677 { 678 // Right one is less. 679 _M_losers[__root] = _M_losers[__left]; 680 return __right; 681 } 682 } 683 } 684 685 void 686 __init() 687 { 688 _M_losers[0] = _M_losers[__init_winner(1)]; 689 690 #if _GLIBCXX_ASSERTIONS 691 // no dummy sequence can ever be at the top at the beginning 692 // (0 sequences!) 693 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 694 #endif 695 } 696 697 // Do not pass a const reference since __key will be used as 698 // local variable. 699 void 700 __delete_min_insert(_Tp __key, bool) 701 { 702 using std::swap; 703 #if _GLIBCXX_ASSERTIONS 704 // no dummy sequence can ever be at the top! 705 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 706 #endif 707 708 int __source = _M_losers[0]._M_source; 709 for (unsigned int __pos = (_M_k + __source) / 2; __pos > 0; 710 __pos /= 2) 711 { 712 // The smaller one gets promoted, ties are broken by _M_source. 713 if (_M_comp(_M_losers[__pos]._M_key, __key) 714 || (!_M_comp(__key, _M_losers[__pos]._M_key) 715 && _M_losers[__pos]._M_source < __source)) 716 { 717 // The other one is smaller. 718 std::swap(_M_losers[__pos]._M_source, __source); 719 swap(_M_losers[__pos]._M_key, __key); 720 } 721 } 722 723 _M_losers[0]._M_source = __source; 724 _M_losers[0]._M_key = __key; 725 } 726 }; 727 728 /** 729 * @brief Non-Stable implementation of unguarded _LoserTree. 730 * 731 * Stable implementation is above. 732 */ 733 template<typename _Tp, typename _Compare> 734 class _LoserTreeUnguarded</* __stable == */false, _Tp, _Compare> 735 : public _LoserTreeUnguardedBase<_Tp, _Compare> 736 { 737 typedef _LoserTreeUnguardedBase<_Tp, _Compare> _Base; 738 using _Base::_M_k; 739 using _Base::_M_comp; 740 using _Base::_M_losers; 741 742 public: 743 _LoserTreeUnguarded(unsigned int __k, const _Tp& __sentinel, 744 _Compare __comp = std::less<_Tp>()) 745 : _Base::_LoserTreeUnguardedBase(__k, __sentinel, __comp) 746 { } 747 748 unsigned int 749 __init_winner(unsigned int __root) 750 { 751 if (__root >= _M_k) 752 return __root; 753 else 754 { 755 unsigned int __left = __init_winner(2 * __root); 756 unsigned int __right = __init_winner(2 * __root + 1); 757 758 #if _GLIBCXX_ASSERTIONS 759 // If __left one is sentinel then __right one must be, too. 760 if (_M_losers[__left]._M_source == -1) 761 _GLIBCXX_PARALLEL_ASSERT(_M_losers[__right]._M_source == -1); 762 #endif 763 764 if (!_M_comp(_M_losers[__right]._M_key, 765 _M_losers[__left]._M_key)) 766 { 767 // Left one is less or equal. 768 _M_losers[__root] = _M_losers[__right]; 769 return __left; 770 } 771 else 772 { 773 // Right one is less. 774 _M_losers[__root] = _M_losers[__left]; 775 return __right; 776 } 777 } 778 } 779 780 void 781 __init() 782 { 783 _M_losers[0] = _M_losers[__init_winner(1)]; 784 785 #if _GLIBCXX_ASSERTIONS 786 // no dummy sequence can ever be at the top at the beginning 787 // (0 sequences!) 788 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 789 #endif 790 } 791 792 // Do not pass a const reference since __key will be used as 793 // local variable. 794 void 795 __delete_min_insert(_Tp __key, bool) 796 { 797 using std::swap; 798 #if _GLIBCXX_ASSERTIONS 799 // no dummy sequence can ever be at the top! 800 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 801 #endif 802 803 int __source = _M_losers[0]._M_source; 804 for (unsigned int __pos = (_M_k + __source) / 2; __pos > 0; 805 __pos /= 2) 806 { 807 // The smaller one gets promoted. 808 if (_M_comp(_M_losers[__pos]._M_key, __key)) 809 { 810 // The other one is smaller. 811 std::swap(_M_losers[__pos]._M_source, __source); 812 swap(_M_losers[__pos]._M_key, __key); 813 } 814 } 815 816 _M_losers[0]._M_source = __source; 817 _M_losers[0]._M_key = __key; 818 } 819 }; 820 821 /** @brief Unguarded loser tree, keeping only pointers to the 822 * elements in the tree structure. 823 * 824 * No guarding is done, therefore not a single input sequence must 825 * run empty. This is a very fast variant. 826 */ 827 template<typename _Tp, typename _Compare> 828 class _LoserTreePointerUnguardedBase 829 { 830 protected: 831 struct _Loser 832 { 833 int _M_source; 834 const _Tp* _M_keyp; 835 }; 836 837 unsigned int _M_ik, _M_k, _M_offset; 838 _Loser* _M_losers; 839 _Compare _M_comp; 840 841 public: 842 843 _LoserTreePointerUnguardedBase(unsigned int __k, const _Tp& __sentinel, 844 _Compare __comp = std::less<_Tp>()) 845 : _M_comp(__comp) 846 { 847 _M_ik = __k; 848 849 // Next greater power of 2. 850 _M_k = 1 << (__rd_log2(_M_ik - 1) + 1); 851 _M_offset = _M_k; 852 // Avoid default-constructing _M_losers[]._M_key 853 _M_losers = new _Loser[2 * _M_k]; 854 855 for (unsigned int __i = _M_k + _M_ik - 1; __i < (2 * _M_k); ++__i) 856 { 857 _M_losers[__i]._M_keyp = &__sentinel; 858 _M_losers[__i]._M_source = -1; 859 } 860 } 861 862 ~_LoserTreePointerUnguardedBase() 863 { delete[] _M_losers; } 864 865 int 866 __get_min_source() 867 { 868 #if _GLIBCXX_ASSERTIONS 869 // no dummy sequence can ever be at the top! 870 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 871 #endif 872 return _M_losers[0]._M_source; 873 } 874 875 void 876 __insert_start(const _Tp& __key, int __source, bool) 877 { 878 unsigned int __pos = _M_k + __source; 879 880 _M_losers[__pos]._M_keyp = &__key; 881 _M_losers[__pos]._M_source = __source; 882 } 883 }; 884 885 /** 886 * @brief Stable unguarded _LoserTree variant storing pointers. 887 * 888 * Unstable variant is implemented below using partial specialization. 889 */ 890 template<bool __stable/* default == true */, typename _Tp, typename _Compare> 891 class _LoserTreePointerUnguarded 892 : public _LoserTreePointerUnguardedBase<_Tp, _Compare> 893 { 894 typedef _LoserTreePointerUnguardedBase<_Tp, _Compare> _Base; 895 using _Base::_M_k; 896 using _Base::_M_comp; 897 using _Base::_M_losers; 898 899 public: 900 _LoserTreePointerUnguarded(unsigned int __k, const _Tp& __sentinel, 901 _Compare __comp = std::less<_Tp>()) 902 : _Base::_LoserTreePointerUnguardedBase(__k, __sentinel, __comp) 903 { } 904 905 unsigned int 906 __init_winner(unsigned int __root) 907 { 908 if (__root >= _M_k) 909 return __root; 910 else 911 { 912 unsigned int __left = __init_winner(2 * __root); 913 unsigned int __right = __init_winner(2 * __root + 1); 914 if (!_M_comp(*_M_losers[__right]._M_keyp, 915 *_M_losers[__left]._M_keyp)) 916 { 917 // Left one is less or equal. 918 _M_losers[__root] = _M_losers[__right]; 919 return __left; 920 } 921 else 922 { 923 // Right one is less. 924 _M_losers[__root] = _M_losers[__left]; 925 return __right; 926 } 927 } 928 } 929 930 void 931 __init() 932 { 933 _M_losers[0] = _M_losers[__init_winner(1)]; 934 935 #if _GLIBCXX_ASSERTIONS 936 // no dummy sequence can ever be at the top at the beginning 937 // (0 sequences!) 938 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 939 #endif 940 } 941 942 void 943 __delete_min_insert(const _Tp& __key, bool __sup) 944 { 945 #if _GLIBCXX_ASSERTIONS 946 // no dummy sequence can ever be at the top! 947 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 948 #endif 949 950 const _Tp* __keyp = &__key; 951 int __source = _M_losers[0]._M_source; 952 for (unsigned int __pos = (_M_k + __source) / 2; __pos > 0; 953 __pos /= 2) 954 { 955 // The smaller one gets promoted, ties are broken by _M_source. 956 if (_M_comp(*_M_losers[__pos]._M_keyp, *__keyp) 957 || (!_M_comp(*__keyp, *_M_losers[__pos]._M_keyp) 958 && _M_losers[__pos]._M_source < __source)) 959 { 960 // The other one is smaller. 961 std::swap(_M_losers[__pos]._M_source, __source); 962 std::swap(_M_losers[__pos]._M_keyp, __keyp); 963 } 964 } 965 966 _M_losers[0]._M_source = __source; 967 _M_losers[0]._M_keyp = __keyp; 968 } 969 }; 970 971 /** 972 * @brief Unstable unguarded _LoserTree variant storing pointers. 973 * 974 * Stable variant is above. 975 */ 976 template<typename _Tp, typename _Compare> 977 class _LoserTreePointerUnguarded</* __stable == */false, _Tp, _Compare> 978 : public _LoserTreePointerUnguardedBase<_Tp, _Compare> 979 { 980 typedef _LoserTreePointerUnguardedBase<_Tp, _Compare> _Base; 981 using _Base::_M_k; 982 using _Base::_M_comp; 983 using _Base::_M_losers; 984 985 public: 986 _LoserTreePointerUnguarded(unsigned int __k, const _Tp& __sentinel, 987 _Compare __comp = std::less<_Tp>()) 988 : _Base::_LoserTreePointerUnguardedBase(__k, __sentinel, __comp) 989 { } 990 991 unsigned int 992 __init_winner(unsigned int __root) 993 { 994 if (__root >= _M_k) 995 return __root; 996 else 997 { 998 unsigned int __left = __init_winner(2 * __root); 999 unsigned int __right = __init_winner(2 * __root + 1); 1000 1001 #if _GLIBCXX_ASSERTIONS 1002 // If __left one is sentinel then __right one must be, too. 1003 if (_M_losers[__left]._M_source == -1) 1004 _GLIBCXX_PARALLEL_ASSERT(_M_losers[__right]._M_source == -1); 1005 #endif 1006 1007 if (!_M_comp(*_M_losers[__right]._M_keyp, 1008 *_M_losers[__left]._M_keyp)) 1009 { 1010 // Left one is less or equal. 1011 _M_losers[__root] = _M_losers[__right]; 1012 return __left; 1013 } 1014 else 1015 { 1016 // Right one is less. 1017 _M_losers[__root] = _M_losers[__left]; 1018 return __right; 1019 } 1020 } 1021 } 1022 1023 void 1024 __init() 1025 { 1026 _M_losers[0] = _M_losers[__init_winner(1)]; 1027 1028 #if _GLIBCXX_ASSERTIONS 1029 // no dummy sequence can ever be at the top at the beginning 1030 // (0 sequences!) 1031 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 1032 #endif 1033 } 1034 1035 void 1036 __delete_min_insert(const _Tp& __key, bool __sup) 1037 { 1038 #if _GLIBCXX_ASSERTIONS 1039 // no dummy sequence can ever be at the top! 1040 _GLIBCXX_PARALLEL_ASSERT(_M_losers[0]._M_source != -1); 1041 #endif 1042 1043 const _Tp* __keyp = &__key; 1044 int __source = _M_losers[0]._M_source; 1045 for (unsigned int __pos = (_M_k + __source) / 2; __pos > 0; 1046 __pos /= 2) 1047 { 1048 // The smaller one gets promoted. 1049 if (_M_comp(*(_M_losers[__pos]._M_keyp), *__keyp)) 1050 { 1051 // The other one is smaller. 1052 std::swap(_M_losers[__pos]._M_source, __source); 1053 std::swap(_M_losers[__pos]._M_keyp, __keyp); 1054 } 1055 } 1056 1057 _M_losers[0]._M_source = __source; 1058 _M_losers[0]._M_keyp = __keyp; 1059 } 1060 }; 1061 } // namespace __gnu_parallel 1062 1063 #endif /* _GLIBCXX_PARALLEL_LOSERTREE_H */ 1064