diff --git a/include/fmt/core.h b/include/fmt/core.h index 5d458b7c..dbefe110 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -314,6 +314,8 @@ template using remove_cvref_t = typename std::remove_cv>::type; template struct type_identity { using type = T; }; template using type_identity_t = typename type_identity::type; +template +using underlying_t = typename std::underlying_type::type; struct monostate { constexpr monostate() {} @@ -1416,8 +1418,8 @@ template struct arg_mapper { !has_fallback_formatter::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> decltype(std::declval().map( - static_cast::type>(val))) { - return map(static_cast::type>(val)); + static_cast>(val))) { + return map(static_cast>(val)); } template constexpr bool is_ascii_letter(Char c) { // Converts a character to ASCII. Returns a number > 127 on conversion failure. template ::value)> -constexpr auto to_ascii(Char value) -> Char { - return value; +constexpr auto to_ascii(Char c) -> Char { + return c; } template ::value)> -constexpr auto to_ascii(Char value) -> - typename std::underlying_type::type { - return value; +constexpr auto to_ascii(Char c) -> underlying_t { + return c; } template diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 4f0d92a0..67399cf6 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -2208,7 +2208,13 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision, if (specs.fallback) return snprintf_float(value, precision, specs, buf); - if (!is_constant_evaluated() && precision < 0) { + int exp = 0; + bool use_dragon = true; + if (!is_fast_float()) { + // Use floor because 0.9 = 9e-1. + exp = static_cast(std::floor(std::log10(value))); + if (fixed) adjust_precision(precision, exp + 1); + } else if (!is_constant_evaluated() && precision < 0) { // Use Dragonbox for the shortest format. if (specs.binary32) { auto dec = dragonbox::to_decimal(static_cast(value)); @@ -2218,11 +2224,7 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision, auto dec = dragonbox::to_decimal(static_cast(value)); write(buffer_appender(buf), dec.significand); return dec.exponent; - } - - int exp = 0; - bool use_dragon = true; - if (is_fast_float()) { + } else { // Use Grisu + Dragon4 for the given precision: // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. const int min_exp = -60; // alpha in Grisu. @@ -2241,10 +2243,6 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision, exp += handler.size - cached_exp10 - 1; precision = handler.precision; } - } else { - // Use floor because 0.9 = 9e-1. - exp = static_cast(std::floor(std::log10(value))); - if (fixed) adjust_precision(precision, exp + 1); } if (use_dragon) { auto f = fp(); diff --git a/include/fmt/format.h b/include/fmt/format.h index 5b52a4c6..819fed4a 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -775,6 +775,7 @@ class basic_memory_buffer final : public detail::buffer { // Set pointer to the inline array so that delete is not called // when deallocating. other.set(other.store_, 0); + other.clear(); } this->resize(size); } @@ -2354,8 +2355,7 @@ template < type::custom_type, FMT_ENABLE_IF(check)> FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { - return write( - out, static_cast::type>(value)); + return write(out, static_cast>(value)); } template auto ptr(const std::shared_ptr& p) -> const void* { \endrst */ template -constexpr auto underlying(Enum e) noexcept -> - typename std::underlying_type::type { - return static_cast::type>(e); +constexpr auto underlying(Enum e) noexcept -> underlying_t { + return static_cast>(e); } +namespace enums { +template ::value)> +constexpr auto format_as(Enum e) noexcept -> underlying_t { + return static_cast>(e); +} +} // namespace enums + #ifdef __cpp_lib_byte inline auto format_as(std::byte b) -> unsigned char { return underlying(b); } FMT_FORMAT_AS(std::byte, unsigned char); diff --git a/test/format-test.cc b/test/format-test.cc index c7a468ad..96b5f1ae 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -250,8 +250,9 @@ TEST(memory_buffer_test, move_ctor_dynamic_buffer) { buffer.push_back('a'); basic_memory_buffer buffer2(std::move(buffer)); // Move should rip the guts of the first buffer. - EXPECT_EQ(inline_buffer_ptr, &buffer[0]); - EXPECT_EQ("testa", std::string(&buffer2[0], buffer2.size())); + EXPECT_EQ(&buffer[0], inline_buffer_ptr); + EXPECT_EQ(buffer.size(), 0); + EXPECT_EQ(std::string(&buffer2[0], buffer2.size()), "testa"); EXPECT_GT(buffer2.capacity(), 4u); } @@ -948,8 +949,10 @@ TEST(format_test, precision) { EXPECT_THAT(outputs, testing::Contains(fmt::format("{:.838A}", -2.14001164E+38))); - auto ld = 8.43821965335442234493E-4933L; - EXPECT_EQ(fmt::format("{:.0}", ld), ld != 0 ? "8e-4933" : "0"); + if (std::numeric_limits::digits == 64) { + auto ld = (std::numeric_limits::min)(); + EXPECT_EQ(fmt::format("{:.0}", ld), "3e-4932"); + } EXPECT_EQ("123.", fmt::format("{:#.0f}", 123.0)); EXPECT_EQ("1.23", fmt::format("{:.02f}", 1.234)); @@ -1459,8 +1462,14 @@ TEST(format_test, write_uintptr_fallback) { enum class color { red, green, blue }; +namespace test_ns { +enum class color { red, green, blue }; +using fmt::enums::format_as; +} // namespace test_ns + TEST(format_test, format_enum_class) { EXPECT_EQ(fmt::format("{}", fmt::underlying(color::red)), "0"); + EXPECT_EQ(fmt::format("{}", test_ns::color::red), "0"); } TEST(format_test, format_string) {