///|
fn resource_number(
value : String,
label : String,
) -> (Int64, Int32) raise CliError {
let mut start = 0
while start < value.length() &&
value[start] is (' ' | '\t' | '\n' | '\r' | '\u000b' | '\u000c') {
start += 1
}
if start < value.length() && value[start] == '+' {
start += 1
}
let mut end = start
let mut number = 0L
while end < value.length() && value[end] >= '0' && value[end] <= '9' {
let digit = (value[end].to_int() - '0'.to_int()).to_int64()
if number > (9223372036854775807L - digit) / 10L {
raise CliError("sort: \{label} argument '\{value}' too large")
}
number = number * 10L + digit
end += 1
}
if end == start {
raise CliError("sort: invalid \{label} argument '\{value}'")
}
(number, end)
}
///|
fn buffer_size(value : String) -> Int64 raise CliError {
let suffix_power = (suffix : String) => {
match suffix {
"K" | "k" => Some(1)
"M" | "m" => Some(2)
"G" | "g" => Some(3)
"T" | "t" => Some(4)
"P" => Some(5)
"E" => Some(6)
"Z" => Some(7)
"Y" => Some(8)
"R" => Some(9)
"Q" => Some(10)
_ => None
}
}
let (amount, end) = if suffix_power(value) is Some(_) {
(1L, 0)
} else {
resource_number(value, "--buffer-size")
}
let mut number = amount
let suffix = value[end:]
if suffix == "%" {
if number == 0L {
return 0L
}
raise CliError(
"sort: unsupported capability: percentage buffer size requires a public physical-memory query",
)
}
let power = match suffix {
"" => 1
"b" => 0
_ =>
match suffix_power(suffix.to_owned()) {
Some(power) => power
None =>
raise CliError("sort: invalid --buffer-size argument '\{value}'")
}
}
for _ in 0.. 9223372036854775807L / 1024L {
raise CliError("sort: --buffer-size argument '\{value}' too large")
}
number *= 1024L
}
number
}
///|
fn resource_controls(parsed : @cli.ParsedArgs) -> (Int64, Int32) raise CliError {
let sizes = parsed.values("buffer-size")
let mut budget = if sizes.is_empty() { 67108864L } else { 0L }
for value in sizes {
budget = budget.max(buffer_size(value))
}
let mut fan_in = 16
for value in parsed.values("batch-size") {
let (number, end) = resource_number(value, "--batch-size")
if end != value.length() {
raise CliError("sort: invalid --batch-size argument '\{value}'")
}
if number < 2 {
raise CliError(
"sort: invalid --batch-size argument '\{value}'\nsort: minimum --batch-size argument is '2'",
)
}
fan_in = number.min(16L).to_int()
}
(budget, fan_in)
}
///|
// Keep at least half of a feasible budget for runs before choosing merge
// fan-in. Tiny budgets retain the documented minimum working-set fallback.
fn merge_budget(budget : Int64, requested_fan_in : Int32) -> (Int64, Int32) {
let fan_in = (budget / 131072L - 6L)
.max(2L)
.min(requested_fan_in.min(16).to_int64())
.to_int()
let reserve = (fan_in + 6).to_int64() * 65536L
((budget - reserve).max(1L), fan_in)
}