* Widen display_width_of() to cover Emoji_Presentation code points
fmt::detail::display_width_of() only treated East Asian Wide/Fullwidth
code points and two hand-picked emoji ranges as two columns wide, so
emoji outside those ranges (e.g. the Dingbats block: cross mark U+274C,
white heavy check mark U+2705) were measured as one column even though
most terminals render them double-width. This produced visibly
inconsistent padding under {:^N} compared to CJK text (fixes#4851).
Replaced the ad hoc boolean expression with a sorted table of ranges
(East Asian Wide/Fullwidth plus the full Emoji_Presentation set from
Unicode's emoji-data.txt) looked up via binary search, and added
regression tests covering the original report plus edge cases:
multiple emoji, mixed emoji/CJK/ASCII content, precision truncation,
alignment/fill variants, newly covered emoji ranges, and regional
indicator (flag) pairs.
* Make wide_cp_ranges C++11-compatible; apply clang-format
* Move wide_cp_range struct into display_width_of()
* Derive wide_cp_ranges from East_Asian_Width data, restore constexpr
* Move wide_cp_ranges to display_width_of function body
* Update format.h
* Update wide_cp_ranges array to include comments
* Add inline to display_width_of and add 1F300-1F5FF and 1F900-1F9FF ranges to match [format.string.std]
* Update display_width_of lo hi varible declaration
---------
Co-authored-by: Eduardo Gomez Saldias <50159560+edugomez102@users.noreply.github.com>
Don't inject -freflection when building the module, so it isn't forced onto
the module or its importers. Build enum-test unconditionally (it is a no-op
without reflection) and drop the now-unneeded reflection detection. Enable
reflection explicitly in the g++-16 C++26 CI job.
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.
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>
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.
* 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>
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.
* 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
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.
* Set matching CC alongside CXX in Linux CI matrix
The Configure step only set CXX, so CMake's C compiler detection
fell back to whatever the default happened to be on the runner,
independent of which C++ compiler the matrix entry was actually
testing (e.g. CXX=clang++-3.6 but CC left to detect GCC 11).
Derive CC from the same matrix.cxx value the job already installs
a matching compiler for.
* Skip c-test when the C compiler is Clang < 3.8
Setting CC from matrix.cxx means the clang++-3.6 job now configures with real
clang 3.6 instead of falling back to the runner's default GCC, which exposes a
compile failure in test/c-test.c: clang predates the LLVM PR16340 fix (landed in
3.8) that applies array-to-pointer decay to the controlling expression of
_Generic, so fmt-c.h's FMT_MAKE_ARG dispatch never matches a string literal
(char[4]) against its char*/const char* associations. It falls through to the
zero-argument default association, which is then called with one argument.
The guard is at configure time rather than in the CI Test step. c-test is part
of the default target, so `cmake --build` compiles it before ctest ever runs --
excluding it with `ctest -E` cannot help, because the job has already failed in
the Build step. Guarding the add_executable also means anyone building fmt's
tests with an old clang benefits, not just this one CI job.
enable_language(C) stays first and unconditional, since CMAKE_C_COMPILER_VERSION
is not set before it. fmt-c itself (src/fmt-c.cc, C++) still builds on that job;
only the C-consumer smoke test is skipped.
The std.h header uses types such as std::atomic and std::atomic_flag.
For the normal build mode, this header does include all the
headers it needs, such as <atomic>.
However when building the C++ module of {fmt}, the std.h header
omits such includes, and instead expects them to be included
beforehand by fmt.cc - which lacked including <atomic>.
This fixes building the C++ module with libc++ 23, which has removed
a number of unnecessary transitive includes.
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.
The FMT_COMPILE("{}") format string takes a to_string fast path that
never runs the compiled field code the format_as fix (#4836) touched.
Use "[{}]" so the test actually goes through detail::field::format.
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().
Rename INSTALL_TARGETS to FMT_TARGETS since the list is now used for both
installation and the build-tree export, and move INSTALL_FILE_SET into the
FMT_INSTALL block as only install(TARGETS) uses it.
Replace the export-test static library and export-lib.cc with an INTERFACE
library, which reproduces the same CMake export dependency check (#4806).
export() was scoped inside if (FMT_INSTALL), so projects that pull in
fmt via add_subdirectory()/FetchContent without installing it had no
way to get the exported fmt::* targets. If such a project tries to
export its own targets that depend on fmt, CMake fails with "target
... requires target fmt that is not in any export set".
Hoist the target list/export name and the export() call itself out of
the FMT_INSTALL guard so the build-tree export file is always
generated; the install()-only pieces (config/version files, pkgconfig,
install(EXPORT ...)) stay behind the guard and installed behavior is
unchanged.
Fixes#4806
Co-authored-by: flink <w741069229@gmail.com>
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.
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.
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.
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>
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.
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.
if FMT_CONSTEXPR is resolved to constexpr MSC warns about dead code
after 'return' instruction. Explicitly using 'else' in these cases
avoids the warning.