Stxxl  1.4.0
include/stxxl/bits/containers/pq_losertree.h
Go to the documentation of this file.
00001 /***************************************************************************
00002  *  include/stxxl/bits/containers/pq_losertree.h
00003  *
00004  *  Part of the STXXL. See http://stxxl.sourceforge.net
00005  *
00006  *  Copyright (C) 1999 Peter Sanders <sanders@mpi-sb.mpg.de>
00007  *  Copyright (C) 2003, 2004, 2007 Roman Dementiev <dementiev@mpi-sb.mpg.de>
00008  *  Copyright (C) 2007-2009 Johannes Singler <singler@ira.uka.de>
00009  *  Copyright (C) 2007, 2008 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
00010  *
00011  *  Distributed under the Boost Software License, Version 1.0.
00012  *  (See accompanying file LICENSE_1_0.txt or copy at
00013  *  http://www.boost.org/LICENSE_1_0.txt)
00014  **************************************************************************/
00015 
00016 #ifndef STXXL_PQ_LOSERTREE_HEADER
00017 #define STXXL_PQ_LOSERTREE_HEADER
00018 
00019 __STXXL_BEGIN_NAMESPACE
00020 
00021 //! \addtogroup stlcontinternals
00022 //!
00023 //! \{
00024 
00025 /*! \internal
00026  */
00027 namespace priority_queue_local
00028 {
00029 //////////////////////////////////////////////////////////////////////
00030 // The data structure from Knuth, "Sorting and Searching", Section 5.4.1
00031     /**
00032      *!  \brief  Loser tree from Knuth, "Sorting and Searching", Section 5.4.1
00033      *!  \param  KNKMAX  maximum arity of loser tree, has to be a power of two
00034      */
00035     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00036     class loser_tree : private noncopyable
00037     {
00038     public:
00039         typedef ValTp_ value_type;
00040         typedef Cmp_ comparator_type;
00041         typedef value_type Element;
00042 
00043     private:
00044 #if STXXL_PQ_INTERNAL_LOSER_TREE
00045         struct Entry
00046         {
00047             value_type key;      // Key of Loser element (winner for 0)
00048             unsigned_type index; // number of losing segment
00049         };
00050 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
00051 
00052         comparator_type cmp;
00053         // stack of free segment indices
00054         internal_bounded_stack<unsigned_type, KNKMAX> free_slots;
00055 
00056         unsigned_type size_; // total number of elements stored
00057         unsigned_type logK;  // log of current tree size
00058         unsigned_type k;     // invariant (k == 1 << logK), always a power of two
00059 
00060         Element sentinel;    // target of free segment pointers
00061 
00062 #if STXXL_PQ_INTERNAL_LOSER_TREE
00063         // upper levels of loser trees
00064         // entry[0] contains the winner info
00065         Entry entry[KNKMAX];
00066 #endif  //STXXL_PQ_INTERNAL_LOSER_TREE
00067 
00068         // leaf information
00069         // note that Knuth uses indices k..k-1
00070         // while we use 0..k-1
00071         Element * current[KNKMAX];          // pointer to current element
00072         Element * current_end[KNKMAX];      // pointer to end of block for current element
00073         Element * segment[KNKMAX];          // start of Segments
00074         unsigned_type segment_size[KNKMAX]; // just to count the internal memory consumption, in bytes
00075 
00076         unsigned_type mem_cons_;
00077 
00078         // private member functions
00079         unsigned_type initWinner(unsigned_type root);
00080         void update_on_insert(unsigned_type node, const Element & newKey, unsigned_type newIndex,
00081                               Element * winnerKey, unsigned_type * winnerIndex, unsigned_type * mask);
00082         void deallocate_segment(unsigned_type slot);
00083         void doubleK();
00084         void compactTree();
00085         void rebuildLoserTree();
00086         bool is_segment_empty(unsigned_type slot);
00087         void multi_merge_k(Element * target, unsigned_type length);
00088 
00089 #if STXXL_PQ_INTERNAL_LOSER_TREE
00090         template <unsigned LogK>
00091         void multi_merge_f(Element * target, unsigned_type length)
00092         {
00093             //Entry *currentPos;
00094             //Element currentKey;
00095             //int currentIndex; // leaf pointed to by current entry
00096             Element * done = target + length;
00097             Entry * regEntry = entry;
00098             Element ** regStates = current;
00099             unsigned_type winnerIndex = regEntry[0].index;
00100             Element winnerKey = regEntry[0].key;
00101             Element * winnerPos;
00102             //Element sup = sentinel; // supremum
00103 
00104             assert(logK >= LogK);
00105             while (target != done)
00106             {
00107                 winnerPos = regStates[winnerIndex];
00108 
00109                 // write result
00110                 *target = winnerKey;
00111 
00112                 // advance winner segment
00113                 ++winnerPos;
00114                 regStates[winnerIndex] = winnerPos;
00115                 winnerKey = *winnerPos;
00116 
00117                 // remove winner segment if empty now
00118                 if (is_sentinel(winnerKey))
00119                 {
00120                     deallocate_segment(winnerIndex);
00121                 }
00122                 ++target;
00123 
00124                 // update loser tree
00125 #define TreeStep(L) \
00126     if (1 << LogK >= 1 << L) { \
00127         Entry * pos ## L = regEntry + ((winnerIndex + (1 << LogK)) >> (((int(LogK - L) + 1) >= 0) ? ((LogK - L) + 1) : 0)); \
00128         Element key ## L = pos ## L->key; \
00129         if (cmp(winnerKey, key ## L)) { \
00130             unsigned_type index ## L = pos ## L->index; \
00131             pos ## L->key = winnerKey; \
00132             pos ## L->index = winnerIndex; \
00133             winnerKey = key ## L; \
00134             winnerIndex = index ## L; \
00135         } \
00136     }
00137                 TreeStep(10);
00138                 TreeStep(9);
00139                 TreeStep(8);
00140                 TreeStep(7);
00141                 TreeStep(6);
00142                 TreeStep(5);
00143                 TreeStep(4);
00144                 TreeStep(3);
00145                 TreeStep(2);
00146                 TreeStep(1);
00147 #undef TreeStep
00148             }
00149             regEntry[0].index = winnerIndex;
00150             regEntry[0].key = winnerKey;
00151         }
00152 #endif  //STXXL_PQ_INTERNAL_LOSER_TREE
00153 
00154     public:
00155         bool is_sentinel(const Element & a)
00156         {
00157             return !(cmp(cmp.min_value(), a));
00158         }
00159         bool not_sentinel(const Element & a)
00160         {
00161             return cmp(cmp.min_value(), a);
00162         }
00163 
00164     public:
00165         loser_tree();
00166         ~loser_tree();
00167         void init();
00168 
00169         void swap(loser_tree & obj)
00170         {
00171             std::swap(cmp, obj.cmp);
00172             std::swap(free_slots, obj.free_slots);
00173             std::swap(size_, obj.size_);
00174             std::swap(logK, obj.logK);
00175             std::swap(k, obj.k);
00176             std::swap(sentinel, obj.sentinel);
00177 #if STXXL_PQ_INTERNAL_LOSER_TREE
00178             swap_1D_arrays(entry, obj.entry, KNKMAX);
00179 #endif      //STXXL_PQ_INTERNAL_LOSER_TREE
00180             swap_1D_arrays(current, obj.current, KNKMAX);
00181             swap_1D_arrays(current_end, obj.current_end, KNKMAX);
00182             swap_1D_arrays(segment, obj.segment, KNKMAX);
00183             swap_1D_arrays(segment_size, obj.segment_size, KNKMAX);
00184             std::swap(mem_cons_, obj.mem_cons_);
00185         }
00186 
00187         void multi_merge(Element * begin, Element * end)
00188         {
00189             multi_merge(begin, end - begin);
00190         }
00191         void multi_merge(Element *, unsigned_type length);
00192 
00193         unsigned_type mem_cons() const { return mem_cons_; }
00194 
00195         bool is_space_available() const // for new segment
00196         {
00197             return (k < KNKMAX) || !free_slots.empty();
00198         }
00199 
00200         void insert_segment(Element * target, unsigned_type length); // insert segment beginning at target
00201         unsigned_type size() const { return size_; }
00202     };
00203 
00204 ///////////////////////// LoserTree ///////////////////////////////////
00205     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00206     loser_tree<ValTp_, Cmp_, KNKMAX>::loser_tree() : size_(0), logK(0), k(1), mem_cons_(0)
00207     {
00208         free_slots.push(0);
00209         segment[0] = NULL;
00210         current[0] = &sentinel;
00211         current_end[0] = &sentinel;
00212         // entry and sentinel are initialized by init
00213         // since they need the value of supremum
00214         init();
00215     }
00216 
00217     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00218     void loser_tree<ValTp_, Cmp_, KNKMAX>::init()
00219     {
00220         assert(!cmp(cmp.min_value(), cmp.min_value())); // verify strict weak ordering
00221         sentinel = cmp.min_value();
00222         rebuildLoserTree();
00223 #if STXXL_PQ_INTERNAL_LOSER_TREE
00224         assert(current[entry[0].index] == &sentinel);
00225 #endif  //STXXL_PQ_INTERNAL_LOSER_TREE
00226     }
00227 
00228 
00229 // rebuild loser tree information from the values in current
00230     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00231     void loser_tree<ValTp_, Cmp_, KNKMAX>::rebuildLoserTree()
00232     {
00233 #if STXXL_PQ_INTERNAL_LOSER_TREE
00234         assert(LOG2<KNKMAX>::floor == LOG2<KNKMAX>::ceil); // KNKMAX needs to be a power of two
00235         unsigned_type winner = initWinner(1);
00236         entry[0].index = winner;
00237         entry[0].key = *(current[winner]);
00238 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
00239     }
00240 
00241 
00242 #if STXXL_PQ_INTERNAL_LOSER_TREE
00243 // given any values in the leaves this
00244 // routing recomputes upper levels of the tree
00245 // from scratch in linear time
00246 // initialize entry[root].index and the subtree rooted there
00247 // return winner index
00248     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00249     unsigned_type loser_tree<ValTp_, Cmp_, KNKMAX>::initWinner(unsigned_type root)
00250     {
00251         if (root >= k) { // leaf reached
00252             return root - k;
00253         } else {
00254             unsigned_type left = initWinner(2 * root);
00255             unsigned_type right = initWinner(2 * root + 1);
00256             Element lk = *(current[left]);
00257             Element rk = *(current[right]);
00258             if (!(cmp(lk, rk))) { // right subtree loses
00259                 entry[root].index = right;
00260                 entry[root].key = rk;
00261                 return left;
00262             } else {
00263                 entry[root].index = left;
00264                 entry[root].key = lk;
00265                 return right;
00266             }
00267         }
00268     }
00269 
00270 
00271 // first go up the tree all the way to the root
00272 // hand down old winner for the respective subtree
00273 // based on new value, and old winner and loser
00274 // update each node on the path to the root top down.
00275 // This is implemented recursively
00276     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00277     void loser_tree<ValTp_, Cmp_, KNKMAX>::update_on_insert(
00278         unsigned_type node,
00279         const Element & newKey,
00280         unsigned_type newIndex,
00281         Element * winnerKey,
00282         unsigned_type * winnerIndex,       // old winner
00283         unsigned_type * mask)              // 1 << (ceil(log KNK) - dist-from-root)
00284     {
00285         if (node == 0) {                   // winner part of root
00286             *mask = 1 << (logK - 1);
00287             *winnerKey = entry[0].key;
00288             *winnerIndex = entry[0].index;
00289             if (cmp(entry[node].key, newKey))
00290             {
00291                 entry[node].key = newKey;
00292                 entry[node].index = newIndex;
00293             }
00294         } else {
00295             update_on_insert(node >> 1, newKey, newIndex, winnerKey, winnerIndex, mask);
00296             Element loserKey = entry[node].key;
00297             unsigned_type loserIndex = entry[node].index;
00298             if ((*winnerIndex & *mask) != (newIndex & *mask)) { // different subtrees
00299                 if (cmp(loserKey, newKey)) {                    // newKey will have influence here
00300                     if (cmp(*winnerKey, newKey)) {              // old winner loses here
00301                         entry[node].key = *winnerKey;
00302                         entry[node].index = *winnerIndex;
00303                     } else {                                    // new entry loses here
00304                         entry[node].key = newKey;
00305                         entry[node].index = newIndex;
00306                     }
00307                 }
00308                 *winnerKey = loserKey;
00309                 *winnerIndex = loserIndex;
00310             }
00311             // note that nothing needs to be done if
00312             // the winner came from the same subtree
00313             // a) newKey <= winnerKey => even more reason for the other tree to lose
00314             // b) newKey >  winnerKey => the old winner will beat the new
00315             //                           entry further down the tree
00316             // also the same old winner is handed down the tree
00317 
00318             *mask >>= 1; // next level
00319         }
00320     }
00321 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
00322 
00323 
00324 // make the tree two times as wide
00325     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00326     void loser_tree<ValTp_, Cmp_, KNKMAX>::doubleK()
00327     {
00328         STXXL_VERBOSE3("loser_tree::doubleK (before) k=" << k << " logK=" << logK << " KNKMAX=" << KNKMAX << " #free=" << free_slots.size());
00329         assert(k > 0);
00330         assert(k < KNKMAX);
00331         assert(free_slots.empty());                      // stack was free (probably not needed)
00332 
00333         // make all new entries free
00334         // and push them on the free stack
00335         for (unsigned_type i = 2 * k - 1; i >= k; i--)   // backwards
00336         {
00337             current[i] = &sentinel;
00338             current_end[i] = &sentinel;
00339             segment[i] = NULL;
00340             free_slots.push(i);
00341         }
00342 
00343         // double the size
00344         k *= 2;
00345         logK++;
00346 
00347         STXXL_VERBOSE3("loser_tree::doubleK (after)  k=" << k << " logK=" << logK << " KNKMAX=" << KNKMAX << " #free=" << free_slots.size());
00348         assert(!free_slots.empty());
00349 
00350         // recompute loser tree information
00351         rebuildLoserTree();
00352     }
00353 
00354 
00355 // compact nonempty segments in the left half of the tree
00356     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00357     void loser_tree<ValTp_, Cmp_, KNKMAX>::compactTree()
00358     {
00359         STXXL_VERBOSE3("loser_tree::compactTree (before) k=" << k << " logK=" << logK << " #free=" << free_slots.size());
00360         assert(logK > 0);
00361 
00362         // compact all nonempty segments to the left
00363         unsigned_type pos = 0;
00364         unsigned_type last_empty = 0;
00365         for ( ; pos < k; pos++)
00366         {
00367             if (not_sentinel(*(current[pos])))
00368             {
00369                 segment_size[last_empty] = segment_size[pos];
00370                 current[last_empty] = current[pos];
00371                 current_end[last_empty] = current_end[pos];
00372                 segment[last_empty] = segment[pos];
00373                 last_empty++;
00374             } /*
00375                 else
00376                 {
00377                 if(segment[pos])
00378                 {
00379                 STXXL_VERBOSE2("loser_tree::compactTree() deleting segment "<<pos<<
00380                                         " address: "<<segment[pos]<<" size: "<<segment_size[pos]);
00381                 delete [] segment[pos];
00382                 segment[pos] = 0;
00383                 mem_cons_ -= segment_size[pos];
00384                 }
00385                 }*/
00386         }
00387 
00388         // half degree as often as possible
00389         while ((k > 1) && ((k / 2) >= last_empty))
00390         {
00391             k /= 2;
00392             logK--;
00393         }
00394 
00395         // overwrite garbage and compact the stack of free segment indices
00396         free_slots.clear(); // none free
00397         for ( ; last_empty < k; last_empty++)
00398         {
00399             current[last_empty] = &sentinel;
00400             current_end[last_empty] = &sentinel;
00401             free_slots.push(last_empty);
00402         }
00403 
00404         STXXL_VERBOSE3("loser_tree::compactTree (after)  k=" << k << " logK=" << logK << " #free=" << free_slots.size());
00405 
00406         // recompute loser tree information
00407         rebuildLoserTree();
00408     }
00409 
00410 
00411 // insert segment beginning at target
00412 // require: is_space_available() == 1
00413     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00414     void loser_tree<ValTp_, Cmp_, KNKMAX>::insert_segment(Element * target, unsigned_type length)
00415     {
00416         STXXL_VERBOSE2("loser_tree::insert_segment(" << target << "," << length << ")");
00417         //std::copy(target,target + length,std::ostream_iterator<ValTp_>(std::cout, "\n"));
00418 
00419         if (length > 0)
00420         {
00421             assert(not_sentinel(target[0]));
00422             assert(not_sentinel(target[length - 1]));
00423             assert(is_sentinel(target[length]));
00424 
00425             // get a free slot
00426             if (free_slots.empty())
00427             {   // tree is too small
00428                 doubleK();
00429             }
00430             assert(!free_slots.empty());
00431             unsigned_type index = free_slots.top();
00432             free_slots.pop();
00433 
00434 
00435             // link new segment
00436             current[index] = segment[index] = target;
00437             current_end[index] = target + length;
00438             segment_size[index] = (length + 1) * sizeof(value_type);
00439             mem_cons_ += (length + 1) * sizeof(value_type);
00440             size_ += length;
00441 
00442 #if STXXL_PQ_INTERNAL_LOSER_TREE
00443             // propagate new information up the tree
00444             Element dummyKey;
00445             unsigned_type dummyIndex;
00446             unsigned_type dummyMask;
00447             update_on_insert((index + k) >> 1, *target, index,
00448                              &dummyKey, &dummyIndex, &dummyMask);
00449 #endif      //STXXL_PQ_INTERNAL_LOSER_TREE
00450         } else {
00451             // immediately deallocate
00452             // this is not only an optimization
00453             // but also needed to keep free segments from
00454             // clogging up the tree
00455             delete[] target;
00456         }
00457     }
00458 
00459 
00460     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00461     loser_tree<ValTp_, Cmp_, KNKMAX>::~loser_tree()
00462     {
00463         STXXL_VERBOSE1("loser_tree::~loser_tree()");
00464         for (unsigned_type i = 0; i < k; ++i)
00465         {
00466             if (segment[i])
00467             {
00468                 STXXL_VERBOSE2("loser_tree::~loser_tree() deleting segment " << i);
00469                 delete[] segment[i];
00470                 mem_cons_ -= segment_size[i];
00471             }
00472         }
00473         // check whether we have not lost any memory
00474         assert(mem_cons_ == 0);
00475     }
00476 
00477 // free an empty segment .
00478     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00479     void loser_tree<ValTp_, Cmp_, KNKMAX>::deallocate_segment(unsigned_type slot)
00480     {
00481         // reroute current pointer to some empty sentinel segment
00482         // with a sentinel key
00483         STXXL_VERBOSE2("loser_tree::deallocate_segment() deleting segment " <<
00484                        slot << " address: " << segment[slot] << " size: " << (segment_size[slot] / sizeof(value_type)) - 1);
00485         current[slot] = &sentinel;
00486         current_end[slot] = &sentinel;
00487 
00488         // free memory
00489         delete[] segment[slot];
00490         segment[slot] = NULL;
00491         mem_cons_ -= segment_size[slot];
00492 
00493         // push on the stack of free segment indices
00494         free_slots.push(slot);
00495     }
00496 
00497 
00498 // delete the length smallest elements and write them to target
00499 // empty segments are deallocated
00500 // require:
00501 // - there are at least length elements
00502 // - segments are ended by sentinels
00503     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00504     void loser_tree<ValTp_, Cmp_, KNKMAX>::multi_merge(Element * target, unsigned_type length)
00505     {
00506         STXXL_VERBOSE3("loser_tree::multi_merge(target=" << target << ", len=" << length << ") k=" << k);
00507 
00508         if (length == 0)
00509             return;
00510 
00511         assert(k > 0);
00512         assert(length <= size_);
00513 
00514         //This is the place to make statistics about internal multi_merge calls.
00515 
00516 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
00517         priority_queue_local::invert_order<Cmp_, value_type, value_type> inv_cmp(cmp);
00518 #endif
00519         switch (logK) {
00520         case 0:
00521             assert(k == 1);
00522 #if STXXL_PQ_INTERNAL_LOSER_TREE
00523             assert(entry[0].index == 0);
00524 #endif      //STXXL_PQ_INTERNAL_LOSER_TREE
00525             assert(free_slots.empty());
00526             memcpy(target, current[0], length * sizeof(Element));
00527             //std::copy(current[0], current[0] + length, target);
00528             current[0] += length;
00529 #if STXXL_PQ_INTERNAL_LOSER_TREE
00530             entry[0].key = **current;
00531 #endif      //STXXL_PQ_INTERNAL_LOSER_TREE
00532             if (is_segment_empty(0))
00533                 deallocate_segment(0);
00534 
00535             break;
00536         case 1:
00537             assert(k == 2);
00538 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
00539             {
00540                 std::pair<Element *, Element *> seqs[2] =
00541                 {
00542                     std::make_pair(current[0], current_end[0]),
00543                     std::make_pair(current[1], current_end[1])
00544                 };
00545                 parallel::multiway_merge_sentinel(seqs, seqs + 2, target, inv_cmp, length);
00546                 current[0] = seqs[0].first;
00547                 current[1] = seqs[1].first;
00548             }
00549 #else
00550             merge_iterator(current[0], current[1], target, length, cmp);
00551             rebuildLoserTree();
00552 #endif
00553             if (is_segment_empty(0))
00554                 deallocate_segment(0);
00555 
00556             if (is_segment_empty(1))
00557                 deallocate_segment(1);
00558 
00559             break;
00560         case 2:
00561             assert(k == 4);
00562 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
00563             {
00564                 std::pair<Element *, Element *> seqs[4] =
00565                 {
00566                     std::make_pair(current[0], current_end[0]),
00567                     std::make_pair(current[1], current_end[1]),
00568                     std::make_pair(current[2], current_end[2]),
00569                     std::make_pair(current[3], current_end[3])
00570                 };
00571                 parallel::multiway_merge_sentinel(seqs, seqs + 4, target, inv_cmp, length);
00572                 current[0] = seqs[0].first;
00573                 current[1] = seqs[1].first;
00574                 current[2] = seqs[2].first;
00575                 current[3] = seqs[3].first;
00576             }
00577 #else
00578             if (is_segment_empty(3))
00579                 merge3_iterator(current[0], current[1], current[2], target, length, cmp);
00580             else
00581                 merge4_iterator(current[0], current[1], current[2], current[3], target, length, cmp);
00582 
00583             rebuildLoserTree();
00584 #endif
00585             if (is_segment_empty(0))
00586                 deallocate_segment(0);
00587 
00588             if (is_segment_empty(1))
00589                 deallocate_segment(1);
00590 
00591             if (is_segment_empty(2))
00592                 deallocate_segment(2);
00593 
00594             if (is_segment_empty(3))
00595                 deallocate_segment(3);
00596 
00597             break;
00598 #if !(STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL)
00599         case  3: multi_merge_f<3>(target, length);
00600             break;
00601         case  4: multi_merge_f<4>(target, length);
00602             break;
00603         case  5: multi_merge_f<5>(target, length);
00604             break;
00605         case  6: multi_merge_f<6>(target, length);
00606             break;
00607         case  7: multi_merge_f<7>(target, length);
00608             break;
00609         case  8: multi_merge_f<8>(target, length);
00610             break;
00611         case  9: multi_merge_f<9>(target, length);
00612             break;
00613         case 10: multi_merge_f<10>(target, length);
00614             break;
00615 #endif
00616         default:
00617 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
00618             {
00619                 std::vector<std::pair<Element *, Element *> > seqs;
00620                 std::vector<int_type> orig_seq_index;
00621                 for (unsigned int i = 0; i < k; ++i)
00622                 {
00623                     if (current[i] != current_end[i] && !is_sentinel(*current[i]))
00624                     {
00625                         seqs.push_back(std::make_pair(current[i], current_end[i]));
00626                         orig_seq_index.push_back(i);
00627                     }
00628                 }
00629 
00630                 parallel::multiway_merge_sentinel(seqs.begin(), seqs.end(), target, inv_cmp, length);
00631 
00632                 for (unsigned int i = 0; i < seqs.size(); ++i)
00633                 {
00634                     int_type seg = orig_seq_index[i];
00635                     current[seg] = seqs[i].first;
00636                 }
00637 
00638                 for (unsigned int i = 0; i < k; ++i)
00639                     if (is_segment_empty(i))
00640                     {
00641                         STXXL_VERBOSE3("deallocated " << i);
00642                         deallocate_segment(i);
00643                     }
00644             }
00645 #else
00646             multi_merge_k(target, length);
00647 #endif
00648             break;
00649         }
00650 
00651 
00652         size_ -= length;
00653 
00654         // compact tree if it got considerably smaller
00655         {
00656             const unsigned_type num_segments_used = k - free_slots.size();
00657             const unsigned_type num_segments_trigger = k - (3 * k / 5);
00658             // using k/2 would be worst case inefficient (for large k)
00659             // for k \in {2, 4, 8} the trigger is k/2 which is good
00660             // because we have special mergers for k \in {1, 2, 4}
00661             // there is also a special 3-way-merger, that will be
00662             // triggered if k == 4 && is_segment_empty(3)
00663             STXXL_VERBOSE3("loser_tree  compact? k=" << k << " #used=" << num_segments_used
00664                                                      << " <= #trigger=" << num_segments_trigger << " ==> "
00665                                                      << ((k > 1 && num_segments_used <= num_segments_trigger) ? "yes" : "no ")
00666                                                      << " || "
00667                                                      << ((k == 4 && !free_slots.empty() && !is_segment_empty(3)) ? "yes" : "no ")
00668                                                      << " #free=" << free_slots.size());
00669             if (k > 1 && ((num_segments_used <= num_segments_trigger) ||
00670                           (k == 4 && !free_slots.empty() && !is_segment_empty(3))))
00671             {
00672                 compactTree();
00673             }
00674         }
00675         //std::copy(target,target + length,std::ostream_iterator<ValTp_>(std::cout, "\n"));
00676     }
00677 
00678 
00679 // is this segment empty and does not point to sentinel yet?
00680     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00681     inline bool loser_tree<ValTp_, Cmp_, KNKMAX>::is_segment_empty(unsigned_type slot)
00682     {
00683         return (is_sentinel(*(current[slot])) && (current[slot] != &sentinel));
00684     }
00685 
00686 #if STXXL_PQ_INTERNAL_LOSER_TREE
00687 // multi-merge for arbitrary K
00688     template <class ValTp_, class Cmp_, unsigned KNKMAX>
00689     void loser_tree<ValTp_, Cmp_, KNKMAX>::
00690     multi_merge_k(Element * target, unsigned_type length)
00691     {
00692         Entry * currentPos;
00693         Element currentKey;
00694         unsigned_type currentIndex; // leaf pointed to by current entry
00695         unsigned_type kReg = k;
00696         Element * done = target + length;
00697         unsigned_type winnerIndex = entry[0].index;
00698         Element winnerKey = entry[0].key;
00699         Element * winnerPos;
00700 
00701         while (target != done)
00702         {
00703             winnerPos = current[winnerIndex];
00704 
00705             // write result
00706             *target = winnerKey;
00707 
00708             // advance winner segment
00709             ++winnerPos;
00710             current[winnerIndex] = winnerPos;
00711             winnerKey = *winnerPos;
00712 
00713             // remove winner segment if empty now
00714             if (is_sentinel(winnerKey)) //
00715                 deallocate_segment(winnerIndex);
00716 
00717 
00718             // go up the entry-tree
00719             for (unsigned_type i = (winnerIndex + kReg) >> 1; i > 0; i >>= 1) {
00720                 currentPos = entry + i;
00721                 currentKey = currentPos->key;
00722                 if (cmp(winnerKey, currentKey)) {
00723                     currentIndex = currentPos->index;
00724                     currentPos->key = winnerKey;
00725                     currentPos->index = winnerIndex;
00726                     winnerKey = currentKey;
00727                     winnerIndex = currentIndex;
00728                 }
00729             }
00730 
00731             ++target;
00732         }
00733         entry[0].index = winnerIndex;
00734         entry[0].key = winnerKey;
00735     }
00736 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
00737 } //priority_queue_local
00738 
00739 //! \}
00740 
00741 __STXXL_END_NAMESPACE
00742 
00743 #endif // !STXXL_PQ_LOSERTREE_HEADER
00744 // vim: et:ts=4:sw=4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines