mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-27 21:31:20 +00:00
Fix handling of weird character types when parsing sign (#1932)
This commit is contained in:
parent
08370c39ff
commit
20d4f2e836
@ -2737,6 +2737,17 @@ FMT_CONSTEXPR const Char* next_code_point(const Char* begin, const Char* end) {
|
||||
return begin;
|
||||
}
|
||||
|
||||
// Converts a character to the underlying integral type.
|
||||
template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
|
||||
constexpr Char to_integral(Char value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
|
||||
constexpr typename std::underlying_type<Char>::type to_integral(Char value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// Parses fill and alignment.
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
|
||||
@ -2746,7 +2757,7 @@ FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
|
||||
auto p = next_code_point(begin, end);
|
||||
if (p == end) p = begin;
|
||||
for (;;) {
|
||||
switch (static_cast<int>(*p)) {
|
||||
switch (to_integral(*p)) {
|
||||
case '<':
|
||||
align = align::left;
|
||||
break;
|
||||
@ -2831,7 +2842,7 @@ FMT_CONSTEXPR const Char* parse_format_specs(const Char* begin, const Char* end,
|
||||
if (begin == end) return begin;
|
||||
|
||||
// Parse sign.
|
||||
switch (static_cast<char>(*begin)) {
|
||||
switch (to_integral(*begin)) {
|
||||
case '+':
|
||||
handler.on_plus();
|
||||
++begin;
|
||||
@ -2908,7 +2919,7 @@ FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin,
|
||||
Handler&& handler) {
|
||||
++begin;
|
||||
if (begin == end) return handler.on_error("invalid format string"), end;
|
||||
if (static_cast<char>(*begin) == '}') {
|
||||
if (*begin == '}') {
|
||||
handler.on_replacement_field(handler.on_arg_id(), begin);
|
||||
} else if (*begin == '{') {
|
||||
handler.on_text(begin, begin + 1);
|
||||
|
@ -719,6 +719,17 @@ TEST(FormatterTest, SpaceSign) {
|
||||
"format specifier requires numeric argument");
|
||||
}
|
||||
|
||||
TEST(FormatterTest, SignNotTruncated) {
|
||||
wchar_t format_str[] = {
|
||||
L'{',
|
||||
L':',
|
||||
'+' | (1 << fmt::detail::num_bits<char>()),
|
||||
L'}',
|
||||
0
|
||||
};
|
||||
EXPECT_THROW(format(format_str, 42), format_error);
|
||||
}
|
||||
|
||||
TEST(FormatterTest, HashFlag) {
|
||||
EXPECT_EQ("42", format("{0:#}", 42));
|
||||
EXPECT_EQ("-42", format("{0:#}", -42));
|
||||
@ -2462,24 +2473,26 @@ TEST(FormatTest, CharTraitsIsNotAmbiguous) {
|
||||
#endif
|
||||
}
|
||||
|
||||
struct mychar {
|
||||
struct custom_char {
|
||||
int value;
|
||||
mychar() = default;
|
||||
custom_char() = default;
|
||||
|
||||
template <typename T> mychar(T val) : value(static_cast<int>(val)) {}
|
||||
template <typename T> custom_char(T val) : value(static_cast<int>(val)) {}
|
||||
|
||||
operator int() const { return value; }
|
||||
};
|
||||
|
||||
int to_integral(custom_char c) { return c; }
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct is_char<mychar> : std::true_type {};
|
||||
template <> struct is_char<custom_char> : std::true_type {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(FormatTest, FormatCustomChar) {
|
||||
const mychar format[] = {'{', '}', 0};
|
||||
auto result = fmt::format(format, mychar('x'));
|
||||
const custom_char format[] = {'{', '}', 0};
|
||||
auto result = fmt::format(format, custom_char('x'));
|
||||
EXPECT_EQ(result.size(), 1);
|
||||
EXPECT_EQ(result[0], mychar('x'));
|
||||
EXPECT_EQ(result[0], custom_char('x'));
|
||||
}
|
||||
|
||||
// Convert a char8_t string to std::string. Otherwise GTest will insist on
|
||||
|
Loading…
Reference in New Issue
Block a user