aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/minikql/invoke_builtins/mkql_builtins_find.cpp
blob: b085f6b93fc7f2f1d50940d2dee4bc9c3ea1dc9a (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
67
68
69
70
71
72
73
74
75
76
77
78
#include "mkql_builtins_impl.h"  // Y_IGNORE

namespace NKikimr {
namespace NMiniKQL {

namespace {

template<bool Reverse>
NUdf::TUnboxedValuePod Find(const NUdf::TUnboxedValuePod haystack, const NUdf::TUnboxedValuePod needle, std::string_view::size_type pos) {
    const std::string_view& one(haystack.AsStringRef());
    const std::string_view& two(needle.AsStringRef());
    const auto f = Reverse ? one.rfind(two, pos): one.find(two, pos);
    return std::string_view::npos == f ? NUdf::TUnboxedValuePod() : NUdf::TUnboxedValuePod(ui32(f));
}

template <bool PosOptional, bool Reverse>
struct TFind {
    static constexpr std::string_view::size_type DefaultPos = Reverse ? std::string_view::npos : 0;

    static NUdf::TUnboxedValuePod Execute(NUdf::TUnboxedValuePod string, NUdf::TUnboxedValuePod sub, NUdf::TUnboxedValuePod pos)
    {
        return Find<Reverse>(string, sub, PosOptional && !pos ? DefaultPos : std::string_view::size_type(pos.Get<ui32>()));
    }

#ifndef MKQL_DISABLE_CODEGEN
    static Value* Generate(Value* string, Value* sub, Value* p, const TCodegenContext& ctx, BasicBlock*& block)
    {
        auto& context = ctx.Codegen.GetContext();
        const auto doFunc = ConstantInt::get(Type::getInt64Ty(context), GetMethodPtr(Find<Reverse>));
        const auto pos = PosOptional ?
            SelectInst::Create(
                IsEmpty(p, block),
                ConstantInt::get(GetTypeFor<std::string_view::size_type>(context), DefaultPos),
                StaticCast<ui32, std::string_view::size_type>(GetterFor<ui32>(p, context, block), context, block),
            "pos", block):
            StaticCast<ui32, std::string_view::size_type>(GetterFor<ui32>(p, context, block), context, block);
        if (NYql::NCodegen::ETarget::Windows != ctx.Codegen.GetEffectiveTarget()) {
            const auto funType = FunctionType::get(string->getType(), {string->getType(), sub->getType(), pos->getType()}, false);
            const auto funcPtr = CastInst::Create(Instruction::IntToPtr, doFunc, PointerType::getUnqual(funType), "func", block);
            const auto result = CallInst::Create(funType, funcPtr, {string, sub, pos}, "find", 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(), pos->getType()}, false);
            const auto funcPtr = CastInst::Create(Instruction::IntToPtr, doFunc, PointerType::getUnqual(funType), "func", block);
            CallInst::Create(funType, funcPtr, {ptrResult, ptrArg, ptrSub, pos}, "", block);
            const auto result = new LoadInst(string->getType(), ptrResult, "find", block);
            return result;
        }
    }
#endif
};

template <typename TInput, bool Reverse>
void RegisterFindOpt(IBuiltinFunctionRegistry& registry, const char* name) {
    RegisterFunctionImpl<TFind<false, Reverse>, TTernaryArgs<NUdf::TDataType<ui32>, TInput, TInput, NUdf::TDataType<ui32>, false, false, false, true>, TTernaryWrap<false>>(registry, name);
    RegisterFunctionImpl<TFind<false, Reverse>, TTernaryArgs<NUdf::TDataType<ui32>, TInput, TInput, NUdf::TDataType<ui32>, true, false, false, true>, TTernaryWrap<true>>(registry, name);

    RegisterFunctionImpl<TFind<true, Reverse>, TTernaryArgs<NUdf::TDataType<ui32>, TInput, TInput, NUdf::TDataType<ui32>, false, false, true, true>, TTernaryWrap<false>>(registry, name);
    RegisterFunctionImpl<TFind<true, Reverse>, TTernaryArgs<NUdf::TDataType<ui32>, TInput, TInput, NUdf::TDataType<ui32>, true, false, true, true>, TTernaryWrap<true>>(registry, name);
}

}

void RegisterFind(IBuiltinFunctionRegistry& registry) {
    RegisterFindOpt<NUdf::TDataType<char*>, false>(registry, "Find");
    RegisterFindOpt<NUdf::TDataType<NUdf::TUtf8>, false>(registry, "Find");

    RegisterFindOpt<NUdf::TDataType<char*>, true>(registry, "RFind");
    RegisterFindOpt<NUdf::TDataType<NUdf::TUtf8>, true>(registry, "RFind");
}

} // namespace NMiniKQL
} // namespace NKikimr