Add localized formatting to non-decimal presentation types of ints (#3750)

This commit is contained in:
js324 2023-12-15 10:51:25 -05:00 committed by GitHub
parent 5471a2426c
commit 6025bd7c37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 16 deletions

View File

@ -2113,24 +2113,66 @@ template <typename Char> class digit_grouping {
} }
}; };
FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) {
prefix |= prefix != 0 ? value << 8 : value;
prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
}
// Writes a decimal integer with digit grouping. // Writes a decimal integer with digit grouping.
template <typename OutputIt, typename UInt, typename Char> template <typename OutputIt, typename UInt, typename Char>
auto write_int(OutputIt out, UInt value, unsigned prefix, auto write_int(OutputIt out, UInt value, unsigned prefix,
const format_specs<Char>& specs, const format_specs<Char>& specs,
const digit_grouping<Char>& grouping) -> OutputIt { const digit_grouping<Char>& grouping) -> OutputIt {
static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, ""); static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, "");
int num_digits = count_digits(value); int num_digits = 0;
char digits[40]; auto buffer = memory_buffer();
format_decimal(digits, value, num_digits); switch (specs.type) {
unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits + case presentation_type::none:
grouping.count_separators(num_digits)); case presentation_type::dec: {
num_digits = count_digits(value);
format_decimal<Char>(appender(buffer), value, num_digits);
break;
}
case presentation_type::hex_lower:
case presentation_type::hex_upper: {
bool upper = specs.type == presentation_type::hex_upper;
if (specs.alt)
prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0');
num_digits = count_digits<4>(value);
format_uint<4,Char>(appender(buffer), value, num_digits, upper);
break;
}
case presentation_type::bin_lower:
case presentation_type::bin_upper: {
bool upper = specs.type == presentation_type::bin_upper;
if (specs.alt)
prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0');
num_digits = count_digits<1>(value);
format_uint<1,Char>(appender(buffer), value, num_digits);
break;
}
case presentation_type::oct: {
num_digits = count_digits<3>(value);
// 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 && value != 0)
prefix_append(prefix, '0');
format_uint<3,Char>(appender(buffer), value, num_digits);
break;
}
case presentation_type::chr:
return write_char(out, static_cast<Char>(value), specs);
default:
throw_format_error("invalid format specifier");
}
unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) +
to_unsigned(grouping.count_separators(num_digits));
return write_padded<align::right>( return write_padded<align::right>(
out, specs, size, size, [&](reserve_iterator<OutputIt> it) { out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
if (prefix != 0) { for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8)
char sign = static_cast<char>(prefix); *it++ = static_cast<Char>(p & 0xff);
*it++ = static_cast<Char>(sign); return grouping.apply(it, string_view(buffer.data(), buffer.size()));
}
return grouping.apply(it, string_view(digits, to_unsigned(num_digits)));
}); });
} }
@ -2143,11 +2185,6 @@ inline auto write_loc(OutputIt, loc_value, const format_specs<Char>&,
return false; return false;
} }
FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) {
prefix |= prefix != 0 ? value << 8 : value;
prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
}
template <typename UInt> struct write_int_arg { template <typename UInt> struct write_int_arg {
UInt abs_value; UInt abs_value;
unsigned prefix; unsigned prefix;

View File

@ -2297,6 +2297,14 @@ TEST(format_test, format_named_arg_with_locale) {
"42"); "42");
} }
TEST(format_test, format_locale) {
auto loc =
std::locale({}, new fmt::format_facet<std::locale>(","));
EXPECT_EQ("7,5bc,d15", fmt::format(loc, "{:Lx}", 123456789));
EXPECT_EQ("-0b111,010,110,111,100,110,100,010,101", fmt::format(loc, "{:#Lb}", -123456789));
EXPECT_EQ(" 30,071", fmt::format(loc, "{:10Lo}", 12345));
}
#endif // FMT_STATIC_THOUSANDS_SEPARATOR #endif // FMT_STATIC_THOUSANDS_SEPARATOR
struct convertible_to_nonconst_cstring { struct convertible_to_nonconst_cstring {