Refactor locale handling

This commit is contained in:
Victor Zverovich
2021-07-05 08:12:39 -07:00
parent 7a0d301753
commit c4a3c2342a

View File

@@ -1393,56 +1393,74 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits,
}); });
} }
template <typename Char> class digit_grouping {
private:
thousands_sep_result<Char> sep_;
std::string::const_iterator group_;
int pos_;
public:
explicit digit_grouping(locale_ref loc) {
if (loc) {
sep_ = thousands_sep<Char>(loc);
reset();
} else {
sep_.thousands_sep = Char();
}
}
void reset() {
group_ = sep_.grouping.begin();
pos_ = 0;
}
// Returns the next digit group separator position.
int next() {
if (!sep_.thousands_sep) return max_value<int>();
if (group_ == sep_.grouping.end()) return pos_ += sep_.grouping.back();
if (*group_ <= 0 || *group_ == max_value<char>()) return max_value<int>();
pos_ += *group_++;
return pos_;
}
int count_separators(int num_digits) {
int count = 0;
while (num_digits > next()) ++count;
reset();
return count;
}
Char separator() const { return sep_.thousands_sep; }
};
template <typename OutputIt, typename UInt, typename Char> template <typename OutputIt, typename UInt, typename Char>
auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, auto write_int_localized(OutputIt& out, UInt value, unsigned prefix,
const basic_format_specs<Char>& specs, locale_ref loc) const basic_format_specs<Char>& specs, locale_ref loc)
-> bool { -> bool {
static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, ""); static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, "");
const auto sep_size = 1;
auto ts = thousands_sep<Char>(loc);
if (!ts.thousands_sep) return false;
int num_digits = count_digits(value); int num_digits = count_digits(value);
int size = num_digits, n = num_digits;
const std::string& groups = ts.grouping;
std::string::const_iterator group = groups.cbegin();
while (group != groups.cend() && n > *group && *group > 0 &&
*group != max_value<char>()) {
size += sep_size;
n -= *group;
++group;
}
if (group == groups.cend()) size += sep_size * ((n - 1) / groups.back());
char digits[40]; char digits[40];
format_decimal(digits, value, num_digits); format_decimal(digits, value, num_digits);
basic_memory_buffer<Char> buffer;
if (prefix != 0) ++size; auto grouping = digit_grouping<Char>(loc);
const auto usize = to_unsigned(size); unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits +
buffer.resize(usize); grouping.count_separators(num_digits));
basic_string_view<Char> s(&ts.thousands_sep, sep_size); auto buffer = basic_memory_buffer<Char>();
// Index of a decimal digit with the least significant digit having index 0. buffer.resize(size);
int digit_index = 0; int separator_pos = grouping.next();
group = groups.cbegin(); auto p = buffer.data() + size;
auto p = buffer.data() + size - 1; for (int i = 0; i < num_digits; ++i) {
for (int i = num_digits - 1; i > 0; --i) { if (i == separator_pos) {
*p-- = static_cast<Char>(digits[i]); *--p = grouping.separator();
if (*group <= 0 || ++digit_index % *group != 0 || separator_pos = grouping.next();
*group == max_value<char>())
continue;
if (group + 1 != groups.cend()) {
digit_index = 0;
++group;
} }
std::uninitialized_copy(s.data(), s.data() + s.size(), *--p = static_cast<Char>(digits[num_digits - i - 1]);
make_checked(p, s.size()));
p -= s.size();
} }
*p-- = static_cast<Char>(*digits); if (prefix != 0) *--p = static_cast<Char>(prefix);
if (prefix != 0) *p = static_cast<Char>(prefix); out = write_padded<align::right>(out, specs, size, size,
auto data = buffer.data(); [=](reserve_iterator<OutputIt> it) {
out = write_padded<align::right>( return copy_str<Char>(p, p + size, it);
out, specs, usize, usize, [=](reserve_iterator<OutputIt> it) { });
return copy_str<Char>(data, data + size, it);
});
return true; return true;
} }
@@ -1669,7 +1687,7 @@ inline auto write_significand(OutputIt out, const char* significand,
template <typename OutputIt, typename DecimalFP, typename Char> template <typename OutputIt, typename DecimalFP, typename Char>
auto write_float(OutputIt out, const DecimalFP& fp, auto write_float(OutputIt out, const DecimalFP& fp,
const basic_format_specs<Char>& specs, float_specs fspecs, const basic_format_specs<Char>& specs, float_specs fspecs,
Char decimal_point) -> OutputIt { locale_ref loc) -> OutputIt {
auto significand = fp.significand; auto significand = fp.significand;
int significand_size = get_significand_size(fp); int significand_size = get_significand_size(fp);
static const Char zero = static_cast<Char>('0'); static const Char zero = static_cast<Char>('0');
@@ -1677,6 +1695,9 @@ auto write_float(OutputIt out, const DecimalFP& fp,
size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); size_t size = to_unsigned(significand_size) + (sign ? 1 : 0);
using iterator = reserve_iterator<OutputIt>; using iterator = reserve_iterator<OutputIt>;
Char decimal_point =
fspecs.locale ? detail::decimal_point<Char>(loc) : static_cast<Char>('.');
int output_exp = fp.exponent + significand_size - 1; int output_exp = fp.exponent + significand_size - 1;
auto use_exp_format = [=]() { auto use_exp_format = [=]() {
if (fspecs.format == float_format::exp) return true; if (fspecs.format == float_format::exp) return true;
@@ -1808,10 +1829,8 @@ auto write(OutputIt out, T value, basic_format_specs<Char> specs,
fspecs.use_grisu = is_fast_float<T>(); fspecs.use_grisu = is_fast_float<T>();
int exp = format_float(promote_float(value), precision, fspecs, buffer); int exp = format_float(promote_float(value), precision, fspecs, buffer);
fspecs.precision = precision; fspecs.precision = precision;
Char point =
fspecs.locale ? decimal_point<Char>(loc) : static_cast<Char>('.');
auto fp = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp}; auto fp = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp};
return write_float(out, fp, specs, fspecs, point); return write_float(out, fp, specs, fspecs, loc);
} }
template <typename Char, typename OutputIt, typename T, template <typename Char, typename OutputIt, typename T,
@@ -1836,7 +1855,7 @@ auto write(OutputIt out, T value) -> OutputIt {
return write_nonfinite(out, std::isinf(value), specs, fspecs); return write_nonfinite(out, std::isinf(value), specs, fspecs);
auto dec = dragonbox::to_decimal(static_cast<floaty>(value)); auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
return write_float(out, dec, specs, fspecs, static_cast<Char>('.')); return write_float(out, dec, specs, fspecs, {});
} }
template <typename Char, typename OutputIt, typename T, template <typename Char, typename OutputIt, typename T,