From 1f8f5450b576ccb92617b50fa5f1ec71aab5220a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 14 Jun 2020 07:42:52 -0700 Subject: [PATCH] Reuse format_decimal --- include/fmt/chrono.h | 2 +- include/fmt/format.h | 66 +++++++++++++++++++------------------------- 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 2325c25e..e70b8053 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -882,7 +882,7 @@ struct chrono_formatter { to_unsigned(to_nonnegative_int(value, max_value())); int num_digits = detail::count_digits(n); if (width > num_digits) out = std::fill_n(out, width - num_digits, '0'); - out = format_decimal(out, n, num_digits); + out = format_decimal(out, n, num_digits).end; } void write_nan() { std::copy_n("nan", 3, out); } diff --git a/include/fmt/format.h b/include/fmt/format.h index 84c56ddd..400acab5 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -884,11 +884,19 @@ template void copy2(Char* dst, const char* src) { } inline void copy2(char* dst, const char* src) { memcpy(dst, src, 2); } -// Formats a decimal unsigned integer value writing into out. +template struct format_decimal_result { + Iterator begin; + Iterator end; +}; + +// Formats a decimal unsigned integer value writing into out pointing to a +// buffer of specified size. The caller must ensure that the buffer is large +// enough. template -inline Char* format_decimal(Char* out, UInt value, int num_digits) { - FMT_ASSERT(num_digits >= 0, "invalid digit count"); - out += num_digits; +inline format_decimal_result format_decimal(Char* out, UInt value, + int size) { + FMT_ASSERT(size >= count_digits(value), "invalid digit count"); + out += size; Char* end = out; while (value >= 100) { // Integer division is slow so do it for a group of two digits instead @@ -900,20 +908,22 @@ inline Char* format_decimal(Char* out, UInt value, int num_digits) { } if (value < 10) { *--out = static_cast('0' + value); - return end; + return {out, end}; } - copy2(out - 2, data::digits + static_cast(value * 2)); - return end; + out -= 2; + copy2(out, data::digits + static_cast(value * 2)); + return {out, end}; } template >::value)> -inline Iterator format_decimal(Iterator out, UInt value, int num_digits) { +inline format_decimal_result format_decimal(Iterator out, UInt value, + int num_digits) { // Buffer should be large enough to hold all digits (<= digits10 + 1). enum { max_size = digits10() + 1 }; Char buffer[2 * max_size]; - auto end = format_decimal(buffer, value, num_digits); - return detail::copy_str(buffer, end, out); + auto end = format_decimal(buffer, value, num_digits).end; + return {out, detail::copy_str(buffer, end, out)}; } template @@ -1488,10 +1498,10 @@ template struct int_writer { void on_dec() { auto num_digits = count_digits(abs_value); - out = write_int(out, num_digits, get_prefix(), specs, - [this, num_digits](iterator it) { - return format_decimal(it, abs_value, num_digits); - }); + out = write_int( + out, num_digits, get_prefix(), specs, [this, num_digits](iterator it) { + return format_decimal(it, abs_value, num_digits).end; + }); } void on_hex() { @@ -1710,7 +1720,7 @@ OutputIt write(OutputIt out, T value) { int num_digits = count_digits(abs_value); auto it = reserve(out, (negative ? 1 : 0) + static_cast(num_digits)); if (negative) *it++ = static_cast('-'); - it = format_decimal(it, abs_value, num_digits); + it = format_decimal(it, abs_value, num_digits).end; return base_iterator(out, it); } @@ -2546,8 +2556,9 @@ template struct id_adapter { }; template -FMT_CONSTEXPR const Char* parse_replacement_field( - const Char* begin, const Char* end, Handler&& handler) { +FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin, + const Char* end, + Handler&& handler) { ++begin; if (begin == end) return handler.on_error("invalid format string"), end; if (static_cast(*begin) == '}') { @@ -2960,27 +2971,8 @@ class format_int { mutable char buffer_[buffer_size]; char* str_; - // Formats value in reverse and returns a pointer to the beginning. char* format_decimal(unsigned long long value) { - char* ptr = buffer_ + (buffer_size - 1); // Parens to workaround MSVC bug. - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - auto index = static_cast((value % 100) * 2); - value /= 100; - ptr -= 2; - // memcpy is faster than copying character by character. - memcpy(ptr, detail::data::digits + index, 2); - } - if (value < 10) { - *--ptr = static_cast('0' + value); - return ptr; - } - auto index = static_cast(value * 2); - ptr -= 2; - memcpy(ptr, detail::data::digits + index, 2); - return ptr; + return detail::format_decimal(buffer_, value, buffer_size - 1).begin; } void format_signed(long long value) {