Merge branch 'fmtlib:master' into patch-1
This commit is contained in:
commit
e8a6f7867f
@ -314,6 +314,8 @@ template <typename T>
|
|||||||
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
|
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
|
||||||
template <typename T> struct type_identity { using type = T; };
|
template <typename T> struct type_identity { using type = T; };
|
||||||
template <typename T> using type_identity_t = typename type_identity<T>::type;
|
template <typename T> using type_identity_t = typename type_identity<T>::type;
|
||||||
|
template <typename T>
|
||||||
|
using underlying_t = typename std::underlying_type<T>::type;
|
||||||
|
|
||||||
struct monostate {
|
struct monostate {
|
||||||
constexpr monostate() {}
|
constexpr monostate() {}
|
||||||
@ -1416,8 +1418,8 @@ template <typename Context> struct arg_mapper {
|
|||||||
!has_fallback_formatter<T, char_type>::value)>
|
!has_fallback_formatter<T, char_type>::value)>
|
||||||
FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
|
FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
|
||||||
-> decltype(std::declval<arg_mapper>().map(
|
-> decltype(std::declval<arg_mapper>().map(
|
||||||
static_cast<typename std::underlying_type<T>::type>(val))) {
|
static_cast<underlying_t<T>>(val))) {
|
||||||
return map(static_cast<typename std::underlying_type<T>::type>(val));
|
return map(static_cast<underlying_t<T>>(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename U = decltype(format_as(T())),
|
template <typename T, typename U = decltype(format_as(T())),
|
||||||
@ -2214,13 +2216,12 @@ template <typename Char> constexpr bool is_ascii_letter(Char c) {
|
|||||||
|
|
||||||
// Converts a character to ASCII. Returns a number > 127 on conversion failure.
|
// Converts a character to ASCII. Returns a number > 127 on conversion failure.
|
||||||
template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
|
template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
|
||||||
constexpr auto to_ascii(Char value) -> Char {
|
constexpr auto to_ascii(Char c) -> Char {
|
||||||
return value;
|
return c;
|
||||||
}
|
}
|
||||||
template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
|
template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
|
||||||
constexpr auto to_ascii(Char value) ->
|
constexpr auto to_ascii(Char c) -> underlying_t<Char> {
|
||||||
typename std::underlying_type<Char>::type {
|
return c;
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
|
|||||||
@ -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 (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<Float>()) {
|
||||||
|
// Use floor because 0.9 = 9e-1.
|
||||||
|
exp = static_cast<int>(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.
|
// Use Dragonbox for the shortest format.
|
||||||
if (specs.binary32) {
|
if (specs.binary32) {
|
||||||
auto dec = dragonbox::to_decimal(static_cast<float>(value));
|
auto dec = dragonbox::to_decimal(static_cast<float>(value));
|
||||||
@ -2218,11 +2224,7 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision,
|
|||||||
auto dec = dragonbox::to_decimal(static_cast<double>(value));
|
auto dec = dragonbox::to_decimal(static_cast<double>(value));
|
||||||
write<char>(buffer_appender<char>(buf), dec.significand);
|
write<char>(buffer_appender<char>(buf), dec.significand);
|
||||||
return dec.exponent;
|
return dec.exponent;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
int exp = 0;
|
|
||||||
bool use_dragon = true;
|
|
||||||
if (is_fast_float<Float>()) {
|
|
||||||
// Use Grisu + Dragon4 for the given precision:
|
// Use Grisu + Dragon4 for the given precision:
|
||||||
// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf.
|
// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf.
|
||||||
const int min_exp = -60; // alpha in Grisu.
|
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;
|
exp += handler.size - cached_exp10 - 1;
|
||||||
precision = handler.precision;
|
precision = handler.precision;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Use floor because 0.9 = 9e-1.
|
|
||||||
exp = static_cast<int>(std::floor(std::log10(value)));
|
|
||||||
if (fixed) adjust_precision(precision, exp + 1);
|
|
||||||
}
|
}
|
||||||
if (use_dragon) {
|
if (use_dragon) {
|
||||||
auto f = fp();
|
auto f = fp();
|
||||||
|
|||||||
@ -775,6 +775,7 @@ class basic_memory_buffer final : public detail::buffer<T> {
|
|||||||
// Set pointer to the inline array so that delete is not called
|
// Set pointer to the inline array so that delete is not called
|
||||||
// when deallocating.
|
// when deallocating.
|
||||||
other.set(other.store_, 0);
|
other.set(other.store_, 0);
|
||||||
|
other.clear();
|
||||||
}
|
}
|
||||||
this->resize(size);
|
this->resize(size);
|
||||||
}
|
}
|
||||||
@ -2354,8 +2355,7 @@ template <
|
|||||||
type::custom_type,
|
type::custom_type,
|
||||||
FMT_ENABLE_IF(check)>
|
FMT_ENABLE_IF(check)>
|
||||||
FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
|
FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
|
||||||
return write<Char>(
|
return write<Char>(out, static_cast<underlying_t<T>>(value));
|
||||||
out, static_cast<typename std::underlying_type<T>::type>(value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename T,
|
template <typename Char, typename OutputIt, typename T,
|
||||||
@ -2888,11 +2888,17 @@ template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
constexpr auto underlying(Enum e) noexcept ->
|
constexpr auto underlying(Enum e) noexcept -> underlying_t<Enum> {
|
||||||
typename std::underlying_type<Enum>::type {
|
return static_cast<underlying_t<Enum>>(e);
|
||||||
return static_cast<typename std::underlying_type<Enum>::type>(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace enums {
|
||||||
|
template <typename Enum, FMT_ENABLE_IF(std::is_enum<Enum>::value)>
|
||||||
|
constexpr auto format_as(Enum e) noexcept -> underlying_t<Enum> {
|
||||||
|
return static_cast<underlying_t<Enum>>(e);
|
||||||
|
}
|
||||||
|
} // namespace enums
|
||||||
|
|
||||||
#ifdef __cpp_lib_byte
|
#ifdef __cpp_lib_byte
|
||||||
inline auto format_as(std::byte b) -> unsigned char { return underlying(b); }
|
inline auto format_as(std::byte b) -> unsigned char { return underlying(b); }
|
||||||
FMT_FORMAT_AS(std::byte, unsigned char);
|
FMT_FORMAT_AS(std::byte, unsigned char);
|
||||||
|
|||||||
@ -250,8 +250,9 @@ TEST(memory_buffer_test, move_ctor_dynamic_buffer) {
|
|||||||
buffer.push_back('a');
|
buffer.push_back('a');
|
||||||
basic_memory_buffer<char, 4, std_allocator> buffer2(std::move(buffer));
|
basic_memory_buffer<char, 4, std_allocator> buffer2(std::move(buffer));
|
||||||
// Move should rip the guts of the first buffer.
|
// Move should rip the guts of the first buffer.
|
||||||
EXPECT_EQ(inline_buffer_ptr, &buffer[0]);
|
EXPECT_EQ(&buffer[0], inline_buffer_ptr);
|
||||||
EXPECT_EQ("testa", std::string(&buffer2[0], buffer2.size()));
|
EXPECT_EQ(buffer.size(), 0);
|
||||||
|
EXPECT_EQ(std::string(&buffer2[0], buffer2.size()), "testa");
|
||||||
EXPECT_GT(buffer2.capacity(), 4u);
|
EXPECT_GT(buffer2.capacity(), 4u);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,8 +949,10 @@ TEST(format_test, precision) {
|
|||||||
EXPECT_THAT(outputs,
|
EXPECT_THAT(outputs,
|
||||||
testing::Contains(fmt::format("{:.838A}", -2.14001164E+38)));
|
testing::Contains(fmt::format("{:.838A}", -2.14001164E+38)));
|
||||||
|
|
||||||
auto ld = 8.43821965335442234493E-4933L;
|
if (std::numeric_limits<long double>::digits == 64) {
|
||||||
EXPECT_EQ(fmt::format("{:.0}", ld), ld != 0 ? "8e-4933" : "0");
|
auto ld = (std::numeric_limits<long double>::min)();
|
||||||
|
EXPECT_EQ(fmt::format("{:.0}", ld), "3e-4932");
|
||||||
|
}
|
||||||
|
|
||||||
EXPECT_EQ("123.", fmt::format("{:#.0f}", 123.0));
|
EXPECT_EQ("123.", fmt::format("{:#.0f}", 123.0));
|
||||||
EXPECT_EQ("1.23", fmt::format("{:.02f}", 1.234));
|
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 };
|
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) {
|
TEST(format_test, format_enum_class) {
|
||||||
EXPECT_EQ(fmt::format("{}", fmt::underlying(color::red)), "0");
|
EXPECT_EQ(fmt::format("{}", fmt::underlying(color::red)), "0");
|
||||||
|
EXPECT_EQ(fmt::format("{}", test_ns::color::red), "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_string) {
|
TEST(format_test, format_string) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user