format.h 14 KB

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