C++ Format v7.1.0 Release Notes

Release Date: 2020-10-26 // 6 months ago
    • Switched from Grisu3 <https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf>_ to Dragonbox <https://github.com/jk-jeon/dragonbox>_ for the default floating-point formatting which gives the shortest decimal representation with round-trip guarantee and correct rounding (#1882 <https://github.com/fmtlib/fmt/pull/1882>, #1887 <https://github.com/fmtlib/fmt/pull/1887>, #1894 <https://github.com/fmtlib/fmt/pull/1894>). This makes {fmt} up to 20-30x faster than common implementations of std::ostringstream and sprintf on dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark> and faster than double-conversion and Ryū:

    .. image:: https://user-images.githubusercontent.com/576385/ 95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png

    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) <https://github.com/jk-jeon>_.

    • ➕ Added an experimental unsynchronized file output API which, together with format string compilation <https://fmt.dev/latest/api.html#compile-api>, can give 5-9 times speed up compared to fprintf <https://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html> on common platforms (godbolt <https://godbolt.org/z/nsTcG8>__):

    .. code:: c++

     #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 <https://github.com/fmtlib/fmt/issues/1819>, #1837 <https://github.com/fmtlib/fmt/pull/1837>). For example (godbolt <https://godbolt.org/z/c4M6fh>__):

    .. code:: c++

     #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) <https://github.com/adamburgess>_.

    • ➕ Added support for ranges with non-const begin/end to fmt::join (#1784 <https://github.com/fmtlib/fmt/issues/1784>, #1786 <https://github.com/fmtlib/fmt/pull/1786>). For example (godbolt <https://godbolt.org/z/jP63Tv>__):

    .. code:: c++

     #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) <https://github.com/tonyelewis>_.

    • ➕ Added a memory_buffer::append overload that takes a range (#1806 <https://github.com/fmtlib/fmt/pull/1806>). Thanks @BRevzin (Barry Revzin) <https://github.com/BRevzin>.

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

    .. code:: c++

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

    compiles to just (godbolt <https://godbolt.org/z/5vncz3>__):

    .. code:: asm

     _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 <https://github.com/fmtlib/fmt/issues/1809>_).

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

    .. code:: c++

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

    Error (godbolt <https://godbolt.org/z/GoxM4e>__):

    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 <https://fmt.dev/7.1.0/api.html#argument-lists>_ function template that allows you to write formatting functions with compile-time format string checks and avoid binary code bloat (godbolt <https://godbolt.org/z/PEf9qr>__):

    .. code:: c++

     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 <https://godbolt.org/z/dPhWvj>__):

    .. code:: c++

     #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 <https://fmt.dev/latest/api.html#core-api>__ (godbolt <https://godbolt.org/z/sPjY1K>__):

    .. code:: c++

     #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 <https://github.com/fmtlib/fmt/issues/1764>, #1767 <https://github.com/fmtlib/fmt/pull/1767>, #1869 <https://github.com/fmtlib/fmt/pull/1869>). For example (godbolt <https://godbolt.org/z/93h86q>_):

    .. code:: c++

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

    Thanks @Kurkin (Dmitry Kurkin) <https://github.com/Kurkin>, @alexezeder (Alexey Ochapov) <https://github.com/alexezeder>.

    • Added fmt::format_to overload that take text_style (#1593 <https://github.com/fmtlib/fmt/issues/1593>, #1842 <https://github.com/fmtlib/fmt/issues/1842>, #1843 <https://github.com/fmtlib/fmt/pull/1843>). For example (godbolt <https://godbolt.org/z/91153r>_):

    .. code:: c++

     #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) <https://github.com/Naios>_.

    • Made the # specifier emit trailing zeros in addition to the decimal point (#1797 <https://github.com/fmtlib/fmt/issues/1797>). For example (godbolt <https://godbolt.org/z/bhdcW9>_):

    .. code:: c++

     #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 <https://github.com/fmtlib/fmt/issues/1893>, #1943 <https://github.com/fmtlib/fmt/issues/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 <https://github.com/fmtlib/fmt/issues/1873>, #1917 <https://github.com/fmtlib/fmt/issues/1917>).

    • Made fmt::to_string fallback on ostream insertion operator if the formatter specialization is not provided (#1815 <https://github.com/fmtlib/fmt/issues/1815>, #1829 <https://github.com/fmtlib/fmt/pull/1829>). Thanks @alexezeder (Alexey Ochapov) <https://github.com/alexezeder>_.

    • ➕ Added support for the append mode to the experimental file API and improved fcntl.h detection. (#1847 <https://github.com/fmtlib/fmt/pull/1847>, #1848 <https://github.com/fmtlib/fmt/pull/1848>). Thanks @t-wiser <https://github.com/t-wiser>_.

    • 🛠 Fixed handling of types that have both an implicit conversion operator and an overloaded ostream insertion operator (#1766 <https://github.com/fmtlib/fmt/issues/1766>_).

    • 🛠 Fixed a slicing issue in an internal iterator type (#1822 <https://github.com/fmtlib/fmt/pull/1822>). Thanks @BRevzin (Barry Revzin) <https://github.com/BRevzin>.

    • 🛠 Fixed an issue in locale-specific integer formatting (#1927 <https://github.com/fmtlib/fmt/issues/1927>_).

    • 🛠 Fixed handling of exotic code unit types (#1870 <https://github.com/fmtlib/fmt/issues/1870>, #1932 <https://github.com/fmtlib/fmt/issues/1932>).

    • Improved FMT_ALWAYS_INLINE (#1878 <https://github.com/fmtlib/fmt/pull/1878>). Thanks @jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>.

    • ✂ Removed dependency on windows.h (#1900 <https://github.com/fmtlib/fmt/pull/1900>). Thanks @bernd5 (Bernd Baumanns) <https://github.com/bernd5>.

    • ⚡️ Optimized counting of decimal digits on MSVC (#1890 <https://github.com/fmtlib/fmt/pull/1890>). Thanks @mwinterb <https://github.com/mwinterb>.

    • 👌 Improved documentation (#1772 <https://github.com/fmtlib/fmt/issues/1772>, #1775 <https://github.com/fmtlib/fmt/pull/1775>, #1792 <https://github.com/fmtlib/fmt/pull/1792>, #1838 <https://github.com/fmtlib/fmt/pull/1838>, #1888 <https://github.com/fmtlib/fmt/pull/1888>, #1918 <https://github.com/fmtlib/fmt/pull/1918>, #1939 <https://github.com/fmtlib/fmt/pull/1939>). Thanks @leolchat (Léonard Gérard) <https://github.com/leolchat>, @pepsiman (Malcolm Parsons) <https://github.com/pepsiman>, @Klaim (Joël Lamotte) <https://github.com/Klaim>, @ravijanjam (Ravi J) <https://github.com/ravijanjam>, @francesco-st <https://github.com/francesco-st>, @udnaan (Adnan) <https://github.com/udnaan>_.

    • ⬇️ 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 <https://github.com/fmtlib/fmt/issues/1778>, #1781 <https://github.com/fmtlib/fmt/pull/1781>). Thanks @kammce (Khalil Estell) <https://github.com/kammce>_.

    • 👉 Added the FMT_USE_INLINE_NAMESPACES macro to control usage of inline namespaces (#1945 <https://github.com/fmtlib/fmt/pull/1945>). Thanks @darklukee <https://github.com/darklukee>.

    • 👌 Improved build configuration (#1760 <https://github.com/fmtlib/fmt/pull/1760>, #1770 <https://github.com/fmtlib/fmt/pull/1770>, #1779 <https://github.com/fmtlib/fmt/issues/1779>, #1783 <https://github.com/fmtlib/fmt/pull/1783>, #1823 <https://github.com/fmtlib/fmt/pull/1823>). Thanks @dvetutnev (Dmitriy Vetutnev) <https://github.com/dvetutnev>, @xvitaly (Vitaly Zaitsev) <https://github.com/xvitaly>, @tambry (Raul Tambre) <https://github.com/tambry>, @medithe <https://github.com/medithe>, @martinwuehrer (Martin Wührer) <https://github.com/martinwuehrer>.

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