diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:17 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:17 +0300 |
commit | d3a398281c6fd1d3672036cb2d63f842d2cb28c5 (patch) | |
tree | dd4bd3ca0f36b817e96812825ffaf10d645803f2 /util/string/cast.cpp | |
parent | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (diff) | |
download | ydb-d3a398281c6fd1d3672036cb2d63f842d2cb28c5.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 2 of 2.
Diffstat (limited to 'util/string/cast.cpp')
-rw-r--r-- | util/string/cast.cpp | 774 |
1 files changed, 387 insertions, 387 deletions
diff --git a/util/string/cast.cpp b/util/string/cast.cpp index 3b1e050e53..aa1e65a8e9 100644 --- a/util/string/cast.cpp +++ b/util/string/cast.cpp @@ -1,41 +1,41 @@ #include <util/system/defaults.h> - -#if defined(_freebsd_) && !defined(__LONG_LONG_SUPPORTED) - #define __LONG_LONG_SUPPORTED -#endif - -#include <cstdio> -#include <string> + +#if defined(_freebsd_) && !defined(__LONG_LONG_SUPPORTED) + #define __LONG_LONG_SUPPORTED +#endif + +#include <cstdio> +#include <string> #include <cmath> - + #include <util/string/type.h> #include <util/string/cast.h> #include <util/string/escape.h> - -#include <contrib/libs/double-conversion/double-conversion.h> - + +#include <contrib/libs/double-conversion/double-conversion.h> + #include <util/generic/string.h> #include <util/system/yassert.h> #include <util/generic/yexception.h> -#include <util/generic/typetraits.h> +#include <util/generic/typetraits.h> #include <util/generic/ylimits.h> -#include <util/generic/singleton.h> -#include <util/generic/utility.h> - -using double_conversion::DoubleToStringConverter; -using double_conversion::StringBuilder; -using double_conversion::StringToDoubleConverter; - -/* - * ------------------------------ formatters ------------------------------ - */ +#include <util/generic/singleton.h> +#include <util/generic/utility.h> + +using double_conversion::DoubleToStringConverter; +using double_conversion::StringBuilder; +using double_conversion::StringToDoubleConverter; + +/* + * ------------------------------ formatters ------------------------------ + */ namespace { constexpr char IntToChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; static_assert(Y_ARRAY_SIZE(IntToChar) == 16, "expect Y_ARRAY_SIZE(IntToChar) == 16"); - // clang-format off + // clang-format off constexpr int LetterToIntMap[] = { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, @@ -49,23 +49,23 @@ namespace { 20, 20, 20, 20, 20, 20, 20, 10, 11, 12, 13, 14, 15, }; - // clang-format on + // clang-format on template <class T> std::enable_if_t<std::is_signed<T>::value, std::make_unsigned_t<T>> NegateNegativeSigned(T value) noexcept { - return std::make_unsigned_t<T>(-(value + 1)) + std::make_unsigned_t<T>(1); + return std::make_unsigned_t<T>(-(value + 1)) + std::make_unsigned_t<T>(1); } template <class T> std::enable_if_t<std::is_unsigned<T>::value, std::make_unsigned_t<T>> NegateNegativeSigned(T) noexcept { - Y_UNREACHABLE(); + Y_UNREACHABLE(); } - template <class T> + template <class T> std::make_signed_t<T> NegatePositiveSigned(T value) noexcept { - return value > 0 ? (-std::make_signed_t<T>(value - 1) - 1) : 0; - } - + return value > 0 ? (-std::make_signed_t<T>(value - 1) - 1) : 0; + } + template <class T, unsigned base, class TChar> struct TBasicIntFormatter { static_assert(1 < base && base < 17, "expect 1 < base && base < 17"); @@ -73,7 +73,7 @@ namespace { static inline size_t Format(T value, TChar* buf, size_t len) { Y_ENSURE(len, TStringBuf("zero length")); - + TChar* tmp = buf; do { @@ -99,46 +99,46 @@ namespace { } return result; - } + } }; - + template <class T, unsigned base, class TChar> struct TIntFormatter { static_assert(1 < base && base < 17, "expect 1 < base && base < 17"); static_assert(std::is_integral<T>::value, "T must be an integral type."); - + static inline size_t Format(T value, TChar* buf, size_t len) { - using TUFmt = TBasicIntFormatter<std::make_unsigned_t<T>, base, TChar>; + using TUFmt = TBasicIntFormatter<std::make_unsigned_t<T>, base, TChar>; - if (std::is_signed<T>::value && value < 0) { + if (std::is_signed<T>::value && value < 0) { Y_ENSURE(len >= 2, TStringBuf("not enough room in buffer")); *buf = '-'; - - return 1 + TUFmt::Format(NegateNegativeSigned(value), buf + 1, len - 1); + + return 1 + TUFmt::Format(NegateNegativeSigned(value), buf + 1, len - 1); } - return TUFmt::Format(value, buf, len); - } + return TUFmt::Format(value, buf, len); + } }; - + template <class T> struct TFltModifiers; - + template <class T, int base, class TChar> Y_NO_INLINE size_t FormatInt(T value, TChar* buf, size_t len) { return TIntFormatter<T, base, TChar>::Format(value, buf, len); } - + template <class T> inline size_t FormatFlt(T t, char* buf, size_t len) { const int ret = snprintf(buf, len, TFltModifiers<T>::ModifierWrite, t); - + Y_ENSURE(ret >= 0 && (size_t)ret <= len, TStringBuf("cannot format float")); - + return (size_t)ret; - } - + } + enum EParseStatus { PS_OK = 0, PS_EMPTY_STRING, @@ -147,97 +147,97 @@ namespace { PS_BAD_SYMBOL, PS_OVERFLOW, }; - + constexpr ui8 SAFE_LENS[4][17] = { - {0, 0, 7, 5, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1}, - {0, 0, 15, 10, 7, 6, 6, 5, 5, 5, 4, 4, 4, 4, 4, 4, 3}, - {0, 0, 31, 20, 15, 13, 12, 11, 10, 10, 9, 9, 8, 8, 8, 8, 7}, - {0, 0, 63, 40, 31, 27, 24, 22, 21, 20, 19, 18, 17, 17, 16, 16, 15}, - }; - - inline constexpr ui8 ConstLog2(ui8 x) noexcept { - return x == 1 ? 0 : 1 + ConstLog2(x / 2); - } - - template <unsigned BASE, class TChar, class T> + {0, 0, 7, 5, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1}, + {0, 0, 15, 10, 7, 6, 6, 5, 5, 5, 4, 4, 4, 4, 4, 4, 3}, + {0, 0, 31, 20, 15, 13, 12, 11, 10, 10, 9, 9, 8, 8, 8, 8, 7}, + {0, 0, 63, 40, 31, 27, 24, 22, 21, 20, 19, 18, 17, 17, 16, 16, 15}, + }; + + inline constexpr ui8 ConstLog2(ui8 x) noexcept { + return x == 1 ? 0 : 1 + ConstLog2(x / 2); + } + + template <unsigned BASE, class TChar, class T> inline std::enable_if_t<(BASE > 10), bool> CharToDigit(TChar c, T* digit) noexcept { - unsigned uc = c; - - if (uc >= Y_ARRAY_SIZE(LetterToIntMap)) { - return false; - } - - *digit = LetterToIntMap[uc]; - - return *digit < BASE; - } - - template <unsigned BASE, class TChar, class T> + unsigned uc = c; + + if (uc >= Y_ARRAY_SIZE(LetterToIntMap)) { + return false; + } + + *digit = LetterToIntMap[uc]; + + return *digit < BASE; + } + + template <unsigned BASE, class TChar, class T> inline std::enable_if_t<(BASE <= 10), bool> CharToDigit(TChar c, T* digit) noexcept { - return (c >= '0') && ((*digit = (c - '0')) < BASE); - } - + return (c >= '0') && ((*digit = (c - '0')) < BASE); + } + template <class T, unsigned base, class TChar> struct TBasicIntParser { static_assert(1 < base && base < 17, "Expect 1 < base && base < 17."); static_assert(std::is_unsigned<T>::value, "TBasicIntParser can only handle unsigned integers."); - enum : unsigned { - BASE_POW_2 = base * base, - }; - - static inline EParseStatus Parse(const TChar** ppos, const TChar* end, T max, T* target) noexcept { + enum : unsigned { + BASE_POW_2 = base * base, + }; + + static inline EParseStatus Parse(const TChar** ppos, const TChar* end, T max, T* target) noexcept { Y_ASSERT(*ppos != end); /* This check should be somewhere up the stack. */ - const size_t maxSafeLen = SAFE_LENS[ConstLog2(sizeof(T))][base]; - - // can parse without overflow - if (size_t(end - *ppos) <= maxSafeLen) { - T result; - - if (ParseFast(*ppos, end, &result) && result <= max) { - *target = result; - - return PS_OK; - } - } - - return ParseSlow(ppos, end, max, target); - } - - static inline bool ParseFast(const TChar* pos, const TChar* end, T* target) noexcept { + const size_t maxSafeLen = SAFE_LENS[ConstLog2(sizeof(T))][base]; + + // can parse without overflow + if (size_t(end - *ppos) <= maxSafeLen) { + T result; + + if (ParseFast(*ppos, end, &result) && result <= max) { + *target = result; + + return PS_OK; + } + } + + return ParseSlow(ppos, end, max, target); + } + + static inline bool ParseFast(const TChar* pos, const TChar* end, T* target) noexcept { + T result = T(); + T d1; + T d2; + + // we have end > pos + auto beforeEnd = end - 1; + + while (pos < beforeEnd && CharToDigit<base>(*pos, &d1) && CharToDigit<base>(*(pos + 1), &d2)) { + result = result * BASE_POW_2 + d1 * base + d2; + pos += 2; + } + + while (pos != end && CharToDigit<base>(*pos, &d1)) { + result = result * base + d1; + ++pos; + } + + *target = result; + + return pos == end; + } + + static inline EParseStatus ParseSlow(const TChar** ppos, const TChar* end, T max, T* target) noexcept { T result = T(); - T d1; - T d2; - - // we have end > pos - auto beforeEnd = end - 1; - - while (pos < beforeEnd && CharToDigit<base>(*pos, &d1) && CharToDigit<base>(*(pos + 1), &d2)) { - result = result * BASE_POW_2 + d1 * base + d2; - pos += 2; - } - - while (pos != end && CharToDigit<base>(*pos, &d1)) { - result = result * base + d1; - ++pos; - } - - *target = result; - - return pos == end; - } - - static inline EParseStatus ParseSlow(const TChar** ppos, const TChar* end, T max, T* target) noexcept { - T result = T(); T preMulMax = max / base; const TChar* pos = *ppos; while (pos != end) { T digit; - - if (!CharToDigit<base>(*pos, &digit)) { + + if (!CharToDigit<base>(*pos, &digit)) { *ppos = pos; - + return PS_BAD_SYMBOL; } @@ -256,7 +256,7 @@ namespace { } *target = result; - + return PS_OK; } }; @@ -282,8 +282,8 @@ namespace { const TChar* pos = *ppos; if (pos == end) { return PS_EMPTY_STRING; - } - + } + bool negative = false; TUnsigned max; if (*pos == '+') { @@ -313,14 +313,14 @@ namespace { } if (IsSigned) { - *target = negative ? NegatePositiveSigned(result) : static_cast<T>(result); + *target = negative ? NegatePositiveSigned(result) : static_cast<T>(result); } else { *target = result; } return PS_OK; - } + } }; - + template <class TChar> [[noreturn]] static Y_NO_INLINE void ThrowParseError(EParseStatus status, const TChar* data, size_t len, const TChar* pos) { Y_ASSERT(status != PS_OK); @@ -341,21 +341,21 @@ namespace { default: ythrow yexception() << TStringBuf("Unknown error code in string converter. "); } - } - + } + template <typename T, typename TUnsigned, int base, typename TChar> Y_NO_INLINE T ParseInt(const TChar* data, size_t len, const TBounds<TUnsigned>& bounds) { T result; const TChar* pos = data; EParseStatus status = TIntParser<T, base, TChar>::Parse(&pos, pos + len, bounds, &result); - + if (status == PS_OK) { return result; } else { ThrowParseError(status, data, len, pos); } } - + template <typename T, typename TUnsigned, int base, typename TChar> Y_NO_INLINE bool TryParseInt(const TChar* data, size_t len, const TBounds<TUnsigned>& bounds, T* result) { return TIntParser<T, base, TChar>::Parse(&data, data + len, bounds, result) == PS_OK; @@ -387,20 +387,20 @@ namespace { ythrow TFromStringException() << TStringBuf("cannot parse float(") << TStringBuf(data, len) << TStringBuf(")"); } -#define DEF_FLT_MOD(type, modifierWrite, modifierRead) \ - template <> \ - struct TFltModifiers<type> { \ - static const char* const ModifierWrite; \ - static const char* const ModifierReadAndChar; \ - }; \ - \ - const char* const TFltModifiers<type>::ModifierWrite = modifierWrite; \ - const char* const TFltModifiers<type>::ModifierReadAndChar = modifierRead "%c"; - +#define DEF_FLT_MOD(type, modifierWrite, modifierRead) \ + template <> \ + struct TFltModifiers<type> { \ + static const char* const ModifierWrite; \ + static const char* const ModifierReadAndChar; \ + }; \ + \ + const char* const TFltModifiers<type>::ModifierWrite = modifierWrite; \ + const char* const TFltModifiers<type>::ModifierReadAndChar = modifierRead "%c"; + DEF_FLT_MOD(long double, "%.10Lg", "%Lg") - -#undef DEF_FLT_MOD - + +#undef DEF_FLT_MOD + /* The following constants are initialized in terms of <climits> constants to make * sure they go into binary as actual values and there is no associated * initialization code. @@ -415,34 +415,34 @@ namespace { constexpr TBounds<ui64> lUBounds = {static_cast<ui64>(ULONG_MAX), 0}; constexpr TBounds<ui64> llSBounds = {static_cast<ui64>(LLONG_MAX), static_cast<ui64>(ULLONG_MAX - LLONG_MAX)}; constexpr TBounds<ui64> llUBounds = {static_cast<ui64>(ULLONG_MAX), 0}; -} - -#define DEF_INT_SPEC_II(TYPE, ITYPE, BASE) \ - template <> \ - size_t IntToString<BASE, TYPE>(TYPE value, char* buf, size_t len) { \ - return FormatInt<ITYPE, BASE, char>(value, buf, len); \ - } - -#define DEF_INT_SPEC_I(TYPE, ITYPE) \ - template <> \ - size_t ToStringImpl<TYPE>(TYPE value, char* buf, size_t len) { \ - return FormatInt<ITYPE, 10, char>(value, buf, len); \ - } \ - DEF_INT_SPEC_II(TYPE, ITYPE, 2) \ - DEF_INT_SPEC_II(TYPE, ITYPE, 8) \ - DEF_INT_SPEC_II(TYPE, ITYPE, 10) \ +} + +#define DEF_INT_SPEC_II(TYPE, ITYPE, BASE) \ + template <> \ + size_t IntToString<BASE, TYPE>(TYPE value, char* buf, size_t len) { \ + return FormatInt<ITYPE, BASE, char>(value, buf, len); \ + } + +#define DEF_INT_SPEC_I(TYPE, ITYPE) \ + template <> \ + size_t ToStringImpl<TYPE>(TYPE value, char* buf, size_t len) { \ + return FormatInt<ITYPE, 10, char>(value, buf, len); \ + } \ + DEF_INT_SPEC_II(TYPE, ITYPE, 2) \ + DEF_INT_SPEC_II(TYPE, ITYPE, 8) \ + DEF_INT_SPEC_II(TYPE, ITYPE, 10) \ DEF_INT_SPEC_II(TYPE, ITYPE, 16) - -#define DEF_INT_SPEC(TYPE) \ - DEF_INT_SPEC_I(signed TYPE, i64) \ + +#define DEF_INT_SPEC(TYPE) \ + DEF_INT_SPEC_I(signed TYPE, i64) \ DEF_INT_SPEC_I(unsigned TYPE, ui64) - -DEF_INT_SPEC(char) -DEF_INT_SPEC(short) -DEF_INT_SPEC(int) -DEF_INT_SPEC(long) -DEF_INT_SPEC(long long) - + +DEF_INT_SPEC(char) +DEF_INT_SPEC(short) +DEF_INT_SPEC(int) +DEF_INT_SPEC(long) +DEF_INT_SPEC(long long) + #ifdef __cpp_char8_t template <> size_t ToStringImpl<char8_t>(char8_t value, char* buf, size_t len) { @@ -458,20 +458,20 @@ DEF_INT_SPEC_I(wchar_t, TWCharIType) DEF_INT_SPEC_I(wchar16, ui64) // wchar16 is always unsigned DEF_INT_SPEC_I(wchar32, ui64) // wchar32 is always unsigned -#undef DEF_INT_SPEC +#undef DEF_INT_SPEC #undef DEF_INT_SPEC_I #undef DEF_INT_SPEC_II - -#define DEF_FLT_SPEC(type) \ - template <> \ - size_t ToStringImpl<type>(type t, char* buf, size_t len) { \ - return FormatFlt<type>(t, buf, len); \ - } - + +#define DEF_FLT_SPEC(type) \ + template <> \ + size_t ToStringImpl<type>(type t, char* buf, size_t len) { \ + return FormatFlt<type>(t, buf, len); \ + } + DEF_FLT_SPEC(long double) -#undef DEF_FLT_SPEC - +#undef DEF_FLT_SPEC + template <> size_t ToStringImpl<bool>(bool t, char* buf, size_t len) { Y_ENSURE(len, TStringBuf("zero length")); @@ -479,9 +479,9 @@ size_t ToStringImpl<bool>(bool t, char* buf, size_t len) { return 1; } -/* - * ------------------------------ parsers ------------------------------ - */ +/* + * ------------------------------ parsers ------------------------------ + */ template <> bool TryFromStringImpl<bool>(const char* data, size_t len, bool& result) { @@ -508,11 +508,11 @@ bool TryFromStringImpl<bool>(const char* data, size_t len, bool& result) { template <> bool FromStringImpl<bool>(const char* data, size_t len) { bool result; - - if (!TryFromStringImpl<bool>(data, len, result)) { + + if (!TryFromStringImpl<bool>(data, len, result)) { ythrow TFromStringException() << TStringBuf("Cannot parse bool(") << TStringBuf(data, len) << TStringBuf("). "); - } - + } + return result; } @@ -527,8 +527,8 @@ TStringBuf FromStringImpl<TStringBuf>(const char* data, size_t len) { } template <> -std::string FromStringImpl<std::string>(const char* data, size_t len) { - return std::string(data, len); +std::string FromStringImpl<std::string>(const char* data, size_t len) { + return std::string(data, len); } template <> @@ -555,7 +555,7 @@ bool TryFromStringImpl<TString>(const char* data, size_t len, TString& result) { } template <> -bool TryFromStringImpl<std::string>(const char* data, size_t len, std::string& result) { +bool TryFromStringImpl<std::string>(const char* data, size_t len, std::string& result) { result.assign(data, len); return true; } @@ -572,46 +572,46 @@ bool TryFromStringImpl<TUtf16String>(const wchar16* data, size_t len, TUtf16Stri return true; } -#define DEF_INT_SPEC_III(CHAR, TYPE, ITYPE, BOUNDS, BASE) \ - template <> \ - TYPE IntFromString<TYPE, BASE>(const CHAR* data, size_t len) { \ - return ParseInt<ITYPE, ui64, BASE>(data, len, BOUNDS); \ - } \ - template <> \ - bool TryIntFromString<BASE>(const CHAR* data, size_t len, TYPE& result) { \ - ITYPE tmp; \ - bool status = TryParseInt<ITYPE, ui64, BASE>(data, len, BOUNDS, &tmp); \ - if (status) { \ - result = tmp; \ - } \ - return status; \ - } - -#define DEF_INT_SPEC_II(CHAR, TYPE, ITYPE, BOUNDS) \ - template <> \ - TYPE FromStringImpl<TYPE>(const CHAR* data, size_t len) { \ - return ParseInt<ITYPE, ui64, 10>(data, len, BOUNDS); \ - } \ - template <> \ - bool TryFromStringImpl<TYPE>(const CHAR* data, size_t len, TYPE& result) { \ - ITYPE tmp; \ - bool status = TryParseInt<ITYPE, ui64, 10>(data, len, BOUNDS, &tmp); \ - if (status) { \ - result = tmp; \ - } \ - return status; \ - } \ - DEF_INT_SPEC_III(CHAR, TYPE, ITYPE, BOUNDS, 2) \ - DEF_INT_SPEC_III(CHAR, TYPE, ITYPE, BOUNDS, 8) \ - DEF_INT_SPEC_III(CHAR, TYPE, ITYPE, BOUNDS, 10) \ +#define DEF_INT_SPEC_III(CHAR, TYPE, ITYPE, BOUNDS, BASE) \ + template <> \ + TYPE IntFromString<TYPE, BASE>(const CHAR* data, size_t len) { \ + return ParseInt<ITYPE, ui64, BASE>(data, len, BOUNDS); \ + } \ + template <> \ + bool TryIntFromString<BASE>(const CHAR* data, size_t len, TYPE& result) { \ + ITYPE tmp; \ + bool status = TryParseInt<ITYPE, ui64, BASE>(data, len, BOUNDS, &tmp); \ + if (status) { \ + result = tmp; \ + } \ + return status; \ + } + +#define DEF_INT_SPEC_II(CHAR, TYPE, ITYPE, BOUNDS) \ + template <> \ + TYPE FromStringImpl<TYPE>(const CHAR* data, size_t len) { \ + return ParseInt<ITYPE, ui64, 10>(data, len, BOUNDS); \ + } \ + template <> \ + bool TryFromStringImpl<TYPE>(const CHAR* data, size_t len, TYPE& result) { \ + ITYPE tmp; \ + bool status = TryParseInt<ITYPE, ui64, 10>(data, len, BOUNDS, &tmp); \ + if (status) { \ + result = tmp; \ + } \ + return status; \ + } \ + DEF_INT_SPEC_III(CHAR, TYPE, ITYPE, BOUNDS, 2) \ + DEF_INT_SPEC_III(CHAR, TYPE, ITYPE, BOUNDS, 8) \ + DEF_INT_SPEC_III(CHAR, TYPE, ITYPE, BOUNDS, 10) \ DEF_INT_SPEC_III(CHAR, TYPE, ITYPE, BOUNDS, 16) - -#define DEF_INT_SPEC_I(TYPE, ITYPE, BOUNDS) \ - DEF_INT_SPEC_II(char, TYPE, ITYPE, BOUNDS) \ - DEF_INT_SPEC_II(wchar16, TYPE, ITYPE, BOUNDS) -#define DEF_INT_SPEC(TYPE, ID) \ - DEF_INT_SPEC_I(signed TYPE, i64, ID##SBounds) \ +#define DEF_INT_SPEC_I(TYPE, ITYPE, BOUNDS) \ + DEF_INT_SPEC_II(char, TYPE, ITYPE, BOUNDS) \ + DEF_INT_SPEC_II(wchar16, TYPE, ITYPE, BOUNDS) + +#define DEF_INT_SPEC(TYPE, ID) \ + DEF_INT_SPEC_I(signed TYPE, i64, ID##SBounds) \ DEF_INT_SPEC_I(unsigned TYPE, ui64, ID##UBounds) #define DEF_INT_SPEC_FIXED_WIDTH(TYPE, ID) \ @@ -625,21 +625,21 @@ DEF_INT_SPEC(long, l) DEF_INT_SPEC(long long, ll) #undef DEF_INT_SPEC_FIXED_WIDTH -#undef DEF_INT_SPEC +#undef DEF_INT_SPEC #undef DEF_INT_SPEC_I #undef DEF_INT_SPEC_II #undef DEF_INT_SPEC_III - -#define DEF_FLT_SPEC(type) \ - template <> \ - type FromStringImpl<type>(const char* data, size_t len) { \ - return ParseFlt<type>(data, len); \ - } - -DEF_FLT_SPEC(long double) - -#undef DEF_FLT_SPEC - + +#define DEF_FLT_SPEC(type) \ + template <> \ + type FromStringImpl<type>(const char* data, size_t len) { \ + return ParseFlt<type>(data, len); \ + } + +DEF_FLT_SPEC(long double) + +#undef DEF_FLT_SPEC + // Using StrToD for float and double because it is faster than sscanf. // Exception-free, specialized for float types template <> @@ -693,152 +693,152 @@ float FromStringImpl<float>(const char* data, size_t len) { return static_cast<float>(FromStringImpl<double>(data, len)); } -double StrToD(const char* b, const char* e, char** se) { - struct TCvt: public StringToDoubleConverter { - inline TCvt() - : StringToDoubleConverter(ALLOW_TRAILING_JUNK | ALLOW_HEX | ALLOW_LEADING_SPACES, 0.0, NAN, nullptr, nullptr) - { - } - }; - - int out = 0; - - const auto res = SingletonWithPriority<TCvt, 0>()->StringToDouble(b, e - b, &out); - - if (se) { - *se = (char*)(b + out); - } - - return res; -} - -double StrToD(const char* b, char** se) { - return StrToD(b, b + strlen(b), se); -} - -namespace { - static inline DoubleToStringConverter& ToStringConverterNoPad() noexcept { - struct TCvt: public DoubleToStringConverter { - inline TCvt() noexcept - : DoubleToStringConverter(EMIT_POSITIVE_EXPONENT_SIGN, "inf", "nan", 'e', -10, 21, 4, 0) - { - } - }; - - return *SingletonWithPriority<TCvt, 0>(); - } - - struct TBuilder { - alignas(StringBuilder) char Store[sizeof(StringBuilder)]; - StringBuilder* SB; - - inline TBuilder(char* buf, size_t len) noexcept - : SB(new (Store) StringBuilder(buf, len)) - { - } - }; - - static inline size_t FixZeros(char* buf, size_t len) noexcept { - auto end = buf + len; - auto point = (char*)memchr(buf, '.', len); - - if (!point) { - return len; - } - - auto exp = (char*)memchr(point, 'e', end - point); - - if (!exp) { - exp = end; - } - - auto c = exp; - - c -= 1; - - while (point < c && *c == '0') { - --c; - } - - if (*c == '.') { - --c; - } - - memmove(c + 1, exp, end - exp); - - return c - buf + 1 + end - exp; - } - - static inline size_t FixEnd(char* buf, size_t len) noexcept { - if (len > 2) { - auto sign = buf[len - 2]; - - if (sign == '-' || sign == '+') { - buf[len] = buf[len - 1]; - buf[len - 1] = '0'; - ++len; - } - } - - buf[len] = 0; - - return len; - } - - static inline size_t DoDtoa(double d, char* buf, size_t len, int prec) noexcept { - TBuilder sb(buf, len); - +double StrToD(const char* b, const char* e, char** se) { + struct TCvt: public StringToDoubleConverter { + inline TCvt() + : StringToDoubleConverter(ALLOW_TRAILING_JUNK | ALLOW_HEX | ALLOW_LEADING_SPACES, 0.0, NAN, nullptr, nullptr) + { + } + }; + + int out = 0; + + const auto res = SingletonWithPriority<TCvt, 0>()->StringToDouble(b, e - b, &out); + + if (se) { + *se = (char*)(b + out); + } + + return res; +} + +double StrToD(const char* b, char** se) { + return StrToD(b, b + strlen(b), se); +} + +namespace { + static inline DoubleToStringConverter& ToStringConverterNoPad() noexcept { + struct TCvt: public DoubleToStringConverter { + inline TCvt() noexcept + : DoubleToStringConverter(EMIT_POSITIVE_EXPONENT_SIGN, "inf", "nan", 'e', -10, 21, 4, 0) + { + } + }; + + return *SingletonWithPriority<TCvt, 0>(); + } + + struct TBuilder { + alignas(StringBuilder) char Store[sizeof(StringBuilder)]; + StringBuilder* SB; + + inline TBuilder(char* buf, size_t len) noexcept + : SB(new (Store) StringBuilder(buf, len)) + { + } + }; + + static inline size_t FixZeros(char* buf, size_t len) noexcept { + auto end = buf + len; + auto point = (char*)memchr(buf, '.', len); + + if (!point) { + return len; + } + + auto exp = (char*)memchr(point, 'e', end - point); + + if (!exp) { + exp = end; + } + + auto c = exp; + + c -= 1; + + while (point < c && *c == '0') { + --c; + } + + if (*c == '.') { + --c; + } + + memmove(c + 1, exp, end - exp); + + return c - buf + 1 + end - exp; + } + + static inline size_t FixEnd(char* buf, size_t len) noexcept { + if (len > 2) { + auto sign = buf[len - 2]; + + if (sign == '-' || sign == '+') { + buf[len] = buf[len - 1]; + buf[len - 1] = '0'; + ++len; + } + } + + buf[len] = 0; + + return len; + } + + static inline size_t DoDtoa(double d, char* buf, size_t len, int prec) noexcept { + TBuilder sb(buf, len); + Y_VERIFY(ToStringConverterNoPad().ToPrecision(d, prec, sb.SB), "conversion failed"); - - return FixEnd(buf, FixZeros(buf, sb.SB->position())); - } -} - -template <> -size_t ToStringImpl<double>(double d, char* buf, size_t len) { - return DoDtoa(d, buf, len, 10); -} - -template <> -size_t ToStringImpl<float>(float f, char* buf, size_t len) { - return DoDtoa(f, buf, len, 6); -} - -size_t FloatToString(float t, char* buf, size_t len, EFloatToStringMode mode, int ndigits) { - if (mode == PREC_AUTO) { - TBuilder sb(buf, len); - + + return FixEnd(buf, FixZeros(buf, sb.SB->position())); + } +} + +template <> +size_t ToStringImpl<double>(double d, char* buf, size_t len) { + return DoDtoa(d, buf, len, 10); +} + +template <> +size_t ToStringImpl<float>(float f, char* buf, size_t len) { + return DoDtoa(f, buf, len, 6); +} + +size_t FloatToString(float t, char* buf, size_t len, EFloatToStringMode mode, int ndigits) { + if (mode == PREC_AUTO) { + TBuilder sb(buf, len); + Y_VERIFY(ToStringConverterNoPad().ToShortestSingle(t, sb.SB), "conversion failed"); - - return FixEnd(buf, sb.SB->position()); - } - - return FloatToString((double)t, buf, len, mode, ndigits); -} - -size_t FloatToString(double t, char* buf, size_t len, EFloatToStringMode mode, int ndigits) { - if (mode == PREC_NDIGITS) { - auto minDigits = DoubleToStringConverter::kMinPrecisionDigits; - auto maxDigits = DoubleToStringConverter::kMaxPrecisionDigits; - - return DoDtoa(t, buf, len, ClampVal(ndigits, minDigits, maxDigits)); - } - - TBuilder sb(buf, len); - - if (mode == PREC_AUTO) { + + return FixEnd(buf, sb.SB->position()); + } + + return FloatToString((double)t, buf, len, mode, ndigits); +} + +size_t FloatToString(double t, char* buf, size_t len, EFloatToStringMode mode, int ndigits) { + if (mode == PREC_NDIGITS) { + auto minDigits = DoubleToStringConverter::kMinPrecisionDigits; + auto maxDigits = DoubleToStringConverter::kMaxPrecisionDigits; + + return DoDtoa(t, buf, len, ClampVal(ndigits, minDigits, maxDigits)); + } + + TBuilder sb(buf, len); + + if (mode == PREC_AUTO) { Y_VERIFY(ToStringConverterNoPad().ToShortest(t, sb.SB), "conversion failed"); - - return FixEnd(buf, sb.SB->position()); - } - - if (!ToStringConverterNoPad().ToFixed(t, ndigits, sb.SB)) { - return FloatToString(t, buf, len, PREC_AUTO); - } - - if (mode == PREC_POINT_DIGITS_STRIP_ZEROES) { - return FixZeros(buf, sb.SB->position()); - } - - return sb.SB->position(); -} + + return FixEnd(buf, sb.SB->position()); + } + + if (!ToStringConverterNoPad().ToFixed(t, ndigits, sb.SB)) { + return FloatToString(t, buf, len, PREC_AUTO); + } + + if (mode == PREC_POINT_DIGITS_STRIP_ZEROES) { + return FixZeros(buf, sb.SB->position()); + } + + return sb.SB->position(); +} |