Autonomy Software C++ 24.5.1
Welcome to the Autonomy Software repository of the Mars Rover Design Team (MRDT) at Missouri University of Science and Technology (Missouri S&T)! API reference contains the source code and other resources for the development of the autonomy software for our Mars rover. The Autonomy Software project aims to compete in the University Rover Challenge (URC) by demonstrating advanced autonomous capabilities and robust navigation algorithms.
Loading...
Searching...
No Matches
duckdb::MergeSortTree< E, O, CMP, F, C > Struct Template Reference
Collaboration diagram for duckdb::MergeSortTree< E, O, CMP, F, C >:

Classes

struct  CompareElements
 

Public Types

using ElementType = E
 
using OffsetType = O
 
using Elements = vector< ElementType >
 
using Offsets = vector< OffsetType >
 
using Level = pair< Elements, Offsets >
 
using Tree = vector< Level >
 
using RunElement = pair< ElementType, idx_t >
 
using RunElements = array< RunElement, F >
 
using Games = array< RunElement, F - 1 >
 

Public Member Functions

 MergeSortTree (const CMP &cmp=CMP())
 
ElementsLowestLevel ()
 
const ElementsLowestLevel () const
 
ElementsAllocate (idx_t count)
 
void Build ()
 
pair< idx_t, idx_tSelectNth (const SubFrames &frames, idx_t n) const
 
ElementType NthElement (idx_t i) const
 
template<typename L >
void AggregateLowerBound (const idx_t lower, const idx_t upper, const E needle, L aggregate) const
 
void Print () const
 

Public Attributes

Tree tree
 
CompareElements cmp
 

Static Public Attributes

static constexpr ElementType INVALID = std::numeric_limits<ElementType>::max()
 
static constexpr auto FANOUT = F
 
static constexpr auto CASCADING = C
 

Protected Member Functions

bool TryNextRun (idx_t &level_idx, idx_t &run_idx)
 
void BuildRun (idx_t level_idx, idx_t run_idx)
 
RunElement StartGames (Games &losers, const RunElements &elements, const RunElement &sentinel)
 
RunElement ReplayGames (Games &losers, idx_t slot_idx, const RunElement &insert_val)
 

Static Protected Member Functions

static idx_t LowestCascadingLevel ()
 

Protected Attributes

mutex build_lock
 Parallel build machinery.
 
atomic< idx_tbuild_level
 
atomic< idx_tbuild_complete
 
idx_t build_run
 
idx_t build_run_length
 
idx_t build_num_runs
 

Constructor & Destructor Documentation

◆ MergeSortTree()

template<typename E = idx_t, typename O = idx_t, typename CMP = std::less<E>, uint64_t F = 32, uint64_t C = 32>
duckdb::MergeSortTree< E, O, CMP, F, C >::MergeSortTree ( const CMP cmp = CMP())
inlineexplicit
59398 : cmp(cmp) {
59399 }

Member Function Documentation

◆ LowestLevel() [1/2]

template<typename E = idx_t, typename O = idx_t, typename CMP = std::less<E>, uint64_t F = 32, uint64_t C = 32>
Elements & duckdb::MergeSortTree< E, O, CMP, F, C >::LowestLevel ( )
inline
59401 {
59402 return tree[0].first;
59403 }

◆ LowestLevel() [2/2]

template<typename E = idx_t, typename O = idx_t, typename CMP = std::less<E>, uint64_t F = 32, uint64_t C = 32>
const Elements & duckdb::MergeSortTree< E, O, CMP, F, C >::LowestLevel ( ) const
inline
59405 {
59406 return tree[0].first;
59407 }

◆ Allocate()

