convert.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. #pragma once
  2. #include <yql/essentials/public/udf/udf_value.h>
  3. #include <yql/essentials/public/udf/udf_value_builder.h>
  4. #include <yql/essentials/utils/utf8.h>
  5. #include <util/string/escape.h>
  6. #include <util/string/cast.h>
  7. #include <util/string/builder.h>
  8. #include <functional>
  9. namespace NYql::NDom {
  10. template<bool Strict, bool AutoConvert>
  11. TUnboxedValuePod ConvertToBool(TUnboxedValuePod x, const IValueBuilder* valueBuilder, const TSourcePosition& pos) {
  12. switch (GetNodeType(x)) {
  13. case ENodeType::Bool:
  14. return TUnboxedValuePod(x.Get<bool>());
  15. case ENodeType::String:
  16. if (const std::string_view str = x.AsStringRef(); str == "true")
  17. return TUnboxedValuePod(true);
  18. else if (str == "false")
  19. return TUnboxedValuePod(false);
  20. else if constexpr (AutoConvert)
  21. return TUnboxedValuePod(x.AsStringRef().Size() > 0U);
  22. else if constexpr (Strict)
  23. break;
  24. else
  25. return {};
  26. case ENodeType::Uint64:
  27. if constexpr (AutoConvert)
  28. return TUnboxedValuePod(x.Get<ui64>() != 0ULL);
  29. else if constexpr (Strict)
  30. break;
  31. else
  32. return {};
  33. case ENodeType::Int64:
  34. if constexpr (AutoConvert)
  35. return TUnboxedValuePod(x.Get<i64>() != 0LL);
  36. else if constexpr (Strict)
  37. break;
  38. else
  39. return {};
  40. case ENodeType::Double:
  41. if constexpr (AutoConvert)
  42. return TUnboxedValuePod(x.Get<double>() != 0.);
  43. else if constexpr (Strict)
  44. break;
  45. else
  46. return {};
  47. case ENodeType::Entity:
  48. if constexpr (AutoConvert)
  49. return TUnboxedValuePod(false);
  50. else if constexpr (Strict)
  51. break;
  52. else if constexpr (AutoConvert)
  53. return TUnboxedValuePod(false);
  54. else
  55. return {};
  56. case ENodeType::List:
  57. if constexpr (AutoConvert)
  58. return TUnboxedValuePod(x.IsBoxed() && x.HasListItems());
  59. else if constexpr (Strict)
  60. break;
  61. else
  62. return {};
  63. case ENodeType::Dict:
  64. if constexpr (AutoConvert)
  65. return TUnboxedValuePod(x.IsBoxed() && x.HasDictItems());
  66. else if constexpr (Strict)
  67. break;
  68. else
  69. return {};
  70. case ENodeType::Attr:
  71. return ConvertToBool<Strict, AutoConvert>(x.GetVariantItem().Release(), valueBuilder, pos);
  72. }
  73. UdfTerminate((::TStringBuilder() << valueBuilder->WithCalleePosition(pos) << " Cannot parse boolean value from " << TDebugPrinter(x)).c_str());
  74. }
  75. template<typename TDst, typename TSrc>
  76. constexpr inline bool InBounds(const TSrc v) {
  77. if constexpr (std::is_same<TSrc, TDst>())
  78. return true;
  79. if constexpr (sizeof(TSrc) > sizeof(TDst))
  80. if constexpr (std::is_signed<TSrc>())
  81. return v <= TSrc(std::numeric_limits<TDst>::max()) && v >= TSrc(std::numeric_limits<TDst>::min());
  82. else
  83. return v <= TSrc(std::numeric_limits<TDst>::max());
  84. else
  85. if constexpr (std::is_signed<TSrc>())
  86. return v >= TSrc(std::numeric_limits<TDst>::min());
  87. else
  88. return v <= TSrc(std::numeric_limits<TDst>::max());
  89. static_assert(sizeof(TSrc) >= sizeof(TDst), "Expects wide to short.");
  90. }
  91. template<bool Strict, bool AutoConvert, typename TargetType>
  92. TUnboxedValuePod ConvertToIntegral(TUnboxedValuePod x, const IValueBuilder* valueBuilder, const TSourcePosition& pos) {
  93. switch (GetNodeType(x)) {
  94. case ENodeType::Int64: {
  95. const auto s = x.Get<i64>();
  96. if constexpr (AutoConvert)
  97. return TUnboxedValuePod(TargetType(s));
  98. else if (InBounds<TargetType>(s))
  99. return TUnboxedValuePod(TargetType(s));
  100. else if constexpr (Strict)
  101. break;
  102. else
  103. return {};
  104. }
  105. case ENodeType::Uint64: {
  106. const auto u = x.Get<ui64>();
  107. if constexpr (AutoConvert)
  108. return TUnboxedValuePod(TargetType(u));
  109. else if (InBounds<TargetType>(u))
  110. return TUnboxedValuePod(TargetType(u));
  111. else if constexpr (Strict)
  112. break;
  113. else
  114. return {};
  115. }
  116. case ENodeType::Bool:
  117. if constexpr (AutoConvert)
  118. return TUnboxedValuePod(TargetType(x.Get<bool>() ? 1 : 0));
  119. else if constexpr (Strict)
  120. break;
  121. else
  122. return {};
  123. case ENodeType::Double:
  124. if constexpr (AutoConvert)
  125. return TUnboxedValuePod(TargetType(x.Get<double>()));
  126. else if constexpr (Strict)
  127. break;
  128. else
  129. return {};
  130. case ENodeType::String:
  131. if constexpr (AutoConvert)
  132. return TUnboxedValuePod(FromStringWithDefault(std::string_view(x.AsStringRef()), TargetType(0)));
  133. else if constexpr (Strict)
  134. break;
  135. else
  136. return {};
  137. case ENodeType::Entity:
  138. if constexpr (AutoConvert)
  139. return TUnboxedValuePod::Zero();
  140. else if constexpr (Strict)
  141. break;
  142. else
  143. return {};
  144. case ENodeType::List:
  145. if constexpr (AutoConvert)
  146. return TUnboxedValuePod::Zero();
  147. else if constexpr (Strict)
  148. break;
  149. else
  150. return {};
  151. case ENodeType::Dict:
  152. if constexpr (AutoConvert)
  153. return TUnboxedValuePod::Zero();
  154. else if constexpr (Strict)
  155. break;
  156. else
  157. return {};
  158. case ENodeType::Attr:
  159. return ConvertToIntegral<Strict, AutoConvert, TargetType>(x.GetVariantItem().Release(), valueBuilder, pos);
  160. }
  161. UdfTerminate((::TStringBuilder() << valueBuilder->WithCalleePosition(pos) << " Cannot parse integer value from " << TDebugPrinter(x)).c_str());
  162. static_assert(std::is_integral<TargetType>(), "Expect integral.");
  163. }
  164. template<bool Strict, bool AutoConvert, typename TargetType>
  165. TUnboxedValuePod ConvertToFloat(TUnboxedValuePod x, const IValueBuilder* valueBuilder, const TSourcePosition& pos) {
  166. switch (GetNodeType(x)) {
  167. case ENodeType::Double:
  168. return TUnboxedValuePod(TargetType(x.Get<double>()));
  169. case ENodeType::Uint64:
  170. return TUnboxedValuePod(TargetType(x.Get<ui64>()));
  171. case ENodeType::Int64:
  172. return TUnboxedValuePod(TargetType(x.Get<i64>()));
  173. case ENodeType::Bool:
  174. if constexpr (AutoConvert)
  175. return TUnboxedValuePod(x.Get<bool>() ? TargetType(1) : TargetType(0));
  176. else if constexpr (Strict)
  177. break;
  178. else
  179. return {};
  180. case ENodeType::String:
  181. if constexpr (AutoConvert)
  182. return TUnboxedValuePod(FromStringWithDefault(std::string_view(x.AsStringRef()), TargetType(0)));
  183. else if constexpr (Strict)
  184. break;
  185. else
  186. return {};
  187. case ENodeType::Entity:
  188. if constexpr (AutoConvert)
  189. return TUnboxedValuePod(TargetType(0));
  190. else if constexpr (Strict)
  191. break;
  192. else
  193. return {};
  194. case ENodeType::List:
  195. if constexpr (AutoConvert)
  196. return TUnboxedValuePod(TargetType(0));
  197. else if constexpr (Strict)
  198. break;
  199. else
  200. return {};
  201. case ENodeType::Dict:
  202. if constexpr (AutoConvert)
  203. return TUnboxedValuePod(TargetType(0));
  204. else if constexpr (Strict)
  205. break;
  206. else
  207. return {};
  208. case ENodeType::Attr:
  209. return ConvertToFloat<Strict, AutoConvert, TargetType>(x.GetVariantItem().Release(), valueBuilder, pos);
  210. }
  211. UdfTerminate((::TStringBuilder() << valueBuilder->WithCalleePosition(pos) << " Cannot parse floating point value from " << TDebugPrinter(x)).c_str());
  212. static_assert(std::is_floating_point<TargetType>(), "Expect float.");
  213. }
  214. template<bool Strict, bool AutoConvert, bool Utf8>
  215. TUnboxedValuePod ConvertToString(TUnboxedValuePod x, const IValueBuilder* valueBuilder, const TSourcePosition& pos) {
  216. switch (GetNodeType(x)) {
  217. case ENodeType::String:
  218. if constexpr (Utf8)
  219. if (IsUtf8(x.AsStringRef()))
  220. return x;
  221. else
  222. if (AutoConvert)
  223. return valueBuilder->NewString(EscapeC(TStringBuf(x.AsStringRef()))).Release();
  224. else if constexpr (Strict)
  225. break;
  226. else
  227. return {};
  228. else
  229. return x;
  230. case ENodeType::Uint64:
  231. if constexpr (AutoConvert)
  232. return valueBuilder->NewString(ToString(x.Get<ui64>())).Release();
  233. else if constexpr (Strict)
  234. break;
  235. else
  236. return {};
  237. case ENodeType::Int64:
  238. if constexpr (AutoConvert)
  239. return valueBuilder->NewString(ToString(x.Get<i64>())).Release();
  240. else if constexpr (Strict)
  241. break;
  242. else
  243. return {};
  244. case ENodeType::Bool:
  245. if constexpr (AutoConvert)
  246. return x.Get<bool>() ? TUnboxedValuePod::Embedded("true") : TUnboxedValuePod::Embedded("false");
  247. else if constexpr (Strict)
  248. break;
  249. else
  250. return {};
  251. case ENodeType::Double:
  252. if constexpr (AutoConvert)
  253. return valueBuilder->NewString(::FloatToString(x.Get<double>())).Release();
  254. else if constexpr (Strict)
  255. break;
  256. else
  257. return {};
  258. case ENodeType::Entity:
  259. case ENodeType::List:
  260. case ENodeType::Dict:
  261. if constexpr (AutoConvert)
  262. return TUnboxedValuePod::Embedded("");
  263. else if constexpr (Strict)
  264. break;
  265. else
  266. return {};
  267. case ENodeType::Attr:
  268. return ConvertToString<Strict, AutoConvert, Utf8>(x.GetVariantItem().Release(), valueBuilder, pos);
  269. }
  270. UdfTerminate((::TStringBuilder() << valueBuilder->WithCalleePosition(pos) << " Cannot parse string value from " << TDebugPrinter(x)).c_str());
  271. }
  272. class TLazyConveter : public TManagedBoxedValue {
  273. public:
  274. using TConverter = std::function<TUnboxedValuePod(TUnboxedValuePod)>;
  275. TLazyConveter(TUnboxedValue&& original, TConverter&& converter)
  276. : Original(std::move(original)), Converter(std::move(converter))
  277. {}
  278. private:
  279. template <bool NoSwap>
  280. class TIterator: public TManagedBoxedValue {
  281. public:
  282. TIterator(TUnboxedValue&& original, const TConverter& converter)
  283. : Original(std::move(original)), Converter(converter)
  284. {}
  285. private:
  286. bool Skip() final {
  287. return Original.Skip();
  288. }
  289. bool Next(TUnboxedValue& value) final {
  290. if (Original.Next(value)) {
  291. if constexpr (!NoSwap) {
  292. value = Converter(value.Release());
  293. }
  294. return true;
  295. }
  296. return false;
  297. }
  298. bool NextPair(TUnboxedValue& key, TUnboxedValue& payload) final {
  299. if (Original.NextPair(key, payload)) {
  300. if constexpr (NoSwap) {
  301. payload = Converter(payload.Release());
  302. } else {
  303. key = Converter(key.Release());
  304. }
  305. return true;
  306. }
  307. return false;
  308. }
  309. const TUnboxedValue Original;
  310. const TConverter Converter;
  311. };
  312. ui64 GetDictLength() const final {
  313. return Original.GetDictLength();
  314. }
  315. ui64 GetListLength() const final {
  316. return Original.GetListLength();
  317. }
  318. bool HasFastListLength() const final {
  319. return Original.HasFastListLength();
  320. }
  321. bool HasDictItems() const final {
  322. return Original.HasDictItems();
  323. }
  324. bool HasListItems() const final {
  325. return Original.HasListItems();
  326. }
  327. TUnboxedValue GetListIterator() const final {
  328. return TUnboxedValuePod(new TIterator<false>(Original.GetListIterator(), Converter));
  329. }
  330. TUnboxedValue GetDictIterator() const final {
  331. return TUnboxedValuePod(new TIterator<true>(Original.GetDictIterator(), Converter));
  332. }
  333. TUnboxedValue GetKeysIterator() const final {
  334. return TUnboxedValuePod(new TIterator<true>(Original.GetKeysIterator(), Converter));
  335. }
  336. TUnboxedValue GetPayloadsIterator() const {
  337. return TUnboxedValuePod(new TIterator<false>(Original.GetPayloadsIterator(), Converter));
  338. }
  339. bool Contains(const TUnboxedValuePod& key) const final {
  340. return Original.Contains(key);
  341. }
  342. TUnboxedValue Lookup(const TUnboxedValuePod& key) const final {
  343. if (auto lookup = Original.Lookup(key)) {
  344. return Converter(lookup.Release().GetOptionalValue()).MakeOptional();
  345. }
  346. return {};
  347. }
  348. bool IsSortedDict() const final {
  349. return Original.IsSortedDict();
  350. }
  351. private:
  352. const TUnboxedValue Original;
  353. const TConverter Converter;
  354. };
  355. }