mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-29 00:35:03 +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;
|
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.
|
// Parses fill and alignment.
|
||||||
template <typename Char, typename Handler>
|
template <typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
|
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);
|
auto p = next_code_point(begin, end);
|
||||||
if (p == end) p = begin;
|
if (p == end) p = begin;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch (static_cast<int>(*p)) {
|
switch (to_integral(*p)) {
|
||||||
case '<':
|
case '<':
|
||||||
align = align::left;
|
align = align::left;
|
||||||
break;
|
break;
|
||||||
@ -2831,7 +2842,7 @@ FMT_CONSTEXPR const Char* parse_format_specs(const Char* begin, const Char* end,
|
|||||||
if (begin == end) return begin;
|
if (begin == end) return begin;
|
||||||
|
|
||||||
// Parse sign.
|
// Parse sign.
|
||||||
switch (static_cast<char>(*begin)) {
|
switch (to_integral(*begin)) {
|
||||||
case '+':
|
case '+':
|
||||||
handler.on_plus();
|
handler.on_plus();
|
||||||
++begin;
|
++begin;
|
||||||
@ -2908,7 +2919,7 @@ FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin,
|
|||||||
Handler&& handler) {
|
Handler&& handler) {
|
||||||
++begin;
|
++begin;
|
||||||
if (begin == end) return handler.on_error("invalid format string"), end;
|
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);
|
handler.on_replacement_field(handler.on_arg_id(), begin);
|
||||||
} else if (*begin == '{') {
|
} else if (*begin == '{') {
|
||||||
handler.on_text(begin, begin + 1);
|
handler.on_text(begin, begin + 1);
|
||||||
|
@ -719,6 +719,17 @@ TEST(FormatterTest, SpaceSign) {
|
|||||||
"format specifier requires numeric argument");
|
"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) {
|
TEST(FormatterTest, HashFlag) {
|
||||||
EXPECT_EQ("42", format("{0:#}", 42));
|
EXPECT_EQ("42", format("{0:#}", 42));
|
||||||
EXPECT_EQ("-42", format("{0:#}", -42));
|
EXPECT_EQ("-42", format("{0:#}", -42));
|
||||||
@ -2462,24 +2473,26 @@ TEST(FormatTest, CharTraitsIsNotAmbiguous) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mychar {
|
struct custom_char {
|
||||||
int value;
|
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; }
|
operator int() const { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int to_integral(custom_char c) { return c; }
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template <> struct is_char<mychar> : std::true_type {};
|
template <> struct is_char<custom_char> : std::true_type {};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(FormatTest, FormatCustomChar) {
|
TEST(FormatTest, FormatCustomChar) {
|
||||||
const mychar format[] = {'{', '}', 0};
|
const custom_char format[] = {'{', '}', 0};
|
||||||
auto result = fmt::format(format, mychar('x'));
|
auto result = fmt::format(format, custom_char('x'));
|
||||||
EXPECT_EQ(result.size(), 1);
|
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
|
// Convert a char8_t string to std::string. Otherwise GTest will insist on
|
||||||
|
Loading…
Reference in New Issue
Block a user