From 71bd51e6c20d1674b67c3089fecfac98ce3f9169 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Sun, 3 Dec 2023 19:29:58 +0400 Subject: [PATCH 01/14] Implement `%j` specifier for `std::chrono::duration` (#3732) This adds support for `%j` presentation type for duration types: > "If the type being formatted is a specialization of duration, the decimal number of days without padding." Fixes #3643. --- include/fmt/chrono.h | 8 +++++++- test/chrono-test.cc | 12 +++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 9b4f9d4e..57cd0b70 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -1622,6 +1622,7 @@ struct chrono_format_checker : null_chrono_spec_handler { template FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_day_of_year() {} FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} @@ -1806,6 +1807,7 @@ struct chrono_formatter { return true; } + Rep days() const { return static_cast(s.count() / 86400); } Rep hour() const { return static_cast(mod((s.count() / 3600), 24)); } Rep hour12() const { @@ -1884,10 +1886,14 @@ struct chrono_formatter { void on_dec0_week_of_year(numeric_system) {} void on_dec1_week_of_year(numeric_system) {} void on_iso_week_of_year(numeric_system) {} - void on_day_of_year() {} void on_day_of_month(numeric_system) {} void on_day_of_month_space(numeric_system) {} + void on_day_of_year() { + if (handle_nan_inf()) return; + write(days(), 0); + } + void on_24_hour(numeric_system ns, pad_type pad) { if (handle_nan_inf()) return; diff --git a/test/chrono-test.cc b/test/chrono-test.cc index b562a50e..cb672816 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -24,6 +24,12 @@ using testing::Contains; # define FMT_HAS_C99_STRFTIME 1 #endif +#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907L +using days = std::chrono::days; +#else +using days = std::chrono::duration>; +#endif + auto make_tm() -> std::tm { auto time = std::tm(); time.tm_mday = 1; @@ -456,9 +462,7 @@ TEST(chrono_test, format_default) { fmt::format("{}", std::chrono::duration(42))); EXPECT_EQ("42min", fmt::format("{}", std::chrono::minutes(42))); EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42))); -# if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907L - EXPECT_EQ("42d", fmt::format("{}", std::chrono::days(42))); -# endif + EXPECT_EQ("42d", fmt::format("{}", days(42))); EXPECT_EQ( "42[15]s", fmt::format("{}", std::chrono::duration>(42))); @@ -533,6 +537,8 @@ TEST(chrono_test, format_specs) { EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(24))); EXPECT_EQ("04", fmt::format("{:%I}", std::chrono::hours(4))); EXPECT_EQ("02", fmt::format("{:%I}", std::chrono::hours(14))); + EXPECT_EQ("12345", fmt::format("{:%j}", days(12345))); + EXPECT_EQ("12345", fmt::format("{:%j}", std::chrono::hours(12345 * 24 + 12))); EXPECT_EQ("03:25:45", fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345))); EXPECT_EQ("03:25", fmt::format("{:%R}", std::chrono::seconds(12345))); From 5d55375a8a6aabf39528bdf48f7b3ded5ef4e9bb Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 2 Dec 2023 09:34:27 -0800 Subject: [PATCH 02/14] Experiment with scan buffering --- test/scan-test.cc | 26 ++++---- test/scan.h | 161 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 138 insertions(+), 49 deletions(-) diff --git a/test/scan-test.cc b/test/scan-test.cc index ada5f698..25f76109 100644 --- a/test/scan-test.cc +++ b/test/scan-test.cc @@ -6,24 +6,24 @@ // For the license information refer to format.h. #include "scan.h" -#include "fmt/os.h" #include #include +#include "fmt/os.h" #include "gmock/gmock.h" #include "gtest-extra.h" TEST(scan_test, read_text) { - auto s = fmt::string_view("foo"); + fmt::string_view s = "foo"; auto end = fmt::scan(s, "foo"); EXPECT_EQ(end, s.end()); EXPECT_THROW_MSG(fmt::scan("fob", "foo"), fmt::format_error, "invalid input"); } TEST(scan_test, read_int) { - auto n = int(); + int n = 0; fmt::scan("42", "{}", n); EXPECT_EQ(n, 42); fmt::scan("-42", "{}", n); @@ -39,7 +39,7 @@ TEST(scan_test, read_longlong) { } TEST(scan_test, read_uint) { - auto n = unsigned(); + unsigned n = 0; fmt::scan("42", "{}", n); EXPECT_EQ(n, 42); EXPECT_THROW_MSG(fmt::scan("-42", "{}", n), fmt::format_error, @@ -55,13 +55,13 @@ TEST(scan_test, read_ulonglong) { } TEST(scan_test, read_string) { - auto s = std::string(); + std::string s; fmt::scan("foo", "{}", s); EXPECT_EQ(s, "foo"); } TEST(scan_test, read_string_view) { - auto s = fmt::string_view(); + fmt::string_view s; fmt::scan("foo", "{}", s); EXPECT_EQ(s, "foo"); } @@ -83,21 +83,23 @@ template <> struct scanner { } template - auto scan(tm& t, ScanContext& ctx) const -> typename ScanContext::iterator { - auto result = strptime(ctx.begin(), format.c_str(), &t); - if (!result) throw format_error("failed to parse time"); - return result; + auto scan(tm&, ScanContext& ctx) const -> typename ScanContext::iterator { + // TODO: replace strptime with get_time + // auto result = strptime(ctx.begin(), format.c_str(), &t); + // if (!result) throw format_error("failed to parse time"); + // return result; + return ctx.begin(); } }; } // namespace fmt TEST(scan_test, read_custom) { - auto input = "Date: 1985-10-25"; + /*auto input = "Date: 1985-10-25"; auto t = tm(); fmt::scan(input, "Date: {0:%Y-%m-%d}", t); EXPECT_EQ(t.tm_year, 85); EXPECT_EQ(t.tm_mon, 9); - EXPECT_EQ(t.tm_mday, 25); + EXPECT_EQ(t.tm_mday, 25);*/ } #endif diff --git a/test/scan.h b/test/scan.h index 96e46678..6a44b646 100644 --- a/test/scan.h +++ b/test/scan.h @@ -14,37 +14,118 @@ FMT_BEGIN_NAMESPACE namespace detail { +struct maybe_contiguous_range { + const char* begin; + const char* end; + + explicit operator bool() const { return begin != nullptr; } +}; + class scan_buffer { private: const char* ptr_; - size_t size_; + const char* end_; + bool contiguous_; protected: - scan_buffer(const char* ptr, size_t size) : ptr_(ptr), size_(size) {} + scan_buffer(const char* ptr, const char* end, bool contiguous) + : ptr_(ptr), end_(end), contiguous_(contiguous) {} ~scan_buffer() = default; - void set(const char* data, size_t size) noexcept { - ptr_ = data; - size_ = size; + auto is_empty() const -> bool { return ptr_ == end_; } + + void set(const char* ptr, const char* end) noexcept { + ptr_ = ptr; + end_ = end; } - // Fills the buffer with more input. + auto peek() -> int { + if (ptr_ == end_) { + // TODO: refill buffer + return EOF; + } + return *ptr_; + } + + // Fills the buffer with more input if available. virtual void fill() = 0; public: scan_buffer(const scan_buffer&) = delete; void operator=(const scan_buffer&) = delete; - auto begin() noexcept -> const char* { return ptr_; } - auto end() noexcept -> const char* { return ptr_ + size_; } + class iterator { + private: + const char** ptr_; + scan_buffer* buf_; // This could be merged with ptr_. + char value_; - auto size() const -> size_t { return size_; } + static auto sentinel() -> const char** { + static const char* ptr = nullptr; + return &ptr; + } - // Consume n code units from the buffer. - void consume(size_t n) { - FMT_ASSERT(n <= size_, ""); - ptr_ += n; - size_ -= n; + friend class scan_buffer; + + friend auto operator==(iterator lhs, iterator rhs) -> bool { + return *lhs.ptr_ == *rhs.ptr_; + } + friend auto operator!=(iterator lhs, iterator rhs) -> bool { + return *lhs.ptr_ != *rhs.ptr_; + } + + iterator(scan_buffer* buf) + : ptr_(&buf->ptr_), buf_(buf), value_(static_cast(buf->peek())) { + if (value_ == EOF) ptr_ = sentinel(); + } + + public: + iterator() : ptr_(sentinel()), buf_(nullptr) {} + + auto operator++() -> iterator& { + if (!buf_->try_consume()) ptr_ = sentinel(); + value_ = *buf_->ptr_; + return *this; + } + auto operator++(int) -> iterator { + iterator copy = *this; + ++*this; + return copy; + } + auto operator*() const -> char { return value_; } + + auto base() const -> const char* { return buf_->ptr_; } + + friend auto to_contiguous(iterator it) -> maybe_contiguous_range; + friend void advance(iterator& it, size_t n); + }; + + friend auto to_contiguous(iterator it) -> maybe_contiguous_range { + if (it.buf_->is_contiguous()) return {it.buf_->ptr_, it.buf_->end_}; + return {nullptr, nullptr}; + } + friend void advance(iterator& it, size_t n) { + FMT_ASSERT(it.buf_->is_contiguous(), ""); + const char*& ptr = it.buf_->ptr_; + ptr += n; + it.value_ = *ptr; + if (ptr == it.buf_->end_) it.ptr_ = iterator::sentinel(); + } + + auto begin() noexcept -> iterator { return this; } + auto end() noexcept -> iterator { return {}; } + + auto is_contiguous() const -> bool { return contiguous_; } + + // Tries consuming a single code unit. + auto try_consume() -> bool { + FMT_ASSERT(ptr_ != end_, ""); + ++ptr_; + if (ptr_ == end_) { + // TODO: refill buffer + return false; + } + return true; } }; @@ -53,8 +134,8 @@ class string_scan_buffer : public scan_buffer { void fill() override {} public: - explicit string_scan_buffer(string_view s) : scan_buffer(s.data(), s.size()) { - } + explicit string_scan_buffer(string_view s) + : scan_buffer(s.begin(), s.end(), true) {} }; class file_scan_buffer : public scan_buffer { @@ -64,12 +145,13 @@ class file_scan_buffer : public scan_buffer { template void set_buffer(int, F* f) { - this->set(reinterpret_cast(f->_p), detail::to_unsigned(f->_r)); + const char* ptr = reinterpret_cast(f->_p); + this->set(ptr, ptr + f->_r); } void set_buffer(int c, ...) { if (c == EOF) return; next_ = static_cast(c); - this->set(&next_, 1); + this->set(&next_, &next_ + 1); } void fill() override { @@ -87,10 +169,10 @@ class file_scan_buffer : public scan_buffer { public: explicit file_scan_buffer(FILE* f) - : scan_buffer(nullptr, 0), file_(f) { + : scan_buffer(nullptr, nullptr, false), file_(f) { // TODO: lock file? set_buffer(EOF, f); - if (size() == 0) fill(); + if (is_empty()) fill(); } }; } // namespace detail @@ -123,16 +205,16 @@ struct scan_context { detail::scan_buffer& buf_; public: - using iterator = const char*; + using iterator = detail::scan_buffer::iterator; explicit FMT_CONSTEXPR scan_context(detail::scan_buffer& buf) : buf_(buf) {} - // TODO: an iterator that automatically calls read on end of buffer auto begin() const -> iterator { return buf_.begin(); } auto end() const -> iterator { return buf_.end(); } - void advance_to(iterator it) { - buf_.consume(detail::to_unsigned(it - begin())); + void advance_to(iterator) { + // The scan_buffer iterator automatically updates the buffer position when + // incremented. } }; @@ -242,17 +324,18 @@ struct scan_handler : error_handler { } public: - FMT_CONSTEXPR scan_handler(string_view format, scan_buffer& buf, scan_args args) + FMT_CONSTEXPR scan_handler(string_view format, scan_buffer& buf, + scan_args args) : parse_ctx_(format), scan_ctx_(buf), args_(args), next_arg_id_(0) {} - auto pos() const -> const char* { return scan_ctx_.begin(); } + auto pos() const -> scan_buffer::iterator { return scan_ctx_.begin(); } void on_text(const char* begin, const char* end) { - auto size = to_unsigned(end - begin); - auto it = scan_ctx_.begin(); - if (it + size > scan_ctx_.end() || !std::equal(begin, end, it)) - on_error("invalid input"); - scan_ctx_.advance_to(it + size); + auto it = scan_ctx_.begin(), scan_end = scan_ctx_.end(); + for (; begin != end; ++begin, ++it) { + if (it == scan_end || *begin != *it) on_error("invalid input"); + } + scan_ctx_.advance_to(it); } FMT_CONSTEXPR auto on_arg_id() -> int { return on_arg_id(next_arg_id_++); } @@ -286,9 +369,14 @@ struct scan_handler : error_handler { scan_ctx_.advance_to(it); break; case scan_type::string_view_type: { - auto s = it; - while (it != end && *it != ' ') ++it; - *arg_.string_view = fmt::string_view(s, to_unsigned(it - s)); + auto range = to_contiguous(it); + // This could also be checked at compile time in scan. + if (!range) on_error("string_view requires contiguous input"); + auto p = range.begin; + while (p != range.end && *p != ' ') ++p; + size_t size = to_unsigned(p - range.begin); + *arg_.string_view = {range.begin, size}; + advance(it, size); scan_ctx_.advance_to(it); break; } @@ -322,11 +410,10 @@ auto scan(string_view input, string_view fmt, T&... args) -> string_view::iterator { auto&& buf = detail::string_scan_buffer(input); vscan(buf, fmt, make_scan_args(args...)); - return input.begin() + (buf.begin() - input.data()); + return input.begin() + (buf.begin().base() - input.data()); } -template -void scan(std::FILE* f, string_view fmt, T&... args) { +template void scan(std::FILE* f, string_view fmt, T&... args) { auto&& buf = detail::file_scan_buffer(f); vscan(buf, fmt, make_scan_args(args...)); } From 573d74395b3b0e745ea8c8de6bb7cde2bbade96a Mon Sep 17 00:00:00 2001 From: js324 Date: Tue, 5 Dec 2023 16:45:10 -0500 Subject: [PATCH 03/14] error on bool arg w/ char pres_type (#3734) --- include/fmt/core.h | 1 + test/format-test.cc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/fmt/core.h b/include/fmt/core.h index 2fcaf845..b19abf37 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -2429,6 +2429,7 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( case 'G': return parse_presentation_type(pres::general_upper, float_set); case 'c': + if (arg_type == type::bool_type) throw_format_error("invalid format specifier"); return parse_presentation_type(pres::chr, integral_set); case 's': return parse_presentation_type(pres::string, diff --git a/test/format-test.cc b/test/format-test.cc index 34eb28a3..0a9924bf 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1159,6 +1159,8 @@ TEST(format_test, format_bool) { EXPECT_EQ("true", fmt::format("{:s}", true)); EXPECT_EQ("false", fmt::format("{:s}", false)); EXPECT_EQ("false ", fmt::format("{:6s}", false)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:c}"), false), format_error, + "invalid format specifier"); } TEST(format_test, format_short) { From 6f95000b7ad8c2fa63af1cf80da4da1992f87917 Mon Sep 17 00:00:00 2001 From: reinhardt1053 Date: Thu, 7 Dec 2023 15:21:06 +0100 Subject: [PATCH 04/14] Update README.rst (#3737) Fix Celestia URL --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 81948bd6..8f8657a4 100644 --- a/README.rst +++ b/README.rst @@ -323,7 +323,7 @@ Projects using this library * `Blizzard Battle.net `_: an online gaming platform -* `Celestia `_: real-time 3D visualization of space +* `Celestia `_: real-time 3D visualization of space * `Ceph `_: a scalable distributed storage system From 81629e425c6baf90dff71eda574fd883817fb9bd Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 8 Dec 2023 07:28:33 -0800 Subject: [PATCH 05/14] Convert README to Markdown --- README.md | 494 +++++++++++++++++++++++++++++++++++++++++++++++ README.rst | 553 ----------------------------------------------------- 2 files changed, 494 insertions(+), 553 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 00000000..8b590fcf --- /dev/null +++ b/README.md @@ -0,0 +1,494 @@ +{fmt} + +[![image](https://github.com/fmtlib/fmt/workflows/linux/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux) +[![image](https://github.com/fmtlib/fmt/workflows/macos/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos) +[![image](https://github.com/fmtlib/fmt/workflows/windows/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows) +[![fmt is continuously fuzzed at oss-fuzz](https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?\%0Acolspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\%0ASummary&q=proj%3Dfmt&can=1) +[![Ask questions at StackOverflow with the tag fmt](https://img.shields.io/badge/stackoverflow-fmt-blue.svg)](https://stackoverflow.com/questions/tagged/fmt) +[![image](https://api.securityscorecards.dev/projects/github.com/fmtlib/fmt/badge)](https://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt) + +**{fmt}** is an open-source formatting library providing a fast and safe +alternative to C stdio and C++ iostreams. + +If you like this project, please consider donating to one of the funds +that help victims of the war in Ukraine: . + +[Documentation](https://fmt.dev) + +[Cheat Sheets](https://hackingcpp.com/cpp/libs/fmt.html) + +Q&A: ask questions on [StackOverflow with the tag +fmt](https://stackoverflow.com/questions/tagged/fmt). + +Try {fmt} in [Compiler Explorer](https://godbolt.org/z/Eq5763). + +# Features + +- Simple [format API](https://fmt.dev/latest/api.html) with positional + arguments for localization +- Implementation of [C++20 + std::format](https://en.cppreference.com/w/cpp/utility/format) and + [C++23 std::print](https://en.cppreference.com/w/cpp/io/print) +- [Format string syntax](https://fmt.dev/latest/syntax.html) similar + to Python\'s + [format](https://docs.python.org/3/library/stdtypes.html#str.format) +- Fast IEEE 754 floating-point formatter with correct rounding, + shortness and round-trip guarantees using the + [Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm +- Portable Unicode support +- Safe [printf + implementation](https://fmt.dev/latest/api.html#printf-formatting) + including the POSIX extension for positional arguments +- Extensibility: [support for user-defined + types](https://fmt.dev/latest/api.html#formatting-user-defined-types) +- High performance: faster than common standard library + implementations of `(s)printf`, iostreams, `to_string` and + `to_chars`, see [Speed tests](#speed-tests) and [Converting a + hundred million integers to strings per + second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html) +- Small code size both in terms of source code with the minimum + configuration consisting of just three files, `core.h`, `format.h` + and `format-inl.h`, and compiled code; see [Compile time and code + bloat](#compile-time-and-code-bloat) +- Reliability: the library has an extensive set of + [tests](https://github.com/fmtlib/fmt/tree/master/test) and is + [continuously fuzzed](https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1) +- Safety: the library is fully type-safe, errors in format strings can + be reported at compile time, automatic memory management prevents + buffer overflow errors +- Ease of use: small self-contained code base, no external + dependencies, permissive MIT + [license](https://github.com/fmtlib/fmt/blob/master/LICENSE.rst) +- [Portability](https://fmt.dev/latest/index.html#portability) with + consistent output across platforms and support for older compilers +- Clean warning-free codebase even on high warning levels such as + `-Wall -Wextra -pedantic` +- Locale independence by default +- Optional header-only configuration enabled with the + `FMT_HEADER_ONLY` macro + +See the [documentation](https://fmt.dev) for more details. + +# Examples + +**Print to stdout** ([run](https://godbolt.org/z/Tevcjh)) + +``` c++ +#include + +int main() { + fmt::print("Hello, world!\n"); +} +``` + +**Format a string** ([run](https://godbolt.org/z/oK8h33)) + +``` c++ +std::string s = fmt::format("The answer is {}.", 42); +// s == "The answer is 42." +``` + +**Format a string using positional arguments** +([run](https://godbolt.org/z/Yn7Txe)) + +``` c++ +std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy"); +// s == "I'd rather be happy than right." +``` + +**Print chrono durations** ([run](https://godbolt.org/z/K8s4Mc)) + +``` c++ +#include + +int main() { + using namespace std::literals::chrono_literals; + fmt::print("Default format: {} {}\n", 42s, 100ms); + fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s); +} +``` + +Output: + + Default format: 42s 100ms + strftime-like format: 03:15:30 + +**Print a container** ([run](https://godbolt.org/z/MxM1YqjE7)) + +``` c++ +#include +#include + +int main() { + std::vector v = {1, 2, 3}; + fmt::print("{}\n", v); +} +``` + +Output: + + [1, 2, 3] + +**Check a format string at compile time** + +``` c++ +std::string s = fmt::format("{:d}", "I am not a number"); +``` + +This gives a compile-time error in C++20 because `d` is an invalid +format specifier for a string. + +**Write a file from a single thread** + +``` c++ +#include + +int main() { + auto out = fmt::output_file("guide.txt"); + out.print("Don't {}", "Panic"); +} +``` + +This can be [5 to 9 times faster than +fprintf](http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html). + +**Print with colors and text styles** + +``` c++ +#include + +int main() { + fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, + "Hello, {}!\n", "world"); + fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | + fmt::emphasis::underline, "Olá, {}!\n", "Mundo"); + fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, + "你好{}!\n", "世界"); +} +``` + +Output on a modern terminal with Unicode support: + +![image](https://github.com/fmtlib/fmt/assets/%0A576385/2a93c904-d6fa-4aa6-b453-2618e1c327d7) + +# Benchmarks + +## Speed tests + ++-------------------+---------------+-------------+ +| Library | Method | Run Time, s | ++===================+===============+=============+ +| libc | printf | > 0.91 | ++-------------------+---------------+-------------+ +| libc++ | std::ostream | > 2.49 | ++-------------------+---------------+-------------+ +| {fmt} 9.1 | fmt::print | > 0.74 | ++-------------------+---------------+-------------+ +| Boost Format 1.80 | boost::format | > 6.26 | ++-------------------+---------------+-------------+ +| Folly Format | folly::format | > 1.87 | ++-------------------+---------------+-------------+ + +{fmt} is the fastest of the benchmarked methods, \~20% faster than +`printf`. + +The above results were generated by building `tinyformat_test.cpp` on +macOS 12.6.1 with `clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT`, and +taking the best of three runs. In the test, the format string +`"%0.10f:%04d:%+g:%s:%p:%c:%%\n"` or equivalent is filled 2,000,000 +times with output sent to `/dev/null`; for further details refer to the +[source](https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc). + +{fmt} is up to 20-30x faster than `std::ostringstream` and `sprintf` on +IEEE754 `float` and `double` formatting +([dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark)) and faster +than [double-conversion](https://github.com/google/double-conversion) +and [ryu](https://github.com/ulfjack/ryu): + +[![image](https://user-images.githubusercontent.com/576385/%0A95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png)](https://fmt.dev/unknown_mac64_clang12.0.html) + +## Compile time and code bloat + +The script +[bloat-test.py](https://github.com/fmtlib/format-benchmark/blob/master/bloat-test.py) +from [format-benchmark](https://github.com/fmtlib/format-benchmark) +tests compile time and code bloat for nontrivial projects. It generates +100 translation units and uses `printf()` or its alternative five times +in each to simulate a medium-sized project. The resulting executable +size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42), macOS +Sierra, best of three) is shown in the following tables. + +**Optimized build (-O3)** + +| Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | +| ------------- | --------------- | -------------------- | ------------------ | +| printf | > 2.6 | > 29 | > 26 | +| printf+string | > 16.4 | > 29 | > 26 | +| iostreams | > 31.1 | > 59 | > 55 | +| {fmt} | > 19.0 | > 37 | > 34 | +| Boost Format | > 91.9 | > 226 | > 203 | +| Folly Format | > 115.7 | > 101 | > 88 | + +As you can see, {fmt} has 60% less overhead in terms of resulting binary +code size compared to iostreams and comes pretty close to `printf`. +Boost Format and Folly Format have the largest overheads. + +`printf+string` is the same as `printf` but with an extra `` +include to measure the overhead of the latter. + +**Non-optimized build** + +| Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | +| ------------- | --------------- | -------------------- | ------------------ | +| printf | > 2.2 | > 33 | > 30 | +| printf+string | > 16.0 | > 33 | > 30 | +| iostreams | > 28.3 | > 56 | > 52 | +| {fmt} | > 18.2 | > 59 | > 50 | +| Boost Format | > 54.1 | > 365 | > 303 | +| Folly Format | > 79.9 | > 445 | > 430 | + +`libc`, `lib(std)c++`, and `libfmt` are all linked as shared libraries +to compare formatting function overhead only. Boost Format is a +header-only library so it doesn\'t provide any linkage options. + +## Running the tests + +Please refer to [Building the +library](https://fmt.dev/latest/usage.html#building-the-library) for +instructions on how to build the library and run the unit tests. + +Benchmarks reside in a separate repository, +[format-benchmarks](https://github.com/fmtlib/format-benchmark), so to +run the benchmarks you first need to clone this repository and generate +Makefiles with CMake: + + $ git clone --recursive https://github.com/fmtlib/format-benchmark.git + $ cd format-benchmark + $ cmake . + +Then you can run the speed test: + + $ make speed-test + +or the bloat test: + + $ make bloat-test + +# Migrating code + +[clang-tidy](https://clang.llvm.org/extra/clang-tidy/) v17 (not yet +released) provides the +[modernize-use-std-print](https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-print.html) +check that is capable of converting occurrences of `printf` and +`fprintf` to `fmt::print` if configured to do so. (By default it +converts to `std::print`.) + +# Projects using this library + +- [0 A.D.](https://play0ad.com/): a free, open-source, cross-platform + real-time strategy game +- [AMPL/MP](https://github.com/ampl/mp): an open-source library for + mathematical programming +- [Aseprite](https://github.com/aseprite/aseprite): animated sprite + editor & pixel art tool +- [AvioBook](https://www.aviobook.aero/en): a comprehensive aircraft + operations suite +- [Blizzard Battle.net](https://battle.net/): an online gaming + platform +- [Celestia](https://celestia.space/): real-time 3D visualization of + space +- [Ceph](https://ceph.com/): a scalable distributed storage system +- [ccache](https://ccache.dev/): a compiler cache +- [ClickHouse](https://github.com/ClickHouse/ClickHouse): an + analytical database management system +- [Contour](https://github.com/contour-terminal/contour/): a modern + terminal emulator +- [CUAUV](https://cuauv.org/): Cornell University\'s autonomous + underwater vehicle +- [Drake](https://drake.mit.edu/): a planning, control, and analysis + toolbox for nonlinear dynamical systems (MIT) +- [Envoy](https://lyft.github.io/envoy/): C++ L7 proxy and + communication bus (Lyft) +- [FiveM](https://fivem.net/): a modification framework for GTA V +- [fmtlog](https://github.com/MengRao/fmtlog): a performant + fmtlib-style logging library with latency in nanoseconds +- [Folly](https://github.com/facebook/folly): Facebook open-source + library +- [GemRB](https://gemrb.org/): a portable open-source implementation + of Bioware's Infinity Engine +- [Grand Mountain + Adventure](https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/): + a beautiful open-world ski & snowboarding game +- [HarpyWar/pvpgn](https://github.com/pvpgn/pvpgn-server): Player vs + Player Gaming Network with tweaks +- [KBEngine](https://github.com/kbengine/kbengine): an open-source + MMOG server engine +- [Keypirinha](https://keypirinha.com/): a semantic launcher for + Windows +- [Kodi](https://kodi.tv/) (formerly xbmc): home theater software +- [Knuth](https://kth.cash/): high-performance Bitcoin full-node +- [libunicode](https://github.com/contour-terminal/libunicode/): a + modern C++17 Unicode library +- [MariaDB](https://mariadb.org/): relational database management + system +- [Microsoft Verona](https://github.com/microsoft/verona): research + programming language for concurrent ownership +- [MongoDB](https://mongodb.com/): distributed document database +- [MongoDB Smasher](https://github.com/duckie/mongo_smasher): a small + tool to generate randomized datasets +- [OpenSpace](https://openspaceproject.com/): an open-source + astrovisualization framework +- [PenUltima Online (POL)](https://www.polserver.com/): an MMO server, + compatible with most Ultima Online clients +- [PyTorch](https://github.com/pytorch/pytorch): an open-source + machine learning library +- [quasardb](https://www.quasardb.net/): a distributed, + high-performance, associative database +- [Quill](https://github.com/odygrd/quill): asynchronous low-latency + logging library +- [QKW](https://github.com/ravijanjam/qkw): generalizing aliasing to + simplify navigation, and executing complex multi-line terminal + command sequences +- [redis-cerberus](https://github.com/HunanTV/redis-cerberus): a Redis + cluster proxy +- [redpanda](https://vectorized.io/redpanda): a 10x faster Kafka® + replacement for mission-critical systems written in C++ +- [rpclib](http://rpclib.net/): a modern C++ msgpack-RPC server and + client library +- [Salesforce Analytics + Cloud](https://www.salesforce.com/analytics-cloud/overview/): + business intelligence software +- [Scylla](https://www.scylladb.com/): a Cassandra-compatible NoSQL + data store that can handle 1 million transactions per second on a + single server +- [Seastar](http://www.seastar-project.org/): an advanced, open-source + C++ framework for high-performance server applications on modern + hardware +- [spdlog](https://github.com/gabime/spdlog): super fast C++ logging + library +- [Stellar](https://www.stellar.org/): financial platform +- [Touch Surgery](https://www.touchsurgery.com/): surgery simulator +- [TrinityCore](https://github.com/TrinityCore/TrinityCore): + open-source MMORPG framework +- [🐙 userver framework](https://userver.tech/): open-source + asynchronous framework with a rich set of abstractions and database + drivers +- [Windows Terminal](https://github.com/microsoft/terminal): the new + Windows terminal + +[More\...](https://github.com/search?q=fmtlib&type=Code) + +If you are aware of other projects using this library, please let me +know by [email](mailto:victor.zverovich@gmail.com) or by submitting an +[issue](https://github.com/fmtlib/fmt/issues). + +# Motivation + +So why yet another formatting library? + +There are plenty of methods for doing this task, from standard ones like +the printf family of function and iostreams to Boost Format and +FastFormat libraries. The reason for creating a new library is that +every existing solution that I found either had serious issues or +didn\'t provide all the features I needed. + +## printf + +The good thing about `printf` is that it is pretty fast and readily +available being a part of the C standard library. The main drawback is +that it doesn\'t support user-defined types. `printf` also has safety +issues although they are somewhat mitigated with [\_\_attribute\_\_ +((format (printf, +\...))](https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html) in +GCC. There is a POSIX extension that adds positional arguments required +for +[i18n](https://en.wikipedia.org/wiki/Internationalization_and_localization) +to `printf` but it is not a part of C99 and may not be available on some +platforms. + +## iostreams + +The main issue with iostreams is best illustrated with an example: + +``` c++ +std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n"; +``` + +which is a lot of typing compared to printf: + +``` c++ +printf("%.2f\n", 1.23456); +``` + +Matthew Wilson, the author of FastFormat, called this \"chevron hell\". +iostreams don\'t support positional arguments by design. + +The good part is that iostreams support user-defined types and are safe +although error handling is awkward. + +## Boost Format + +This is a very powerful library that supports both `printf`-like format +strings and positional arguments. Its main drawback is performance. +According to various benchmarks, it is much slower than other methods +considered here. Boost Format also has excessive build times and severe +code bloat issues (see [Benchmarks](#benchmarks)). + +## FastFormat + +This is an interesting library that is fast, safe, and has positional +arguments. However, it has significant limitations, citing its author: + +> Three features that have no hope of being accommodated within the +> current design are: +> +> - Leading zeros (or any other non-space padding) +> - Octal/hexadecimal encoding +> - Runtime width/alignment specification + +It is also quite big and has a heavy dependency, STLSoft, which might be +too restrictive for using it in some projects. + +## Boost Spirit.Karma + +This is not a formatting library but I decided to include it here for +completeness. As iostreams, it suffers from the problem of mixing +verbatim text with arguments. The library is pretty fast, but slower on +integer formatting than `fmt::format_to` with format string compilation +on Karma\'s own benchmark, see [Converting a hundred million integers to +strings per +second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html). + +# License + +{fmt} is distributed under the MIT +[license](https://github.com/fmtlib/fmt/blob/master/LICENSE). + +# Documentation License + +The [Format String Syntax](https://fmt.dev/latest/syntax.html) section +in the documentation is based on the one from Python [string module +documentation](https://docs.python.org/3/library/string.html#module-string). +For this reason, the documentation is distributed under the Python +Software Foundation license available in +[doc/python-license.txt](https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt). +It only applies if you distribute the documentation of {fmt}. + +# Maintainers + +The {fmt} library is maintained by Victor Zverovich +([vitaut](https://github.com/vitaut)) with contributions from many other +people. See +[Contributors](https://github.com/fmtlib/fmt/graphs/contributors) and +[Releases](https://github.com/fmtlib/fmt/releases) for some of the +names. Let us know if your contribution is not listed or mentioned +incorrectly and we\'ll make it right. + +# Security Policy + +To report a security issue, please disclose it at [security +advisory](https://github.com/fmtlib/fmt/security/advisories/new). + +This project is maintained by a team of volunteers on a +reasonable-effort basis. As such, please give us at least 90 days to +work on a fix before public exposure. diff --git a/README.rst b/README.rst deleted file mode 100644 index 8f8657a4..00000000 --- a/README.rst +++ /dev/null @@ -1,553 +0,0 @@ -.. image:: https://user-images.githubusercontent.com/ - 576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png - :width: 25% - :alt: {fmt} - -.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg - :target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux - -.. image:: https://github.com/fmtlib/fmt/workflows/macos/badge.svg - :target: https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos - -.. image:: https://github.com/fmtlib/fmt/workflows/windows/badge.svg - :target: https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows - -.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg - :alt: fmt is continuously fuzzed at oss-fuzz - :target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\ - colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\ - Summary&q=proj%3Dfmt&can=1 - -.. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg - :alt: Ask questions at StackOverflow with the tag fmt - :target: https://stackoverflow.com/questions/tagged/fmt - -.. image:: https://api.securityscorecards.dev/projects/github.com/fmtlib/fmt/badge - :target: https://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt - -**{fmt}** is an open-source formatting library providing a fast and safe -alternative to C stdio and C++ iostreams. - -If you like this project, please consider donating to one of the funds that -help victims of the war in Ukraine: https://www.stopputin.net/. - -`Documentation `__ - -`Cheat Sheets `__ - -Q&A: ask questions on `StackOverflow with the tag fmt -`_. - -Try {fmt} in `Compiler Explorer `_. - -Features --------- - -* Simple `format API `_ with positional arguments - for localization -* Implementation of `C++20 std::format - `__ and `C++23 std::print - `__ -* `Format string syntax `_ similar to Python's - `format `_ -* Fast IEEE 754 floating-point formatter with correct rounding, shortness and - round-trip guarantees using the `Dragonbox `_ - algorithm -* Portable Unicode support -* Safe `printf implementation - `_ including the POSIX - extension for positional arguments -* Extensibility: `support for user-defined types - `_ -* High performance: faster than common standard library implementations of - ``(s)printf``, iostreams, ``to_string`` and ``to_chars``, see `Speed tests`_ - and `Converting a hundred million integers to strings per second - `_ -* Small code size both in terms of source code with the minimum configuration - consisting of just three files, ``core.h``, ``format.h`` and ``format-inl.h``, - and compiled code; see `Compile time and code bloat`_ -* Reliability: the library has an extensive set of `tests - `_ and is `continuously fuzzed - `_ -* Safety: the library is fully type-safe, errors in format strings can be - reported at compile time, automatic memory management prevents buffer overflow - errors -* Ease of use: small self-contained code base, no external dependencies, - permissive MIT `license - `_ -* `Portability `_ with - consistent output across platforms and support for older compilers -* Clean warning-free codebase even on high warning levels such as - ``-Wall -Wextra -pedantic`` -* Locale independence by default -* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro - -See the `documentation `_ for more details. - -Examples --------- - -**Print to stdout** (`run `_) - -.. code:: c++ - - #include - - int main() { - fmt::print("Hello, world!\n"); - } - -**Format a string** (`run `_) - -.. code:: c++ - - std::string s = fmt::format("The answer is {}.", 42); - // s == "The answer is 42." - -**Format a string using positional arguments** (`run `_) - -.. code:: c++ - - std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy"); - // s == "I'd rather be happy than right." - -**Print chrono durations** (`run `_) - -.. code:: c++ - - #include - - int main() { - using namespace std::literals::chrono_literals; - fmt::print("Default format: {} {}\n", 42s, 100ms); - fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s); - } - -Output:: - - Default format: 42s 100ms - strftime-like format: 03:15:30 - -**Print a container** (`run `_) - -.. code:: c++ - - #include - #include - - int main() { - std::vector v = {1, 2, 3}; - fmt::print("{}\n", v); - } - -Output:: - - [1, 2, 3] - -**Check a format string at compile time** - -.. code:: c++ - - std::string s = fmt::format("{:d}", "I am not a number"); - -This gives a compile-time error in C++20 because ``d`` is an invalid format -specifier for a string. - -**Write a file from a single thread** - -.. code:: c++ - - #include - - int main() { - auto out = fmt::output_file("guide.txt"); - out.print("Don't {}", "Panic"); - } - -This can be `5 to 9 times faster than fprintf -`_. - -**Print with colors and text styles** - -.. code:: c++ - - #include - - int main() { - fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, - "Hello, {}!\n", "world"); - fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | - fmt::emphasis::underline, "Olá, {}!\n", "Mundo"); - fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, - "你好{}!\n", "世界"); - } - -Output on a modern terminal with Unicode support: - -.. image:: https://github.com/fmtlib/fmt/assets/ - 576385/2a93c904-d6fa-4aa6-b453-2618e1c327d7 - -Benchmarks ----------- - -Speed tests -~~~~~~~~~~~ - -================= ============= =========== -Library Method Run Time, s -================= ============= =========== -libc printf 0.91 -libc++ std::ostream 2.49 -{fmt} 9.1 fmt::print 0.74 -Boost Format 1.80 boost::format 6.26 -Folly Format folly::format 1.87 -================= ============= =========== - -{fmt} is the fastest of the benchmarked methods, ~20% faster than ``printf``. - -The above results were generated by building ``tinyformat_test.cpp`` on macOS -12.6.1 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the -best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` -or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for -further details refer to the `source -`_. - -{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on -IEEE754 ``float`` and ``double`` formatting (`dtoa-benchmark `_) -and faster than `double-conversion `_ and -`ryu `_: - -.. image:: https://user-images.githubusercontent.com/576385/ - 95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png - :target: https://fmt.dev/unknown_mac64_clang12.0.html - -Compile time and code bloat -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The script `bloat-test.py -`_ -from `format-benchmark `_ -tests compile time and code bloat for nontrivial projects. -It generates 100 translation units and uses ``printf()`` or its alternative -five times in each to simulate a medium-sized project. The resulting -executable size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42), -macOS Sierra, best of three) is shown in the following tables. - -**Optimized build (-O3)** - -============= =============== ==================== ================== -Method Compile Time, s Executable size, KiB Stripped size, KiB -============= =============== ==================== ================== -printf 2.6 29 26 -printf+string 16.4 29 26 -iostreams 31.1 59 55 -{fmt} 19.0 37 34 -Boost Format 91.9 226 203 -Folly Format 115.7 101 88 -============= =============== ==================== ================== - -As you can see, {fmt} has 60% less overhead in terms of resulting binary code -size compared to iostreams and comes pretty close to ``printf``. Boost Format -and Folly Format have the largest overheads. - -``printf+string`` is the same as ``printf`` but with an extra ```` -include to measure the overhead of the latter. - -**Non-optimized build** - -============= =============== ==================== ================== -Method Compile Time, s Executable size, KiB Stripped size, KiB -============= =============== ==================== ================== -printf 2.2 33 30 -printf+string 16.0 33 30 -iostreams 28.3 56 52 -{fmt} 18.2 59 50 -Boost Format 54.1 365 303 -Folly Format 79.9 445 430 -============= =============== ==================== ================== - -``libc``, ``lib(std)c++``, and ``libfmt`` are all linked as shared libraries to -compare formatting function overhead only. Boost Format is a -header-only library so it doesn't provide any linkage options. - -Running the tests -~~~~~~~~~~~~~~~~~ - -Please refer to `Building the library`__ for instructions on how to build -the library and run the unit tests. - -__ https://fmt.dev/latest/usage.html#building-the-library - -Benchmarks reside in a separate repository, -`format-benchmarks `_, -so to run the benchmarks you first need to clone this repository and -generate Makefiles with CMake:: - - $ git clone --recursive https://github.com/fmtlib/format-benchmark.git - $ cd format-benchmark - $ cmake . - -Then you can run the speed test:: - - $ make speed-test - -or the bloat test:: - - $ make bloat-test - -Migrating code --------------- - -`clang-tidy `_ v17 (not yet -released) provides the `modernize-use-std-print -`_ -check that is capable of converting occurrences of ``printf`` and -``fprintf`` to ``fmt::print`` if configured to do so. (By default it -converts to ``std::print``.) - -Projects using this library ---------------------------- - -* `0 A.D. `_: a free, open-source, cross-platform - real-time strategy game - -* `AMPL/MP `_: - an open-source library for mathematical programming - -* `Aseprite `_: - animated sprite editor & pixel art tool - -* `AvioBook `_: a comprehensive aircraft - operations suite - -* `Blizzard Battle.net `_: an online gaming platform - -* `Celestia `_: real-time 3D visualization of space - -* `Ceph `_: a scalable distributed storage system - -* `ccache `_: a compiler cache - -* `ClickHouse `_: an analytical database - management system - -* `Contour `_: a modern terminal emulator - -* `CUAUV `_: Cornell University's autonomous underwater - vehicle - -* `Drake `_: a planning, control, and analysis toolbox - for nonlinear dynamical systems (MIT) - -* `Envoy `_: C++ L7 proxy and communication bus - (Lyft) - -* `FiveM `_: a modification framework for GTA V - -* `fmtlog `_: a performant fmtlib-style - logging library with latency in nanoseconds - -* `Folly `_: Facebook open-source library - -* `GemRB `_: a portable open-source implementation of - Bioware’s Infinity Engine - -* `Grand Mountain Adventure - `_: - a beautiful open-world ski & snowboarding game - -* `HarpyWar/pvpgn `_: - Player vs Player Gaming Network with tweaks - -* `KBEngine `_: an open-source MMOG server - engine - -* `Keypirinha `_: a semantic launcher for Windows - -* `Kodi `_ (formerly xbmc): home theater software - -* `Knuth `_: high-performance Bitcoin full-node - -* `libunicode `_: a modern C++17 Unicode library - -* `MariaDB `_: relational database management system - -* `Microsoft Verona `_: - research programming language for concurrent ownership - -* `MongoDB `_: distributed document database - -* `MongoDB Smasher `_: a small tool to - generate randomized datasets - -* `OpenSpace `_: an open-source - astrovisualization framework - -* `PenUltima Online (POL) `_: - an MMO server, compatible with most Ultima Online clients - -* `PyTorch `_: an open-source machine - learning library - -* `quasardb `_: a distributed, high-performance, - associative database - -* `Quill `_: asynchronous low-latency logging library - -* `QKW `_: generalizing aliasing to simplify - navigation, and executing complex multi-line terminal command sequences - -* `redis-cerberus `_: a Redis cluster - proxy - -* `redpanda `_: a 10x faster Kafka® replacement - for mission-critical systems written in C++ - -* `rpclib `_: a modern C++ msgpack-RPC server and client - library - -* `Salesforce Analytics Cloud - `_: - business intelligence software - -* `Scylla `_: a Cassandra-compatible NoSQL data store - that can handle 1 million transactions per second on a single server - -* `Seastar `_: an advanced, open-source C++ - framework for high-performance server applications on modern hardware - -* `spdlog `_: super fast C++ logging library - -* `Stellar `_: financial platform - -* `Touch Surgery `_: surgery simulator - -* `TrinityCore `_: open-source - MMORPG framework - -* `🐙 userver framework `_: open-source asynchronous - framework with a rich set of abstractions and database drivers - -* `Windows Terminal `_: the new Windows - terminal - -`More... `_ - -If you are aware of other projects using this library, please let me know -by `email `_ or by submitting an -`issue `_. - -Motivation ----------- - -So why yet another formatting library? - -There are plenty of methods for doing this task, from standard ones like -the printf family of function and iostreams to Boost Format and FastFormat -libraries. The reason for creating a new library is that every existing -solution that I found either had serious issues or didn't provide -all the features I needed. - -printf -~~~~~~ - -The good thing about ``printf`` is that it is pretty fast and readily available -being a part of the C standard library. The main drawback is that it -doesn't support user-defined types. ``printf`` also has safety issues although -they are somewhat mitigated with `__attribute__ ((format (printf, ...)) -`_ in GCC. -There is a POSIX extension that adds positional arguments required for -`i18n `_ -to ``printf`` but it is not a part of C99 and may not be available on some -platforms. - -iostreams -~~~~~~~~~ - -The main issue with iostreams is best illustrated with an example: - -.. code:: c++ - - std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n"; - -which is a lot of typing compared to printf: - -.. code:: c++ - - printf("%.2f\n", 1.23456); - -Matthew Wilson, the author of FastFormat, called this "chevron hell". iostreams -don't support positional arguments by design. - -The good part is that iostreams support user-defined types and are safe although -error handling is awkward. - -Boost Format -~~~~~~~~~~~~ - -This is a very powerful library that supports both ``printf``-like format -strings and positional arguments. Its main drawback is performance. According to -various benchmarks, it is much slower than other methods considered here. Boost -Format also has excessive build times and severe code bloat issues (see -`Benchmarks`_). - -FastFormat -~~~~~~~~~~ - -This is an interesting library that is fast, safe, and has positional arguments. -However, it has significant limitations, citing its author: - - Three features that have no hope of being accommodated within the - current design are: - - * Leading zeros (or any other non-space padding) - * Octal/hexadecimal encoding - * Runtime width/alignment specification - -It is also quite big and has a heavy dependency, STLSoft, which might be too -restrictive for using it in some projects. - -Boost Spirit.Karma -~~~~~~~~~~~~~~~~~~ - -This is not a formatting library but I decided to include it here for -completeness. As iostreams, it suffers from the problem of mixing verbatim text -with arguments. The library is pretty fast, but slower on integer formatting -than ``fmt::format_to`` with format string compilation on Karma's own benchmark, -see `Converting a hundred million integers to strings per second -`_. - -License -------- - -{fmt} is distributed under the MIT `license -`_. - -Documentation License ---------------------- - -The `Format String Syntax `_ -section in the documentation is based on the one from Python `string module -documentation `_. -For this reason, the documentation is distributed under the Python Software -Foundation license available in `doc/python-license.txt -`_. -It only applies if you distribute the documentation of {fmt}. - -Maintainers ------------ - -The {fmt} library is maintained by Victor Zverovich (`vitaut -`_) with contributions from many other people. -See `Contributors `_ and -`Releases `_ for some of the names. -Let us know if your contribution is not listed or mentioned incorrectly and -we'll make it right. - -Security Policy ---------------- - -To report a security issue, please disclose it at `security advisory `_. - -This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. From 4497a2d09adea0ea78cfbb365f433bb32044c70c Mon Sep 17 00:00:00 2001 From: H1X4 <10332146+H1X4Dev@users.noreply.github.com> Date: Fri, 8 Dec 2023 18:13:18 +0200 Subject: [PATCH 06/14] fix cmake build --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 639c44f4..4b928ae3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,7 +283,7 @@ if (FMT_OS) endif () add_module_library(fmt src/fmt.cc FALLBACK - ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.md + ${FMT_SOURCES} ${FMT_HEADERS} README.md ChangeLog.md IF FMT_MODULE) add_library(fmt::fmt ALIAS fmt) if (FMT_MODULE) @@ -448,6 +448,6 @@ if (FMT_MASTER_PROJECT AND EXISTS ${gitignore}) set(CPACK_SOURCE_IGNORE_FILES ${ignored_files}) set(CPACK_SOURCE_PACKAGE_FILE_NAME fmt-${FMT_VERSION}) set(CPACK_PACKAGE_NAME fmt) - set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.rst) + set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.md) include(CPack) endif () From 9c3c107c8c233a4d31a88745c383414bf821a6b3 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Fri, 8 Dec 2023 12:36:33 -0500 Subject: [PATCH 07/14] Fix compile with GCC 6.3.0 (bug #3738) (#3743) --- include/fmt/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index b19abf37..baedccc1 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -817,7 +817,7 @@ template class buffer { protected: // Don't initialize ptr_ since it is not accessed to save a few cycles. FMT_MSC_WARNING(suppress : 26495) - buffer(size_t sz) noexcept : size_(sz), capacity_(sz) {} + FMT_CONSTEXPR buffer(size_t sz) noexcept : size_(sz), capacity_(sz) {} FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) noexcept : ptr_(p), size_(sz), capacity_(cap) {} From 2fabb43b93ed6b9efbae9a429bf20ec56e13dc30 Mon Sep 17 00:00:00 2001 From: George Liontos Date: Fri, 8 Dec 2023 20:26:52 +0200 Subject: [PATCH 08/14] Fix README file table (#3744) Co-authored-by: George Liontos --- README.md | 282 ++++++++++++++++++++++++++---------------------------- 1 file changed, 138 insertions(+), 144 deletions(-) diff --git a/README.md b/README.md index 8b590fcf..2e591937 100644 --- a/README.md +++ b/README.md @@ -24,48 +24,48 @@ Try {fmt} in [Compiler Explorer](https://godbolt.org/z/Eq5763). # Features -- Simple [format API](https://fmt.dev/latest/api.html) with positional - arguments for localization -- Implementation of [C++20 - std::format](https://en.cppreference.com/w/cpp/utility/format) and - [C++23 std::print](https://en.cppreference.com/w/cpp/io/print) -- [Format string syntax](https://fmt.dev/latest/syntax.html) similar - to Python\'s - [format](https://docs.python.org/3/library/stdtypes.html#str.format) -- Fast IEEE 754 floating-point formatter with correct rounding, - shortness and round-trip guarantees using the - [Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm -- Portable Unicode support -- Safe [printf - implementation](https://fmt.dev/latest/api.html#printf-formatting) - including the POSIX extension for positional arguments -- Extensibility: [support for user-defined - types](https://fmt.dev/latest/api.html#formatting-user-defined-types) -- High performance: faster than common standard library - implementations of `(s)printf`, iostreams, `to_string` and - `to_chars`, see [Speed tests](#speed-tests) and [Converting a - hundred million integers to strings per - second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html) -- Small code size both in terms of source code with the minimum - configuration consisting of just three files, `core.h`, `format.h` - and `format-inl.h`, and compiled code; see [Compile time and code - bloat](#compile-time-and-code-bloat) -- Reliability: the library has an extensive set of - [tests](https://github.com/fmtlib/fmt/tree/master/test) and is - [continuously fuzzed](https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1) -- Safety: the library is fully type-safe, errors in format strings can - be reported at compile time, automatic memory management prevents - buffer overflow errors -- Ease of use: small self-contained code base, no external - dependencies, permissive MIT - [license](https://github.com/fmtlib/fmt/blob/master/LICENSE.rst) -- [Portability](https://fmt.dev/latest/index.html#portability) with - consistent output across platforms and support for older compilers -- Clean warning-free codebase even on high warning levels such as - `-Wall -Wextra -pedantic` -- Locale independence by default -- Optional header-only configuration enabled with the - `FMT_HEADER_ONLY` macro +- Simple [format API](https://fmt.dev/latest/api.html) with positional + arguments for localization +- Implementation of [C++20 + std::format](https://en.cppreference.com/w/cpp/utility/format) and + [C++23 std::print](https://en.cppreference.com/w/cpp/io/print) +- [Format string syntax](https://fmt.dev/latest/syntax.html) similar + to Python\'s + [format](https://docs.python.org/3/library/stdtypes.html#str.format) +- Fast IEEE 754 floating-point formatter with correct rounding, + shortness and round-trip guarantees using the + [Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm +- Portable Unicode support +- Safe [printf + implementation](https://fmt.dev/latest/api.html#printf-formatting) + including the POSIX extension for positional arguments +- Extensibility: [support for user-defined + types](https://fmt.dev/latest/api.html#formatting-user-defined-types) +- High performance: faster than common standard library + implementations of `(s)printf`, iostreams, `to_string` and + `to_chars`, see [Speed tests](#speed-tests) and [Converting a + hundred million integers to strings per + second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html) +- Small code size both in terms of source code with the minimum + configuration consisting of just three files, `core.h`, `format.h` + and `format-inl.h`, and compiled code; see [Compile time and code + bloat](#compile-time-and-code-bloat) +- Reliability: the library has an extensive set of + [tests](https://github.com/fmtlib/fmt/tree/master/test) and is + [continuously fuzzed](https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1) +- Safety: the library is fully type-safe, errors in format strings can + be reported at compile time, automatic memory management prevents + buffer overflow errors +- Ease of use: small self-contained code base, no external + dependencies, permissive MIT + [license](https://github.com/fmtlib/fmt/blob/master/LICENSE.rst) +- [Portability](https://fmt.dev/latest/index.html#portability) with + consistent output across platforms and support for older compilers +- Clean warning-free codebase even on high warning levels such as + `-Wall -Wextra -pedantic` +- Locale independence by default +- Optional header-only configuration enabled with the + `FMT_HEADER_ONLY` macro See the [documentation](https://fmt.dev) for more details. @@ -175,19 +175,13 @@ Output on a modern terminal with Unicode support: ## Speed tests -+-------------------+---------------+-------------+ | Library | Method | Run Time, s | -+===================+===============+=============+ +|-------------------|---------------|-------------| | libc | printf | > 0.91 | -+-------------------+---------------+-------------+ | libc++ | std::ostream | > 2.49 | -+-------------------+---------------+-------------+ | {fmt} 9.1 | fmt::print | > 0.74 | -+-------------------+---------------+-------------+ | Boost Format 1.80 | boost::format | > 6.26 | -+-------------------+---------------+-------------+ | Folly Format | folly::format | > 1.87 | -+-------------------+---------------+-------------+ {fmt} is the fastest of the benchmarked methods, \~20% faster than `printf`. @@ -221,7 +215,7 @@ Sierra, best of three) is shown in the following tables. **Optimized build (-O3)** | Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | -| ------------- | --------------- | -------------------- | ------------------ | +|---------------|-----------------|----------------------|--------------------| | printf | > 2.6 | > 29 | > 26 | | printf+string | > 16.4 | > 29 | > 26 | | iostreams | > 31.1 | > 59 | > 55 | @@ -239,7 +233,7 @@ include to measure the overhead of the latter. **Non-optimized build** | Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | -| ------------- | --------------- | -------------------- | ------------------ | +|---------------|-----------------|----------------------|--------------------| | printf | > 2.2 | > 33 | > 30 | | printf+string | > 16.0 | > 33 | > 30 | | iostreams | > 28.3 | > 56 | > 52 | @@ -285,96 +279,96 @@ converts to `std::print`.) # Projects using this library -- [0 A.D.](https://play0ad.com/): a free, open-source, cross-platform - real-time strategy game -- [AMPL/MP](https://github.com/ampl/mp): an open-source library for - mathematical programming -- [Aseprite](https://github.com/aseprite/aseprite): animated sprite - editor & pixel art tool -- [AvioBook](https://www.aviobook.aero/en): a comprehensive aircraft - operations suite -- [Blizzard Battle.net](https://battle.net/): an online gaming - platform -- [Celestia](https://celestia.space/): real-time 3D visualization of - space -- [Ceph](https://ceph.com/): a scalable distributed storage system -- [ccache](https://ccache.dev/): a compiler cache -- [ClickHouse](https://github.com/ClickHouse/ClickHouse): an - analytical database management system -- [Contour](https://github.com/contour-terminal/contour/): a modern - terminal emulator -- [CUAUV](https://cuauv.org/): Cornell University\'s autonomous - underwater vehicle -- [Drake](https://drake.mit.edu/): a planning, control, and analysis - toolbox for nonlinear dynamical systems (MIT) -- [Envoy](https://lyft.github.io/envoy/): C++ L7 proxy and - communication bus (Lyft) -- [FiveM](https://fivem.net/): a modification framework for GTA V -- [fmtlog](https://github.com/MengRao/fmtlog): a performant - fmtlib-style logging library with latency in nanoseconds -- [Folly](https://github.com/facebook/folly): Facebook open-source - library -- [GemRB](https://gemrb.org/): a portable open-source implementation - of Bioware's Infinity Engine -- [Grand Mountain - Adventure](https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/): - a beautiful open-world ski & snowboarding game -- [HarpyWar/pvpgn](https://github.com/pvpgn/pvpgn-server): Player vs - Player Gaming Network with tweaks -- [KBEngine](https://github.com/kbengine/kbengine): an open-source - MMOG server engine -- [Keypirinha](https://keypirinha.com/): a semantic launcher for - Windows -- [Kodi](https://kodi.tv/) (formerly xbmc): home theater software -- [Knuth](https://kth.cash/): high-performance Bitcoin full-node -- [libunicode](https://github.com/contour-terminal/libunicode/): a - modern C++17 Unicode library -- [MariaDB](https://mariadb.org/): relational database management - system -- [Microsoft Verona](https://github.com/microsoft/verona): research - programming language for concurrent ownership -- [MongoDB](https://mongodb.com/): distributed document database -- [MongoDB Smasher](https://github.com/duckie/mongo_smasher): a small - tool to generate randomized datasets -- [OpenSpace](https://openspaceproject.com/): an open-source - astrovisualization framework -- [PenUltima Online (POL)](https://www.polserver.com/): an MMO server, - compatible with most Ultima Online clients -- [PyTorch](https://github.com/pytorch/pytorch): an open-source - machine learning library -- [quasardb](https://www.quasardb.net/): a distributed, - high-performance, associative database -- [Quill](https://github.com/odygrd/quill): asynchronous low-latency - logging library -- [QKW](https://github.com/ravijanjam/qkw): generalizing aliasing to - simplify navigation, and executing complex multi-line terminal - command sequences -- [redis-cerberus](https://github.com/HunanTV/redis-cerberus): a Redis - cluster proxy -- [redpanda](https://vectorized.io/redpanda): a 10x faster Kafka® - replacement for mission-critical systems written in C++ -- [rpclib](http://rpclib.net/): a modern C++ msgpack-RPC server and - client library -- [Salesforce Analytics - Cloud](https://www.salesforce.com/analytics-cloud/overview/): - business intelligence software -- [Scylla](https://www.scylladb.com/): a Cassandra-compatible NoSQL - data store that can handle 1 million transactions per second on a - single server -- [Seastar](http://www.seastar-project.org/): an advanced, open-source - C++ framework for high-performance server applications on modern - hardware -- [spdlog](https://github.com/gabime/spdlog): super fast C++ logging - library -- [Stellar](https://www.stellar.org/): financial platform -- [Touch Surgery](https://www.touchsurgery.com/): surgery simulator -- [TrinityCore](https://github.com/TrinityCore/TrinityCore): - open-source MMORPG framework -- [🐙 userver framework](https://userver.tech/): open-source - asynchronous framework with a rich set of abstractions and database - drivers -- [Windows Terminal](https://github.com/microsoft/terminal): the new - Windows terminal +- [0 A.D.](https://play0ad.com/): a free, open-source, cross-platform + real-time strategy game +- [AMPL/MP](https://github.com/ampl/mp): an open-source library for + mathematical programming +- [Aseprite](https://github.com/aseprite/aseprite): animated sprite + editor & pixel art tool +- [AvioBook](https://www.aviobook.aero/en): a comprehensive aircraft + operations suite +- [Blizzard Battle.net](https://battle.net/): an online gaming + platform +- [Celestia](https://celestia.space/): real-time 3D visualization of + space +- [Ceph](https://ceph.com/): a scalable distributed storage system +- [ccache](https://ccache.dev/): a compiler cache +- [ClickHouse](https://github.com/ClickHouse/ClickHouse): an + analytical database management system +- [Contour](https://github.com/contour-terminal/contour/): a modern + terminal emulator +- [CUAUV](https://cuauv.org/): Cornell University\'s autonomous + underwater vehicle +- [Drake](https://drake.mit.edu/): a planning, control, and analysis + toolbox for nonlinear dynamical systems (MIT) +- [Envoy](https://lyft.github.io/envoy/): C++ L7 proxy and + communication bus (Lyft) +- [FiveM](https://fivem.net/): a modification framework for GTA V +- [fmtlog](https://github.com/MengRao/fmtlog): a performant + fmtlib-style logging library with latency in nanoseconds +- [Folly](https://github.com/facebook/folly): Facebook open-source + library +- [GemRB](https://gemrb.org/): a portable open-source implementation + of Bioware's Infinity Engine +- [Grand Mountain + Adventure](https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/): + a beautiful open-world ski & snowboarding game +- [HarpyWar/pvpgn](https://github.com/pvpgn/pvpgn-server): Player vs + Player Gaming Network with tweaks +- [KBEngine](https://github.com/kbengine/kbengine): an open-source + MMOG server engine +- [Keypirinha](https://keypirinha.com/): a semantic launcher for + Windows +- [Kodi](https://kodi.tv/) (formerly xbmc): home theater software +- [Knuth](https://kth.cash/): high-performance Bitcoin full-node +- [libunicode](https://github.com/contour-terminal/libunicode/): a + modern C++17 Unicode library +- [MariaDB](https://mariadb.org/): relational database management + system +- [Microsoft Verona](https://github.com/microsoft/verona): research + programming language for concurrent ownership +- [MongoDB](https://mongodb.com/): distributed document database +- [MongoDB Smasher](https://github.com/duckie/mongo_smasher): a small + tool to generate randomized datasets +- [OpenSpace](https://openspaceproject.com/): an open-source + astrovisualization framework +- [PenUltima Online (POL)](https://www.polserver.com/): an MMO server, + compatible with most Ultima Online clients +- [PyTorch](https://github.com/pytorch/pytorch): an open-source + machine learning library +- [quasardb](https://www.quasardb.net/): a distributed, + high-performance, associative database +- [Quill](https://github.com/odygrd/quill): asynchronous low-latency + logging library +- [QKW](https://github.com/ravijanjam/qkw): generalizing aliasing to + simplify navigation, and executing complex multi-line terminal + command sequences +- [redis-cerberus](https://github.com/HunanTV/redis-cerberus): a Redis + cluster proxy +- [redpanda](https://vectorized.io/redpanda): a 10x faster Kafka® + replacement for mission-critical systems written in C++ +- [rpclib](http://rpclib.net/): a modern C++ msgpack-RPC server and + client library +- [Salesforce Analytics + Cloud](https://www.salesforce.com/analytics-cloud/overview/): + business intelligence software +- [Scylla](https://www.scylladb.com/): a Cassandra-compatible NoSQL + data store that can handle 1 million transactions per second on a + single server +- [Seastar](http://www.seastar-project.org/): an advanced, open-source + C++ framework for high-performance server applications on modern + hardware +- [spdlog](https://github.com/gabime/spdlog): super fast C++ logging + library +- [Stellar](https://www.stellar.org/): financial platform +- [Touch Surgery](https://www.touchsurgery.com/): surgery simulator +- [TrinityCore](https://github.com/TrinityCore/TrinityCore): + open-source MMORPG framework +- [🐙 userver framework](https://userver.tech/): open-source + asynchronous framework with a rich set of abstractions and database + drivers +- [Windows Terminal](https://github.com/microsoft/terminal): the new + Windows terminal [More\...](https://github.com/search?q=fmtlib&type=Code) @@ -442,9 +436,9 @@ arguments. However, it has significant limitations, citing its author: > Three features that have no hope of being accommodated within the > current design are: > -> - Leading zeros (or any other non-space padding) -> - Octal/hexadecimal encoding -> - Runtime width/alignment specification +> - Leading zeros (or any other non-space padding) +> - Octal/hexadecimal encoding +> - Runtime width/alignment specification It is also quite big and has a heavy dependency, STLSoft, which might be too restrictive for using it in some projects. From dee0dbf07f9a992160ad105ec830941b07e69370 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 8 Dec 2023 14:24:11 -0800 Subject: [PATCH 09/14] Update README.md --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 2e591937..5454ce09 100644 --- a/README.md +++ b/README.md @@ -177,11 +177,11 @@ Output on a modern terminal with Unicode support: | Library | Method | Run Time, s | |-------------------|---------------|-------------| -| libc | printf | > 0.91 | -| libc++ | std::ostream | > 2.49 | -| {fmt} 9.1 | fmt::print | > 0.74 | -| Boost Format 1.80 | boost::format | > 6.26 | -| Folly Format | folly::format | > 1.87 | +| libc | printf | 0.91 | +| libc++ | std::ostream | 2.49 | +| {fmt} 9.1 | fmt::print | 0.74 | +| Boost Format 1.80 | boost::format | 6.26 | +| Folly Format | folly::format | 1.87 | {fmt} is the fastest of the benchmarked methods, \~20% faster than `printf`. @@ -216,12 +216,12 @@ Sierra, best of three) is shown in the following tables. | Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | |---------------|-----------------|----------------------|--------------------| -| printf | > 2.6 | > 29 | > 26 | -| printf+string | > 16.4 | > 29 | > 26 | -| iostreams | > 31.1 | > 59 | > 55 | -| {fmt} | > 19.0 | > 37 | > 34 | -| Boost Format | > 91.9 | > 226 | > 203 | -| Folly Format | > 115.7 | > 101 | > 88 | +| printf | 2.6 | 29 | 26 | +| printf+string | 16.4 | 29 | 26 | +| iostreams | 31.1 | 59 | 55 | +| {fmt} | 19.0 | 37 | 34 | +| Boost Format | 91.9 | 226 | 203 | +| Folly Format | 115.7 | 101 | 88 | As you can see, {fmt} has 60% less overhead in terms of resulting binary code size compared to iostreams and comes pretty close to `printf`. @@ -234,12 +234,12 @@ include to measure the overhead of the latter. | Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | |---------------|-----------------|----------------------|--------------------| -| printf | > 2.2 | > 33 | > 30 | -| printf+string | > 16.0 | > 33 | > 30 | -| iostreams | > 28.3 | > 56 | > 52 | -| {fmt} | > 18.2 | > 59 | > 50 | -| Boost Format | > 54.1 | > 365 | > 303 | -| Folly Format | > 79.9 | > 445 | > 430 | +| printf | 2.2 | 33 | 30 | +| printf+string | 16.0 | 33 | 30 | +| iostreams | 28.3 | 56 | 52 | +| {fmt} | 18.2 | 59 | 50 | +| Boost Format | 54.1 | 365 | 303 | +| Folly Format | 79.9 | 445 | 430 | `libc`, `lib(std)c++`, and `libfmt` are all linked as shared libraries to compare formatting function overhead only. Boost Format is a From 9a6fd11a56fe7d581180651068b8eeb5a81aa9b9 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Sun, 10 Dec 2023 01:13:20 +0900 Subject: [PATCH 10/14] Fix typo in gmock-gtest-all.cc (#3747) syntetic -> synthetic --- test/gtest/gmock-gtest-all.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gtest/gmock-gtest-all.cc b/test/gtest/gmock-gtest-all.cc index 7b33134f..9d3b9bc1 100644 --- a/test/gtest/gmock-gtest-all.cc +++ b/test/gtest/gmock-gtest-all.cc @@ -1912,7 +1912,7 @@ void AssertHelper::operator=(const Message& message) const { namespace { // When TEST_P is found without a matching INSTANTIATE_TEST_SUITE_P -// to creates test cases for it, a syntetic test case is +// to creates test cases for it, a synthetic test case is // inserted to report ether an error or a log message. // // This configuration bit will likely be removed at some point. From 6392dba21c46c3b32a40430ce7d2a24d4b01c6fb Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Sat, 9 Dec 2023 21:16:57 +0500 Subject: [PATCH 11/14] Fix warning: identifier '_a' preceded by whitespace in a literal operator declaration is deprecated (#3748) Signed-off-by: Vladislav Shchapov --- include/fmt/xchar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fmt/xchar.h b/include/fmt/xchar.h index 625ec369..2bf8c276 100644 --- a/include/fmt/xchar.h +++ b/include/fmt/xchar.h @@ -70,7 +70,7 @@ constexpr format_arg_store make_wformat_args( inline namespace literals { #if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS -constexpr detail::udl_arg operator"" _a(const wchar_t* s, size_t) { +constexpr detail::udl_arg operator""_a(const wchar_t* s, size_t) { return {s}; } #endif From 640e0c02d48e19076e976b395d919c815a27ae5d Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 9 Dec 2023 17:37:07 -0800 Subject: [PATCH 12/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5454ce09..41f46abc 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,7 @@ IEEE754 `float` and `double` formatting than [double-conversion](https://github.com/google/double-conversion) and [ryu](https://github.com/ulfjack/ryu): -[![image](https://user-images.githubusercontent.com/576385/%0A95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png)](https://fmt.dev/unknown_mac64_clang12.0.html) +[![image](https://user-images.githubusercontent.com/576385/95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png)](https://fmt.dev/unknown_mac64_clang12.0.html) ## Compile time and code bloat From 9048add999a4e77420fee949f743b9aca0f0bac3 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 10 Dec 2023 07:26:45 -0800 Subject: [PATCH 13/14] Report out-of-range errors in chrono --- include/fmt/chrono.h | 8 ++++---- test/chrono-test.cc | 17 +++++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 57cd0b70..bed584b6 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -1049,10 +1049,10 @@ inline void tzset_once() { // Converts value to Int and checks that it's in the range [0, upper). template ::value)> inline Int to_nonnegative_int(T value, Int upper) { - FMT_ASSERT(std::is_unsigned::value || - (value >= 0 && to_unsigned(value) <= to_unsigned(upper)), - "invalid value"); - (void)upper; + if (!std::is_unsigned::value && + (value < 0 || to_unsigned(value) > to_unsigned(upper))) { + FMT_THROW(fmt::format_error("chrono value is out of range")); + } return static_cast(value); } template ::value)> diff --git a/test/chrono-test.cc b/test/chrono-test.cc index cb672816..56fbd382 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -740,8 +740,8 @@ TEST(chrono_test, special_durations) { EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration{2}), "03:33:20"); EXPECT_EQ("01.234", - fmt::format("{:.3%S}", std::chrono::duration( - 1.234e12))); + fmt::format("{:.3%S}", + std::chrono::duration(1.234e12))); } TEST(chrono_test, unsigned_duration) { @@ -864,18 +864,18 @@ TEST(chrono_test, timestamps_ratios) { EXPECT_EQ(fmt::format("{:%M:%S}", t1), "01:07.890"); - std::chrono::time_point - t2(std::chrono::minutes(7)); + std::chrono::time_point t2( + std::chrono::minutes(7)); EXPECT_EQ(fmt::format("{:%M:%S}", t2), "07:00"); - std::chrono::time_point>> t3(std::chrono::duration>(7)); EXPECT_EQ(fmt::format("{:%M:%S}", t3), "01:03"); - std::chrono::time_point>> t4(std::chrono::duration>(1)); @@ -1023,3 +1023,8 @@ TEST(chrono_test, glibc_extensions) { EXPECT_EQ(fmt::format("{:%-S}", d), "3.140000"); } } + +TEST(chrono_test, out_of_range) { + auto d = std::chrono::duration(538976288); + EXPECT_THROW((void)fmt::format("{:%j}", d), fmt::format_error); +} \ No newline at end of file From 274ba2645bdae12f6f0c7d7ca24659c4af670548 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Mon, 11 Dec 2023 00:49:53 +0800 Subject: [PATCH 14/14] allow format_as() to format reference (#3739) before this change, format_as() is unable to format a type which has `auto format_as() -> const another_type&`, and `another_type` is formattable. because `format_as_result` maps the result type as it is, and the compiler refuses to compile `static_cast(nullptr)`, where T is a reference type. but it would be handy if we could use `format_as()` to format types which, for instance, owns / inherit from a formattable type, and delegate the formatter to these variables instead without creating a copy of them. in this change: * instruct `format_as_result` to map the result type to the decayed type, so that `type` can be the decayed type of result type, and this also enables `type` to be formattable, as long as the decayed type is formattable. * corresponding test is added to format-test.cc Signed-off-by: Kefu Chai --- include/fmt/core.h | 2 +- test/format-test.cc | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index baedccc1..f6e68868 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1332,7 +1332,7 @@ using ulong_type = conditional_t; template struct format_as_result { template ::value || std::is_class::value)> - static auto map(U*) -> decltype(format_as(std::declval())); + static auto map(U*) -> remove_cvref_t()))>; static auto map(...) -> void; using type = decltype(map(static_cast(nullptr))); diff --git a/test/format-test.cc b/test/format-test.cc index 0a9924bf..a708dd00 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -2173,6 +2173,13 @@ auto format_as(scoped_enum_as_string) -> std::string { return "foo"; } struct struct_as_int {}; auto format_as(struct_as_int) -> int { return 42; } + +struct struct_as_const_reference { + const std::string name = "foo"; +}; +auto format_as(const struct_as_const_reference& s) -> const std::string& { + return s.name; +} } // namespace test TEST(format_test, format_as) { @@ -2180,6 +2187,7 @@ TEST(format_test, format_as) { EXPECT_EQ(fmt::format("{}", test::scoped_enum_as_string_view()), "foo"); EXPECT_EQ(fmt::format("{}", test::scoped_enum_as_string()), "foo"); EXPECT_EQ(fmt::format("{}", test::struct_as_int()), "42"); + EXPECT_EQ(fmt::format("{}", test::struct_as_const_reference()), "foo"); } TEST(format_test, format_as_to_string) {