mkql_hasitems.cpp 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #include "mkql_hasitems.h"
  2. #include <yql/essentials/minikql/computation/mkql_computation_node_codegen.h> // Y_IGNORE
  3. #include <yql/essentials/minikql/mkql_node_cast.h>
  4. #include <yql/essentials/minikql/mkql_node_builder.h>
  5. namespace NKikimr {
  6. namespace NMiniKQL {
  7. namespace {
  8. template <bool IsDict, bool IsOptional>
  9. class THasItemsWrapper : public TMutableCodegeneratorNode<THasItemsWrapper<IsDict, IsOptional>> {
  10. typedef TMutableCodegeneratorNode<THasItemsWrapper<IsDict, IsOptional>> TBaseComputation;
  11. public:
  12. THasItemsWrapper(TComputationMutables& mutables, IComputationNode* collection)
  13. : TBaseComputation(mutables, EValueRepresentation::Embedded)
  14. , Collection(collection)
  15. {}
  16. NUdf::TUnboxedValuePod DoCalculate(TComputationContext& compCtx) const {
  17. const auto& collection = Collection->GetValue(compCtx);
  18. if (IsOptional && !collection) {
  19. return NUdf::TUnboxedValuePod();
  20. }
  21. const bool hasItems = IsDict ? collection.HasDictItems() : collection.HasListItems();
  22. return NUdf::TUnboxedValuePod(hasItems);
  23. }
  24. #ifndef MKQL_DISABLE_CODEGEN
  25. Value* DoGenerateGetValue(const TCodegenContext& ctx, BasicBlock*& block) const {
  26. auto& context = ctx.Codegen.GetContext();
  27. const auto collection = GetNodeValue(Collection, ctx, block);
  28. if constexpr (IsOptional) {
  29. const auto good = BasicBlock::Create(context, "good", ctx.Func);
  30. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  31. const auto result = PHINode::Create(collection->getType(), 2U, "result", done);
  32. result->addIncoming(collection, block);
  33. BranchInst::Create(done, good, IsEmpty(collection, block, context), block);
  34. block = good;
  35. const auto has = CallBoxedValueVirtualMethod<IsDict ? NUdf::TBoxedValueAccessor::EMethod::HasDictItems : NUdf::TBoxedValueAccessor::EMethod::HasListItems>(Type::getInt1Ty(context), collection, ctx.Codegen, block);
  36. if (Collection->IsTemporaryValue())
  37. CleanupBoxed(collection, ctx, block);
  38. result->addIncoming(MakeBoolean(has, context, block), block);
  39. BranchInst::Create(done, block);
  40. block = done;
  41. return result;
  42. } else {
  43. const auto has = CallBoxedValueVirtualMethod<IsDict ? NUdf::TBoxedValueAccessor::EMethod::HasDictItems : NUdf::TBoxedValueAccessor::EMethod::HasListItems>(Type::getInt1Ty(context), collection, ctx.Codegen, block);
  44. if (Collection->IsTemporaryValue())
  45. CleanupBoxed(collection, ctx, block);
  46. return MakeBoolean(has, context, block);
  47. }
  48. }
  49. #endif
  50. private:
  51. void RegisterDependencies() const final {
  52. this->DependsOn(Collection);
  53. }
  54. IComputationNode* const Collection;
  55. };
  56. }
  57. IComputationNode* WrapHasItems(TCallable& callable, const TComputationNodeFactoryContext& ctx) {
  58. MKQL_ENSURE(callable.GetInputsCount() == 1, "Expected 1 arg");
  59. bool isOptional;
  60. const auto type = UnpackOptional(callable.GetInput(0).GetStaticType(), isOptional);
  61. if (type->IsDict()) {
  62. if (isOptional)
  63. return new THasItemsWrapper<true, true>(ctx.Mutables, LocateNode(ctx.NodeLocator, callable, 0));
  64. else
  65. return new THasItemsWrapper<true, false>(ctx.Mutables, LocateNode(ctx.NodeLocator, callable, 0));
  66. } else {
  67. if (isOptional)
  68. return new THasItemsWrapper<false, true>(ctx.Mutables, LocateNode(ctx.NodeLocator, callable, 0));
  69. else
  70. return new THasItemsWrapper<false, false>(ctx.Mutables, LocateNode(ctx.NodeLocator, callable, 0));
  71. }
  72. THROW yexception() << "Expected list or dict.";
  73. }
  74. }
  75. }