#include "format.h" #include "output.h" #include #include namespace NFormatPrivate { static inline i64 Round(double value) { double res1 = floor(value); double res2 = ceil(value); return (value - res1 < res2 - value) ? (i64)res1 : (i64)res2; } static inline IOutputStream& PrintDoubleShortly(IOutputStream& os, const double& d) { // General case: request 3 significant digits // Side-effect: allows exponential representation EFloatToStringMode mode = PREC_NDIGITS; int ndigits = 3; if (IsValidFloat(d) && Abs(d) < 1e12) { // For reasonably-sized finite values, it's better to avoid // exponential representation. // Use compact fixed representation and determine // precision based on magnitude. mode = PREC_POINT_DIGITS_STRIP_ZEROES; if (i64(Abs(d) * 100) < 1000) { ndigits = 2; } else if (i64(Abs(d) * 10) < 1000) { ndigits = 1; } else { ndigits = 0; } } return os << Prec(d, mode, ndigits); } } template <> void Out(IOutputStream& stream, const NFormatPrivate::THumanReadableSize& value) { ui64 base = value.Format == SF_BYTES ? 1024 : 1000; ui64 base2 = base * base; ui64 base3 = base * base2; ui64 base4 = base * base3; double v = value.Value; if (v < 0) { stream << "-"; v = -v; } if (v < base) { NFormatPrivate::PrintDoubleShortly(stream, v); } else if (v < base2) { NFormatPrivate::PrintDoubleShortly(stream, v / (double)base) << 'K'; } else if (v < base3) { NFormatPrivate::PrintDoubleShortly(stream, v / (double)base2) << 'M'; } else if (v < base4) { NFormatPrivate::PrintDoubleShortly(stream, v / (double)base3) << 'G'; } else { NFormatPrivate::PrintDoubleShortly(stream, v / (double)base4) << 'T'; } if (value.Format == SF_BYTES) { if (v < base) { stream << "B"; } else { stream << "iB"; } } } template <> void Out(IOutputStream& os, const NFormatPrivate::THumanReadableDuration& hr) { TTempBuf buf; TMemoryOutput ss(buf.Data(), buf.Size()); do { ui64 microSeconds = hr.Value.MicroSeconds(); if (microSeconds < 1000) { ss << microSeconds << "us"; break; } if (microSeconds < 1000 * 1000) { NFormatPrivate::PrintDoubleShortly(ss, (double)microSeconds / 1000.0) << "ms"; break; } double seconds = (double)(hr.Value.MilliSeconds()) / 1000.0; if (seconds < 60) { NFormatPrivate::PrintDoubleShortly(ss, seconds) << 's'; break; } ui64 s = NFormatPrivate::Round(seconds * 1000 + 0.5) / 1000; ui64 m = s / 60; s = s % 60; ui64 h = m / 60; m = m % 60; ui64 d = h / 24; h = h % 24; ui64 times[] = {d, h, m, s}; char names[] = {'d', 'h', 'm', 's'}; bool first = true; for (size_t i = 0; i < Y_ARRAY_SIZE(times); ++i) { if (times[i] > 0) { if (!first) { ss << ' '; } ss << times[i] << names[i]; first = false; } } } while (false); size_t written = buf.Size() - ss.Avail(); os.Write(buf.Data(), written); } void Time(IOutputStream& l) { l << millisec(); } void TimeHumanReadable(IOutputStream& l) { char timeStr[30]; const time_t t = time(nullptr); l << ctime_r(&t, timeStr); }