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