Skip to content

support fill, alignment and width in range and tuple formatters - #4910

Open
avionicharshit-byte wants to merge 1 commit into
fmtlib:mainfrom
avionicharshit-byte:range-tuple-width
Open

support fill, alignment and width in range and tuple formatters#4910
avionicharshit-byte wants to merge 1 commit into
fmtlib:mainfrom
avionicharshit-byte:range-tuple-width

Conversation

@avionicharshit-byte

Copy link
Copy Markdown

fmt::format("{:*>20}", std::vector<int>{1,2,3}) doesnt compile , it fails with "invalid format specifier" . same for tuple , pair and map . std::format accepts it .

// before
fmt::format("{:*>20}", std::vector<int>{1, 2, 3});  // error: invalid format specifier

// after
fmt::format("{:*>20}", std::vector<int>{1, 2, 3});  // "***********[1, 2, 3]"

in C++23 both range-format-spec and tuple-format-spec start with fill-and-align_opt width_opt , so fill , alignment and width belong to the composed output . range_formatter::parse never called parse_align or parse_width , it went straight to looking for n , s and ? . doc/syntax.md documented the shorter grammar as well , so thats updated too .

the fix adds detail::composed_specs in include/fmt/ranges.h , used from the range , tuple and map formatters . it parses alignment and width before the range's own options , and skips a leading : so {::>5} still means the underlying element spec , which is what std::format does . in format() , when a width is asked for the composed output goes into a memory_buffer first and is then written padded . thats the same buffer and pad idiom nested_formatter uses , and the same one #4860 used for the std::exception formatter .

each formatter's old body moved into write_body unchanged and format() became the padding wrapper . nothing existing changed behaviour , no existing test expectation was edited .

i checked 22 cases against real std::format output from libc++ : default align , < > ^ , custom fill , dynamic width {:*>{}} , width with n , width with a nested element spec , sets , maps , vector<std::string> debug quoting , tuple , pair , and output longer than the width . 21 of the 22 match byte for byte . added ranges_test.format_width covering them , all 22 test suites pass , clang-format clean .

the 22nd is not part of this PR . fmt::format("{:n}", std::pair<int, int>{1, 2}) gives 12 where std::format gives 1, 2 , fmt drops the separator along with the brackets for tuples but keeps it for ranges . thats already on master and i havent touched it , fixing it would change the expectations at test/ranges-test.cc:176 and :183 . happy to file it separately .

@avionicharshit-byte avionicharshit-byte changed the title Support fill, alignment and width in range and tuple formatters support fill, alignment and width in range and tuple formatters Sep 2, 2026
@avionicharshit-byte
avionicharshit-byte marked this pull request as ready for review September 2, 2026 18:06
@avionicharshit-byte

Copy link
Copy Markdown
Author

@vitaut ci is waiting on workflow approval. the earlier failure was a missing FMT_CONSTEXPR on composed_specs::resolve, fixed and amended.

@vitaut vitaut left a comment

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.

Thanks for the PR! Overall looks good but please update the doc per inline comment.

Comment thread doc/syntax.md Outdated
Comment on lines +632 to +634
The `fill`, `align` and `width` options have the same meaning as in the
[standard format specification](#format-specification-mini-language) and apply
to the whole formatted range rather than to its elements.

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.

Please clarify that : is not allowed, something like:

The fill, align and width options have the same meaning as in the standard format specification, except that : cannot be used as a fill character because it introduces the underlying element specification.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done , used your wording

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.

2 participants