///|
/// One bounded Merge Group expressed as half-open Run indexes.
pub(all) struct MergeGroup {
start : Int
end : Int
} derive(Debug, Eq)
///|
/// Plan one Merge Pass without opening files or allocating record buffers.
pub fn plan_merge_pass(
run_count : Int,
max_open_runs : Int,
) -> Array[MergeGroup] raise SortError {
if run_count < 0 {
raise InvalidConfig("run_count must not be negative")
}
if max_open_runs < 2 {
raise InvalidConfig("max_open_runs must be at least 2")
}
let groups : Array[MergeGroup] = []
let mut start = 0
while start < run_count {
let end = if start > run_count - max_open_runs {
run_count
} else {
start + max_open_runs
}
groups.push({ start, end, })
start = end
}
groups
}
///|
/// Number of Merge Passes required to reduce `run_count` Runs to one.
pub fn merge_pass_count(
run_count : Int,
max_open_runs : Int,
) -> Int raise SortError {
if run_count < 0 {
raise InvalidConfig("run_count must not be negative")
}
if max_open_runs < 2 {
raise InvalidConfig("max_open_runs must be at least 2")
}
let mut count = run_count
let mut passes = 0
while count > 1 {
count = (count + max_open_runs - 1) / max_open_runs
passes += 1
}
passes
}