template<typename E , typename O , typename CMP , uint64_t F, uint64_t C>
vector< E > & duckdb::MergeSortTree< E, O, CMP, F, C >::Allocate ( idx_t  count)
59605 {
59606 const auto fanout = F;
59607 const auto cascading = C;
59608 Elements lowest_level(count);
59609 tree.emplace_back(Level(std::move(lowest_level), Offsets()));
59610
59611 for (idx_t child_run_length = 1; child_run_length < count;) {
59612 const auto run_length = child_run_length * fanout;
59613 const auto num_runs = (count + run_length - 1) / run_length;
59614
59615 Elements elements;
59616 elements.resize(count);
59617
59618 // Allocate cascading pointers only if there is room
59619 Offsets cascades;
59620 if (cascading > 0 && run_length > cascading) {
59621 const auto num_cascades = fanout * num_runs * (run_length / cascading + 2);
59622 cascades.resize(num_cascades);
59623 }
59624
59625 // Insert completed level and move up to the next one
59626 tree.emplace_back(std::move(elements), std::move(cascades));
59627 child_run_length = run_length;
59628 }
59629
59630 // Set up for parallel build
59631 build_level = 1;
59632 build_complete = 0;
59633 build_run = 0;
59634 build_run_length = fanout;
59635 build_num_runs = (count + build_run_length - 1) / build_run_length;
59636
59637 return LowestLevel();
59638}

◆ Build()

template<typename E , typename O , typename CMP , uint64_t F, uint64_t C>
void duckdb::MergeSortTree< E, O, CMP, F, C >::Build ( )
59641 {
59642 // Fan in parent levels until we are at the top
59643 // Note that we don't build the top layer as that would just be all the data.
59644 while (build_level.load() < tree.size()) {
59645 idx_t level_idx;
59646 idx_t run_idx;
59647 if (TryNextRun(level_idx, run_idx)) {
59648 BuildRun(level_idx, run_idx);
59649 } else {
59650 std::this_thread::yield();
59651 }
59652 }
59653}

◆ SelectNth()

