STXXL  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pq_losertree.h
Go to the documentation of this file.
1 /***************************************************************************
2  * include/stxxl/bits/containers/pq_losertree.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 1999 Peter Sanders <[email protected]>
7  * Copyright (C) 2003, 2004, 2007 Roman Dementiev <[email protected]>
8  * Copyright (C) 2007-2009 Johannes Singler <[email protected]>
9  * Copyright (C) 2007, 2008 Andreas Beckmann <[email protected]>
10  *
11  * Distributed under the Boost Software License, Version 1.0.
12  * (See accompanying file LICENSE_1_0.txt or copy at
13  * http://www.boost.org/LICENSE_1_0.txt)
14  **************************************************************************/
15 
16 #ifndef STXXL_CONTAINERS_PQ_LOSERTREE_HEADER
17 #define STXXL_CONTAINERS_PQ_LOSERTREE_HEADER
18 
20 
22 
23 //! \addtogroup stlcontinternals
24 //!
25 //! \{
26 
27 /*! \internal
28  */
29 namespace priority_queue_local {
30 
31 //////////////////////////////////////////////////////////////////////
32 // The data structure from Knuth, "Sorting and Searching", Section 5.4.1
33 /*!
34  * Loser tree from Knuth, "Sorting and Searching", Section 5.4.1
35  * \param KNKMAX maximum arity of loser tree, has to be a power of two
36  */
37 template <class ValTp_, class Cmp_, unsigned KNKMAX>
38 class loser_tree : private noncopyable
39 {
40 public:
41  typedef ValTp_ value_type;
42  typedef Cmp_ comparator_type;
44 
45 private:
46 #if STXXL_PQ_INTERNAL_LOSER_TREE
47  struct Entry
48  {
49  value_type key; // Key of Loser element (winner for 0)
50  unsigned_type index; // number of losing segment
51  };
52 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
53 
55  // stack of free segment indices
57 
58  unsigned_type size_; // total number of elements stored
59  unsigned_type logK; // log of current tree size
60  unsigned_type k; // invariant (k == 1 << logK), always a power of two
61 
62  Element sentinel; // target of free segment pointers
63 
64 #if STXXL_PQ_INTERNAL_LOSER_TREE
65  // upper levels of loser trees
66  // entry[0] contains the winner info
67  Entry entry[KNKMAX];
68 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
69 
70  // leaf information
71  // note that Knuth uses indices k..k-1
72  // while we use 0..k-1
73  Element* current[KNKMAX]; // pointer to current element
74  Element* current_end[KNKMAX]; // pointer to end of block for current element
75  Element* segment[KNKMAX]; // start of Segments
76  unsigned_type segment_size[KNKMAX]; // just to count the internal memory consumption, in bytes
77 
79 
80  // private member functions
81  unsigned_type initWinner(unsigned_type root);
82  void update_on_insert(unsigned_type node, const Element& newKey, unsigned_type newIndex,
83  Element* winnerKey, unsigned_type* winnerIndex, unsigned_type* mask);
84  void deallocate_segment(unsigned_type slot);
85  void doubleK();
86  void compactTree();
87  void rebuildLoserTree();
88  bool is_segment_empty(unsigned_type slot);
89  void multi_merge_k(Element* target, unsigned_type length);
90 
91 #if STXXL_PQ_INTERNAL_LOSER_TREE
92  template <int LogK>
93  void multi_merge_f(Element* target, unsigned_type length)
94  {
95  //Entry *currentPos;
96  //Element currentKey;
97  //int currentIndex; // leaf pointed to by current entry
98  Element* done = target + length;
99  Entry* regEntry = entry;
100  Element** regStates = current;
101  unsigned_type winnerIndex = regEntry[0].index;
102  Element winnerKey = regEntry[0].key;
103  Element* winnerPos;
104  //Element sup = sentinel; // supremum
105 
106  assert(logK >= LogK);
107  while (target != done)
108  {
109  winnerPos = regStates[winnerIndex];
110 
111  // write result
112  *target = winnerKey;
113 
114  // advance winner segment
115  ++winnerPos;
116  regStates[winnerIndex] = winnerPos;
117  winnerKey = *winnerPos;
118 
119  // remove winner segment if empty now
120  if (is_sentinel(winnerKey))
121  {
122  deallocate_segment(winnerIndex);
123  }
124  ++target;
125 
126  // update loser tree
127 #define TreeStep(L) \
128  if (1 << LogK >= 1 << L) { \
129  Entry* pos ## L = regEntry + ((winnerIndex + (1 << LogK)) >> ((LogK - L + 1 >= 0) ? (LogK - L + 1) : 0)); \
130  Element key ## L = pos ## L->key; \
131  if (cmp(winnerKey, key ## L)) { \
132  unsigned_type index ## L = pos ## L->index; \
133  pos ## L->key = winnerKey; \
134  pos ## L->index = winnerIndex; \
135  winnerKey = key ## L; \
136  winnerIndex = index ## L; \
137  } \
138  }
139  TreeStep(10);
140  TreeStep(9);
141  TreeStep(8);
142  TreeStep(7);
143  TreeStep(6);
144  TreeStep(5);
145  TreeStep(4);
146  TreeStep(3);
147  TreeStep(2);
148  TreeStep(1);
149 #undef TreeStep
150  }
151  regEntry[0].index = winnerIndex;
152  regEntry[0].key = winnerKey;
153  }
154 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
155 
156 public:
157  bool is_sentinel(const Element& a)
158  {
159  return !(cmp(cmp.min_value(), a));
160  }
161  bool not_sentinel(const Element& a)
162  {
163  return cmp(cmp.min_value(), a);
164  }
165 
166 public:
167  loser_tree();
168  ~loser_tree();
169  void init();
170 
171  void swap(loser_tree& obj)
172  {
173  std::swap(cmp, obj.cmp);
174  std::swap(free_slots, obj.free_slots);
175  std::swap(size_, obj.size_);
176  std::swap(logK, obj.logK);
177  std::swap(k, obj.k);
178  std::swap(sentinel, obj.sentinel);
179 #if STXXL_PQ_INTERNAL_LOSER_TREE
180  swap_1D_arrays(entry, obj.entry, KNKMAX);
181 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
182  swap_1D_arrays(current, obj.current, KNKMAX);
183  swap_1D_arrays(current_end, obj.current_end, KNKMAX);
184  swap_1D_arrays(segment, obj.segment, KNKMAX);
185  swap_1D_arrays(segment_size, obj.segment_size, KNKMAX);
186  std::swap(mem_cons_, obj.mem_cons_);
187  }
188 
189  void multi_merge(Element* begin, Element* end)
190  {
191  multi_merge(begin, end - begin);
192  }
193  void multi_merge(Element*, unsigned_type length);
194 
195  unsigned_type mem_cons() const { return mem_cons_; }
196 
197  bool is_space_available() const // for new segment
198  {
199  return (k < KNKMAX) || !free_slots.empty();
200  }
201 
202  void insert_segment(Element * target, unsigned_type length); // insert segment beginning at target
203  unsigned_type size() const { return size_; }
204 };
205 
206 ///////////////////////// LoserTree ///////////////////////////////////
207 template <class ValTp_, class Cmp_, unsigned KNKMAX>
208 loser_tree<ValTp_, Cmp_, KNKMAX>::loser_tree() : size_(0), logK(0), k(1), mem_cons_(0)
209 {
210  free_slots.push(0);
211  segment[0] = NULL;
212  current[0] = &sentinel;
213  current_end[0] = &sentinel;
214  // entry and sentinel are initialized by init
215  // since they need the value of supremum
216  init();
217 }
218 
219 template <class ValTp_, class Cmp_, unsigned KNKMAX>
221 {
222  assert(!cmp(cmp.min_value(), cmp.min_value())); // verify strict weak ordering
223  sentinel = cmp.min_value();
224  rebuildLoserTree();
225 #if STXXL_PQ_INTERNAL_LOSER_TREE
226  assert(current[entry[0].index] == &sentinel);
227 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
228 }
229 
230 
231 // rebuild loser tree information from the values in current
232 template <class ValTp_, class Cmp_, unsigned KNKMAX>
234 {
235 #if STXXL_PQ_INTERNAL_LOSER_TREE
236  assert(LOG2<KNKMAX>::floor == LOG2<KNKMAX>::ceil); // KNKMAX needs to be a power of two
237  unsigned_type winner = initWinner(1);
238  entry[0].index = winner;
239  entry[0].key = *(current[winner]);
240 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
241 }
242 
243 
244 #if STXXL_PQ_INTERNAL_LOSER_TREE
245 // given any values in the leaves this
246 // routing recomputes upper levels of the tree
247 // from scratch in linear time
248 // initialize entry[root].index and the subtree rooted there
249 // return winner index
250 template <class ValTp_, class Cmp_, unsigned KNKMAX>
252 {
253  if (root >= k) { // leaf reached
254  return root - k;
255  } else {
256  unsigned_type left = initWinner(2 * root);
257  unsigned_type right = initWinner(2 * root + 1);
258  Element lk = *(current[left]);
259  Element rk = *(current[right]);
260  if (!(cmp(lk, rk))) { // right subtree loses
261  entry[root].index = right;
262  entry[root].key = rk;
263  return left;
264  } else {
265  entry[root].index = left;
266  entry[root].key = lk;
267  return right;
268  }
269  }
270 }
271 
272 
273 // first go up the tree all the way to the root
274 // hand down old winner for the respective subtree
275 // based on new value, and old winner and loser
276 // update each node on the path to the root top down.
277 // This is implemented recursively
278 template <class ValTp_, class Cmp_, unsigned KNKMAX>
280  unsigned_type node,
281  const Element& newKey,
282  unsigned_type newIndex,
283  Element* winnerKey,
284  unsigned_type* winnerIndex, // old winner
285  unsigned_type* mask) // 1 << (ceil(log KNK) - dist-from-root)
286 {
287  if (node == 0) { // winner part of root
288  *mask = (unsigned_type)(1) << (logK - 1);
289  *winnerKey = entry[0].key;
290  *winnerIndex = entry[0].index;
291  if (cmp(entry[node].key, newKey))
292  {
293  entry[node].key = newKey;
294  entry[node].index = newIndex;
295  }
296  } else {
297  update_on_insert(node >> 1, newKey, newIndex, winnerKey, winnerIndex, mask);
298  Element loserKey = entry[node].key;
299  unsigned_type loserIndex = entry[node].index;
300  if ((*winnerIndex & *mask) != (newIndex & *mask)) { // different subtrees
301  if (cmp(loserKey, newKey)) { // newKey will have influence here
302  if (cmp(*winnerKey, newKey)) { // old winner loses here
303  entry[node].key = *winnerKey;
304  entry[node].index = *winnerIndex;
305  } else { // new entry loses here
306  entry[node].key = newKey;
307  entry[node].index = newIndex;
308  }
309  }
310  *winnerKey = loserKey;
311  *winnerIndex = loserIndex;
312  }
313  // note that nothing needs to be done if
314  // the winner came from the same subtree
315  // a) newKey <= winnerKey => even more reason for the other tree to lose
316  // b) newKey > winnerKey => the old winner will beat the new
317  // entry further down the tree
318  // also the same old winner is handed down the tree
319 
320  *mask >>= 1; // next level
321  }
322 }
323 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
324 
325 
326 // make the tree two times as wide
327 template <class ValTp_, class Cmp_, unsigned KNKMAX>
329 {
330  STXXL_VERBOSE3("loser_tree::doubleK (before) k=" << k << " logK=" << logK << " KNKMAX=" << KNKMAX << " #free=" << free_slots.size());
331  assert(k > 0);
332  assert(k < KNKMAX);
333  assert(free_slots.empty()); // stack was free (probably not needed)
334 
335  // make all new entries free
336  // and push them on the free stack
337  for (unsigned_type i = 2 * k - 1; i >= k; i--) // backwards
338  {
339  current[i] = &sentinel;
340  current_end[i] = &sentinel;
341  segment[i] = NULL;
342  free_slots.push(i);
343  }
344 
345  // double the size
346  k *= 2;
347  logK++;
348 
349  STXXL_VERBOSE3("loser_tree::doubleK (after) k=" << k << " logK=" << logK << " KNKMAX=" << KNKMAX << " #free=" << free_slots.size());
350  assert(!free_slots.empty());
351 
352  // recompute loser tree information
353  rebuildLoserTree();
354 }
355 
356 
357 // compact nonempty segments in the left half of the tree
358 template <class ValTp_, class Cmp_, unsigned KNKMAX>
360 {
361  STXXL_VERBOSE3("loser_tree::compactTree (before) k=" << k << " logK=" << logK << " #free=" << free_slots.size());
362  assert(logK > 0);
363 
364  // compact all nonempty segments to the left
365  unsigned_type pos = 0;
366  unsigned_type last_empty = 0;
367  for ( ; pos < k; pos++)
368  {
369  if (not_sentinel(*(current[pos])))
370  {
371  segment_size[last_empty] = segment_size[pos];
372  current[last_empty] = current[pos];
373  current_end[last_empty] = current_end[pos];
374  segment[last_empty] = segment[pos];
375  last_empty++;
376  } /*
377  else
378  {
379  if(segment[pos])
380  {
381  STXXL_VERBOSE2("loser_tree::compactTree() deleting segment "<<pos<<
382  " address: "<<segment[pos]<<" size: "<<segment_size[pos]);
383  delete [] segment[pos];
384  segment[pos] = 0;
385  mem_cons_ -= segment_size[pos];
386  }
387  }*/
388  }
389 
390  // half degree as often as possible
391  while ((k > 1) && ((k / 2) >= last_empty))
392  {
393  k /= 2;
394  logK--;
395  }
396 
397  // overwrite garbage and compact the stack of free segment indices
398  free_slots.clear(); // none free
399  for ( ; last_empty < k; last_empty++)
400  {
401  current[last_empty] = &sentinel;
402  current_end[last_empty] = &sentinel;
403  free_slots.push(last_empty);
404  }
405 
406  STXXL_VERBOSE3("loser_tree::compactTree (after) k=" << k << " logK=" << logK << " #free=" << free_slots.size());
407 
408  // recompute loser tree information
409  rebuildLoserTree();
410 }
411 
412 
413 // insert segment beginning at target
414 // require: is_space_available() == 1
415 template <class ValTp_, class Cmp_, unsigned KNKMAX>
417 {
418  STXXL_VERBOSE2("loser_tree::insert_segment(" << target << "," << length << ")");
419  //std::copy(target,target + length,std::ostream_iterator<ValTp_>(std::cout, "\n"));
420 
421  if (length > 0)
422  {
423  assert(not_sentinel(target[0]));
424  assert(not_sentinel(target[length - 1]));
425  assert(is_sentinel(target[length]));
426 
427  // get a free slot
428  if (free_slots.empty())
429  { // tree is too small
430  doubleK();
431  }
432  assert(!free_slots.empty());
433  unsigned_type index = free_slots.top();
434  free_slots.pop();
435 
436 
437  // link new segment
438  current[index] = segment[index] = target;
439  current_end[index] = target + length;
440  segment_size[index] = (length + 1) * sizeof(value_type);
441  mem_cons_ += (length + 1) * sizeof(value_type);
442  size_ += length;
443 
444 #if STXXL_PQ_INTERNAL_LOSER_TREE
445  // propagate new information up the tree
446  Element dummyKey;
447  unsigned_type dummyIndex;
448  unsigned_type dummyMask;
449  update_on_insert((index + k) >> 1, *target, index,
450  &dummyKey, &dummyIndex, &dummyMask);
451 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
452  } else {
453  // immediately deallocate
454  // this is not only an optimization
455  // but also needed to keep free segments from
456  // clogging up the tree
457  delete[] target;
458  }
459 }
460 
461 
462 template <class ValTp_, class Cmp_, unsigned KNKMAX>
464 {
465  STXXL_VERBOSE1("loser_tree::~loser_tree()");
466  for (unsigned_type i = 0; i < k; ++i)
467  {
468  if (segment[i])
469  {
470  STXXL_VERBOSE2("loser_tree::~loser_tree() deleting segment " << i);
471  delete[] segment[i];
472  mem_cons_ -= segment_size[i];
473  }
474  }
475  // check whether we have not lost any memory
476  assert(mem_cons_ == 0);
477 }
478 
479 // free an empty segment .
480 template <class ValTp_, class Cmp_, unsigned KNKMAX>
482 {
483  // reroute current pointer to some empty sentinel segment
484  // with a sentinel key
485  STXXL_VERBOSE2("loser_tree::deallocate_segment() deleting segment " <<
486  slot << " address: " << segment[slot] << " size: " << (segment_size[slot] / sizeof(value_type)) - 1);
487  current[slot] = &sentinel;
488  current_end[slot] = &sentinel;
489 
490  // free memory
491  delete[] segment[slot];
492  segment[slot] = NULL;
493  mem_cons_ -= segment_size[slot];
494 
495  // push on the stack of free segment indices
496  free_slots.push(slot);
497 }
498 
499 
500 // delete the length smallest elements and write them to target
501 // empty segments are deallocated
502 // require:
503 // - there are at least length elements
504 // - segments are ended by sentinels
505 template <class ValTp_, class Cmp_, unsigned KNKMAX>
507 {
508  STXXL_VERBOSE3("loser_tree::multi_merge(target=" << target << ", len=" << length << ") k=" << k);
509 
510  if (length == 0)
511  return;
512 
513  assert(k > 0);
514  assert(length <= size_);
515 
516  //This is the place to make statistics about internal multi_merge calls.
517 
518 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
520 #endif
521  switch (logK) {
522  case 0:
523  assert(k == 1);
524 #if STXXL_PQ_INTERNAL_LOSER_TREE
525  assert(entry[0].index == 0);
526 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
527  assert(free_slots.empty());
528  memcpy(target, current[0], length * sizeof(Element));
529  //std::copy(current[0], current[0] + length, target);
530  current[0] += length;
531 #if STXXL_PQ_INTERNAL_LOSER_TREE
532  entry[0].key = **current;
533 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
534  if (is_segment_empty(0))
535  deallocate_segment(0);
536 
537  break;
538  case 1:
539  assert(k == 2);
540 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
541  {
542  std::pair<Element*, Element*> seqs[2] =
543  {
544  std::make_pair(current[0], current_end[0]),
545  std::make_pair(current[1], current_end[1])
546  };
547  parallel::multiway_merge_sentinel(seqs, seqs + 2, target, inv_cmp, length);
548  current[0] = seqs[0].first;
549  current[1] = seqs[1].first;
550  }
551 #else
552  merge_iterator(current[0], current[1], target, length, cmp);
553  rebuildLoserTree();
554 #endif
555  if (is_segment_empty(0))
556  deallocate_segment(0);
557 
558  if (is_segment_empty(1))
559  deallocate_segment(1);
560 
561  break;
562  case 2:
563  assert(k == 4);
564 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
565  {
566  std::pair<Element*, Element*> seqs[4] =
567  {
568  std::make_pair(current[0], current_end[0]),
569  std::make_pair(current[1], current_end[1]),
570  std::make_pair(current[2], current_end[2]),
571  std::make_pair(current[3], current_end[3])
572  };
573  parallel::multiway_merge_sentinel(seqs, seqs + 4, target, inv_cmp, length);
574  current[0] = seqs[0].first;
575  current[1] = seqs[1].first;
576  current[2] = seqs[2].first;
577  current[3] = seqs[3].first;
578  }
579 #else
580  if (is_segment_empty(3))
581  merge3_iterator(current[0], current[1], current[2], target, length, cmp);
582  else
583  merge4_iterator(current[0], current[1], current[2], current[3], target, length, cmp);
584 
585  rebuildLoserTree();
586 #endif
587  if (is_segment_empty(0))
588  deallocate_segment(0);
589 
590  if (is_segment_empty(1))
591  deallocate_segment(1);
592 
593  if (is_segment_empty(2))
594  deallocate_segment(2);
595 
596  if (is_segment_empty(3))
597  deallocate_segment(3);
598 
599  break;
600 #if !(STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL)
601  case 3: multi_merge_f<3>(target, length);
602  break;
603  case 4: multi_merge_f<4>(target, length);
604  break;
605  case 5: multi_merge_f<5>(target, length);
606  break;
607  case 6: multi_merge_f<6>(target, length);
608  break;
609  case 7: multi_merge_f<7>(target, length);
610  break;
611  case 8: multi_merge_f<8>(target, length);
612  break;
613  case 9: multi_merge_f<9>(target, length);
614  break;
615  case 10: multi_merge_f<10>(target, length);
616  break;
617 #endif
618  default:
619 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
620  {
621  std::vector<std::pair<Element*, Element*> > seqs;
622  std::vector<int_type> orig_seq_index;
623  for (unsigned int i = 0; i < k; ++i)
624  {
625  if (current[i] != current_end[i] && !is_sentinel(*current[i]))
626  {
627  seqs.push_back(std::make_pair(current[i], current_end[i]));
628  orig_seq_index.push_back(i);
629  }
630  }
631 
632  parallel::multiway_merge_sentinel(seqs.begin(), seqs.end(), target, inv_cmp, length);
633 
634  for (unsigned int i = 0; i < seqs.size(); ++i)
635  {
636  int_type seg = orig_seq_index[i];
637  current[seg] = seqs[i].first;
638  }
639 
640  for (unsigned int i = 0; i < k; ++i)
641  if (is_segment_empty(i))
642  {
643  STXXL_VERBOSE3("deallocated " << i);
644  deallocate_segment(i);
645  }
646  }
647 #else
648  multi_merge_k(target, length);
649 #endif
650  break;
651  }
652 
653 
654  size_ -= length;
655 
656  // compact tree if it got considerably smaller
657  {
658  const unsigned_type num_segments_used = k - free_slots.size();
659  const unsigned_type num_segments_trigger = k - (3 * k / 5);
660  // using k/2 would be worst case inefficient (for large k)
661  // for k \in {2, 4, 8} the trigger is k/2 which is good
662  // because we have special mergers for k \in {1, 2, 4}
663  // there is also a special 3-way-merger, that will be
664  // triggered if k == 4 && is_segment_empty(3)
665  STXXL_VERBOSE3("loser_tree compact? k=" << k << " #used=" << num_segments_used
666  << " <= #trigger=" << num_segments_trigger << " ==> "
667  << ((k > 1 && num_segments_used <= num_segments_trigger) ? "yes" : "no ")
668  << " || "
669  << ((k == 4 && !free_slots.empty() && !is_segment_empty(3)) ? "yes" : "no ")
670  << " #free=" << free_slots.size());
671  if (k > 1 && ((num_segments_used <= num_segments_trigger) ||
672  (k == 4 && !free_slots.empty() && !is_segment_empty(3))))
673  {
674  compactTree();
675  }
676  }
677  //std::copy(target,target + length,std::ostream_iterator<ValTp_>(std::cout, "\n"));
678 }
679 
680 
681 // is this segment empty and does not point to sentinel yet?
682 template <class ValTp_, class Cmp_, unsigned KNKMAX>
684 {
685  return (is_sentinel(*(current[slot])) && (current[slot] != &sentinel));
686 }
687 
688 #if STXXL_PQ_INTERNAL_LOSER_TREE
689 // multi-merge for arbitrary K
690 template <class ValTp_, class Cmp_, unsigned KNKMAX>
692 multi_merge_k(Element* target, unsigned_type length)
693 {
694  Entry* currentPos;
695  Element currentKey;
696  unsigned_type currentIndex; // leaf pointed to by current entry
697  unsigned_type kReg = k;
698  Element* done = target + length;
699  unsigned_type winnerIndex = entry[0].index;
700  Element winnerKey = entry[0].key;
701  Element* winnerPos;
702 
703  while (target != done)
704  {
705  winnerPos = current[winnerIndex];
706 
707  // write result
708  *target = winnerKey;
709 
710  // advance winner segment
711  ++winnerPos;
712  current[winnerIndex] = winnerPos;
713  winnerKey = *winnerPos;
714 
715  // remove winner segment if empty now
716  if (is_sentinel(winnerKey)) //
717  deallocate_segment(winnerIndex);
718 
719 
720  // go up the entry-tree
721  for (unsigned_type i = (winnerIndex + kReg) >> 1; i > 0; i >>= 1) {
722  currentPos = entry + i;
723  currentKey = currentPos->key;
724  if (cmp(winnerKey, currentKey)) {
725  currentIndex = currentPos->index;
726  currentPos->key = winnerKey;
727  currentPos->index = winnerIndex;
728  winnerKey = currentKey;
729  winnerIndex = currentIndex;
730  }
731  }
732 
733  ++target;
734  }
735  entry[0].index = winnerIndex;
736  entry[0].key = winnerKey;
737 }
738 #endif // STXXL_PQ_INTERNAL_LOSER_TREE
739 
740 } // namespace priority_queue_local
741 
742 //! \}
743 
745 
746 #endif // !STXXL_CONTAINERS_PQ_LOSERTREE_HEADER
747 // vim: et:ts=4:sw=4
void swap_1D_arrays(T *a, T *b, unsigned_type size)
Definition: utils.h:247
Inverts the order of a comparison functor by swapping its arguments.
Definition: pq_helpers.h:189
void update_on_insert(unsigned_type node, const Element &newKey, unsigned_type newIndex, Element *winnerKey, unsigned_type *winnerIndex, unsigned_type *mask)
internal_bounded_stack< unsigned_type, KNKMAX > free_slots
Definition: pq_losertree.h:56
void merge4_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, InputIterator &source3, OutputIterator target, unsigned_type length, CompareType &cmp)
Definition: pq_mergers.h:141
void deallocate_segment(unsigned_type slot)
Definition: pq_losertree.h:481
#define STXXL_VERBOSE2(x)
Definition: verbose.h:107
void merge_iterator(InputIterator &source0, InputIterator &source1, OutputIterator target, unsigned_type length, CompareType &cmp)
Definition: pq_mergers.h:41
Loser tree from Knuth, &quot;Sorting and Searching&quot;, Section 5.4.1.
Definition: pq_losertree.h:38
void multi_merge(Element *begin, Element *end)
Definition: pq_losertree.h:189
void multi_merge_k(Element *target, unsigned_type length)
#define STXXL_VERBOSE3(x)
Definition: verbose.h:113
choose_int_types< my_pointer_size >::int_type int_type
Definition: types.h:66
bool is_segment_empty(unsigned_type slot)
Definition: pq_losertree.h:683
void merge3_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, OutputIterator target, unsigned_type length, CompareType &cmp)
Definition: pq_mergers.h:73
#define STXXL_BEGIN_NAMESPACE
Definition: namespace.h:16
#define STXXL_VERBOSE1(x)
Definition: verbose.h:99
unsigned_type initWinner(unsigned_type root)
void insert_segment(Element *target, unsigned_type length)
Definition: pq_losertree.h:416
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
Definition: types.h:67
#define TreeStep(L)
#define STXXL_END_NAMESPACE
Definition: namespace.h:17