cast.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  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. }
  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. }
  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. template <typename T, typename TChar>
  181. bool TryFromStringImpl(const TChar* data, size_t len, T& result);
  182. /**
  183. * @param data Source string buffer pointer
  184. * @param len Source string length, in characters
  185. * @param result Place to store conversion result value.
  186. * If conversion error occurs, no value stored in @c result
  187. * @return @c true in case of successful conversion, @c false otherwise
  188. **/
  189. template <typename T, typename TChar>
  190. inline bool TryFromString(const TChar* data, size_t len, T& result) {
  191. return TryFromStringImpl<T>(data, len, result);
  192. }
  193. template <typename T, typename TChar>
  194. inline bool TryFromString(const TChar* data, T& result) {
  195. return TryFromString<T>(data, std::char_traits<TChar>::length(data), result);
  196. }
  197. template <class T, class TChar>
  198. inline bool TryFromString(const TChar* data, const size_t len, T& result, const T& def) {
  199. if (TryFromString<T>(data, len, result)) {
  200. return true;
  201. }
  202. result = def;
  203. return false;
  204. }
  205. template <class T>
  206. inline bool TryFromString(const TStringBuf& s, T& result) {
  207. return TryFromString<T>(s.data(), s.size(), result);
  208. }
  209. template <class T>
  210. inline bool TryFromString(const TString& s, T& result) {
  211. return TryFromString<T>(s.data(), s.size(), result);
  212. }
  213. template <class T>
  214. inline bool TryFromString(const std::string& s, T& result) {
  215. return TryFromString<T>(s.data(), s.size(), result);
  216. }
  217. template <class T>
  218. inline bool TryFromString(const TWtringBuf& s, T& result) {
  219. return TryFromString<T>(s.data(), s.size(), result);
  220. }
  221. template <class T>
  222. inline bool TryFromString(const TUtf16String& s, T& result) {
  223. return TryFromString<T>(s.data(), s.size(), result);
  224. }
  225. template <class T, class TChar>
  226. inline TMaybe<T> TryFromString(TBasicStringBuf<TChar> s) {
  227. TMaybe<T> result{NMaybe::TInPlace{}};
  228. if (!TryFromString<T>(s, *result)) {
  229. result.Clear();
  230. }
  231. return result;
  232. }
  233. template <class T, class TChar>
  234. inline TMaybe<T> TryFromString(const TChar* data) {
  235. return TryFromString<T>(TBasicStringBuf<TChar>(data));
  236. }
  237. template <class T>
  238. inline TMaybe<T> TryFromString(const TString& s) {
  239. return TryFromString<T>(TStringBuf(s));
  240. }
  241. template <class T>
  242. inline TMaybe<T> TryFromString(const std::string& s) {
  243. return TryFromString<T>(TStringBuf(s));
  244. }
  245. template <class T>
  246. inline TMaybe<T> TryFromString(const TUtf16String& s) {
  247. return TryFromString<T>(TWtringBuf(s));
  248. }
  249. template <class T, class TStringType>
  250. inline bool TryFromStringWithDefault(const TStringType& s, T& result, const T& def) {
  251. return TryFromString<T>(s.data(), s.size(), result, def);
  252. }
  253. template <class T>
  254. inline bool TryFromStringWithDefault(const char* s, T& result, const T& def) {
  255. return TryFromStringWithDefault<T>(TStringBuf(s), result, def);
  256. }
  257. template <class T, class TStringType>
  258. inline bool TryFromStringWithDefault(const TStringType& s, T& result) {
  259. return TryFromStringWithDefault<T>(s, result, T());
  260. }
  261. // FromString methods with default value if data is invalid
  262. template <class T, class TChar>
  263. inline T FromString(const TChar* data, const size_t len, const T& def) {
  264. T result;
  265. TryFromString<T>(data, len, result, def);
  266. return result;
  267. }
  268. template <class T, class TStringType>
  269. inline T FromStringWithDefault(const TStringType& s, const T& def) {
  270. return FromString<T>(s.data(), s.size(), def);
  271. }
  272. template <class T>
  273. inline T FromStringWithDefault(const char* s, const T& def) {
  274. return FromStringWithDefault<T>(TStringBuf(s), def);
  275. }
  276. template <class T, class TStringType>
  277. inline T FromStringWithDefault(const TStringType& s) {
  278. return FromStringWithDefault<T>(s, T());
  279. }
  280. double StrToD(const char* b, char** se);
  281. double StrToD(const char* b, const char* e, char** se);
  282. template <int base, class T>
  283. size_t IntToString(T t, char* buf, size_t len);
  284. template <int base, class T>
  285. inline TString IntToString(T t) {
  286. static_assert(std::is_arithmetic<std::remove_cv_t<T>>::value, "expect std::is_arithmetic<std::remove_cv_t<T>>::value");
  287. char buf[256];
  288. return TString(buf, IntToString<base>(t, buf, sizeof(buf)));
  289. }
  290. template <int base, class TInt, class TChar>
  291. bool TryIntFromString(const TChar* data, size_t len, TInt& result);
  292. template <int base, class TInt, class TStringType>
  293. inline bool TryIntFromString(const TStringType& s, TInt& result) {
  294. return TryIntFromString<base>(s.data(), s.size(), result);
  295. }
  296. template <class TInt, int base, class TChar>
  297. TInt IntFromString(const TChar* str, size_t len);
  298. template <class TInt, int base, class TChar>
  299. inline TInt IntFromString(const TChar* str) {
  300. return IntFromString<TInt, base>(str, std::char_traits<TChar>::length(str));
  301. }
  302. template <class TInt, int base, class TStringType>
  303. inline TInt IntFromString(const TStringType& str) {
  304. return IntFromString<TInt, base>(str.data(), str.size());
  305. }
  306. static inline TString ToString(const TStringBuf str) {
  307. return TString(str);
  308. }
  309. static inline TUtf16String ToWtring(const TWtringBuf wtr) {
  310. return TUtf16String(wtr);
  311. }
  312. static inline TUtf32String ToUtf32String(const TUtf32StringBuf wtr) {
  313. return TUtf32String(wtr);
  314. }
  315. template <typename T, unsigned radix = 10, class TChar = char>
  316. class TIntStringBuf {
  317. private:
  318. // inline constexprs are not supported by CUDA yet
  319. static constexpr char IntToChar[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  320. static_assert(1 < radix && radix < 17, "expect 1 < radix && radix < 17");
  321. // auxiliary recursive template used to calculate maximum buffer size for the given type
  322. template <T v>
  323. struct TBufSizeRec {
  324. // MSVC is tries to evaluate both sides of ?: operator and doesn't break recursion
  325. static constexpr ui32 GetValue() {
  326. if (v == 0) {
  327. return 1;
  328. }
  329. return 1 + TBufSizeRec<v / radix>::value;
  330. }
  331. static constexpr ui32 value = GetValue();
  332. };
  333. public:
  334. static constexpr ui32 bufferSize = (std::is_signed<T>::value ? 1 : 0) +
  335. ((radix == 2) ? sizeof(T) * 8 : TBufSizeRec<std::numeric_limits<T>::max()>::value);
  336. template <std::enable_if_t<std::is_integral<T>::value, bool> = true>
  337. explicit constexpr TIntStringBuf(T t) {
  338. Size_ = Convert(t, Buf_, sizeof(Buf_));
  339. #if __cplusplus >= 202002L // is_constant_evaluated is not supported by CUDA yet
  340. if (std::is_constant_evaluated()) {
  341. #endif
  342. // Init the rest of the array,
  343. // otherwise constexpr copy and move constructors don't work due to uninitialized data access
  344. std::fill(Buf_ + Size_, Buf_ + sizeof(Buf_), '\0');
  345. #if __cplusplus >= 202002L
  346. }
  347. #endif
  348. }
  349. constexpr operator TStringBuf() const noexcept {
  350. return TStringBuf(Buf_, Size_);
  351. }
  352. constexpr static ui32 Convert(T t, TChar* buf, size_t bufLen) {
  353. bufLen = std::min<size_t>(bufferSize, bufLen);
  354. if (std::is_signed<T>::value && t < 0) {
  355. Y_ENSURE(bufLen >= 2, TStringBuf("not enough room in buffer"));
  356. buf[0] = '-';
  357. const auto mt = std::make_unsigned_t<T>(-(t + 1)) + std::make_unsigned_t<T>(1);
  358. return ConvertUnsigned(mt, &buf[1], bufLen - 1) + 1;
  359. } else {
  360. return ConvertUnsigned(t, buf, bufLen);
  361. }
  362. }
  363. private:
  364. constexpr static ui32 ConvertUnsigned(typename std::make_unsigned<T>::type t, TChar* buf, ui32 bufLen) {
  365. Y_ENSURE(bufLen, TStringBuf("zero length"));
  366. if (t == 0) {
  367. *buf = '0';
  368. return 1;
  369. }
  370. auto* be = buf + bufLen;
  371. ui32 l = 0;
  372. while (t > 0 && be > buf) {
  373. const auto v = t / radix;
  374. const auto r = (radix == 2 || radix == 4 || radix == 8 || radix == 16) ? t & (radix - 1) : t - radix * v;
  375. --be;
  376. if /*constexpr*/ (radix <= 10) { // if constexpr is not supported by CUDA yet
  377. *be = r + '0';
  378. } else {
  379. *be = IntToChar[r];
  380. }
  381. ++l;
  382. t = v;
  383. }
  384. Y_ENSURE(!t, TStringBuf("not enough room in buffer"));
  385. if (buf != be) {
  386. for (ui32 i = 0; i < l; ++i) {
  387. *buf = *be;
  388. ++buf;
  389. ++be;
  390. }
  391. }
  392. return l;
  393. }
  394. ui32 Size_;
  395. TChar Buf_[bufferSize];
  396. };