3479 Commits

Author SHA1 Message Date
Victor Zverovich
9375eb3792 Simplify enum identifier handling and tidy reflection docs
Use std::string_view directly for enumerator identifiers, dropping the
identifier wrapper and inlining count_enumerators. Update the fmt/enum.h
documentation to point at cppreference and drop an inaccurate note. Also
remove the no-longer-needed -Wno-sfinae-incomplete option for format-test.
2026-08-29 15:11:31 -07:00
Avi Kivity
e589a16ecb
Look up sparse enum identifiers in a hash table instead of a linear search (#4899)
Enums that are too sparse for the index table were formatted by scanning
all enumerators. Replace the scan with an open-addressed hash table with
linear probing, sized to the smallest power of two that keeps the load
factor at or below 0.5. This guarantees a free slot, which terminates the
probe sequence and doubles as the not-found result because identifiers
are never empty.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 07:47:28 -07:00
Advit Arora
e76a9520a3
Right-align inf and nan with a bare width (#4895)
fmt::format("{:6}", nan) gave "nan   " where std::format and printf("%6f")
give "   nan". write_nonfinite was the only numeric write path taking
write_padded's align::left default, so a width with no explicit align
left-aligned inf and nan while every finite value right-aligned. That
default only reaches align::none, leaving explicit <, > and ^ and the 0
flag unchanged.
2026-08-27 08:54:40 -07:00
Avi Kivity
e27cc20bd9
Format enums annotated with fmt::as_identifiers (requires C++26 reflection) (#4885)
* Format enums annotated with fmt::as_identifiers (requires C++26 reflection)

Format an enum as the identifier of the matching enumerator if the enum is
annotated with fmt::as_identifiers:

  enum class [[=fmt::as_identifiers]] color { red, green, blue };
  fmt::format("{}", color::green);  // "green"

Values that don't match any enumerator are represented as their underlying
value in decimal before applying string formatting.

Identifiers are retrieved via C++26 reflection (P2996) and the annotation
via P3394. FMT_USE_REFLECTION is autodetected and can be overridden by the
user; without reflection the header is empty.

The header is also part of the fmt module, but, unlike with headers, whether
it provides anything is decided when the module is compiled, so the module
build detects reflection and enables it if the configured standard allows.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Look up enum identifiers by index when the values are dense

The formatter for enums annotated with fmt::as_identifiers did a linear
search over all enumerators. Build a table indexed by the distance from
the smallest enumerator value instead, with empty string views in the
holes, which reduces the lookup to a bounds check and one load.

The table is only used if at least 70% of its elements are identifiers,
limiting its size to 10/7 of the number of enumerators. Sparser enums
keep using the linear search. Distances are computed in uint64_t so that
enums with negative values and values spanning the whole range of the
underlying type are handled without overflow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Suppress -Wsfinae-incomplete in format-test on GCC 16

GCC 16 warns when a type is completed after it failed to be complete in a
SFINAE context. format-test does this deliberately to check that formatting
of incomplete types works, so the warning is a false positive there and
breaks the build with -Werror.

* Test GCC 16 on CI

GCC 16 is the first compiler with C++26 reflection support, which is needed
by fmt/enum.h, so add a job that builds with it in C++26 mode. It comes from
the ubuntu-toolchain-r/test PPA since Ubuntu 24.04 only ships GCC 14.

Also report when reflection is not detected to make it visible that
enum-test was skipped.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 09:31:28 -07:00
Victor Zverovich
21d4cc15c8 Reject sign-aware zero padding in std::exception and error_code formatters
Treat a leading '0' as the zero flag rather than the start of the width so
it is rejected (as in the core formatter) instead of being silently consumed.
Also trim the exception_align test to the cases this actually introduces.
2026-08-16 10:00:41 -07:00
egorkaa
cde18a38bb
Support width and alignment in std::exception formatter (#4860)
* Support width and alignment in std::exception formatter

The formatter for std::exception (and std::exception_ptr) previously
accepted only the optional 't' type-name specifier, so standard fill,
align and width specifiers were rejected with "unknown format
specifier". This made it impossible to pad or align exception messages,
e.g. when laying them out in a log column.

Parse the standard fill/align/width specifiers (as the std::filesystem::
path formatter already does) and apply them when writing the message.
Dynamic width ({:{}}) and the 'none'/'unknown exception' cases for
exception_ptr are handled too. Existing behavior ({}, {:t}, nested
exception unwinding) is unchanged.

* Update std.h
2026-08-13 11:00:46 -07:00
Victor Zverovich
be39437ee7 Simplify hexfloat comment and retry CI downloads on more 50x errors 2026-08-12 09:21:04 -07:00
hexonal
6c285ba88a
Format zero as 0x0p+0 in hexfloat (#4878)
fmt::format("{:a}", 0.0) produced 0x0p-1022 where printf's %a gives
0x0p+0, and likewise for -0.0, {:A}, {:#a} and any explicit precision.

basic_fp::assign maps a zero biased exponent to 1 ("subnormals use
biased exponent 1"), which is right for subnormals but not for zero, so
format_hexfloat inherited the minimum subnormal exponent for a value
whose significand carries no information. Reset the exponent there
rather than in assign, which the decimal path shares.

A zero significand can only come from +-0: normals get the implicit bit
added, and a subnormal has a nonzero significand by definition. So the
guard cannot affect anything else, and denorm_min keeps its existing
denormalized form (0x0.0000000000001p-1022, asserted in format_double).

The five new expectations were taken from printf rather than derived,
and all fail without this change.
2026-08-10 09:52:03 -07:00
Victor Zverovich
0cf9f5c99e Rename loc_copy to locale in locale helpers (#4876) 2026-08-10 09:12:29 -07:00
aouxwoux
60ccad511f
revert clang tidy suppression (#4877) 2026-08-05 08:48:24 -07:00
Vitalii Orazov
5f06f84835
Avoid -Wdangling-reference false positive in locale helpers (#4876) 2026-08-05 08:05:22 -07:00
Victor Zverovich
a00f82c6b6 Bump version 2026-07-29 11:04:35 -07:00
Victor Zverovich
26c01df3bd Handle const-qualified named arguments
A named argument that arrives const-qualified was not recognized by
is_named_arg, silently dropping its name. This happens both when a
named argument is passed through an intermediate function returning
const T& (https://github.com/fmtlib/fmt/issues/4866) and in fmt's own
compiled format path, which passes arguments as const T&.

Make is_named_arg and is_static_named_arg see through top-level const so
the name is preserved instead of dropped.
2026-07-29 09:20:23 -07:00
Victor Zverovich
2a2d9edb25 Remove extra newline 2026-07-25 07:52:08 -07:00
Avi Kivity
6439aa09b1
Export ostream formatters and streamed() from the module (#4861)
Make basic_ostream_formatter, ostream_formatter and streamed() accessible
to module users via FMT_BEGIN_EXPORT/FMT_BEGIN_EXPORT. Drop now unneeded
FMT_EXPORT for print() and println().
2026-07-23 08:14:21 -07:00
Victor Zverovich
7b4ef1c814 Optimize 128-bit integer formatting
count_digits and do_format_decimal divided the full 128-bit value by a
constant in a loop. Compilers do not strength-reduce 128-bit division, so
each iteration became a slow __udivti3 library call (~27 per number).

Reduce the value to 64-bit chunks by dividing by 10^19 (at most twice) and
reuse the fast 64-bit paths, giving a ~5x speedup on full-range values.
2026-07-19 17:05:39 -07:00
Victor Zverovich
b5d1e5404b Annotate FMT_USE_RTTI #endif directives
Add trailing "// FMT_USE_RTTI" comments to the matching #endif lines to make
the conditional-compilation blocks easier to follow.
2026-07-17 12:12:25 -07:00
Victor Zverovich
7852fc384c Fix out-of-range integers with the 'c' presentation type (#4839)
Formatting an integer with ':c' used the magnitude (abs_value) and never
range-checked, so negatives were mangled and out-of-range values silently
truncated. Copy the value as a character and report an error when it is out
of range, treating all character types as unsigned for portability.
2026-07-17 11:36:52 -07:00
Victor Zverovich
d45179c1e7 Merge the two integer write overloads into one
The appender and generic-iterator overloads only differed in whether the
integer formatting code was inlined. Merge them into a single overload and
select write_int_noinline vs inline write_int via if constexpr, keeping the
same codegen (out of line for appenders, inlined for compiled formatting)
with no size regression.
2026-07-17 11:16:40 -07:00
AMAN UPADHYAY
af2d9f2b78
Fix FMT_COMPILE failure with format_as mapped types (Issue #4794) (#4836) 2026-07-12 09:21:55 -07:00
Avi Kivity
1a99c2630c
Format nested exceptions in std::exception formatter (#4844)
Detect when a std::exception also derives from std::nested_exception
(e.g. via std::throw_with_nested) and unwind the whole chain, joining
each level with ": ". The type-name flag ({:t}) is honored at every
level, and the std::exception_ptr formatter inherits this behavior.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 08:50:10 -07:00
Victor Zverovich
7077b016cc Guard fast decimal path on bit width instead of byte size
Use num_bits<UInt>() == 32 instead of sizeof(UInt) == 4 in
do_format_decimal. The magic-number two-digit algorithm requires
exactly 32 value bits, so this is more precise on platforms where
CHAR_BIT != 8 and is consistent with existing num_bits<T>() usage.
2026-07-11 09:18:24 -07:00
Victor Zverovich
9d13c41ce6 Format null std::exception_ptr as "none"
Change the null exception_ptr representation from "nullptr" to "none" to
convey the "no exception" state more clearly, and update the test.
2026-07-11 08:21:32 -07:00
Jan
6dac6cad05
feat: add formatter for std::exception_ptr (#4808) (#4819) 2026-07-05 09:22:18 -07:00
Victor Zverovich
cd67635a19 Suppress MSVC C4702 header-wide instead of restructuring code
Revert the explicit-else workaround from #4822 and instead disable the
"unreachable code" warning for all of base.h. Add an FMT_PRAGMA_MSVC
helper (mirroring FMT_PRAGMA_GCC/CLANG) and wrap the header in a single
warning(push)/disable:4702/pop pair, keeping the original control flow.
2026-07-04 10:01:11 -07:00
torsten48
b54093c658
avoid MSC warning C4702: unreachable code (#4822)
if FMT_CONSTEXPR is resolved to constexpr MSC warns about dead code
after 'return' instruction. Explicitly using 'else' in these cases
avoids the warning.
2026-07-03 10:39:09 -07:00
Victor Zverovich
d24fef27d1 Minor cleanup 2026-06-26 15:57:41 -07:00
Jan Engelhardt
719823cc64
Turn libfmt-c into a shared library (#4812)
Linux distros don't like having static archives. Set fmt-c to shared
just like the main fmt library.
2026-06-26 06:55:44 -07:00
Yat Ho
0e601c34de
fix: explicitly check operator[] in is_contiguous (#4825)
Prevent false positives when the container itself does not have `operator[](size_t)`, but the target type of one of the non-explicit user-defined conversion functions does.
2026-06-25 12:21:59 -07:00
Vinay Kumar
588b3a0f8f
Fix fallback uint128 bitwise not (#4813) 2026-06-17 23:52:12 -07:00
Victor Zverovich
979c94dff8 Fix hang/assertion when printing to a pipe with closed read end (#4797) 2026-06-18 08:08:44 +02:00
aizu-m
de4c6c502e
fix out-of-range float to int conversion in to_nonnegative_int (#4802) 2026-06-16 23:14:58 -07:00
aizu-m
128ba144ab
fix out-of-bounds read in basic_format_args::get (#4800) 2026-06-09 22:18:35 -07:00
Ferdinand Bachmann
ffd8397db1
Add fmt_print to C API (#4789)
* Add FMT_FORMAT_ARGS(fmt, ...) macro to C API to simplify user-defined format wrappers

* Add fmt_print to C API
2026-06-05 06:40:30 -07:00
Victor Zverovich
70f794e395 Bump version 2026-06-02 15:16:15 -07:00
Jiami Lin
a90ad5d6fd
Fix formatting std::tm with null tm_zone (#4790) 2026-06-01 18:16:49 -07:00
Victor Zverovich
46cf422f54 Unify copyright notices 2026-05-31 08:54:06 -07:00
Victor Zverovich
a823ba0699 Deconstexprify exception formatter 2026-05-31 08:24:38 -07:00
j4niwzis
029d543768
Fix compile time format for ranges, style, and std (#4759) 2026-05-31 08:21:35 -07:00
ahoarau
0acf106c52
Add println functions for formatted output with color support (#4782) 2026-05-25 08:30:36 -07:00
Victor Zverovich
93e26fa578 Cleanup is_contiguous 2026-05-22 08:04:50 -07:00
Vladislav Shchapov
a30cf7d1ad
Provide reasonable default definition for is_contiguous (#4770)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2026-05-21 07:19:19 -07:00
theflashwin
2f18a88e68 fix GCC PCH Breakage Triggered by fmt Scoped #pragma GCC optimize(0g) 2026-05-11 07:20:40 -07:00
Vladislav Shchapov
9cb8c0f92b
Fix ambiguous formatter<std::optional<T>> between fmt/std.h and fmt/ranges.h on C++26 (P3168R2) (#4761)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2026-05-03 07:37:46 -07:00
Victor Zverovich
5a9a184448 Apply clang-format 2026-05-03 07:33:53 -07:00
Kağan Can Şit
d0e3d20af8
chore(IWYU):Remove redundant includes (#4758) 2026-04-29 20:50:56 -07:00
Victor Zverovich
432fda7bfa Fix false positive in tsan (fixes #4755) 2026-04-29 17:16:36 -07:00
user202729
eeff8680ed
Avoid dropping null byte in format string (#4732)
* Avoid dropping null byte in format string

* Add a test for null byte in format string
2026-04-23 09:34:27 -07:00
Victor Zverovich
27d0c03c4d Minor cleanup 2026-04-12 09:50:12 -07:00
Cazadorro
03cfb8645e
Workaround a CUDA issue in handing UTF-32 literals (#4719) 2026-04-10 16:28:52 -07:00