aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/minikql/invoke_builtins/mkql_builtins_with.cpp
blob: 723bff5cab66c0247febab58c7fbb1e887410872 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include "mkql_builtins_compare.h"

namespace NKikimr {
namespace NMiniKQL {

namespace {

template<bool Reverse>
NUdf::TUnboxedValuePod StringWith(const NUdf::TUnboxedValuePod full, const NUdf::TUnboxedValuePod part) {
    const std::string_view one = full.AsStringRef();
    const std::string_view two = part.AsStringRef();
    return NUdf::TUnboxedValuePod(Reverse ? one.ends_with(two) : one.starts_with(two));
}

NUdf::TUnboxedValuePod StringContains(const NUdf::TUnboxedValuePod full, const NUdf::TUnboxedValuePod part) {
    const std::string_view one = full.AsStringRef();
    const std::string_view two = part.AsStringRef();
    return NUdf::TUnboxedValuePod(one.contains(two));
}

template <NUdf::TUnboxedValuePod (*StringFunc)(const NUdf::TUnboxedValuePod full, const NUdf::TUnboxedValuePod part)>
struct TStringWith {
    static NUdf::TUnboxedValuePod Execute(NUdf::TUnboxedValuePod string, NUdf::TUnboxedValuePod sub)
    {
        return StringFunc(string, sub);
    }
#ifndef MKQL_DISABLE_CODEGEN
    static Value* Generate(Value* string, Value* sub, const TCodegenContext& ctx, BasicBlock*& block)
    {
        auto& context = ctx.Codegen.GetContext();
        const auto doFunc = ConstantInt::get(Type::getInt64Ty(context), GetMethodPtr(StringFunc));
        if (NYql::NCodegen::ETarget::Windows != ctx.Codegen.GetEffectiveTarget()) {
            const auto funType = FunctionType::get(string->getType(), {string->getType(), sub->getType()}, false);
            const auto funcPtr = CastInst::Create(Instruction::IntToPtr, doFunc, PointerType::getUnqual(funType), "func", block);
            const auto result = CallInst::Create(funType, funcPtr, {string, sub}, "has", block);
            return result;
        } else {
            const auto ptrArg = new AllocaInst(string->getType(), 0U, "arg", block);
            const auto ptrSub = new AllocaInst(sub->getType(), 0U, "sub", block);
            const auto ptrResult = new AllocaInst(string->getType(), 0U, "result", block);
            new StoreInst(string, ptrArg, block);
            new StoreInst(sub, ptrSub, block);
            const auto funType = FunctionType::get(Type::getVoidTy(context), {ptrResult->getType(), ptrArg->getType(), ptrSub->getType()}, false);
            const auto funcPtr = CastInst::Create(Instruction::IntToPtr, doFunc, PointerType::getUnqual(funType), "func", block);
            CallInst::Create(funType, funcPtr, {ptrResult, ptrArg, ptrSub}, "", block);
            const auto result = new LoadInst(string->getType(), ptrResult, "has", block);
            return result;
        }
    }
#endif
};

template<NUdf::EDataSlot> using TStartsWith = TStringWith<&StringWith<false>>;
template<NUdf::EDataSlot> using TEndsWith = TStringWith<&StringWith<true>>;
template<NUdf::EDataSlot> using TContains = TStringWith<&StringContains>;

}

void RegisterWith(IBuiltinFunctionRegistry& registry) {
    RegisterCompareStrings<TStartsWith, TCompareArgsOpt, false>(registry, "StartsWith");
    RegisterCompareStrings<TEndsWith, TCompareArgsOpt, false>(registry, "EndsWith");
    RegisterCompareStrings<TContains, TCompareArgsOpt, false>(registry, "StringContains");
}

} // namespace NMiniKQL
} // namespace NKikimr