format.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #include "format.h"
  2. #include "output.h"
  3. #include <util/generic/ymath.h>
  4. #include <util/string/cast.h>
  5. namespace NFormatPrivate {
  6. static inline i64 Round(double value) {
  7. double res1 = floor(value);
  8. double res2 = ceil(value);
  9. return (value - res1 < res2 - value) ? (i64)res1 : (i64)res2;
  10. }
  11. static inline IOutputStream& PrintDoubleShortly(IOutputStream& os, const double& d) {
  12. // General case: request 3 significant digits
  13. // Side-effect: allows exponential representation
  14. EFloatToStringMode mode = PREC_NDIGITS;
  15. int ndigits = 3;
  16. if (IsValidFloat(d) && Abs(d) < 1e12) {
  17. // For reasonably-sized finite values, it's better to avoid
  18. // exponential representation.
  19. // Use compact fixed representation and determine
  20. // precision based on magnitude.
  21. mode = PREC_POINT_DIGITS_STRIP_ZEROES;
  22. if (i64(Abs(d) * 100) < 1000) {
  23. ndigits = 2;
  24. } else if (i64(Abs(d) * 10) < 1000) {
  25. ndigits = 1;
  26. } else {
  27. ndigits = 0;
  28. }
  29. }
  30. return os << Prec(d, mode, ndigits);
  31. }
  32. } // namespace NFormatPrivate
  33. template <>
  34. void Out<NFormatPrivate::THumanReadableSize>(IOutputStream& stream, const NFormatPrivate::THumanReadableSize& value) {
  35. ui64 base = value.Format == SF_BYTES ? 1024 : 1000;
  36. ui64 base2 = base * base;
  37. ui64 base3 = base * base2;
  38. ui64 base4 = base * base3;
  39. double v = value.Value;
  40. if (v < 0) {
  41. stream << "-";
  42. v = -v;
  43. }
  44. if (v < base) {
  45. NFormatPrivate::PrintDoubleShortly(stream, v);
  46. } else if (v < base2) {
  47. NFormatPrivate::PrintDoubleShortly(stream, v / (double)base) << 'K';
  48. } else if (v < base3) {
  49. NFormatPrivate::PrintDoubleShortly(stream, v / (double)base2) << 'M';
  50. } else if (v < base4) {
  51. NFormatPrivate::PrintDoubleShortly(stream, v / (double)base3) << 'G';
  52. } else {
  53. NFormatPrivate::PrintDoubleShortly(stream, v / (double)base4) << 'T';
  54. }
  55. if (value.Format == SF_BYTES) {
  56. if (v < base) {
  57. stream << "B";
  58. } else {
  59. stream << "iB";
  60. }
  61. }
  62. }
  63. template <>
  64. void Out<NFormatPrivate::THumanReadableDuration>(IOutputStream& os, const NFormatPrivate::THumanReadableDuration& hr) {
  65. TTempBuf buf;
  66. TMemoryOutput ss(buf.Data(), buf.Size());
  67. do {
  68. ui64 microSeconds = hr.Value.MicroSeconds();
  69. if (microSeconds < 1000) {
  70. ss << microSeconds << "us";
  71. break;
  72. }
  73. if (microSeconds < 1000 * 1000) {
  74. NFormatPrivate::PrintDoubleShortly(ss, (double)microSeconds / 1000.0) << "ms";
  75. break;
  76. }
  77. double seconds = (double)(hr.Value.MilliSeconds()) / 1000.0;
  78. if (seconds < 60) {
  79. NFormatPrivate::PrintDoubleShortly(ss, seconds) << 's';
  80. break;
  81. }
  82. ui64 s = NFormatPrivate::Round(seconds * 1000 + 0.5) / 1000;
  83. ui64 m = s / 60;
  84. s = s % 60;
  85. ui64 h = m / 60;
  86. m = m % 60;
  87. ui64 d = h / 24;
  88. h = h % 24;
  89. ui64 times[] = {d, h, m, s};
  90. char names[] = {'d', 'h', 'm', 's'};
  91. bool first = true;
  92. for (size_t i = 0; i < Y_ARRAY_SIZE(times); ++i) {
  93. if (times[i] > 0) {
  94. if (!first) {
  95. ss << ' ';
  96. }
  97. ss << times[i] << names[i];
  98. first = false;
  99. }
  100. }
  101. } while (false);
  102. size_t written = buf.Size() - ss.Avail();
  103. os.Write(buf.Data(), written);
  104. }
  105. void Time(IOutputStream& l) {
  106. l << millisec();
  107. }
  108. void TimeHumanReadable(IOutputStream& l) {
  109. char timeStr[30];
  110. const time_t t = time(nullptr);
  111. l << ctime_r(&t, timeStr);
  112. }