template<typename E , typename O , typename CMP , uint64_t F, uint64_t C>
pair< idx_t, idx_t > duckdb::MergeSortTree< E, O, CMP, F, C >::SelectNth ( const SubFrames frames,
idx_t  n 
) const
59735 {
59736 // Handle special case of a one-element tree
59737 if (tree.size() < 2) {
59738 return {0, 0};
59739 }
59740
59741 // The first level contains a single run,
59742 // so the only thing we need is any cascading pointers
59743 auto level_no = tree.size() - 2;
59744 idx_t level_width = 1;
59745 for (idx_t i = 0; i < level_no; ++i) {
59746 level_width *= FANOUT;
59747 }
59748
59749 // Find Nth element in a top-down traversal
59750 idx_t result = 0;
59751
59752 // First, handle levels with cascading pointers
59753 const auto min_cascaded = LowestCascadingLevel();
59754 if (level_no > min_cascaded) {
59755 // Initialise the cascade indicies from the previous level
59756 using CascadeRange = pair<idx_t, idx_t>;
59757 std::array<CascadeRange, 3> cascades;
59758 const auto &level = tree[level_no + 1].first;
59759 for (idx_t f = 0; f < frames.size(); ++f) {
59760 const auto &frame = frames[f];
59761 auto &cascade_idx = cascades[f];
59762 const auto lower_idx =
59763 UnsafeNumericCast<idx_t>(std::lower_bound(level.begin(), level.end(), frame.start) - level.begin());
59764 cascade_idx.first = lower_idx / CASCADING * FANOUT;
59765 const auto upper_idx =
59766 UnsafeNumericCast<idx_t>(std::lower_bound(level.begin(), level.end(), frame.end) - level.begin());
59767 cascade_idx.second = upper_idx / CASCADING * FANOUT;
59768 }
59769
59770 // Walk the cascaded levels
59771 for (; level_no >= min_cascaded; --level_no) {
59772 // The cascade indicies into this level are in the previous level
59773 const auto &level_cascades = tree[level_no + 1].second;
59774
59775 // Go over all children until we found enough in range
59776 const auto *level_data = tree[level_no].first.data();
59777 while (true) {
59778 idx_t matched = 0;
59779 std::array<CascadeRange, 3> matches;
59780 for (idx_t f = 0; f < frames.size(); ++f) {
59781 const auto &frame = frames[f];
59782 auto &cascade_idx = cascades[f];
59783 auto &match = matches[f];
59784
59785 const auto lower_begin = level_data + level_cascades[cascade_idx.first];
59786 const auto lower_end = level_data + level_cascades[cascade_idx.first + FANOUT];
59787 match.first =
59788 UnsafeNumericCast<idx_t>(std::lower_bound(lower_begin, lower_end, frame.start) - level_data);
59789
59790 const auto upper_begin = level_data + level_cascades[cascade_idx.second];
59791 const auto upper_end = level_data + level_cascades[cascade_idx.second + FANOUT];
59792 match.second =
59793 UnsafeNumericCast<idx_t>(std::lower_bound(upper_begin, upper_end, frame.end) - level_data);
59794
59795 matched += idx_t(match.second - match.first);
59796 }
59797 if (matched > n) {
59798 // Too much in this level, so move down to leftmost child candidate within the cascade range
59799 for (idx_t f = 0; f < frames.size(); ++f) {
59800 auto &cascade_idx = cascades[f];
59801 auto &match = matches[f];
59802 cascade_idx.first = (match.first / CASCADING + 2 * result) * FANOUT;
59803 cascade_idx.second = (match.second / CASCADING + 2 * result) * FANOUT;
59804 }
59805 break;
59806 }
59807
59808 // Not enough in this child, so move right
59809 for (idx_t f = 0; f < frames.size(); ++f) {
59810 auto &cascade_idx = cascades[f];
59811 ++cascade_idx.first;
59812 ++cascade_idx.second;
59813 }
59814 ++result;
59815 n -= matched;
59816 }
59817 result *= FANOUT;
59818 level_width /= FANOUT;
59819 }
59820 }
59821
59822 // Continue with the uncascaded levels (except the first)
59823 for (; level_no > 0; --level_no) {
59824 const auto &level = tree[level_no].first;
59825 auto range_begin = level.begin() + UnsafeNumericCast<int64_t>(result * level_width);
59826 auto range_end = range_begin + UnsafeNumericCast<int64_t>(level_width);
59827 while (range_end < level.end()) {
59828 idx_t matched = 0;
59829 for (idx_t f = 0; f < frames.size(); ++f) {
59830 const auto &frame = frames[f];
59831 const auto lower_match = std::lower_bound(range_begin, range_end, frame.start);
59832 const auto upper_match = std::lower_bound(lower_match, range_end, frame.end);
59833 matched += idx_t(upper_match - lower_match);
59834 }
59835 if (matched > n) {
59836 // Too much in this level, so move down to leftmost child candidate
59837 // Since we have no cascade pointers left, this is just the start of the next level.
59838 break;
59839 }
59840 // Not enough in this child, so move right
59841 range_begin = range_end;
59842 range_end += UnsafeNumericCast<int64_t>(level_width);
59843 ++result;
59844 n -= matched;
59845 }
59846 result *= FANOUT;
59847 level_width /= FANOUT;
59848 }
59849
59850 // The last level
59851 const auto *level_data = tree[level_no].first.data();
59852 ++n;
59853
59854 const auto count = tree[level_no].first.size();
59855 for (const auto limit = MinValue<idx_t>(result + FANOUT, count); result < limit; ++result) {
59856 const auto v = level_data[result];
59857 for (const auto &frame : frames) {
59858 n -= (v >= frame.start) && (v < frame.end);
59859 }
59860 if (!n) {
59861 break;
59862 }
59863 }
59864
59865 return {result, n};
59866}
uint32_t v
uint64_t idx_t
a saner size_t for loop indices etc
Definition duckdb.hpp:237

◆ NthElement()

template<typename E = idx_t, typename O = idx_t, typename CMP = std::less<E>, uint64_t F = 32, uint64_t C = 32>
ElementType duckdb::MergeSortTree< E, O, CMP, F, C >::NthElement ( idx_t  i) const
inline
59416 {
59417 if (tree.empty() || tree.front().first.empty()) {
59418 return INVALID;
59419 }
59420 return tree.front().first[i];
59421 }

◆ AggregateLowerBound()

