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()));
227 sentinel = 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>
261 Element lk = *(current[left]);
262 Element rk = *(current[right]);
263 if (!(cmp(lk, rk))) {
264 entry[root].index = right;
265 entry[root].key = rk;
268 entry[root].index = left;
269 entry[root].key = lk;
280 template <
class ValueType,
class CompareType,
unsigned MaxArity>
283 const Element& newKey,
291 *winnerKey = entry[0].key;
292 *winnerIndex = entry[0].index;
293 if (cmp(entry[node].key, newKey))
295 entry[node].key = newKey;
296 entry[node].index = newIndex;
299 update_on_insert(node >> 1, newKey, newIndex, winnerKey, winnerIndex, mask);
300 Element loserKey = entry[node].key;
302 if ((*winnerIndex & *mask) != (newIndex & *mask)) {
303 if (cmp(loserKey, newKey)) {
304 if (cmp(*winnerKey, newKey)) {
305 entry[node].key = *winnerKey;
306 entry[node].index = *winnerIndex;
308 entry[node].key = newKey;
309 entry[node].index = newIndex;
312 *winnerKey = loserKey;
313 *winnerIndex = loserIndex;
325 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
328 template <
class ValueType,
class CompareType,
unsigned MaxArity>
331 STXXL_VERBOSE3(
"loser_tree::doubleK (before) k=" << k <<
" logK=" << logK <<
" MaxArity=" << MaxArity <<
" #free=" << free_slots.size());
333 assert(k < MaxArity);
334 assert(free_slots.empty());
340 current[i] = &sentinel;
341 current_end[i] = &sentinel;
350 STXXL_VERBOSE3(
"loser_tree::doubleK (after) k=" << k <<
" logK=" << logK <<
" MaxArity=" << MaxArity <<
" #free=" << free_slots.size());
351 assert(!free_slots.empty());
358 template <
class ValueType,
class CompareType,
unsigned MaxArity>
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());
414 template <
class ValueType,
class CompareType,
unsigned MaxArity>
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());
437 current[index] = segment[index] = target;
438 current_end[index] = target + length;
439 segment_size[index] = (length + 1) *
sizeof(
value_type);
440 mem_cons_ += (length + 1) *
sizeof(
value_type);
443 #if STXXL_PQ_INTERNAL_LOSER_TREE
448 update_on_insert((index + k) >> 1, *target, index,
449 &dummyKey, &dummyIndex, &dummyMask);
450 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
460 template <
class ValueType,
class CompareType,
unsigned MaxArity>
468 STXXL_VERBOSE2(
"loser_tree::~loser_tree() deleting segment " << i);
470 mem_cons_ -= segment_size[i];
474 assert(mem_cons_ == 0);
478 template <
class ValueType,
class CompareType,
unsigned MaxArity>
484 STXXL_VERBOSE2(
"loser_tree::deallocate_segment() deleting segment " <<
485 slot <<
" address: " << segment[slot] <<
" size: " << (segment_size[slot] /
sizeof(
value_type)) - 1);
486 current[slot] = &sentinel;
487 current_end[slot] = &sentinel;
490 delete[] segment[slot];
491 segment[slot] = NULL;
492 mem_cons_ -= segment_size[slot];
495 free_slots.push(slot);
503 template <
class ValueType,
class CompareType,
unsigned MaxArity>
507 STXXL_VERBOSE3(
"loser_tree::multi_merge(target=" << target <<
", len=" << length <<
") k=" << k);
513 assert(length <= size_);
517 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
523 #if STXXL_PQ_INTERNAL_LOSER_TREE
524 assert(entry[0].index == 0);
525 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
526 assert(free_slots.empty());
527 memcpy(target, current[0], length *
sizeof(
Element));
529 current[0] += length;
530 #if STXXL_PQ_INTERNAL_LOSER_TREE
531 entry[0].key = **current;
532 #endif //STXXL_PQ_INTERNAL_LOSER_TREE
533 if (is_segment_empty(0))
534 deallocate_segment(0);
539 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
541 std::pair<Element*, Element*> seqs[2] =
543 std::make_pair(current[0], current_end[0]),
544 std::make_pair(current[1], current_end[1])
546 parallel::multiway_merge_sentinel(seqs, seqs + 2, target, inv_cmp, length);
547 current[0] = seqs[0].first;
548 current[1] = seqs[1].first;
554 if (is_segment_empty(0))
555 deallocate_segment(0);
557 if (is_segment_empty(1))
558 deallocate_segment(1);
563 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
565 std::pair<Element*, Element*> seqs[4] =
567 std::make_pair(current[0], current_end[0]),
568 std::make_pair(current[1], current_end[1]),
569 std::make_pair(current[2], current_end[2]),
570 std::make_pair(current[3], current_end[3])
572 parallel::multiway_merge_sentinel(seqs, seqs + 4, target, inv_cmp, length);
573 current[0] = seqs[0].first;
574 current[1] = seqs[1].first;
575 current[2] = seqs[2].first;
576 current[3] = seqs[3].first;
579 if (is_segment_empty(3))
580 merge3_iterator(current[0], current[1], current[2], target, length, cmp);
582 merge4_iterator(current[0], current[1], current[2], current[3], target, length, cmp);
586 if (is_segment_empty(0))
587 deallocate_segment(0);
589 if (is_segment_empty(1))
590 deallocate_segment(1);
592 if (is_segment_empty(2))
593 deallocate_segment(2);
595 if (is_segment_empty(3))
596 deallocate_segment(3);
599 #if !(STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL)
600 case 3: multi_merge_f<3>(target, length);
602 case 4: multi_merge_f<4>(target, length);
604 case 5: multi_merge_f<5>(target, length);
606 case 6: multi_merge_f<6>(target, length);
608 case 7: multi_merge_f<7>(target, length);
610 case 8: multi_merge_f<8>(target, length);
612 case 9: multi_merge_f<9>(target, length);
614 case 10: multi_merge_f<10>(target, length);
618 #if STXXL_PARALLEL && STXXL_PARALLEL_PQ_MULTIWAY_MERGE_INTERNAL
620 std::vector<std::pair<Element*, Element*> > seqs;
621 std::vector<int_type> orig_seq_index;
622 for (
unsigned int i = 0; i < k; ++i)
624 if (current[i] != current_end[i] && !is_sentinel(*current[i]))
626 seqs.push_back(std::make_pair(current[i], current_end[i]));
627 orig_seq_index.push_back(i);
631 parallel::multiway_merge_sentinel(seqs.begin(), seqs.end(), target, inv_cmp, length);
633 for (
unsigned int i = 0; i < seqs.size(); ++i)
636 current[seg] = seqs[i].first;
639 for (
unsigned int i = 0; i < k; ++i)
640 if (is_segment_empty(i))
643 deallocate_segment(i);
647 multi_merge_k(target, length);
656 const unsigned_type num_segments_used = k - free_slots.size();
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))))
679 template <
class ValueType,
class CompareType,
unsigned MaxArity>
683 return (is_sentinel(*(current[slot])) && (current[slot] != &sentinel));
686 #if STXXL_PQ_INTERNAL_LOSER_TREE
688 template <
class ValueType,
class CompareType,
unsigned MaxArity>
696 Element* done = target + length;
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);
718 for (
unsigned_type i = (winnerIndex + kReg) >> 1; i > 0; i >>= 1) {
719 currentPos = entry + i;
720 currentKey = currentPos->key;
721 if (cmp(winnerKey, currentKey)) {
722 currentIndex = currentPos->index;
723 currentPos->key = winnerKey;
724 currentPos->index = winnerIndex;
725 winnerKey = currentKey;
726 winnerIndex = currentIndex;
732 entry[0].index = winnerIndex;
733 entry[0].key = winnerKey;
735 #endif // STXXL_PQ_INTERNAL_LOSER_TREE
743 #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]
bool is_segment_empty(unsigned_type slot)
void merge3_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, OutputIterator target, SizeType length, CompareType &cmp)
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.
void multi_merge_k(Element *target, unsigned_type length)
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
#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)
bool is_sentinel(const Element &a)
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
internal_bounded_stack< unsigned_type, MaxArity > free_slots
unsigned_type size() const
Element * segment[MaxArity]
void merge_iterator(InputIterator &source0, InputIterator &source1, OutputIterator target, SizeType length, CompareType &cmp)
void swap(loser_tree &obj)
#define STXXL_END_NAMESPACE
void merge4_iterator(InputIterator &source0, InputIterator &source1, InputIterator &source2, InputIterator &source3, OutputIterator target, SizeType length, CompareType &cmp)