#include "mkql_builtins_decimal.h" // Y_IGNORE #include #include #include #include #include #include namespace NKikimr { namespace NMiniKQL { namespace { template struct TFloatToIntegralImpl { static constexpr TIn MinValue = static_cast(std::numeric_limits::min()); static constexpr TIn MaxValue = std::is_same::value ? MaxFloor() : static_cast(std::numeric_limits::max()); static NUdf::TUnboxedValuePod Do(TIn val) { switch (std::fpclassify(val)) { case FP_NORMAL: break; case FP_ZERO: case FP_SUBNORMAL: return NUdf::TUnboxedValuePod::Zero(); default: return NUdf::TUnboxedValuePod(); } if (val < MinValue || val > MaxValue) { return NUdf::TUnboxedValuePod(); } return NUdf::TUnboxedValuePod(static_cast(val)); } #ifndef MKQL_DISABLE_CODEGEN static Value* Gen(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); auto& module = ctx.Codegen.GetModule(); const auto val = GetterFor(arg, context, block); const auto type = Type::getInt32Ty(context); const auto fnType = FunctionType::get(type, {val->getType()}, false); const auto name = std::is_same() ? "MyFloatClassify" : "MyDoubleClassify"; ctx.Codegen.AddGlobalMapping(name, reinterpret_cast(static_cast(&std::fpclassify))); const auto func = module.getOrInsertFunction(name, fnType).getCallee(); const auto classify = CallInst::Create(fnType, func, {val}, "fpclassify", block); const auto none = BasicBlock::Create(context, "none", ctx.Func); const auto zero = BasicBlock::Create(context, "zero", ctx.Func); const auto good = BasicBlock::Create(context, "good", ctx.Func); const auto done = BasicBlock::Create(context, "done", ctx.Func); const auto result = PHINode::Create(arg->getType(), 3, "result", done); result->addIncoming(GetFalse(context), zero); result->addIncoming(ConstantInt::get(arg->getType(), 0), none); const auto choise = SwitchInst::Create(classify, none, 5, block); choise->addCase(ConstantInt::get(type, FP_NAN), none); choise->addCase(ConstantInt::get(type, FP_INFINITE), none); BranchInst::Create(done, none); choise->addCase(ConstantInt::get(type, FP_ZERO), zero); choise->addCase(ConstantInt::get(type, FP_SUBNORMAL), zero); BranchInst::Create(done, zero); choise->addCase(ConstantInt::get(type, FP_NORMAL), good); block = good; const auto less = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_OLT, val, ConstantFP::get(val->getType(), MinValue), "less", block); const auto greater = CmpInst::Create(Instruction::FCmp, FCmpInst::FCMP_OGT, val, ConstantFP::get(val->getType(), MaxValue), "greater", block); const auto bad = BinaryOperator::CreateOr(less, greater, "or", block); const auto make = BasicBlock::Create(context, "make", ctx.Func); BranchInst::Create(none, make, bad, block); block = make; const auto cast = StaticCast(val, context, block); const auto wide = SetterFor(cast, context, block); result->addIncoming(wide, block); BranchInst::Create(done, block); block = done; return result; } #endif }; template struct TFloatToIntegralImpl { static NUdf::TUnboxedValuePod Do(TIn val) { switch (std::fpclassify(val)) { case FP_NORMAL: case FP_INFINITE: return NUdf::TUnboxedValuePod(true); break; case FP_ZERO: case FP_SUBNORMAL: return NUdf::TUnboxedValuePod(false); default: return NUdf::TUnboxedValuePod(); } } #ifndef MKQL_DISABLE_CODEGEN static Value* Gen(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); auto& module = ctx.Codegen.GetModule(); const auto val = GetterFor(arg, context, block); const auto type = Type::getInt32Ty(context); const auto fnType = FunctionType::get(type, {val->getType()}, false); const auto name = std::is_same() ? "MyFloatClassify" : "MyDoubleClassify"; ctx.Codegen.AddGlobalMapping(name, reinterpret_cast(static_cast(&std::fpclassify))); const auto func = module.getOrInsertFunction(name, fnType).getCallee(); const auto classify = CallInst::Create(fnType, func, {val}, "fpclassify", block); const auto none = BasicBlock::Create(context, "none", ctx.Func); const auto zero = BasicBlock::Create(context, "zero", ctx.Func); const auto good = BasicBlock::Create(context, "good", ctx.Func); const auto done = BasicBlock::Create(context, "done", ctx.Func); const auto result = PHINode::Create(arg->getType(), 3, "result", done); result->addIncoming(GetTrue(context), good); result->addIncoming(GetFalse(context), zero); result->addIncoming(ConstantInt::get(arg->getType(), 0), none); const auto choise = SwitchInst::Create(classify, none, 5, block); choise->addCase(ConstantInt::get(type, FP_NAN), none); BranchInst::Create(done, none); choise->addCase(ConstantInt::get(type, FP_ZERO), zero); choise->addCase(ConstantInt::get(type, FP_SUBNORMAL), zero); BranchInst::Create(done, zero); choise->addCase(ConstantInt::get(type, FP_INFINITE), good); choise->addCase(ConstantInt::get(type, FP_NORMAL), good); BranchInst::Create(done, good); block = done; return result; } #endif }; template struct TFloatToIntegral : public TArithmeticConstraintsUnary { static_assert(std::is_floating_point::value, "Input type must be floating point!"); static_assert(std::is_integral::value, "Output type must be integral!"); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return TFloatToIntegralImpl::Do(arg.template Get()); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { return TFloatToIntegralImpl::Gen(arg, ctx, block); } #endif }; #ifndef MKQL_DISABLE_CODEGEN Value* GenInBounds(Value* val, Constant* low, Constant* high, BasicBlock* block) { const auto lt = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLE, val, high, "lt", block); const auto gt = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGE, val, low, "gt", block); const auto good = BinaryOperator::CreateAnd(lt, gt, "and", block); return good; } #endif template ::max(), TOutput MinVal = std::numeric_limits::min()> struct TWideToShort : public TArithmeticConstraintsUnary { static_assert(std::is_integral_v, "Input type must be integral!"); static_assert(std::is_integral_v, "Output type must be integral!"); static constexpr auto LowerBound = static_cast(MinVal); static constexpr auto UpperBound = static_cast(MaxVal); static constexpr bool SkipLower = std::is_unsigned_v || (sizeof(TInput) < sizeof(TOutput) && std::is_signed_v); static constexpr bool SkipUpper = sizeof(TInput) < sizeof(TOutput) || (sizeof(TInput) == sizeof(TOutput) && std::is_signed_v && std::is_unsigned_v && UpperBound < 0); static_assert(!(SkipLower && SkipUpper), "Only for cut input digits!"); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { const auto val = arg.template Get(); const bool ok = (SkipLower || val >= LowerBound) && (SkipUpper || val <= UpperBound); return ok ? NUdf::TUnboxedValuePod(static_cast(val)) : NUdf::TUnboxedValuePod(); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto lb = ConstantInt::get(val->getType(), LowerBound); const auto ub = ConstantInt::get(val->getType(), UpperBound); const auto good = SkipLower ? CmpInst::Create(Instruction::ICmp, std::is_signed_v ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE, val, ub, "ok", block): SkipUpper ? CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGE, val, lb, "ok", block): GenInBounds(val, lb, ub, block); const auto full = SetterFor(StaticCast(val, context, block), context, block); const auto res = SelectInst::Create(good, full, ConstantInt::get(arg->getType(), 0), "result", block); return res; } #endif }; template struct TConvert : public TArithmeticConstraintsUnary { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return NUdf::TUnboxedValuePod(static_cast(arg.template Get())); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto res = StaticCast(val, context, block); const auto wide = SetterFor(res, context, block); return wide; } #endif }; template struct TScaleUp : public TArithmeticConstraintsUnary { static_assert(sizeof(TInput) < sizeof(TOutput), "Output should be wider than input."); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return NUdf::TUnboxedValuePod(Multiplier * static_cast(arg.template Get())); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto cast = StaticCast(val, context, block); const auto mul = BinaryOperator::CreateMul(ConstantInt::get(cast->getType(), Multiplier), cast, "mul", block); const auto wide = SetterFor(mul, context, block); return wide; } #endif }; template struct TDatetimeScale; template <> struct TDatetimeScale { static constexpr ui32 Modifier = 86400U; }; template <> struct TDatetimeScale { static constexpr ui64 Modifier = 1000000ULL; }; template <> struct TDatetimeScale { static constexpr ui64 Modifier = 86400000000ULL; }; template struct TBigDateScale; template <> struct TBigDateScale, NUdf::TDataType> { static constexpr i64 Modifier = 86400LL; }; template <> struct TBigDateScale, NUdf::TDataType> { static constexpr i64 Modifier = 86400LL; }; template <> struct TBigDateScale, NUdf::TDataType> { static constexpr i64 Modifier = 86400LL; }; template <> struct TBigDateScale, NUdf::TDataType> { static constexpr i64 Modifier = 1000000LL; }; template <> struct TBigDateScale, NUdf::TDataType> { static constexpr i64 Modifier = 1000000LL; }; template <> struct TBigDateScale, NUdf::TDataType> { static constexpr i64 Modifier = 1000000LL; }; template <> struct TBigDateScale, NUdf::TDataType> { static constexpr i64 Modifier = 86400000000LL; }; template <> struct TBigDateScale, NUdf::TDataType> { static constexpr i64 Modifier = 86400000000LL; }; template <> struct TBigDateScale, NUdf::TDataType> { static constexpr i64 Modifier = 86400000000LL; }; template struct TBigDateScaleUp : public TArithmeticConstraintsUnary { static_assert( sizeof(typename TInput::TLayout) <= sizeof(typename TOutput::TLayout), "Output size should be greater or equal than input size."); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return NUdf::TUnboxedValuePod( TBigDateScale::Modifier * static_cast(arg.template Get())); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto cast = StaticCast(val, context, block); const auto mul = BinaryOperator::CreateMul(ConstantInt::get(cast->getType(), TBigDateScale::Modifier), cast, "mul", block); return SetterFor(mul, context, block); } #endif }; template struct TBigDateToNarrowScaleUp : public TArithmeticConstraintsUnary { static_assert( sizeof(typename TInput::TLayout) <= sizeof(typename TOutput::TLayout), "Output size should be greater or equal than input size."); static_assert(std::is_signed_v, "Expect signed input type"); static_assert(std::is_unsigned_v, "Expect unsigned output type"); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { auto result = TBigDateScale::Modifier * arg.template Get(); if (result < 0 || result > UpperBound) { return NUdf::TUnboxedValuePod(); } return NUdf::TUnboxedValuePod(static_cast(result)); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto val64 = StaticCast(val, context, block); const auto mul = BinaryOperator::CreateMul(val64, ConstantInt::get(val64->getType(), TBigDateScale::Modifier), "mul", block); const auto cast = StaticCast(mul, context, block); const auto gt = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGE, val, ConstantInt::get(val->getType(), 0), "gt", block); const auto lt = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULE, mul, ConstantInt::get(mul->getType(), UpperBound), "lt", block); const auto good = BinaryOperator::CreateAnd(gt, lt, "and", block); const auto full = SetterFor(cast, context, block); return SelectInst::Create(good, full, ConstantInt::get(arg->getType(), 0), "result", block); } #endif }; template struct TNarrowToBigDateScaleDown : public TArithmeticConstraintsUnary { static_assert( sizeof(typename TInput::TLayout) >= sizeof(typename TOutput::TLayout), "Output size should be smaller or equal than input size."); static_assert(std::is_unsigned_v, "Input type must be unsigned."); static_assert(std::is_signed_v, "Output type must be signed."); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return NUdf::TUnboxedValuePod(static_cast( arg.template Get() / TBigDateScale::Modifier)); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto div = BinaryOperator::CreateUDiv(val, ConstantInt::get(val->getType(), TBigDateScale::Modifier), "div", block); const auto cast = StaticCast(div, context, block); return SetterFor(cast, context, block); } #endif }; template struct TBigDateScaleDown : public TArithmeticConstraintsUnary { static_assert( sizeof(typename TInput::TLayout) >= sizeof(typename TOutput::TLayout), "Output size should be smaller or equal than input size."); static_assert( std::is_signed_v && std::is_signed_v, "Only for signed layout types."); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return NUdf::TUnboxedValuePod(static_cast( arg.template Get() / TBigDateScale::Modifier)); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto div = BinaryOperator::CreateSDiv(val, ConstantInt::get(val->getType(), TBigDateScale::Modifier), "div", block); const auto cast = StaticCast(div, context, block); return SetterFor(cast, context, block); } #endif }; template struct TBigDateToNarrowScaleDown : public TArithmeticConstraintsUnary { static_assert( sizeof(typename TInput::TLayout) > sizeof(typename TOutput::TLayout), "Output size should be smaller than input size."); static_assert(std::is_same_v, "Expect i64 input type"); static_assert(std::is_unsigned_v, "Expect unsigned output type"); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { auto inputValue = arg.template Get(); if (inputValue < 0) { return NUdf::TUnboxedValuePod(); } auto result = inputValue / TBigDateScale::Modifier; if (result > UpperBound) { return NUdf::TUnboxedValuePod(); } return NUdf::TUnboxedValuePod(static_cast(result)); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto div = BinaryOperator::CreateSDiv(val, ConstantInt::get(val->getType(), TBigDateScale::Modifier), "div", block); const auto gt = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGE, val, ConstantInt::get(val->getType(), 0), "gt", block); const auto lt = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLE, div, ConstantInt::get(div->getType(), UpperBound), "lt", block); const auto good = BinaryOperator::CreateAnd(gt, lt, "and", block); const auto cast = StaticCast(div, context, block); const auto full = SetterFor(cast, context, block); return SelectInst::Create(good, full, ConstantInt::get(arg->getType(), 0), "result", block); } #endif }; template struct TDatetimeScaleUp : public TArithmeticConstraintsUnary { static_assert(sizeof(TInput) < sizeof(TOutput), "Output size should be wider than input size."); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { auto result = NUdf::TUnboxedValuePod(TDatetimeScale::Modifier * static_cast(arg.template Get())); if constexpr (Tz) { result.SetTimezoneId(arg.GetTimezoneId()); } return result; } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto cast = StaticCast(val, context, block); const auto mul = BinaryOperator::CreateMul(ConstantInt::get(cast->getType(), TDatetimeScale::Modifier), cast, "mul", block); const auto wide = SetterFor(mul, context, block); if constexpr (Tz) { const uint64_t init[] = {0ULL, 0xFFFFULL}; const auto mask = ConstantInt::get(arg->getType(), APInt(128, 2, init)); const auto tzid = BinaryOperator::CreateAnd(arg, mask, "tzid", block); const auto full = BinaryOperator::CreateOr(wide, tzid, "full", block); return full; } else { return wide; } } #endif }; template struct TDatetimeScaleDown : public TArithmeticConstraintsUnary { static_assert(sizeof(TInput) > sizeof(TOutput), "Output size should be narrower than input size."); static_assert(std::is_unsigned_v && std::is_unsigned_v, "Only for unsigned."); static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { auto result = NUdf::TUnboxedValuePod(static_cast(arg.template Get() / TDatetimeScale::Modifier)); if constexpr (Tz) { result.SetTimezoneId(arg.GetTimezoneId()); } return result; } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterFor(arg, context, block); const auto div = BinaryOperator::CreateUDiv(val, ConstantInt::get(val->getType(), TDatetimeScale::Modifier), "div", block); const auto cast = StaticCast(div, context, block); const auto wide = SetterFor(cast, context, block); if constexpr (Tz) { const uint64_t init[] = {0ULL, 0xFFFFULL}; const auto mask = ConstantInt::get(arg->getType(), APInt(128, 2, init)); const auto tzid = BinaryOperator::CreateAnd(arg, mask, "tzid", block); const auto full = BinaryOperator::CreateOr(wide, tzid, "full", block); return full; } else { return wide; } } #endif }; template using TDatetimeRescale = std::conditional_t, TDatetimeScaleDown >; template struct TDatetimeTzStub { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { auto result = arg; if (Cleanup) { result.SetTimezoneId(0); } return result; } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext&, BasicBlock*& block) { if constexpr (Cleanup) { const uint64_t init[] = {0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFF0000ULL}; const auto mask = ConstantInt::get(arg->getType(), APInt(128, 2, init)); return BinaryOperator::CreateAnd(arg, mask, "clean", block); } else { return arg; } } #endif }; struct TStringConvert { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { Y_DEBUG_ABORT_UNLESS(!arg.IsBoxed(), "Expected unboxed arg in String::Convert()"); return arg; // handle optional args as well } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext&, BasicBlock*&) { return arg; } #endif }; NUdf::TUnboxedValuePod JsonToJsonDocument(const NUdf::TUnboxedValuePod value) { auto maybeBinaryJson = NKikimr::NBinaryJson::SerializeToBinaryJson(value.AsStringRef()); if (std::holds_alternative(maybeBinaryJson)) { // JSON parse error happened, return NULL return NUdf::TUnboxedValuePod(); } const auto& binaryJson = std::get(maybeBinaryJson); return MakeString(TStringBuf(binaryJson.Data(), binaryJson.Size())); } struct TJsonToJsonDocumentConvert { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return JsonToJsonDocument(arg); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* json, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto functionAddress = ConstantInt::get(Type::getInt64Ty(context), GetMethodPtr(JsonToJsonDocument)); const auto functionType = FunctionType::get(json->getType(), {json->getType()}, /* isVarArg */ false); const auto functionPtr = CastInst::Create(Instruction::IntToPtr, functionAddress, PointerType::getUnqual(functionType), "func", block); return CallInst::Create(functionType, functionPtr, {json}, "jsonToJsonDocument", block); } #endif }; NUdf::TUnboxedValuePod JsonDocumentToJson(const NUdf::TUnboxedValuePod value) { auto json = NKikimr::NBinaryJson::SerializeToJson(value.AsStringRef()); return MakeString(json); } struct TJsonDocumentToJsonConvert { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return JsonDocumentToJson(arg); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* jsonDocument, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto functionAddress = ConstantInt::get(Type::getInt64Ty(context), GetMethodPtr(JsonDocumentToJson)); const auto functionType = FunctionType::get(jsonDocument->getType(), {jsonDocument->getType()}, /* isVarArg */ false); const auto functionPtr = CastInst::Create(Instruction::IntToPtr, functionAddress, PointerType::getUnqual(functionType), "func", block); return CallInst::Create(functionType, functionPtr, {jsonDocument}, "jsonDocumentToJson", block); } #endif }; } namespace NDecimal { template struct TConvertFromIntegral { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return NUdf::TUnboxedValuePod(NYql::NDecimal::TInt128(arg.Get())); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { const auto val = GetterFor(arg, ctx.Codegen.GetContext(), block); const auto ext = CastInst::Create(std::is_signed() ? Instruction::SExt : Instruction::ZExt, val, arg->getType(), "ext", block); return SetterForInt128(ext, block); } #endif static_assert(std::is_arithmetic::value, "Input type must be arithmetic!"); }; template struct TConvertToIntegral { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { const auto v = arg.GetInt128(); return v >= std::numeric_limits::min() && v <= std::numeric_limits::max() ? NUdf::TUnboxedValuePod(static_cast(arg.GetInt128())) : NUdf::TUnboxedValuePod(); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterForInt128(arg, block); const auto cut = CastInst::Create(Instruction::Trunc, val, GetTypeFor(context), "cut", block); const auto full = SetterFor(cut, context, block); const auto good = GenInBounds(val, GenConstant(std::numeric_limits::min(), context), GenConstant(std::numeric_limits::max(), context), block); const auto res = SelectInst::Create(good, full, ConstantInt::get(arg->getType(), 0), "result", block); return res; } #endif static_assert(std::is_arithmetic::value, "Output type must be arithmetic!"); }; template TOutput GetFP(NYql::NDecimal::TInt128 v); template<> float GetFP(NYql::NDecimal::TInt128 v) { return static_cast(v); } template<> double GetFP(NYql::NDecimal::TInt128 v) { return static_cast(v); } template TOutput GetFP(NYql::NDecimal::TInt128 v) { if (v % 10) return static_cast(v) / static_cast(NYql::NDecimal::GetDivider()); else return GetFP(v / 10); } #ifndef MKQL_DISABLE_CODEGEN template void GenFP(PHINode* result, Value* val, const TCodegenContext& ctx, BasicBlock* done, BasicBlock*& block); template<> void GenFP(PHINode* result, Value* val, const TCodegenContext& ctx, BasicBlock* done, BasicBlock*& block) { const auto cast = CastInst::Create(Instruction::SIToFP, val, GetTypeFor(ctx.Codegen.GetContext()), "cast", block); result->addIncoming(cast, block); BranchInst::Create(done, block); } template<> void GenFP(PHINode* result, Value* val, const TCodegenContext& ctx, BasicBlock* done, BasicBlock*& block) { const auto cast = CastInst::Create(Instruction::SIToFP, val, GetTypeFor(ctx.Codegen.GetContext()), "cast", block); result->addIncoming(cast, block); BranchInst::Create(done, block); } template void GenFP(PHINode* result, Value* val, const TCodegenContext& ctx, BasicBlock* done, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto& str = ToString(Scale); const auto stop = BasicBlock::Create(context, (TString("stop_") += str).c_str(), ctx.Func); const auto step = BasicBlock::Create(context, (TString("step_") += str).c_str(), ctx.Func); const auto ten = ConstantInt::get(val->getType(), 10U); const auto rem = BinaryOperator::CreateSRem(val, ten, "rem", block); const auto nul = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, rem, ConstantInt::get(val->getType(), 0U), "nul", block); BranchInst::Create(step, stop, nul, block); block = stop; const auto cast = CastInst::Create(Instruction::SIToFP, val, GetTypeFor(ctx.Codegen.GetContext()), "cast", block); const auto divf = BinaryOperator::CreateFDiv(cast, ConstantFP::get(GetTypeFor(context), static_cast(NYql::NDecimal::GetDivider())), "divf", block); result->addIncoming(divf, block); BranchInst::Create(done, block); block = step; const auto div = BinaryOperator::CreateSDiv(val, ten, "div", block); GenFP(result, div, ctx, done, block); } #endif template struct TToFP { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { const auto v = arg.GetInt128(); if (v == +NYql::NDecimal::Inf()) return NUdf::TUnboxedValuePod(+std::numeric_limits::infinity()); if (v == -NYql::NDecimal::Inf()) return NUdf::TUnboxedValuePod(-std::numeric_limits::infinity()); if (v == +NYql::NDecimal::Nan()) return NUdf::TUnboxedValuePod(+std::numeric_limits::quiet_NaN()); if (v == -NYql::NDecimal::Nan()) return NUdf::TUnboxedValuePod(-std::numeric_limits::quiet_NaN()); return NUdf::TUnboxedValuePod(GetFP(v)); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterForInt128(arg, block); const auto pnan = BasicBlock::Create(context, "pnan", ctx.Func); const auto pinf = BasicBlock::Create(context, "pinf", ctx.Func); const auto mnan = BasicBlock::Create(context, "mnan", ctx.Func); const auto minf = BasicBlock::Create(context, "minf", ctx.Func); const auto norm = BasicBlock::Create(context, "norm", ctx.Func); const auto done = BasicBlock::Create(context, "done", ctx.Func); const auto result = PHINode::Create(GetTypeFor(context), 5U + Scale, "result", done); const auto choise = SwitchInst::Create(val, norm, 4U, block); choise->addCase(GenConstant(+NYql::NDecimal::Nan(), context), pnan); choise->addCase(GenConstant(-NYql::NDecimal::Nan(), context), mnan); choise->addCase(GenConstant(+NYql::NDecimal::Inf(), context), pinf); choise->addCase(GenConstant(-NYql::NDecimal::Inf(), context), minf); block = pnan; result->addIncoming(ConstantFP::get(GetTypeFor(context), +std::numeric_limits::quiet_NaN()), block); BranchInst::Create(done, block); block = mnan; result->addIncoming(ConstantFP::get(GetTypeFor(context), -std::numeric_limits::quiet_NaN()), block); BranchInst::Create(done, block); block = pinf; result->addIncoming(ConstantFP::get(GetTypeFor(context), +std::numeric_limits::infinity()), block); BranchInst::Create(done, block); block = minf; result->addIncoming(ConstantFP::get(GetTypeFor(context), -std::numeric_limits::infinity()), block); BranchInst::Create(done, block); block = norm; GenFP(result, val, ctx, done, block); block = done; return SetterFor(result, context, block); } #endif static_assert(std::is_floating_point::value, "Output type must be floating point!"); static_assert(Scale <= NYql::NDecimal::MaxPrecision, "Too large scale!"); }; template using TToFloat = TToFP; template using TToDouble = TToFP; template struct TScaleUp { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return NUdf::TUnboxedValuePod(NYql::NDecimal::Mul(arg.GetInt128(), NYql::NDecimal::GetDivider())); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterForInt128(arg, block); const auto mul = BinaryOperator::CreateMul(val, GenConstant(NYql::NDecimal::GetDivider(), context), "mul", block); const auto res = SelectInst::Create(GenIsNormal(val, context, block), mul, val, "result", block); return SetterForInt128(res, block); } #endif static_assert(Scale <= NYql::NDecimal::MaxPrecision, "Too large scale!"); }; template struct TScaleDown { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { return NUdf::TUnboxedValuePod(NYql::NDecimal::Div(arg.GetInt128(), NYql::NDecimal::GetDivider())); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterForInt128(arg, block); const auto divider = GenConstant(NYql::NDecimal::GetDivider() >> 1, context); const auto nul = ConstantInt::get(val->getType(), 0); const auto one = ConstantInt::get(val->getType(), 1); const auto div = BinaryOperator::CreateSDiv(val, divider, "div", block); const auto ashr = BinaryOperator::CreateAShr(div, one, "ashr", block); const auto bit = CastInst::Create(Instruction::Trunc, div, Type::getInt1Ty(context), "bit", block); const auto done = BasicBlock::Create(context, "done", ctx.Func); const auto round = BasicBlock::Create(context, "round", ctx.Func); const auto result = PHINode::Create(val->getType(), 2, "result", done); result->addIncoming(ashr, block); BranchInst::Create(round, done, bit, block); block = round; const auto mod = BinaryOperator::CreateSRem(val, divider, "mod", block); const auto zero = CmpInst::Create(Instruction::ICmp, FCmpInst::ICMP_EQ, mod, nul, "zero", block); const auto plus = CmpInst::Create(Instruction::ICmp, FCmpInst::ICMP_SGT, mod, nul, "plus", block); const auto test = CastInst::Create(Instruction::Trunc, ashr, Type::getInt1Ty(context), "test", block); const auto even = BinaryOperator::CreateAnd(test, zero, "even", block); const auto up = BinaryOperator::CreateOr(plus, even, "up", block); const auto inc = BinaryOperator::CreateAdd(ashr, one, "inc", block); const auto rounded = SelectInst::Create(up, inc, ashr, "result", block); result->addIncoming(rounded, block); BranchInst::Create(done, block); block = done; const auto res = SelectInst::Create(GenIsNormal(val, context, block), result, val, "res", block); return SetterForInt128(res, block); } #endif static_assert(Scale <= NYql::NDecimal::MaxPrecision, "Too large scale!"); }; template struct TCheckBounds { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& arg) { const auto v = arg.GetInt128(); using namespace NYql::NDecimal; if (IsNormal(v)) return arg; return NUdf::TUnboxedValuePod(IsNan(v) ? Nan() : (v > 0 ? +Inf() : -Inf())); } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* arg, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto val = GetterForInt128(arg, block); const auto& bounds = GenBounds(context); const auto good = GenInBounds(val, bounds.first, bounds.second, block); const auto nan = GenIsNonComparable(val, context, block); const auto plus = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGT, val, ConstantInt::get(val->getType(), 0), "plus", block); const auto inf = SelectInst::Create(plus, GetDecimalPlusInf(context), GetDecimalMinusInf(context), "inf", block); const auto bad = SelectInst::Create(nan, GetDecimalNan(context), inf, "bad", block); const auto res = SelectInst::Create(good, arg, SetterForInt128(bad, block), "res", block); return res; } #endif static_assert(Precision <= NYql::NDecimal::MaxPrecision, "Too large precision!"); }; } namespace { constexpr auto convert = "Convert"; constexpr auto integral = "ToIntegral"; constexpr auto decimal = "ToDecimal"; template void RegisterConvert(IBuiltinFunctionRegistry& registry) { RegisterFunctionUnOpt(registry, convert); } template void RegisterStringConvert(IBuiltinFunctionRegistry& registry) { RegisterFunctionOpt(registry, convert); } template void RegisterIntegralCasts(IBuiltinFunctionRegistry& registry) { RegisterConvert, TOutput>(registry); RegisterConvert, TOutput>(registry); RegisterConvert, TOutput>(registry); RegisterConvert, TOutput>(registry); RegisterConvert, TOutput>(registry); RegisterConvert, TOutput>(registry); RegisterConvert, TOutput>(registry); RegisterConvert, TOutput>(registry); RegisterConvert, TOutput>(registry); } template void RegisterDecimalConvertFromIntegral(IBuiltinFunctionRegistry& registry) { RegisterFunctionOpt, NUdf::TDataType, NDecimal::TConvertFromIntegral, TUnaryArgsOpt>(registry, decimal); } template void RegisterDecimalConvertToIntegral(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); } void RegisterDecimalConvert(IBuiltinFunctionRegistry& registry) { RegisterDecimalConvertFromIntegral(registry); RegisterDecimalConvertFromIntegral(registry); RegisterDecimalConvertFromIntegral(registry); RegisterDecimalConvertFromIntegral(registry); RegisterDecimalConvertFromIntegral(registry); RegisterDecimalConvertFromIntegral(registry); RegisterDecimalConvertFromIntegral(registry); RegisterDecimalConvertFromIntegral(registry); RegisterDecimalConvertToIntegral(registry); RegisterDecimalConvertToIntegral(registry); RegisterDecimalConvertToIntegral(registry); RegisterDecimalConvertToIntegral(registry); RegisterDecimalConvertToIntegral(registry); RegisterDecimalConvertToIntegral(registry); RegisterDecimalConvertToIntegral(registry); RegisterDecimalConvertToIntegral(registry); NDecimal::RegisterUnaryFunctionForAllPrecisions(registry, "ScaleUp_"); NDecimal::RegisterUnaryFunctionForAllPrecisions(registry, "ScaleDown_"); NDecimal::RegisterUnaryFunctionForAllPrecisions(registry, "CheckBounds_"); NDecimal::RegisterCastFunctionForAllPrecisions>(registry, "ToFloat_"); NDecimal::RegisterCastFunctionForAllPrecisions>(registry, "ToDouble_"); } template void RegisterRealCasts(IBuiltinFunctionRegistry& registry) { RegisterConvert, TOutput>(registry); RegisterConvert, TOutput>(registry); } template void RegisterRealToIntegralCastsImpl(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, TUnaryWrap>(registry, integral); } template void RegisterRealToIntegralCasts(IBuiltinFunctionRegistry& registry) { RegisterRealToIntegralCastsImpl>(registry); RegisterRealToIntegralCastsImpl>(registry); RegisterRealToIntegralCastsImpl>(registry); RegisterRealToIntegralCastsImpl>(registry); RegisterRealToIntegralCastsImpl>(registry); RegisterRealToIntegralCastsImpl>(registry); RegisterRealToIntegralCastsImpl>(registry); RegisterRealToIntegralCastsImpl>(registry); RegisterRealToIntegralCastsImpl>(registry); } template void RegisterWideToShortCastsImpl(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, TUnaryWrap>(registry, integral); } template ::max()> void RegisterWideToDateCastsImpl(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, TUnaryWrap>(registry, integral); } template ::max(), typename TInput::TLayout LowerBound = std::numeric_limits::min()> void RegisterWideToBigDateCastsImpl(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, TUnaryWrap>(registry, integral); } void RegisterWideToIntervalCasts(IBuiltinFunctionRegistry& registry) { constexpr auto TimestampLimit = static_cast(NUdf::MAX_TIMESTAMP - 1ULL); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); } template void RegisterWideToUnsignedCasts(IBuiltinFunctionRegistry& registry) { RegisterWideToShortCastsImpl>(registry); RegisterWideToShortCastsImpl>(registry); RegisterWideToShortCastsImpl>(registry); RegisterWideToShortCastsImpl>(registry); } void RegisterWideToDateCasts(IBuiltinFunctionRegistry& registry) { RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE - 1U>(registry); } void RegisterWideToDatetimeCasts(IBuiltinFunctionRegistry& registry) { RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>(registry); } void RegisterWideToBigDateCasts(IBuiltinFunctionRegistry& registry) { RegisterWideToBigDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE32, NUdf::MIN_DATE32>(registry); RegisterWideToBigDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE32, NUdf::MIN_DATE32>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE32>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATE32>(registry); RegisterWideToBigDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATETIME64, NUdf::MIN_DATETIME64>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_DATETIME64>(registry); RegisterWideToBigDateCastsImpl, NUdf::TDataType, NUdf::MAX_TIMESTAMP64, NUdf::MIN_TIMESTAMP64>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_TIMESTAMP64>(registry); RegisterWideToBigDateCastsImpl, NUdf::TDataType, NUdf::MAX_INTERVAL64, -NUdf::MAX_INTERVAL64>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_INTERVAL64>(registry); } void RegisterWideToTimestampCasts(IBuiltinFunctionRegistry& registry) { RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_TIMESTAMP - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_TIMESTAMP - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_TIMESTAMP - 1U>(registry); RegisterWideToDateCastsImpl, NUdf::TDataType, NUdf::MAX_TIMESTAMP - 1U>(registry); } void RegisterWideToShortIntegralCasts(IBuiltinFunctionRegistry& registry) { RegisterWideToUnsignedCasts>(registry); RegisterWideToUnsignedCasts>(registry); RegisterWideToUnsignedCasts>(registry); RegisterWideToUnsignedCasts>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToUnsignedCasts>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToUnsignedCasts>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToUnsignedCasts>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToUnsignedCasts>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToShortCastsImpl, NUdf::TDataType>(registry); RegisterWideToUnsignedCasts>(registry); RegisterWideToDateCasts(registry); RegisterWideToBigDateCasts(registry); RegisterWideToDatetimeCasts(registry); RegisterWideToTimestampCasts(registry); RegisterWideToIntervalCasts(registry); } template void RegisterFromDateConvert(IBuiltinFunctionRegistry& registry) { RegisterConvert>(registry); RegisterConvert>(registry); RegisterConvert>(registry); RegisterConvert>(registry); RegisterConvert>(registry); RegisterConvert>(registry); RegisterConvert>(registry); RegisterConvert>(registry); RegisterConvert>(registry); RegisterConvert>(registry); } void RegisterToDateConvert(IBuiltinFunctionRegistry& registry) { RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); // Unsafe converts from layout type. Only for internal use. RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); } void RegisterToBigDateConvert(IBuiltinFunctionRegistry& registry) { RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); } template void RegisterBigDateScaleUp(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsOpt, TUnaryStub>(registry, convert); RegisterFunctionImpl, TUnaryArgsOpt, TUnaryWrap>(registry, convert); } template void RegisterBigDateScaleDown(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsOpt, TUnaryStub>(registry, convert); RegisterFunctionImpl, TUnaryArgsOpt, TUnaryWrap>(registry, convert); } void RegisterBigDateRescale(IBuiltinFunctionRegistry& registry) { RegisterBigDateScaleUp, NUdf::TDataType>(registry); RegisterBigDateScaleUp, NUdf::TDataType>(registry); RegisterBigDateScaleUp, NUdf::TDataType>(registry); RegisterBigDateScaleDown, NUdf::TDataType>(registry); RegisterBigDateScaleDown, NUdf::TDataType>(registry); RegisterBigDateScaleDown, NUdf::TDataType>(registry); } void RegisterNarrowToBigDateCasts(IBuiltinFunctionRegistry& registry) { RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterConvert, NUdf::TDataType>(registry); RegisterBigDateScaleUp, NUdf::TDataType>(registry); RegisterBigDateScaleUp, NUdf::TDataType>(registry); RegisterBigDateScaleUp, NUdf::TDataType>(registry); RegisterFunctionImpl, NUdf::TDataType>, TUnaryArgsOpt, NUdf::TDataType, false>, TUnaryStub>(registry, convert); RegisterFunctionImpl, NUdf::TDataType>, TUnaryArgsOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, convert); RegisterFunctionImpl, NUdf::TDataType>, TUnaryArgsOpt, NUdf::TDataType, false>, TUnaryStub>(registry, convert); RegisterFunctionImpl, NUdf::TDataType>, TUnaryArgsOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, convert); RegisterFunctionImpl, NUdf::TDataType>, TUnaryArgsOpt, NUdf::TDataType, false>, TUnaryStub>(registry, convert); RegisterFunctionImpl, NUdf::TDataType>, TUnaryArgsOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, convert); } void RegisterBigDateToNarrowCasts(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); constexpr auto TimestampLimit = static_cast(NUdf::MAX_TIMESTAMP - 1ULL); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleUp, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleUp, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleUp, NUdf::TDataType, NUdf::MAX_TIMESTAMP - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleUp, NUdf::TDataType, NUdf::MAX_TIMESTAMP - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleUp, NUdf::TDataType, NUdf::MAX_TIMESTAMP - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleUp, NUdf::TDataType, NUdf::MAX_TIMESTAMP - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleDown, NUdf::TDataType, NUdf::MAX_DATE - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleDown, NUdf::TDataType, NUdf::MAX_DATE - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleDown, NUdf::TDataType, NUdf::MAX_DATE - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleDown, NUdf::TDataType, NUdf::MAX_DATE - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleDown, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, false>, TUnaryStub>(registry, integral); RegisterFunctionImpl< TBigDateToNarrowScaleDown, NUdf::TDataType, NUdf::MAX_DATETIME - 1U>, TUnaryArgsWithNullableResultOpt, NUdf::TDataType, true>, TUnaryWrap>(registry, integral); } template void RegisterRescaleOpt(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsOpt, TUnaryStub>(registry, convert); RegisterFunctionImpl, TUnaryArgsOpt, TUnaryWrap>(registry, convert); } void RegisterDatetimeRescale(IBuiltinFunctionRegistry& registry) { RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType, true>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType, true>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType, true>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType, true>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType, true>(registry); RegisterRescaleOpt, NUdf::TDataType>(registry); RegisterRescaleOpt, NUdf::TDataType, true>(registry); } template void RegisterTzDateimeOpt(IBuiltinFunctionRegistry& registry) { RegisterFunctionImpl, TUnaryArgsOpt, TUnaryStub>(registry, convert); RegisterFunctionImpl, TUnaryArgsOpt, TUnaryWrap>(registry, convert); } void RegisterTzDateimeConvert(IBuiltinFunctionRegistry& registry) { RegisterTzDateimeOpt, NUdf::TDataType>(registry); RegisterTzDateimeOpt, NUdf::TDataType>(registry); RegisterTzDateimeOpt, NUdf::TDataType>(registry); RegisterTzDateimeOpt, NUdf::TDataType, true>(registry); RegisterTzDateimeOpt, NUdf::TDataType, true>(registry); RegisterTzDateimeOpt, NUdf::TDataType, true>(registry); RegisterTzDateimeOpt, NUdf::TDataType>(registry); RegisterTzDateimeOpt, NUdf::TDataType>(registry); RegisterTzDateimeOpt, NUdf::TDataType>(registry); RegisterTzDateimeOpt, NUdf::TDataType, true>(registry); RegisterTzDateimeOpt, NUdf::TDataType, true>(registry); RegisterTzDateimeOpt, NUdf::TDataType, true>(registry); } void RegisterJsonDocumentConvert(IBuiltinFunctionRegistry& registry) { // String/Utf8 -> JsonDocument and JsonDocument -> String/Utf8 conversions. TStringConvert is used as a placeholder because // actual conversions are handled by ValueFromString and ValueToString in mkql_type_ops.cpp RegisterFunctionOpt, NUdf::TDataType, TStringConvert, TUnaryArgsOpt>(registry, convert); RegisterFunctionOpt, NUdf::TDataType, TStringConvert, TUnaryArgsOpt>(registry, convert); RegisterFunctionOpt, NUdf::TDataType, TStringConvert, TUnaryArgsOpt>(registry, convert); RegisterFunctionOpt, NUdf::TDataType, TStringConvert, TUnaryArgsOpt>(registry, convert); // Json -> JsonDocument and JsonDocument -> Json conversions RegisterFunctionOpt, NUdf::TDataType, TJsonToJsonDocumentConvert, TUnaryArgsOpt>(registry, convert); RegisterFunctionOpt, NUdf::TDataType, TJsonDocumentToJsonConvert, TUnaryArgsOpt>(registry, convert); } } void RegisterConvert(IBuiltinFunctionRegistry& registry) { RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterIntegralCasts>(registry); RegisterWideToShortIntegralCasts(registry); RegisterRealCasts>(registry); RegisterRealCasts>(registry); RegisterRealCasts>(registry); RegisterRealCasts>(registry); RegisterRealCasts>(registry); RegisterRealCasts>(registry); RegisterRealCasts>(registry); RegisterRealCasts>(registry); RegisterRealCasts>(registry); RegisterRealCasts>(registry); RegisterRealToIntegralCasts>(registry); RegisterRealToIntegralCasts>(registry); RegisterStringConvert, NUdf::TDataType>(registry); RegisterStringConvert, NUdf::TDataType>(registry); RegisterStringConvert, NUdf::TDataType>(registry); RegisterStringConvert, NUdf::TDataType>(registry); RegisterStringConvert, NUdf::TDataType>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterFromDateConvert>(registry); RegisterTzDateimeConvert(registry); RegisterDatetimeRescale(registry); RegisterToDateConvert(registry); RegisterToBigDateConvert(registry); RegisterBigDateRescale(registry); RegisterNarrowToBigDateCasts(registry); RegisterBigDateToNarrowCasts(registry); RegisterDecimalConvert(registry); RegisterJsonDocumentConvert(registry); } } // namespace NMiniKQL } // namespace NKikimr