add locale formatting to non-decimal numerics
This commit is contained in:
parent
f575089243
commit
d1ac2bb26d
@ -794,13 +794,13 @@ inline auto code_point_index(string_view s, size_t n) -> size_t {
|
|||||||
size_t result = s.size();
|
size_t result = s.size();
|
||||||
const char* begin = s.begin();
|
const char* begin = s.begin();
|
||||||
for_each_codepoint(s, [begin, &n, &result](uint32_t, string_view sv) {
|
for_each_codepoint(s, [begin, &n, &result](uint32_t, string_view sv) {
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
--n;
|
--n;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
result = to_unsigned(sv.begin() - begin);
|
result = to_unsigned(sv.begin() - begin);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2113,23 +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);
|
|
||||||
char digits[40];
|
char digits[40];
|
||||||
format_decimal(digits, value, num_digits);
|
int num_digits;
|
||||||
unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits +
|
|
||||||
|
switch (specs.type) {
|
||||||
|
case presentation_type::none:
|
||||||
|
case presentation_type::dec: {
|
||||||
|
num_digits = count_digits(value);
|
||||||
|
format_decimal(digits, 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>(digits, 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>(digits, 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>(digits, 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 = to_unsigned((prefix != 0 ? prefix >> 24 : 0) + num_digits +
|
||||||
grouping.count_separators(num_digits));
|
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(digits, to_unsigned(num_digits)));
|
return grouping.apply(it, string_view(digits, to_unsigned(num_digits)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2143,11 +2186,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;
|
||||||
|
|||||||
@ -1333,6 +1333,9 @@ TEST(format_test, format_oct) {
|
|||||||
|
|
||||||
TEST(format_test, format_int_locale) {
|
TEST(format_test, format_int_locale) {
|
||||||
EXPECT_EQ("1234", fmt::format("{:L}", 1234));
|
EXPECT_EQ("1234", fmt::format("{:L}", 1234));
|
||||||
|
EXPECT_EQ("7,5bc,d15", fmt::format(std::locale("en_US.UTF-8"), "{:Lx}", 123456789));
|
||||||
|
EXPECT_EQ("-0b111,010,110,111,100,110,100,010,101", fmt::format(std::locale("en_US.UTF-8"), "{:#Lb}", -123456789));
|
||||||
|
EXPECT_EQ(" 24", fmt::format(std::locale("en_US.UTF-8"), "{:10Lo}", 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_float) {
|
TEST(format_test, format_float) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user