format.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. #pragma once
  2. #include "mem.h"
  3. #include "output.h"
  4. #include <util/datetime/base.h>
  5. #include <util/generic/strbuf.h>
  6. #include <util/generic/flags.h>
  7. #include <util/memory/tempbuf.h>
  8. #include <util/string/cast.h>
  9. enum ENumberFormatFlag {
  10. HF_FULL = 0x01, /**< Output number with leading zeros. */
  11. HF_ADDX = 0x02, /**< Output '0x' or '0b' before hex/bin digits. */
  12. };
  13. Y_DECLARE_FLAGS(ENumberFormat, ENumberFormatFlag);
  14. Y_DECLARE_OPERATORS_FOR_FLAGS(ENumberFormat);
  15. enum ESizeFormat {
  16. SF_QUANTITY, /**< Base 1000, usual suffixes. 1100 gets turned into "1.1K". */
  17. SF_BYTES, /**< Base 1024, byte suffix. 1100 gets turned into "1.07KiB". */
  18. };
  19. namespace NFormatPrivate {
  20. template <size_t Value>
  21. struct TLog2: std::integral_constant<size_t, TLog2<Value / 2>::value + 1> {};
  22. template <>
  23. struct TLog2<1>: std::integral_constant<size_t, 0> {};
  24. template <typename T>
  25. inline void StreamWrite(T& stream, const char* s, size_t size) {
  26. stream.write(s, size);
  27. }
  28. template <>
  29. inline void StreamWrite(IOutputStream& stream, const char* s, size_t size) {
  30. stream.Write(s, size);
  31. }
  32. template <>
  33. inline void StreamWrite(TStringStream& stream, const char* s, size_t size) {
  34. stream.Write(s, size);
  35. }
  36. template <typename T>
  37. static inline void WriteChars(T& os, char c, size_t count) {
  38. if (count == 0) {
  39. return;
  40. }
  41. TTempBuf buf(count);
  42. memset(buf.Data(), c, count);
  43. StreamWrite(os, buf.Data(), count);
  44. }
  45. template <typename T>
  46. struct TLeftPad {
  47. T Value;
  48. size_t Width;
  49. char Padc;
  50. inline TLeftPad(const T& value, size_t width, char padc)
  51. : Value(value)
  52. , Width(width)
  53. , Padc(padc)
  54. {
  55. }
  56. };
  57. template <typename T>
  58. IOutputStream& operator<<(IOutputStream& o Y_LIFETIME_BOUND, const TLeftPad<T>& lp) {
  59. TTempBuf buf;
  60. TMemoryOutput ss(buf.Data(), buf.Size());
  61. ss << lp.Value;
  62. size_t written = buf.Size() - ss.Avail();
  63. if (lp.Width > written) {
  64. WriteChars(o, lp.Padc, lp.Width - written);
  65. }
  66. o.Write(buf.Data(), written);
  67. return o;
  68. }
  69. template <typename T>
  70. struct TRightPad {
  71. T Value;
  72. size_t Width;
  73. char Padc;
  74. inline TRightPad(const T& value, size_t width, char padc)
  75. : Value(value)
  76. , Width(width)
  77. , Padc(padc)
  78. {
  79. }
  80. };
  81. template <typename T>
  82. IOutputStream& operator<<(IOutputStream& o Y_LIFETIME_BOUND, const TRightPad<T>& lp) {
  83. TTempBuf buf;
  84. TMemoryOutput ss(buf.Data(), buf.Size());
  85. ss << lp.Value;
  86. size_t written = buf.Size() - ss.Avail();
  87. o.Write(buf.Data(), written);
  88. if (lp.Width > written) {
  89. WriteChars(o, lp.Padc, lp.Width - written);
  90. }
  91. return o;
  92. }
  93. template <typename T, size_t Base>
  94. struct TBaseNumber {
  95. T Value;
  96. ENumberFormat Flags;
  97. template <typename OtherT>
  98. inline TBaseNumber(OtherT value, ENumberFormat flags)
  99. : Value(value)
  100. , Flags(flags)
  101. {
  102. }
  103. };
  104. template <typename T, size_t Base>
  105. using TUnsignedBaseNumber = TBaseNumber<std::make_unsigned_t<std::remove_cv_t<T>>, Base>;
  106. template <typename TStream, typename T, size_t Base>
  107. TStream& ToStreamImpl(TStream& stream Y_LIFETIME_BOUND, const TBaseNumber<T, Base>& value) {
  108. char buf[8 * sizeof(T) + 1]; /* Add 1 for sign. */
  109. TStringBuf str(buf, IntToString<Base>(value.Value, buf, sizeof(buf)));
  110. if (str[0] == '-') {
  111. stream << '-';
  112. str.Skip(1);
  113. }
  114. if (value.Flags & HF_ADDX) {
  115. if (Base == 16) {
  116. stream << TStringBuf("0x");
  117. } else if (Base == 2) {
  118. stream << TStringBuf("0b");
  119. }
  120. }
  121. if (value.Flags & HF_FULL) {
  122. WriteChars(stream, '0', (8 * sizeof(T) + TLog2<Base>::value - 1) / TLog2<Base>::value - str.size());
  123. }
  124. stream << str;
  125. return stream;
  126. }
  127. template <typename T, size_t Base>
  128. IOutputStream& operator<<(IOutputStream& stream Y_LIFETIME_BOUND, const TBaseNumber<T, Base>& value) {
  129. return ToStreamImpl(stream, value);
  130. }
  131. template <typename T, size_t Base>
  132. std::ostream& operator<<(std::ostream& stream Y_LIFETIME_BOUND, const TBaseNumber<T, Base>& value) {
  133. return ToStreamImpl(stream, value);
  134. }
  135. template <typename Char, size_t Base>
  136. struct TBaseText {
  137. TBasicStringBuf<Char> Text;
  138. inline TBaseText(const TBasicStringBuf<Char> text)
  139. : Text(text)
  140. {
  141. }
  142. };
  143. template <typename Char, size_t Base>
  144. IOutputStream& operator<<(IOutputStream& os Y_LIFETIME_BOUND, const TBaseText<Char, Base>& text) {
  145. for (size_t i = 0; i < text.Text.size(); ++i) {
  146. if (i != 0) {
  147. os << ' ';
  148. }
  149. os << TUnsignedBaseNumber<Char, Base>(text.Text[i], HF_FULL);
  150. }
  151. return os;
  152. }
  153. template <typename T>
  154. struct TFloatPrecision {
  155. using TdVal = std::remove_cv_t<T>;
  156. static_assert(std::is_floating_point<TdVal>::value, "expect std::is_floating_point<TdVal>::value");
  157. TdVal Value;
  158. EFloatToStringMode Mode;
  159. int NDigits;
  160. };
  161. template <typename T>
  162. IOutputStream& operator<<(IOutputStream& o Y_LIFETIME_BOUND, const TFloatPrecision<T>& prec) {
  163. char buf[512];
  164. size_t count = FloatToString(prec.Value, buf, sizeof(buf), prec.Mode, prec.NDigits);
  165. o << TStringBuf(buf, count);
  166. return o;
  167. }
  168. struct THumanReadableDuration {
  169. TDuration Value;
  170. constexpr THumanReadableDuration(const TDuration& value)
  171. : Value(value)
  172. {
  173. }
  174. };
  175. struct THumanReadableSize {
  176. double Value;
  177. ESizeFormat Format;
  178. };
  179. } // namespace NFormatPrivate
  180. /**
  181. * Output manipulator basically equivalent to `std::setw` and `std::setfill`
  182. * combined.
  183. *
  184. * When written into a `IOutputStream`, writes out padding characters first,
  185. * and then provided value.
  186. *
  187. * Example usage:
  188. * @code
  189. * stream << LeftPad(12345, 10, '0'); // Will output "0000012345"
  190. * @endcode
  191. *
  192. * @param value Value to output.
  193. * @param width Target total width.
  194. * @param padc Character to use for padding.
  195. * @see RightPad
  196. */
  197. template <typename T>
  198. static constexpr ::NFormatPrivate::TLeftPad<T> LeftPad(const T& value, const size_t width, const char padc = ' ') noexcept {
  199. return ::NFormatPrivate::TLeftPad<T>(value, width, padc);
  200. }
  201. template <typename T, int N>
  202. static constexpr ::NFormatPrivate::TLeftPad<const T*> LeftPad(const T (&value)[N], const size_t width, const char padc = ' ') noexcept {
  203. return ::NFormatPrivate::TLeftPad<const T*>(value, width, padc);
  204. }
  205. /**
  206. * Output manipulator similar to `std::setw` and `std::setfill`.
  207. *
  208. * When written into a `IOutputStream`, writes provided value first, and then
  209. * the padding characters.
  210. *
  211. * Example usage:
  212. * @code
  213. * stream << RightPad("column1", 10, ' '); // Will output "column1 "
  214. * @endcode
  215. *
  216. * @param value Value to output.
  217. * @param width Target total width.
  218. * @param padc Character to use for padding.
  219. * @see LeftPad
  220. */
  221. template <typename T>
  222. static constexpr ::NFormatPrivate::TRightPad<T> RightPad(const T& value, const size_t width, const char padc = ' ') noexcept {
  223. return ::NFormatPrivate::TRightPad<T>(value, width, padc);
  224. }
  225. template <typename T, int N>
  226. static constexpr ::NFormatPrivate::TRightPad<const T*> RightPad(const T (&value)[N], const size_t width, const char padc = ' ') noexcept {
  227. return ::NFormatPrivate::TRightPad<const T*>(value, width, padc);
  228. }
  229. /**
  230. * Output manipulator similar to `std::setbase(16)`.
  231. *
  232. * When written into a `IOutputStream`, writes out the provided value in
  233. * hexadecimal form. The value is treated as unsigned, even if its type is in
  234. * fact signed.
  235. *
  236. * Example usage:
  237. * @code
  238. * stream << Hex(-1); // Will output "0xFFFFFFFF"
  239. * stream << Hex(1ull); // Will output "0x0000000000000001"
  240. * @endcode
  241. *
  242. * @param value Value to output.
  243. * @param flags Output flags.
  244. */
  245. template <typename T>
  246. static constexpr ::NFormatPrivate::TUnsignedBaseNumber<T, 16> Hex(const T& value, const ENumberFormat flags = HF_FULL | HF_ADDX) noexcept {
  247. return {value, flags};
  248. }
  249. /**
  250. * Output manipulator similar to `std::setbase(16)`.
  251. *
  252. * When written into a `IOutputStream`, writes out the provided value in
  253. * hexadecimal form.
  254. *
  255. * Example usage:
  256. * @code
  257. * stream << SHex(-1); // Will output "-0x00000001"
  258. * stream << SHex(1ull); // Will output "0x0000000000000001"
  259. * @endcode
  260. *
  261. * @param value Value to output.
  262. * @param flags Output flags.
  263. */
  264. template <typename T>
  265. static constexpr ::NFormatPrivate::TBaseNumber<T, 16> SHex(const T& value, const ENumberFormat flags = HF_FULL | HF_ADDX) noexcept {
  266. return {value, flags};
  267. }
  268. /**
  269. * Output manipulator similar to `std::setbase(2)`.
  270. *
  271. * When written into a `IOutputStream`, writes out the provided value in
  272. * binary form. The value is treated as unsigned, even if its type is in
  273. * fact signed.
  274. *
  275. * Example usage:
  276. * @code
  277. * stream << Bin(-1); // Will output "0b11111111111111111111111111111111"
  278. * stream << Bin(1); // Will output "0b00000000000000000000000000000001"
  279. * @endcode
  280. *
  281. * @param value Value to output.
  282. * @param flags Output flags.
  283. */
  284. template <typename T>
  285. static constexpr ::NFormatPrivate::TUnsignedBaseNumber<T, 2> Bin(const T& value, const ENumberFormat flags = HF_FULL | HF_ADDX) noexcept {
  286. return {value, flags};
  287. }
  288. /**
  289. * Output manipulator similar to `std::setbase(2)`.
  290. *
  291. * When written into a `IOutputStream`, writes out the provided value in
  292. * binary form.
  293. *
  294. * Example usage:
  295. * @code
  296. * stream << SBin(-1); // Will output "-0b00000000000000000000000000000001"
  297. * stream << SBin(1); // Will output "0b00000000000000000000000000000001"
  298. * @endcode
  299. *
  300. * @param value Value to output.
  301. * @param flags Output flags.
  302. */
  303. template <typename T>
  304. static constexpr ::NFormatPrivate::TBaseNumber<T, 2> SBin(const T& value, const ENumberFormat flags = HF_FULL | HF_ADDX) noexcept {
  305. return {value, flags};
  306. }
  307. /**
  308. * Output manipulator for hexadecimal string output.
  309. *
  310. * When written into a `IOutputStream`, writes out the provided characters
  311. * in hexadecimal form divided by space character.
  312. *
  313. * Example usage:
  314. * @code
  315. * stream << HexText(TStringBuf("abcи")); // Will output "61 62 63 D0 B8"
  316. * stream << HexText(TWtringBuf(u"abcи")); // Will output "0061 0062 0063 0438"
  317. * @endcode
  318. *
  319. * @param value String to output.
  320. */
  321. template <typename TChar>
  322. static inline ::NFormatPrivate::TBaseText<TChar, 16> HexText(const TBasicStringBuf<TChar> value) {
  323. return ::NFormatPrivate::TBaseText<TChar, 16>(value);
  324. }
  325. /**
  326. * Output manipulator for binary string output.
  327. *
  328. * When written into a `IOutputStream`, writes out the provided characters
  329. * in binary form divided by space character.
  330. *
  331. * Example usage:
  332. * @code
  333. * stream << BinText(TStringBuf("aaa")); // Will output "01100001 01100001 01100001"
  334. * @endcode
  335. *
  336. * @param value String to output.
  337. */
  338. template <typename TChar>
  339. static inline ::NFormatPrivate::TBaseText<TChar, 2> BinText(const TBasicStringBuf<TChar> value) {
  340. return ::NFormatPrivate::TBaseText<TChar, 2>(value);
  341. }
  342. /**
  343. * Output manipulator for printing `TDuration` values.
  344. *
  345. * When written into a `IOutputStream`, writes out the provided `TDuration`
  346. * in auto-adjusted human-readable format.
  347. *
  348. * Example usage:
  349. * @code
  350. * stream << HumanReadable(TDuration::MicroSeconds(100)); // Will output "100us"
  351. * stream << HumanReadable(TDuration::Seconds(3672)); // Will output "1h 1m 12s"
  352. * @endcode
  353. *
  354. * @param value Value to output.
  355. */
  356. static constexpr ::NFormatPrivate::THumanReadableDuration HumanReadable(const TDuration duration) noexcept {
  357. return ::NFormatPrivate::THumanReadableDuration(duration);
  358. }
  359. /**
  360. * Output manipulator for writing out human-readable number of elements / memory
  361. * amount in `ls -h` style.
  362. *
  363. * When written into a `IOutputStream`, writes out the provided unsigned integer
  364. * variable with small precision and a suffix (like 'K', 'M', 'G' for numbers, or
  365. * 'B', 'KiB', 'MiB', 'GiB' for bytes).
  366. *
  367. * For quantities, base 1000 is used. For bytes, base is 1024.
  368. *
  369. * Example usage:
  370. * @code
  371. * stream << HumanReadableSize(1024, SF_QUANTITY); // Will output "1.02K"
  372. * stream << HumanReadableSize(1024, SF_BYTES); // Will output "1KiB"
  373. * stream << "average usage " << HumanReadableSize(100 / 3., SF_BYTES); // Will output "average usage "33.3B""
  374. * @endcode
  375. *
  376. * @param value Value to output.
  377. * @param format Format to use.
  378. */
  379. static constexpr ::NFormatPrivate::THumanReadableSize HumanReadableSize(const double size, ESizeFormat format) noexcept {
  380. return {size, format};
  381. }
  382. void Time(IOutputStream& l);
  383. void TimeHumanReadable(IOutputStream& l);
  384. /**
  385. * Output manipulator for adjusting precision of floating point values.
  386. *
  387. * When written into a `IOutputStream`, writes out the provided floating point
  388. * variable with given precision. The behavior depends on provided `mode`.
  389. *
  390. * Example usage:
  391. * @code
  392. * stream << Prec(1.2345678901234567, PREC_AUTO); // Will output "1.2345678901234567"
  393. * @endcode
  394. *
  395. * @param value float or double to output.
  396. * @param mode Output mode.
  397. * @param ndigits Number of significant digits (in `PREC_NDIGITS` and `PREC_POINT_DIGITS` mode).
  398. * @see EFloatToStringMode
  399. */
  400. template <typename T>
  401. static constexpr ::NFormatPrivate::TFloatPrecision<T> Prec(const T& value, const EFloatToStringMode mode, const int ndigits = 0) noexcept {
  402. return {value, mode, ndigits};
  403. }
  404. /**
  405. * Output manipulator for adjusting precision of floating point values.
  406. *
  407. * When written into a `IOutputStream`, writes out the provided floating point
  408. * variable with given precision. The behavior is equivalent to `Prec(value, PREC_NDIGITS, ndigits)`.
  409. *
  410. * Example usage:
  411. * @code
  412. * stream << Prec(1.2345678901234567, 3); // Will output "1.23"
  413. * @endcode
  414. *
  415. * @param value float or double to output.
  416. * @param ndigits Number of significant digits.
  417. */
  418. template <typename T>
  419. static constexpr ::NFormatPrivate::TFloatPrecision<T> Prec(const T& value, const int ndigits) noexcept {
  420. return {value, PREC_NDIGITS, ndigits};
  421. }