123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- #pragma once
- #include <util/system/defaults.h>
- #include <util/stream/str.h>
- #include <util/generic/maybe.h>
- #include <util/generic/string.h>
- #include <util/generic/strbuf.h>
- #include <util/generic/typetraits.h>
- #include <util/generic/yexception.h>
- /*
- * specialized for all arithmetic types
- */
- template <class T>
- size_t ToStringImpl(T t, char* buf, size_t len);
- /**
- * Converts @c t to string writing not more than @c len bytes to output buffer @c buf.
- * No NULL terminator appended! Throws exception on buffer overflow.
- * @return number of bytes written
- */
- template <class T>
- inline size_t ToString(const T& t, char* buf, size_t len) {
- using TParam = typename TTypeTraits<T>::TFuncParam;
- return ToStringImpl<TParam>(t, buf, len);
- }
- /**
- * Floating point to string conversion mode, values are enforced by `dtoa_impl.cpp`.
- */
- enum EFloatToStringMode {
- /** 0.1f -> "0.1", 0.12345678f -> "0.12345678", ignores ndigits. */
- PREC_AUTO = 0,
- /** "%g" mode, writes up to the given number of significant digits:
- * 0.1f -> "0.1", 0.12345678f -> "0.123457" for ndigits=6, 1.2e-06f -> "1.2e-06" */
- PREC_NDIGITS = 2,
- /** "%f" mode, writes the given number of digits after decimal point:
- * 0.1f -> "0.100000", 1.2e-06f -> "0.000001" for ndigits=6 */
- PREC_POINT_DIGITS = 3,
- /** same as PREC_POINT_DIGITS, but stripping trailing zeroes:
- * 0.1f for ndgigits=6 -> "0.1" */
- PREC_POINT_DIGITS_STRIP_ZEROES = 4
- };
- size_t FloatToString(float t, char* buf, size_t len, EFloatToStringMode mode = PREC_AUTO, int ndigits = 0);
- size_t FloatToString(double t, char* buf, size_t len, EFloatToStringMode mode = PREC_AUTO, int ndigits = 0);
- template <typename T>
- inline TString FloatToString(const T& t, EFloatToStringMode mode = PREC_AUTO, int ndigits = 0) {
- char buf[512]; // Max<double>() with mode = PREC_POINT_DIGITS has 309 digits before the decimal point
- size_t count = FloatToString(t, buf, sizeof(buf), mode, ndigits);
- return TString(buf, count);
- }
- namespace NPrivate {
- template <class T, bool isSimple>
- struct TToString {
- static inline TString Cvt(const T& t) {
- char buf[512];
- return TString(buf, ToString<T>(t, buf, sizeof(buf)));
- }
- };
- template <class T>
- struct TToString<T, false> {
- static inline TString Cvt(const T& t) {
- TString s;
- TStringOutput o(s);
- o << t;
- return s;
- }
- };
- } // namespace NPrivate
- /*
- * some clever implementations...
- */
- template <class T>
- inline TString ToString(const T& t) {
- using TR = std::remove_cv_t<T>;
- return ::NPrivate::TToString<TR, std::is_arithmetic<TR>::value>::Cvt((const TR&)t);
- }
- inline const TString& ToString(const TString& s Y_LIFETIME_BOUND) noexcept {
- return s;
- }
- inline TString&& ToString(TString&& s Y_LIFETIME_BOUND) noexcept {
- return std::move(s);
- }
- inline TString ToString(const char* s) {
- return s;
- }
- inline TString ToString(char* s) {
- return s;
- }
- /*
- * Wrapper for wide strings.
- */
- template <class T>
- inline TUtf16String ToWtring(const T& t) {
- return TUtf16String::FromAscii(ToString(t));
- }
- inline const TUtf16String& ToWtring(const TUtf16String& w Y_LIFETIME_BOUND) noexcept {
- return w;
- }
- inline TUtf16String&& ToWtring(TUtf16String&& w Y_LIFETIME_BOUND) noexcept {
- return std::move(w);
- }
- struct TFromStringException: public TBadCastException {
- };
- /*
- * specialized for:
- * bool
- * short
- * unsigned short
- * int
- * unsigned int
- * long
- * unsigned long
- * long long
- * unsigned long long
- * float
- * double
- * long double
- */
- template <typename T, typename TChar>
- T FromStringImpl(const TChar* data, size_t len);
- template <typename T, typename TChar>
- inline T FromString(const TChar* data, size_t len) {
- return ::FromStringImpl<T>(data, len);
- }
- template <typename T, typename TChar>
- inline T FromString(const TChar* data) {
- return ::FromString<T>(data, std::char_traits<TChar>::length(data));
- }
- template <class T>
- inline T FromString(const TStringBuf& s) {
- return ::FromString<T>(s.data(), s.size());
- }
- template <class T>
- inline T FromString(const TString& s) {
- return ::FromString<T>(s.data(), s.size());
- }
- template <class T>
- inline T FromString(const std::string& s) {
- return ::FromString<T>(s.data(), s.size());
- }
- template <>
- inline TString FromString<TString>(const TString& s) {
- return s;
- }
- template <class T>
- inline T FromString(const TWtringBuf& s) {
- return ::FromString<T, typename TWtringBuf::char_type>(s.data(), s.size());
- }
- template <class T>
- inline T FromString(const TUtf16String& s) {
- return ::FromString<T, wchar16>(s.data(), s.size());
- }
- namespace NPrivate {
- template <typename TChar>
- class TFromString {
- const TChar* const Data;
- const size_t Len;
- public:
- inline TFromString(const TChar* data, size_t len)
- : Data(data)
- , Len(len)
- {
- }
- template <typename T>
- inline operator T() const {
- return FromString<T, TChar>(Data, Len);
- }
- };
- } // namespace NPrivate
- template <typename TChar>
- inline ::NPrivate::TFromString<TChar> FromString(const TChar* data, size_t len) {
- return ::NPrivate::TFromString<TChar>(data, len);
- }
- template <typename TChar>
- inline ::NPrivate::TFromString<TChar> FromString(const TChar* data) {
- return ::NPrivate::TFromString<TChar>(data, std::char_traits<TChar>::length(data));
- }
- template <typename T>
- inline ::NPrivate::TFromString<typename T::TChar> FromString(const T& s) {
- return ::NPrivate::TFromString<typename T::TChar>(s.data(), s.size());
- }
- // Conversion exception free versions
- template <typename T, typename TChar>
- bool TryFromStringImpl(const TChar* data, size_t len, T& result);
- /**
- * @param data Source string buffer pointer
- * @param len Source string length, in characters
- * @param result Place to store conversion result value.
- * If conversion error occurs, no value stored in @c result
- * @return @c true in case of successful conversion, @c false otherwise
- **/
- template <typename T, typename TChar>
- inline bool TryFromString(const TChar* data, size_t len, T& result) {
- return TryFromStringImpl<T>(data, len, result);
- }
- template <typename T, typename TChar>
- inline bool TryFromString(const TChar* data, T& result) {
- return TryFromString<T>(data, std::char_traits<TChar>::length(data), result);
- }
- template <class T, class TChar>
- inline bool TryFromString(const TChar* data, const size_t len, T& result, const T& def) {
- if (TryFromString<T>(data, len, result)) {
- return true;
- }
- result = def;
- return false;
- }
- template <class T>
- inline bool TryFromString(const TStringBuf& s, T& result) {
- return TryFromString<T>(s.data(), s.size(), result);
- }
- template <class T>
- inline bool TryFromString(const TString& s, T& result) {
- return TryFromString<T>(s.data(), s.size(), result);
- }
- template <class T>
- inline bool TryFromString(const std::string& s, T& result) {
- return TryFromString<T>(s.data(), s.size(), result);
- }
- template <class T>
- inline bool TryFromString(const TWtringBuf& s, T& result) {
- return TryFromString<T>(s.data(), s.size(), result);
- }
- template <class T>
- inline bool TryFromString(const TUtf16String& s, T& result) {
- return TryFromString<T>(s.data(), s.size(), result);
- }
- template <class T, class TChar>
- inline TMaybe<T> TryFromString(TBasicStringBuf<TChar> s) {
- TMaybe<T> result{NMaybe::TInPlace{}};
- if (!TryFromString<T>(s, *result)) {
- result.Clear();
- }
- return result;
- }
- template <class T, class TChar>
- inline TMaybe<T> TryFromString(const TChar* data) {
- return TryFromString<T>(TBasicStringBuf<TChar>(data));
- }
- template <class T>
- inline TMaybe<T> TryFromString(const TString& s) {
- return TryFromString<T>(TStringBuf(s));
- }
- template <class T>
- inline TMaybe<T> TryFromString(const std::string& s) {
- return TryFromString<T>(TStringBuf(s));
- }
- template <class T>
- inline TMaybe<T> TryFromString(const TUtf16String& s) {
- return TryFromString<T>(TWtringBuf(s));
- }
- template <class T, class TStringType>
- inline bool TryFromStringWithDefault(const TStringType& s, T& result, const T& def) {
- return TryFromString<T>(s.data(), s.size(), result, def);
- }
- template <class T>
- inline bool TryFromStringWithDefault(const char* s, T& result, const T& def) {
- return TryFromStringWithDefault<T>(TStringBuf(s), result, def);
- }
- template <class T, class TStringType>
- inline bool TryFromStringWithDefault(const TStringType& s, T& result) {
- return TryFromStringWithDefault<T>(s, result, T());
- }
- // FromString methods with default value if data is invalid
- template <class T, class TChar>
- inline T FromString(const TChar* data, const size_t len, const T& def) {
- T result;
- TryFromString<T>(data, len, result, def);
- return result;
- }
- template <class T, class TStringType>
- inline T FromStringWithDefault(const TStringType& s, const T& def) {
- return FromString<T>(s.data(), s.size(), def);
- }
- template <class T>
- inline T FromStringWithDefault(const char* s, const T& def) {
- return FromStringWithDefault<T>(TStringBuf(s), def);
- }
- template <class T, class TStringType>
- inline T FromStringWithDefault(const TStringType& s) {
- return FromStringWithDefault<T>(s, T());
- }
- double StrToD(const char* b, char** se);
- double StrToD(const char* b, const char* e, char** se);
- template <int base, class T>
- size_t IntToString(T t, char* buf, size_t len);
- template <int base, class T>
- inline TString IntToString(T t) {
- static_assert(std::is_arithmetic<std::remove_cv_t<T>>::value, "expect std::is_arithmetic<std::remove_cv_t<T>>::value");
- char buf[256];
- return TString(buf, IntToString<base>(t, buf, sizeof(buf)));
- }
- template <int base, class TInt, class TChar>
- bool TryIntFromString(const TChar* data, size_t len, TInt& result);
- template <int base, class TInt, class TStringType>
- inline bool TryIntFromString(const TStringType& s, TInt& result) {
- return TryIntFromString<base>(s.data(), s.size(), result);
- }
- template <class TInt, int base, class TChar>
- TInt IntFromString(const TChar* str, size_t len);
- template <class TInt, int base, class TChar>
- inline TInt IntFromString(const TChar* str) {
- return IntFromString<TInt, base>(str, std::char_traits<TChar>::length(str));
- }
- template <class TInt, int base, class TStringType>
- inline TInt IntFromString(const TStringType& str) {
- return IntFromString<TInt, base>(str.data(), str.size());
- }
- static inline TString ToString(const TStringBuf str) {
- return TString(str);
- }
- static inline TUtf16String ToWtring(const TWtringBuf wtr) {
- return TUtf16String(wtr);
- }
- static inline TUtf32String ToUtf32String(const TUtf32StringBuf wtr) {
- return TUtf32String(wtr);
- }
- template <typename T, unsigned radix = 10, class TChar = char>
- class TIntStringBuf {
- private:
- // inline constexprs are not supported by CUDA yet
- static constexpr char IntToChar[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
- static_assert(1 < radix && radix < 17, "expect 1 < radix && radix < 17");
- // auxiliary recursive template used to calculate maximum buffer size for the given type
- template <T v>
- struct TBufSizeRec {
- // MSVC is tries to evaluate both sides of ?: operator and doesn't break recursion
- static constexpr ui32 GetValue() {
- if (v == 0) {
- return 1;
- }
- return 1 + TBufSizeRec<v / radix>::value;
- }
- static constexpr ui32 value = GetValue();
- };
- public:
- static constexpr ui32 bufferSize = (std::is_signed<T>::value ? 1 : 0) +
- ((radix == 2) ? sizeof(T) * 8 : TBufSizeRec<std::numeric_limits<T>::max()>::value);
- template <std::enable_if_t<std::is_integral<T>::value, bool> = true>
- explicit constexpr TIntStringBuf(T t) {
- Size_ = Convert(t, Buf_, sizeof(Buf_));
- #if __cplusplus >= 202002L // is_constant_evaluated is not supported by CUDA yet
- if (std::is_constant_evaluated()) {
- #endif
- // Init the rest of the array,
- // otherwise constexpr copy and move constructors don't work due to uninitialized data access
- std::fill(Buf_ + Size_, Buf_ + sizeof(Buf_), '\0');
- #if __cplusplus >= 202002L
- }
- #endif
- }
- constexpr operator TStringBuf() const noexcept {
- return TStringBuf(Buf_, Size_);
- }
- constexpr static ui32 Convert(T t, TChar* buf, size_t bufLen) {
- bufLen = std::min<size_t>(bufferSize, bufLen);
- if (std::is_signed<T>::value && t < 0) {
- Y_ENSURE(bufLen >= 2, TStringBuf("not enough room in buffer"));
- buf[0] = '-';
- const auto mt = std::make_unsigned_t<T>(-(t + 1)) + std::make_unsigned_t<T>(1);
- return ConvertUnsigned(mt, &buf[1], bufLen - 1) + 1;
- } else {
- return ConvertUnsigned(t, buf, bufLen);
- }
- }
- private:
- constexpr static ui32 ConvertUnsigned(typename std::make_unsigned<T>::type t, TChar* buf, ui32 bufLen) {
- Y_ENSURE(bufLen, TStringBuf("zero length"));
- if (t == 0) {
- *buf = '0';
- return 1;
- }
- auto* be = buf + bufLen;
- ui32 l = 0;
- while (t > 0 && be > buf) {
- const auto v = t / radix;
- const auto r = (radix == 2 || radix == 4 || radix == 8 || radix == 16) ? t & (radix - 1) : t - radix * v;
- --be;
- if /*constexpr*/ (radix <= 10) { // if constexpr is not supported by CUDA yet
- *be = r + '0';
- } else {
- *be = IntToChar[r];
- }
- ++l;
- t = v;
- }
- Y_ENSURE(!t, TStringBuf("not enough room in buffer"));
- if (buf != be) {
- for (ui32 i = 0; i < l; ++i) {
- *buf = *be;
- ++buf;
- ++be;
- }
- }
- return l;
- }
- ui32 Size_;
- TChar Buf_[bufferSize];
- };
|