123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- #pragma once
- #include "mem.h"
- #include "output.h"
- #include <util/datetime/base.h>
- #include <util/generic/strbuf.h>
- #include <util/generic/flags.h>
- #include <util/memory/tempbuf.h>
- #include <util/string/cast.h>
- enum ENumberFormatFlag {
- HF_FULL = 0x01, /**< Output number with leading zeros. */
- HF_ADDX = 0x02, /**< Output '0x' or '0b' before hex/bin digits. */
- };
- Y_DECLARE_FLAGS(ENumberFormat, ENumberFormatFlag);
- Y_DECLARE_OPERATORS_FOR_FLAGS(ENumberFormat);
- enum ESizeFormat {
- SF_QUANTITY, /**< Base 1000, usual suffixes. 1100 gets turned into "1.1K". */
- SF_BYTES, /**< Base 1024, byte suffix. 1100 gets turned into "1.07KiB". */
- };
- namespace NFormatPrivate {
- template <size_t Value>
- struct TLog2: std::integral_constant<size_t, TLog2<Value / 2>::value + 1> {};
- template <>
- struct TLog2<1>: std::integral_constant<size_t, 0> {};
- template <typename T>
- inline void StreamWrite(T& stream, const char* s, size_t size) {
- stream.write(s, size);
- }
- template <>
- inline void StreamWrite(IOutputStream& stream, const char* s, size_t size) {
- stream.Write(s, size);
- }
- template <>
- inline void StreamWrite(TStringStream& stream, const char* s, size_t size) {
- stream.Write(s, size);
- }
- template <typename T>
- static inline void WriteChars(T& os, char c, size_t count) {
- if (count == 0)
- return;
- TTempBuf buf(count);
- memset(buf.Data(), c, count);
- StreamWrite(os, buf.Data(), count);
- }
- template <typename T>
- struct TLeftPad {
- T Value;
- size_t Width;
- char Padc;
- inline TLeftPad(const T& value, size_t width, char padc)
- : Value(value)
- , Width(width)
- , Padc(padc)
- {
- }
- };
- template <typename T>
- IOutputStream& operator<<(IOutputStream& o, const TLeftPad<T>& lp) {
- TTempBuf buf;
- TMemoryOutput ss(buf.Data(), buf.Size());
- ss << lp.Value;
- size_t written = buf.Size() - ss.Avail();
- if (lp.Width > written) {
- WriteChars(o, lp.Padc, lp.Width - written);
- }
- o.Write(buf.Data(), written);
- return o;
- }
- template <typename T>
- struct TRightPad {
- T Value;
- size_t Width;
- char Padc;
- inline TRightPad(const T& value, size_t width, char padc)
- : Value(value)
- , Width(width)
- , Padc(padc)
- {
- }
- };
- template <typename T>
- IOutputStream& operator<<(IOutputStream& o, const TRightPad<T>& lp) {
- TTempBuf buf;
- TMemoryOutput ss(buf.Data(), buf.Size());
- ss << lp.Value;
- size_t written = buf.Size() - ss.Avail();
- o.Write(buf.Data(), written);
- if (lp.Width > written) {
- WriteChars(o, lp.Padc, lp.Width - written);
- }
- return o;
- }
- template <typename T, size_t Base>
- struct TBaseNumber {
- T Value;
- ENumberFormat Flags;
- template <typename OtherT>
- inline TBaseNumber(OtherT value, ENumberFormat flags)
- : Value(value)
- , Flags(flags)
- {
- }
- };
- template <typename T, size_t Base>
- using TUnsignedBaseNumber = TBaseNumber<std::make_unsigned_t<std::remove_cv_t<T>>, Base>;
- template <typename TStream, typename T, size_t Base>
- TStream& ToStreamImpl(TStream& stream, const TBaseNumber<T, Base>& value) {
- char buf[8 * sizeof(T) + 1]; /* Add 1 for sign. */
- TStringBuf str(buf, IntToString<Base>(value.Value, buf, sizeof(buf)));
- if (str[0] == '-') {
- stream << '-';
- str.Skip(1);
- }
- if (value.Flags & HF_ADDX) {
- if (Base == 16) {
- stream << TStringBuf("0x");
- } else if (Base == 2) {
- stream << TStringBuf("0b");
- }
- }
- if (value.Flags & HF_FULL) {
- WriteChars(stream, '0', (8 * sizeof(T) + TLog2<Base>::value - 1) / TLog2<Base>::value - str.size());
- }
- stream << str;
- return stream;
- }
- template <typename T, size_t Base>
- IOutputStream& operator<<(IOutputStream& stream, const TBaseNumber<T, Base>& value) {
- return ToStreamImpl(stream, value);
- }
- template <typename T, size_t Base>
- std::ostream& operator<<(std::ostream& stream, const TBaseNumber<T, Base>& value) {
- return ToStreamImpl(stream, value);
- }
- template <typename Char, size_t Base>
- struct TBaseText {
- TBasicStringBuf<Char> Text;
- inline TBaseText(const TBasicStringBuf<Char> text)
- : Text(text)
- {
- }
- };
- template <typename Char, size_t Base>
- IOutputStream& operator<<(IOutputStream& os, const TBaseText<Char, Base>& text) {
- for (size_t i = 0; i < text.Text.size(); ++i) {
- if (i != 0) {
- os << ' ';
- }
- os << TUnsignedBaseNumber<Char, Base>(text.Text[i], HF_FULL);
- }
- return os;
- }
- template <typename T>
- struct TFloatPrecision {
- using TdVal = std::remove_cv_t<T>;
- static_assert(std::is_floating_point<TdVal>::value, "expect std::is_floating_point<TdVal>::value");
- TdVal Value;
- EFloatToStringMode Mode;
- int NDigits;
- };
- template <typename T>
- IOutputStream& operator<<(IOutputStream& o, const TFloatPrecision<T>& prec) {
- char buf[512];
- size_t count = FloatToString(prec.Value, buf, sizeof(buf), prec.Mode, prec.NDigits);
- o << TStringBuf(buf, count);
- return o;
- }
- struct THumanReadableDuration {
- TDuration Value;
- constexpr THumanReadableDuration(const TDuration& value)
- : Value(value)
- {
- }
- };
- struct THumanReadableSize {
- double Value;
- ESizeFormat Format;
- };
- } // namespace NFormatPrivate
- /**
- * Output manipulator basically equivalent to `std::setw` and `std::setfill`
- * combined.
- *
- * When written into a `IOutputStream`, writes out padding characters first,
- * and then provided value.
- *
- * Example usage:
- * @code
- * stream << LeftPad(12345, 10, '0'); // Will output "0000012345"
- * @endcode
- *
- * @param value Value to output.
- * @param width Target total width.
- * @param padc Character to use for padding.
- * @see RightPad
- */
- template <typename T>
- static constexpr ::NFormatPrivate::TLeftPad<T> LeftPad(const T& value, const size_t width, const char padc = ' ') noexcept {
- return ::NFormatPrivate::TLeftPad<T>(value, width, padc);
- }
- template <typename T, int N>
- static constexpr ::NFormatPrivate::TLeftPad<const T*> LeftPad(const T (&value)[N], const size_t width, const char padc = ' ') noexcept {
- return ::NFormatPrivate::TLeftPad<const T*>(value, width, padc);
- }
- /**
- * Output manipulator similar to `std::setw` and `std::setfill`.
- *
- * When written into a `IOutputStream`, writes provided value first, and then
- * the padding characters.
- *
- * Example usage:
- * @code
- * stream << RightPad("column1", 10, ' '); // Will output "column1 "
- * @endcode
- *
- * @param value Value to output.
- * @param width Target total width.
- * @param padc Character to use for padding.
- * @see LeftPad
- */
- template <typename T>
- static constexpr ::NFormatPrivate::TRightPad<T> RightPad(const T& value, const size_t width, const char padc = ' ') noexcept {
- return ::NFormatPrivate::TRightPad<T>(value, width, padc);
- }
- template <typename T, int N>
- static constexpr ::NFormatPrivate::TRightPad<const T*> RightPad(const T (&value)[N], const size_t width, const char padc = ' ') noexcept {
- return ::NFormatPrivate::TRightPad<const T*>(value, width, padc);
- }
- /**
- * Output manipulator similar to `std::setbase(16)`.
- *
- * When written into a `IOutputStream`, writes out the provided value in
- * hexadecimal form. The value is treated as unsigned, even if its type is in
- * fact signed.
- *
- * Example usage:
- * @code
- * stream << Hex(-1); // Will output "0xFFFFFFFF"
- * stream << Hex(1ull); // Will output "0x0000000000000001"
- * @endcode
- *
- * @param value Value to output.
- * @param flags Output flags.
- */
- template <typename T>
- static constexpr ::NFormatPrivate::TUnsignedBaseNumber<T, 16> Hex(const T& value, const ENumberFormat flags = HF_FULL | HF_ADDX) noexcept {
- return {value, flags};
- }
- /**
- * Output manipulator similar to `std::setbase(16)`.
- *
- * When written into a `IOutputStream`, writes out the provided value in
- * hexadecimal form.
- *
- * Example usage:
- * @code
- * stream << SHex(-1); // Will output "-0x00000001"
- * stream << SHex(1ull); // Will output "0x0000000000000001"
- * @endcode
- *
- * @param value Value to output.
- * @param flags Output flags.
- */
- template <typename T>
- static constexpr ::NFormatPrivate::TBaseNumber<T, 16> SHex(const T& value, const ENumberFormat flags = HF_FULL | HF_ADDX) noexcept {
- return {value, flags};
- }
- /**
- * Output manipulator similar to `std::setbase(2)`.
- *
- * When written into a `IOutputStream`, writes out the provided value in
- * binary form. The value is treated as unsigned, even if its type is in
- * fact signed.
- *
- * Example usage:
- * @code
- * stream << Bin(-1); // Will output "0b11111111111111111111111111111111"
- * stream << Bin(1); // Will output "0b00000000000000000000000000000001"
- * @endcode
- *
- * @param value Value to output.
- * @param flags Output flags.
- */
- template <typename T>
- static constexpr ::NFormatPrivate::TUnsignedBaseNumber<T, 2> Bin(const T& value, const ENumberFormat flags = HF_FULL | HF_ADDX) noexcept {
- return {value, flags};
- }
- /**
- * Output manipulator similar to `std::setbase(2)`.
- *
- * When written into a `IOutputStream`, writes out the provided value in
- * binary form.
- *
- * Example usage:
- * @code
- * stream << SBin(-1); // Will output "-0b00000000000000000000000000000001"
- * stream << SBin(1); // Will output "0b00000000000000000000000000000001"
- * @endcode
- *
- * @param value Value to output.
- * @param flags Output flags.
- */
- template <typename T>
- static constexpr ::NFormatPrivate::TBaseNumber<T, 2> SBin(const T& value, const ENumberFormat flags = HF_FULL | HF_ADDX) noexcept {
- return {value, flags};
- }
- /**
- * Output manipulator for hexadecimal string output.
- *
- * When written into a `IOutputStream`, writes out the provided characters
- * in hexadecimal form divided by space character.
- *
- * Example usage:
- * @code
- * stream << HexText(TStringBuf("abcи")); // Will output "61 62 63 D0 B8"
- * stream << HexText(TWtringBuf(u"abcи")); // Will output "0061 0062 0063 0438"
- * @endcode
- *
- * @param value String to output.
- */
- template <typename TChar>
- static inline ::NFormatPrivate::TBaseText<TChar, 16> HexText(const TBasicStringBuf<TChar> value) {
- return ::NFormatPrivate::TBaseText<TChar, 16>(value);
- }
- /**
- * Output manipulator for binary string output.
- *
- * When written into a `IOutputStream`, writes out the provided characters
- * in binary form divided by space character.
- *
- * Example usage:
- * @code
- * stream << BinText(TStringBuf("aaa")); // Will output "01100001 01100001 01100001"
- * @endcode
- *
- * @param value String to output.
- */
- template <typename TChar>
- static inline ::NFormatPrivate::TBaseText<TChar, 2> BinText(const TBasicStringBuf<TChar> value) {
- return ::NFormatPrivate::TBaseText<TChar, 2>(value);
- }
- /**
- * Output manipulator for printing `TDuration` values.
- *
- * When written into a `IOutputStream`, writes out the provided `TDuration`
- * in auto-adjusted human-readable format.
- *
- * Example usage:
- * @code
- * stream << HumanReadable(TDuration::MicroSeconds(100)); // Will output "100us"
- * stream << HumanReadable(TDuration::Seconds(3672)); // Will output "1h 1m 12s"
- * @endcode
- *
- * @param value Value to output.
- */
- static constexpr ::NFormatPrivate::THumanReadableDuration HumanReadable(const TDuration duration) noexcept {
- return ::NFormatPrivate::THumanReadableDuration(duration);
- }
- /**
- * Output manipulator for writing out human-readable number of elements / memory
- * amount in `ls -h` style.
- *
- * When written into a `IOutputStream`, writes out the provided unsigned integer
- * variable with small precision and a suffix (like 'K', 'M', 'G' for numbers, or
- * 'B', 'KiB', 'MiB', 'GiB' for bytes).
- *
- * For quantities, base 1000 is used. For bytes, base is 1024.
- *
- * Example usage:
- * @code
- * stream << HumanReadableSize(1024, SF_QUANTITY); // Will output "1.02K"
- * stream << HumanReadableSize(1024, SF_BYTES); // Will output "1KiB"
- * stream << "average usage " << HumanReadableSize(100 / 3., SF_BYTES); // Will output "average usage "33.3B""
- * @endcode
- *
- * @param value Value to output.
- * @param format Format to use.
- */
- static constexpr ::NFormatPrivate::THumanReadableSize HumanReadableSize(const double size, ESizeFormat format) noexcept {
- return {size, format};
- }
- void Time(IOutputStream& l);
- void TimeHumanReadable(IOutputStream& l);
- /**
- * Output manipulator for adjusting precision of floating point values.
- *
- * When written into a `IOutputStream`, writes out the provided floating point
- * variable with given precision. The behavior depends on provided `mode`.
- *
- * Example usage:
- * @code
- * stream << Prec(1.2345678901234567, PREC_AUTO); // Will output "1.2345678901234567"
- * @endcode
- *
- * @param value float or double to output.
- * @param mode Output mode.
- * @param ndigits Number of significant digits (in `PREC_NDIGITS` and `PREC_POINT_DIGITS` mode).
- * @see EFloatToStringMode
- */
- template <typename T>
- static constexpr ::NFormatPrivate::TFloatPrecision<T> Prec(const T& value, const EFloatToStringMode mode, const int ndigits = 0) noexcept {
- return {value, mode, ndigits};
- }
- /**
- * Output manipulator for adjusting precision of floating point values.
- *
- * When written into a `IOutputStream`, writes out the provided floating point
- * variable with given precision. The behavior is equivalent to `Prec(value, PREC_NDIGITS, ndigits)`.
- *
- * Example usage:
- * @code
- * stream << Prec(1.2345678901234567, 3); // Will output "1.23"
- * @endcode
- *
- * @param value float or double to output.
- * @param ndigits Number of significant digits.
- */
- template <typename T>
- static constexpr ::NFormatPrivate::TFloatPrecision<T> Prec(const T& value, const int ndigits) noexcept {
- return {value, PREC_NDIGITS, ndigits};
- }
|