py_list.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. #include "py_list.h"
  2. #include "py_dict.h"
  3. #include "py_cast.h"
  4. #include "py_errors.h"
  5. #include "py_utils.h"
  6. #include <yql/essentials/public/udf/udf_value.h>
  7. #include <yql/essentials/public/udf/udf_value_builder.h>
  8. using namespace NKikimr;
  9. #if PY_MAJOR_VERSION >= 3
  10. #define SLICEOBJ(obj) obj
  11. #else
  12. #define SLICEOBJ(obj) (reinterpret_cast<PySliceObject*>(obj))
  13. // See details about need for backports in ya.make
  14. #include "py27_backports.h"
  15. #endif
  16. namespace NPython {
  17. namespace {
  18. inline Py_ssize_t CastIndex(PyObject* key, const char* name)
  19. {
  20. Py_ssize_t index = -1;
  21. if (PyIndex_Check(key)) {
  22. index = PyNumber_AsSsize_t(key, PyExc_IndexError);
  23. }
  24. if (index < 0) {
  25. const TPyObjectPtr value = PyUnicode_FromFormat("argument of %s must be positive integer or long", name);
  26. PyErr_SetObject(PyExc_IndexError, value.Get());
  27. }
  28. return index;
  29. }
  30. }
  31. //////////////////////////////////////////////////////////////////////////////
  32. // TPyLazyList interface
  33. //////////////////////////////////////////////////////////////////////////////
  34. struct TPyLazyList
  35. {
  36. using TPtr = NUdf::TRefCountedPtr<TPyLazyList, TPyPtrOps<TPyLazyList>>;
  37. PyObject_HEAD;
  38. TPyCastContext::TPtr CastCtx;
  39. const NUdf::TType* ItemType;
  40. TPyCleanupListItem<NUdf::IBoxedValuePtr> Value;
  41. TPyCleanupListItem<NUdf::IBoxedValuePtr> Dict;
  42. Py_ssize_t Step;
  43. Py_ssize_t CachedLength;
  44. inline static TPyLazyList* Cast(PyObject* o) {
  45. return reinterpret_cast<TPyLazyList*>(o);
  46. }
  47. inline static void Dealloc(PyObject* self) {
  48. delete Cast(self);
  49. }
  50. static PyObject* New(
  51. const TPyCastContext::TPtr& castCtx,
  52. const NUdf::TType* itemType,
  53. NUdf::IBoxedValuePtr value,
  54. Py_ssize_t step = 1,
  55. Py_ssize_t size = -1);
  56. static int Bool(PyObject* self);
  57. static PyObject* Repr(PyObject* self);
  58. static PyObject* Iter(PyObject* self);
  59. static Py_ssize_t Len(PyObject* self);
  60. static PyObject* Subscript(PyObject* self, PyObject* slice);
  61. static PyObject* ToIndexDict(PyObject* self, PyObject* /* arg */);
  62. static PyObject* Reversed(PyObject* self, PyObject* /* arg */);
  63. static PyObject* Take(PyObject* self, PyObject* arg);
  64. static PyObject* Skip(PyObject* self, PyObject* arg);
  65. static PyObject* HasFastLen(PyObject* self, PyObject* /* arg */);
  66. static PyObject* HasItems(PyObject* self, PyObject* /* arg */);
  67. };
  68. PyMappingMethods LazyListMapping = {
  69. INIT_MEMBER(mp_length, TPyLazyList::Len),
  70. INIT_MEMBER(mp_subscript, TPyLazyList::Subscript),
  71. INIT_MEMBER(mp_ass_subscript, nullptr),
  72. };
  73. PyNumberMethods LazyListNumbering = {
  74. INIT_MEMBER(nb_add, nullptr),
  75. INIT_MEMBER(nb_subtract, nullptr),
  76. INIT_MEMBER(nb_multiply, nullptr),
  77. #if PY_MAJOR_VERSION < 3
  78. INIT_MEMBER(nb_divide, nullptr),
  79. #endif
  80. INIT_MEMBER(nb_remainder, nullptr),
  81. INIT_MEMBER(nb_divmod, nullptr),
  82. INIT_MEMBER(nb_power, nullptr),
  83. INIT_MEMBER(nb_negative, nullptr),
  84. INIT_MEMBER(nb_positive, nullptr),
  85. INIT_MEMBER(nb_absolute, nullptr),
  86. #if PY_MAJOR_VERSION >= 3
  87. INIT_MEMBER(nb_bool, TPyLazyList::Bool),
  88. #else
  89. INIT_MEMBER(nb_nonzero, TPyLazyList::Bool),
  90. #endif
  91. INIT_MEMBER(nb_invert, nullptr),
  92. INIT_MEMBER(nb_lshift, nullptr),
  93. INIT_MEMBER(nb_rshift, nullptr),
  94. INIT_MEMBER(nb_and, nullptr),
  95. INIT_MEMBER(nb_xor, nullptr),
  96. INIT_MEMBER(nb_or, nullptr),
  97. #if PY_MAJOR_VERSION < 3
  98. INIT_MEMBER(nb_coerce, nullptr),
  99. #endif
  100. INIT_MEMBER(nb_int, nullptr),
  101. #if PY_MAJOR_VERSION >= 3
  102. INIT_MEMBER(nb_reserved, nullptr),
  103. #else
  104. INIT_MEMBER(nb_long, nullptr),
  105. #endif
  106. INIT_MEMBER(nb_float, nullptr),
  107. #if PY_MAJOR_VERSION < 3
  108. INIT_MEMBER(nb_oct, nullptr),
  109. INIT_MEMBER(nb_hex, nullptr),
  110. #endif
  111. INIT_MEMBER(nb_inplace_add, nullptr),
  112. INIT_MEMBER(nb_inplace_subtract, nullptr),
  113. INIT_MEMBER(nb_inplace_multiply, nullptr),
  114. INIT_MEMBER(nb_inplace_remainder, nullptr),
  115. INIT_MEMBER(nb_inplace_power, nullptr),
  116. INIT_MEMBER(nb_inplace_lshift, nullptr),
  117. INIT_MEMBER(nb_inplace_rshift, nullptr),
  118. INIT_MEMBER(nb_inplace_and, nullptr),
  119. INIT_MEMBER(nb_inplace_xor, nullptr),
  120. INIT_MEMBER(nb_inplace_or, nullptr),
  121. INIT_MEMBER(nb_floor_divide, nullptr),
  122. INIT_MEMBER(nb_true_divide, nullptr),
  123. INIT_MEMBER(nb_inplace_floor_divide, nullptr),
  124. INIT_MEMBER(nb_inplace_true_divide, nullptr),
  125. INIT_MEMBER(nb_index, nullptr),
  126. #if PY_MAJOR_VERSION >= 3
  127. INIT_MEMBER(nb_matrix_multiply, nullptr),
  128. INIT_MEMBER(nb_inplace_matrix_multiply, nullptr),
  129. #endif
  130. };
  131. PyDoc_STRVAR(reversed__doc__, "DEPRECATED: use reversed(list) or list[::-1] instead.");
  132. PyDoc_STRVAR(take__doc__, "DEPRECATED: use slice list[:n] instead.");
  133. PyDoc_STRVAR(skip__doc__, "DEPRECATED: use slice list[n:] instead.");
  134. PyDoc_STRVAR(to_index_dict__doc__, "DEPRECATED: use list[n] instead.");
  135. PyDoc_STRVAR(has_fast_len__doc__, "DEPRECATED: do not use.");
  136. PyDoc_STRVAR(has_items__doc__, "DEPRECATED: test list as bool instead.");
  137. static PyMethodDef TPyLazyListMethods[] = {
  138. { "__reversed__", TPyLazyList::Reversed, METH_NOARGS, nullptr },
  139. { "to_index_dict", TPyLazyList::ToIndexDict, METH_NOARGS, to_index_dict__doc__ },
  140. { "reversed", TPyLazyList::Reversed, METH_NOARGS, reversed__doc__ },
  141. { "take", TPyLazyList::Take, METH_O, take__doc__ },
  142. { "skip", TPyLazyList::Skip, METH_O, skip__doc__ },
  143. { "has_fast_len", TPyLazyList::HasFastLen, METH_NOARGS, has_fast_len__doc__ },
  144. { "has_items", TPyLazyList::HasItems, METH_NOARGS, has_items__doc__ },
  145. { nullptr, nullptr, 0, nullptr } /* sentinel */
  146. };
  147. #if PY_MAJOR_VERSION >= 3
  148. #define Py_TPFLAGS_HAVE_ITER 0
  149. #endif
  150. PyTypeObject PyLazyListType = {
  151. PyVarObject_HEAD_INIT(&PyType_Type, 0)
  152. INIT_MEMBER(tp_name , "yql.TList"),
  153. INIT_MEMBER(tp_basicsize , sizeof(TPyLazyList)),
  154. INIT_MEMBER(tp_itemsize , 0),
  155. INIT_MEMBER(tp_dealloc , TPyLazyList::Dealloc),
  156. #if PY_VERSION_HEX < 0x030800b4
  157. INIT_MEMBER(tp_print , nullptr),
  158. #else
  159. INIT_MEMBER(tp_vectorcall_offset, 0),
  160. #endif
  161. INIT_MEMBER(tp_getattr , nullptr),
  162. INIT_MEMBER(tp_setattr , nullptr),
  163. #if PY_MAJOR_VERSION >= 3
  164. INIT_MEMBER(tp_as_async , nullptr),
  165. #else
  166. INIT_MEMBER(tp_compare , nullptr),
  167. #endif
  168. INIT_MEMBER(tp_repr , TPyLazyList::Repr),
  169. INIT_MEMBER(tp_as_number , &LazyListNumbering),
  170. INIT_MEMBER(tp_as_sequence , nullptr),
  171. INIT_MEMBER(tp_as_mapping , &LazyListMapping),
  172. INIT_MEMBER(tp_hash , nullptr),
  173. INIT_MEMBER(tp_call , nullptr),
  174. INIT_MEMBER(tp_str , nullptr),
  175. INIT_MEMBER(tp_getattro , nullptr),
  176. INIT_MEMBER(tp_setattro , nullptr),
  177. INIT_MEMBER(tp_as_buffer , nullptr),
  178. INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
  179. INIT_MEMBER(tp_doc , "yql.TList object"),
  180. INIT_MEMBER(tp_traverse , nullptr),
  181. INIT_MEMBER(tp_clear , nullptr),
  182. INIT_MEMBER(tp_richcompare , nullptr),
  183. INIT_MEMBER(tp_weaklistoffset , 0),
  184. INIT_MEMBER(tp_iter , TPyLazyList::Iter),
  185. INIT_MEMBER(tp_iternext , nullptr),
  186. INIT_MEMBER(tp_methods , TPyLazyListMethods),
  187. INIT_MEMBER(tp_members , nullptr),
  188. INIT_MEMBER(tp_getset , nullptr),
  189. INIT_MEMBER(tp_base , nullptr),
  190. INIT_MEMBER(tp_dict , nullptr),
  191. INIT_MEMBER(tp_descr_get , nullptr),
  192. INIT_MEMBER(tp_descr_set , nullptr),
  193. INIT_MEMBER(tp_dictoffset , 0),
  194. INIT_MEMBER(tp_init , nullptr),
  195. INIT_MEMBER(tp_alloc , nullptr),
  196. INIT_MEMBER(tp_new , nullptr),
  197. INIT_MEMBER(tp_free , nullptr),
  198. INIT_MEMBER(tp_is_gc , nullptr),
  199. INIT_MEMBER(tp_bases , nullptr),
  200. INIT_MEMBER(tp_mro , nullptr),
  201. INIT_MEMBER(tp_cache , nullptr),
  202. INIT_MEMBER(tp_subclasses , nullptr),
  203. INIT_MEMBER(tp_weaklist , nullptr),
  204. INIT_MEMBER(tp_del , nullptr),
  205. INIT_MEMBER(tp_version_tag , 0),
  206. #if PY_MAJOR_VERSION >= 3
  207. INIT_MEMBER(tp_finalize , nullptr),
  208. #endif
  209. #if PY_VERSION_HEX >= 0x030800b1
  210. INIT_MEMBER(tp_vectorcall , nullptr),
  211. #endif
  212. #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
  213. INIT_MEMBER(tp_print , nullptr),
  214. #endif
  215. };
  216. //////////////////////////////////////////////////////////////////////////////
  217. // TPyLazyListIterator interface
  218. //////////////////////////////////////////////////////////////////////////////
  219. struct TPyLazyListIterator
  220. {
  221. PyObject_HEAD;
  222. TPyLazyList::TPtr List;
  223. TPyCleanupListItem<NUdf::TUnboxedValue> Iterator;
  224. Py_ssize_t Length;
  225. TPyCastContext::TPtr CastCtx;
  226. inline static TPyLazyListIterator* Cast(PyObject* o) {
  227. return reinterpret_cast<TPyLazyListIterator*>(o);
  228. }
  229. inline static void Dealloc(PyObject* self) {
  230. auto obj = Cast(self);
  231. auto ctx = obj->CastCtx;
  232. ctx->MemoryLock->Acquire();
  233. delete obj;
  234. ctx->MemoryLock->Release();
  235. }
  236. inline static PyObject* Repr(PyObject* self) {
  237. Y_UNUSED(self);
  238. return PyRepr("<yql.TListIterator>").Release();
  239. }
  240. static PyObject* New(TPyLazyList* list);
  241. static PyObject* Next(PyObject* self);
  242. };
  243. PyTypeObject PyLazyListIteratorType = {
  244. PyVarObject_HEAD_INIT(&PyType_Type, 0)
  245. INIT_MEMBER(tp_name , "yql.TListIterator"),
  246. INIT_MEMBER(tp_basicsize , sizeof(TPyLazyListIterator)),
  247. INIT_MEMBER(tp_itemsize , 0),
  248. INIT_MEMBER(tp_dealloc , TPyLazyListIterator::Dealloc),
  249. #if PY_VERSION_HEX < 0x030800b4
  250. INIT_MEMBER(tp_print , nullptr),
  251. #else
  252. INIT_MEMBER(tp_vectorcall_offset, 0),
  253. #endif
  254. INIT_MEMBER(tp_getattr , nullptr),
  255. INIT_MEMBER(tp_setattr , nullptr),
  256. #if PY_MAJOR_VERSION >= 3
  257. INIT_MEMBER(tp_as_async , nullptr),
  258. #else
  259. INIT_MEMBER(tp_compare , nullptr),
  260. #endif
  261. INIT_MEMBER(tp_repr , TPyLazyListIterator::Repr),
  262. INIT_MEMBER(tp_as_number , nullptr),
  263. INIT_MEMBER(tp_as_sequence , nullptr),
  264. INIT_MEMBER(tp_as_mapping , nullptr),
  265. INIT_MEMBER(tp_hash , nullptr),
  266. INIT_MEMBER(tp_call , nullptr),
  267. INIT_MEMBER(tp_str , nullptr),
  268. INIT_MEMBER(tp_getattro , nullptr),
  269. INIT_MEMBER(tp_setattro , nullptr),
  270. INIT_MEMBER(tp_as_buffer , nullptr),
  271. INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
  272. INIT_MEMBER(tp_doc , "yql.ListIterator object"),
  273. INIT_MEMBER(tp_traverse , nullptr),
  274. INIT_MEMBER(tp_clear , nullptr),
  275. INIT_MEMBER(tp_richcompare , nullptr),
  276. INIT_MEMBER(tp_weaklistoffset , 0),
  277. INIT_MEMBER(tp_iter , PyObject_SelfIter),
  278. INIT_MEMBER(tp_iternext , TPyLazyListIterator::Next),
  279. INIT_MEMBER(tp_methods , nullptr),
  280. INIT_MEMBER(tp_members , nullptr),
  281. INIT_MEMBER(tp_getset , nullptr),
  282. INIT_MEMBER(tp_base , nullptr),
  283. INIT_MEMBER(tp_dict , nullptr),
  284. INIT_MEMBER(tp_descr_get , nullptr),
  285. INIT_MEMBER(tp_descr_set , nullptr),
  286. INIT_MEMBER(tp_dictoffset , 0),
  287. INIT_MEMBER(tp_init , nullptr),
  288. INIT_MEMBER(tp_alloc , nullptr),
  289. INIT_MEMBER(tp_new , nullptr),
  290. INIT_MEMBER(tp_free , nullptr),
  291. INIT_MEMBER(tp_is_gc , nullptr),
  292. INIT_MEMBER(tp_bases , nullptr),
  293. INIT_MEMBER(tp_mro , nullptr),
  294. INIT_MEMBER(tp_cache , nullptr),
  295. INIT_MEMBER(tp_subclasses , nullptr),
  296. INIT_MEMBER(tp_weaklist , nullptr),
  297. INIT_MEMBER(tp_del , nullptr),
  298. INIT_MEMBER(tp_version_tag , 0),
  299. #if PY_MAJOR_VERSION >= 3
  300. INIT_MEMBER(tp_finalize , nullptr),
  301. #endif
  302. #if PY_VERSION_HEX >= 0x030800b1
  303. INIT_MEMBER(tp_vectorcall , nullptr),
  304. #endif
  305. #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
  306. INIT_MEMBER(tp_print , nullptr),
  307. #endif
  308. };
  309. //////////////////////////////////////////////////////////////////////////////
  310. // TPyLazyList implementation
  311. //////////////////////////////////////////////////////////////////////////////
  312. PyObject* TPyLazyList::New(
  313. const TPyCastContext::TPtr& castCtx,
  314. const NUdf::TType* itemType,
  315. NUdf::IBoxedValuePtr value,
  316. Py_ssize_t step,
  317. Py_ssize_t size)
  318. {
  319. TPyLazyList* list = new TPyLazyList;
  320. PyObject_INIT(list, &PyLazyListType);
  321. list->CastCtx = castCtx;
  322. list->ItemType = itemType;
  323. list->Value.Set(castCtx->PyCtx, value);
  324. list->Step = step;
  325. list->CachedLength = size;
  326. return reinterpret_cast<PyObject*>(list);
  327. }
  328. PyObject* TPyLazyList::Repr(PyObject*)
  329. {
  330. return PyRepr("<yql.TList>").Release();
  331. }
  332. PyObject* TPyLazyList::Iter(PyObject* self)
  333. {
  334. PY_TRY {
  335. TPyLazyList* list = Cast(self);
  336. return TPyLazyListIterator::New(list);
  337. } PY_CATCH(nullptr)
  338. }
  339. Py_ssize_t TPyLazyList::Len(PyObject* self)
  340. {
  341. PY_TRY {
  342. TPyLazyList* list = Cast(self);
  343. if (list->CachedLength == -1) {
  344. list->CachedLength = static_cast<Py_ssize_t>(NUdf::TBoxedValueAccessor::GetListLength(*list->Value.Get()));
  345. }
  346. return (list->CachedLength + list->Step - 1) / list->Step;
  347. } PY_CATCH(-1)
  348. }
  349. PyObject* TPyLazyList::Subscript(PyObject* self, PyObject* slice)
  350. {
  351. PY_TRY {
  352. TPyLazyList* list = Cast(self);
  353. const auto vb = list->CastCtx->ValueBuilder;
  354. if (PyIndex_Check(slice)) {
  355. Py_ssize_t index = PyNumber_AsSsize_t(slice, PyExc_IndexError);
  356. if (!list->Dict.IsSet()) {
  357. list->Dict.Set(list->CastCtx->PyCtx, vb->ToIndexDict(NUdf::TUnboxedValuePod(list->Value.Get().Get())).AsBoxed());
  358. }
  359. if (index < 0) {
  360. if (list->CachedLength == -1) {
  361. list->CachedLength = static_cast<Py_ssize_t>(NUdf::TBoxedValueAccessor::GetDictLength(*list->Dict.Get()));
  362. }
  363. ++index *= list->Step;
  364. --index += list->CachedLength;
  365. } else {
  366. index *= list->Step;
  367. }
  368. if (index < 0 || (list->CachedLength != -1 && index >= list->CachedLength)) {
  369. const TPyObjectPtr error = PyUnicode_FromFormat("index %zd out of bounds, list size: %zd", index, list->CachedLength);
  370. PyErr_SetObject(PyExc_IndexError, error.Get());
  371. return nullptr;
  372. }
  373. if (const auto item = NUdf::TBoxedValueAccessor::Lookup(*list->Dict.Get(), NUdf::TUnboxedValuePod(ui64(index)))) {
  374. return ToPyObject(list->CastCtx, list->ItemType, item.GetOptionalValue()).Release();
  375. }
  376. const TPyObjectPtr error = PyUnicode_FromFormat("index %zd out of bounds", index);
  377. PyErr_SetObject(PyExc_IndexError, error.Get());
  378. return nullptr;
  379. }
  380. if (PySlice_Check(slice)) {
  381. Py_ssize_t start, stop, step, size;
  382. if (list->CachedLength >= 0) {
  383. if (PySlice_GetIndicesEx(SLICEOBJ(slice), (list->CachedLength + list->Step - 1) / list->Step, &start, &stop, &step, &size) < 0) {
  384. return nullptr;
  385. }
  386. } else {
  387. if (PySlice_Unpack(slice, &start, &stop, &step) < 0) {
  388. return nullptr;
  389. }
  390. if (step < -1 || step > 1 || (start < 0 && start > PY_SSIZE_T_MIN) || (stop < 0 && stop > PY_SSIZE_T_MIN)) {
  391. list->CachedLength = static_cast<Py_ssize_t>(NUdf::TBoxedValueAccessor::GetListLength(*list->Value.Get()));
  392. size = PySlice_AdjustIndices((list->CachedLength + list->Step - 1) / list->Step, &start, &stop, step);
  393. } else {
  394. size = PySlice_AdjustIndices(PY_SSIZE_T_MAX, &start, &stop, step);
  395. }
  396. }
  397. if (!step) {
  398. PyErr_SetString(PyExc_ValueError, "slice step cannot be zero");
  399. return nullptr;
  400. }
  401. const Py_ssize_t hi = PY_SSIZE_T_MAX / list->Step;
  402. const Py_ssize_t lo = PY_SSIZE_T_MIN / list->Step;
  403. step = step > lo && step < hi ? step * list->Step : (step > 0 ? PY_SSIZE_T_MAX : PY_SSIZE_T_MIN);
  404. NUdf::TUnboxedValue newList;
  405. if (size > 0) {
  406. size = step > 0 ?
  407. (size < PY_SSIZE_T_MAX / step ? --size * step + 1 : PY_SSIZE_T_MAX):
  408. (size < PY_SSIZE_T_MAX / -step ? --size * -step + 1 : PY_SSIZE_T_MAX);
  409. start = start < hi ? start * list->Step : PY_SSIZE_T_MAX;
  410. const Py_ssize_t skip = step > 0 ? start : start - size + 1;
  411. newList = NUdf::TUnboxedValuePod(list->Value.Get().Get());
  412. if (skip > 0) {
  413. newList = vb->SkipList(newList, skip);
  414. }
  415. if (size < PY_SSIZE_T_MAX && (list->CachedLength == -1 || list->CachedLength - skip > size)) {
  416. newList = vb->TakeList(newList, size);
  417. }
  418. if (step < 0) {
  419. step = -step;
  420. newList = vb->ReverseList(newList);
  421. }
  422. } else {
  423. newList = vb->NewEmptyList();
  424. }
  425. return New(list->CastCtx, list->ItemType, newList.AsBoxed(), step, size);
  426. }
  427. const TPyObjectPtr type = PyObject_Type(slice);
  428. const TPyObjectPtr repr = PyObject_Repr(type.Get());
  429. const TPyObjectPtr error = PyUnicode_FromFormat("Unsupported slice object type: %R", repr.Get());
  430. PyErr_SetObject(PyExc_TypeError, error.Get());
  431. return nullptr;
  432. } PY_CATCH(nullptr)
  433. }
  434. PyObject* TPyLazyList::ToIndexDict(PyObject* self, PyObject* /* arg */)
  435. {
  436. PY_TRY {
  437. TPyLazyList* list = Cast(self);
  438. if (!list->Dict.IsSet()) {
  439. list->Dict.Set(list->CastCtx->PyCtx, list->CastCtx->ValueBuilder->ToIndexDict(NUdf::TUnboxedValuePod(list->Value.Get().Get())).AsBoxed());
  440. }
  441. return ToPyLazyDict(list->CastCtx, nullptr, list->ItemType, NUdf::TUnboxedValuePod(list->Dict.Get().Get())).Release();
  442. } PY_CATCH(nullptr)
  443. }
  444. PyObject* TPyLazyList::Reversed(PyObject* self, PyObject* /* arg */)
  445. {
  446. PY_TRY {
  447. TPyLazyList* list = Cast(self);
  448. const auto newList = list->CastCtx->ValueBuilder->ReverseList(NUdf::TUnboxedValuePod(list->Value.Get().Get()));
  449. return New(list->CastCtx, list->ItemType, newList.AsBoxed(), list->Step);
  450. } PY_CATCH(nullptr)
  451. }
  452. PyObject* TPyLazyList::Take(PyObject* self, PyObject* arg)
  453. {
  454. PY_TRY {
  455. TPyLazyList* list = Cast(self);
  456. Py_ssize_t count = CastIndex(arg, "take");
  457. if (count < 0) {
  458. return nullptr;
  459. }
  460. count *= list->Step;
  461. auto vb = list->CastCtx->ValueBuilder;
  462. NUdf::TUnboxedValue value(NUdf::TUnboxedValuePod(list->Value.Get().Get()));
  463. auto newList = vb->TakeList(value, static_cast<ui64>(count));
  464. return New(list->CastCtx, list->ItemType, newList.AsBoxed(), list->Step);
  465. } PY_CATCH(nullptr)
  466. }
  467. PyObject* TPyLazyList::Skip(PyObject* self, PyObject* arg)
  468. {
  469. PY_TRY {
  470. TPyLazyList* list = Cast(self);
  471. Py_ssize_t count = CastIndex(arg, "skip");
  472. if (count < 0) {
  473. return nullptr;
  474. }
  475. count *= list->Step;
  476. NUdf::TUnboxedValue value(NUdf::TUnboxedValuePod(list->Value.Get().Get()));
  477. const auto newList = list->CastCtx->ValueBuilder->SkipList(value, static_cast<ui64>(count));
  478. return New(list->CastCtx, list->ItemType, newList.AsBoxed(), list->Step);
  479. } PY_CATCH(nullptr)
  480. }
  481. PyObject* TPyLazyList::HasFastLen(PyObject* self, PyObject* /* arg */)
  482. {
  483. PY_TRY {
  484. TPyLazyList* list = Cast(self);
  485. if (NUdf::TBoxedValueAccessor::HasFastListLength(*list->Value.Get())) {
  486. Py_RETURN_TRUE;
  487. }
  488. Py_RETURN_FALSE;
  489. } PY_CATCH(nullptr)
  490. }
  491. PyObject* TPyLazyList::HasItems(PyObject* self, PyObject* /* arg */)
  492. {
  493. PY_TRY {
  494. TPyLazyList* list = Cast(self);
  495. if (NUdf::TBoxedValueAccessor::HasListItems(*list->Value.Get())) {
  496. Py_RETURN_TRUE;
  497. }
  498. Py_RETURN_FALSE;
  499. } PY_CATCH(nullptr)
  500. }
  501. int TPyLazyList::Bool(PyObject* self)
  502. {
  503. PY_TRY {
  504. TPyLazyList* list = Cast(self);
  505. if (list->CachedLength == -1) {
  506. return NUdf::TBoxedValueAccessor::HasListItems(*list->Value.Get()) ? 1 : 0;
  507. } else {
  508. return list->CachedLength > 0 ? 1 : 0;
  509. }
  510. } PY_CATCH(-1)
  511. }
  512. //////////////////////////////////////////////////////////////////////////////
  513. // TPyLazyListIterator implementation
  514. //////////////////////////////////////////////////////////////////////////////
  515. PyObject* TPyLazyListIterator::New(TPyLazyList* list)
  516. {
  517. TPyLazyListIterator* listIter = new TPyLazyListIterator;
  518. PyObject_INIT(listIter, &PyLazyListIteratorType);
  519. listIter->List.Reset(list);
  520. listIter->Iterator.Set(list->CastCtx->PyCtx, NUdf::TBoxedValueAccessor::GetListIterator(*list->Value.Get()));
  521. listIter->Length = 0;
  522. listIter->CastCtx = list->CastCtx;
  523. return reinterpret_cast<PyObject*>(listIter);
  524. }
  525. PyObject* TPyLazyListIterator::Next(PyObject* self)
  526. {
  527. PY_TRY {
  528. TPyLazyListIterator* iter = Cast(self);
  529. TPyLazyList* list = iter->List.Get();
  530. NUdf::TUnboxedValue item;
  531. if (iter->Iterator.Get().Next(item)) {
  532. ++iter->Length;
  533. for (auto skip = list->Step; --skip && iter->Iterator.Get().Skip(); ++iter->Length)
  534. continue;
  535. return ToPyObject(list->CastCtx, list->ItemType, item).Release();
  536. }
  537. // store calculated list length after traverse over whole list
  538. if (list->CachedLength == -1) {
  539. list->CachedLength = iter->Length;
  540. }
  541. return nullptr;
  542. } PY_CATCH(nullptr)
  543. }
  544. //////////////////////////////////////////////////////////////////////////////
  545. // TPyThinList interface
  546. //////////////////////////////////////////////////////////////////////////////
  547. struct TPyThinList
  548. {
  549. using TPtr = NUdf::TRefCountedPtr<TPyThinList, TPyPtrOps<TPyThinList>>;
  550. PyObject_HEAD;
  551. TPyCastContext::TPtr CastCtx;
  552. const NUdf::TType* ItemType;
  553. TPyCleanupListItem<NUdf::IBoxedValuePtr> Value;
  554. const NUdf::TUnboxedValue* Elements;
  555. Py_ssize_t Length;
  556. Py_ssize_t Step;
  557. inline static TPyThinList* Cast(PyObject* o) {
  558. return reinterpret_cast<TPyThinList*>(o);
  559. }
  560. inline static void Dealloc(PyObject* self) {
  561. delete Cast(self);
  562. }
  563. static PyObject* New(
  564. const TPyCastContext::TPtr& castCtx,
  565. const NUdf::TType* itemType,
  566. NUdf::IBoxedValuePtr value = NUdf::IBoxedValuePtr(),
  567. const NUdf::TUnboxedValue* elements = nullptr,
  568. Py_ssize_t length = 0,
  569. Py_ssize_t step = 1);
  570. static int Bool(PyObject* self);
  571. static PyObject* Repr(PyObject* self);
  572. static PyObject* Iter(PyObject* self);
  573. static Py_ssize_t Len(PyObject* self);
  574. static PyObject* Subscript(PyObject* self, PyObject* slice);
  575. static PyObject* ToIndexDict(PyObject* self, PyObject* /* arg */);
  576. static PyObject* Reversed(PyObject* self, PyObject* /* arg */);
  577. static PyObject* Take(PyObject* self, PyObject* arg);
  578. static PyObject* Skip(PyObject* self, PyObject* arg);
  579. static PyObject* HasFastLen(PyObject* self, PyObject* /* arg */);
  580. static PyObject* HasItems(PyObject* self, PyObject* /* arg */);
  581. };
  582. PyMappingMethods ThinListMapping = {
  583. INIT_MEMBER(mp_length, TPyThinList::Len),
  584. INIT_MEMBER(mp_subscript, TPyThinList::Subscript),
  585. INIT_MEMBER(mp_ass_subscript, nullptr),
  586. };
  587. PyNumberMethods ThinListNumbering = {
  588. INIT_MEMBER(nb_add, nullptr),
  589. INIT_MEMBER(nb_subtract, nullptr),
  590. INIT_MEMBER(nb_multiply, nullptr),
  591. #if PY_MAJOR_VERSION < 3
  592. INIT_MEMBER(nb_divide, nullptr),
  593. #endif
  594. INIT_MEMBER(nb_remainder, nullptr),
  595. INIT_MEMBER(nb_divmod, nullptr),
  596. INIT_MEMBER(nb_power, nullptr),
  597. INIT_MEMBER(nb_negative, nullptr),
  598. INIT_MEMBER(nb_positive, nullptr),
  599. INIT_MEMBER(nb_absolute, nullptr),
  600. #if PY_MAJOR_VERSION >= 3
  601. INIT_MEMBER(nb_bool, TPyThinList::Bool),
  602. #else
  603. INIT_MEMBER(nb_nonzero, TPyThinList::Bool),
  604. #endif
  605. INIT_MEMBER(nb_invert, nullptr),
  606. INIT_MEMBER(nb_lshift, nullptr),
  607. INIT_MEMBER(nb_rshift, nullptr),
  608. INIT_MEMBER(nb_and, nullptr),
  609. INIT_MEMBER(nb_xor, nullptr),
  610. INIT_MEMBER(nb_or, nullptr),
  611. #if PY_MAJOR_VERSION < 3
  612. INIT_MEMBER(nb_coerce, nullptr),
  613. #endif
  614. INIT_MEMBER(nb_int, nullptr),
  615. #if PY_MAJOR_VERSION >= 3
  616. INIT_MEMBER(nb_reserved, nullptr),
  617. #else
  618. INIT_MEMBER(nb_long, nullptr),
  619. #endif
  620. INIT_MEMBER(nb_float, nullptr),
  621. #if PY_MAJOR_VERSION < 3
  622. INIT_MEMBER(nb_oct, nullptr),
  623. INIT_MEMBER(nb_hex, nullptr),
  624. #endif
  625. INIT_MEMBER(nb_inplace_add, nullptr),
  626. INIT_MEMBER(nb_inplace_subtract, nullptr),
  627. INIT_MEMBER(nb_inplace_multiply, nullptr),
  628. INIT_MEMBER(nb_inplace_remainder, nullptr),
  629. INIT_MEMBER(nb_inplace_power, nullptr),
  630. INIT_MEMBER(nb_inplace_lshift, nullptr),
  631. INIT_MEMBER(nb_inplace_rshift, nullptr),
  632. INIT_MEMBER(nb_inplace_and, nullptr),
  633. INIT_MEMBER(nb_inplace_xor, nullptr),
  634. INIT_MEMBER(nb_inplace_or, nullptr),
  635. INIT_MEMBER(nb_floor_divide, nullptr),
  636. INIT_MEMBER(nb_true_divide, nullptr),
  637. INIT_MEMBER(nb_inplace_floor_divide, nullptr),
  638. INIT_MEMBER(nb_inplace_true_divide, nullptr),
  639. INIT_MEMBER(nb_index, nullptr),
  640. #if PY_MAJOR_VERSION >= 3
  641. INIT_MEMBER(nb_matrix_multiply, nullptr),
  642. INIT_MEMBER(nb_inplace_matrix_multiply, nullptr),
  643. #endif
  644. };
  645. static PyMethodDef TPyThinListMethods[] = {
  646. { "__reversed__", TPyThinList::Reversed, METH_NOARGS, nullptr },
  647. { "to_index_dict", TPyThinList::ToIndexDict, METH_NOARGS, to_index_dict__doc__ },
  648. { "reversed", TPyThinList::Reversed, METH_NOARGS, reversed__doc__ },
  649. { "take", TPyThinList::Take, METH_O, take__doc__ },
  650. { "skip", TPyThinList::Skip, METH_O, skip__doc__ },
  651. { "has_fast_len", TPyThinList::HasFastLen, METH_NOARGS, has_fast_len__doc__ },
  652. { "has_items", TPyThinList::HasItems, METH_NOARGS, has_items__doc__ },
  653. { nullptr, nullptr, 0, nullptr } /* sentinel */
  654. };
  655. #if PY_MAJOR_VERSION >= 3
  656. #define Py_TPFLAGS_HAVE_ITER 0
  657. #endif
  658. PyTypeObject PyThinListType = {
  659. PyVarObject_HEAD_INIT(&PyType_Type, 0)
  660. INIT_MEMBER(tp_name , "yql.TList"),
  661. INIT_MEMBER(tp_basicsize , sizeof(TPyThinList)),
  662. INIT_MEMBER(tp_itemsize , 0),
  663. INIT_MEMBER(tp_dealloc , TPyThinList::Dealloc),
  664. #if PY_VERSION_HEX < 0x030800b4
  665. INIT_MEMBER(tp_print , nullptr),
  666. #else
  667. INIT_MEMBER(tp_vectorcall_offset, 0),
  668. #endif
  669. INIT_MEMBER(tp_getattr , nullptr),
  670. INIT_MEMBER(tp_setattr , nullptr),
  671. #if PY_MAJOR_VERSION >= 3
  672. INIT_MEMBER(tp_as_async , nullptr),
  673. #else
  674. INIT_MEMBER(tp_compare , nullptr),
  675. #endif
  676. INIT_MEMBER(tp_repr , TPyThinList::Repr),
  677. INIT_MEMBER(tp_as_number , &ThinListNumbering),
  678. INIT_MEMBER(tp_as_sequence , nullptr),
  679. INIT_MEMBER(tp_as_mapping , &ThinListMapping),
  680. INIT_MEMBER(tp_hash , nullptr),
  681. INIT_MEMBER(tp_call , nullptr),
  682. INIT_MEMBER(tp_str , nullptr),
  683. INIT_MEMBER(tp_getattro , nullptr),
  684. INIT_MEMBER(tp_setattro , nullptr),
  685. INIT_MEMBER(tp_as_buffer , nullptr),
  686. INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
  687. INIT_MEMBER(tp_doc , "yql.TList object"),
  688. INIT_MEMBER(tp_traverse , nullptr),
  689. INIT_MEMBER(tp_clear , nullptr),
  690. INIT_MEMBER(tp_richcompare , nullptr),
  691. INIT_MEMBER(tp_weaklistoffset , 0),
  692. INIT_MEMBER(tp_iter , TPyThinList::Iter),
  693. INIT_MEMBER(tp_iternext , nullptr),
  694. INIT_MEMBER(tp_methods , TPyThinListMethods),
  695. INIT_MEMBER(tp_members , nullptr),
  696. INIT_MEMBER(tp_getset , nullptr),
  697. INIT_MEMBER(tp_base , nullptr),
  698. INIT_MEMBER(tp_dict , nullptr),
  699. INIT_MEMBER(tp_descr_get , nullptr),
  700. INIT_MEMBER(tp_descr_set , nullptr),
  701. INIT_MEMBER(tp_dictoffset , 0),
  702. INIT_MEMBER(tp_init , nullptr),
  703. INIT_MEMBER(tp_alloc , nullptr),
  704. INIT_MEMBER(tp_new , nullptr),
  705. INIT_MEMBER(tp_free , nullptr),
  706. INIT_MEMBER(tp_is_gc , nullptr),
  707. INIT_MEMBER(tp_bases , nullptr),
  708. INIT_MEMBER(tp_mro , nullptr),
  709. INIT_MEMBER(tp_cache , nullptr),
  710. INIT_MEMBER(tp_subclasses , nullptr),
  711. INIT_MEMBER(tp_weaklist , nullptr),
  712. INIT_MEMBER(tp_del , nullptr),
  713. INIT_MEMBER(tp_version_tag , 0),
  714. #if PY_MAJOR_VERSION >= 3
  715. INIT_MEMBER(tp_finalize , nullptr),
  716. #endif
  717. #if PY_VERSION_HEX >= 0x030800b1
  718. INIT_MEMBER(tp_vectorcall , nullptr),
  719. #endif
  720. #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
  721. INIT_MEMBER(tp_print , nullptr),
  722. #endif
  723. };
  724. //////////////////////////////////////////////////////////////////////////////
  725. // TPyThinListIterator interface
  726. //////////////////////////////////////////////////////////////////////////////
  727. struct TPyThinListIterator
  728. {
  729. PyObject_HEAD;
  730. TPyThinList::TPtr List;
  731. const NUdf::TUnboxedValue* Elements;
  732. Py_ssize_t Count;
  733. inline static TPyThinListIterator* Cast(PyObject* o) {
  734. return reinterpret_cast<TPyThinListIterator*>(o);
  735. }
  736. inline static void Dealloc(PyObject* self) {
  737. delete Cast(self);
  738. }
  739. inline static PyObject* Repr(PyObject* self) {
  740. Y_UNUSED(self);
  741. return PyRepr("<yql.TListIterator>").Release();
  742. }
  743. static PyObject* New(TPyThinList* list);
  744. static PyObject* Next(PyObject* self);
  745. };
  746. PyTypeObject PyThinListIteratorType = {
  747. PyVarObject_HEAD_INIT(&PyType_Type, 0)
  748. INIT_MEMBER(tp_name , "yql.TListIterator"),
  749. INIT_MEMBER(tp_basicsize , sizeof(TPyThinListIterator)),
  750. INIT_MEMBER(tp_itemsize , 0),
  751. INIT_MEMBER(tp_dealloc , TPyThinListIterator::Dealloc),
  752. #if PY_VERSION_HEX < 0x030800b4
  753. INIT_MEMBER(tp_print , nullptr),
  754. #else
  755. INIT_MEMBER(tp_vectorcall_offset, 0),
  756. #endif
  757. INIT_MEMBER(tp_getattr , nullptr),
  758. INIT_MEMBER(tp_setattr , nullptr),
  759. #if PY_MAJOR_VERSION >= 3
  760. INIT_MEMBER(tp_as_async , nullptr),
  761. #else
  762. INIT_MEMBER(tp_compare , nullptr),
  763. #endif
  764. INIT_MEMBER(tp_repr , TPyThinListIterator::Repr),
  765. INIT_MEMBER(tp_as_number , nullptr),
  766. INIT_MEMBER(tp_as_sequence , nullptr),
  767. INIT_MEMBER(tp_as_mapping , nullptr),
  768. INIT_MEMBER(tp_hash , nullptr),
  769. INIT_MEMBER(tp_call , nullptr),
  770. INIT_MEMBER(tp_str , nullptr),
  771. INIT_MEMBER(tp_getattro , nullptr),
  772. INIT_MEMBER(tp_setattro , nullptr),
  773. INIT_MEMBER(tp_as_buffer , nullptr),
  774. INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
  775. INIT_MEMBER(tp_doc , "yql.ListIterator object"),
  776. INIT_MEMBER(tp_traverse , nullptr),
  777. INIT_MEMBER(tp_clear , nullptr),
  778. INIT_MEMBER(tp_richcompare , nullptr),
  779. INIT_MEMBER(tp_weaklistoffset , 0),
  780. INIT_MEMBER(tp_iter , PyObject_SelfIter),
  781. INIT_MEMBER(tp_iternext , TPyThinListIterator::Next),
  782. INIT_MEMBER(tp_methods , nullptr),
  783. INIT_MEMBER(tp_members , nullptr),
  784. INIT_MEMBER(tp_getset , nullptr),
  785. INIT_MEMBER(tp_base , nullptr),
  786. INIT_MEMBER(tp_dict , nullptr),
  787. INIT_MEMBER(tp_descr_get , nullptr),
  788. INIT_MEMBER(tp_descr_set , nullptr),
  789. INIT_MEMBER(tp_dictoffset , 0),
  790. INIT_MEMBER(tp_init , nullptr),
  791. INIT_MEMBER(tp_alloc , nullptr),
  792. INIT_MEMBER(tp_new , nullptr),
  793. INIT_MEMBER(tp_free , nullptr),
  794. INIT_MEMBER(tp_is_gc , nullptr),
  795. INIT_MEMBER(tp_bases , nullptr),
  796. INIT_MEMBER(tp_mro , nullptr),
  797. INIT_MEMBER(tp_cache , nullptr),
  798. INIT_MEMBER(tp_subclasses , nullptr),
  799. INIT_MEMBER(tp_weaklist , nullptr),
  800. INIT_MEMBER(tp_del , nullptr),
  801. INIT_MEMBER(tp_version_tag , 0),
  802. #if PY_MAJOR_VERSION >= 3
  803. INIT_MEMBER(tp_finalize , nullptr),
  804. #endif
  805. #if PY_VERSION_HEX >= 0x030800b1
  806. INIT_MEMBER(tp_vectorcall , nullptr),
  807. #endif
  808. #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
  809. INIT_MEMBER(tp_print , nullptr),
  810. #endif
  811. };
  812. //////////////////////////////////////////////////////////////////////////////
  813. // TPyThinList implementation
  814. //////////////////////////////////////////////////////////////////////////////
  815. PyObject* TPyThinList::New(
  816. const TPyCastContext::TPtr& castCtx,
  817. const NUdf::TType* itemType,
  818. NUdf::IBoxedValuePtr value,
  819. const NUdf::TUnboxedValue* elements,
  820. Py_ssize_t length,
  821. Py_ssize_t step)
  822. {
  823. TPyThinList* list = new TPyThinList;
  824. PyObject_INIT(list, &PyThinListType);
  825. list->CastCtx = castCtx;
  826. list->ItemType = itemType;
  827. list->Value.Set(castCtx->PyCtx, value);
  828. list->Elements = elements;
  829. list->Length = length;
  830. list->Step = step;
  831. return reinterpret_cast<PyObject*>(list);
  832. }
  833. PyObject* TPyThinList::Repr(PyObject*)
  834. {
  835. return PyRepr("<yql.TList>").Release();
  836. }
  837. PyObject* TPyThinList::Iter(PyObject* self)
  838. {
  839. PY_TRY {
  840. TPyThinList* list = Cast(self);
  841. return TPyThinListIterator::New(list);
  842. } PY_CATCH(nullptr)
  843. }
  844. Py_ssize_t TPyThinList::Len(PyObject* self)
  845. {
  846. return Cast(self)->Length;
  847. }
  848. PyObject* TPyThinList::Subscript(PyObject* self, PyObject* slice)
  849. {
  850. PY_TRY {
  851. TPyThinList* list = Cast(self);
  852. const auto vb = list->CastCtx->ValueBuilder;
  853. if (PyIndex_Check(slice)) {
  854. Py_ssize_t index = PyNumber_AsSsize_t(slice, PyExc_IndexError);
  855. if (index < 0) {
  856. index += list->Length;
  857. }
  858. if (index < 0 || index >= list->Length) {
  859. const TPyObjectPtr error = PyUnicode_FromFormat("index %zd out of bounds, list size: %zd", index, list->Length);
  860. PyErr_SetObject(PyExc_IndexError, error.Get());
  861. return nullptr;
  862. }
  863. if (list->Step > 0) {
  864. index *= list->Step;
  865. } else {
  866. index = list->Length - ++index;
  867. index *= -list->Step;
  868. }
  869. return ToPyObject(list->CastCtx, list->ItemType, list->Elements[index]).Release();
  870. }
  871. if (PySlice_Check(slice)) {
  872. Py_ssize_t start, stop, step, size;
  873. if (PySlice_GetIndicesEx(SLICEOBJ(slice), list->Length, &start, &stop, &step, &size) < 0) {
  874. return nullptr;
  875. }
  876. if (!step) {
  877. PyErr_SetString(PyExc_ValueError, "slice step cannot be zero");
  878. return nullptr;
  879. }
  880. if (size > 0) {
  881. const Py_ssize_t skip = list->Step * (list->Step > 0 ?
  882. (step > 0 ? start : start + step * (size - 1)):
  883. (step > 0 ? stop : start + 1) - list->Length);
  884. return New(list->CastCtx, list->ItemType, list->Value.Get(), list->Elements + skip, size, step * list->Step);
  885. } else {
  886. return New(list->CastCtx, list->ItemType, list->Value.Get());
  887. }
  888. }
  889. const TPyObjectPtr type = PyObject_Type(slice);
  890. const TPyObjectPtr repr = PyObject_Repr(type.Get());
  891. const TPyObjectPtr error = PyUnicode_FromFormat("Unsupported slice object type: %R", repr.Get());
  892. PyErr_SetObject(PyExc_TypeError, error.Get());
  893. return nullptr;
  894. } PY_CATCH(nullptr)
  895. }
  896. #undef SLICEOBJ
  897. PyObject* TPyThinList::ToIndexDict(PyObject* self, PyObject* /* arg */)
  898. {
  899. PY_TRY {
  900. TPyThinList* list = Cast(self);
  901. const auto dict = list->CastCtx->ValueBuilder->ToIndexDict(NUdf::TUnboxedValuePod(list->Value.Get().Get()));
  902. return ToPyLazyDict(list->CastCtx, nullptr, list->ItemType, dict).Release();
  903. } PY_CATCH(nullptr)
  904. }
  905. PyObject* TPyThinList::Reversed(PyObject* self, PyObject* /* arg */)
  906. {
  907. PY_TRY {
  908. TPyThinList* list = Cast(self);
  909. return New(list->CastCtx, list->ItemType, list->Value.Get(), list->Elements, list->Length, -list->Step);
  910. } PY_CATCH(nullptr)
  911. }
  912. PyObject* TPyThinList::Take(PyObject* self, PyObject* arg)
  913. {
  914. PY_TRY {
  915. TPyThinList* list = Cast(self);
  916. const Py_ssize_t count = CastIndex(arg, "take");
  917. if (count < 0) {
  918. return nullptr;
  919. }
  920. if (const auto size = std::min(count, list->Length)) {
  921. return New(list->CastCtx, list->ItemType, list->Value.Get(), list->Step > 0 ? list->Elements : list->Elements + list->Length + size * list->Step, size, list->Step);
  922. } else {
  923. return New(list->CastCtx, list->ItemType, list->Value.Get());
  924. }
  925. } PY_CATCH(nullptr)
  926. }
  927. PyObject* TPyThinList::Skip(PyObject* self, PyObject* arg)
  928. {
  929. PY_TRY {
  930. TPyThinList* list = Cast(self);
  931. const Py_ssize_t count = CastIndex(arg, "skip");
  932. if (count < 0) {
  933. return nullptr;
  934. }
  935. if (const auto size = std::max(list->Length - count, Py_ssize_t(0))) {
  936. return New(list->CastCtx, list->ItemType, list->Value.Get(), list->Step > 0 ? list->Elements + count * list->Step : list->Elements, size, list->Step);
  937. } else {
  938. return New(list->CastCtx, list->ItemType);
  939. }
  940. } PY_CATCH(nullptr)
  941. }
  942. PyObject* TPyThinList::HasFastLen(PyObject* self, PyObject* /* arg */)
  943. {
  944. Py_RETURN_TRUE;
  945. }
  946. PyObject* TPyThinList::HasItems(PyObject* self, PyObject* /* arg */)
  947. {
  948. if (Cast(self)->Length > 0)
  949. Py_RETURN_TRUE;
  950. else
  951. Py_RETURN_FALSE;
  952. }
  953. int TPyThinList::Bool(PyObject* self)
  954. {
  955. return Cast(self)->Length > 0 ? 1 : 0;
  956. }
  957. //////////////////////////////////////////////////////////////////////////////
  958. // TPyThinListIterator implementation
  959. //////////////////////////////////////////////////////////////////////////////
  960. PyObject* TPyThinListIterator::New(TPyThinList* list)
  961. {
  962. TPyThinListIterator* listIter = new TPyThinListIterator;
  963. PyObject_INIT(listIter, &PyThinListIteratorType);
  964. listIter->List.Reset(list);
  965. listIter->Elements = list->Step > 0 ? list->Elements - list->Step : list->Elements - list->Length * list->Step;
  966. listIter->Count = list->Length;
  967. return reinterpret_cast<PyObject*>(listIter);
  968. }
  969. PyObject* TPyThinListIterator::Next(PyObject* self)
  970. {
  971. PY_TRY {
  972. TPyThinListIterator* iter = Cast(self);
  973. if (iter->Count) {
  974. --iter->Count;
  975. TPyThinList* list = iter->List.Get();
  976. return ToPyObject(list->CastCtx, list->ItemType, *(iter->Elements += list->Step)).Release();
  977. }
  978. return nullptr;
  979. } PY_CATCH(nullptr)
  980. }
  981. TPyObjectPtr ToPyLazyList(
  982. const TPyCastContext::TPtr& castCtx,
  983. const NUdf::TType* itemType,
  984. const NUdf::TUnboxedValuePod& value)
  985. {
  986. if (const auto elements = value.GetElements()) {
  987. return TPyThinList::New(castCtx, itemType, value.AsBoxed(), elements, value.GetListLength());
  988. } else {
  989. return TPyLazyList::New(castCtx, itemType, value.AsBoxed());
  990. }
  991. }
  992. } // namspace NPython