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