top_udf.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. #include <yql/essentials/public/udf/udf_helpers.h>
  2. #include <yql/essentials/public/udf/udf_type_ops.h>
  3. #include <library/cpp/containers/top_keeper/top_keeper.h>
  4. #include <util/generic/set.h>
  5. #include <algorithm>
  6. #include <iterator>
  7. using namespace NKikimr;
  8. using namespace NUdf;
  9. namespace {
  10. using TUnboxedValuePair = std::pair<TUnboxedValue, TUnboxedValue>;
  11. template <EDataSlot Slot, bool IsTop>
  12. struct TDataCompare {
  13. bool operator()(const TUnboxedValue& left, const TUnboxedValue& right) const {
  14. if (IsTop) {
  15. return CompareValues<Slot>(left, right) > 0;
  16. } else {
  17. return CompareValues<Slot>(left, right) < 0;
  18. }
  19. }
  20. };
  21. template <EDataSlot Slot, bool IsTop>
  22. struct TDataPairCompare {
  23. bool operator()(const TUnboxedValuePair& left, const TUnboxedValuePair& right) const {
  24. if (IsTop) {
  25. return CompareValues<Slot>(left.first, right.first) > 0;
  26. } else {
  27. return CompareValues<Slot>(left.first, right.first) < 0;
  28. }
  29. }
  30. };
  31. template <bool IsTop>
  32. struct TGenericCompare {
  33. ICompare::TPtr Compare;
  34. bool operator()(const TUnboxedValue& left, const TUnboxedValue& right) const {
  35. if (IsTop) {
  36. return Compare->Less(right, left);
  37. } else {
  38. return Compare->Less(left, right);
  39. }
  40. }
  41. };
  42. template <bool IsTop>
  43. struct TGenericPairCompare {
  44. ICompare::TPtr Compare;
  45. bool operator()(const TUnboxedValuePair& left, const TUnboxedValuePair& right) const {
  46. if (IsTop) {
  47. return Compare->Less(right.first, left.first);
  48. } else {
  49. return Compare->Less(left.first, right.first);
  50. }
  51. }
  52. };
  53. template <typename TValue, typename TCompare, typename TAllocator>
  54. class TTopKeeperContainer {
  55. TTopKeeper<TValue, TCompare, true, TAllocator> Keeper;
  56. using TOrderedSet = TMultiSet<TValue, TCompare, TAllocator>;
  57. TMaybe<TOrderedSet> OrderedSet;
  58. size_t MaxSize = 0;
  59. bool Finalized = false;
  60. TCompare Compare;
  61. public:
  62. explicit TTopKeeperContainer(TCompare compare)
  63. : Keeper(0, compare)
  64. , Compare(compare)
  65. {}
  66. TVector<TValue, TAllocator> GetInternal() {
  67. if (OrderedSet) {
  68. TVector<TValue, TAllocator> result;
  69. std::copy(OrderedSet->begin(), OrderedSet->end(), std::back_inserter(result));
  70. return result;
  71. }
  72. Finalized = true;
  73. return Keeper.GetInternal();
  74. }
  75. void Insert(const TValue& value) {
  76. if (MaxSize == 0) {
  77. return;
  78. }
  79. if (Finalized && !OrderedSet) {
  80. const auto& items = Keeper.Extract();
  81. OrderedSet = TOrderedSet{items.begin(), items.end(), Compare};
  82. }
  83. if (OrderedSet) {
  84. if (OrderedSet->size() < MaxSize) {
  85. OrderedSet->insert(value);
  86. return;
  87. }
  88. Y_ENSURE(OrderedSet->size() == MaxSize);
  89. Y_ENSURE(!OrderedSet->empty());
  90. auto last = --OrderedSet->end();
  91. if (Compare(value, *last)) {
  92. OrderedSet->erase(last);
  93. OrderedSet->insert(value);
  94. }
  95. return;
  96. }
  97. Keeper.Insert(value);
  98. }
  99. bool IsEmpty() const {
  100. return OrderedSet ? OrderedSet->empty() : Keeper.IsEmpty();
  101. }
  102. size_t GetSize() const {
  103. return OrderedSet ? OrderedSet->size() : Keeper.GetSize();
  104. }
  105. size_t GetMaxSize() const {
  106. return MaxSize;
  107. }
  108. void SetMaxSize(size_t newMaxSize) {
  109. MaxSize = newMaxSize;
  110. if (Finalized && !OrderedSet) {
  111. auto items = Keeper.Extract();
  112. auto begin = items.begin();
  113. auto end = begin + Min(MaxSize, items.size());
  114. OrderedSet = TOrderedSet{begin, end, Compare};
  115. }
  116. if (OrderedSet) {
  117. while (OrderedSet->size() > MaxSize) {
  118. auto last = --OrderedSet->end();
  119. OrderedSet->erase(last);
  120. }
  121. return;
  122. }
  123. Keeper.SetMaxSize(MaxSize);
  124. }
  125. };
  126. template <typename TCompare>
  127. class TTopKeeperWrapperBase {
  128. protected:
  129. TTopKeeperContainer<TUnboxedValue, TCompare, TUnboxedValue::TAllocator> Keeper;
  130. protected:
  131. explicit TTopKeeperWrapperBase(TCompare compare)
  132. : Keeper(compare)
  133. {}
  134. void Init(const TUnboxedValuePod& value, ui32 maxSize) {
  135. Keeper.SetMaxSize(maxSize);
  136. AddValue(value);
  137. }
  138. void Merge(TTopKeeperWrapperBase& left, TTopKeeperWrapperBase& right) {
  139. Keeper.SetMaxSize(left.Keeper.GetMaxSize());
  140. for (const auto& item : left.Keeper.GetInternal()) {
  141. AddValue(item);
  142. }
  143. for (const auto& item : right.Keeper.GetInternal()) {
  144. AddValue(item);
  145. }
  146. }
  147. void Deserialize(const TUnboxedValuePod& serialized) {
  148. auto maxSize = serialized.GetElement(0).Get<ui32>();
  149. auto list = serialized.GetElement(1);
  150. Keeper.SetMaxSize(maxSize);
  151. const auto listIter = list.GetListIterator();
  152. for (TUnboxedValue current; listIter.Next(current);) {
  153. AddValue(current);
  154. }
  155. }
  156. public:
  157. void AddValue(const TUnboxedValuePod& value) {
  158. Keeper.Insert(TUnboxedValuePod(value));
  159. }
  160. TUnboxedValue Serialize(const IValueBuilder* builder) {
  161. TUnboxedValue* values = nullptr;
  162. auto list = builder->NewArray(Keeper.GetSize(), values);
  163. for (const auto& item : Keeper.GetInternal()) {
  164. *values++ = item;
  165. }
  166. TUnboxedValue* items = nullptr;
  167. auto result = builder->NewArray(2U, items);
  168. items[0] = TUnboxedValuePod((ui32)Keeper.GetMaxSize());
  169. items[1] = list;
  170. return result;
  171. }
  172. TUnboxedValue GetResult(const IValueBuilder* builder) {
  173. TUnboxedValue* values = nullptr;
  174. auto list = builder->NewArray(Keeper.GetSize(), values);
  175. for (const auto& item : Keeper.GetInternal()) {
  176. *values++ = item;
  177. }
  178. return list;
  179. }
  180. };
  181. template <typename TCompare>
  182. class TTopKeeperPairWrapperBase {
  183. protected:
  184. TTopKeeperContainer<TUnboxedValuePair, TCompare, TStdAllocatorForUdf<TUnboxedValuePair>> Keeper;
  185. protected:
  186. explicit TTopKeeperPairWrapperBase(TCompare compare)
  187. : Keeper(compare)
  188. {}
  189. void Init(const TUnboxedValuePod& key, const TUnboxedValuePod& payload, ui32 maxSize) {
  190. Keeper.SetMaxSize(maxSize);
  191. AddValue(key, payload);
  192. }
  193. void Merge(TTopKeeperPairWrapperBase& left, TTopKeeperPairWrapperBase& right) {
  194. Keeper.SetMaxSize(left.Keeper.GetMaxSize());
  195. for (const auto& item : left.Keeper.GetInternal()) {
  196. AddValue(item.first, item.second);
  197. }
  198. for (const auto& item : right.Keeper.GetInternal()) {
  199. AddValue(item.first, item.second);
  200. }
  201. }
  202. void Deserialize(const TUnboxedValuePod& serialized) {
  203. auto maxSize = serialized.GetElement(0).Get<ui32>();
  204. auto list = serialized.GetElement(1);
  205. Keeper.SetMaxSize(maxSize);
  206. const auto listIter = list.GetListIterator();
  207. for (TUnboxedValue current; listIter.Next(current);) {
  208. AddValue(current.GetElement(0), current.GetElement(1));
  209. }
  210. }
  211. public:
  212. void AddValue(const TUnboxedValuePod& key, const TUnboxedValuePod& payload) {
  213. Keeper.Insert(std::make_pair(TUnboxedValuePod(key), TUnboxedValuePod(payload)));
  214. }
  215. TUnboxedValue Serialize(const IValueBuilder* builder) {
  216. TUnboxedValue* values = nullptr;
  217. auto list = builder->NewArray(Keeper.GetSize(), values);
  218. for (const auto& item : Keeper.GetInternal()) {
  219. TUnboxedValue* items = nullptr;
  220. auto pair = builder->NewArray(2U, items);
  221. items[0] = item.first;
  222. items[1] = item.second;
  223. *values++ = pair;
  224. }
  225. TUnboxedValue* items = nullptr;
  226. auto result = builder->NewArray(2U, items);
  227. items[0] = TUnboxedValuePod((ui32)Keeper.GetMaxSize());
  228. items[1] = list;
  229. return result;
  230. }
  231. TUnboxedValue GetResult(const IValueBuilder* builder) {
  232. TUnboxedValue* values = nullptr;
  233. auto list = builder->NewArray(Keeper.GetSize(), values);
  234. for (const auto& item : Keeper.GetInternal()) {
  235. *values++ = item.second;
  236. }
  237. return list;
  238. }
  239. };
  240. template <EDataSlot Slot, bool HasKey, bool IsTop>
  241. class TTopKeeperDataWrapper;
  242. template <EDataSlot Slot, bool IsTop>
  243. class TTopKeeperDataWrapper<Slot, false, IsTop>
  244. : public TTopKeeperWrapperBase<TDataCompare<Slot, IsTop>>
  245. {
  246. public:
  247. using TBase = TTopKeeperWrapperBase<TDataCompare<Slot, IsTop>>;
  248. TTopKeeperDataWrapper(const TUnboxedValuePod& value, ui32 maxSize)
  249. : TBase(TDataCompare<Slot, IsTop>())
  250. {
  251. TBase::Init(value, maxSize);
  252. }
  253. TTopKeeperDataWrapper(TTopKeeperDataWrapper& left, TTopKeeperDataWrapper& right)
  254. : TBase(TDataCompare<Slot, IsTop>())
  255. {
  256. TBase::Merge(left, right);
  257. }
  258. explicit TTopKeeperDataWrapper(const TUnboxedValuePod& serialized)
  259. : TBase(TDataCompare<Slot, IsTop>())
  260. {
  261. TBase::Deserialize(serialized);
  262. }
  263. };
  264. template <EDataSlot Slot, bool IsTop>
  265. class TTopKeeperDataWrapper<Slot, true, IsTop>
  266. : public TTopKeeperPairWrapperBase<TDataPairCompare<Slot, IsTop>>
  267. {
  268. public:
  269. using TBase = TTopKeeperPairWrapperBase<TDataPairCompare<Slot, IsTop>>;
  270. TTopKeeperDataWrapper(const TUnboxedValuePod& key, const TUnboxedValuePod& payload, ui32 maxSize)
  271. : TBase(TDataPairCompare<Slot, IsTop>())
  272. {
  273. TBase::Init(key, payload, maxSize);
  274. }
  275. TTopKeeperDataWrapper(TTopKeeperDataWrapper& left, TTopKeeperDataWrapper& right)
  276. : TBase(TDataPairCompare<Slot, IsTop>())
  277. {
  278. TBase::Merge(left, right);
  279. }
  280. explicit TTopKeeperDataWrapper(const TUnboxedValuePod& serialized)
  281. : TBase(TDataPairCompare<Slot, IsTop>())
  282. {
  283. TBase::Deserialize(serialized);
  284. }
  285. };
  286. template <bool HasKey, bool IsTop>
  287. class TTopKeeperWrapper;
  288. template <bool IsTop>
  289. class TTopKeeperWrapper<false, IsTop>
  290. : public TTopKeeperWrapperBase<TGenericCompare<IsTop>>
  291. {
  292. public:
  293. using TBase = TTopKeeperWrapperBase<TGenericCompare<IsTop>>;
  294. TTopKeeperWrapper(const TUnboxedValuePod& value, ui32 maxSize, ICompare::TPtr compare)
  295. : TBase(TGenericCompare<IsTop>{compare})
  296. {
  297. TBase::Init(value, maxSize);
  298. }
  299. TTopKeeperWrapper(TTopKeeperWrapper& left, TTopKeeperWrapper& right, ICompare::TPtr compare)
  300. : TBase(TGenericCompare<IsTop>{compare})
  301. {
  302. TBase::Merge(left, right);
  303. }
  304. TTopKeeperWrapper(const TUnboxedValuePod& serialized, ICompare::TPtr compare)
  305. : TBase(TGenericCompare<IsTop>{compare})
  306. {
  307. TBase::Deserialize(serialized);
  308. }
  309. };
  310. template <bool IsTop>
  311. class TTopKeeperWrapper<true, IsTop>
  312. : public TTopKeeperPairWrapperBase<TGenericPairCompare<IsTop>>
  313. {
  314. public:
  315. using TBase = TTopKeeperPairWrapperBase<TGenericPairCompare<IsTop>>;
  316. TTopKeeperWrapper(const TUnboxedValuePod& key, const TUnboxedValuePod& payload, ui32 maxSize, ICompare::TPtr compare)
  317. : TBase(TGenericPairCompare<IsTop>{compare})
  318. {
  319. TBase::Init(key, payload, maxSize);
  320. }
  321. TTopKeeperWrapper(TTopKeeperWrapper& left, TTopKeeperWrapper& right, ICompare::TPtr compare)
  322. : TBase(TGenericPairCompare<IsTop>{compare})
  323. {
  324. TBase::Merge(left, right);
  325. }
  326. TTopKeeperWrapper(const TUnboxedValuePod& serialized, ICompare::TPtr compare)
  327. : TBase(TGenericPairCompare<IsTop>{compare})
  328. {
  329. TBase::Deserialize(serialized);
  330. }
  331. };
  332. template <EDataSlot Slot, bool HasKey, bool IsTop>
  333. class TTopResourceData;
  334. template <EDataSlot Slot, bool HasKey, bool IsTop>
  335. TTopResourceData<Slot, HasKey, IsTop>* GetTopResourceData(const TUnboxedValuePod& arg) {
  336. TTopResourceData<Slot, HasKey, IsTop>::Validate(arg);
  337. return static_cast<TTopResourceData<Slot, HasKey, IsTop>*>(arg.AsBoxed().Get());
  338. }
  339. template <bool HasKey, bool IsTop>
  340. class TTopResource;
  341. template <bool HasKey, bool IsTop>
  342. TTopResource<HasKey, IsTop>* GetTopResource(const TUnboxedValuePod& arg) {
  343. TTopResource<HasKey, IsTop>::Validate(arg);
  344. return static_cast<TTopResource<HasKey, IsTop>*>(arg.AsBoxed().Get());
  345. }
  346. template <EDataSlot Slot, bool HasKey, bool IsTop>
  347. class TTopCreateData : public TBoxedValue {
  348. private:
  349. template <bool HasKey_ = HasKey, typename std::enable_if_t<!HasKey_>* = nullptr>
  350. TUnboxedValue RunImpl(const TUnboxedValuePod* args) const {
  351. return TUnboxedValuePod(
  352. new TTopResourceData<Slot, HasKey, IsTop>(args[0], args[1].Get<ui32>()));
  353. }
  354. template <bool HasKey_ = HasKey, typename std::enable_if_t<HasKey_>* = nullptr>
  355. TUnboxedValue RunImpl(const TUnboxedValuePod* args) const {
  356. return TUnboxedValuePod(
  357. new TTopResourceData<Slot, HasKey, IsTop>(args[0], args[1], args[2].Get<ui32>()));
  358. }
  359. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const override {
  360. return RunImpl(args);
  361. }
  362. };
  363. template <bool HasKey, bool IsTop>
  364. class TTopCreate : public TBoxedValue {
  365. private:
  366. template <bool HasKey_ = HasKey, typename std::enable_if_t<!HasKey_>* = nullptr>
  367. TUnboxedValue RunImpl(const TUnboxedValuePod* args) const {
  368. return TUnboxedValuePod(
  369. new TTopResource<HasKey, IsTop>(args[0], args[1].Get<ui32>(), Compare_));
  370. }
  371. template <bool HasKey_ = HasKey, typename std::enable_if_t<HasKey_>* = nullptr>
  372. TUnboxedValue RunImpl(const TUnboxedValuePod* args) const {
  373. return TUnboxedValuePod(
  374. new TTopResource<HasKey, IsTop>(args[0], args[1], args[2].Get<ui32>(), Compare_));
  375. }
  376. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const override {
  377. return RunImpl(args);
  378. }
  379. public:
  380. explicit TTopCreate(ICompare::TPtr compare)
  381. : Compare_(compare)
  382. {}
  383. private:
  384. ICompare::TPtr Compare_;
  385. };
  386. template <EDataSlot Slot, bool HasKey, bool IsTop>
  387. class TTopAddValueData : public TBoxedValue {
  388. private:
  389. template <bool HasKey_ = HasKey, typename std::enable_if_t<!HasKey_>* = nullptr>
  390. TUnboxedValue RunImpl(const TUnboxedValuePod* args) const {
  391. auto resource = GetTopResourceData<Slot, HasKey, IsTop>(args[0]);
  392. resource->Get()->AddValue(args[1]);
  393. return TUnboxedValuePod(resource);
  394. }
  395. template <bool HasKey_ = HasKey, typename std::enable_if_t<HasKey_>* = nullptr>
  396. TUnboxedValue RunImpl(const TUnboxedValuePod* args) const {
  397. auto resource = GetTopResourceData<Slot, HasKey, IsTop>(args[0]);
  398. resource->Get()->AddValue(args[1], args[2]);
  399. return TUnboxedValuePod(resource);
  400. }
  401. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const override {
  402. return RunImpl(args);
  403. }
  404. };
  405. template <bool HasKey, bool IsTop>
  406. class TTopAddValue : public TBoxedValue {
  407. private:
  408. template <bool HasKey_ = HasKey, typename std::enable_if_t<!HasKey_>* = nullptr>
  409. TUnboxedValue RunImpl(const TUnboxedValuePod* args) const {
  410. auto resource = GetTopResource<HasKey, IsTop>(args[0]);
  411. resource->Get()->AddValue(args[1]);
  412. return TUnboxedValuePod(resource);
  413. }
  414. template <bool HasKey_ = HasKey, typename std::enable_if_t<HasKey_>* = nullptr>
  415. TUnboxedValue RunImpl(const TUnboxedValuePod* args) const {
  416. auto resource = GetTopResource<HasKey, IsTop>(args[0]);
  417. resource->Get()->AddValue(args[1], args[2]);
  418. return TUnboxedValuePod(resource);
  419. }
  420. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const override {
  421. return RunImpl(args);
  422. }
  423. public:
  424. explicit TTopAddValue(ICompare::TPtr)
  425. {}
  426. };
  427. template <EDataSlot Slot, bool HasKey, bool IsTop>
  428. class TTopSerializeData : public TBoxedValue {
  429. private:
  430. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const override {
  431. auto resource = GetTopResourceData<Slot, HasKey, IsTop>(args[0]);
  432. return resource->Get()->Serialize(valueBuilder);
  433. }
  434. };
  435. template <bool HasKey, bool IsTop>
  436. class TTopSerialize : public TBoxedValue {
  437. private:
  438. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const override {
  439. auto resource = GetTopResource<HasKey, IsTop>(args[0]);
  440. return resource->Get()->Serialize(valueBuilder);
  441. }
  442. public:
  443. explicit TTopSerialize(ICompare::TPtr)
  444. {}
  445. };
  446. template <EDataSlot Slot, bool HasKey, bool IsTop>
  447. class TTopDeserializeData : public TBoxedValue {
  448. private:
  449. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const override {
  450. return TUnboxedValuePod(new TTopResourceData<Slot, HasKey, IsTop>(args[0]));
  451. }
  452. };
  453. template <bool HasKey, bool IsTop>
  454. class TTopDeserialize : public TBoxedValue {
  455. private:
  456. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const override {
  457. return TUnboxedValuePod(new TTopResource<HasKey, IsTop>(args[0], Compare_));
  458. }
  459. public:
  460. explicit TTopDeserialize(ICompare::TPtr compare)
  461. : Compare_(compare)
  462. {}
  463. private:
  464. ICompare::TPtr Compare_;
  465. };
  466. template <EDataSlot Slot, bool HasKey, bool IsTop>
  467. class TTopMergeData : public TBoxedValue {
  468. private:
  469. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const override {
  470. auto left = GetTopResourceData<Slot, HasKey, IsTop>(args[0]);
  471. auto right = GetTopResourceData<Slot, HasKey, IsTop>(args[1]);
  472. return TUnboxedValuePod(new TTopResourceData<Slot, HasKey, IsTop>(*left->Get(), *right->Get()));
  473. }
  474. };
  475. template <bool HasKey, bool IsTop>
  476. class TTopMerge : public TBoxedValue {
  477. private:
  478. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const override {
  479. auto left = GetTopResource<HasKey, IsTop>(args[0]);
  480. auto right = GetTopResource<HasKey, IsTop>(args[1]);
  481. return TUnboxedValuePod(new TTopResource<HasKey, IsTop>(*left->Get(), *right->Get(), Compare_));
  482. }
  483. public:
  484. explicit TTopMerge(ICompare::TPtr compare)
  485. : Compare_(compare)
  486. {}
  487. private:
  488. ICompare::TPtr Compare_;
  489. };
  490. template <EDataSlot Slot, bool HasKey, bool IsTop>
  491. class TTopGetResultData : public TBoxedValue {
  492. private:
  493. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const override {
  494. auto resource = GetTopResourceData<Slot, HasKey, IsTop>(args[0]);
  495. return resource->Get()->GetResult(valueBuilder);
  496. }
  497. };
  498. template <bool HasKey, bool IsTop>
  499. class TTopGetResult : public TBoxedValue {
  500. private:
  501. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const override {
  502. auto resource = GetTopResource<HasKey, IsTop>(args[0]);
  503. return resource->Get()->GetResult(valueBuilder);
  504. }
  505. public:
  506. explicit TTopGetResult(ICompare::TPtr)
  507. {}
  508. };
  509. #define RESOURCE(slot, hasKey, isTop) \
  510. extern const char TopResourceName_##slot##_##hasKey##_##isTop[] = \
  511. "Top.TopResource."#slot"."#hasKey"."#isTop; \
  512. template <> \
  513. class TTopResourceData<EDataSlot::slot, hasKey, isTop>: \
  514. public TBoxedResource< \
  515. TTopKeeperDataWrapper<EDataSlot::slot, hasKey, isTop>, \
  516. TopResourceName_##slot##_##hasKey##_##isTop> \
  517. { \
  518. public: \
  519. template <typename... Args> \
  520. inline TTopResourceData(Args&&... args) \
  521. : TBoxedResource(std::forward<Args>(args)...) \
  522. {} \
  523. };
  524. #define RESOURCE_00(slot, ...) RESOURCE(slot, false, false)
  525. #define RESOURCE_01(slot, ...) RESOURCE(slot, false, true)
  526. #define RESOURCE_10(slot, ...) RESOURCE(slot, true, false)
  527. #define RESOURCE_11(slot, ...) RESOURCE(slot, true, true)
  528. UDF_TYPE_ID_MAP(RESOURCE_00)
  529. UDF_TYPE_ID_MAP(RESOURCE_01)
  530. UDF_TYPE_ID_MAP(RESOURCE_10)
  531. UDF_TYPE_ID_MAP(RESOURCE_11)
  532. #define MAKE_IMPL(operation, slot, hasKey, isTop) \
  533. case EDataSlot::slot: \
  534. builder.Implementation(new operation<EDataSlot::slot, hasKey, isTop>); \
  535. break;
  536. #define CREATE_00(slot, ...) MAKE_IMPL(TTopCreateData, slot, false, false)
  537. #define CREATE_01(slot, ...) MAKE_IMPL(TTopCreateData, slot, false, true)
  538. #define CREATE_10(slot, ...) MAKE_IMPL(TTopCreateData, slot, true, false)
  539. #define CREATE_11(slot, ...) MAKE_IMPL(TTopCreateData, slot, true, true)
  540. #define ADD_VALUE_00(slot, ...) MAKE_IMPL(TTopAddValueData, slot, false, false)
  541. #define ADD_VALUE_01(slot, ...) MAKE_IMPL(TTopAddValueData, slot, false, true)
  542. #define ADD_VALUE_10(slot, ...) MAKE_IMPL(TTopAddValueData, slot, true, false)
  543. #define ADD_VALUE_11(slot, ...) MAKE_IMPL(TTopAddValueData, slot, true, true)
  544. #define MERGE_00(slot, ...) MAKE_IMPL(TTopMergeData, slot, false, false)
  545. #define MERGE_01(slot, ...) MAKE_IMPL(TTopMergeData, slot, false, true)
  546. #define MERGE_10(slot, ...) MAKE_IMPL(TTopMergeData, slot, true, false)
  547. #define MERGE_11(slot, ...) MAKE_IMPL(TTopMergeData, slot, true, true)
  548. #define SERIALIZE_00(slot, ...) MAKE_IMPL(TTopSerializeData, slot, false, false)
  549. #define SERIALIZE_01(slot, ...) MAKE_IMPL(TTopSerializeData, slot, false, true)
  550. #define SERIALIZE_10(slot, ...) MAKE_IMPL(TTopSerializeData, slot, true, false)
  551. #define SERIALIZE_11(slot, ...) MAKE_IMPL(TTopSerializeData, slot, true, true)
  552. #define DESERIALIZE_00(slot, ...) MAKE_IMPL(TTopDeserializeData, slot, false, false)
  553. #define DESERIALIZE_01(slot, ...) MAKE_IMPL(TTopDeserializeData, slot, false, true)
  554. #define DESERIALIZE_10(slot, ...) MAKE_IMPL(TTopDeserializeData, slot, true, false)
  555. #define DESERIALIZE_11(slot, ...) MAKE_IMPL(TTopDeserializeData, slot, true, true)
  556. #define GET_RESULT_00(slot, ...) MAKE_IMPL(TTopGetResultData, slot, false, false)
  557. #define GET_RESULT_01(slot, ...) MAKE_IMPL(TTopGetResultData, slot, false, true)
  558. #define GET_RESULT_10(slot, ...) MAKE_IMPL(TTopGetResultData, slot, true, false)
  559. #define GET_RESULT_11(slot, ...) MAKE_IMPL(TTopGetResultData, slot, true, true)
  560. #define MAKE_TYPE(slot, hasKey, isTop) \
  561. case EDataSlot::slot: \
  562. topType = builder.Resource(TopResourceName_##slot##_##hasKey##_##isTop); \
  563. break;
  564. #define TYPE_00(slot, ...) MAKE_TYPE(slot, false, false)
  565. #define TYPE_01(slot, ...) MAKE_TYPE(slot, false, true)
  566. #define TYPE_10(slot, ...) MAKE_TYPE(slot, true, false)
  567. #define TYPE_11(slot, ...) MAKE_TYPE(slot, true, true)
  568. #define PARAMETRIZE(action) \
  569. if (hasKey) { \
  570. if (isTop) { \
  571. switch (*slot) { \
  572. UDF_TYPE_ID_MAP(action##_11) \
  573. } \
  574. } else { \
  575. switch (*slot) { \
  576. UDF_TYPE_ID_MAP(action##_10) \
  577. } \
  578. } \
  579. } else { \
  580. if (isTop) { \
  581. switch (*slot) { \
  582. UDF_TYPE_ID_MAP(action##_01) \
  583. } \
  584. } else { \
  585. switch (*slot) { \
  586. UDF_TYPE_ID_MAP(action##_00) \
  587. } \
  588. } \
  589. }
  590. #define RESOURCE_GENERIC(hasKey, isTop) \
  591. extern const char TopResourceName_Generic_##hasKey##_##isTop[] = \
  592. "Top.TopResource.Generic."#hasKey"."#isTop; \
  593. template <> \
  594. class TTopResource<hasKey, isTop>: \
  595. public TBoxedResource< \
  596. TTopKeeperWrapper<hasKey, isTop>, \
  597. TopResourceName_Generic_##hasKey##_##isTop> \
  598. { \
  599. public: \
  600. template <typename... Args> \
  601. inline TTopResource(Args&&... args) \
  602. : TBoxedResource(std::forward<Args>(args)...) \
  603. {} \
  604. };
  605. RESOURCE_GENERIC(false, false)
  606. RESOURCE_GENERIC(false, true)
  607. RESOURCE_GENERIC(true, false)
  608. RESOURCE_GENERIC(true, true)
  609. #define MAKE_IMPL_GENERIC(operation, hasKey, isTop) \
  610. builder.Implementation(new operation<hasKey, isTop>(compare));
  611. #define CREATE_GENERIC(hasKey, isTop) MAKE_IMPL_GENERIC(TTopCreate, hasKey, isTop)
  612. #define ADD_VALUE_GENERIC(hasKey, isTop) MAKE_IMPL_GENERIC(TTopAddValue, hasKey, isTop)
  613. #define MERGE_GENERIC(hasKey, isTop) MAKE_IMPL_GENERIC(TTopMerge, hasKey, isTop)
  614. #define SERIALIZE_GENERIC(hasKey, isTop) MAKE_IMPL_GENERIC(TTopSerialize, hasKey, isTop)
  615. #define DESERIALIZE_GENERIC(hasKey, isTop) MAKE_IMPL_GENERIC(TTopDeserialize, hasKey, isTop)
  616. #define GET_RESULT_GENERIC(hasKey, isTop) MAKE_IMPL_GENERIC(TTopGetResult, hasKey, isTop)
  617. #define TYPE_GENERIC(hasKey, isTop) \
  618. topType = builder.Resource(TopResourceName_Generic_##hasKey##_##isTop);
  619. #define PARAMETRIZE_GENERIC(action) \
  620. if (hasKey) { \
  621. if (isTop) { \
  622. action(true, true) \
  623. } else { \
  624. action(true, false) \
  625. } \
  626. } else { \
  627. if (isTop) { \
  628. action(false, true) \
  629. } else { \
  630. action(false, false) \
  631. } \
  632. }
  633. static const auto CreateName = TStringRef::Of("Create");
  634. static const auto AddValueName = TStringRef::Of("AddValue");
  635. static const auto SerializeName = TStringRef::Of("Serialize");
  636. static const auto DeserializeName = TStringRef::Of("Deserialize");
  637. static const auto MergeName = TStringRef::Of("Merge");
  638. static const auto GetResultName = TStringRef::Of("GetResult");
  639. class TTopModule : public IUdfModule {
  640. public:
  641. TStringRef Name() const {
  642. return TStringRef::Of("Top");
  643. }
  644. void CleanupOnTerminate() const final {
  645. }
  646. void GetAllFunctions(IFunctionsSink& sink) const final {
  647. sink.Add(CreateName)->SetTypeAwareness();
  648. sink.Add(AddValueName)->SetTypeAwareness();
  649. sink.Add(SerializeName)->SetTypeAwareness();
  650. sink.Add(DeserializeName)->SetTypeAwareness();
  651. sink.Add(MergeName)->SetTypeAwareness();
  652. sink.Add(GetResultName)->SetTypeAwareness();
  653. }
  654. void BuildFunctionTypeInfo(
  655. const TStringRef& name,
  656. TType* userType,
  657. const TStringRef& typeConfig,
  658. ui32 flags,
  659. IFunctionTypeInfoBuilder& builder) const final
  660. {
  661. Y_UNUSED(typeConfig);
  662. try {
  663. bool typesOnly = (flags & TFlags::TypesOnly);
  664. builder.UserType(userType);
  665. if (typeConfig.Size() != 2) {
  666. builder.SetError(TStringBuilder() << "Invalid type config: " << typeConfig.Data());
  667. return;
  668. }
  669. bool hasKey = (typeConfig.Data()[0] == '1');
  670. bool isTop = (typeConfig.Data()[1] == '1');
  671. auto typeHelper = builder.TypeInfoHelper();
  672. auto userTypeInspector = TTupleTypeInspector(*typeHelper, userType);
  673. if (!userTypeInspector || userTypeInspector.GetElementsCount() != 3) {
  674. builder.SetError("User type is not a 3-tuple");
  675. return;
  676. }
  677. auto valueType = userTypeInspector.GetElementType(2);
  678. auto keyType = valueType;
  679. auto payloadType = valueType;
  680. if (hasKey) {
  681. auto keyPayloadTypeInspector = TTupleTypeInspector(*typeHelper, valueType);
  682. if (!keyPayloadTypeInspector || keyPayloadTypeInspector.GetElementsCount() != 2) {
  683. builder.SetError("Key/payload type is not a 2-tuple");
  684. return;
  685. }
  686. keyType = keyPayloadTypeInspector.GetElementType(0);
  687. payloadType = keyPayloadTypeInspector.GetElementType(1);
  688. }
  689. bool isGeneric = false;
  690. ICompare::TPtr compare;
  691. TMaybe<EDataSlot> slot;
  692. auto keyTypeInspector = TDataTypeInspector(*typeHelper, keyType);
  693. if (!keyTypeInspector) {
  694. isGeneric = true;
  695. compare = builder.MakeCompare(keyType);
  696. if (!compare) {
  697. return;
  698. }
  699. } else {
  700. slot = FindDataSlot(keyTypeInspector.GetTypeId());
  701. if (!slot) {
  702. builder.SetError("Unknown data type");
  703. return;
  704. }
  705. if (!(GetDataTypeInfo(*slot).Features & NUdf::CanCompare)) {
  706. builder.SetError("Data type is not comparable");
  707. return;
  708. }
  709. }
  710. auto serializedListType = builder.List()->Item(valueType).Build();
  711. auto serializedType = builder.Tuple()->Add<ui32>().Add(serializedListType).Build();
  712. TType* topType = nullptr;
  713. if (isGeneric) {
  714. PARAMETRIZE_GENERIC(TYPE_GENERIC)
  715. } else {
  716. PARAMETRIZE(TYPE)
  717. }
  718. if (name == CreateName) {
  719. if (hasKey) {
  720. builder.Args()->Add(keyType).Add(payloadType).Add<ui32>().Done().Returns(topType);
  721. } else {
  722. builder.Args()->Add(valueType).Add<ui32>().Done().Returns(topType);
  723. }
  724. if (!typesOnly) {
  725. if (isGeneric) {
  726. PARAMETRIZE_GENERIC(CREATE_GENERIC)
  727. } else {
  728. PARAMETRIZE(CREATE)
  729. }
  730. }
  731. builder.IsStrict();
  732. }
  733. if (name == AddValueName) {
  734. if (hasKey) {
  735. builder.Args()->Add(topType).Add(keyType).Add(payloadType).Done().Returns(topType);
  736. } else {
  737. builder.Args()->Add(topType).Add(valueType).Done().Returns(topType);
  738. }
  739. if (!typesOnly) {
  740. if (isGeneric) {
  741. PARAMETRIZE_GENERIC(ADD_VALUE_GENERIC)
  742. } else {
  743. PARAMETRIZE(ADD_VALUE)
  744. }
  745. }
  746. builder.IsStrict();
  747. }
  748. if (name == SerializeName) {
  749. builder.Args()->Add(topType).Done().Returns(serializedType);
  750. if (!typesOnly) {
  751. if (isGeneric) {
  752. PARAMETRIZE_GENERIC(SERIALIZE_GENERIC)
  753. } else {
  754. PARAMETRIZE(SERIALIZE)
  755. }
  756. }
  757. builder.IsStrict();
  758. }
  759. if (name == DeserializeName) {
  760. builder.Args()->Add(serializedType).Done().Returns(topType);
  761. if (!typesOnly) {
  762. if (isGeneric) {
  763. PARAMETRIZE_GENERIC(DESERIALIZE_GENERIC)
  764. } else {
  765. PARAMETRIZE(DESERIALIZE)
  766. }
  767. }
  768. }
  769. if (name == MergeName) {
  770. builder.Args()->Add(topType).Add(topType).Done().Returns(topType);
  771. if (!typesOnly) {
  772. if (isGeneric) {
  773. PARAMETRIZE_GENERIC(MERGE_GENERIC)
  774. } else {
  775. PARAMETRIZE(MERGE)
  776. }
  777. }
  778. builder.IsStrict();
  779. }
  780. if (name == GetResultName) {
  781. auto listType = builder.List()->Item(payloadType).Build();
  782. builder.Args()->Add(topType).Done().Returns(listType);
  783. if (!typesOnly) {
  784. if (isGeneric) {
  785. PARAMETRIZE_GENERIC(GET_RESULT_GENERIC)
  786. } else {
  787. PARAMETRIZE(GET_RESULT)
  788. }
  789. }
  790. builder.IsStrict();
  791. }
  792. } catch (const std::exception& e) {
  793. builder.SetError(CurrentExceptionMessage());
  794. }
  795. }
  796. };
  797. } // namespace
  798. REGISTER_MODULES(TTopModule)