diff --git a/include/fmt/core.h b/include/fmt/core.h index c946e12a64a8..2a3334225ef2 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -16,6 +16,9 @@ #include #include +#undef FMT_EXCEPTIONS +#define FMT_EXCEPTIONS 0 + // The fmt library version in the form major * 10000 + minor * 100 + patch. #define FMT_VERSION 80100 @@ -2059,7 +2062,8 @@ enum class presentation_type : unsigned char { general_upper, // 'G' chr, // 'c' string, // 's' - pointer // 'p' + pointer, // 'p' + any // 'y' }; // Format specifiers for built-in and string types. @@ -2475,6 +2479,8 @@ FMT_CONSTEXPR auto parse_presentation_type(Char type) -> presentation_type { return presentation_type::string; case 'p': return presentation_type::pointer; + case 'y': + return presentation_type::any; default: return presentation_type::none; } @@ -2695,7 +2701,7 @@ class compile_parse_context template FMT_CONSTEXPR void check_int_type_spec(presentation_type type, ErrorHandler&& eh) { - if (type > presentation_type::bin_upper && type != presentation_type::chr) + if (type > presentation_type::bin_upper && type != presentation_type::chr && type != presentation_type::any) eh.on_error("invalid type specifier"); } @@ -2703,8 +2709,8 @@ FMT_CONSTEXPR void check_int_type_spec(presentation_type type, template FMT_CONSTEXPR auto check_char_specs(const basic_format_specs& specs, ErrorHandler&& eh = {}) -> bool { - if (specs.type != presentation_type::none && - specs.type != presentation_type::chr) { + if (specs.type != presentation_type::none && specs.type != presentation_type::chr && + specs.type != presentation_type::string && specs.type != presentation_type::any) { check_int_type_spec(specs.type, eh); return false; } @@ -2747,6 +2753,7 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs& specs, result.upper = true; FMT_FALLTHROUGH; case presentation_type::general_lower: + case presentation_type::any: result.format = float_format::general; break; case presentation_type::exp_upper: @@ -2771,6 +2778,7 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs& specs, break; default: eh.on_error("invalid type specifier"); + result.format = float_format::general; break; } return result; @@ -2779,23 +2787,27 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs& specs, template FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type, ErrorHandler&& eh = {}) -> bool { - if (type == presentation_type::none || type == presentation_type::string) + if (type == presentation_type::none || type == presentation_type::string || + type == presentation_type::any) return true; - if (type != presentation_type::pointer) eh.on_error("invalid type specifier"); - return false; + if (type != presentation_type::pointer) + eh.on_error("invalid type specifier"); + return true; } template FMT_CONSTEXPR void check_string_type_spec(presentation_type type, ErrorHandler&& eh = {}) { - if (type != presentation_type::none && type != presentation_type::string) + if (type != presentation_type::none && type != presentation_type::string && + type != presentation_type::any) eh.on_error("invalid type specifier"); } template FMT_CONSTEXPR void check_pointer_type_spec(presentation_type type, ErrorHandler&& eh) { - if (type != presentation_type::none && type != presentation_type::pointer) + if (type != presentation_type::none && type != presentation_type::pointer && + type != presentation_type::any) eh.on_error("invalid type specifier"); } diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 04ded48292e5..59f5c0c1afd6 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -34,10 +34,7 @@ namespace detail { FMT_FUNC void assert_fail(const char* file, int line, const char* message) { // Use unchecked std::fprintf to avoid triggering another assertion when // writing to stderr fails - std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); - // Chosen instead of std::abort to satisfy Clang in CUDA mode during device - // code pass. - std::terminate(); + std::fprintf(stderr, "%s:%d: assertion failed: %s\n", file, line, message); } FMT_FUNC void throw_format_error(const char* message) { diff --git a/include/fmt/format.h b/include/fmt/format.h index 1a5ff230092e..d72bef031b97 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -40,6 +40,7 @@ #include // std::runtime_error #include // std::system_error #include // std::swap +#include // DBL_DIG #ifdef __cpp_lib_bit_cast # include // std::bitcast @@ -95,10 +96,17 @@ FMT_END_NAMESPACE # define FMT_THROW(x) throw x # endif # else -# define FMT_THROW(x) \ - do { \ - FMT_ASSERT(false, (x).what()); \ - } while (false) +# ifdef _DEBUG +# define FMT_THROW(x) \ + do { \ + ::printf("%s\n", x.what()); \ + } while (false) +# else +# define FMT_THROW(x) \ + do { \ + static_cast(x); \ + } while (false) +# endif # endif #endif @@ -1573,6 +1581,10 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, auto abs_value = arg.abs_value; auto prefix = arg.prefix; switch (specs.type) { + default: + throw_format_error("invalid type specifier"); + FMT_FALLTHROUGH; + case presentation_type::any: case presentation_type::none: case presentation_type::dec: { if (specs.localized && @@ -1621,8 +1633,6 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, } case presentation_type::chr: return write_char(out, static_cast(abs_value), specs); - default: - throw_format_error("invalid type specifier"); } return out; } @@ -1993,6 +2003,31 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value, if (const_check(!is_supported_floating_point(value))) return out; float_specs fspecs = parse_float_type_spec(specs); fspecs.sign = specs.sign; + + if (specs.type == presentation_type::fixed_lower) { + static const double prevPowerOfTen[17] = {1e-1, 1, 1e1, 1e2, 1e3, 1e4, + 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, + 1e11, 1e12, 1e13, 1e14, 1e15}; + if (specs.precision < 0) { + specs.precision = 6; + } + if (specs.precision > DBL_DIG || fabs(value) >= prevPowerOfTen[DBL_DIG - specs.precision + 1]) { + specs.precision = DBL_DIG; + fspecs.format = float_format::general; + fspecs.showpoint = specs.alt; + } else { +#ifdef __cpp_if_constexpr + if constexpr (std::is_same()) { +#else + if (std::is_same()) { +#endif + if (fabs(value) < prevPowerOfTen[DBL_DIG - specs.precision]) { + value = static_cast( std::nextafter(value, value >= 0.0 ? 1e15 : -1e15) ); + } + } + } + } + if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit. fspecs.sign = sign::minus; value = -value; diff --git a/include/fmt/printf.h b/include/fmt/printf.h index 19d550f6cf53..48acaeb3d339 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -128,6 +128,9 @@ template class arg_converter { template ::value)> void operator()(U value) { + if (type_ != 'd' && type_ != 'i' && type_ != 'o' && type_ != 'u' && + type_ != 'x' && type_ != 'X') + return; bool is_signed = type_ == 'd' || type_ == 'i'; using target_type = conditional_t::value, U, T>; if (const_check(sizeof(target_type) <= sizeof(int))) { @@ -250,8 +253,9 @@ class printf_arg_formatter : public arg_formatter { if (std::is_same::value) { format_specs fmt_specs = this->specs; if (fmt_specs.type != presentation_type::none && - fmt_specs.type != presentation_type::chr) { - return (*this)(static_cast(value)); + fmt_specs.type != presentation_type::chr && + fmt_specs.type != presentation_type::any) { + fmt_specs.type = presentation_type::chr; } fmt_specs.sign = sign::none; fmt_specs.alt = false; diff --git a/src/format.cc b/src/format.cc index ecb8cc79a6e9..9fb66076748e 100644 --- a/src/format.cc +++ b/src/format.cc @@ -5,6 +5,9 @@ // // For the license information refer to format.h. +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif #include "fmt/format-inl.h" FMT_BEGIN_NAMESPACE