template<typename E , typename O , typename CMP , uint64_t F, uint64_t C>
template<typename L >
void duckdb::MergeSortTree< E, O, CMP, F, C >::AggregateLowerBound ( const idx_t  lower,
const idx_t  upper,
const E  needle,
L  aggregate 
) const
59871 {
59872 if (lower >= upper) {
59873 return;
59874 }
59875
59876 D_ASSERT(upper <= tree[0].first.size());
59877
59878 using IdxRange = std::pair<idx_t, idx_t>;
59879
59880 // Find the entry point into the tree
59881 IdxRange run_idx(lower, upper - 1);
59882 idx_t level_width = 1;
59883 idx_t level = 0;
59884 IdxRange prev_run_idx;
59885 IdxRange curr;
59886 if (run_idx.first == run_idx.second) {
59887 curr.first = curr.second = run_idx.first;
59888 } else {
59889 do {
59890 prev_run_idx.second = run_idx.second;
59891 run_idx.first /= FANOUT;
59892 run_idx.second /= FANOUT;
59893 level_width *= FANOUT;
59894 ++level;
59895 } while (run_idx.first != run_idx.second);
59896 curr.second = prev_run_idx.second * level_width / FANOUT;
59897 curr.first = curr.second;
59898 }
59899
59900 // Aggregate layers using the cascading indices
59901 if (level > LowestCascadingLevel()) {
59902 IdxRange cascading_idx;
59903 // Find the initial cascading idcs
59904 {
59905 IdxRange entry;
59906 entry.first = run_idx.first * level_width;
59907 entry.second = std::min(entry.first + level_width, static_cast<idx_t>(tree[0].first.size()));
59908 auto *level_data = tree[level].first.data();
59909 auto entry_idx = NumericCast<idx_t>(
59910 std::lower_bound(level_data + entry.first, level_data + entry.second, needle) - level_data);
59911 cascading_idx.first = cascading_idx.second =
59912 (entry_idx / CASCADING + 2 * (entry.first / level_width)) * FANOUT;
59913
59914 // We have to slightly shift the initial CASCADING idcs because at the top level
59915 // we won't be exactly on a boundary
59916 auto correction = (prev_run_idx.second - run_idx.second * FANOUT);
59917 cascading_idx.first -= (FANOUT - correction);
59918 cascading_idx.second += correction;
59919 }
59920
59921 // Aggregate all layers until we reach a layer without cascading indices
59922 // For the first layer, we already checked we have cascading indices available, otherwise
59923 // we wouldn't have even searched the entry points. Hence, we use a `do-while` instead of `while`
59924 do {
59925 --level;
59926 level_width /= FANOUT;
59927 auto *level_data = tree[level].first.data();
59928 auto &cascading_idcs = tree[level + 1].second;
59929 // Left side of tree
59930 // Handle all completely contained runs
59931 cascading_idx.first += FANOUT - 1;
59932 while (curr.first - lower >= level_width) {
59933 // Search based on cascading info from previous level
59934 const auto *search_begin = level_data + cascading_idcs[cascading_idx.first];
59935 const auto *search_end = level_data + cascading_idcs[cascading_idx.first + FANOUT];
59936 const auto run_pos = std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data;
59937 // Compute runBegin and pass it to our callback
59938 const auto run_begin = curr.first - level_width;
59939 aggregate(level, run_begin, NumericCast<idx_t>(run_pos));
59940 // Update state for next round
59941 curr.first -= level_width;
59942 --cascading_idx.first;
59943 }
59944 // Handle the partial last run to find the cascading entry point for the next level
59945 if (curr.first != lower) {
59946 const auto *search_begin = level_data + cascading_idcs[cascading_idx.first];
59947 const auto *search_end = level_data + cascading_idcs[cascading_idx.first + FANOUT];
59948 auto idx = NumericCast<idx_t>(std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data);
59949 cascading_idx.first = (idx / CASCADING + 2 * (lower / level_width)) * FANOUT;
59950 }
59951
59952 // Right side of tree
59953 // Handle all completely contained runs
59954 while (upper - curr.second >= level_width) {
59955 // Search based on cascading info from previous level
59956 const auto *search_begin = level_data + cascading_idcs[cascading_idx.second];
59957 const auto *search_end = level_data + cascading_idcs[cascading_idx.second + FANOUT];
59958 const auto run_pos = std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data;
59959 // Compute runBegin and pass it to our callback
59960 const auto run_begin = curr.second;
59961 aggregate(level, run_begin, NumericCast<idx_t>(run_pos));
59962 // Update state for next round
59963 curr.second += level_width;
59964 ++cascading_idx.second;
59965 }
59966 // Handle the partial last run to find the cascading entry point for the next level
59967 if (curr.second != upper) {
59968 const auto *search_begin = level_data + cascading_idcs[cascading_idx.second];
59969 const auto *search_end = level_data + cascading_idcs[cascading_idx.second + FANOUT];
59970 auto idx = NumericCast<idx_t>(std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data);
59971 cascading_idx.second = (idx / CASCADING + 2 * (upper / level_width)) * FANOUT;
59972 }
59973 } while (level >= LowestCascadingLevel());
59974 }
59975
59976 // Handle lower levels which won't have cascading info
59977 if (level) {
59978 while (--level) {
59979 level_width /= FANOUT;
59980 auto *level_data = tree[level].first.data();
59981 // Left side
59982 while (curr.first - lower >= level_width) {
59983 const auto *search_end = level_data + curr.first;
59984 const auto *search_begin = search_end - level_width;
59985 const auto run_pos =
59986 NumericCast<idx_t>(std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data);
59987 const auto run_begin = NumericCast<idx_t>(search_begin - level_data);
59988 aggregate(level, run_begin, run_pos);
59989 curr.first -= level_width;
59990 }
59991 // Right side
59992 while (upper - curr.second >= level_width) {
59993 const auto *search_begin = level_data + curr.second;
59994 const auto *search_end = search_begin + level_width;
59995 const auto run_pos =
59996 NumericCast<idx_t>(std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data);
59997 const auto run_begin = NumericCast<idx_t>(search_begin - level_data);
59998 aggregate(level, run_begin, run_pos);
59999 curr.second += level_width;
60000 }
60001 }
60002 }
60003
60004 // The last layer
60005 {
60006 auto *level_data = tree[0].first.data();
60007 // Left side
60008 auto lower_it = lower;
60009 while (lower_it != curr.first) {
60010 const auto *search_begin = level_data + lower_it;
60011 const auto run_begin = lower_it;
60012 const auto run_pos = run_begin + cmp.cmp(*search_begin, needle);
60013 aggregate(level, run_begin, run_pos);
60014 ++lower_it;
60015 }
60016 // Right side
60017 while (curr.second != upper) {
60018 const auto *search_begin = level_data + curr.second;
60019 const auto run_begin = curr.second;
60020 const auto run_pos = run_begin + cmp.cmp(*search_begin, needle);
60021 aggregate(level, run_begin, run_pos);
60022 ++curr.second;
60023 }
60024 }
60025}

