py_iterator.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include "py_iterator.h"
  2. #include "py_cast.h"
  3. #include "py_errors.h"
  4. #include "py_utils.h"
  5. #include <yql/essentials/public/udf/udf_value.h>
  6. #include <yql/essentials/public/udf/udf_value_builder.h>
  7. using namespace NKikimr;
  8. namespace NPython {
  9. //////////////////////////////////////////////////////////////////////////////
  10. // TPyIterator interface
  11. //////////////////////////////////////////////////////////////////////////////
  12. struct TPyIterator
  13. {
  14. PyObject_HEAD;
  15. TPyCastContext::TPtr CastCtx;
  16. const NUdf::TType* ItemType;
  17. TPyCleanupListItem<NUdf::IBoxedValuePtr> Iterator;
  18. inline static TPyIterator* Cast(PyObject* o) {
  19. return reinterpret_cast<TPyIterator*>(o);
  20. }
  21. inline static void Dealloc(PyObject* self) {
  22. delete Cast(self);
  23. }
  24. inline static PyObject* Repr(PyObject* self) {
  25. Y_UNUSED(self);
  26. return PyRepr("<yql.TDictKeysIterator>").Release();
  27. }
  28. static PyObject* New(const TPyCastContext::TPtr& ctx, const NUdf::TType* itemType, NUdf::IBoxedValuePtr&& iterator);
  29. static PyObject* Next(PyObject* self);
  30. };
  31. #if PY_MAJOR_VERSION >= 3
  32. #define Py_TPFLAGS_HAVE_ITER 0
  33. #endif
  34. PyTypeObject PyIteratorType = {
  35. PyVarObject_HEAD_INIT(&PyType_Type, 0)
  36. INIT_MEMBER(tp_name , "yql.TIterator"),
  37. INIT_MEMBER(tp_basicsize , sizeof(TPyIterator)),
  38. INIT_MEMBER(tp_itemsize , 0),
  39. INIT_MEMBER(tp_dealloc , TPyIterator::Dealloc),
  40. #if PY_VERSION_HEX < 0x030800b4
  41. INIT_MEMBER(tp_print , nullptr),
  42. #else
  43. INIT_MEMBER(tp_vectorcall_offset, 0),
  44. #endif
  45. INIT_MEMBER(tp_getattr , nullptr),
  46. INIT_MEMBER(tp_setattr , nullptr),
  47. #if PY_MAJOR_VERSION >= 3
  48. INIT_MEMBER(tp_as_async , nullptr),
  49. #else
  50. INIT_MEMBER(tp_compare , nullptr),
  51. #endif
  52. INIT_MEMBER(tp_repr , TPyIterator::Repr),
  53. INIT_MEMBER(tp_as_number , nullptr),
  54. INIT_MEMBER(tp_as_sequence , nullptr),
  55. INIT_MEMBER(tp_as_mapping , nullptr),
  56. INIT_MEMBER(tp_hash , nullptr),
  57. INIT_MEMBER(tp_call , nullptr),
  58. INIT_MEMBER(tp_str , nullptr),
  59. INIT_MEMBER(tp_getattro , nullptr),
  60. INIT_MEMBER(tp_setattro , nullptr),
  61. INIT_MEMBER(tp_as_buffer , nullptr),
  62. INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
  63. INIT_MEMBER(tp_doc , "yql.TDictKeysIterator object"),
  64. INIT_MEMBER(tp_traverse , nullptr),
  65. INIT_MEMBER(tp_clear , nullptr),
  66. INIT_MEMBER(tp_richcompare , nullptr),
  67. INIT_MEMBER(tp_weaklistoffset , 0),
  68. INIT_MEMBER(tp_iter , PyObject_SelfIter),
  69. INIT_MEMBER(tp_iternext , TPyIterator::Next),
  70. INIT_MEMBER(tp_methods , nullptr),
  71. INIT_MEMBER(tp_members , nullptr),
  72. INIT_MEMBER(tp_getset , nullptr),
  73. INIT_MEMBER(tp_base , nullptr),
  74. INIT_MEMBER(tp_dict , nullptr),
  75. INIT_MEMBER(tp_descr_get , nullptr),
  76. INIT_MEMBER(tp_descr_set , nullptr),
  77. INIT_MEMBER(tp_dictoffset , 0),
  78. INIT_MEMBER(tp_init , nullptr),
  79. INIT_MEMBER(tp_alloc , nullptr),
  80. INIT_MEMBER(tp_new , nullptr),
  81. INIT_MEMBER(tp_free , nullptr),
  82. INIT_MEMBER(tp_is_gc , nullptr),
  83. INIT_MEMBER(tp_bases , nullptr),
  84. INIT_MEMBER(tp_mro , nullptr),
  85. INIT_MEMBER(tp_cache , nullptr),
  86. INIT_MEMBER(tp_subclasses , nullptr),
  87. INIT_MEMBER(tp_weaklist , nullptr),
  88. INIT_MEMBER(tp_del , nullptr),
  89. INIT_MEMBER(tp_version_tag , 0),
  90. #if PY_MAJOR_VERSION >= 3
  91. INIT_MEMBER(tp_finalize , nullptr),
  92. #endif
  93. #if PY_VERSION_HEX >= 0x030800b1
  94. INIT_MEMBER(tp_vectorcall , nullptr),
  95. #endif
  96. #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
  97. INIT_MEMBER(tp_print , nullptr),
  98. #endif
  99. };
  100. //////////////////////////////////////////////////////////////////////////////
  101. // TPyPairIterator interface
  102. //////////////////////////////////////////////////////////////////////////////
  103. struct TPyPairIterator
  104. {
  105. PyObject_HEAD;
  106. TPyCastContext::TPtr CastCtx;
  107. const NUdf::TType* KeyType;
  108. const NUdf::TType* PayloadType;
  109. TPyCleanupListItem<NUdf::IBoxedValuePtr> Iterator;
  110. inline static TPyPairIterator* Cast(PyObject* o) {
  111. return reinterpret_cast<TPyPairIterator*>(o);
  112. }
  113. inline static void Dealloc(PyObject* self) {
  114. delete Cast(self);
  115. }
  116. inline static PyObject* Repr(PyObject* self) {
  117. Y_UNUSED(self);
  118. return PyRepr("<yql.TDictIterator>").Release();
  119. }
  120. static PyObject* New(const TPyCastContext::TPtr& ctx, const NUdf::TType* keyType, const NUdf::TType* payloadType, NUdf::IBoxedValuePtr&& iterator);
  121. static PyObject* Next(PyObject* self);
  122. };
  123. PyTypeObject PyPairIteratorType = {
  124. PyVarObject_HEAD_INIT(&PyType_Type, 0)
  125. INIT_MEMBER(tp_name , "yql.TDictIterator"),
  126. INIT_MEMBER(tp_basicsize , sizeof(TPyPairIterator)),
  127. INIT_MEMBER(tp_itemsize , 0),
  128. INIT_MEMBER(tp_dealloc , TPyPairIterator::Dealloc),
  129. #if PY_VERSION_HEX < 0x030800b4
  130. INIT_MEMBER(tp_print , nullptr),
  131. #else
  132. INIT_MEMBER(tp_vectorcall_offset, 0),
  133. #endif
  134. INIT_MEMBER(tp_getattr , nullptr),
  135. INIT_MEMBER(tp_setattr , nullptr),
  136. #if PY_MAJOR_VERSION >= 3
  137. INIT_MEMBER(tp_as_async , nullptr),
  138. #else
  139. INIT_MEMBER(tp_compare , nullptr),
  140. #endif
  141. INIT_MEMBER(tp_repr , TPyPairIterator::Repr),
  142. INIT_MEMBER(tp_as_number , nullptr),
  143. INIT_MEMBER(tp_as_sequence , nullptr),
  144. INIT_MEMBER(tp_as_mapping , nullptr),
  145. INIT_MEMBER(tp_hash , nullptr),
  146. INIT_MEMBER(tp_call , nullptr),
  147. INIT_MEMBER(tp_str , nullptr),
  148. INIT_MEMBER(tp_getattro , nullptr),
  149. INIT_MEMBER(tp_setattro , nullptr),
  150. INIT_MEMBER(tp_as_buffer , nullptr),
  151. INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
  152. INIT_MEMBER(tp_doc , "yql.TPairIterator object"),
  153. INIT_MEMBER(tp_traverse , nullptr),
  154. INIT_MEMBER(tp_clear , nullptr),
  155. INIT_MEMBER(tp_richcompare , nullptr),
  156. INIT_MEMBER(tp_weaklistoffset , 0),
  157. INIT_MEMBER(tp_iter , PyObject_SelfIter),
  158. INIT_MEMBER(tp_iternext , TPyPairIterator::Next),
  159. INIT_MEMBER(tp_methods , nullptr),
  160. INIT_MEMBER(tp_members , nullptr),
  161. INIT_MEMBER(tp_getset , nullptr),
  162. INIT_MEMBER(tp_base , nullptr),
  163. INIT_MEMBER(tp_dict , nullptr),
  164. INIT_MEMBER(tp_descr_get , nullptr),
  165. INIT_MEMBER(tp_descr_set , nullptr),
  166. INIT_MEMBER(tp_dictoffset , 0),
  167. INIT_MEMBER(tp_init , nullptr),
  168. INIT_MEMBER(tp_alloc , nullptr),
  169. INIT_MEMBER(tp_new , nullptr),
  170. INIT_MEMBER(tp_free , nullptr),
  171. INIT_MEMBER(tp_is_gc , nullptr),
  172. INIT_MEMBER(tp_bases , nullptr),
  173. INIT_MEMBER(tp_mro , nullptr),
  174. INIT_MEMBER(tp_cache , nullptr),
  175. INIT_MEMBER(tp_subclasses , nullptr),
  176. INIT_MEMBER(tp_weaklist , nullptr),
  177. INIT_MEMBER(tp_del , nullptr),
  178. INIT_MEMBER(tp_version_tag , 0),
  179. #if PY_MAJOR_VERSION >= 3
  180. INIT_MEMBER(tp_finalize , nullptr),
  181. #endif
  182. #if PY_VERSION_HEX >= 0x030800b1
  183. INIT_MEMBER(tp_vectorcall , nullptr),
  184. #endif
  185. #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
  186. INIT_MEMBER(tp_print , nullptr),
  187. #endif
  188. };
  189. //////////////////////////////////////////////////////////////////////////////
  190. // TPyIterator implementation
  191. //////////////////////////////////////////////////////////////////////////////
  192. PyObject* TPyIterator::New(const TPyCastContext::TPtr& ctx, const NUdf::TType* itemType, NUdf::IBoxedValuePtr&& iterator)
  193. {
  194. TPyIterator* dictIter = new TPyIterator;
  195. PyObject_INIT(dictIter, &PyIteratorType);
  196. dictIter->CastCtx = ctx;
  197. dictIter->ItemType = itemType;
  198. dictIter->Iterator.Set(ctx->PyCtx, iterator);
  199. return reinterpret_cast<PyObject*>(dictIter);
  200. }
  201. PyObject* TPyIterator::Next(PyObject* self)
  202. {
  203. PY_TRY {
  204. const auto iter = Cast(self);
  205. NUdf::TUnboxedValue item;
  206. if (NUdf::TBoxedValueAccessor::Next(*iter->Iterator.Get(), item)) {
  207. return (iter->ItemType ? ToPyObject(iter->CastCtx, iter->ItemType, item) : PyCast<ui64>(item.Get<ui64>())).Release();
  208. }
  209. return nullptr;
  210. } PY_CATCH(nullptr)
  211. }
  212. //////////////////////////////////////////////////////////////////////////////
  213. // TPyPairIterator implementation
  214. //////////////////////////////////////////////////////////////////////////////
  215. PyObject* TPyPairIterator::New(const TPyCastContext::TPtr& ctx, const NUdf::TType* keyType, const NUdf::TType* payloadType, NUdf::IBoxedValuePtr&& iterator)
  216. {
  217. TPyPairIterator* dictIter = new TPyPairIterator;
  218. PyObject_INIT(dictIter, &PyPairIteratorType);
  219. dictIter->CastCtx = ctx;
  220. dictIter->KeyType = keyType;
  221. dictIter->PayloadType = payloadType;
  222. dictIter->Iterator.Set(ctx->PyCtx, iterator);
  223. return reinterpret_cast<PyObject*>(dictIter);
  224. }
  225. PyObject* TPyPairIterator::Next(PyObject* self)
  226. {
  227. PY_TRY {
  228. const auto iter = Cast(self);
  229. NUdf::TUnboxedValue k, v;
  230. if (NUdf::TBoxedValueAccessor::NextPair(*iter->Iterator.Get(), k, v)) {
  231. const TPyObjectPtr key = iter->KeyType ?
  232. ToPyObject(iter->CastCtx, iter->KeyType, k):
  233. PyCast<ui64>(k.Get<ui64>());
  234. const TPyObjectPtr value = ToPyObject(iter->CastCtx, iter->PayloadType, v);
  235. return PyTuple_Pack(2, key.Get(), value.Get());
  236. }
  237. return nullptr;
  238. } PY_CATCH(nullptr)
  239. }
  240. //////////////////////////////////////////////////////////////////////////////
  241. TPyObjectPtr ToPyIterator(
  242. const TPyCastContext::TPtr& castCtx,
  243. const NUdf::TType* itemType,
  244. const NUdf::TUnboxedValuePod& value)
  245. {
  246. return TPyIterator::New(castCtx, itemType, value.AsBoxed());
  247. }
  248. TPyObjectPtr ToPyIterator(
  249. const TPyCastContext::TPtr& castCtx,
  250. const NUdf::TType* keyType,
  251. const NUdf::TType* payloadType,
  252. const NUdf::TUnboxedValuePod& value)
  253. {
  254. return TPyPairIterator::New(castCtx, keyType, payloadType, value.AsBoxed());
  255. }
  256. } // namspace NPython