16 #ifndef STXXL_PQ_LOSERTREE_HEADER
17 #define STXXL_PQ_LOSERTREE_HEADER
19 __STXXL_BEGIN_NAMESPACE
27 namespace priority_queue_local
35 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
39 typedef ValTp_ value_type;
40 typedef Cmp_ comparator_type;
41 typedef value_type Element;
44 #if STXXL_PQ_INTERNAL_LOSER_TREE
50 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
62 #if STXXL_PQ_INTERNAL_LOSER_TREE
66 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
71 Element * current[KNKMAX];
72 Element * current_end[KNKMAX];
73 Element * segment[KNKMAX];
74 unsigned_type segment_size[KNKMAX];
76 unsigned_type mem_cons_;
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);
85 void rebuildLoserTree();
86 bool is_segment_empty(unsigned_type slot);
87 void multi_merge_k(Element * target, unsigned_type length);
89 #if STXXL_PQ_INTERNAL_LOSER_TREE
90 template <
unsigned LogK>
91 void multi_merge_f(Element * target, unsigned_type length)
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;
104 assert(logK >= LogK);
105 while (target != done)
107 winnerPos = regStates[winnerIndex];
114 regStates[winnerIndex] = winnerPos;
115 winnerKey = *winnerPos;
118 if (is_sentinel(winnerKey))
120 deallocate_segment(winnerIndex);
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; \
149 regEntry[0].index = winnerIndex;
150 regEntry[0].key = winnerKey;
152 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
155 bool is_sentinel(
const Element & a)
157 return !(cmp(cmp.min_value(), a));
159 bool not_sentinel(
const Element & a)
161 return cmp(cmp.min_value(), a);
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);
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_);
187 void multi_merge(Element * begin, Element * end)
189 multi_merge(begin, end - begin);
191 void multi_merge(Element *, unsigned_type length);
193 unsigned_type mem_cons()
const {
return mem_cons_; }
195 bool is_space_available()
const
197 return (k < KNKMAX) || !free_slots.empty();
200 void insert_segment(Element * target, unsigned_type length);
201 unsigned_type size() {
return size_; }
205 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
210 current[0] = &sentinel;
211 current_end[0] = &sentinel;
217 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
218 void loser_tree<ValTp_, Cmp_, KNKMAX>::init()
220 assert(!cmp(cmp.min_value(), cmp.min_value()));
221 sentinel = cmp.min_value();
223 #if STXXL_PQ_INTERNAL_LOSER_TREE
224 assert(current[entry[0].index] == &sentinel);
225 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
230 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
231 void loser_tree<ValTp_, Cmp_, KNKMAX>::rebuildLoserTree()
233 #if STXXL_PQ_INTERNAL_LOSER_TREE
234 assert(LOG2<KNKMAX>::floor == LOG2<KNKMAX>::ceil);
235 unsigned_type winner = initWinner(1);
236 entry[0].index = winner;
237 entry[0].key = *(current[winner]);
238 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
242 #if STXXL_PQ_INTERNAL_LOSER_TREE
248 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
249 unsigned_type loser_tree<ValTp_, Cmp_, KNKMAX>::initWinner(unsigned_type root)
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))) {
259 entry[root].index = right;
260 entry[root].key = rk;
263 entry[root].index = left;
264 entry[root].key = lk;
276 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
277 void loser_tree<ValTp_, Cmp_, KNKMAX>::update_on_insert(
279 const Element & newKey,
280 unsigned_type newIndex,
282 unsigned_type * winnerIndex,
283 unsigned_type * mask)
286 *mask = 1 << (logK - 1);
287 *winnerKey = entry[0].key;
288 *winnerIndex = entry[0].index;
289 if (cmp(entry[node].key, newKey))
291 entry[node].key = newKey;
292 entry[node].index = newIndex;
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)) {
299 if (cmp(loserKey, newKey)) {
300 if (cmp(*winnerKey, newKey)) {
301 entry[node].key = *winnerKey;
302 entry[node].index = *winnerIndex;
304 entry[node].key = newKey;
305 entry[node].index = newIndex;
308 *winnerKey = loserKey;
309 *winnerIndex = loserIndex;
321 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
325 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
326 void loser_tree<ValTp_, Cmp_, KNKMAX>::doubleK()
328 STXXL_VERBOSE3(
"loser_tree::doubleK (before) k=" << k <<
" logK=" << logK <<
" KNKMAX=" << KNKMAX <<
" #free=" << free_slots.size());
331 assert(free_slots.empty());
335 for (unsigned_type i = 2 * k - 1; i >= k; i--)
337 current[i] = &sentinel;
338 current_end[i] = &sentinel;
347 STXXL_VERBOSE3(
"loser_tree::doubleK (after) k=" << k <<
" logK=" << logK <<
" KNKMAX=" << KNKMAX <<
" #free=" << free_slots.size());
348 assert(!free_slots.empty());
356 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
357 void loser_tree<ValTp_, Cmp_, KNKMAX>::compactTree()
359 STXXL_VERBOSE3(
"loser_tree::compactTree (before) k=" << k <<
" logK=" << logK <<
" #free=" << free_slots.size());
363 unsigned_type pos = 0;
364 unsigned_type last_empty = 0;
365 for ( ; pos < k; pos++)
367 if (not_sentinel(*(current[pos])))
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];
389 while ((k > 1) && ((k / 2) >= last_empty))
397 for ( ; last_empty < k; last_empty++)
399 current[last_empty] = &sentinel;
400 current_end[last_empty] = &sentinel;
401 free_slots.push(last_empty);
404 STXXL_VERBOSE3(
"loser_tree::compactTree (after) k=" << k <<
" logK=" << logK <<
" #free=" << free_slots.size());
413 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
414 void loser_tree<ValTp_, Cmp_, KNKMAX>::insert_segment(Element * target, unsigned_type length)
416 STXXL_VERBOSE2(
"loser_tree::insert_segment(" << target <<
"," << length <<
")");
421 assert(not_sentinel(target[0]));
422 assert(not_sentinel(target[length - 1]));
423 assert(is_sentinel(target[length]));
426 if (free_slots.empty())
430 assert(!free_slots.empty());
431 unsigned_type index = free_slots.top();
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);
442 #if STXXL_PQ_INTERNAL_LOSER_TREE
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
460 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
461 loser_tree<ValTp_, Cmp_, KNKMAX>::~loser_tree()
463 STXXL_VERBOSE1(
"loser_tree::~loser_tree()");
464 for (unsigned_type i = 0; i < k; ++i)
468 STXXL_VERBOSE2(
"loser_tree::~loser_tree() deleting segment " << i);
470 mem_cons_ -= segment_size[i];
474 assert(mem_cons_ == 0);
478 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
479 void loser_tree<ValTp_, Cmp_, KNKMAX>::deallocate_segment(unsigned_type slot)
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;
489 delete[] segment[slot];
490 segment[slot] = NULL;
491 mem_cons_ -= segment_size[slot];
494 free_slots.push(slot);
503 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
504 void loser_tree<ValTp_, Cmp_, KNKMAX>::multi_merge(Element * target, unsigned_type length)
506 STXXL_VERBOSE3(
"loser_tree::multi_merge(target=" << target <<
", len=" << length <<
") k=" << k);
512 assert(length <= size_);
516 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
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));
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);
538 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
540 std::pair<Element *, Element *> seqs[2] =
542 std::make_pair(current[0], current_end[0]),
543 std::make_pair(current[1], current_end[1])
545 parallel::multiway_merge_sentinel(seqs, seqs + 2, target, inv_cmp, length);
546 current[0] = seqs[0].first;
547 current[1] = seqs[1].first;
550 merge_iterator(current[0], current[1], target, length, cmp);
553 if (is_segment_empty(0))
554 deallocate_segment(0);
556 if (is_segment_empty(1))
557 deallocate_segment(1);
562 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
564 std::pair<Element *, Element *> seqs[4] =
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])
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;
578 if (is_segment_empty(3))
579 merge3_iterator(current[0], current[1], current[2], target, length, cmp);
581 merge4_iterator(current[0], current[1], current[2], current[3], target, length, cmp);
585 if (is_segment_empty(0))
586 deallocate_segment(0);
588 if (is_segment_empty(1))
589 deallocate_segment(1);
591 if (is_segment_empty(2))
592 deallocate_segment(2);
594 if (is_segment_empty(3))
595 deallocate_segment(3);
598 #if !(STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL)
599 case 3: multi_merge_f<3>(target, length);
601 case 4: multi_merge_f<4>(target, length);
603 case 5: multi_merge_f<5>(target, length);
605 case 6: multi_merge_f<6>(target, length);
607 case 7: multi_merge_f<7>(target, length);
609 case 8: multi_merge_f<8>(target, length);
611 case 9: multi_merge_f<9>(target, length);
613 case 10: multi_merge_f<10>(target, length);
617 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
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)
623 if (current[i] != current_end[i] && !is_sentinel(*current[i]))
625 seqs.push_back(std::make_pair(current[i], current_end[i]));
626 orig_seq_index.push_back(i);
630 parallel::multiway_merge_sentinel(seqs.begin(), seqs.end(), target, inv_cmp, length);
632 for (
unsigned int i = 0; i < seqs.size(); ++i)
634 int_type seg = orig_seq_index[i];
635 current[seg] = seqs[i].first;
638 for (
unsigned int i = 0; i < k; ++i)
639 if (is_segment_empty(i))
641 STXXL_VERBOSE3(
"deallocated " << i);
642 deallocate_segment(i);
646 multi_merge_k(target, length);
656 const unsigned_type num_segments_used = k - free_slots.size();
657 const unsigned_type num_segments_trigger = k - (3 * k / 5);
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 ")
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))))
680 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
681 inline bool loser_tree<ValTp_, Cmp_, KNKMAX>::is_segment_empty(unsigned_type slot)
683 return (is_sentinel(*(current[slot])) && (current[slot] != &sentinel));
686 #if STXXL_PQ_INTERNAL_LOSER_TREE
688 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
689 void loser_tree<ValTp_, Cmp_, KNKMAX>::
690 multi_merge_k(Element * target, unsigned_type length)
694 unsigned_type currentIndex;
695 unsigned_type kReg = k;
696 Element * done = target + length;
697 unsigned_type winnerIndex = entry[0].index;
698 Element winnerKey = entry[0].key;
701 while (target != done)
703 winnerPos = current[winnerIndex];
710 current[winnerIndex] = winnerPos;
711 winnerKey = *winnerPos;
714 if (is_sentinel(winnerKey))
715 deallocate_segment(winnerIndex);
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;
733 entry[0].index = winnerIndex;
734 entry[0].key = winnerKey;
736 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
741 __STXXL_END_NAMESPACE
743 #endif // !STXXL_PQ_LOSERTREE_HEADER
Inverts the order of a comparison functor by swapping its arguments.
Definition: pq_helpers.h:145
Loser tree from Knuth, "Sorting and Searching", Section 5.4.1 !
Definition: pq_losertree.h:36