Fmt Versions Save

A modern formatting library

8.0.0

2 years ago

Enabled compile-time format string check by default. For example (godbolt):

#include <fmt/core.h>

int main() {
  fmt::print("{:d}", "I am not a number");
}

gives a compile-time error on compilers with C++20 consteval support (gcc 10+, clang 11+) because d is not a valid format specifier for a string.

To pass a runtime string wrap it in fmt::runtime:

fmt::print(fmt::runtime("{:d}"), "I am not a number");

Added compile-time formatting (#2019, #2044, #2056, #2072, #2075, #2078, #2129, #2326). For example (godbolt):

#include <fmt/compile.h>

consteval auto compile_time_itoa(int value) -> std::array<char, 10> {
  auto result = std::array<char, 10>();
  fmt::format_to(result.data(), FMT_COMPILE("{}"), value);
  return result;
}

constexpr auto answer = compile_time_itoa(42);

Most of the formatting functionality is available at compile time with a notable exception of floating-point numbers and pointers. Thanks @alexezeder (Alexey Ochapov).

Optimized handling of format specifiers during format string compilation. For example, hexadecimal formatting ("{:x}") is now 3-7x faster than before when using format_to with format string compilation and a stack-allocated buffer (#1944).

Before (7.1.3):

----------------------------------------------------------------------------
Benchmark                                  Time             CPU   Iterations
----------------------------------------------------------------------------
FMTCompileOld/0                         15.5 ns         15.5 ns     43302898
FMTCompileOld/42                        16.6 ns         16.6 ns     43278267
FMTCompileOld/273123                    18.7 ns         18.6 ns     37035861
FMTCompileOld/9223372036854775807       19.4 ns         19.4 ns     35243000
----------------------------------------------------------------------------

After (8.x):

----------------------------------------------------------------------------
Benchmark                                  Time             CPU   Iterations
----------------------------------------------------------------------------
FMTCompileNew/0                         1.99 ns         1.99 ns    360523686
FMTCompileNew/42                        2.33 ns         2.33 ns    279865664
FMTCompileNew/273123                    3.72 ns         3.71 ns    190230315
FMTCompileNew/9223372036854775807       5.28 ns         5.26 ns    130711631
----------------------------------------------------------------------------

It is even faster than std::to_chars from libc++ compiled with clang on macOS:

----------------------------------------------------------------------------
Benchmark                                  Time             CPU   Iterations
----------------------------------------------------------------------------
ToChars/0                               4.42 ns         4.41 ns    160196630
ToChars/42                              5.00 ns         4.98 ns    140735201
ToChars/273123                          7.26 ns         7.24 ns     95784130
ToChars/9223372036854775807             8.77 ns         8.75 ns     75872534
----------------------------------------------------------------------------

In other cases, especially involving std::string construction, the speed up is usually lower because handling format specifiers takes a smaller fraction of the total time.

Added the _cf user-defined literal to represent a compiled format string. It can be used instead of the FMT_COMPILE macro (#2043, #2242):

#include <fmt/compile.h>

using namespace fmt::literals;
auto s = fmt::format(FMT_COMPILE("{}"), 42); // 🙁 not modern
auto s = fmt::format("{}"_cf, 42);           // 🙂 modern as hell

It requires compiler support for class types in non-type template parameters (a C++20 feature) which is available in GCC 9.3+. Thanks @alexezeder (Alexey Ochapov).

Format string compilation now requires format functions of formatter specializations for user-defined types to be const:

template <> struct fmt::formatter<my_type>: formatter<string_view> {
  template <typename FormatContext>
  auto format(my_type obj, FormatContext& ctx) const {  // Note const here.
    // ...
  }
};

Added UDL-based named argument support to format string compilation (#2243, #2281). For example:

#include <fmt/compile.h>

using namespace fmt::literals;
auto s = fmt::format(FMT_COMPILE("{answer}"), "answer"_a = 42);

Here the argument named "answer" is resolved at compile time with no runtime overhead. Thanks @alexezeder (Alexey Ochapov).

Added format string compilation support to fmt::print (#2280, #2304). Thanks @alexezeder (Alexey Ochapov).

Added initial support for compiling {fmt} as a C++20 module (#2235, #2240, #2260, #2282, #2283, #2288, #2298, #2306, #2307, #2309, #2318, #2324, #2332, #2340). Thanks @DanielaE (Daniela Engert).

Made symbols private by default reducing shared library size (#2301). For example there was a ~15% reported reduction on one platform. Thanks @sergiud (Sergiu Deitsch).

Optimized includes making the result of preprocessing fmt/format.h ~20% smaller with libstdc++/C++20 and slightly improving build times (#1998).

Added support of ranges with non-const begin / end (#1953). Thanks @kitegi (sarah).

Added support of std::byte and other formattable types to fmt::join (#1981, #2040, #2050, #2262). For example:

#include <fmt/format.h>
#include <cstddef>
#include <vector>

int main() {
  auto bytes = std::vector{std::byte(4), std::byte(2)};
  fmt::print("{}", fmt::join(bytes, ""));
}

prints "42".

Thanks @kamibo (Camille Bordignon).

Implemented the default format for std::chrono::system_clock (#2319, #2345). For example:

#include <fmt/chrono.h>

int main() {
  fmt::print("{}", std::chrono::system_clock::now());
}

prints "2021-06-18 15:22:00" (the output depends on the current date and time). Thanks @sunmy2019.

Made more chrono specifiers locale independent by default. Use the 'L' specifier to get localized formatting. For example:

#include <fmt/chrono.h>

int main() {
  std::locale::global(std::locale("ru_RU.UTF-8"));
  auto monday = std::chrono::weekday(1);
  fmt::print("{}\n", monday);   // prints "Mon"
  fmt::print("{:L}\n", monday); // prints "пн"
}

Improved locale handling in chrono formatting (#2337, #2349, #2350). Thanks @phprus (Vladislav Shchapov).

Deprecated fmt/locale.h moving the formatting functions that take a locale to fmt/format.h (char) and fmt/xchar (other overloads). This doesn't introduce a dependency on <locale> so there is virtually no compile time effect.

Made parameter order in vformat_to consistent with format_to (#2327).

Added support for time points with arbitrary durations (#2208). For example:

#include <fmt/chrono.h>

int main() {
  using tp = std::chrono::time_point<
    std::chrono::system_clock, std::chrono::seconds>;
  fmt::print("{:%S}", tp(std::chrono::seconds(42)));
}

prints "42".

Formatting floating-point numbers no longer produces trailing zeros by default for consistency with std::format. For example:

#include <fmt/core.h>

int main() {
  fmt::print("{0:.3}", 1.1);
}

prints "1.1". Use the '#' specifier to keep trailing zeros.

Dropped a limit on the number of elements in a range and replaced {} with [] as range delimiters for consistency with Python's str.format.

The 'L' specifier for locale-specific numeric formatting can now be combined with presentation specifiers as in std::format. For example:

#include <fmt/core.h>
#include <locale>

int main() {
  std::locale::global(std::locale("fr_FR.UTF-8"));
  fmt::print("{0:.2Lf}", 0.42);
}

prints "0,42". The deprecated 'n' specifier has been removed.

Made the 0 specifier ignored for infinity and NaN (#2305, #2310). Thanks @Liedtke (Matthias Liedtke).

Made the hexfloat formatting use the right alignment by default (#2308, #2317). Thanks @Liedtke (Matthias Liedtke).

Removed the deprecated numeric alignment ('='). Use the '0' specifier instead.

Removed the deprecated fmt/posix.h header that has been replaced with fmt/os.h.

Removed the deprecated format_to_n_context, format_to_n_args and make_format_to_n_args. They have been replaced with format_context, format_args and make_format_args respectively.

Moved wchar_t-specific functions and types to fmt/xchar.h. You can define FMT_DEPRECATED_INCLUDE_XCHAR to automatically include fmt/xchar.h from fmt/format.h but this will be disabled in the next major release.

Fixed handling of the '+' specifier in localized formatting (#2133).

Added support for the 's' format specifier that gives textual representation of bool (#2094, #2109). For example:

#include <fmt/core.h>

int main() {
  fmt::print("{:s}", true);
}

prints "true". Thanks @powercoderlol (Ivan Polyakov).

Made fmt::ptr work with function pointers (#2131). For example:

#include <fmt/format.h>

int main() {
  fmt::print("My main: {}\n", fmt::ptr(main));
}

Thanks @mikecrowe (Mike Crowe).

Fixed fmt::formatted_size with format string compilation (#2141, #2161). Thanks @alexezeder (Alexey Ochapov).

Fixed handling of empty format strings during format string compilation (#2042):

auto s = fmt::format(FMT_COMPILE(""));

Thanks @alexezeder (Alexey Ochapov).

Fixed handling of enums in fmt::to_string (#2036).

Improved width computation (#2033, #2091). For example:

#include <fmt/core.h>

int main() {
  fmt::print("{:-<10}{}\n", "你好", "世界");
  fmt::print("{:-<10}{}\n", "hello", "world");
}

prints

on a modern terminal.

The experimental fast output stream (fmt::ostream) is now truncated by default for consistency with fopen (#2018). For example:

#include <fmt/os.h>

int main() {
  fmt::ostream out1 = fmt::output_file("guide");
  out1.print("Zaphod");
  out1.close();
  fmt::ostream out2 = fmt::output_file("guide");
  out2.print("Ford");
}

writes "Ford" to the file "guide". To preserve the old file content if any pass fmt::file::WRONLY | fmt::file::CREATE flags to fmt::output_file.

Fixed moving of fmt::ostream that holds buffered data (#2197, #2198). Thanks @vtta.

Replaced the fmt::system_error exception with a function of the same name that constructs std::system_error (#2266).

Replaced the fmt::windows_error exception with a function of the same name that constructs std::system_error with the category returned by fmt::system_category() (#2274, #2275). The latter is similar to std::sytem_category but correctly handles UTF-8. Thanks @phprus (Vladislav Shchapov).

Replaced fmt::error_code with std::error_code and made it formattable (#2269, #2270, #2273). Thanks @phprus (Vladislav Shchapov).

Added speech synthesis support (#2206).

Made format_to work with a memory buffer that has a custom allocator (#2300). Thanks @voxmea.

Added Allocator::max_size support to basic_memory_buffer. (#1960). Thanks @phprus (Vladislav Shchapov).

Added wide string support to fmt::join (#2236). Thanks @crbrz.

Made iterators passed to formatter specializations via a format context satisfy C++20 std::output_iterator requirements (#2156, #2158, #2195, #2204). Thanks @randomnetcat (Jason Cobb).

Optimized the printf implementation (#1982, #1984, #2016, #2164). Thanks @rimathia and @moiwi.

Improved detection of constexpr char_traits (#2246, #2257). Thanks @phprus (Vladislav Shchapov).

Fixed writing to stdout when it is redirected to NUL on Windows (#2080).

Fixed exception propagation from iterators (#2097).

Improved strftime error handling (#2238, #2244). Thanks @yumeyao.

Stopped using deprecated GCC UDL template extension.

Added fmt/args.h to the install target (#2096).

Error messages are now passed to assert when exceptions are disabled (#2145). Thanks @NobodyXu (Jiahao XU).

Added the FMT_MASTER_PROJECT CMake option to control build and install targets when {fmt} is included via add_subdirectory (#2098, #2100). Thanks @randomizedthinking.

Improved build configuration (#2026, #2122). Thanks @luncliff (Park DongHa) and @ibaned (Dan Ibanez).

Fixed various warnings and compilation issues (#1947, #1959, #1963, #1965, #1966, #1974, #1975, #1990, #2000, #2001, #2002, #2004, #2006, #2009, #2010, #2038, #2039, #2047, #2053, #2059, #2065, #2067, #2068, #2073, #2103 #2105 #2106, #2107, #2116 #2117, #2118 #2119, #2127, #2128, #2140, #2142, #2143, #2144, #2147, #2148, #2149, #2152, #2160, #2170, #2175, #2176, #2177, #2178, #2179, #2180, #2181, #2183, #2184, #2185, #2186, #2187, #2190, #2192, #2194, #2205, #2210, #2211, #2215, #2216, #2218, #2220, #2228, #2229, #2230, #2233, #2239, #2248, #2252, #2253, #2255, #2261, #2278, #2284, #2287, #2289, #2290, #2293, #2295, #2296, #2297, #2311, #2313, #2315, #2320, #2321, #2323, #2328, #2329, #2333, #2338, #2341). Thanks @darklukee, @fagg (Ashton Fagg), @killerbot242 (Lieven de Cock), @jgopel (Jonathan Gopel), @yeswalrus (Walter Gray), @Finkman, @HazardyKnusperkeks (Björn Schäpers), @dkavolis (Daumantas Kavolis) @concatime (Issam Maghni), @chronoxor (Ivan Shynkarenka), @summivox (Yin Zhong), @yNeo, @Apache-HB (Elliot), @alexezeder (Alexey Ochapov), @toojays (John Steele Scott), @Brainy0207, @vadz (VZ), @imsherlock (Ryan Sherlock), @phprus (Vladislav Shchapov), @white238 (Chris White), @yafshar (Yaser Afshar), @BillyDonahue (Billy Donahue), @jstaahl, @denchat, @DanielaE (Daniela Engert), @ilyakurdyukov (Ilya Kurdyukov), @ilmai, @JessyDL (Jessy De Lannoit), @sergiud (Sergiu Deitsch), @mwinterb, @sven-herrmann, @jmelas (John Melas), @twoixter (Jose Miguel Pérez), @crbrz, @upsj (Tobias Ribizel).

Improved documentation (#1986, #2051, #2057, #2081, #2084, #2312). Thanks @imba-tjd (谭九鼎), @0x416c69 (AlιAѕѕaѕѕιN), @mordante.

Continuous integration and test improvements (#1969, #1991, #2020, #2110, #2114, #2196, #2217, #2247, #2256, #2336, #2346). Thanks @jgopel (Jonathan Gopel), @alexezeder (Alexey Ochapov) and @DanielaE (Daniela Engert).

7.1.3

3 years ago
  • Fixed handling of buffer boundaries in format_to_n (#1996, #2029).

  • Fixed linkage errors when linking with a shared library (#2011).

  • Reintroduced ostream support to range formatters (#2014).

  • Worked around an issue with mixing std versions in gcc (#2017).

7.1.2

3 years ago
  • Fixed floating point formatting with large precision (#1976).

7.1.1

3 years ago
  • Fixed ABI compatibility with 7.0.x (#1961).

  • Added the FMT_ARM_ABI_COMPATIBILITY macro to work around ABI incompatibility between GCC and Clang on ARM (#1919).

  • Worked around a SFINAE bug in GCC 8 (#1957).

  • Fixed linkage errors when building with GCC's LTO (#1955).

  • Fixed a compilation error when building without __builtin_clz or equivalent (#1968). Thanks @tohammer (Tobias Hammer).

  • Fixed a sign conversion warning (#1964). Thanks @OptoCloud.

7.1.0

3 years ago
  • Switched from Grisu3 to Dragonbox for the default floating-point formatting which gives the shortest decimal representation with round-trip guarantee and correct rounding (#1882, #1887, #1894). This makes {fmt} up to 20-30x faster than common implementations of std::ostringstream and sprintf on dtoa-benchmark and faster than double-conversion and Ryū:It is possible to get even better performance at the cost of larger binary size by compiling with the FMT_USE_FULL_CACHE_DRAGONBOX macro set to 1. Thanks @jk-jeon (Junekey Jeon).

  • Added an experimental unsynchronized file output API which, together with format string compilation, can give 5-9 times speed up compared to fprintf on common platforms (godbolt):

    #include <fmt/os.h>
    
    int main() {
      auto f = fmt::output_file("guide");
      f.print("The answer is {}.", 42);
    }
    
  • Added a formatter for std::chrono::time_point<system_clock> (#1819, #1837). For example (godbolt):

    #include <fmt/chrono.h>
    
    int main() {
      auto now = std::chrono::system_clock::now();
      fmt::print("The time is {:%H:%M:%S}.\n", now);
    }
    

    Thanks @adamburgess (Adam Burgess).

  • Added support for ranges with non-const begin/end to fmt::join (#1784, #1786). For example (godbolt):

    #include <fmt/ranges.h>
    #include <range/v3/view/filter.hpp>
    
    int main() {
      using std::literals::string_literals::operator""s;
      auto strs = std::array{"a"s, "bb"s, "ccc"s};
      auto range = strs | ranges::views::filter(
        [] (const std::string &x) { return x.size() != 2; }
      );
      fmt::print("{}\n", fmt::join(range, ""));
    }
    

    prints "accc". Thanks @tonyelewis (Tony E Lewis).

  • Added a memory_buffer::append overload that takes a range (#1806). Thanks @BRevzin (Barry Revzin).

  • Improved handling of single code units in FMT_COMPILE. For example:

    #include <fmt/compile.h>
    
    char* f(char* buf) {
      return fmt::format_to(buf, FMT_COMPILE("x{}"), 42);
    }
    

    compiles to just (godbolt):

    _Z1fPc:
      movb $120, (%rdi)
      xorl %edx, %edx
      cmpl $42, _ZN3fmt2v76detail10basic_dataIvE23zero_or_powers_of_10_32E+8(%rip)
      movl $3, %eax
      seta %dl
      subl %edx, %eax
      movzwl _ZN3fmt2v76detail10basic_dataIvE6digitsE+84(%rip), %edx
      cltq
      addq %rdi, %rax
      movw %dx, -2(%rax)
      ret
    

    Here a single mov instruction writes 'x' ($120) to the output buffer.

  • Added dynamic width support to format string compilation (#1809).

  • Improved error reporting for unformattable types: now you'll get the type name directly in the error message instead of the note:

    #include <fmt/core.h>
    
    struct how_about_no {};
    
    int main() {
      fmt::print("{}", how_about_no());
    }
    

    Error (godbolt): fmt/core.h:1438:3: error: static_assert failed due to requirement 'fmt::v7::formattable<how_about_no>()' "Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt" ...

  • Added the make_args_checked function template that allows you to write formatting functions with compile-time format string checks and avoid binary code bloat (godbolt):

    void vlog(const char* file, int line, fmt::string_view format,
              fmt::format_args args) {
      fmt::print("{}: {}: ", file, line);
      fmt::vprint(format, args);
    }
    
    template <typename S, typename... Args>
    void log(const char* file, int line, const S& format, Args&&... args) {
      vlog(file, line, format,
          fmt::make_args_checked<Args...>(format, args...));
    }
    
    #define MY_LOG(format, ...) \
      log(__FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__)
    
    MY_LOG("invalid squishiness: {}", 42);
    
  • Replaced snprintf fallback with a faster internal IEEE 754 float and double formatter for arbitrary precision. For example (godbolt):

    #include <fmt/core.h>
    
    int main() {
      fmt::print("{:.500}\n", 4.9406564584124654E-324);
    }
    

    prints 4.9406564584124654417656879286822137236505980261432476442558568250067550727020875186529983636163599237979656469544571773092665671035593979639877479601078187812630071319031140452784581716784898210368871863605699873072305000638740915356498438731247339727316961514003171538539807412623856559117102665855668676818703956031062493194527159149245532930545654440112748012970999954193198940908041656332452475714786901472678015935523861155013480352649347201937902681071074917033322268447533357208324319360923829e-324.

  • Made format_to_n and formatted_size part of the core API (godbolt):

    #include <fmt/core.h>
    
    int main() {
      char buffer[10];
      auto result = fmt::format_to_n(buffer, sizeof(buffer), "{}", 42);
    }
    
  • Added fmt::format_to_n overload with format string compilation (#1764, #1767, #1869). For example (godbolt):

    #include <fmt/compile.h>
    
    int main() {
      char buffer[8];
      fmt::format_to_n(buffer, sizeof(buffer), FMT_COMPILE("{}"), 42);
    }
    

    Thanks @Kurkin (Dmitry Kurkin), @alexezeder (Alexey Ochapov).

  • Added fmt::format_to overload that take text_style (#1593, #1842, #1843). For example (godbolt):

    #include <fmt/color.h>
    
    int main() {
      std::string out;
      fmt::format_to(std::back_inserter(out),
                     fmt::emphasis::bold | fg(fmt::color::red),
                     "The answer is {}.", 42);
    }
    

    Thanks @Naios (Denis Blank).

  • Made the # specifier emit trailing zeros in addition to the decimal point (#1797). For example (godbolt):

    #include <fmt/core.h>
    
    int main() {
      fmt::print("{:#.2g}", 0.5);
    }
    

    prints 0.50.

  • Changed the default floating point format to not include .0 for consistency with std::format and std::to_chars (#1893, #1943). It is possible to get the decimal point and trailing zero with the # specifier.

  • Fixed an issue with floating-point formatting that could result in addition of a non-significant trailing zero in rare cases e.g. 1.00e-34 instead of 1.0e-34 (#1873, #1917).

  • Made fmt::to_string fallback on ostream insertion operator if the formatter specialization is not provided (#1815, #1829). Thanks @alexezeder (Alexey Ochapov).

  • Added support for the append mode to the experimental file API and improved fcntl.h detection. (#1847, #1848). Thanks @t-wiser.

  • Fixed handling of types that have both an implicit conversion operator and an overloaded ostream insertion operator (#1766).

  • Fixed a slicing issue in an internal iterator type (#1822). Thanks @BRevzin (Barry Revzin).

  • Fixed an issue in locale-specific integer formatting (#1927).

  • Fixed handling of exotic code unit types (#1870, #1932).

  • Improved FMT_ALWAYS_INLINE (#1878). Thanks @jk-jeon (Junekey Jeon).

  • Removed dependency on windows.h (#1900). Thanks @bernd5 (Bernd Baumanns).

  • Optimized counting of decimal digits on MSVC (#1890). Thanks @mwinterb.

  • Improved documentation (#1772, #1775, #1792, #1838, #1888, #1918, #1939). Thanks @leolchat (Léonard Gérard), @pepsiman (Malcolm Parsons), @Klaim (Joël Lamotte), @ravijanjam (Ravi J), @francesco-st, @udnaan (Adnan).

  • Added the FMT_REDUCE_INT_INSTANTIATIONS CMake option that reduces the binary code size at the cost of some integer formatting performance. This can be useful for extremely memory-constrained embedded systems (#1778, #1781). Thanks @kammce (Khalil Estell).

  • Added the FMT_USE_INLINE_NAMESPACES macro to control usage of inline namespaces (#1945). Thanks @darklukee.

  • Improved build configuration (#1760, #1770, #1779, #1783, #1823). Thanks @dvetutnev (Dmitriy Vetutnev), @xvitaly (Vitaly Zaitsev), @tambry (Raul Tambre), @medithe, @martinwuehrer (Martin Wührer).

  • Fixed various warnings and compilation issues (#1790, #1802, #1808, #1810, #1811, #1812, #1814, #1816, #1817, #1818, #1825, #1836, #1855, #1856, #1860, #1877, #1879, #1880, #1896, #1897, #1898, #1904, #1908, #1911, #1912, #1928, #1929, #1935 #1937, #1942, #1949). Thanks @TheQwertiest, @medithe, @martinwuehrer (Martin Wührer), @n16h7hunt3r, @Othereum (Seokjin Lee), @gsjaardema (Greg Sjaardema), @AlexanderLanin (Alexander Lanin), @gcerretani (Giovanni Cerretani), @chronoxor (Ivan Shynkarenka), @noizefloor (Jan Schwers), @akohlmey (Axel Kohlmeyer), @jk-jeon (Junekey Jeon), @rimathia, @rglarix (Riccardo Ghetta (larix)), @moiwi, @heckad (Kazantcev Andrey), @MarcDirven. @BartSiwek (Bart Siwek), @darklukee.

7.0.3

3 years ago
  • Worked around broken numeric_limits for 128-bit integers (#1787).

  • Added error reporting on missing named arguments (#1796).

  • Stopped using 128-bit integers with clang-cl (#1800). Thanks @Kingcom.

  • Fixed issues in locale-specific integer formatting (#1782, #1801).

7.0.2

3 years ago
  • Worked around broken numeric_limits for 128-bit integers (#1725).

  • Fixed compatibility with CMake 3.4 (#1779).

  • Fixed handling of digit separators in locale-specific formatting (#1782).

7.0.1

3 years ago
  • Updated the inline version namespace name.

  • Worked around a gcc bug in mangling of alias templates (#1753).

  • Fixed a linkage error on Windows (#1757). Thanks @Kurkin (Dmitry Kurkin).

  • Fixed minor issues with the documentation.

7.0.0

3 years ago
  • Reduced the library size. For example, on macOS a stripped test binary statically linked with {fmt} shrank from ~368k to less than 100k.

  • Added a simpler and more efficient format string compilation API:

    #include <fmt/compile.h>
    
    // Converts 42 into std::string using the most efficient method and no
    // runtime format string processing.
    std::string s = fmt::format(FMT_COMPILE("{}"), 42);
    

    The old fmt::compile API is now deprecated.

    Thanks @ldionne (Louis Dionne) for the suggestion and @hanickadot (Hana Dusíková) for the initial prototype.

  • Optimized integer formatting: format_to with format string compilation and a stack-allocated buffer is now faster than to_chars on both libc++ and libstdc++.

  • Optimized handling of small format strings. For example,

    fmt::format("Result: {}: ({},{},{},{})", str1, str2, str3, str4, str5)
    

    is now ~40% faster (#1685).

  • Applied extern templates to improve compile times when using the core API and fmt/format.h (#1452). For example, on macOS with clang the compile time of a test translation unit dropped from 2.3s to 0.3s with -O2 and from 0.6s to 0.3s with the default settings (-O0).

    Before (-O2):

    % time c++ -c test.cc -I include -std=c++17 -O2
    c++ -c test.cc -I include -std=c++17 -O2  2.22s user 0.08s system 99% cpu 2.311 total
    

    After (-O2):

    % time c++ -c test.cc -I include -std=c++17 -O2
    c++ -c test.cc -I include -std=c++17 -O2  0.26s user 0.04s system 98% cpu 0.303 total
    

    Before (default):

    % time c++ -c test.cc -I include -std=c++17
    c++ -c test.cc -I include -std=c++17  0.53s user 0.06s system 98% cpu 0.601 total
    

    After (default):

    % time c++ -c test.cc -I include -std=c++17
    c++ -c test.cc -I include -std=c++17  0.24s user 0.06s system 98% cpu 0.301 total
    

    It is still recommended to use fmt/core.h instead of fmt/format.h but the compile time difference is now smaller. Thanks @alex3d for the suggestion.

  • Named arguments are now stored on stack (no dynamic memory allocations) and the compiled code is more compact and efficient. For example

    #include <fmt/core.h>
    
    int main() {
      fmt::print("The answer is {answer}\n", fmt::arg("answer", 42));
    }
    

    compiles to just (godbolt)

    .LC0:
            .string "answer"
    .LC1:
            .string "The answer is {answer}\n"
    main:
            sub     rsp, 56
            mov     edi, OFFSET FLAT:.LC1
            mov     esi, 23
            movabs  rdx, 4611686018427387905
            lea     rax, [rsp+32]
            lea     rcx, [rsp+16]
            mov     QWORD PTR [rsp+8], 1
            mov     QWORD PTR [rsp], rax
            mov     DWORD PTR [rsp+16], 42
            mov     QWORD PTR [rsp+32], OFFSET FLAT:.LC0
            mov     DWORD PTR [rsp+40], 0
            call    fmt::v6::vprint(fmt::v6::basic_string_view<char>,
                                    fmt::v6::format_args)
            xor     eax, eax
            add     rsp, 56
            ret
    
        .L.str.1:
                .asciz  "answer"
    
  • Implemented compile-time checks for dynamic width and precision (#1614):

    #include <fmt/format.h>
    
    int main() {
      fmt::print(FMT_STRING("{0:{1}}"), 42);
    }
    

    now gives a compilation error because argument 1 doesn't exist:

    In file included from test.cc:1:
    include/fmt/format.h:2726:27: error: constexpr variable 'invalid_format' must be
    initialized by a constant expression
      FMT_CONSTEXPR_DECL bool invalid_format =
                              ^
    ...
    include/fmt/core.h:569:26: note: in call to
    '&checker(s, {}).context_->on_error(&"argument not found"[0])'
        if (id >= num_args_) on_error("argument not found");
                            ^
    
  • Added sentinel support to fmt::join (#1689)

    struct zstring_sentinel {};
    bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; }
    bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; }
    
    struct zstring {
      const char* p;
      const char* begin() const { return p; }
      zstring_sentinel end() const { return {}; }
    };
    
    auto s = fmt::format("{}", fmt::join(zstring{"hello"}, "_"));
    // s == "h_e_l_l_o"
    

    Thanks @BRevzin (Barry Revzin).

  • Added support for named args, clear and reserve to dynamic_format_arg_store (#1655, #1663, #1674, #1677). Thanks @vsolontsov-ll (Vladimir Solontsov).

  • Added support for the 'c' format specifier to integral types for compatibility with std::format (#1652).

  • Replaced the 'n' format specifier with 'L' for compatibility with std::format (#1624). The 'n' specifier can be enabled via the FMT_DEPRECATED_N_SPECIFIER macro.

  • The '=' format specifier is now disabled by default for compatibility with std::format. It can be enabled via the FMT_DEPRECATED_NUMERIC_ALIGN macro.

  • Removed the following deprecated APIs:

    • FMT_STRING_ALIAS and fmt macros - replaced by FMT_STRING

    • fmt::basic_string_view::char_type - replaced by fmt::basic_string_view::value_type

    • convert_to_int

    • format_arg_store::types

    • *parse_context - replaced by *format_parse_context

    • FMT_DEPRECATED_INCLUDE_OS

    • FMT_DEPRECATED_PERCENT - incompatible with std::format

    • *writer - replaced by compiled format API

  • Renamed the internal namespace to detail (#1538). The former is still provided as an alias if the FMT_USE_INTERNAL macro is defined.

  • Improved compatibility between fmt::printf with the standard specs (#1595, #1682, #1683, #1687, #1699). Thanks @rimathia.

  • Fixed handling of operator<< overloads that use copyfmt (#1666).

  • Added the FMT_OS CMake option to control inclusion of OS-specific APIs in the fmt target. This can be useful for embedded platforms (#1654, #1656). Thanks @kwesolowski (Krzysztof Wesolowski).

  • Replaced FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION with the FMT_FUZZ macro to prevent interferring with fuzzing of projects using {fmt} (#1650). Thanks @asraa (Asra Ali).

  • Fixed compatibility with emscripten (#1636, #1637). Thanks @ArthurSonzogni (Arthur Sonzogni).

  • Improved documentation (#704, #1643, #1660, #1681, #1691, #1706, #1714, #1721, #1739, #1740, #1741, #1751). Thanks @senior7515 (Alexander Gallego), @lsr0 (Lindsay Roberts), @puetzk (Kevin Puetz), @fpelliccioni (Fernando Pelliccioni), Alexey Kuzmenko, @jelly (jelle van der Waa), @claremacrae (Clare Macrae), @jiapengwen (文佳鹏), @gsjaardema (Greg Sjaardema), @alexey-milovidov.

  • Implemented various build configuration fixes and improvements (#1603, #1657, #1702, #1728). Thanks @scramsby (Scott Ramsby), @jtojnar (Jan Tojnar), @orivej (Orivej Desh), @flagarde.

  • Fixed various warnings and compilation issues (#1616, #1620, #1622, #1625, #1627, #1628, #1629, #1631, #1633, #1649, #1658, #1661, #1667, #1668, #1669, #1692, #1696, #1697, #1707, #1712, #1716, #1722, #1724, #1729, #1738, #1742, #1743, #1744, #1747, #1750). Thanks @gsjaardema (Greg Sjaardema), @gabime (Gabi Melman), @johnor (Johan), @gabime (Dmitry Kurkin), @invexed (James Beach), @peterbell10, @daixtrose (Markus Werle), @petrutlucian94 (Lucian Petrut), @Neargye (Daniil Goncharov), @ambitslix (Attila M. Szilagyi), @gabime (Gabi Melman), @erthink (Leonid Yuriev), @tohammer (Tobias Hammer), @0x8000-0000 (Florin Iucha).

6.2.1

4 years ago
  • Fixed ostream support in sprintf (#1631).

  • Fixed type detection when using implicit conversion to string_view and ostream operator<< inconsistently (#1662).