ChangeLog.md 103 KB

11.1.1 - 2024-12-27

11.1.0 - 2024-12-25

GCC:

  • Before: 161 instructions of which 105 are in reusable functions (godbolt).
  • After: 116 instructions of which 60 are in reusable functions (godbolt).

Clang:

  • Before: 310 instructions of which 251 are in reusable functions (godbolt).
  • After: 194 instructions of which 135 are in reusable functions (godbolt).

  • Added an experimental fmt::writer API that can be used for writing to different destinations such as files or strings (https://github.com/fmtlib/fmt/issues/2354). For example (godbolt):

    #include <fmt/os.h>
    
    void write_text(fmt::writer w) {
    w.print("The answer is {}.", 42);
    }
    
    int main() {
    // Write to FILE.
    write_text(stdout);
    
    // Write to fmt::ostream.
    auto f = fmt::output_file("myfile");
    write_text(f);
    
    // Write to std::string.
    auto sb = fmt::string_buffer();
    write_text(sb);
    std::string s = sb.str();
    }
    
  • Added width and alignment support to the formatter of std::error_code.

  • Made std::expected<void, E> formattable (https://github.com/fmtlib/fmt/issues/4145, https://github.com/fmtlib/fmt/pull/4148). For example (godbolt):

    fmt::print("{}", std::expected<void, int>());
    

prints

  expected()

Thanks @phprus.

Thanks @Arghnews.

11.0.2 - 2024-07-20

11.0.1 - 2024-07-05

11.0.0 - 2024-07-01

  • Added fmt/base.h which provides a subset of the API with minimal include dependencies and enough functionality to replace all uses of the printf family of functions. This brings the compile time of code using {fmt} much closer to the equivalent printf code as shown on the following benchmark that compiles 100 source files:

| Method | Compile Time (s) | |--------------|------------------| | printf | 1.6 | | IOStreams | 25.9 | | fmt 10.x | 19.0 | | fmt 11.0 | 4.8 | | tinyformat | 29.1 | | Boost Format | 55.0 |

This gives almost 4x improvement in build speed compared to version 10. Note that the benchmark is purely formatting code and includes. In real projects the difference from printf will be smaller partly because common standard headers will be included in almost any translation unit (TU) anyway. In particular, in every case except printf above ~1s is spent in total on including <type_traits> in all TUs.

For example, it gives ~24% improvement on a simple benchmark compiled with Apple clang version 15.0.0 (clang-1500.1.0.2.5) and run on macOS 14.2.1:

  -------------------------------------------------------
  Benchmark             Time             CPU   Iterations
  -------------------------------------------------------
  printf             81.8 ns         81.5 ns      8496899
  fmt::print (10.x)  63.8 ns         61.9 ns     11524151
  fmt::print (11.0)  51.3 ns         51.0 ns     13846580

no longer results in a buffer overflow. Instead the output will be truncated and you can get the end iterator and whether truncation occurred from the result object. Thanks @ThePhD.

prints a green day:

image

Thanks @zivshek.

10.2.1 - 2024-01-04

10.2.0 - 2024-01-01

Thanks @Richardk2n.

prints

  /app/example.cpp:5:51: int main()

Thanks @felix642.

Thanks @muggenhor.

  • Added an experimental nested_formatter that provides an easy way of applying a formatter to one or more subobjects while automatically handling width, fill and alignment. For example:

    #include <fmt/format.h>
    
    struct point {
    double x, y;
    };
    
    template <>
    struct fmt::formatter<point> : nested_formatter<double> {
    auto format(point p, format_context& ctx) const {
      return write_padded(ctx, [=](auto out) {
        return format_to(out, "({}, {})", nested(p.x), nested(p.y));
      });
    }
    };
    
    int main() {
    fmt::print("[{:>20.2f}]", point{1, 2});
    }
    

prints

  [          (1.00, 2.00)]

prints "C:/foo" on Windows.

Thanks @js324.

Pass fmt::styled(...) as a parameter instead.

10.1.1 - 2023-08-28

10.1.0 - 2023-08-12

{fmt} 10.0:

  ---------------------------------------------------------
  Benchmark               Time             CPU   Iterations
  ---------------------------------------------------------
  BM_format_to         78.9 ns         78.9 ns      8881746
  BM_format_to_n        568 ns          568 ns      1232089

{fmt} 10.1:

  ---------------------------------------------------------
  Benchmark               Time             CPU   Iterations
  ---------------------------------------------------------
  BM_format_to         54.9 ns         54.9 ns     12727944
  BM_format_to_n        133 ns          133 ns      5257795

Thanks @phprus and @felix642.

10.0.0 - 2023-05-09

  • Red: new algorithm
  • Green: new algorithm with FMT_USE_FULL_CACHE_DRAGONBOX defined to 1
  • Blue: old algorithm

Thanks @jk-jeon.

Thanks @ShawnZhong.

Thanks @patrickroocks @phprus and @BRevzin.

Thanks @ShawnZhong.

prints:

  vector<bool>::_M_range_check: __n (which is 0) >= this->size() (which is 0)

on libstdc++. Thanks @zach2good and @phprus.

Thanks @ShawnZhong.

where is U+2019 used as a digit separator in the de_CH locale.

9.1.0 - 2022-08-27

  • fmt::formatted_size now works at compile time (https://github.com/fmtlib/fmt/pull/3026). For example (godbolt):

    #include <fmt/compile.h>
    
    int main() {
    using namespace fmt::literals;
    constexpr size_t n = fmt::formatted_size("{}"_cf, 42);
    fmt::print("{}\n", n); // prints 2
    }
    

Thanks @marksantaniello.

Thanks @BRevzin.

9.0.0 - 2022-07-04

  • Switched to the internal floating point formatter for all decimal presentation formats. In particular this results in consistent rounding on all platforms and removing the s[n]printf fallback for decimal FP formatting.

  • Compile-time floating point formatting no longer requires the header-only mode. For example (godbolt):

    #include <array>
    #include <fmt/compile.h>
    
    consteval auto compile_time_dtoa(double 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_dtoa(0.42);
    

works with the default settings.

  • Improved the implementation of Dragonbox, the algorithm used for the default floating-point formatting (https://github.com/fmtlib/fmt/pull/2713, https://github.com/fmtlib/fmt/pull/2750). Thanks @jk-jeon.

  • Made fmt::to_string work with __float128. This uses the internal FP formatter and works even on system without __float128 support in [s]printf.

  • Disabled automatic std::ostream insertion operator (operator<<) discovery when fmt/ostream.h is included to prevent ODR violations. You can get the old behavior by defining FMT_DEPRECATED_OSTREAM but this will be removed in the next major release. Use fmt::streamed or fmt::ostream_formatter to enable formatting via std::ostream instead.

  • Added fmt::ostream_formatter that can be used to write formatter specializations that perform formatting via std::ostream. For example (godbolt):

    #include <fmt/ostream.h>
    
    struct date {
    int year, month, day;
    
    friend std::ostream& operator<<(std::ostream& os, const date& d) {
      return os << d.year << '-' << d.month << '-' << d.day;
    }
    };
    
    template <> struct fmt::formatter<date> : ostream_formatter {};
    
    std::string s = fmt::format("The date is {}", date{2012, 12, 9});
    // s == "The date is 2012-12-9"
    
  • Added the fmt::streamed function that takes an object and formats it via std::ostream. For example (godbolt):

    #include <thread>
    #include <fmt/ostream.h>
    
    int main() {
    fmt::print("Current thread id: {}\n",
               fmt::streamed(std::this_thread::get_id()));
    }
    

Note that fmt/std.h provides a formatter specialization for std::thread::id so you don\'t need to format it via std::ostream.

  • Deprecated implicit conversions of unscoped enums to integers for consistency with scoped enums.

  • Added an argument-dependent lookup based format_as extension API to simplify formatting of enums.

  • Added experimental std::variant formatting support (https://github.com/fmtlib/fmt/pull/2941). For example (godbolt):

    #include <variant>
    #include <fmt/std.h>
    
    int main() {
    auto v = std::variant<int, std::string>(42);
    fmt::print("{}\n", v);
    }
    

prints:

  variant(42)

Thanks @jehelset.

prints:

  There is no place like "/home".

Thanks @phprus.

  • Added a std::thread::id formatter to fmt/std.h. For example (godbolt):

    #include <thread>
    #include <fmt/std.h>
    
    int main() {
    fmt::print("Current thread id: {}\n", std::this_thread::get_id());
    }
    
  • Added fmt::styled that applies a text style to an individual argument (https://github.com/fmtlib/fmt/pull/2793). For example (godbolt):

    #include <fmt/chrono.h>
    #include <fmt/color.h>
    
    int main() {
    auto now = std::chrono::system_clock::now();
    fmt::print(
      "[{}] {}: {}\n",
      fmt::styled(now, fmt::emphasis::bold),
      fmt::styled("error", fg(fmt::color::red)),
      "something went wrong");
    }
    

prints

Thanks @rbrugo.

prints [0xa, 0x14, 0x1e].

Thanks @BRevzin.

8.1.1 - 2022-01-06

8.1.0 - 2022-01-02

Processing of some specifiers such as %z and %Y is now up to 10-20 times faster, for example on GCC 11 with libstdc++:

  ----------------------------------------------------------------------------
  Benchmark                                  Before             After
  ----------------------------------------------------------------------------
  FMTFormatter_z                             261 ns             26.3 ns
  FMTFormatterCompile_z                      246 ns             11.6 ns
  FMTFormatter_Y                             263 ns             26.1 ns
  FMTFormatterCompile_Y                      244 ns             10.5 ns
  ----------------------------------------------------------------------------

Thanks @phprus and @toughengineer.

prints \"01.234\".

Thanks @matrackif.

prints \"1,000,000 dollars\".

https://user-images.githubusercontent.com/576385/147710227-c68f5317-f8fa-42c3-9123-7c4ba3c398cb.mp4

Thanks @benit8 and @data-man.

gives a compile-time error on compilers with C++20 consteval and non-type template parameter support (gcc 10+) because s is not a valid format specifier for an integer.

Thanks @alexezeder.

  • Implemented escaping of string range elements. For example (godbolt):

    #include <fmt/ranges.h>
    #include <vector>
    
    int main() {
    fmt::print("{}", std::vector<std::string>{"\naan"});
    }
    

is now printed as:

  ["\naan"]

instead of:

  ["
  aan"]
  • Added an experimental ? specifier for escaping strings. (https://github.com/fmtlib/fmt/pull/2674). Thanks @BRevzin.

  • Switched to JSON-like representation of maps and sets for consistency with Python\'s str.format. For example (godbolt):

    #include <fmt/ranges.h>
    #include <map>
    
    int main() {
    fmt::print("{}", std::map<std::string, int>{{"answer", 42}});
    }
    

is now printed as:

  {"answer": 42}

8.0.1 - 2021-07-02

8.0.0 - 2021-06-21

  • Enabled compile-time format string checks 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");

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

  • 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 (https://github.com/fmtlib/fmt/issues/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.

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.

  • 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 (https://github.com/fmtlib/fmt/pull/2243, https://github.com/fmtlib/fmt/pull/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.

prints \"42\".

Thanks @kamibo.

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 (https://github.com/fmtlib/fmt/issues/2337, https://github.com/fmtlib/fmt/pull/2349, https://github.com/fmtlib/fmt/pull/2350). Thanks @phprus.

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

  • Deprecated an undocumented format_to overload that takes basic_memory_buffer.

  • Made parameter order in vformat_to consistent with format_to (https://github.com/fmtlib/fmt/issues/2327).

  • Added support for time points with arbitrary durations (https://github.com/fmtlib/fmt/issues/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.

prints \"true\". Thanks @powercoderlol.

Thanks @mikecrowe.

Thanks @alexezeder.

prints

on a modern terminal.

  • The experimental fast output stream (fmt::ostream) is now truncated by default for consistency with fopen (https://github.com/fmtlib/fmt/issues/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.

The change log for versions 0.8.0 - 7.1.3 is available here.