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