16 #ifndef STXXL_CONTAINERS_PQ_LOSERTREE_HEADER
17 #define STXXL_CONTAINERS_PQ_LOSERTREE_HEADER
29 namespace priority_queue_local {
37 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
46 #if STXXL_PQ_INTERNAL_LOSER_TREE
52 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
64 #if STXXL_PQ_INTERNAL_LOSER_TREE
68 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
73 Element* current[KNKMAX];
74 Element* current_end[KNKMAX];
75 Element* segment[KNKMAX];
87 void rebuildLoserTree();
91 #if STXXL_PQ_INTERNAL_LOSER_TREE
98 Element* done = target + length;
99 Entry* regEntry = entry;
100 Element** regStates = current;
102 Element winnerKey = regEntry[0].key;
106 assert(logK >= LogK);
107 while (target != done)
109 winnerPos = regStates[winnerIndex];
116 regStates[winnerIndex] = winnerPos;
117 winnerKey = *winnerPos;
120 if (is_sentinel(winnerKey))
122 deallocate_segment(winnerIndex);
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; \
151 regEntry[0].index = winnerIndex;
152 regEntry[0].key = winnerKey;
154 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
159 return !(cmp(cmp.min_value(), a));
163 return cmp(cmp.min_value(), a);
173 std::swap(cmp, obj.
cmp);
175 std::swap(size_, obj.
size_);
176 std::swap(logK, obj.
logK);
179 #if STXXL_PQ_INTERNAL_LOSER_TREE
181 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
191 multi_merge(begin, end - begin);
199 return (k < KNKMAX) || !free_slots.empty();
207 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
219 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
222 assert(!cmp(cmp.min_value(), cmp.min_value()));
223 sentinel = cmp.min_value();
225 #if STXXL_PQ_INTERNAL_LOSER_TREE
226 assert(current[entry[0].index] == &sentinel);
227 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
232 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
235 #if STXXL_PQ_INTERNAL_LOSER_TREE
238 entry[0].index = winner;
239 entry[0].key = *(current[winner]);
240 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
244 #if STXXL_PQ_INTERNAL_LOSER_TREE
250 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
258 Element lk = *(current[left]);
259 Element rk = *(current[right]);
260 if (!(cmp(lk, rk))) {
261 entry[root].index = right;
262 entry[root].key = rk;
265 entry[root].index = left;
266 entry[root].key = lk;
278 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
281 const Element& newKey,
289 *winnerKey = entry[0].key;
290 *winnerIndex = entry[0].index;
291 if (cmp(entry[node].key, newKey))
293 entry[node].key = newKey;
294 entry[node].index = newIndex;
297 update_on_insert(node >> 1, newKey, newIndex, winnerKey, winnerIndex, mask);
298 Element loserKey = entry[node].key;
300 if ((*winnerIndex & *mask) != (newIndex & *mask)) {
301 if (cmp(loserKey, newKey)) {
302 if (cmp(*winnerKey, newKey)) {
303 entry[node].key = *winnerKey;
304 entry[node].index = *winnerIndex;
306 entry[node].key = newKey;
307 entry[node].index = newIndex;
310 *winnerKey = loserKey;
311 *winnerIndex = loserIndex;
323 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
327 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
330 STXXL_VERBOSE3(
"loser_tree::doubleK (before) k=" << k <<
" logK=" << logK <<
" KNKMAX=" << KNKMAX <<
" #free=" << free_slots.size());
333 assert(free_slots.empty());
339 current[i] = &sentinel;
340 current_end[i] = &sentinel;
349 STXXL_VERBOSE3(
"loser_tree::doubleK (after) k=" << k <<
" logK=" << logK <<
" KNKMAX=" << KNKMAX <<
" #free=" << free_slots.size());
350 assert(!free_slots.empty());
358 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
361 STXXL_VERBOSE3(
"loser_tree::compactTree (before) k=" << k <<
" logK=" << logK <<
" #free=" << free_slots.size());
367 for ( ; pos < k; pos++)
369 if (not_sentinel(*(current[pos])))
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];
391 while ((k > 1) && ((k / 2) >= last_empty))
399 for ( ; last_empty < k; last_empty++)
401 current[last_empty] = &sentinel;
402 current_end[last_empty] = &sentinel;
403 free_slots.push(last_empty);
406 STXXL_VERBOSE3(
"loser_tree::compactTree (after) k=" << k <<
" logK=" << logK <<
" #free=" << free_slots.size());
415 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
418 STXXL_VERBOSE2(
"loser_tree::insert_segment(" << target <<
"," << length <<
")");
423 assert(not_sentinel(target[0]));
424 assert(not_sentinel(target[length - 1]));
425 assert(is_sentinel(target[length]));
428 if (free_slots.empty())
432 assert(!free_slots.empty());
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);
444 #if STXXL_PQ_INTERNAL_LOSER_TREE
449 update_on_insert((index + k) >> 1, *target, index,
450 &dummyKey, &dummyIndex, &dummyMask);
451 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
462 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
470 STXXL_VERBOSE2(
"loser_tree::~loser_tree() deleting segment " << i);
472 mem_cons_ -= segment_size[i];
476 assert(mem_cons_ == 0);
480 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
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;
491 delete[] segment[slot];
492 segment[slot] = NULL;
493 mem_cons_ -= segment_size[slot];
496 free_slots.push(slot);
505 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
508 STXXL_VERBOSE3(
"loser_tree::multi_merge(target=" << target <<
", len=" << length <<
") k=" << k);
514 assert(length <= size_);
518 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
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));
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);
540 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
542 std::pair<Element*, Element*> seqs[2] =
544 std::make_pair(current[0], current_end[0]),
545 std::make_pair(current[1], current_end[1])
547 parallel::multiway_merge_sentinel(seqs, seqs + 2, target, inv_cmp, length);
548 current[0] = seqs[0].first;
549 current[1] = seqs[1].first;
555 if (is_segment_empty(0))
556 deallocate_segment(0);
558 if (is_segment_empty(1))
559 deallocate_segment(1);
564 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
566 std::pair<Element*, Element*> seqs[4] =
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])
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;
580 if (is_segment_empty(3))
581 merge3_iterator(current[0], current[1], current[2], target, length, cmp);
583 merge4_iterator(current[0], current[1], current[2], current[3], target, length, cmp);
587 if (is_segment_empty(0))
588 deallocate_segment(0);
590 if (is_segment_empty(1))
591 deallocate_segment(1);
593 if (is_segment_empty(2))
594 deallocate_segment(2);
596 if (is_segment_empty(3))
597 deallocate_segment(3);
600 #if !(STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL)
601 case 3: multi_merge_f<3>(target, length);
603 case 4: multi_merge_f<4>(target, length);
605 case 5: multi_merge_f<5>(target, length);
607 case 6: multi_merge_f<6>(target, length);
609 case 7: multi_merge_f<7>(target, length);
611 case 8: multi_merge_f<8>(target, length);
613 case 9: multi_merge_f<9>(target, length);
615 case 10: multi_merge_f<10>(target, length);
619 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
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)
625 if (current[i] != current_end[i] && !is_sentinel(*current[i]))
627 seqs.push_back(std::make_pair(current[i], current_end[i]));
628 orig_seq_index.push_back(i);
632 parallel::multiway_merge_sentinel(seqs.begin(), seqs.end(), target, inv_cmp, length);
634 for (
unsigned int i = 0; i < seqs.size(); ++i)
637 current[seg] = seqs[i].first;
640 for (
unsigned int i = 0; i < k; ++i)
641 if (is_segment_empty(i))
644 deallocate_segment(i);
648 multi_merge_k(target, length);
658 const unsigned_type num_segments_used = k - free_slots.size();
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 ")
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))))
682 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
685 return (is_sentinel(*(current[slot])) && (current[slot] != &sentinel));
688 #if STXXL_PQ_INTERNAL_LOSER_TREE
690 template <
class ValTp_,
class Cmp_,
unsigned KNKMAX>
698 Element* done = target + length;
700 Element winnerKey = entry[0].key;
703 while (target != done)
705 winnerPos = current[winnerIndex];
712 current[winnerIndex] = winnerPos;
713 winnerKey = *winnerPos;
716 if (is_sentinel(winnerKey))
717 deallocate_segment(winnerIndex);
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;
735 entry[0].index = winnerIndex;
736 entry[0].key = winnerKey;
738 #endif // STXXL_PQ_INTERNAL_LOSER_TREE
746 #endif // !STXXL_CONTAINERS_PQ_LOSERTREE_HEADER
unsigned_type size() const
Element * segment[KNKMAX]
void swap_1D_arrays(T *a, T *b, unsigned_type size)
Inverts the order of a comparison functor by swapping its arguments.
void update_on_insert(unsigned_type node, const Element &newKey, unsigned_type newIndex, Element *winnerKey, unsigned_type *winnerIndex, unsigned_type *mask)
bool is_space_available() const
internal_bounded_stack< unsigned_type, KNKMAX > free_slots
void merge4_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, InputIterator &source3, OutputIterator target, unsigned_type length, CompareType &cmp)
void deallocate_segment(unsigned_type slot)
bool not_sentinel(const Element &a)
#define STXXL_VERBOSE2(x)
void merge_iterator(InputIterator &source0, InputIterator &source1, OutputIterator target, unsigned_type length, CompareType &cmp)
Element * current[KNKMAX]
Loser tree from Knuth, "Sorting and Searching", Section 5.4.1.
void multi_merge(Element *begin, Element *end)
void multi_merge_k(Element *target, unsigned_type length)
#define STXXL_VERBOSE3(x)
choose_int_types< my_pointer_size >::int_type int_type
bool is_segment_empty(unsigned_type slot)
void merge3_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, OutputIterator target, unsigned_type length, CompareType &cmp)
#define STXXL_BEGIN_NAMESPACE
#define STXXL_VERBOSE1(x)
unsigned_type initWinner(unsigned_type root)
void insert_segment(Element *target, unsigned_type length)
void push(const value_type &x)
unsigned_type mem_cons() const
unsigned_type segment_size[KNKMAX]
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
void swap(loser_tree &obj)
bool is_sentinel(const Element &a)
Element * current_end[KNKMAX]
#define STXXL_END_NAMESPACE