#include "mkql_builtins_decimal.h" // Y_IGNORE #include namespace NKikimr { namespace NMiniKQL { namespace { template struct TNanvl { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& left, const NUdf::TUnboxedValuePod& right) { const auto lv = left.Get(); if (!std::isnan(lv)) { return std::is_same() ? left : NUdf::TUnboxedValuePod(static_cast(lv)); } if (std::is_same()) { return right; } else { if (IsRightOptional && !right) { return NUdf::TUnboxedValuePod(); } const auto rv = right.Get(); return NUdf::TUnboxedValuePod(static_cast(rv)); } } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); auto& module = ctx.Codegen.GetModule(); const auto val = GetterFor(left, context, block); const auto fnType = FunctionType::get(Type::getInt1Ty(context), {val->getType()}, false); const auto name = std::is_same() ? "MyFloatIsNan" : "MyDoubleIsNan"; ctx.Codegen.AddGlobalMapping(name, reinterpret_cast(static_cast(&std::isnan))); const auto func = module.getOrInsertFunction(name, fnType).getCallee(); const auto isnan = CallInst::Create(fnType, func, {val}, "isnan", block); const auto lout = std::is_same() ? left : SetterFor(StaticCast(val, context, block), context, block); const auto rout = std::is_same() ? right : SetterFor(StaticCast(GetterFor(right, context, block), context, block), context, block); if (IsRightOptional && !std::is_same()) { const auto nanvl = SelectInst::Create(isnan, rout, lout, "nanvl", block); return nanvl; } else { const auto nanvl = SelectInst::Create(isnan, rout, lout, "nanvl", block); return nanvl; } } #endif }; struct TDecimalNanvl { static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& left, const NUdf::TUnboxedValuePod& right) { return NYql::NDecimal::IsComparable(left.GetInt128()) ? left : right; } #ifndef MKQL_DISABLE_CODEGEN static Value* Generate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block) { auto& context = ctx.Codegen.GetContext(); const auto good = NDecimal::GenIsComparable(GetterForInt128(left, block), context, block); const auto sel = SelectInst::Create(good, left, right, "sel", block); return sel; } #endif }; template < typename TInput1, typename TInput2, typename TOutput, template class TFunc, template class TArgs > void RegisterBinaryNavlLeftOpt(IBuiltinFunctionRegistry& registry, const char* name) { RegisterFunctionImpl, TArgs, TBinaryWrap>(registry, name); RegisterFunctionImpl, TArgs, TBinaryWrap>(registry, name); RegisterFunctionImpl, TArgs, TBinaryWrap>(registry, name); RegisterFunctionImpl, TArgs, TBinaryWrap>(registry, name); } void RegisterBinaryNavlFunction(IBuiltinFunctionRegistry& registry, const char* name) { RegisterBinaryNavlLeftOpt, NUdf::TDataType, NUdf::TDataType, TNanvl, TBinaryArgsOpt>(registry, name); RegisterBinaryNavlLeftOpt, NUdf::TDataType, NUdf::TDataType, TNanvl, TBinaryArgsOpt>(registry, name); RegisterBinaryNavlLeftOpt, NUdf::TDataType, NUdf::TDataType, TNanvl, TBinaryArgsOpt>(registry, name); RegisterBinaryNavlLeftOpt, NUdf::TDataType, NUdf::TDataType, TNanvl, TBinaryArgsOpt>(registry, name); } void RegisterBinaryNavlDecimal(IBuiltinFunctionRegistry& registry, const char* name) { RegisterFunctionImpl, NUdf::TDataType, NUdf::TDataType, false, false>, TBinaryWrap>(registry, name); RegisterFunctionImpl, NUdf::TDataType, NUdf::TDataType, false, true>, TBinaryWrap>(registry, name); RegisterFunctionImpl, NUdf::TDataType, NUdf::TDataType, true, false>, TBinaryWrap>(registry, name); RegisterFunctionImpl, NUdf::TDataType, NUdf::TDataType, true, true>, TBinaryWrap>(registry, name); } } void RegisterNanvl(IBuiltinFunctionRegistry& registry) { RegisterBinaryNavlFunction(registry, "Nanvl"); RegisterBinaryNavlDecimal(registry, "Nanvl"); } } // namespace NMiniKQL } // namespace NKikimr