* Move logic of handling subseconds from utility class to function with name write_fractional_seconds()
* Revert write(Rep value, int width) function to previous state
This commit is contained in:
parent
3d860b7cf5
commit
0fcdb017ab
@ -1389,59 +1389,47 @@ inline std::chrono::duration<Rep, std::milli> get_milliseconds(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Duration> class subsecond_helper {
|
// Returns the amount of digits according to the c++ 20 spec
|
||||||
// Returns the amount of digits according to the c++ 20 spec
|
// In the range [0, 18], if more than 18 fractional digits are required,
|
||||||
// In the range [0, 18], if more than 18 fractional digits are required,
|
// then we return 6 for microseconds precision.
|
||||||
// then we return 6 for microseconds precision
|
static constexpr int num_digits(long long num, long long den, int n = 0) {
|
||||||
static constexpr int num_digits(long long num, long long den, int n = 0) {
|
return num % den == 0 ? n : (n > 18 ? 6 : num_digits(num * 10, den, n + 1));
|
||||||
return num % den == 0 ? n : (n > 18 ? 6 : num_digits(num * 10, den, n + 1));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr long long pow10(std::uint32_t n) {
|
static constexpr long long pow10(std::uint32_t n) {
|
||||||
return n == 0 ? 1 : 10 * pow10(n - 1);
|
return n == 0 ? 1 : 10 * pow10(n - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Rep, class Period,
|
template <class Rep, class Period,
|
||||||
FMT_ENABLE_IF(std::numeric_limits<Rep>::is_signed)>
|
FMT_ENABLE_IF(std::numeric_limits<Rep>::is_signed)>
|
||||||
static constexpr std::chrono::duration<Rep, Period> abs(
|
static constexpr std::chrono::duration<Rep, Period> abs(
|
||||||
std::chrono::duration<Rep, Period> d) {
|
std::chrono::duration<Rep, Period> d) {
|
||||||
// We need to compare the duration using the count() method directly
|
// We need to compare the duration using the count() method directly
|
||||||
// due to a compiler bug in clang-11 regarding the spaceship operator,
|
// due to a compiler bug in clang-11 regarding the spaceship operator,
|
||||||
// when -Wzero-as-null-pointer-constant is enabled.
|
// when -Wzero-as-null-pointer-constant is enabled.
|
||||||
// In clang-12 the bug has been fixed. See
|
// In clang-12 the bug has been fixed. See
|
||||||
// https://bugs.llvm.org/show_bug.cgi?id=46235 and the reproducible example:
|
// https://bugs.llvm.org/show_bug.cgi?id=46235 and the reproducible example:
|
||||||
// https://www.godbolt.org/z/Knbb5joYx
|
// https://www.godbolt.org/z/Knbb5joYx
|
||||||
return d.count() >= d.zero().count() ? d : -d;
|
return d.count() >= d.zero().count() ? d : -d;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Rep, class Period,
|
template <class Rep, class Period,
|
||||||
FMT_ENABLE_IF(!std::numeric_limits<Rep>::is_signed)>
|
FMT_ENABLE_IF(!std::numeric_limits<Rep>::is_signed)>
|
||||||
static constexpr std::chrono::duration<Rep, Period> abs(
|
static constexpr std::chrono::duration<Rep, Period> abs(
|
||||||
std::chrono::duration<Rep, Period> d) {
|
std::chrono::duration<Rep, Period> d) {
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
template <class Rep, class Period, class ToDuration>
|
||||||
static constexpr auto fractional_width =
|
static constexpr typename ToDuration::rep get_subseconds(
|
||||||
num_digits(Duration::period::num, Duration::period::den);
|
std::chrono::duration<Rep, Period> d) {
|
||||||
|
return std::chrono::treat_as_floating_point<typename ToDuration::rep>::value
|
||||||
using precision = std::chrono::duration<
|
? (abs(d) - std::chrono::duration_cast<std::chrono::seconds>(d))
|
||||||
typename std::common_type<typename Duration::rep,
|
.count()
|
||||||
std::chrono::seconds::rep>::type,
|
: std::chrono::duration_cast<ToDuration>(
|
||||||
std::ratio<1, pow10(fractional_width)>>;
|
abs(d) - std::chrono::duration_cast<std::chrono::seconds>(d))
|
||||||
|
.count();
|
||||||
template <class Rep, class Period>
|
}
|
||||||
static constexpr typename precision::rep get_subseconds(
|
|
||||||
std::chrono::duration<Rep, Period> d) {
|
|
||||||
return std::chrono::treat_as_floating_point<typename precision::rep>::value
|
|
||||||
? (abs(d) - std::chrono::duration_cast<std::chrono::seconds>(d))
|
|
||||||
.count()
|
|
||||||
: std::chrono::duration_cast<precision>(
|
|
||||||
abs(d) -
|
|
||||||
std::chrono::duration_cast<std::chrono::seconds>(d))
|
|
||||||
.count();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, typename Rep, typename OutputIt,
|
template <typename Char, typename Rep, typename OutputIt,
|
||||||
FMT_ENABLE_IF(std::is_integral<Rep>::value)>
|
FMT_ENABLE_IF(std::is_integral<Rep>::value)>
|
||||||
@ -1593,16 +1581,47 @@ struct chrono_formatter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename RepType> void write(RepType value, int width) {
|
void write(Rep value, int width) {
|
||||||
write_sign();
|
write_sign();
|
||||||
if (isnan(value)) return write_nan();
|
if (isnan(value)) return write_nan();
|
||||||
uint32_or_64_or_128_t<long long> n =
|
uint32_or_64_or_128_t<int> n =
|
||||||
to_unsigned(to_nonnegative_int(value, max_value<long long>()));
|
to_unsigned(to_nonnegative_int(value, max_value<int>()));
|
||||||
int num_digits = detail::count_digits(n);
|
int num_digits = detail::count_digits(n);
|
||||||
if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
|
if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
|
||||||
out = format_decimal<char_type>(out, n, num_digits).end;
|
out = format_decimal<char_type>(out, n, num_digits).end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Duration> void write_fractional_seconds(Duration d) {
|
||||||
|
static constexpr auto fractional_width =
|
||||||
|
detail::num_digits(Duration::period::num, Duration::period::den);
|
||||||
|
|
||||||
|
using precision = std::chrono::duration<
|
||||||
|
typename std::common_type<typename Duration::rep,
|
||||||
|
std::chrono::seconds::rep>::type,
|
||||||
|
std::ratio<1, detail::pow10(fractional_width)>>;
|
||||||
|
// We could use c++ 17 if constexpr here.
|
||||||
|
if (std::ratio_less<typename precision::period,
|
||||||
|
std::chrono::seconds::period>::value) {
|
||||||
|
*out++ = '.';
|
||||||
|
const auto subseconds =
|
||||||
|
std::chrono::treat_as_floating_point<typename precision::rep>::value
|
||||||
|
? (detail::abs(d) -
|
||||||
|
std::chrono::duration_cast<std::chrono::seconds>(d))
|
||||||
|
.count()
|
||||||
|
: std::chrono::duration_cast<precision>(
|
||||||
|
detail::abs(d) -
|
||||||
|
std::chrono::duration_cast<std::chrono::seconds>(d))
|
||||||
|
.count();
|
||||||
|
uint32_or_64_or_128_t<long long> n =
|
||||||
|
to_unsigned(to_nonnegative_int(subseconds, max_value<long long>()));
|
||||||
|
int num_digits = detail::count_digits(n);
|
||||||
|
if (fractional_width > num_digits) {
|
||||||
|
out = std::fill_n(out, fractional_width - num_digits, '0');
|
||||||
|
}
|
||||||
|
out = format_decimal<char_type>(out, n, num_digits).end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void write_nan() { std::copy_n("nan", 3, out); }
|
void write_nan() { std::copy_n("nan", 3, out); }
|
||||||
void write_pinf() { std::copy_n("inf", 3, out); }
|
void write_pinf() { std::copy_n("inf", 3, out); }
|
||||||
void write_ninf() { std::copy_n("-inf", 4, out); }
|
void write_ninf() { std::copy_n("-inf", 4, out); }
|
||||||
@ -1680,15 +1699,7 @@ struct chrono_formatter {
|
|||||||
|
|
||||||
if (ns == numeric_system::standard) {
|
if (ns == numeric_system::standard) {
|
||||||
write(second(), 2);
|
write(second(), 2);
|
||||||
using duration_rep = std::chrono::duration<rep, Period>;
|
write_fractional_seconds(std::chrono::duration<rep, Period>{val});
|
||||||
using subsec_helper = detail::subsecond_helper<duration_rep>;
|
|
||||||
// Could use c++ 17 if constexpr
|
|
||||||
if (std::ratio_less<typename subsec_helper::precision::period,
|
|
||||||
std::chrono::seconds::period>::value) {
|
|
||||||
*out++ = '.';
|
|
||||||
write(subsec_helper::get_subseconds(duration_rep{val}),
|
|
||||||
subsec_helper::fractional_width);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user