mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-24 11:10:13 +00:00
Refactor presentation types
This commit is contained in:
parent
4eb97fa4e3
commit
894faf3fed
@ -151,7 +151,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
-Wcast-align
|
||||
-Wctor-dtor-privacy -Wdisabled-optimization
|
||||
-Winvalid-pch -Woverloaded-virtual
|
||||
-Wconversion -Wswitch-enum -Wundef
|
||||
-Wconversion -Wundef
|
||||
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
|
||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
|
||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
||||
|
@ -904,7 +904,8 @@ template <typename Char, typename Rep, typename OutputIt,
|
||||
OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
|
||||
auto specs = basic_format_specs<Char>();
|
||||
specs.precision = precision;
|
||||
specs.type = precision > 0 ? 'f' : 'g';
|
||||
specs.type = precision > 0 ? presentation_type::fixed_lower
|
||||
: presentation_type::general_lower;
|
||||
return write<Char>(out, val, specs);
|
||||
}
|
||||
|
||||
|
@ -1949,11 +1949,33 @@ template <typename Char> struct fill_t {
|
||||
};
|
||||
FMT_END_DETAIL_NAMESPACE
|
||||
|
||||
enum class presentation_type : unsigned char {
|
||||
none,
|
||||
// Integer types should go first,
|
||||
dec, // 'd'
|
||||
oct, // 'o'
|
||||
hex_lower, // 'x'
|
||||
hex_upper, // 'X'
|
||||
bin_lower, // 'b'
|
||||
bin_upper, // 'B'
|
||||
hexfloat_lower, // 'a'
|
||||
hexfloat_upper, // 'A'
|
||||
exp_lower, // 'e'
|
||||
exp_upper, // 'E'
|
||||
fixed_lower, // 'f'
|
||||
fixed_upper, // 'F'
|
||||
general_lower, // 'g'
|
||||
general_upper, // 'G'
|
||||
chr, // 'c'
|
||||
string, // 's'
|
||||
pointer // 'p'
|
||||
};
|
||||
|
||||
// Format specifiers for built-in and string types.
|
||||
template <typename Char> struct basic_format_specs {
|
||||
int width;
|
||||
int precision;
|
||||
char type;
|
||||
presentation_type type;
|
||||
align_t align : 4;
|
||||
sign_t sign : 3;
|
||||
bool alt : 1; // Alternate form ('#').
|
||||
@ -1963,7 +1985,7 @@ template <typename Char> struct basic_format_specs {
|
||||
constexpr basic_format_specs()
|
||||
: width(0),
|
||||
precision(-1),
|
||||
type(0),
|
||||
type(presentation_type::none),
|
||||
align(align::none),
|
||||
sign(sign::none),
|
||||
alt(false),
|
||||
@ -2043,9 +2065,7 @@ template <typename Char> class specs_setter {
|
||||
}
|
||||
FMT_CONSTEXPR void end_precision() {}
|
||||
|
||||
FMT_CONSTEXPR void on_type(Char type) {
|
||||
specs_.type = static_cast<char>(type);
|
||||
}
|
||||
FMT_CONSTEXPR void on_type(presentation_type type) { specs_.type = type; }
|
||||
};
|
||||
|
||||
// Format spec handler that saves references to arguments representing dynamic
|
||||
@ -2327,6 +2347,48 @@ FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
|
||||
return begin;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR auto parse_presentation_type(Char type) -> presentation_type {
|
||||
switch (to_ascii(type)) {
|
||||
case 'd':
|
||||
return presentation_type::dec;
|
||||
case 'o':
|
||||
return presentation_type::oct;
|
||||
case 'x':
|
||||
return presentation_type::hex_lower;
|
||||
case 'X':
|
||||
return presentation_type::hex_upper;
|
||||
case 'b':
|
||||
return presentation_type::bin_lower;
|
||||
case 'B':
|
||||
return presentation_type::bin_upper;
|
||||
case 'a':
|
||||
return presentation_type::hexfloat_lower;
|
||||
case 'A':
|
||||
return presentation_type::hexfloat_upper;
|
||||
case 'e':
|
||||
return presentation_type::exp_lower;
|
||||
case 'E':
|
||||
return presentation_type::exp_upper;
|
||||
case 'f':
|
||||
return presentation_type::fixed_lower;
|
||||
case 'F':
|
||||
return presentation_type::fixed_upper;
|
||||
case 'g':
|
||||
return presentation_type::general_lower;
|
||||
case 'G':
|
||||
return presentation_type::general_upper;
|
||||
case 'c':
|
||||
return presentation_type::chr;
|
||||
case 's':
|
||||
return presentation_type::string;
|
||||
case 'p':
|
||||
return presentation_type::pointer;
|
||||
default:
|
||||
return presentation_type::none;
|
||||
}
|
||||
}
|
||||
|
||||
// Parses standard format specifiers and sends notifications about parsed
|
||||
// components to handler.
|
||||
template <typename Char, typename SpecHandler>
|
||||
@ -2336,7 +2398,10 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin,
|
||||
-> const Char* {
|
||||
if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) &&
|
||||
*begin != 'L') {
|
||||
handler.on_type(*begin++);
|
||||
presentation_type type = parse_presentation_type(*begin++);
|
||||
if (type == presentation_type::none)
|
||||
handler.on_error("invalid type specifier");
|
||||
handler.on_type(type);
|
||||
return begin;
|
||||
}
|
||||
|
||||
@ -2390,7 +2455,12 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin,
|
||||
}
|
||||
|
||||
// Parse type.
|
||||
if (begin != end && *begin != '}') handler.on_type(*begin++);
|
||||
if (begin != end && *begin != '}') {
|
||||
presentation_type type = parse_presentation_type(*begin++);
|
||||
if (type == presentation_type::none)
|
||||
handler.on_error("invalid type specifier");
|
||||
handler.on_type(type);
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
|
||||
@ -2532,28 +2602,18 @@ class compile_parse_context
|
||||
};
|
||||
|
||||
template <typename ErrorHandler>
|
||||
FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) {
|
||||
switch (spec) {
|
||||
case 0:
|
||||
case 'd':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'b':
|
||||
case 'B':
|
||||
case 'o':
|
||||
case 'c':
|
||||
break;
|
||||
default:
|
||||
FMT_CONSTEXPR void check_int_type_spec(presentation_type type,
|
||||
ErrorHandler&& eh) {
|
||||
if (type > presentation_type::bin_upper && type != presentation_type::chr)
|
||||
eh.on_error("invalid type specifier");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Checks char specs and returns true if the type spec is char (and not int).
|
||||
template <typename Char, typename ErrorHandler = error_handler>
|
||||
FMT_CONSTEXPR auto check_char_specs(const basic_format_specs<Char>& specs,
|
||||
ErrorHandler&& eh = {}) -> bool {
|
||||
if (specs.type && specs.type != 'c') {
|
||||
if (specs.type != presentation_type::none &&
|
||||
specs.type != presentation_type::chr) {
|
||||
check_int_type_spec(specs.type, eh);
|
||||
return false;
|
||||
}
|
||||
@ -2589,33 +2649,33 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs,
|
||||
result.showpoint = specs.alt;
|
||||
result.locale = specs.localized;
|
||||
switch (specs.type) {
|
||||
case 0:
|
||||
case presentation_type::none:
|
||||
result.format = float_format::general;
|
||||
break;
|
||||
case 'G':
|
||||
case presentation_type::general_upper:
|
||||
result.upper = true;
|
||||
FMT_FALLTHROUGH;
|
||||
case 'g':
|
||||
case presentation_type::general_lower:
|
||||
result.format = float_format::general;
|
||||
break;
|
||||
case 'E':
|
||||
case presentation_type::exp_upper:
|
||||
result.upper = true;
|
||||
FMT_FALLTHROUGH;
|
||||
case 'e':
|
||||
case presentation_type::exp_lower:
|
||||
result.format = float_format::exp;
|
||||
result.showpoint |= specs.precision != 0;
|
||||
break;
|
||||
case 'F':
|
||||
case presentation_type::fixed_upper:
|
||||
result.upper = true;
|
||||
FMT_FALLTHROUGH;
|
||||
case 'f':
|
||||
case presentation_type::fixed_lower:
|
||||
result.format = float_format::fixed;
|
||||
result.showpoint |= specs.precision != 0;
|
||||
break;
|
||||
case 'A':
|
||||
case presentation_type::hexfloat_upper:
|
||||
result.upper = true;
|
||||
FMT_FALLTHROUGH;
|
||||
case 'a':
|
||||
case presentation_type::hexfloat_lower:
|
||||
result.format = float_format::hex;
|
||||
break;
|
||||
default:
|
||||
@ -2625,22 +2685,27 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs,
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Char, typename ErrorHandler = error_handler>
|
||||
FMT_CONSTEXPR auto check_cstring_type_spec(Char spec, ErrorHandler&& eh = {})
|
||||
-> bool {
|
||||
if (spec == 0 || spec == 's') return true;
|
||||
if (spec != 'p') eh.on_error("invalid type specifier");
|
||||
template <typename ErrorHandler = error_handler>
|
||||
FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type,
|
||||
ErrorHandler&& eh = {}) -> bool {
|
||||
if (type == presentation_type::none || type == presentation_type::string)
|
||||
return true;
|
||||
if (type != presentation_type::pointer) eh.on_error("invalid type specifier");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Char, typename ErrorHandler = error_handler>
|
||||
FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh = {}) {
|
||||
if (spec != 0 && spec != 's') eh.on_error("invalid type specifier");
|
||||
template <typename ErrorHandler = error_handler>
|
||||
FMT_CONSTEXPR void check_string_type_spec(presentation_type type,
|
||||
ErrorHandler&& eh = {}) {
|
||||
if (type != presentation_type::none && type != presentation_type::string)
|
||||
eh.on_error("invalid type specifier");
|
||||
}
|
||||
|
||||
template <typename Char, typename ErrorHandler>
|
||||
FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
|
||||
if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier");
|
||||
template <typename ErrorHandler>
|
||||
FMT_CONSTEXPR void check_pointer_type_spec(presentation_type type,
|
||||
ErrorHandler&& eh) {
|
||||
if (type != presentation_type::none && type != presentation_type::pointer)
|
||||
eh.on_error("invalid type specifier");
|
||||
}
|
||||
|
||||
// A parse_format_specs handler that checks if specifiers are consistent with
|
||||
@ -2818,7 +2883,10 @@ struct formatter<T, Char,
|
||||
FMT_ASSERT(false, "invalid argument type");
|
||||
break;
|
||||
case detail::type::bool_type:
|
||||
if (!specs_.type || specs_.type == 's') break;
|
||||
if (specs_.type == presentation_type::none ||
|
||||
specs_.type == presentation_type::string) {
|
||||
break;
|
||||
}
|
||||
FMT_FALLTHROUGH;
|
||||
case detail::type::int_type:
|
||||
case detail::type::uint_type:
|
||||
|
@ -1558,10 +1558,10 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
|
||||
static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value, "");
|
||||
auto abs_value = arg.abs_value;
|
||||
auto prefix = arg.prefix;
|
||||
auto utype = static_cast<unsigned>(specs.type);
|
||||
switch (specs.type) {
|
||||
case 0:
|
||||
case 'd': {
|
||||
auto pres_type = static_cast<presentation_type>(specs.type);
|
||||
switch (pres_type) {
|
||||
case presentation_type::none:
|
||||
case presentation_type::dec: {
|
||||
if (specs.localized &&
|
||||
write_int_localized(out, static_cast<uint64_or_128_t<T>>(abs_value),
|
||||
prefix, specs, loc)) {
|
||||
@ -1573,38 +1573,40 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
|
||||
return format_decimal<Char>(it, abs_value, num_digits).end;
|
||||
});
|
||||
}
|
||||
case 'x':
|
||||
case 'X': {
|
||||
if (specs.alt) prefix_append(prefix, (utype << 8) | '0');
|
||||
bool upper = specs.type != 'x';
|
||||
case presentation_type::hex_lower:
|
||||
case presentation_type::hex_upper: {
|
||||
bool upper = pres_type == presentation_type::hex_upper;
|
||||
if (specs.alt)
|
||||
prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0');
|
||||
int num_digits = count_digits<4>(abs_value);
|
||||
return write_int(
|
||||
out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
|
||||
return format_uint<4, Char>(it, abs_value, num_digits, upper);
|
||||
});
|
||||
}
|
||||
case 'b':
|
||||
case 'B': {
|
||||
if (specs.alt) prefix_append(prefix, (utype << 8) | '0');
|
||||
case presentation_type::bin_lower:
|
||||
case presentation_type::bin_upper: {
|
||||
bool upper = pres_type == presentation_type::bin_upper;
|
||||
if (specs.alt)
|
||||
prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0');
|
||||
int num_digits = count_digits<1>(abs_value);
|
||||
return write_int(out, num_digits, prefix, specs,
|
||||
[=](reserve_iterator<OutputIt> it) {
|
||||
return format_uint<1, Char>(it, abs_value, num_digits);
|
||||
});
|
||||
}
|
||||
case 'o': {
|
||||
case presentation_type::oct: {
|
||||
int num_digits = count_digits<3>(abs_value);
|
||||
if (specs.alt && specs.precision <= num_digits && abs_value != 0) {
|
||||
// Octal prefix '0' is counted as a digit, so only add it if precision
|
||||
// is not greater than the number of digits.
|
||||
// Octal prefix '0' is counted as a digit, so only add it if precision
|
||||
// is not greater than the number of digits.
|
||||
if (specs.alt && specs.precision <= num_digits && abs_value != 0)
|
||||
prefix_append(prefix, '0');
|
||||
}
|
||||
return write_int(out, num_digits, prefix, specs,
|
||||
[=](reserve_iterator<OutputIt> it) {
|
||||
return format_uint<3, Char>(it, abs_value, num_digits);
|
||||
});
|
||||
}
|
||||
case 'c':
|
||||
case presentation_type::chr:
|
||||
return write_char(out, static_cast<Char>(abs_value), specs);
|
||||
default:
|
||||
FMT_THROW(format_error("invalid type specifier"));
|
||||
@ -1924,7 +1926,9 @@ auto write(OutputIt out, T value, basic_format_specs<Char> specs,
|
||||
return write_bytes<align::right>(out, {buffer.data(), buffer.size()},
|
||||
specs);
|
||||
}
|
||||
int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
|
||||
int precision = specs.precision >= 0 || specs.type == presentation_type::none
|
||||
? specs.precision
|
||||
: 6;
|
||||
if (fspecs.format == float_format::exp) {
|
||||
if (precision == max_value<int>())
|
||||
FMT_THROW(format_error("number is too big"));
|
||||
@ -2032,7 +2036,8 @@ template <typename Char, typename OutputIt, typename T,
|
||||
FMT_CONSTEXPR auto write(OutputIt out, T value,
|
||||
const basic_format_specs<Char>& specs = {},
|
||||
locale_ref = {}) -> OutputIt {
|
||||
return specs.type && specs.type != 's'
|
||||
return specs.type != presentation_type::none &&
|
||||
specs.type != presentation_type::string
|
||||
? write(out, value ? 1 : 0, specs, {})
|
||||
: write_bytes(out, value ? "true" : "false", specs);
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
||||
|
||||
OutputIt write_null_pointer(bool is_string = false) {
|
||||
auto s = this->specs;
|
||||
s.type = 0;
|
||||
s.type = presentation_type::none;
|
||||
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
|
||||
}
|
||||
|
||||
@ -249,8 +249,10 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
||||
// std::is_same instead.
|
||||
if (std::is_same<T, Char>::value) {
|
||||
format_specs fmt_specs = this->specs;
|
||||
if (fmt_specs.type && fmt_specs.type != 'c')
|
||||
if (fmt_specs.type != presentation_type::none &&
|
||||
fmt_specs.type != presentation_type::chr) {
|
||||
return (*this)(static_cast<int>(value));
|
||||
}
|
||||
fmt_specs.sign = sign::none;
|
||||
fmt_specs.alt = false;
|
||||
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
|
||||
@ -271,13 +273,13 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
||||
/** Formats a null-terminated C string. */
|
||||
OutputIt operator()(const char* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs.type != 'p');
|
||||
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||
}
|
||||
|
||||
/** Formats a null-terminated wide C string. */
|
||||
OutputIt operator()(const wchar_t* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs.type != 'p');
|
||||
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||
}
|
||||
|
||||
OutputIt operator()(basic_string_view<Char> value) {
|
||||
@ -490,13 +492,13 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
|
||||
// Parse type.
|
||||
if (it == end) FMT_THROW(format_error("invalid format string"));
|
||||
specs.type = static_cast<char>(*it++);
|
||||
char type = static_cast<char>(*it++);
|
||||
if (arg.is_integral()) {
|
||||
// Normalize type.
|
||||
switch (specs.type) {
|
||||
switch (type) {
|
||||
case 'i':
|
||||
case 'u':
|
||||
specs.type = 'd';
|
||||
type = 'd';
|
||||
break;
|
||||
case 'c':
|
||||
visit_format_arg(
|
||||
@ -505,6 +507,9 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
break;
|
||||
}
|
||||
}
|
||||
specs.type = parse_presentation_type(type);
|
||||
if (specs.type == presentation_type::none)
|
||||
parse_ctx.on_error("invalid type specifier");
|
||||
|
||||
start = it;
|
||||
|
||||
|
@ -524,7 +524,7 @@ struct test_format_specs_handler {
|
||||
fmt::detail::arg_ref<char> width_ref;
|
||||
int precision = 0;
|
||||
fmt::detail::arg_ref<char> precision_ref;
|
||||
char type = 0;
|
||||
fmt::presentation_type type = fmt::presentation_type::none;
|
||||
|
||||
// Workaround for MSVC2017 bug that results in "expression did not evaluate
|
||||
// to a constant" with compiler-generated copy ctor.
|
||||
@ -550,14 +550,14 @@ struct test_format_specs_handler {
|
||||
constexpr void on_dynamic_precision(string_view) {}
|
||||
|
||||
constexpr void end_precision() {}
|
||||
constexpr void on_type(char t) { type = t; }
|
||||
constexpr void on_type(fmt::presentation_type t) { type = t; }
|
||||
constexpr void on_error(const char*) { res = error; }
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
constexpr test_format_specs_handler parse_test_specs(const char (&s)[N]) {
|
||||
auto h = test_format_specs_handler();
|
||||
fmt::detail::parse_format_specs(s, s + N, h);
|
||||
fmt::detail::parse_format_specs(s, s + N - 1, h);
|
||||
return h;
|
||||
}
|
||||
|
||||
@ -575,7 +575,7 @@ TEST(core_test, constexpr_parse_format_specs) {
|
||||
static_assert(parse_test_specs("{42}").width_ref.val.index == 42, "");
|
||||
static_assert(parse_test_specs(".42").precision == 42, "");
|
||||
static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, "");
|
||||
static_assert(parse_test_specs("d").type == 'd', "");
|
||||
static_assert(parse_test_specs("d").type == fmt::presentation_type::dec, "");
|
||||
static_assert(parse_test_specs("{<").res == handler::error, "");
|
||||
}
|
||||
|
||||
@ -597,7 +597,7 @@ constexpr fmt::detail::dynamic_format_specs<char> parse_dynamic_specs(
|
||||
auto specs = fmt::detail::dynamic_format_specs<char>();
|
||||
auto ctx = test_parse_context();
|
||||
auto h = fmt::detail::dynamic_specs_handler<test_parse_context>(specs, ctx);
|
||||
parse_format_specs(s, s + N, h);
|
||||
parse_format_specs(s, s + N - 1, h);
|
||||
return specs;
|
||||
}
|
||||
|
||||
@ -615,14 +615,15 @@ TEST(format_test, constexpr_dynamic_specs_handler) {
|
||||
static_assert(parse_dynamic_specs(".42").precision == 42, "");
|
||||
static_assert(parse_dynamic_specs(".{}").precision_ref.val.index == 11, "");
|
||||
static_assert(parse_dynamic_specs(".{42}").precision_ref.val.index == 42, "");
|
||||
static_assert(parse_dynamic_specs("d").type == 'd', "");
|
||||
static_assert(parse_dynamic_specs("d").type == fmt::presentation_type::dec,
|
||||
"");
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
constexpr test_format_specs_handler check_specs(const char (&s)[N]) {
|
||||
fmt::detail::specs_checker<test_format_specs_handler> checker(
|
||||
test_format_specs_handler(), fmt::detail::type::double_type);
|
||||
parse_format_specs(s, s + N, checker);
|
||||
parse_format_specs(s, s + N - 1, checker);
|
||||
return checker;
|
||||
}
|
||||
|
||||
@ -639,7 +640,7 @@ TEST(format_test, constexpr_specs_checker) {
|
||||
static_assert(check_specs("{42}").width_ref.val.index == 42, "");
|
||||
static_assert(check_specs(".42").precision == 42, "");
|
||||
static_assert(check_specs(".{42}").precision_ref.val.index == 42, "");
|
||||
static_assert(check_specs("d").type == 'd', "");
|
||||
static_assert(check_specs("d").type == fmt::presentation_type::dec, "");
|
||||
static_assert(check_specs("{<").res == handler::error, "");
|
||||
}
|
||||
|
||||
|
@ -555,7 +555,7 @@ TEST(format_test, fill) {
|
||||
fmt::format(string_view("{:\0>4}", 6), '*'));
|
||||
EXPECT_EQ("жж42", fmt::format("{0:ж>4}", 42));
|
||||
EXPECT_THROW_MSG(fmt::format(runtime("{:\x80\x80\x80\x80\x80>}"), 0),
|
||||
format_error, "missing '}' in format string");
|
||||
format_error, "invalid type specifier");
|
||||
}
|
||||
|
||||
TEST(format_test, plus_sign) {
|
||||
@ -1037,7 +1037,7 @@ void check_unknown_types(const T& value, const char* types, const char*) {
|
||||
|
||||
TEST(format_test, format_int) {
|
||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:v"), 42), format_error,
|
||||
"missing '}' in format string");
|
||||
"invalid type specifier");
|
||||
check_unknown_types(42, "bBdoxXnLc", "integer");
|
||||
EXPECT_EQ("x", fmt::format("{:c}", static_cast<int>('x')));
|
||||
}
|
||||
|
@ -29,7 +29,8 @@ void invoke_fmt(const uint8_t* data, size_t size, unsigned arg_name_size) {
|
||||
fmt::format(format_str.get(), fmt::arg(arg_name.data(), value));
|
||||
#else
|
||||
fmt::memory_buffer out;
|
||||
fmt::format_to(out, format_str.get(), fmt::arg(arg_name.data(), value));
|
||||
fmt::format_to(std::back_inserter(out), format_str.get(),
|
||||
fmt::arg(arg_name.data(), value));
|
||||
#endif
|
||||
} catch (std::exception&) {
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ template <class charT> struct formatter<std::complex<double>, charT> {
|
||||
specs_.precision, specs_.precision_ref, ctx);
|
||||
auto specs = std::string();
|
||||
if (specs_.precision > 0) specs = fmt::format(".{}", specs_.precision);
|
||||
if (specs_.type) specs += specs_.type;
|
||||
if (specs_.type == presentation_type::fixed_lower) specs += 'f';
|
||||
auto real = fmt::format(ctx.locale().template get<std::locale>(),
|
||||
fmt::runtime("{:" + specs + "}"), c.real());
|
||||
auto imag = fmt::format(ctx.locale().template get<std::locale>(),
|
||||
|
Loading…
Reference in New Issue
Block a user