◆ TryNextRun()

template<typename E = idx_t, typename O = idx_t, typename CMP = std::less<E>, uint64_t F = 32, uint64_t C = 32>
bool duckdb::MergeSortTree< E, O, CMP, F, C >::TryNextRun ( idx_t level_idx,
idx_t run_idx 
)
inlineprotected
59441 {
59442 const auto fanout = F;
59443
59444 lock_guard<mutex> stage_guard(build_lock);
59445
59446 // Finished with this level?
59447 if (build_complete >= build_num_runs) {
59448 ++build_level;
59449 if (build_level >= tree.size()) {
59450 return false;
59451 }
59452
59453 const auto count = LowestLevel().size();
59454 build_run_length *= fanout;
59455 build_num_runs = (count + build_run_length - 1) / build_run_length;
59456 build_run = 0;
59457 build_complete = 0;
59458 }
59459
59460 // If all runs are in flight,
59461 // yield until the next level is ready
59462 if (build_run >= build_num_runs) {
59463 return false;
59464 }
59465
59466 level_idx = build_level;
59467 run_idx = build_run++;
59468
59469 return true;
59470 }
mutex build_lock
Parallel build machinery.
Definition duckdb.cpp:59434

◆ BuildRun()

template<typename E , typename O , typename CMP , uint64_t F, uint64_t C>
void duckdb::MergeSortTree< E, O, CMP, F, C >::BuildRun ( idx_t  level_idx,
idx_t  run_idx 
)
protected
59656 {
59657 // Create each parent run by merging the child runs using a tournament tree
59658 // https://en.wikipedia.org/wiki/K-way_merge_algorithm
59659 const auto fanout = F;
59660 const auto cascading = C;
59661
59662 auto &elements = tree[level_idx].first;
59663 auto &cascades = tree[level_idx].second;
59664 const auto &child_level = tree[level_idx - 1];
59665 const auto count = elements.size();
59666
59667 idx_t child_run_length = 1;
59668 auto run_length = child_run_length * fanout;
59669 for (idx_t l = 1; l < level_idx; ++l) {
59670 child_run_length = run_length;
59671 run_length *= fanout;
59672 }
59673
59674 const RunElement SENTINEL(MergeSortTraits<ElementType>::SENTINEL(), MergeSortTraits<idx_t>::SENTINEL());
59675
59676 // Position markers for scanning the children.
59677 using Bounds = pair<OffsetType, OffsetType>;
59678 array<Bounds, fanout> bounds;
59679 // Start with first element of each (sorted) child run
59680 RunElements players;
59681 const auto child_base = run_idx * run_length;
59682 for (idx_t child_run = 0; child_run < fanout; ++child_run) {
59683 const auto child_idx = child_base + child_run * child_run_length;
59684 bounds[child_run] = {OffsetType(MinValue<idx_t>(child_idx, count)),
59685 OffsetType(MinValue<idx_t>(child_idx + child_run_length, count))};
59686 if (bounds[child_run].first != bounds[child_run].second) {
59687 players[child_run] = {child_level.first[child_idx], child_run};
59688 } else {
59689 // Empty child
59690 players[child_run] = SENTINEL;
59691 }
59692 }
59693
59694 // Play the first round and extract the winner
59695 Games games;
59696 auto element_idx = child_base;
59697 auto cascade_idx = fanout * run_idx * (run_length / cascading + 2);
59698 auto winner = StartGames(games, players, SENTINEL);
59699 while (winner != SENTINEL) {
59700 // Add fractional cascading pointers
59701 // if we are on a fraction boundary
59702 if (!cascades.empty() && element_idx % cascading == 0) {
59703 for (idx_t i = 0; i < fanout; ++i) {
59704 cascades[cascade_idx++] = bounds[i].first;
59705 }
59706 }
59707
59708 // Insert new winner element into the current run
59709 elements[element_idx++] = winner.first;
59710 const auto child_run = winner.second;
59711 auto &child_idx = bounds[child_run].first;
59712 ++child_idx;
59713
59714 // Move to the next entry in the child run (if any)
59715 if (child_idx < bounds[child_run].second) {
59716 winner = ReplayGames(games, child_run, {child_level.first[child_idx], child_run});
59717 } else {
59718 winner = ReplayGames(games, child_run, SENTINEL);
59719 }
59720 }
59721
59722 // Add terminal cascade pointers to the end
59723 if (!cascades.empty()) {
59724 for (idx_t j = 0; j < 2; ++j) {
59725 for (idx_t i = 0; i < fanout; ++i) {
59726 cascades[cascade_idx++] = bounds[i].first;
59727 }
59728 }
59729 }
59730
59731 ++build_complete;
59732}

