Skip to content

numfmt: implement the last changes#11411

Merged
sylvestre merged 17 commits intouutils:mainfrom
sylvestre:numfmt-2
Apr 4, 2026
Merged

numfmt: implement the last changes#11411
sylvestre merged 17 commits intouutils:mainfrom
sylvestre:numfmt-2

Conversation

@sylvestre
Copy link
Copy Markdown
Contributor

should fix gnu/tests/numfmt/numfmt.pl

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 19, 2026

Merging this PR will improve performance by 23.64%

⚡ 1 improved benchmark
✅ 308 untouched benchmarks
⏩ 46 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation numfmt_padding[(10000, 50)] 47.9 ms 38.7 ms +23.64%

Comparing sylvestre:numfmt-2 (98b222e) with main (dfcb521)

Open in CodSpeed

Footnotes

  1. 46 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@sylvestre sylvestre force-pushed the numfmt-2 branch 2 times, most recently from 339ca87 to 524c1b1 Compare March 19, 2026 19:36
@sylvestre
Copy link
Copy Markdown
Contributor Author

and it passed!
2026-03-19T21:14:50.0513240Z PASS: tests/numfmt/numfmt.pl

@sylvestre sylvestre force-pushed the numfmt-2 branch 2 times, most recently from 32deeba to 840c848 Compare March 20, 2026 07:19
@sylvestre
Copy link
Copy Markdown
Contributor Author

@cakebaker i can split it into several if you want

@sylvestre sylvestre marked this pull request as ready for review March 23, 2026 16:35
@github-actions
Copy link
Copy Markdown

GNU testsuite comparison:

