123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- #pragma once
- #include <yql/essentials/public/udf/udf_value.h>
- #include <yql/essentials/public/udf/udf_value_builder.h>
- #include <yql/essentials/utils/utf8.h>
- #include <util/string/escape.h>
- #include <util/string/cast.h>
- #include <util/string/builder.h>
- #include <functional>
- namespace NYql::NDom {
- template<bool Strict, bool AutoConvert>
- TUnboxedValuePod ConvertToBool(TUnboxedValuePod x, const IValueBuilder* valueBuilder, const TSourcePosition& pos) {
- switch (GetNodeType(x)) {
- case ENodeType::Bool:
- return TUnboxedValuePod(x.Get<bool>());
- case ENodeType::String:
- if (const std::string_view str = x.AsStringRef(); str == "true")
- return TUnboxedValuePod(true);
- else if (str == "false")
- return TUnboxedValuePod(false);
- else if constexpr (AutoConvert)
- return TUnboxedValuePod(x.AsStringRef().Size() > 0U);
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Uint64:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(x.Get<ui64>() != 0ULL);
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Int64:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(x.Get<i64>() != 0LL);
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Double:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(x.Get<double>() != 0.);
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Entity:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(false);
- else if constexpr (Strict)
- break;
- else if constexpr (AutoConvert)
- return TUnboxedValuePod(false);
- else
- return {};
- case ENodeType::List:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(x.IsBoxed() && x.HasListItems());
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Dict:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(x.IsBoxed() && x.HasDictItems());
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Attr:
- return ConvertToBool<Strict, AutoConvert>(x.GetVariantItem().Release(), valueBuilder, pos);
- }
- UdfTerminate((::TStringBuilder() << valueBuilder->WithCalleePosition(pos) << " Cannot parse boolean value from " << TDebugPrinter(x)).c_str());
- }
- template<typename TDst, typename TSrc>
- constexpr inline bool InBounds(const TSrc v) {
- if constexpr (std::is_same<TSrc, TDst>())
- return true;
- if constexpr (sizeof(TSrc) > sizeof(TDst))
- if constexpr (std::is_signed<TSrc>())
- return v <= TSrc(std::numeric_limits<TDst>::max()) && v >= TSrc(std::numeric_limits<TDst>::min());
- else
- return v <= TSrc(std::numeric_limits<TDst>::max());
- else
- if constexpr (std::is_signed<TSrc>())
- return v >= TSrc(std::numeric_limits<TDst>::min());
- else
- return v <= TSrc(std::numeric_limits<TDst>::max());
- static_assert(sizeof(TSrc) >= sizeof(TDst), "Expects wide to short.");
- }
- template<bool Strict, bool AutoConvert, typename TargetType>
- TUnboxedValuePod ConvertToIntegral(TUnboxedValuePod x, const IValueBuilder* valueBuilder, const TSourcePosition& pos) {
- switch (GetNodeType(x)) {
- case ENodeType::Int64: {
- const auto s = x.Get<i64>();
- if constexpr (AutoConvert)
- return TUnboxedValuePod(TargetType(s));
- else if (InBounds<TargetType>(s))
- return TUnboxedValuePod(TargetType(s));
- else if constexpr (Strict)
- break;
- else
- return {};
- }
- case ENodeType::Uint64: {
- const auto u = x.Get<ui64>();
- if constexpr (AutoConvert)
- return TUnboxedValuePod(TargetType(u));
- else if (InBounds<TargetType>(u))
- return TUnboxedValuePod(TargetType(u));
- else if constexpr (Strict)
- break;
- else
- return {};
- }
- case ENodeType::Bool:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(TargetType(x.Get<bool>() ? 1 : 0));
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Double:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(TargetType(x.Get<double>()));
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::String:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(FromStringWithDefault(std::string_view(x.AsStringRef()), TargetType(0)));
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Entity:
- if constexpr (AutoConvert)
- return TUnboxedValuePod::Zero();
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::List:
- if constexpr (AutoConvert)
- return TUnboxedValuePod::Zero();
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Dict:
- if constexpr (AutoConvert)
- return TUnboxedValuePod::Zero();
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Attr:
- return ConvertToIntegral<Strict, AutoConvert, TargetType>(x.GetVariantItem().Release(), valueBuilder, pos);
- }
- UdfTerminate((::TStringBuilder() << valueBuilder->WithCalleePosition(pos) << " Cannot parse integer value from " << TDebugPrinter(x)).c_str());
- static_assert(std::is_integral<TargetType>(), "Expect integral.");
- }
- template<bool Strict, bool AutoConvert, typename TargetType>
- TUnboxedValuePod ConvertToFloat(TUnboxedValuePod x, const IValueBuilder* valueBuilder, const TSourcePosition& pos) {
- switch (GetNodeType(x)) {
- case ENodeType::Double:
- return TUnboxedValuePod(TargetType(x.Get<double>()));
- case ENodeType::Uint64:
- return TUnboxedValuePod(TargetType(x.Get<ui64>()));
- case ENodeType::Int64:
- return TUnboxedValuePod(TargetType(x.Get<i64>()));
- case ENodeType::Bool:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(x.Get<bool>() ? TargetType(1) : TargetType(0));
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::String:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(FromStringWithDefault(std::string_view(x.AsStringRef()), TargetType(0)));
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Entity:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(TargetType(0));
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::List:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(TargetType(0));
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Dict:
- if constexpr (AutoConvert)
- return TUnboxedValuePod(TargetType(0));
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Attr:
- return ConvertToFloat<Strict, AutoConvert, TargetType>(x.GetVariantItem().Release(), valueBuilder, pos);
- }
- UdfTerminate((::TStringBuilder() << valueBuilder->WithCalleePosition(pos) << " Cannot parse floating point value from " << TDebugPrinter(x)).c_str());
- static_assert(std::is_floating_point<TargetType>(), "Expect float.");
- }
- template<bool Strict, bool AutoConvert, bool Utf8>
- TUnboxedValuePod ConvertToString(TUnboxedValuePod x, const IValueBuilder* valueBuilder, const TSourcePosition& pos) {
- switch (GetNodeType(x)) {
- case ENodeType::String:
- if constexpr (Utf8)
- if (IsUtf8(x.AsStringRef()))
- return x;
- else
- if (AutoConvert)
- return valueBuilder->NewString(EscapeC(TStringBuf(x.AsStringRef()))).Release();
- else if constexpr (Strict)
- break;
- else
- return {};
- else
- return x;
- case ENodeType::Uint64:
- if constexpr (AutoConvert)
- return valueBuilder->NewString(ToString(x.Get<ui64>())).Release();
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Int64:
- if constexpr (AutoConvert)
- return valueBuilder->NewString(ToString(x.Get<i64>())).Release();
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Bool:
- if constexpr (AutoConvert)
- return x.Get<bool>() ? TUnboxedValuePod::Embedded("true") : TUnboxedValuePod::Embedded("false");
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Double:
- if constexpr (AutoConvert)
- return valueBuilder->NewString(::FloatToString(x.Get<double>())).Release();
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Entity:
- case ENodeType::List:
- case ENodeType::Dict:
- if constexpr (AutoConvert)
- return TUnboxedValuePod::Embedded("");
- else if constexpr (Strict)
- break;
- else
- return {};
- case ENodeType::Attr:
- return ConvertToString<Strict, AutoConvert, Utf8>(x.GetVariantItem().Release(), valueBuilder, pos);
- }
- UdfTerminate((::TStringBuilder() << valueBuilder->WithCalleePosition(pos) << " Cannot parse string value from " << TDebugPrinter(x)).c_str());
- }
- class TLazyConveter : public TManagedBoxedValue {
- public:
- using TConverter = std::function<TUnboxedValuePod(TUnboxedValuePod)>;
- TLazyConveter(TUnboxedValue&& original, TConverter&& converter)
- : Original(std::move(original)), Converter(std::move(converter))
- {}
- private:
- template <bool NoSwap>
- class TIterator: public TManagedBoxedValue {
- public:
- TIterator(TUnboxedValue&& original, const TConverter& converter)
- : Original(std::move(original)), Converter(converter)
- {}
- private:
- bool Skip() final {
- return Original.Skip();
- }
- bool Next(TUnboxedValue& value) final {
- if (Original.Next(value)) {
- if constexpr (!NoSwap) {
- value = Converter(value.Release());
- }
- return true;
- }
- return false;
- }
- bool NextPair(TUnboxedValue& key, TUnboxedValue& payload) final {
- if (Original.NextPair(key, payload)) {
- if constexpr (NoSwap) {
- payload = Converter(payload.Release());
- } else {
- key = Converter(key.Release());
- }
- return true;
- }
- return false;
- }
- const TUnboxedValue Original;
- const TConverter Converter;
- };
- ui64 GetDictLength() const final {
- return Original.GetDictLength();
- }
- ui64 GetListLength() const final {
- return Original.GetListLength();
- }
- bool HasFastListLength() const final {
- return Original.HasFastListLength();
- }
- bool HasDictItems() const final {
- return Original.HasDictItems();
- }
- bool HasListItems() const final {
- return Original.HasListItems();
- }
- TUnboxedValue GetListIterator() const final {
- return TUnboxedValuePod(new TIterator<false>(Original.GetListIterator(), Converter));
- }
- TUnboxedValue GetDictIterator() const final {
- return TUnboxedValuePod(new TIterator<true>(Original.GetDictIterator(), Converter));
- }
- TUnboxedValue GetKeysIterator() const final {
- return TUnboxedValuePod(new TIterator<true>(Original.GetKeysIterator(), Converter));
- }
- TUnboxedValue GetPayloadsIterator() const {
- return TUnboxedValuePod(new TIterator<false>(Original.GetPayloadsIterator(), Converter));
- }
- bool Contains(const TUnboxedValuePod& key) const final {
- return Original.Contains(key);
- }
- TUnboxedValue Lookup(const TUnboxedValuePod& key) const final {
- if (auto lookup = Original.Lookup(key)) {
- return Converter(lookup.Release().GetOptionalValue()).MakeOptional();
- }
- return {};
- }
- bool IsSortedDict() const final {
- return Original.IsSortedDict();
- }
- private:
- const TUnboxedValue Original;
- const TConverter Converter;
- };
- }
|