◆ StartGames()

template<typename E = idx_t, typename O = idx_t, typename CMP = std::less<E>, uint64_t F = 32, uint64_t C = 32>
RunElement duckdb::MergeSortTree< E, O, CMP, F, C >::StartGames ( Games losers,
const RunElements elements,
const RunElement sentinel 
)
inlineprotected
59474 {
59475 const auto elem_nodes = elements.size();
59476 const auto game_nodes = losers.size();
59477 Games winners;
59478
59479 // Play the first round of games,
59480 // placing the losers at the bottom of the game
59481 const auto base_offset = game_nodes / 2;
59482 auto losers_base = losers.data() + base_offset;
59483 auto winners_base = winners.data() + base_offset;
59484
59485 const auto base_count = elem_nodes / 2;
59486 for (idx_t i = 0; i < base_count; ++i) {
59487 const auto &e0 = elements[i * 2 + 0];
59488 const auto &e1 = elements[i * 2 + 1];
59489 if (cmp(e0, e1)) {
59490 losers_base[i] = e1;
59491 winners_base[i] = e0;
59492 } else {
59493 losers_base[i] = e0;
59494 winners_base[i] = e1;
59495 }
59496 }
59497
59498 // Fill in any byes
59499 if (elem_nodes % 2) {
59500 winners_base[base_count] = elements.back();
59501 losers_base[base_count] = sentinel;
59502 }
59503
59504 // Pad to a power of 2
59505 const auto base_size = (game_nodes + 1) / 2;
59506 for (idx_t i = (elem_nodes + 1) / 2; i < base_size; ++i) {
59507 winners_base[i] = sentinel;
59508 losers_base[i] = sentinel;
59509 }
59510
59511 // Play the winners against each other
59512 // and stick the losers in the upper levels of the tournament tree
59513 for (idx_t i = base_offset; i-- > 0;) {
59514 // Indexing backwards
59515 const auto &e0 = winners[i * 2 + 1];
59516 const auto &e1 = winners[i * 2 + 2];
59517 if (cmp(e0, e1)) {
59518 losers[i] = e1;
59519 winners[i] = e0;
59520 } else {
59521 losers[i] = e0;
59522 winners[i] = e1;
59523 }
59524 }
59525
59526 // Return the final winner
59527 return winners[0];
59528 }