GNU test failed: tests/seq/seq-epipe. tests/seq/seq-epipe is passing on 'main'. Maybe you have to rebase?
Skip an intermittent issue tests/date/resolution (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/cut/bounded-memory (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/numfmt/numfmt is no longer failing!
Note: The gnu test tests/expand/bounded-memory is now being skipped but was previously passing.
Note: The gnu test tests/printf/printf-surprise is now being skipped but was previously passing.

@github-actions
Copy link
Copy Markdown

GNU testsuite comparison:

Skipping an intermittent issue tests/date/resolution (passes in this run but fails in the 'main' branch)
Note: The gnu test tests/printf/printf-surprise is now being skipped but was previously passing.

@cakebaker
Copy link
Copy Markdown
Contributor

i can split it into several if you want

@sylvestre yes, please.

@sylvestre
Copy link
Copy Markdown
Contributor Author

@cakebaker started:
#11560
#11561

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 1, 2026

GNU testsuite comparison:

Skip an intermittent issue tests/pr/bounded-memory (fails in this run but passes in the 'main' branch)
Skip an intermittent issue tests/tty/tty-eof (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/tail/inotify-dir-recreate (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/numfmt/numfmt is no longer failing!
Congrats! The gnu test tests/printf/printf-surprise is now passing!

Comment on lines +83 to +89
if valid_part == "." {
return Some(translate!("numfmt-error-invalid-suffix", "input" => s.quote()));
}

if valid_part.ends_with('.') {
return Some(translate!("numfmt-error-invalid-number", "input" => s.quote()));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name valid_part is a bit unlucky as its content can be invalid ;-)

Comment on lines +97 to +114
let rest = &s[valid_part.len()..];
if let Some(after_sep) = rest.strip_prefix(unit_separator) {
// Check if the next char is a valid suffix letter
let mut chars = after_sep.chars();
let has_suffix = chars
.next()
.is_some_and(|c| RawSuffix::try_from(&c).is_ok());
if has_suffix {
let suffix_char_len = 1;
let with_i =
chars.next() == Some('i') && [Unit::Auto, Unit::Iec(true)].contains(&unit);
let suffix_len = if with_i {
suffix_char_len + 1
} else {
suffix_char_len
};
valid_part.len() + unit_separator.len() + suffix_len
} else {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move this stuff into its own function to get rid of the nesting and all the else { valid_part.len() }. Something like:

fn some_great_function_name(
    s: &str,
    valid_part: &str,
    unit: Unit,
    unit_separator: &str,
) -> Option<usize> {
    let after_sep = s.get(valid_part.len()..)?.strip_prefix(unit_separator)?;

    let mut chars = after_sep.chars();
    let first_char = chars.next()?;

    RawSuffix::try_from(&first_char).ok()?;

    let is_iec = chars.next() == Some('i') && matches!(unit, Unit::Auto | Unit::Iec(true));
    let suffix_len = 1 + usize::from(is_iec);

    Some(valid_part.len() + unit_separator.len() + suffix_len)
}

And then use it like:

    let valid_end =
        if !unit_separator.is_empty() && valid_part == find_numeric_beginning(s).unwrap_or("") {
            some_great_function_name(s, valid_part, unit, &unit_separator).unwrap_or(valid_part.len())
        } else {
            valid_part.len()
        };

Comment on lines +128 to +130
Some('+' | '-') => {
Some(translate!("numfmt-error-invalid-number", "input" => s.quote()))
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional? GNU numfmt shows an "invalid suffix" error in such cases:

$ numfmt 123-
numfmt: invalid suffix in input: ‘123-’
$ numfmt 123+
numfmt: invalid suffix in input: ‘123+’

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 3, 2026

GNU testsuite comparison:

Skip an intermittent issue tests/date/resolution (fails in this run but passes in the 'main' branch)
Skip an intermittent issue tests/tty/tty-eof (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/date/date-locale-hour (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/numfmt/numfmt is no longer failing!
Congrats! The gnu test tests/timeout/timeout-group is no longer failing!
Note: The gnu test tests/tail/pipe-f is now being skipped but was previously passing.
Congrats! The gnu test tests/expand/bounded-memory is now passing!
Skip an intermittent issue tests/pr/bounded-memory (was skipped on 'main', now failing)

Skip GNU numfmt.pl tests not yet supported: unit-sep-22-fail, grp-1,
grp-2, delim-7, field-1, field-range-err-{1-4,6-13}, strtod-6,
strtod-6.1, leading-4, debug-2, devdebug-{1-7,9-11}, help-1,
fmt-err-9, fmt-err-11, fmt-15, ign-err-5, ign-err-m2.2, ign-err-m3.1.

Also unconditionally refresh binary symlinks to avoid stale builds.
…alidation

Fixes GNU numfmt.pl tests: grp-1, grp-2, debug-2, fmt-err-9,
fmt-err-11.
Buffer formatted output so that --invalid=fail does not duplicate lines
on error, and --invalid=abort streams directly for partial output.

Fixes GNU numfmt.pl test: field-3. Re-enables the full numfmt.pl test
suite by removing the skip list added earlier in the stack.
Build the grouped string in a single forward pass using chunk iteration
instead of reversing, inserting separators, then reversing again. This
avoids an extra String allocation and collection.
sylvestre added 12 commits April 4, 2026 22:51
Remove the trivial single-use helper and simplify split_next_field into
a compact 4-line function.
The two match arms for length 1 and length 2 had identical
RawSuffix::try_from checks. Unify into a single check after a boolean
guard.
Flatten the nested block scope by moving the output trait object and
format dispatch to the same level, reducing indentation.
Use the existing print_warning helper for the grouping-no-effect
message instead of a one-off writeln with util_name(). Use hardcoded
"numfmt:" prefix for the failed-to-convert message to match the other
debug warnings. Remove now-unused util_name import.
GNU test: numfmt.pl fmt-15
GNU test: numfmt.pl devdebug-*, help-1, field-1, field-range-err-*
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 4, 2026

GNU testsuite comparison:

Skipping an intermittent issue tests/cut/bounded-memory (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/numfmt/numfmt is no longer failing!
Congrats! The gnu test tests/tee/tee is no longer failing!

@sylvestre sylvestre merged commit 4552c0f into uutils:main Apr 4, 2026
172 checks passed
@sylvestre
Copy link
Copy Markdown
Contributor Author

merging for the next release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants