From 9cc7edfddce6ad0ec7310b1f2afd8802d8d51555 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 3 May 2020 17:34:48 -0700 Subject: [PATCH] Move int_writer to the namespace scope --- include/fmt/format.h | 268 +++++++++++++++++++++---------------------- 1 file changed, 132 insertions(+), 136 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 2dc540f2..6da2bfba 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1448,6 +1448,135 @@ OutputIt write_int(OutputIt out, int num_digits, string_view prefix, }); } +// The handle_int_type_spec handler that writes an integer. +template struct int_writer { + OutputIt out; + locale_ref locale; + const basic_format_specs& specs; + UInt abs_value; + char prefix[4]; + unsigned prefix_size; + + using iterator = + remove_reference_t(), 0))>; + + string_view get_prefix() const { return string_view(prefix, prefix_size); } + + template + int_writer(OutputIt output, locale_ref loc, Int value, + const basic_format_specs& s) + : out(output), + locale(loc), + specs(s), + abs_value(static_cast(value)), + prefix_size(0) { + static_assert(std::is_same, UInt>::value, ""); + if (is_negative(value)) { + prefix[0] = '-'; + ++prefix_size; + abs_value = 0 - abs_value; + } else if (specs.sign != sign::none && specs.sign != sign::minus) { + prefix[0] = specs.sign == sign::plus ? '+' : ' '; + ++prefix_size; + } + } + + void on_dec() { + auto num_digits = count_digits(abs_value); + out = write_int(out, num_digits, get_prefix(), specs, [=](iterator it) { + return format_decimal(it, abs_value, num_digits); + }); + } + + void on_hex() { + if (specs.alt) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = specs.type; + } + int num_digits = count_digits<4>(abs_value); + out = write_int(out, num_digits, get_prefix(), specs, [=](iterator it) { + return format_uint<4, Char>(it, abs_value, num_digits, specs.type != 'x'); + }); + } + + void on_bin() { + if (specs.alt) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = static_cast(specs.type); + } + int num_digits = count_digits<1>(abs_value); + out = write_int(out, num_digits, get_prefix(), specs, [=](iterator it) { + return format_uint<1, Char>(it, abs_value, num_digits); + }); + } + + void on_oct() { + int num_digits = count_digits<3>(abs_value); + if (specs.alt && specs.precision <= num_digits && abs_value != 0) { + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + prefix[prefix_size++] = '0'; + } + out = write_int(out, num_digits, get_prefix(), specs, [=](iterator it) { + return format_uint<3, Char>(it, abs_value, num_digits); + }); + } + + enum { sep_size = 1 }; + + struct num_writer { + UInt abs_value; + int size; + const std::string& groups; + Char sep; + + template It operator()(It it) const { + basic_string_view s(&sep, sep_size); + // Index of a decimal digit with the least significant digit having + // index 0. + int digit_index = 0; + std::string::const_iterator group = groups.cbegin(); + return format_decimal( + it, abs_value, size, [this, s, &group, &digit_index](Char*& buffer) { + if (*group <= 0 || ++digit_index % *group != 0 || + *group == max_value()) + return; + if (group + 1 != groups.cend()) { + digit_index = 0; + ++group; + } + buffer -= s.size(); + std::uninitialized_copy(s.data(), s.data() + s.size(), + make_checked(buffer, s.size())); + }); + } + }; + + void on_num() { + std::string groups = grouping(locale); + if (groups.empty()) return on_dec(); + auto sep = thousands_sep(locale); + if (!sep) return on_dec(); + int num_digits = count_digits(abs_value); + int size = num_digits; + std::string::const_iterator group = groups.cbegin(); + while (group != groups.cend() && num_digits > *group && *group > 0 && + *group != max_value()) { + size += sep_size; + num_digits -= *group; + ++group; + } + if (group == groups.cend()) + size += sep_size * ((num_digits - 1) / groups.back()); + out = write_int(out, size, get_prefix(), specs, + num_writer{abs_value, size, groups, sep}); + } + + FMT_NORETURN void on_error() { + FMT_THROW(format_error("invalid type specifier")); + } +}; + // This template provides operations for formatting and writing data into a // character range. template class basic_writer { @@ -1478,141 +1607,6 @@ template class basic_writer { it = format_decimal(it, abs_value, num_digits); } - // The handle_int_type_spec handler that writes an integer. - template struct int_writer { - basic_writer& writer; - const basic_format_specs& specs; - UInt abs_value; - char prefix[4]; - unsigned prefix_size; - - string_view get_prefix() const { return string_view(prefix, prefix_size); } - - template - int_writer(basic_writer& w, Int value, - const basic_format_specs& s) - : writer(w), - specs(s), - abs_value(static_cast(value)), - prefix_size(0) { - static_assert(std::is_same, UInt>::value, ""); - if (is_negative(value)) { - prefix[0] = '-'; - ++prefix_size; - abs_value = 0 - abs_value; - } else if (specs.sign != sign::none && specs.sign != sign::minus) { - prefix[0] = specs.sign == sign::plus ? '+' : ' '; - ++prefix_size; - } - } - - void on_dec() { - auto num_digits = count_digits(abs_value); - writer.out_ = internal::write_int(writer.out_, num_digits, get_prefix(), - specs, [=](reserve_iterator it) { - return format_decimal( - it, abs_value, num_digits); - }); - } - - void on_hex() { - if (specs.alt) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = specs.type; - } - int num_digits = count_digits<4>(abs_value); - writer.out_ = internal::write_int(writer.out_, num_digits, get_prefix(), - specs, [=](reserve_iterator it) { - return format_uint<4, char_type>( - it, abs_value, num_digits, - specs.type != 'x'); - }); - } - - void on_bin() { - if (specs.alt) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = static_cast(specs.type); - } - int num_digits = count_digits<1>(abs_value); - writer.out_ = internal::write_int(writer.out_, num_digits, get_prefix(), - specs, [=](reserve_iterator it) { - return format_uint<1, char_type>( - it, abs_value, num_digits); - }); - } - - void on_oct() { - int num_digits = count_digits<3>(abs_value); - if (specs.alt && specs.precision <= num_digits && abs_value != 0) { - // Octal prefix '0' is counted as a digit, so only add it if precision - // is not greater than the number of digits. - prefix[prefix_size++] = '0'; - } - writer.out_ = internal::write_int(writer.out_, num_digits, get_prefix(), - specs, [=](reserve_iterator it) { - return format_uint<3, char_type>( - it, abs_value, num_digits); - }); - } - - enum { sep_size = 1 }; - - struct num_writer { - UInt abs_value; - int size; - const std::string& groups; - char_type sep; - - template It operator()(It it) const { - basic_string_view s(&sep, sep_size); - // Index of a decimal digit with the least significant digit having - // index 0. - int digit_index = 0; - std::string::const_iterator group = groups.cbegin(); - return format_decimal( - it, abs_value, size, - [this, s, &group, &digit_index](char_type*& buffer) { - if (*group <= 0 || ++digit_index % *group != 0 || - *group == max_value()) - return; - if (group + 1 != groups.cend()) { - digit_index = 0; - ++group; - } - buffer -= s.size(); - std::uninitialized_copy(s.data(), s.data() + s.size(), - make_checked(buffer, s.size())); - }); - } - }; - - void on_num() { - std::string groups = grouping(writer.locale_); - if (groups.empty()) return on_dec(); - auto sep = thousands_sep(writer.locale_); - if (!sep) return on_dec(); - int num_digits = count_digits(abs_value); - int size = num_digits; - std::string::const_iterator group = groups.cbegin(); - while (group != groups.cend() && num_digits > *group && *group > 0 && - *group != max_value()) { - size += sep_size; - num_digits -= *group; - ++group; - } - if (group == groups.cend()) - size += sep_size * ((num_digits - 1) / groups.back()); - writer.out_ = - internal::write_int(writer.out_, size, get_prefix(), specs, - num_writer{abs_value, size, groups, sep}); - } - - FMT_NORETURN void on_error() { - FMT_THROW(format_error("invalid type specifier")); - } - }; - using reserve_iterator = remove_reference_t(), 0))>; @@ -1637,7 +1631,9 @@ template class basic_writer { template void write_int(T value, const format_specs& spec) { using uint_type = uint32_or_64_or_128_t; - handle_int_type_spec(spec.type, int_writer(*this, value, spec)); + int_writer w(out_, locale_, value, spec); + handle_int_type_spec(spec.type, w); + out_ = w.out; } template ::value)>