◆ ReplayGames()

template<typename E = idx_t, typename O = idx_t, typename CMP = std::less<E>, uint64_t F = 32, uint64_t C = 32>
RunElement duckdb::MergeSortTree< E, O, CMP, F, C >::ReplayGames ( Games losers,
idx_t  slot_idx,
const RunElement insert_val 
)
inlineprotected
59530 {
59531 RunElement smallest = insert_val;
59532 // Start at a fake level below
59533 auto idx = slot_idx + losers.size();
59534 do {
59535 // Parent index
59536 idx = (idx - 1) / 2;
59537 // swap if out of order
59538 if (cmp(losers[idx], smallest)) {
59539 std::swap(losers[idx], smallest);
59540 }
59541 } while (idx);
59542
59543 return smallest;
59544 }

◆ LowestCascadingLevel()

template<typename E = idx_t, typename O = idx_t, typename CMP = std::less<E>, uint64_t F = 32, uint64_t C = 32>
static idx_t duckdb::MergeSortTree< E, O, CMP, F, C >::LowestCascadingLevel ( )
inlinestaticprotected
59546 {
59547 idx_t level = 0;
59548 idx_t level_width = 1;
59549 while (level_width <= CASCADING) {
59550 ++level;
59551 level_width *= FANOUT;
59552 }
59553 return level;
59554 }

◆ Print()

template<typename E = idx_t, typename O = idx_t, typename CMP = std::less<E>, uint64_t F = 32, uint64_t C = 32>
void duckdb::MergeSortTree< E, O, CMP, F, C >::Print ( ) const
inline
59557 {
59558 std::ostringstream out;
59559 const char *separator = " ";
59560 const char *group_separator = " || ";
59561 idx_t level_width = 1;
59562 idx_t number_width = 0;
59563 for (auto &level : tree) {
59564 for (auto &e : level.first) {
59565 if (e) {
59566 idx_t digits = ceil(log10(fabs(e))) + (e < 0);
59567 if (digits > number_width) {
59568 number_width = digits;
59569 }
59570 }
59571 }
59572 }
59573 for (auto &level : tree) {
59574 // Print the elements themself
59575 {
59576 out << 'd';
59577 for (size_t i = 0; i < level.first.size(); ++i) {
59578 out << ((i && i % level_width == 0) ? group_separator : separator);
59579 out << std::setw(NumericCast<int32_t>(number_width)) << level.first[i];
59580 }
59581 out << '\n';
59582 }
59583 // Print the pointers
59584 if (!level.second.empty()) {
59585 idx_t run_cnt = (level.first.size() + level_width - 1) / level_width;
59586 idx_t cascading_idcs_cnt = run_cnt * (2 + level_width / CASCADING) * FANOUT;
59587 for (idx_t child_nr = 0; child_nr < FANOUT; ++child_nr) {
59588 out << " ";
59589 for (idx_t idx = 0; idx < cascading_idcs_cnt; idx += FANOUT) {
59590 out << ((idx && ((idx / FANOUT) % (level_width / CASCADING + 2) == 0)) ? group_separator
59591 : separator);
59592 out << std::setw(NumericCast<int32_t>(number_width)) << level.second[idx + child_nr];
59593 }
59594 out << '\n';
59595 }
59596 }
59597 level_width *= FANOUT;
59598 }
59599
59600 Printer::Print(out.str());
59601 }
static DUCKDB_API void Print(OutputStream stream, const string &str)
Print the object to the stream.
__device__ __forceinline__ float1 log10(const uchar1 &a)

The documentation for this struct was generated from the following file: