Skip to content

Commit bf69bef

Browse files
committed
free: fix humanization
1 parent 39cb446 commit bf69bef

File tree

1 file changed

+40
-24
lines changed

1 file changed

+40
-24
lines changed

src/uu/free/src/free.rs

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -457,31 +457,33 @@ fn construct_committed_str(mem_info: &MemInfo, n2s: &dyn Fn(u64) -> String) -> S
457457
}
458458

459459
// Here's the `-h` `--human` flag processing logic
460+
// See: https://github.com/uutils/procps/pull/431
460461
fn humanized(kib: u64, si: bool) -> String {
461-
let binding = {
462-
let display = ByteSize::kib(kib).display();
463-
464-
if si {
465-
display.si()
466-
} else {
467-
display.iec()
468-
}
462+
let b = ByteSize::kib(kib).0;
463+
let units = ['B', 'K', 'M', 'G', 'T', 'P'];
464+
let mut level = 0;
465+
let mut divisor = 1;
466+
while level < units.len() - 1 && divisor * 100 <= b {
467+
divisor *= if si { 1000 } else { 1024 };
468+
level += 1;
469+
}
470+
if level == 0 {
471+
return format!("{}{}", b, units[level]);
469472
}
470-
.to_string();
471-
472-
let split: Vec<&str> = binding.split(' ').collect();
473-
474-
// TODO: finish the logic of automatic scale.
475-
let num_string = String::from(split[0]);
476473

477-
let unit_string = {
478-
let mut tmp = String::from(split[1]);
479-
if tmp != "B" {
480-
tmp.pop();
481-
}
482-
tmp
474+
let value = (b as f64) / (divisor as f64);
475+
let formatted_value = if (value * 10.0).round() < 100.0 {
476+
format!("{:.1}", (value * 10.0).round() / 10.0)
477+
} else {
478+
(value as u64).to_string()
483479
};
484-
format!("{}{}", num_string, unit_string)
480+
481+
format!(
482+
"{}{}{}",
483+
formatted_value,
484+
units[level].to_owned(),
485+
if si { "" } else { "i" }
486+
)
485487
}
486488

487489
fn detect_unit(arg: &ArgMatches) -> fn(u64) -> u64 {
@@ -541,8 +543,22 @@ mod test {
541543
}
542544

543545
#[test]
544-
fn test_humanized_unit_for_zero() {
545-
assert_eq!("0B", humanized(0, false));
546-
assert_eq!("0B", humanized(0, true));
546+
fn test_humanized_unit() {
547+
let test_cases = [
548+
(0, false, "0B"),
549+
(0, true, "0B"),
550+
(1023, false, "1.0Mi"),
551+
(1024, true, "1.0M"),
552+
(1024, false, "1.0Mi"),
553+
(1536, true, "1.6M"),
554+
(1536, false, "1.5Mi"),
555+
(8500, true, "8.7M"),
556+
(8500, false, "8.3Mi"),
557+
(10138, false, "9.9Mi"),
558+
(10230, false, "9Mi"),
559+
];
560+
for &(kib, si, expected) in &test_cases {
561+
assert_eq!(humanized(kib, si), expected);
562+
}
547563
}
548564
}

0 commit comments

Comments
 (0)