16 #ifndef STXXL_CONTAINERS_PQ_LOSERTREE_HEADER
17 #define STXXL_CONTAINERS_PQ_LOSERTREE_HEADER
29 namespace priority_queue_local {
37 template <
class ValueType,
class CompareType,
unsigned MaxArity>
44 enum { max_arity = MaxArity };
47 #if STXXL_PQ_INTERNAL_LOSER_TREE
53 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
65 #if STXXL_PQ_INTERNAL_LOSER_TREE
68 Entry entry[MaxArity];
69 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
74 Element* current[MaxArity];
75 Element* current_end[MaxArity];
76 Element* segment[MaxArity];
88 void rebuildLoserTree();
92 #if STXXL_PQ_INTERNAL_LOSER_TREE
99 Element* done = target + length;
100 Entry* regEntry = entry;
101 Element** regStates = current;
103 Element winnerKey = regEntry[0].key;
107 assert(logK >= LogK);
108 while (target != done)
110 winnerPos = regStates[winnerIndex];
117 regStates[winnerIndex] = winnerPos;
118 winnerKey = *winnerPos;
121 if (is_sentinel(winnerKey))
123 deallocate_segment(winnerIndex);
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; \
152 regEntry[0].index = winnerIndex;
153 regEntry[0].key = winnerKey;
155 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
160 return !(cmp(cmp.min_value(), a));
164 return cmp(cmp.min_value(), a);
174 std::swap(cmp, obj.
cmp);
176 std::swap(size_, obj.
size_);
177 std::swap(logK, obj.
logK);
180 #if STXXL_PQ_INTERNAL_LOSER_TREE
182 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
192 multi_merge(begin, end - begin);
200 return (k < MaxArity) || !free_slots.empty();
210 template <
class ValueType,
class CompareType,
unsigned MaxArity>
212 : size_(0), logK(0), k(1), mem_cons_(0)
223 template <
class ValueType,
class CompareType,
unsigned MaxArity>
226 assert(!cmp(cmp.min_value(), cmp.min_value()));
229 #if STXXL_PQ_INTERNAL_LOSER_TREE
230 assert(current[entry[0].index] == &
sentinel);
231 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
235 template <
class ValueType,
class CompareType,
unsigned MaxArity>
238 #if STXXL_PQ_INTERNAL_LOSER_TREE
242 entry[0].index = winner;
243 entry[0].key = *(current[winner]);
244 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
247 #if STXXL_PQ_INTERNAL_LOSER_TREE
253 template <
class ValueType,
class CompareType,
unsigned MaxArity>
262 Element lk = *(current[left]);
263 Element rk = *(current[right]);
264 if (!(cmp(lk, rk))) {
265 entry[root].index = right;
266 entry[root].key = rk;
270 entry[root].index = left;
271 entry[root].key = lk;
282 template <
class ValueType,
class CompareType,
unsigned MaxArity>
285 const Element& newKey,
293 *winnerKey = entry[0].key;
294 *winnerIndex = entry[0].index;
295 if (cmp(entry[node].key, newKey))
297 entry[node].key = newKey;
298 entry[node].index = newIndex;
302 update_on_insert(node >> 1, newKey, newIndex, winnerKey, winnerIndex, mask);
303 Element loserKey = entry[node].key;
305 if ((*winnerIndex & *mask) != (newIndex & *mask)) {
306 if (cmp(loserKey, newKey)) {
307 if (cmp(*winnerKey, newKey)) {
308 entry[node].key = *winnerKey;
309 entry[node].index = *winnerIndex;
312 entry[node].key = newKey;
313 entry[node].index = newIndex;
316 *winnerKey = loserKey;
317 *winnerIndex = loserIndex;
329 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
332 template <
class ValueType,
class CompareType,
unsigned MaxArity>
335 STXXL_VERBOSE3(
"loser_tree::doubleK (before) k=" << k <<
" logK=" << logK <<
" MaxArity=" << MaxArity <<
" #free=" << free_slots.size());
337 assert(k < MaxArity);
338 assert(free_slots.empty());
354 STXXL_VERBOSE3(
"loser_tree::doubleK (after) k=" << k <<
" logK=" << logK <<
" MaxArity=" << MaxArity <<
" #free=" << free_slots.size());
355 assert(!free_slots.empty());
362 template <
class ValueType,
class CompareType,
unsigned MaxArity>
365 STXXL_VERBOSE3(
"loser_tree::compactTree (before) k=" << k <<
" logK=" << logK <<
" #free=" << free_slots.size());
371 for ( ; pos < k; pos++)
373 if (not_sentinel(*(current[pos])))
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];
395 while ((k > 1) && ((k / 2) >= last_empty))
403 for ( ; last_empty < k; last_empty++)
406 current_end[last_empty] = &
sentinel;
407 free_slots.push(last_empty);
410 STXXL_VERBOSE3(
"loser_tree::compactTree (after) k=" << k <<
" logK=" << logK <<
" #free=" << free_slots.size());
418 template <
class ValueType,
class CompareType,
unsigned MaxArity>
422 STXXL_VERBOSE2(
"loser_tree::insert_segment(" << target <<
"," << length <<
")");
427 assert(not_sentinel(target[0]));
428 assert(not_sentinel(target[length - 1]));
429 assert(is_sentinel(target[length]));
432 if (free_slots.empty())
436 assert(!free_slots.empty());
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);
447 #if STXXL_PQ_INTERNAL_LOSER_TREE
452 update_on_insert((index + k) >> 1, *target, index,
453 &dummyKey, &dummyIndex, &dummyMask);
454 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
465 template <
class ValueType,
class CompareType,
unsigned MaxArity>
473 STXXL_VERBOSE2(
"loser_tree::~loser_tree() deleting segment " << i);
475 mem_cons_ -= segment_size[i];
479 assert(mem_cons_ == 0);
483 template <
class ValueType,
class CompareType,
unsigned MaxArity>
489 STXXL_VERBOSE2(
"loser_tree::deallocate_segment() deleting segment " <<
490 slot <<
" address: " << segment[slot] <<
" size: " << (segment_size[slot] /
sizeof(
value_type)) - 1);
495 delete[] segment[slot];
496 segment[slot] = NULL;
497 mem_cons_ -= segment_size[slot];
500 free_slots.push(slot);
508 template <
class ValueType,
class CompareType,
unsigned MaxArity>
512 STXXL_VERBOSE3(
"loser_tree::multi_merge(target=" << target <<
", len=" << length <<
") k=" << k);
518 assert(length <= size_);
522 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
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));
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);
544 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
546 std::pair<Element*, Element*> seqs[2] =
548 std::make_pair(current[0], current_end[0]),
549 std::make_pair(current[1], current_end[1])
552 seqs, seqs + 2, target, length, inv_cmp);
553 current[0] = seqs[0].first;
554 current[1] = seqs[1].first;
557 merge_iterator(current[0], current[1], target, length, cmp);
560 if (is_segment_empty(0))
561 deallocate_segment(0);
563 if (is_segment_empty(1))
564 deallocate_segment(1);
569 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
571 std::pair<Element*, Element*> seqs[4] =
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])
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;
586 if (is_segment_empty(3))
587 merge3_iterator(current[0], current[1], current[2], target, length, cmp);
589 merge4_iterator(current[0], current[1], current[2], current[3], target, length, cmp);
593 if (is_segment_empty(0))
594 deallocate_segment(0);
596 if (is_segment_empty(1))
597 deallocate_segment(1);
599 if (is_segment_empty(2))
600 deallocate_segment(2);
602 if (is_segment_empty(3))
603 deallocate_segment(3);
606 #if !(STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL)
607 case 3: multi_merge_f<3>(target, length);
609 case 4: multi_merge_f<4>(target, length);
611 case 5: multi_merge_f<5>(target, length);
613 case 6: multi_merge_f<6>(target, length);
615 case 7: multi_merge_f<7>(target, length);
617 case 8: multi_merge_f<8>(target, length);
619 case 9: multi_merge_f<9>(target, length);
621 case 10: multi_merge_f<10>(target, length);
625 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
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)
631 if (current[i] != current_end[i] && !is_sentinel(*current[i]))
633 seqs.push_back(std::make_pair(current[i], current_end[i]));
634 orig_seq_index.push_back(i);
639 seqs.begin(), seqs.end(), target, length, inv_cmp);
641 for (
unsigned int i = 0; i < seqs.size(); ++i)
644 current[seg] = seqs[i].first;
647 for (
unsigned int i = 0; i < k; ++i)
648 if (is_segment_empty(i))
651 deallocate_segment(i);
655 multi_merge_k(target, length);
664 const unsigned_type num_segments_used = k - free_slots.size();
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 ")
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))))
687 template <
class ValueType,
class CompareType,
unsigned MaxArity>
691 return (is_sentinel(*(current[slot])) && (current[slot] != &
sentinel));
694 #if STXXL_PQ_INTERNAL_LOSER_TREE
696 template <
class ValueType,
class CompareType,
unsigned MaxArity>
704 Element* done = target + length;
706 Element winnerKey = entry[0].key;
709 while (target != done)
711 winnerPos = current[winnerIndex];
718 current[winnerIndex] = winnerPos;
719 winnerKey = *winnerPos;
722 if (is_sentinel(winnerKey))
723 deallocate_segment(winnerIndex);
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;
740 entry[0].index = winnerIndex;
741 entry[0].key = winnerKey;
743 #endif // STXXL_PQ_INTERNAL_LOSER_TREE
751 #endif // !STXXL_CONTAINERS_PQ_LOSERTREE_HEADER
bool not_sentinel(const Element &a)
unsigned_type mem_cons() const
CompareType comparator_type
bool is_space_available() const
Inverts the order of a comparison functor by swapping its arguments.
Element * current_end[MaxArity]
void merge3_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, OutputIterator target, OutputIterator end, CompareType &cmp)
bool is_segment_empty(unsigned_type slot)
void swap_1D_arrays(Type *a, Type *b, unsigned_type size)
#define STXXL_VERBOSE2(x)
Loser tree from Knuth, "Sorting and Searching", Section 5.4.1.
unsigned_type k
current tree size, invariant (k == 1 << logK), always a power of two
void merge4_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, InputIterator &source3, OutputIterator target, OutputIterator end, CompareType &cmp)
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.
unsigned_type initWinner(unsigned_type root)
#define STXXL_VERBOSE3(x)
choose_int_types< my_pointer_size >::int_type int_type
void multi_merge(Element *begin, Element *end)
void push(const value_type &x)
unsigned_type segment_size[MaxArity]
#define STXXL_BEGIN_NAMESPACE
struct Entry entry[max_arity]
levels of loser tree: entry[0] contains the winner info
#define STXXL_VERBOSE1(x)
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
Element * current[MaxArity]
void deallocate_segment(unsigned_type slot)
unsigned_type logK
log of current tree size
bool is_sentinel(const Element &a)
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
internal_bounded_stack< unsigned_type, MaxArity > free_slots
static const size_t sentinel
unsigned_type size() const
Element * segment[MaxArity]
void swap(loser_tree &obj)
#define STXXL_END_NAMESPACE