cast.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. #pragma once
  2. #include <util/system/defaults.h>
  3. #include <util/stream/str.h>
  4. #include <util/generic/maybe.h>
  5. #include <util/generic/string.h>
  6. #include <util/generic/strbuf.h>
  7. #include <util/generic/typetraits.h>
  8. #include <util/generic/yexception.h>
  9. /*
  10. * specialized for all arithmetic types
  11. */
  12. template <class T>
  13. size_t ToStringImpl(T t, char* buf, size_t len);
  14. /**
  15. * Converts @c t to string writing not more than @c len bytes to output buffer @c buf.
  16. * No NULL terminator appended! Throws exception on buffer overflow.
  17. * @return number of bytes written
  18. */
  19. template <class T>
  20. inline size_t ToString(const T& t, char* buf, size_t len) {
  21. using TParam = typename TTypeTraits<T>::TFuncParam;
  22. return ToStringImpl<TParam>(t, buf, len);
  23. }
  24. /**
  25. * Floating point to string conversion mode, values are enforced by `dtoa_impl.cpp`.
  26. */
  27. enum EFloatToStringMode {
  28. /** 0.1f -> "0.1", 0.12345678f -> "0.12345678", ignores ndigits. */
  29. PREC_AUTO = 0,
  30. /** "%g" mode, writes up to the given number of significant digits:
  31. * 0.1f -> "0.1", 0.12345678f -> "0.123457" for ndigits=6, 1.2e-06f -> "1.2e-06" */
  32. PREC_NDIGITS = 2,
  33. /** "%f" mode, writes the given number of digits after decimal point:
  34. * 0.1f -> "0.100000", 1.2e-06f -> "0.000001" for ndigits=6 */
  35. PREC_POINT_DIGITS = 3,
  36. /** same as PREC_POINT_DIGITS, but stripping trailing zeroes:
  37. * 0.1f for ndgigits=6 -> "0.1" */
  38. PREC_POINT_DIGITS_STRIP_ZEROES = 4
  39. };
  40. size_t FloatToString(float t, char* buf, size_t len, EFloatToStringMode mode = PREC_AUTO, int ndigits = 0);
  41. size_t FloatToString(double t, char* buf, size_t len, EFloatToStringMode mode = PREC_AUTO, int ndigits = 0);
  42. template <typename T>
  43. inline TString FloatToString(const T& t, EFloatToStringMode mode = PREC_AUTO, int ndigits = 0) {
  44. char buf[512]; // Max<double>() with mode = PREC_POINT_DIGITS has 309 digits before the decimal point
  45. size_t count = FloatToString(t, buf, sizeof(buf), mode, ndigits);
  46. return TString(buf, count);
  47. }
  48. namespace NPrivate {
  49. template <class T, bool isSimple>
  50. struct TToString {
  51. static inline TString Cvt(const T& t) {
  52. char buf[512];
  53. return TString(buf, ToString<T>(t, buf, sizeof(buf)));
  54. }
  55. };
  56. template <class T>
  57. struct TToString<T, false> {
  58. static inline TString Cvt(const T& t) {
  59. TString s;
  60. TStringOutput o(s);
  61. o << t;
  62. return s;
  63. }
  64. };
  65. } // namespace NPrivate
  66. /*
  67. * some clever implementations...
  68. */
  69. template <class T>
  70. inline TString ToString(const T& t) {
  71. using TR = std::remove_cv_t<T>;
  72. return ::NPrivate::TToString<TR, std::is_arithmetic<TR>::value>::Cvt((const TR&)t);
  73. }
  74. inline const TString& ToString(const TString& s Y_LIFETIME_BOUND) noexcept {
  75. return s;
  76. }
  77. inline TString&& ToString(TString&& s Y_LIFETIME_BOUND) noexcept {
  78. return std::move(s);
  79. }
  80. inline TString ToString(const char* s) {
  81. return s;
  82. }
  83. inline TString ToString(char* s) {
  84. return s;
  85. }
  86. /*
  87. * Wrapper for wide strings.
  88. */
  89. template <class T>
  90. inline TUtf16String ToWtring(const T& t) {
  91. return TUtf16String::FromAscii(ToString(t));
  92. }
  93. inline const TUtf16String& ToWtring(const TUtf16String& w Y_LIFETIME_BOUND) noexcept {
  94. return w;
  95. }
  96. inline TUtf16String&& ToWtring(TUtf16String&& w Y_LIFETIME_BOUND) noexcept {
  97. return std::move(w);
  98. }
  99. struct TFromStringException: public TBadCastException {
  100. };
  101. /*
  102. * specialized for:
  103. * bool
  104. * short
  105. * unsigned short
  106. * int
  107. * unsigned int
  108. * long
  109. * unsigned long
  110. * long long
  111. * unsigned long long
  112. * float
  113. * double
  114. * long double
  115. */
  116. template <typename T, typename TChar>
  117. T FromStringImpl(const TChar* data, size_t len);
  118. template <typename T, typename TChar>
  119. inline T FromString(const TChar* data, size_t len) {
  120. return ::FromStringImpl<T>(data, len);
  121. }
  122. template <typename T, typename TChar>
  123. inline T FromString(const TChar* data) {
  124. return ::FromString<T>(data, std::char_traits<TChar>::length(data));
  125. }
  126. template <class T>
  127. inline T FromString(const TStringBuf& s) {
  128. return ::FromString<T>(s.data(), s.size());
  129. }
  130. template <class T>
  131. inline T FromString(const TString& s) {
  132. return ::FromString<T>(s.data(), s.size());
  133. }
  134. template <class T>
  135. inline T FromString(const std::string& s) {
  136. return ::FromString<T>(s.data(), s.size());
  137. }
  138. template <>
  139. inline TString FromString<TString>(const TString& s) {
  140. return s;
  141. }
  142. template <class T>
  143. inline T FromString(const TWtringBuf& s) {
  144. return ::FromString<T, typename TWtringBuf::char_type>(s.data(), s.size());
  145. }
  146. template <class T>
  147. inline T FromString(const TUtf16String& s) {
  148. return ::FromString<T, wchar16>(s.data(), s.size());
  149. }
  150. namespace NPrivate {
  151. template <typename TChar>
  152. class TFromString {
  153. const TChar* const Data;
  154. const size_t Len;
  155. public:
  156. inline TFromString(const TChar* data, size_t len)
  157. : Data(data)
  158. , Len(len)
  159. {
  160. }
  161. template <typename T>
  162. inline operator T() const {
  163. return FromString<T, TChar>(Data, Len);
  164. }
  165. };
  166. } // namespace NPrivate
  167. template <typename TChar>
  168. inline ::NPrivate::TFromString<TChar> FromString(const TChar* data, size_t len) {
  169. return ::NPrivate::TFromString<TChar>(data, len);
  170. }
  171. template <typename TChar>
  172. inline ::NPrivate::TFromString<TChar> FromString(const TChar* data) {
  173. return ::NPrivate::TFromString<TChar>(data, std::char_traits<TChar>::length(data));
  174. }
  175. template <typename T>
  176. inline ::NPrivate::TFromString<typename T::TChar> FromString(const T& s) {
  177. return ::NPrivate::TFromString<typename T::TChar>(s.data(), s.size());
  178. }
  179. // Conversion exception free versions
  180. // But can throw other exceptions, e.g. std::bad_alloc when allocating memory for the new 'result' value.
  181. template <typename T, typename TChar>
  182. bool TryFromStringImpl(const TChar* data, size_t len, T& result);
  183. /**
  184. * @param data Source string buffer pointer
  185. * @param len Source string length, in characters
  186. * @param result Place to store conversion result value.
  187. * If conversion error occurs, no value stored in @c result
  188. * @return @c true in case of successful conversion, @c false otherwise
  189. **/
  190. template <typename T, typename TChar>
  191. inline bool TryFromString(const TChar* data, size_t len, T& result) {
  192. return TryFromStringImpl<T>(data, len, result);
  193. }
  194. template <typename T, typename TChar>
  195. inline bool TryFromString(const TChar* data, T& result) {
  196. return TryFromString<T>(data, std::char_traits<TChar>::length(data), result);
  197. }
  198. template <class T, class TChar>
  199. inline bool TryFromString(const TChar* data, const size_t len, T& result, const T& def) {
  200. if (TryFromString<T>(data, len, result)) {
  201. return true;
  202. }
  203. result = def;
  204. return false;
  205. }
  206. template <class T>
  207. inline bool TryFromString(const TStringBuf& s, T& result) {
  208. return TryFromString<T>(s.data(), s.size(), result);
  209. }
  210. template <class T>
  211. inline bool TryFromString(const TString& s, T& result) {
  212. return TryFromString<T>(s.data(), s.size(), result);
  213. }
  214. template <class T>
  215. inline bool TryFromString(const std::string& s, T& result) {
  216. return TryFromString<T>(s.data(), s.size(), result);
  217. }
  218. template <class T>
  219. inline bool TryFromString(const TWtringBuf& s, T& result) {
  220. return TryFromString<T>(s.data(), s.size(), result);
  221. }
  222. template <class T>
  223. inline bool TryFromString(const TUtf16String& s, T& result) {
  224. return TryFromString<T>(s.data(), s.size(), result);
  225. }
  226. template <class T, class TChar>
  227. inline TMaybe<T> TryFromString(TBasicStringBuf<TChar> s) {
  228. TMaybe<T> result{NMaybe::TInPlace{}};
  229. if (!TryFromString<T>(s, *result)) {
  230. result.Clear();
  231. }
  232. return result;
  233. }
  234. template <class T, class TChar>
  235. inline TMaybe<T> TryFromString(const TChar* data) {
  236. return TryFromString<T>(TBasicStringBuf<TChar>(data));
  237. }
  238. template <class T>
  239. inline TMaybe<T> TryFromString(const TString& s) {
  240. return TryFromString<T>(TStringBuf(s));
  241. }
  242. template <class T>
  243. inline TMaybe<T> TryFromString(const std::string& s) {
  244. return TryFromString<T>(TStringBuf(s));
  245. }
  246. template <class T>
  247. inline TMaybe<T> TryFromString(const TUtf16String& s) {
  248. return TryFromString<T>(TWtringBuf(s));
  249. }
  250. template <class T, class TStringType>
  251. inline bool TryFromStringWithDefault(const TStringType& s, T& result, const T& def) {
  252. return TryFromString<T>(s.data(), s.size(), result, def);
  253. }
  254. template <class T>
  255. inline bool TryFromStringWithDefault(const char* s, T& result, const T& def) {
  256. return TryFromStringWithDefault<T>(TStringBuf(s), result, def);
  257. }
  258. template <class T, class TStringType>
  259. inline bool TryFromStringWithDefault(const TStringType& s, T& result) {
  260. return TryFromStringWithDefault<T>(s, result, T());
  261. }
  262. // FromString methods with default value if data is invalid
  263. template <class T, class TChar>
  264. inline T FromString(const TChar* data, const size_t len, const T& def) {
  265. T result;
  266. TryFromString<T>(data, len, result, def);
  267. return result;
  268. }
  269. template <class T, class TStringType>
  270. inline T FromStringWithDefault(const TStringType& s, const T& def) {
  271. return FromString<T>(s.data(), s.size(), def);
  272. }
  273. template <class T>
  274. inline T FromStringWithDefault(const char* s, const T& def) {
  275. return FromStringWithDefault<T>(TStringBuf(s), def);
  276. }
  277. template <class T, class TStringType>
  278. inline T FromStringWithDefault(const TStringType& s) {
  279. return FromStringWithDefault<T>(s, T());
  280. }
  281. double StrToD(const char* b, char** se);
  282. double StrToD(const char* b, const char* e, char** se);
  283. template <int base, class T>
  284. size_t IntToString(T t, char* buf, size_t len);
  285. template <int base, class T>
  286. inline TString IntToString(T t) {
  287. static_assert(std::is_arithmetic<std::remove_cv_t<T>>::value, "expect std::is_arithmetic<std::remove_cv_t<T>>::value");
  288. char buf[256];
  289. return TString(buf, IntToString<base>(t, buf, sizeof(buf)));
  290. }
  291. template <int base, class TInt, class TChar>
  292. bool TryIntFromString(const TChar* data, size_t len, TInt& result);
  293. template <int base, class TInt, class TStringType>
  294. inline bool TryIntFromString(const TStringType& s, TInt& result) {
  295. return TryIntFromString<base>(s.data(), s.size(), result);
  296. }
  297. template <class TInt, int base, class TChar>
  298. TInt IntFromString(const TChar* str, size_t len);
  299. template <class TInt, int base, class TChar>
  300. inline TInt IntFromString(const TChar* str) {
  301. return IntFromString<TInt, base>(str, std::char_traits<TChar>::length(str));
  302. }
  303. template <class TInt, int base, class TStringType>
  304. inline TInt IntFromString(const TStringType& str) {
  305. return IntFromString<TInt, base>(str.data(), str.size());
  306. }
  307. static inline TString ToString(const TStringBuf str) {
  308. return TString(str);
  309. }
  310. static inline TUtf16String ToWtring(const TWtringBuf wtr) {
  311. return TUtf16String(wtr);
  312. }
  313. static inline TUtf32String ToUtf32String(const TUtf32StringBuf wtr) {
  314. return TUtf32String(wtr);
  315. }
  316. template <typename T, unsigned radix = 10, class TChar = char>
  317. class TIntStringBuf {
  318. private:
  319. // inline constexprs are not supported by CUDA yet
  320. static constexpr char IntToChar[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  321. static_assert(1 < radix && radix < 17, "expect 1 < radix && radix < 17");
  322. // auxiliary recursive template used to calculate maximum buffer size for the given type
  323. template <T v>
  324. struct TBufSizeRec {
  325. // MSVC is tries to evaluate both sides of ?: operator and doesn't break recursion
  326. static constexpr ui32 GetValue() {
  327. if (v == 0) {
  328. return 1;
  329. }
  330. return 1 + TBufSizeRec<v / radix>::value;
  331. }
  332. static constexpr ui32 value = GetValue();
  333. };
  334. public:
  335. static constexpr ui32 bufferSize = (std::is_signed<T>::value ? 1 : 0) +
  336. ((radix == 2) ? sizeof(T) * 8 : TBufSizeRec<std::numeric_limits<T>::max()>::value);
  337. template <std::enable_if_t<std::is_integral<T>::value, bool> = true>
  338. explicit constexpr TIntStringBuf(T t) {
  339. Size_ = Convert(t, Buf_, sizeof(Buf_));
  340. #if __cplusplus >= 202002L // is_constant_evaluated is not supported by CUDA yet
  341. if (std::is_constant_evaluated()) {
  342. #endif
  343. // Init the rest of the array,
  344. // otherwise constexpr copy and move constructors don't work due to uninitialized data access
  345. std::fill(Buf_ + Size_, Buf_ + sizeof(Buf_), '\0');
  346. #if __cplusplus >= 202002L
  347. }
  348. #endif
  349. }
  350. constexpr operator TStringBuf() const noexcept {
  351. return TStringBuf(Buf_, Size_);
  352. }
  353. constexpr static ui32 Convert(T t, TChar* buf, size_t bufLen) {
  354. bufLen = std::min<size_t>(bufferSize, bufLen);
  355. if (std::is_signed<T>::value && t < 0) {
  356. Y_ENSURE(bufLen >= 2, TStringBuf("not enough room in buffer"));
  357. buf[0] = '-';
  358. const auto mt = std::make_unsigned_t<T>(-(t + 1)) + std::make_unsigned_t<T>(1);
  359. return ConvertUnsigned(mt, &buf[1], bufLen - 1) + 1;
  360. } else {
  361. return ConvertUnsigned(t, buf, bufLen);
  362. }
  363. }
  364. private:
  365. constexpr static ui32 ConvertUnsigned(typename std::make_unsigned<T>::type t, TChar* buf, ui32 bufLen) {
  366. Y_ENSURE(bufLen, TStringBuf("zero length"));
  367. if (t == 0) {
  368. *buf = '0';
  369. return 1;
  370. }
  371. auto* be = buf + bufLen;
  372. ui32 l = 0;
  373. while (t > 0 && be > buf) {
  374. const auto v = t / radix;
  375. const auto r = (radix == 2 || radix == 4 || radix == 8 || radix == 16) ? t & (radix - 1) : t - radix * v;
  376. --be;
  377. if /*constexpr*/ (radix <= 10) { // if constexpr is not supported by CUDA yet
  378. *be = r + '0';
  379. } else {
  380. *be = IntToChar[r];
  381. }
  382. ++l;
  383. t = v;
  384. }
  385. Y_ENSURE(!t, TStringBuf("not enough room in buffer"));
  386. if (buf != be) {
  387. for (ui32 i = 0; i < l; ++i) {
  388. *buf = *be;
  389. ++buf;
  390. ++be;
  391. }
  392. }
  393. return l;
  394. }
  395. ui32 Size_;
  396. TChar Buf_[bufferSize];
  397. };