From 2a69f56769e6da448af7a81ddc7500350620eade Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 5 Aug 2020 08:22:12 -0700 Subject: [PATCH 01/29] Tweak buffer size --- include/fmt/os.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fmt/os.h b/include/fmt/os.h index 7f40ca34b19ec..7796260a43cc4 100644 --- a/include/fmt/os.h +++ b/include/fmt/os.h @@ -356,7 +356,7 @@ struct buffer_size { struct ostream_params { int oflag = file::WRONLY | file::CREATE; - size_t buffer_size = BUFSIZ > 65536 ? BUFSIZ : 65536; + size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; ostream_params() {} From 717b226b59716a326f4a0f4eea7649d7b7dbda0c Mon Sep 17 00:00:00 2001 From: medithe <40990424+medithe@users.noreply.github.com> Date: Wed, 5 Aug 2020 18:37:10 +0200 Subject: [PATCH 02/29] include/fmt/format.h: explicit cast to std::size_t for parameter to buffer.resize() in order to get rid of warning 'implicit conversion changes signedness:' in clang-8 (#1802) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martin Wührer --- include/fmt/format.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index b52da26f39cde..a0e35f4b3f067 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1593,7 +1593,7 @@ template struct int_writer { format_decimal(digits, abs_value, num_digits); basic_memory_buffer buffer; size += prefix_size; - buffer.resize(size); + buffer.resize(to_unsigned(size)); basic_string_view s(&sep, sep_size); // Index of a decimal digit with the least significant digit having index 0. int digit_index = 0; From 2f8fc29e9b9ba268f810897517beabb85655dc58 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 5 Aug 2020 10:53:49 -0700 Subject: [PATCH 03/29] Update README.rst --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e2907a1918fab..6da777a5d046c 100644 --- a/README.rst +++ b/README.rst @@ -145,7 +145,8 @@ a string. out.print("Don't {}", "Panic"); } -This is up to 6x faster than glibc's ``fprintf``. +This can be `5 to 9 times faster than fprintf +`_. **Color support** From 61602a75db980737870e7f5e91de99e49dcd1c9e Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 5 Aug 2020 08:48:50 -0700 Subject: [PATCH 04/29] Remove -Wno-shadow --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a45e7fc130110..c13a0610b46b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") -Wctor-dtor-privacy -Wdisabled-optimization -Winvalid-pch -Woverloaded-virtual -Wconversion -Wswitch-enum - -Wno-ctor-dtor-privacy -Wno-format-nonliteral -Wno-shadow) + -Wno-ctor-dtor-privacy -Wno-format-nonliteral) if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6) set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept -Wno-dangling-else -Wno-unused-local-typedefs) From 4a4fc225ed5f96b35124ec9625ed6bf19740d6db Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 6 Aug 2020 07:34:56 -0700 Subject: [PATCH 05/29] Update changelog --- ChangeLog.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ChangeLog.rst b/ChangeLog.rst index aa1b7fe0eeb05..4bae496ea7612 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,3 +1,20 @@ +7.0.3 - TBD +----------- + +* Worked around broken ``numeric_limits`` for 128-bit integers + (`#1787 `_). + +* Added error reporting on missing named arguments + (`#1796 `_). + +* Stopped using 128-bit integers with clang-cl + (`#1800 `_). + Thanks `@Kingcom `_. + +* Fixed issues in locale-specific integer formatting (#) + (`#1782 `_, + `#1801 `_) + 7.0.2 - 2020-07-29 ------------------ From 33efc3c94fb8eea56dbf6067d7957a8cee0c9a8d Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 30 Jul 2020 07:03:11 -0700 Subject: [PATCH 06/29] Fix handling of iterators in locale-specific formatting (#1782) --- include/fmt/format.h | 9 +++++---- test/locale-test.cc | 12 ++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index b1ba07136f5aa..7213a0da7cf5c 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -745,9 +745,9 @@ FMT_CONSTEXPR bool is_supported_floating_point(T) { // Smallest of uint32_t, uint64_t, uint128_t that is large enough to // represent all values of T. template -using uint32_or_64_or_128_t = conditional_t< - num_bits() <= 32, uint32_t, - conditional_t() <= 64, uint64_t, uint128_t>>; +using uint32_or_64_or_128_t = + conditional_t() <= 32, uint32_t, + conditional_t() <= 64, uint64_t, uint128_t>>; // Static data is placed in this class template for the header-only config. template struct FMT_EXTERN_TEMPLATE_API basic_data { @@ -1593,7 +1593,8 @@ template struct int_writer { make_checked(p, s.size())); } if (prefix_size != 0) p[-1] = static_cast('-'); - write(out, basic_string_view(buffer.data(), buffer.size()), specs); + out = write(out, basic_string_view(buffer.data(), buffer.size()), + specs); } void on_chr() { *out++ = static_cast(abs_value); } diff --git a/test/locale-test.cc b/test/locale-test.cc index 15a40d9997051..b2cb8a631766e 100644 --- a/test/locale-test.cc +++ b/test/locale-test.cc @@ -89,4 +89,16 @@ TEST(LocaleTest, WFormat) { fmt::format(small_grouping_loc, L"{:L}", max_value())); } +TEST(LocaleTest, DoubleFormatter) { + auto loc = std::locale(std::locale(), new special_grouping()); + auto f = fmt::formatter(); + auto parse_ctx = fmt::format_parse_context("L"); + f.parse(parse_ctx); + char buf[10] = {}; + fmt::basic_format_context format_ctx( + buf, {}, fmt::detail::locale_ref(loc)); + *f.format(12345, format_ctx) = 0; + EXPECT_STREQ("12,345", buf); +} + #endif // FMT_STATIC_THOUSANDS_SEPARATOR From 0cc73ebf79ec39ba74f3d31a76c0acb2df824908 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 30 Jul 2020 07:16:15 -0700 Subject: [PATCH 07/29] Report error on missing named argument (#1796) --- include/fmt/core.h | 2 +- test/format-test.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 40c4ddb077c79..e83800cef69a8 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1713,7 +1713,7 @@ template class basic_format_args { } template int get_id(basic_string_view name) const { - if (!has_named_args()) return {}; + if (!has_named_args()) return -1; const auto& named_args = (is_packed() ? values_[-1] : args_[-1].value_).named_args; for (size_t i = 0; i < named_args.size; ++i) { diff --git a/test/format-test.cc b/test/format-test.cc index 978feef299278..2a25566c693e9 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -543,7 +543,6 @@ TEST(FormatterTest, ManyArgs) { TEST(FormatterTest, NamedArg) { EXPECT_EQ("1/a/A", format("{_1}/{a_}/{A_}", fmt::arg("a_", 'a'), fmt::arg("A_", "A"), fmt::arg("_1", 1))); - EXPECT_THROW_MSG(format("{a}"), format_error, "argument not found"); EXPECT_EQ(" -42", format("{0:{width}}", -42, fmt::arg("width", 4))); EXPECT_EQ("st", format("{0:.{precision}}", "str", fmt::arg("precision", 2))); EXPECT_EQ("1 2", format("{} {two}", 1, fmt::arg("two", 2))); @@ -553,6 +552,8 @@ TEST(FormatterTest, NamedArg) { fmt::arg("i", 0), fmt::arg("j", 0), fmt::arg("k", 0), fmt::arg("l", 0), fmt::arg("m", 0), fmt::arg("n", 0), fmt::arg("o", 0), fmt::arg("p", 0))); + EXPECT_THROW_MSG(format("{a}"), format_error, "argument not found"); + EXPECT_THROW_MSG(format("{a}", 42), format_error, "argument not found"); } TEST(FormatterTest, AutoArgIndex) { From ccf8561cb3e85676179c286e3e40edaebe0a45ae Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 30 Jul 2020 09:42:24 -0700 Subject: [PATCH 08/29] Workaround broken numeric_limites, part 2 (#1787) --- include/fmt/format.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 7213a0da7cf5c..ca7cefd9cd4d1 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -724,13 +724,18 @@ class FMT_API format_error : public std::runtime_error { namespace detail { +template +constexpr bool is_signed() { + return std::numeric_limits::is_signed || std::is_same(); +} + // Returns true if value is negative, false otherwise. // Same as `value < 0` but doesn't produce warnings if T is an unsigned type. -template ::is_signed)> +template ())> FMT_CONSTEXPR bool is_negative(T value) { return value < 0; } -template ::is_signed)> +template ())> FMT_CONSTEXPR bool is_negative(T) { return false; } From eaaaec99929ece68baa8bebce7325a78cd21cc96 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 30 Jul 2020 11:13:54 -0700 Subject: [PATCH 09/29] Workaround a bug in msvc --- include/fmt/format.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index ca7cefd9cd4d1..405b7e960aeae 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -725,17 +725,17 @@ class FMT_API format_error : public std::runtime_error { namespace detail { template -constexpr bool is_signed() { - return std::numeric_limits::is_signed || std::is_same(); -} +using is_signed = + std::integral_constant::is_signed || + std::is_same::value>; // Returns true if value is negative, false otherwise. // Same as `value < 0` but doesn't produce warnings if T is an unsigned type. -template ())> +template ::value)> FMT_CONSTEXPR bool is_negative(T value) { return value < 0; } -template ())> +template ::value)> FMT_CONSTEXPR bool is_negative(T) { return false; } From 37c8f4eaf33cecff0930d753e0021533fb722db5 Mon Sep 17 00:00:00 2001 From: Kingcom Date: Fri, 31 Jul 2020 02:21:35 +0200 Subject: [PATCH 10/29] Don't use 128 bit integers with clang-cl (#1800) clang-cl currently has a long-standing bug that using 128 bit integers generates references to symbols that are provided neither by its own nor by the Microsoft runtime: https://bugs.llvm.org/show_bug.cgi?id=25305 --- 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 e83800cef69a8..73f23c91c210c 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -299,7 +299,7 @@ template struct std_string_view {}; #ifdef FMT_USE_INT128 // Do nothing. -#elif defined(__SIZEOF_INT128__) && !FMT_NVCC +#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && !(FMT_CLANG_VERSION && FMT_MSC_VER) # define FMT_USE_INT128 1 using int128_t = __int128_t; using uint128_t = __uint128_t; From 0907c08ae56de6e0cea4874dfc45eef44f4178c9 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 3 Aug 2020 10:51:42 -0700 Subject: [PATCH 11/29] Fix handling of default alignmment with locale (#1801) --- include/fmt/format.h | 7 +++++-- test/locale-test.cc | 5 +++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 405b7e960aeae..17509b7b45dca 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1598,8 +1598,11 @@ template struct int_writer { make_checked(p, s.size())); } if (prefix_size != 0) p[-1] = static_cast('-'); - out = write(out, basic_string_view(buffer.data(), buffer.size()), - specs); + using iterator = remove_reference_t; + auto data = buffer.data(); + out = write_padded(out, specs, size, size, [=](iterator it) { + return copy_str(data, data + size, it); + }); } void on_chr() { *out++ = static_cast(abs_value); } diff --git a/test/locale-test.cc b/test/locale-test.cc index b2cb8a631766e..af3078afc6b54 100644 --- a/test/locale-test.cc +++ b/test/locale-test.cc @@ -68,6 +68,11 @@ TEST(LocaleTest, Format) { fmt::format(small_grouping_loc, "{:L}", max_value())); } +TEST(LocaleTest, FormatDetaultAlign) { + std::locale special_grouping_loc(std::locale(), new special_grouping()); + EXPECT_EQ(" 12,345", fmt::format(special_grouping_loc, "{:8L}", 12345)); +} + TEST(LocaleTest, WFormat) { std::locale loc(std::locale(), new numpunct()); EXPECT_EQ(L"1234567", fmt::format(std::locale(), L"{:L}", 1234567)); From 72920ba30a81dbaabbad51f19b16f580aa77b6ab Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 6 Aug 2020 07:34:56 -0700 Subject: [PATCH 12/29] Update changelog --- ChangeLog.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ChangeLog.rst b/ChangeLog.rst index aa1b7fe0eeb05..4bae496ea7612 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,3 +1,20 @@ +7.0.3 - TBD +----------- + +* Worked around broken ``numeric_limits`` for 128-bit integers + (`#1787 `_). + +* Added error reporting on missing named arguments + (`#1796 `_). + +* Stopped using 128-bit integers with clang-cl + (`#1800 `_). + Thanks `@Kingcom `_. + +* Fixed issues in locale-specific integer formatting (#) + (`#1782 `_, + `#1801 `_) + 7.0.2 - 2020-07-29 ------------------ From f4c997062a3e6ea60539f2570e3cd05c0db89fc8 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 6 Aug 2020 07:40:46 -0700 Subject: [PATCH 13/29] Fix changelog --- ChangeLog.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.rst b/ChangeLog.rst index 4bae496ea7612..b13ac6d6c69ea 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -11,9 +11,9 @@ (`#1800 `_). Thanks `@Kingcom `_. -* Fixed issues in locale-specific integer formatting (#) +* Fixed issues in locale-specific integer formatting (`#1782 `_, - `#1801 `_) + `#1801 `_). 7.0.2 - 2020-07-29 ------------------ From 1ebc2f7cc6b38f93ce5eba7cc72da6b11bb26836 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 6 Aug 2020 07:41:04 -0700 Subject: [PATCH 14/29] Bump version --- 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 73f23c91c210c..37799a3a0c488 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -18,7 +18,7 @@ #include // The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 70002 +#define FMT_VERSION 70003 #ifdef __clang__ # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) From cd4af11efc9c622896a3e4cb599fa28668ca3d05 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 6 Aug 2020 08:51:01 -0700 Subject: [PATCH 15/29] Update version --- ChangeLog.rst | 4 ++-- doc/build.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog.rst b/ChangeLog.rst index b13ac6d6c69ea..97a0a7da69552 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,5 +1,5 @@ -7.0.3 - TBD ------------ +7.0.3 - 2020-08-06 +------------------ * Worked around broken ``numeric_limits`` for 128-bit integers (`#1787 `_). diff --git a/doc/build.py b/doc/build.py index ba9eea752d9e8..06e105aa0838c 100755 --- a/doc/build.py +++ b/doc/build.py @@ -6,7 +6,7 @@ from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE from distutils.version import LooseVersion -versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2'] +versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3'] def pip_install(package, commit=None, **kwargs): "Install package using pip." From d7921d649a5bbd212f9983588b7af90dfc23f02c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 6 Aug 2020 19:41:17 -0700 Subject: [PATCH 16/29] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6da777a5d046c..be901c6e95af8 100644 --- a/README.rst +++ b/README.rst @@ -109,7 +109,7 @@ Output:: Default format: 42s 100ms strftime-like format: 03:15:30 -**Print a container** +**Print a container** (`run `_) .. code:: c++ From e4c954ff0ebb57716faa901586365430cf4f218f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 7 Aug 2020 16:03:15 -0700 Subject: [PATCH 17/29] Update README.rst --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index be901c6e95af8..88e996fa28f69 100644 --- a/README.rst +++ b/README.rst @@ -48,8 +48,9 @@ Features * 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 `unit tests - `_ and is continuously fuzzed +* 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 From e2c8c4557af6d56d8b64612e14934d4b51cfa639 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 7 Aug 2020 20:58:29 -0700 Subject: [PATCH 18/29] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 88e996fa28f69..4be852e08a2be 100644 --- a/README.rst +++ b/README.rst @@ -149,7 +149,7 @@ a string. This can be `5 to 9 times faster than fprintf `_. -**Color support** +**Print with colors and text styles** .. code:: c++ From d0dd6786938500b42c7f05118d1aae76c0951cd6 Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Fri, 7 Aug 2020 10:15:52 -0500 Subject: [PATCH 19/29] Adding convenience append(range) --- include/fmt/format.h | 7 +++++++ test/format-test.cc | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index a0e35f4b3f067..93e4b1e623394 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -685,6 +685,13 @@ class basic_memory_buffer : public detail::buffer { /** Increases the buffer capacity to *new_capacity*. */ void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } + + // Directly append data into the buffer + using detail::buffer::append; + template + void append(const ContiguousRange& range) { + append(range.data(), range.data() + range.size()); + } }; template diff --git a/test/format-test.cc b/test/format-test.cc index 6e6b6af9e0e8c..b48fd6be6ef2a 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -236,7 +236,7 @@ TEST(MemoryBufferTest, MoveCtorInlineBuffer) { std::allocator alloc; basic_memory_buffer buffer((TestAllocator(&alloc))); const char test[] = "test"; - buffer.append(test, test + 4); + buffer.append(string_view(test, 4)); check_move_buffer("test", buffer); // Adding one more character fills the inline buffer, but doesn't cause // dynamic allocation. From 065889a5937e01157eb5278c5865340d55a0b6c6 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 8 Aug 2020 07:01:21 -0700 Subject: [PATCH 20/29] Use correct capacity in iterator_buffer (#1807) --- include/fmt/core.h | 2 +- test/format-test.cc | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 359deb257c89e..f8b2c70907d02 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -771,7 +771,7 @@ class iterator_buffer : public Traits, public buffer { void flush(); public: - explicit iterator_buffer(OutputIt out, size_t n = 0) + explicit iterator_buffer(OutputIt out, size_t n = buffer_size) : Traits(n), buffer(data_, 0, n < size_t(buffer_size) ? n : size_t(buffer_size)), out_(out) {} diff --git a/test/format-test.cc b/test/format-test.cc index b48fd6be6ef2a..bd3dcfdb3382a 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1946,6 +1946,12 @@ TEST(FormatTest, FormattedSize) { EXPECT_EQ(2u, fmt::formatted_size("{}", 42)); } +TEST(FormatTest, FormatTo) { + std::vector v; + fmt::format_to(std::back_inserter(v), "{}", "foo"); + EXPECT_EQ(string_view(v.data(), v.size()), "foo"); +} + TEST(FormatTest, FormatToN) { char buffer[4]; buffer[3] = 'x'; From 7fc3d1f54ccbb77aa28204cbe46cef31dae4ebb7 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 8 Aug 2020 07:23:11 -0700 Subject: [PATCH 21/29] Add override to grow --- include/fmt/core.h | 8 ++++---- include/fmt/format.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index f8b2c70907d02..2816a64ba00f1 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -765,7 +765,7 @@ class iterator_buffer : public Traits, public buffer { T data_[buffer_size]; protected: - void grow(size_t) final { + void grow(size_t) final FMT_OVERRIDE { if (this->size() == buffer_size) flush(); } void flush(); @@ -786,7 +786,7 @@ class iterator_buffer : public Traits, public buffer { template class iterator_buffer : public buffer { protected: - void grow(size_t) final {} + void grow(size_t) final FMT_OVERRIDE {} public: explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {} @@ -804,7 +804,7 @@ class iterator_buffer, Container& container_; protected: - void grow(size_t capacity) final { + void grow(size_t capacity) final FMT_OVERRIDE { container_.resize(capacity); this->set(&container_[0], capacity); } @@ -827,7 +827,7 @@ template class counting_buffer : public buffer { size_t count_ = 0; protected: - void grow(size_t) final { + void grow(size_t) final FMT_OVERRIDE { if (this->size() != buffer_size) return; count_ += this->size(); this->clear(); diff --git a/include/fmt/format.h b/include/fmt/format.h index 93e4b1e623394..a0c8045e02b5d 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -622,7 +622,7 @@ class basic_memory_buffer : public detail::buffer { } protected: - void grow(size_t size) final; + void grow(size_t size) final FMT_OVERRIDE; public: using value_type = T; From e06ae3229436ba5efd81bb3b73e1c8d88131b285 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 8 Aug 2020 07:39:43 -0700 Subject: [PATCH 22/29] Avoid warnings on functions with external linkage that don't have declarations --- include/fmt/format-inl.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 35bae2dcd647c..e38ed16b7be0a 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -79,8 +79,8 @@ inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) { // ERANGE - buffer is not large enough to store the error message // other - failure // Buffer should be at least of size 1. -FMT_FUNC int safe_strerror(int error_code, char*& buffer, - size_t buffer_size) FMT_NOEXCEPT { +inline int safe_strerror(int error_code, char*& buffer, + size_t buffer_size) FMT_NOEXCEPT { FMT_ASSERT(buffer != nullptr && buffer_size != 0, "invalid buffer"); class dispatcher { @@ -173,8 +173,8 @@ FMT_FUNC void report_error(format_func func, int error_code, } // A wrapper around fwrite that throws on error. -FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count, - FILE* stream) { +inline void fwrite_fully(const void* ptr, size_t size, size_t count, + FILE* stream) { size_t written = std::fwrite(ptr, size, count, stream); if (written < count) FMT_THROW(system_error(errno, "cannot write to file")); } @@ -1264,7 +1264,7 @@ int snprintf_float(T value, int precision, float_specs specs, * occurs, this pointer will be a guess that depends on the particular * error, but it will always advance at least one byte. */ -FMT_FUNC const char* utf8_decode(const char* buf, uint32_t* c, int* e) { +inline const char* utf8_decode(const char* buf, uint32_t* c, int* e) { static const char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; From 4fd95e4b4d18be6be8fd8f6c8d685ad62e43de46 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 8 Aug 2020 08:14:39 -0700 Subject: [PATCH 23/29] Don't remove trailing zeros with # --- include/fmt/format-inl.h | 2 +- test/format-test.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index e38ed16b7be0a..6d3288450be51 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -1131,7 +1131,7 @@ int format_float(T value, int precision, float_specs specs, buffer& buf) { if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error) return snprintf_float(value, precision, specs, buf); int num_digits = handler.size; - if (!fixed) { + if (!fixed && !specs.showpoint) { // Remove trailing zeros. while (num_digits > 0 && buf[num_digits - 1] == '0') { --num_digits; diff --git a/test/format-test.cc b/test/format-test.cc index bd3dcfdb3382a..d0a38f2589756 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -761,6 +761,7 @@ TEST(FormatterTest, HashFlag) { EXPECT_EQ("-42.0", format("{0:#}", -42.0l)); EXPECT_EQ("4.e+01", format("{:#.0e}", 42.0)); EXPECT_EQ("0.", format("{:#.0f}", 0.01)); + EXPECT_EQ("0.50", format("{:#.2g}", 0.5)); auto s = format("{:#.0f}", 0.5); // MSVC's printf uses wrong rounding mode. EXPECT_TRUE(s == "0." || s == "1."); EXPECT_THROW_MSG(format("{0:#", 'c'), format_error, From 1378ddaefd8cc339c31ee93898bf6f4fb9497b75 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 8 Aug 2020 18:01:56 -0700 Subject: [PATCH 24/29] Update README.rst --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 4be852e08a2be..eff1179d341f8 100644 --- a/README.rst +++ b/README.rst @@ -50,7 +50,8 @@ Features 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 @@ -164,7 +165,7 @@ This can be `5 to 9 times faster than fprintf "Hello, {}!\n", "世界"); } -prints the following on a modern terminal: +Output on a modern terminal: .. image:: https://user-images.githubusercontent.com/ 576385/88485597-d312f600-cf2b-11ea-9cbe-61f535a86e28.png From 16985fdadff9beb43561912ba3c4dd9ab96dceed Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 9 Aug 2020 08:56:51 -0700 Subject: [PATCH 25/29] Update README.rst --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index eff1179d341f8..3fea71dbaa443 100644 --- a/README.rst +++ b/README.rst @@ -345,6 +345,8 @@ Projects using this library * `quasardb `_: A distributed, high-performance, associative database + +* `Quill `_: Asynchronous low-latency logging library * `readpe `_: Read Portable Executable From 6fb7c6fb25e2c0088b4aa5e53a59d8efb2bd3319 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 10 Aug 2020 07:20:34 -0700 Subject: [PATCH 26/29] Workaround a bug in gcc10 (#1810) --- include/fmt/format-inl.h | 7 ------- include/fmt/format.h | 17 +++++++++++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 6d3288450be51..f50c2da1b9689 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -263,13 +263,6 @@ const typename basic_data::digit_pair basic_data::digits[] = { template const char basic_data::hex_digits[] = "0123456789abcdef"; -template -const uint16_t basic_data::bsr2log10[] = { - 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, - 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, - 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; - #define FMT_POWERS_OF_10(factor) \ factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \ (factor)*1000000, (factor)*10000000, (factor)*100000000, \ diff --git a/include/fmt/format.h b/include/fmt/format.h index a0c8045e02b5d..d8680c3955da7 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -777,8 +777,6 @@ using uint32_or_64_or_128_t = // Static data is placed in this class template for the header-only config. template struct FMT_EXTERN_TEMPLATE_API basic_data { - // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). - static const uint16_t bsr2log10[]; static const uint64_t powers_of_10_64[]; static const uint32_t zero_or_powers_of_10_32[]; static const uint64_t zero_or_powers_of_10_64[]; @@ -797,6 +795,17 @@ template struct FMT_EXTERN_TEMPLATE_API basic_data { static const char right_padding_shifts[5]; }; +// Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). +// This is a function instead of an array to workaround a bug in GCC10 (#1810). +FMT_INLINE uint16_t bsr2log10(int bsr) { + constexpr uint16_t data[] = { + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, + 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; + return data[bsr]; +} + #ifndef FMT_EXPORTED FMT_EXTERN template struct basic_data; #endif @@ -809,7 +818,7 @@ struct data : basic_data<> {}; // except for n == 0 in which case count_digits returns 1. inline int count_digits(uint64_t n) { // https://github.com/fmtlib/format-benchmark/blob/master/digits10 - auto t = data::bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; + auto t = bsr2log10(FMT_BUILTIN_CLZLL(n | 1) ^ 63); return t - (n < data::zero_or_powers_of_10_64[t]); } #else @@ -867,7 +876,7 @@ template <> int count_digits<4>(detail::fallback_uintptr n); #ifdef FMT_BUILTIN_CLZ // Optional version of count_digits for better performance on 32-bit platforms. inline int count_digits(uint32_t n) { - auto t = data::bsr2log10[FMT_BUILTIN_CLZ(n | 1) ^ 31]; + auto t = bsr2log10(FMT_BUILTIN_CLZ(n | 1) ^ 31); return t - (n < data::zero_or_powers_of_10_32[t]); } #endif From 54daa0864afb57e9d12c26f50a4c4e2f1e2d5dea Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 10 Aug 2020 09:13:13 -0700 Subject: [PATCH 27/29] Add dynamic width support to FMT_COMPILE (#1809) --- include/fmt/compile.h | 14 ++++++++------ include/fmt/core.h | 8 +++++--- test/compile-test.cc | 5 +++++ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 679da4f293443..40e1a5a0d1421 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -443,7 +443,8 @@ template struct spec_field { OutputIt format(OutputIt out, const Args&... args) const { // This ensures that the argument type is convertile to `const T&`. const T& arg = get(args...); - basic_format_context ctx(out, {}); + const auto& vargs = make_format_args(args...); + basic_format_context ctx(out, vargs); return fmt.format(arg, ctx); } }; @@ -502,16 +503,17 @@ constexpr auto parse_tail(T head, S format_str) { template struct parse_specs_result { formatter fmt; size_t end; + int next_arg_id; }; template constexpr parse_specs_result parse_specs(basic_string_view str, - size_t pos) { + size_t pos, int arg_id) { str.remove_prefix(pos); - auto ctx = basic_format_parse_context(str); + auto ctx = basic_format_parse_context(str, {}, arg_id + 1); auto f = formatter(); auto end = f.parse(ctx); - return {f, pos + (end - str.data()) + 1}; + return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()}; } // Compiles a non-empty format string and returns the compiled representation @@ -531,8 +533,8 @@ constexpr auto compile_format_string(S format_str) { format_str); } else if constexpr (str[POS + 1] == ':') { using type = get_type; - constexpr auto result = parse_specs(str, POS + 2); - return parse_tail( + constexpr auto result = parse_specs(str, POS + 2, ID); + return parse_tail( spec_field{result.fmt}, format_str); } else { return unknown_format(); diff --git a/include/fmt/core.h b/include/fmt/core.h index 2816a64ba00f1..2b474e36a671e 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -298,7 +298,8 @@ template struct std_string_view {}; #ifdef FMT_USE_INT128 // Do nothing. -#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && !(FMT_CLANG_VERSION && FMT_MSC_VER) +#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \ + !(FMT_CLANG_VERSION && FMT_MSC_VER) # define FMT_USE_INT128 1 using int128_t = __int128_t; using uint128_t = __uint128_t; @@ -556,8 +557,9 @@ class basic_format_parse_context : private ErrorHandler { using iterator = typename basic_string_view::iterator; explicit constexpr basic_format_parse_context( - basic_string_view format_str, ErrorHandler eh = {}) - : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} + basic_string_view format_str, ErrorHandler eh = {}, + int next_arg_id = 0) + : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {} /** Returns an iterator to the beginning of the format string range being diff --git a/test/compile-test.cc b/test/compile-test.cc index 6dca548d55e3c..fd98c772723aa 100644 --- a/test/compile-test.cc +++ b/test/compile-test.cc @@ -153,6 +153,11 @@ TEST(CompileTest, FormatSpecs) { EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42)); } +TEST(CompileTest, DynamicWidth) { + EXPECT_EQ(" 42foo ", + fmt::format(FMT_COMPILE("{:{}}{:{}}"), 42, 4, "foo", 5)); +} + TEST(CompileTest, FormatTo) { char buf[8]; auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42); From fb0aeb8209d815688b4b4c0e69ca61a57d72c941 Mon Sep 17 00:00:00 2001 From: n16h7hunt3r <31915716+n16h7hunt3r@users.noreply.github.com> Date: Wed, 12 Aug 2020 00:27:27 +0200 Subject: [PATCH 28/29] fix: disabled UDL templates for PGI (#1811) (#1812) * fix: disabled UDL templates for PGI (#1811) * fix: insert defined auround __PGI Co-authored-by: n16h7hunt3r --- include/fmt/format.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index d8680c3955da7..efe090d0be9c5 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -139,12 +139,13 @@ FMT_END_NAMESPACE #endif #ifndef FMT_USE_UDL_TEMPLATE -// EDG frontend based compilers (icc, nvcc, etc) and GCC < 6.4 do not properly -// support UDL templates and GCC >= 9 warns about them. +// EDG frontend based compilers (icc, nvcc, PGI, etc) and GCC < 6.4 do not +// properly support UDL templates and GCC >= 9 warns about them. # if FMT_USE_USER_DEFINED_LITERALS && \ (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 501) && \ ((FMT_GCC_VERSION >= 604 && __cplusplus >= 201402L) || \ - FMT_CLANG_VERSION >= 304) + FMT_CLANG_VERSION >= 304) && \ + !defined(__PGI) # define FMT_USE_UDL_TEMPLATE 1 # else # define FMT_USE_UDL_TEMPLATE 0 From 4b69c78751488704c4dfdf03937112f179b0d4f4 Mon Sep 17 00:00:00 2001 From: Seokjin Lee Date: Wed, 12 Aug 2020 22:57:22 +0900 Subject: [PATCH 29/29] fix: warning C4100: unreferenced formal parameter (#1814) Add [[maybe_unused]] to fix it. --- include/fmt/compile.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 40e1a5a0d1421..fa0b2812b1de2 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -368,7 +368,8 @@ template struct type_list {}; // Returns a reference to the argument at index N from [first, rest...]. template -constexpr const auto& get(const T& first, const Args&... rest) { +constexpr const auto& get([[maybe_unused]] const T& first, + [[maybe_unused]] const Args&... rest) { static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); if constexpr (N == 0) return first;