C++ Format v7.0.0 Release Notes

Release Date: 2020-07-05 // 9 months ago
    • ⬇️ Reduced the library size. For example, on macOS a stripped test binary statically linked with {fmt} shrank from ~368k to less than 100k <http://www.zverovich.net/2020/05/21/reducing-library-size.html>_.

    • ➕ Added a simpler and more efficient format string compilation API <https://fmt.dev/7.0.0/api.html#compile-api>_:

    .. code:: c++

     #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.

    • ⚡️ 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++ <http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>_.

    • ⚡️ Optimized handling of small format strings. For example,

    .. code:: c++

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

    is now ~40% faster (#1685 <https://github.com/fmtlib/fmt/issues/1685>_).

    • Applied extern templates to improve compile times when using the core API and fmt/format.h (#1452 <https://github.com/fmtlib/fmt/issues/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 <https://github.com/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

    .. code:: c++

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

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

    .. code:: asm

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

    .. code:: c++

     #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 <https://github.com/fmtlib/fmt/pull/1689>_)

    .. code:: c++

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

    • ➕ Added support for named arguments, clear and reserve to dynamic_format_arg_store (#1655 <https://github.com/fmtlib/fmt/issues/1655>, #1663 <https://github.com/fmtlib/fmt/pull/1663>, #1674 <https://github.com/fmtlib/fmt/pull/1674>, #1677 <https://github.com/fmtlib/fmt/pull/1677>). Thanks @vsolontsov-ll (Vladimir Solontsov) <https://github.com/vsolontsov-ll>_.

    • ➕ Added support for the 'c' format specifier to integral types for compatibility with std::format (#1652 <https://github.com/fmtlib/fmt/issues/1652>_).

    • Replaced the 'n' format specifier with 'L' for compatibility with std::format (#1624 <https://github.com/fmtlib/fmt/issues/1624>_). The 'n' specifier can be enabled via the FMT_DEPRECATED_N_SPECIFIER macro.

    • 0️⃣ 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 <https://github.com/fmtlib/fmt/issues/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 <https://github.com/fmtlib/fmt/issues/1595>, #1682 <https://github.com/fmtlib/fmt/pull/1682>, #1683 <https://github.com/fmtlib/fmt/pull/1683>, #1687 <https://github.com/fmtlib/fmt/pull/1687>, #1699 <https://github.com/fmtlib/fmt/pull/1699>). Thanks @rimathia <https://github.com/rimathia>.

    • 🛠 Fixed handling of operator<< overloads that use copyfmt (#1666 <https://github.com/fmtlib/fmt/issues/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 <https://github.com/fmtlib/fmt/issues/1654>, #1656 <https://github.com/fmtlib/fmt/pull/1656>). Thanks @kwesolowski (Krzysztof Wesolowski) <https://github.com/kwesolowski>_.

    • 🏗 Replaced FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION with the FMT_FUZZ macro to prevent interferring with fuzzing of projects using {fmt} (#1650 <https://github.com/fmtlib/fmt/pull/1650>). Thanks @asraa (Asra Ali) <https://github.com/asraa>.

    • 🛠 Fixed compatibility with emscripten (#1636 <https://github.com/fmtlib/fmt/issues/1636>, #1637 <https://github.com/fmtlib/fmt/pull/1637>). Thanks @ArthurSonzogni (Arthur Sonzogni) <https://github.com/ArthurSonzogni>_.

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

    • 🏗 Implemented various build configuration fixes and improvements (#1603 <https://github.com/fmtlib/fmt/pull/1603>, #1657 <https://github.com/fmtlib/fmt/pull/1657>, #1702 <https://github.com/fmtlib/fmt/pull/1702>, #1728 <https://github.com/fmtlib/fmt/pull/1728>). Thanks @scramsby (Scott Ramsby) <https://github.com/scramsby>, @jtojnar (Jan Tojnar) <https://github.com/jtojnar>, @orivej (Orivej Desh) <https://github.com/orivej>, @flagarde <https://github.com/flagarde>.

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