123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116 |
- #include "py_list.h"
- #include "py_dict.h"
- #include "py_cast.h"
- #include "py_errors.h"
- #include "py_utils.h"
- #include <yql/essentials/public/udf/udf_value.h>
- #include <yql/essentials/public/udf/udf_value_builder.h>
- using namespace NKikimr;
- #if PY_MAJOR_VERSION >= 3
- #define SLICEOBJ(obj) obj
- #else
- #define SLICEOBJ(obj) (reinterpret_cast<PySliceObject*>(obj))
- // See details about need for backports in ya.make
- #include "py27_backports.h"
- #endif
- namespace NPython {
- namespace {
- inline Py_ssize_t CastIndex(PyObject* key, const char* name)
- {
- Py_ssize_t index = -1;
- if (PyIndex_Check(key)) {
- index = PyNumber_AsSsize_t(key, PyExc_IndexError);
- }
- if (index < 0) {
- const TPyObjectPtr value = PyUnicode_FromFormat("argument of %s must be positive integer or long", name);
- PyErr_SetObject(PyExc_IndexError, value.Get());
- }
- return index;
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- // TPyLazyList interface
- //////////////////////////////////////////////////////////////////////////////
- struct TPyLazyList
- {
- using TPtr = NUdf::TRefCountedPtr<TPyLazyList, TPyPtrOps<TPyLazyList>>;
- PyObject_HEAD;
- TPyCastContext::TPtr CastCtx;
- const NUdf::TType* ItemType;
- TPyCleanupListItem<NUdf::IBoxedValuePtr> Value;
- TPyCleanupListItem<NUdf::IBoxedValuePtr> Dict;
- Py_ssize_t Step;
- Py_ssize_t CachedLength;
- inline static TPyLazyList* Cast(PyObject* o) {
- return reinterpret_cast<TPyLazyList*>(o);
- }
- inline static void Dealloc(PyObject* self) {
- delete Cast(self);
- }
- static PyObject* New(
- const TPyCastContext::TPtr& castCtx,
- const NUdf::TType* itemType,
- NUdf::IBoxedValuePtr value,
- Py_ssize_t step = 1,
- Py_ssize_t size = -1);
- static int Bool(PyObject* self);
- static PyObject* Repr(PyObject* self);
- static PyObject* Iter(PyObject* self);
- static Py_ssize_t Len(PyObject* self);
- static PyObject* Subscript(PyObject* self, PyObject* slice);
- static PyObject* ToIndexDict(PyObject* self, PyObject* /* arg */);
- static PyObject* Reversed(PyObject* self, PyObject* /* arg */);
- static PyObject* Take(PyObject* self, PyObject* arg);
- static PyObject* Skip(PyObject* self, PyObject* arg);
- static PyObject* HasFastLen(PyObject* self, PyObject* /* arg */);
- static PyObject* HasItems(PyObject* self, PyObject* /* arg */);
- };
- PyMappingMethods LazyListMapping = {
- INIT_MEMBER(mp_length, TPyLazyList::Len),
- INIT_MEMBER(mp_subscript, TPyLazyList::Subscript),
- INIT_MEMBER(mp_ass_subscript, nullptr),
- };
- PyNumberMethods LazyListNumbering = {
- INIT_MEMBER(nb_add, nullptr),
- INIT_MEMBER(nb_subtract, nullptr),
- INIT_MEMBER(nb_multiply, nullptr),
- #if PY_MAJOR_VERSION < 3
- INIT_MEMBER(nb_divide, nullptr),
- #endif
- INIT_MEMBER(nb_remainder, nullptr),
- INIT_MEMBER(nb_divmod, nullptr),
- INIT_MEMBER(nb_power, nullptr),
- INIT_MEMBER(nb_negative, nullptr),
- INIT_MEMBER(nb_positive, nullptr),
- INIT_MEMBER(nb_absolute, nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(nb_bool, TPyLazyList::Bool),
- #else
- INIT_MEMBER(nb_nonzero, TPyLazyList::Bool),
- #endif
- INIT_MEMBER(nb_invert, nullptr),
- INIT_MEMBER(nb_lshift, nullptr),
- INIT_MEMBER(nb_rshift, nullptr),
- INIT_MEMBER(nb_and, nullptr),
- INIT_MEMBER(nb_xor, nullptr),
- INIT_MEMBER(nb_or, nullptr),
- #if PY_MAJOR_VERSION < 3
- INIT_MEMBER(nb_coerce, nullptr),
- #endif
- INIT_MEMBER(nb_int, nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(nb_reserved, nullptr),
- #else
- INIT_MEMBER(nb_long, nullptr),
- #endif
- INIT_MEMBER(nb_float, nullptr),
- #if PY_MAJOR_VERSION < 3
- INIT_MEMBER(nb_oct, nullptr),
- INIT_MEMBER(nb_hex, nullptr),
- #endif
- INIT_MEMBER(nb_inplace_add, nullptr),
- INIT_MEMBER(nb_inplace_subtract, nullptr),
- INIT_MEMBER(nb_inplace_multiply, nullptr),
- INIT_MEMBER(nb_inplace_remainder, nullptr),
- INIT_MEMBER(nb_inplace_power, nullptr),
- INIT_MEMBER(nb_inplace_lshift, nullptr),
- INIT_MEMBER(nb_inplace_rshift, nullptr),
- INIT_MEMBER(nb_inplace_and, nullptr),
- INIT_MEMBER(nb_inplace_xor, nullptr),
- INIT_MEMBER(nb_inplace_or, nullptr),
- INIT_MEMBER(nb_floor_divide, nullptr),
- INIT_MEMBER(nb_true_divide, nullptr),
- INIT_MEMBER(nb_inplace_floor_divide, nullptr),
- INIT_MEMBER(nb_inplace_true_divide, nullptr),
- INIT_MEMBER(nb_index, nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(nb_matrix_multiply, nullptr),
- INIT_MEMBER(nb_inplace_matrix_multiply, nullptr),
- #endif
- };
- PyDoc_STRVAR(reversed__doc__, "DEPRECATED: use reversed(list) or list[::-1] instead.");
- PyDoc_STRVAR(take__doc__, "DEPRECATED: use slice list[:n] instead.");
- PyDoc_STRVAR(skip__doc__, "DEPRECATED: use slice list[n:] instead.");
- PyDoc_STRVAR(to_index_dict__doc__, "DEPRECATED: use list[n] instead.");
- PyDoc_STRVAR(has_fast_len__doc__, "DEPRECATED: do not use.");
- PyDoc_STRVAR(has_items__doc__, "DEPRECATED: test list as bool instead.");
- static PyMethodDef TPyLazyListMethods[] = {
- { "__reversed__", TPyLazyList::Reversed, METH_NOARGS, nullptr },
- { "to_index_dict", TPyLazyList::ToIndexDict, METH_NOARGS, to_index_dict__doc__ },
- { "reversed", TPyLazyList::Reversed, METH_NOARGS, reversed__doc__ },
- { "take", TPyLazyList::Take, METH_O, take__doc__ },
- { "skip", TPyLazyList::Skip, METH_O, skip__doc__ },
- { "has_fast_len", TPyLazyList::HasFastLen, METH_NOARGS, has_fast_len__doc__ },
- { "has_items", TPyLazyList::HasItems, METH_NOARGS, has_items__doc__ },
- { nullptr, nullptr, 0, nullptr } /* sentinel */
- };
- #if PY_MAJOR_VERSION >= 3
- #define Py_TPFLAGS_HAVE_ITER 0
- #endif
- PyTypeObject PyLazyListType = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- INIT_MEMBER(tp_name , "yql.TList"),
- INIT_MEMBER(tp_basicsize , sizeof(TPyLazyList)),
- INIT_MEMBER(tp_itemsize , 0),
- INIT_MEMBER(tp_dealloc , TPyLazyList::Dealloc),
- #if PY_VERSION_HEX < 0x030800b4
- INIT_MEMBER(tp_print , nullptr),
- #else
- INIT_MEMBER(tp_vectorcall_offset, 0),
- #endif
- INIT_MEMBER(tp_getattr , nullptr),
- INIT_MEMBER(tp_setattr , nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(tp_as_async , nullptr),
- #else
- INIT_MEMBER(tp_compare , nullptr),
- #endif
- INIT_MEMBER(tp_repr , TPyLazyList::Repr),
- INIT_MEMBER(tp_as_number , &LazyListNumbering),
- INIT_MEMBER(tp_as_sequence , nullptr),
- INIT_MEMBER(tp_as_mapping , &LazyListMapping),
- INIT_MEMBER(tp_hash , nullptr),
- INIT_MEMBER(tp_call , nullptr),
- INIT_MEMBER(tp_str , nullptr),
- INIT_MEMBER(tp_getattro , nullptr),
- INIT_MEMBER(tp_setattro , nullptr),
- INIT_MEMBER(tp_as_buffer , nullptr),
- INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
- INIT_MEMBER(tp_doc , "yql.TList object"),
- INIT_MEMBER(tp_traverse , nullptr),
- INIT_MEMBER(tp_clear , nullptr),
- INIT_MEMBER(tp_richcompare , nullptr),
- INIT_MEMBER(tp_weaklistoffset , 0),
- INIT_MEMBER(tp_iter , TPyLazyList::Iter),
- INIT_MEMBER(tp_iternext , nullptr),
- INIT_MEMBER(tp_methods , TPyLazyListMethods),
- INIT_MEMBER(tp_members , nullptr),
- INIT_MEMBER(tp_getset , nullptr),
- INIT_MEMBER(tp_base , nullptr),
- INIT_MEMBER(tp_dict , nullptr),
- INIT_MEMBER(tp_descr_get , nullptr),
- INIT_MEMBER(tp_descr_set , nullptr),
- INIT_MEMBER(tp_dictoffset , 0),
- INIT_MEMBER(tp_init , nullptr),
- INIT_MEMBER(tp_alloc , nullptr),
- INIT_MEMBER(tp_new , nullptr),
- INIT_MEMBER(tp_free , nullptr),
- INIT_MEMBER(tp_is_gc , nullptr),
- INIT_MEMBER(tp_bases , nullptr),
- INIT_MEMBER(tp_mro , nullptr),
- INIT_MEMBER(tp_cache , nullptr),
- INIT_MEMBER(tp_subclasses , nullptr),
- INIT_MEMBER(tp_weaklist , nullptr),
- INIT_MEMBER(tp_del , nullptr),
- INIT_MEMBER(tp_version_tag , 0),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(tp_finalize , nullptr),
- #endif
- #if PY_VERSION_HEX >= 0x030800b1
- INIT_MEMBER(tp_vectorcall , nullptr),
- #endif
- #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
- INIT_MEMBER(tp_print , nullptr),
- #endif
- };
- //////////////////////////////////////////////////////////////////////////////
- // TPyLazyListIterator interface
- //////////////////////////////////////////////////////////////////////////////
- struct TPyLazyListIterator
- {
- PyObject_HEAD;
- TPyLazyList::TPtr List;
- TPyCleanupListItem<NUdf::TUnboxedValue> Iterator;
- Py_ssize_t Length;
- TPyCastContext::TPtr CastCtx;
- inline static TPyLazyListIterator* Cast(PyObject* o) {
- return reinterpret_cast<TPyLazyListIterator*>(o);
- }
- inline static void Dealloc(PyObject* self) {
- auto obj = Cast(self);
- auto ctx = obj->CastCtx;
- ctx->MemoryLock->Acquire();
- delete obj;
- ctx->MemoryLock->Release();
- }
- inline static PyObject* Repr(PyObject* self) {
- Y_UNUSED(self);
- return PyRepr("<yql.TListIterator>").Release();
- }
- static PyObject* New(TPyLazyList* list);
- static PyObject* Next(PyObject* self);
- };
- PyTypeObject PyLazyListIteratorType = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- INIT_MEMBER(tp_name , "yql.TListIterator"),
- INIT_MEMBER(tp_basicsize , sizeof(TPyLazyListIterator)),
- INIT_MEMBER(tp_itemsize , 0),
- INIT_MEMBER(tp_dealloc , TPyLazyListIterator::Dealloc),
- #if PY_VERSION_HEX < 0x030800b4
- INIT_MEMBER(tp_print , nullptr),
- #else
- INIT_MEMBER(tp_vectorcall_offset, 0),
- #endif
- INIT_MEMBER(tp_getattr , nullptr),
- INIT_MEMBER(tp_setattr , nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(tp_as_async , nullptr),
- #else
- INIT_MEMBER(tp_compare , nullptr),
- #endif
- INIT_MEMBER(tp_repr , TPyLazyListIterator::Repr),
- INIT_MEMBER(tp_as_number , nullptr),
- INIT_MEMBER(tp_as_sequence , nullptr),
- INIT_MEMBER(tp_as_mapping , nullptr),
- INIT_MEMBER(tp_hash , nullptr),
- INIT_MEMBER(tp_call , nullptr),
- INIT_MEMBER(tp_str , nullptr),
- INIT_MEMBER(tp_getattro , nullptr),
- INIT_MEMBER(tp_setattro , nullptr),
- INIT_MEMBER(tp_as_buffer , nullptr),
- INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
- INIT_MEMBER(tp_doc , "yql.ListIterator object"),
- INIT_MEMBER(tp_traverse , nullptr),
- INIT_MEMBER(tp_clear , nullptr),
- INIT_MEMBER(tp_richcompare , nullptr),
- INIT_MEMBER(tp_weaklistoffset , 0),
- INIT_MEMBER(tp_iter , PyObject_SelfIter),
- INIT_MEMBER(tp_iternext , TPyLazyListIterator::Next),
- INIT_MEMBER(tp_methods , nullptr),
- INIT_MEMBER(tp_members , nullptr),
- INIT_MEMBER(tp_getset , nullptr),
- INIT_MEMBER(tp_base , nullptr),
- INIT_MEMBER(tp_dict , nullptr),
- INIT_MEMBER(tp_descr_get , nullptr),
- INIT_MEMBER(tp_descr_set , nullptr),
- INIT_MEMBER(tp_dictoffset , 0),
- INIT_MEMBER(tp_init , nullptr),
- INIT_MEMBER(tp_alloc , nullptr),
- INIT_MEMBER(tp_new , nullptr),
- INIT_MEMBER(tp_free , nullptr),
- INIT_MEMBER(tp_is_gc , nullptr),
- INIT_MEMBER(tp_bases , nullptr),
- INIT_MEMBER(tp_mro , nullptr),
- INIT_MEMBER(tp_cache , nullptr),
- INIT_MEMBER(tp_subclasses , nullptr),
- INIT_MEMBER(tp_weaklist , nullptr),
- INIT_MEMBER(tp_del , nullptr),
- INIT_MEMBER(tp_version_tag , 0),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(tp_finalize , nullptr),
- #endif
- #if PY_VERSION_HEX >= 0x030800b1
- INIT_MEMBER(tp_vectorcall , nullptr),
- #endif
- #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
- INIT_MEMBER(tp_print , nullptr),
- #endif
- };
- //////////////////////////////////////////////////////////////////////////////
- // TPyLazyList implementation
- //////////////////////////////////////////////////////////////////////////////
- PyObject* TPyLazyList::New(
- const TPyCastContext::TPtr& castCtx,
- const NUdf::TType* itemType,
- NUdf::IBoxedValuePtr value,
- Py_ssize_t step,
- Py_ssize_t size)
- {
- TPyLazyList* list = new TPyLazyList;
- PyObject_INIT(list, &PyLazyListType);
- list->CastCtx = castCtx;
- list->ItemType = itemType;
- list->Value.Set(castCtx->PyCtx, value);
- list->Step = step;
- list->CachedLength = size;
- return reinterpret_cast<PyObject*>(list);
- }
- PyObject* TPyLazyList::Repr(PyObject*)
- {
- return PyRepr("<yql.TList>").Release();
- }
- PyObject* TPyLazyList::Iter(PyObject* self)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- return TPyLazyListIterator::New(list);
- } PY_CATCH(nullptr)
- }
- Py_ssize_t TPyLazyList::Len(PyObject* self)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- if (list->CachedLength == -1) {
- list->CachedLength = static_cast<Py_ssize_t>(NUdf::TBoxedValueAccessor::GetListLength(*list->Value.Get()));
- }
- return (list->CachedLength + list->Step - 1) / list->Step;
- } PY_CATCH(-1)
- }
- PyObject* TPyLazyList::Subscript(PyObject* self, PyObject* slice)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- const auto vb = list->CastCtx->ValueBuilder;
- if (PyIndex_Check(slice)) {
- Py_ssize_t index = PyNumber_AsSsize_t(slice, PyExc_IndexError);
- if (!list->Dict.IsSet()) {
- list->Dict.Set(list->CastCtx->PyCtx, vb->ToIndexDict(NUdf::TUnboxedValuePod(list->Value.Get().Get())).AsBoxed());
- }
- if (index < 0) {
- if (list->CachedLength == -1) {
- list->CachedLength = static_cast<Py_ssize_t>(NUdf::TBoxedValueAccessor::GetDictLength(*list->Dict.Get()));
- }
- ++index *= list->Step;
- --index += list->CachedLength;
- } else {
- index *= list->Step;
- }
- if (index < 0 || (list->CachedLength != -1 && index >= list->CachedLength)) {
- const TPyObjectPtr error = PyUnicode_FromFormat("index %zd out of bounds, list size: %zd", index, list->CachedLength);
- PyErr_SetObject(PyExc_IndexError, error.Get());
- return nullptr;
- }
- if (const auto item = NUdf::TBoxedValueAccessor::Lookup(*list->Dict.Get(), NUdf::TUnboxedValuePod(ui64(index)))) {
- return ToPyObject(list->CastCtx, list->ItemType, item.GetOptionalValue()).Release();
- }
- const TPyObjectPtr error = PyUnicode_FromFormat("index %zd out of bounds", index);
- PyErr_SetObject(PyExc_IndexError, error.Get());
- return nullptr;
- }
- if (PySlice_Check(slice)) {
- Py_ssize_t start, stop, step, size;
- if (list->CachedLength >= 0) {
- if (PySlice_GetIndicesEx(SLICEOBJ(slice), (list->CachedLength + list->Step - 1) / list->Step, &start, &stop, &step, &size) < 0) {
- return nullptr;
- }
- } else {
- if (PySlice_Unpack(slice, &start, &stop, &step) < 0) {
- return nullptr;
- }
- if (step < -1 || step > 1 || (start < 0 && start > PY_SSIZE_T_MIN) || (stop < 0 && stop > PY_SSIZE_T_MIN)) {
- list->CachedLength = static_cast<Py_ssize_t>(NUdf::TBoxedValueAccessor::GetListLength(*list->Value.Get()));
- size = PySlice_AdjustIndices((list->CachedLength + list->Step - 1) / list->Step, &start, &stop, step);
- } else {
- size = PySlice_AdjustIndices(PY_SSIZE_T_MAX, &start, &stop, step);
- }
- }
- if (!step) {
- PyErr_SetString(PyExc_ValueError, "slice step cannot be zero");
- return nullptr;
- }
- const Py_ssize_t hi = PY_SSIZE_T_MAX / list->Step;
- const Py_ssize_t lo = PY_SSIZE_T_MIN / list->Step;
- step = step > lo && step < hi ? step * list->Step : (step > 0 ? PY_SSIZE_T_MAX : PY_SSIZE_T_MIN);
- NUdf::TUnboxedValue newList;
- if (size > 0) {
- size = step > 0 ?
- (size < PY_SSIZE_T_MAX / step ? --size * step + 1 : PY_SSIZE_T_MAX):
- (size < PY_SSIZE_T_MAX / -step ? --size * -step + 1 : PY_SSIZE_T_MAX);
- start = start < hi ? start * list->Step : PY_SSIZE_T_MAX;
- const Py_ssize_t skip = step > 0 ? start : start - size + 1;
- newList = NUdf::TUnboxedValuePod(list->Value.Get().Get());
- if (skip > 0) {
- newList = vb->SkipList(newList, skip);
- }
- if (size < PY_SSIZE_T_MAX && (list->CachedLength == -1 || list->CachedLength - skip > size)) {
- newList = vb->TakeList(newList, size);
- }
- if (step < 0) {
- step = -step;
- newList = vb->ReverseList(newList);
- }
- } else {
- newList = vb->NewEmptyList();
- }
- return New(list->CastCtx, list->ItemType, newList.AsBoxed(), step, size);
- }
- const TPyObjectPtr type = PyObject_Type(slice);
- const TPyObjectPtr repr = PyObject_Repr(type.Get());
- const TPyObjectPtr error = PyUnicode_FromFormat("Unsupported slice object type: %R", repr.Get());
- PyErr_SetObject(PyExc_TypeError, error.Get());
- return nullptr;
- } PY_CATCH(nullptr)
- }
- PyObject* TPyLazyList::ToIndexDict(PyObject* self, PyObject* /* arg */)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- if (!list->Dict.IsSet()) {
- list->Dict.Set(list->CastCtx->PyCtx, list->CastCtx->ValueBuilder->ToIndexDict(NUdf::TUnboxedValuePod(list->Value.Get().Get())).AsBoxed());
- }
- return ToPyLazyDict(list->CastCtx, nullptr, list->ItemType, NUdf::TUnboxedValuePod(list->Dict.Get().Get())).Release();
- } PY_CATCH(nullptr)
- }
- PyObject* TPyLazyList::Reversed(PyObject* self, PyObject* /* arg */)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- const auto newList = list->CastCtx->ValueBuilder->ReverseList(NUdf::TUnboxedValuePod(list->Value.Get().Get()));
- return New(list->CastCtx, list->ItemType, newList.AsBoxed(), list->Step);
- } PY_CATCH(nullptr)
- }
- PyObject* TPyLazyList::Take(PyObject* self, PyObject* arg)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- Py_ssize_t count = CastIndex(arg, "take");
- if (count < 0) {
- return nullptr;
- }
- count *= list->Step;
- auto vb = list->CastCtx->ValueBuilder;
- NUdf::TUnboxedValue value(NUdf::TUnboxedValuePod(list->Value.Get().Get()));
- auto newList = vb->TakeList(value, static_cast<ui64>(count));
- return New(list->CastCtx, list->ItemType, newList.AsBoxed(), list->Step);
- } PY_CATCH(nullptr)
- }
- PyObject* TPyLazyList::Skip(PyObject* self, PyObject* arg)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- Py_ssize_t count = CastIndex(arg, "skip");
- if (count < 0) {
- return nullptr;
- }
- count *= list->Step;
- NUdf::TUnboxedValue value(NUdf::TUnboxedValuePod(list->Value.Get().Get()));
- const auto newList = list->CastCtx->ValueBuilder->SkipList(value, static_cast<ui64>(count));
- return New(list->CastCtx, list->ItemType, newList.AsBoxed(), list->Step);
- } PY_CATCH(nullptr)
- }
- PyObject* TPyLazyList::HasFastLen(PyObject* self, PyObject* /* arg */)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- if (NUdf::TBoxedValueAccessor::HasFastListLength(*list->Value.Get())) {
- Py_RETURN_TRUE;
- }
- Py_RETURN_FALSE;
- } PY_CATCH(nullptr)
- }
- PyObject* TPyLazyList::HasItems(PyObject* self, PyObject* /* arg */)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- if (NUdf::TBoxedValueAccessor::HasListItems(*list->Value.Get())) {
- Py_RETURN_TRUE;
- }
- Py_RETURN_FALSE;
- } PY_CATCH(nullptr)
- }
- int TPyLazyList::Bool(PyObject* self)
- {
- PY_TRY {
- TPyLazyList* list = Cast(self);
- if (list->CachedLength == -1) {
- return NUdf::TBoxedValueAccessor::HasListItems(*list->Value.Get()) ? 1 : 0;
- } else {
- return list->CachedLength > 0 ? 1 : 0;
- }
- } PY_CATCH(-1)
- }
- //////////////////////////////////////////////////////////////////////////////
- // TPyLazyListIterator implementation
- //////////////////////////////////////////////////////////////////////////////
- PyObject* TPyLazyListIterator::New(TPyLazyList* list)
- {
- TPyLazyListIterator* listIter = new TPyLazyListIterator;
- PyObject_INIT(listIter, &PyLazyListIteratorType);
- listIter->List.Reset(list);
- listIter->Iterator.Set(list->CastCtx->PyCtx, NUdf::TBoxedValueAccessor::GetListIterator(*list->Value.Get()));
- listIter->Length = 0;
- listIter->CastCtx = list->CastCtx;
- return reinterpret_cast<PyObject*>(listIter);
- }
- PyObject* TPyLazyListIterator::Next(PyObject* self)
- {
- PY_TRY {
- TPyLazyListIterator* iter = Cast(self);
- TPyLazyList* list = iter->List.Get();
- NUdf::TUnboxedValue item;
- if (iter->Iterator.Get().Next(item)) {
- ++iter->Length;
- for (auto skip = list->Step; --skip && iter->Iterator.Get().Skip(); ++iter->Length)
- continue;
- return ToPyObject(list->CastCtx, list->ItemType, item).Release();
- }
- // store calculated list length after traverse over whole list
- if (list->CachedLength == -1) {
- list->CachedLength = iter->Length;
- }
- return nullptr;
- } PY_CATCH(nullptr)
- }
- //////////////////////////////////////////////////////////////////////////////
- // TPyThinList interface
- //////////////////////////////////////////////////////////////////////////////
- struct TPyThinList
- {
- using TPtr = NUdf::TRefCountedPtr<TPyThinList, TPyPtrOps<TPyThinList>>;
- PyObject_HEAD;
- TPyCastContext::TPtr CastCtx;
- const NUdf::TType* ItemType;
- TPyCleanupListItem<NUdf::IBoxedValuePtr> Value;
- const NUdf::TUnboxedValue* Elements;
- Py_ssize_t Length;
- Py_ssize_t Step;
- inline static TPyThinList* Cast(PyObject* o) {
- return reinterpret_cast<TPyThinList*>(o);
- }
- inline static void Dealloc(PyObject* self) {
- delete Cast(self);
- }
- static PyObject* New(
- const TPyCastContext::TPtr& castCtx,
- const NUdf::TType* itemType,
- NUdf::IBoxedValuePtr value = NUdf::IBoxedValuePtr(),
- const NUdf::TUnboxedValue* elements = nullptr,
- Py_ssize_t length = 0,
- Py_ssize_t step = 1);
- static int Bool(PyObject* self);
- static PyObject* Repr(PyObject* self);
- static PyObject* Iter(PyObject* self);
- static Py_ssize_t Len(PyObject* self);
- static PyObject* Subscript(PyObject* self, PyObject* slice);
- static PyObject* ToIndexDict(PyObject* self, PyObject* /* arg */);
- static PyObject* Reversed(PyObject* self, PyObject* /* arg */);
- static PyObject* Take(PyObject* self, PyObject* arg);
- static PyObject* Skip(PyObject* self, PyObject* arg);
- static PyObject* HasFastLen(PyObject* self, PyObject* /* arg */);
- static PyObject* HasItems(PyObject* self, PyObject* /* arg */);
- };
- PyMappingMethods ThinListMapping = {
- INIT_MEMBER(mp_length, TPyThinList::Len),
- INIT_MEMBER(mp_subscript, TPyThinList::Subscript),
- INIT_MEMBER(mp_ass_subscript, nullptr),
- };
- PyNumberMethods ThinListNumbering = {
- INIT_MEMBER(nb_add, nullptr),
- INIT_MEMBER(nb_subtract, nullptr),
- INIT_MEMBER(nb_multiply, nullptr),
- #if PY_MAJOR_VERSION < 3
- INIT_MEMBER(nb_divide, nullptr),
- #endif
- INIT_MEMBER(nb_remainder, nullptr),
- INIT_MEMBER(nb_divmod, nullptr),
- INIT_MEMBER(nb_power, nullptr),
- INIT_MEMBER(nb_negative, nullptr),
- INIT_MEMBER(nb_positive, nullptr),
- INIT_MEMBER(nb_absolute, nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(nb_bool, TPyThinList::Bool),
- #else
- INIT_MEMBER(nb_nonzero, TPyThinList::Bool),
- #endif
- INIT_MEMBER(nb_invert, nullptr),
- INIT_MEMBER(nb_lshift, nullptr),
- INIT_MEMBER(nb_rshift, nullptr),
- INIT_MEMBER(nb_and, nullptr),
- INIT_MEMBER(nb_xor, nullptr),
- INIT_MEMBER(nb_or, nullptr),
- #if PY_MAJOR_VERSION < 3
- INIT_MEMBER(nb_coerce, nullptr),
- #endif
- INIT_MEMBER(nb_int, nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(nb_reserved, nullptr),
- #else
- INIT_MEMBER(nb_long, nullptr),
- #endif
- INIT_MEMBER(nb_float, nullptr),
- #if PY_MAJOR_VERSION < 3
- INIT_MEMBER(nb_oct, nullptr),
- INIT_MEMBER(nb_hex, nullptr),
- #endif
- INIT_MEMBER(nb_inplace_add, nullptr),
- INIT_MEMBER(nb_inplace_subtract, nullptr),
- INIT_MEMBER(nb_inplace_multiply, nullptr),
- INIT_MEMBER(nb_inplace_remainder, nullptr),
- INIT_MEMBER(nb_inplace_power, nullptr),
- INIT_MEMBER(nb_inplace_lshift, nullptr),
- INIT_MEMBER(nb_inplace_rshift, nullptr),
- INIT_MEMBER(nb_inplace_and, nullptr),
- INIT_MEMBER(nb_inplace_xor, nullptr),
- INIT_MEMBER(nb_inplace_or, nullptr),
- INIT_MEMBER(nb_floor_divide, nullptr),
- INIT_MEMBER(nb_true_divide, nullptr),
- INIT_MEMBER(nb_inplace_floor_divide, nullptr),
- INIT_MEMBER(nb_inplace_true_divide, nullptr),
- INIT_MEMBER(nb_index, nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(nb_matrix_multiply, nullptr),
- INIT_MEMBER(nb_inplace_matrix_multiply, nullptr),
- #endif
- };
- static PyMethodDef TPyThinListMethods[] = {
- { "__reversed__", TPyThinList::Reversed, METH_NOARGS, nullptr },
- { "to_index_dict", TPyThinList::ToIndexDict, METH_NOARGS, to_index_dict__doc__ },
- { "reversed", TPyThinList::Reversed, METH_NOARGS, reversed__doc__ },
- { "take", TPyThinList::Take, METH_O, take__doc__ },
- { "skip", TPyThinList::Skip, METH_O, skip__doc__ },
- { "has_fast_len", TPyThinList::HasFastLen, METH_NOARGS, has_fast_len__doc__ },
- { "has_items", TPyThinList::HasItems, METH_NOARGS, has_items__doc__ },
- { nullptr, nullptr, 0, nullptr } /* sentinel */
- };
- #if PY_MAJOR_VERSION >= 3
- #define Py_TPFLAGS_HAVE_ITER 0
- #endif
- PyTypeObject PyThinListType = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- INIT_MEMBER(tp_name , "yql.TList"),
- INIT_MEMBER(tp_basicsize , sizeof(TPyThinList)),
- INIT_MEMBER(tp_itemsize , 0),
- INIT_MEMBER(tp_dealloc , TPyThinList::Dealloc),
- #if PY_VERSION_HEX < 0x030800b4
- INIT_MEMBER(tp_print , nullptr),
- #else
- INIT_MEMBER(tp_vectorcall_offset, 0),
- #endif
- INIT_MEMBER(tp_getattr , nullptr),
- INIT_MEMBER(tp_setattr , nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(tp_as_async , nullptr),
- #else
- INIT_MEMBER(tp_compare , nullptr),
- #endif
- INIT_MEMBER(tp_repr , TPyThinList::Repr),
- INIT_MEMBER(tp_as_number , &ThinListNumbering),
- INIT_MEMBER(tp_as_sequence , nullptr),
- INIT_MEMBER(tp_as_mapping , &ThinListMapping),
- INIT_MEMBER(tp_hash , nullptr),
- INIT_MEMBER(tp_call , nullptr),
- INIT_MEMBER(tp_str , nullptr),
- INIT_MEMBER(tp_getattro , nullptr),
- INIT_MEMBER(tp_setattro , nullptr),
- INIT_MEMBER(tp_as_buffer , nullptr),
- INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
- INIT_MEMBER(tp_doc , "yql.TList object"),
- INIT_MEMBER(tp_traverse , nullptr),
- INIT_MEMBER(tp_clear , nullptr),
- INIT_MEMBER(tp_richcompare , nullptr),
- INIT_MEMBER(tp_weaklistoffset , 0),
- INIT_MEMBER(tp_iter , TPyThinList::Iter),
- INIT_MEMBER(tp_iternext , nullptr),
- INIT_MEMBER(tp_methods , TPyThinListMethods),
- INIT_MEMBER(tp_members , nullptr),
- INIT_MEMBER(tp_getset , nullptr),
- INIT_MEMBER(tp_base , nullptr),
- INIT_MEMBER(tp_dict , nullptr),
- INIT_MEMBER(tp_descr_get , nullptr),
- INIT_MEMBER(tp_descr_set , nullptr),
- INIT_MEMBER(tp_dictoffset , 0),
- INIT_MEMBER(tp_init , nullptr),
- INIT_MEMBER(tp_alloc , nullptr),
- INIT_MEMBER(tp_new , nullptr),
- INIT_MEMBER(tp_free , nullptr),
- INIT_MEMBER(tp_is_gc , nullptr),
- INIT_MEMBER(tp_bases , nullptr),
- INIT_MEMBER(tp_mro , nullptr),
- INIT_MEMBER(tp_cache , nullptr),
- INIT_MEMBER(tp_subclasses , nullptr),
- INIT_MEMBER(tp_weaklist , nullptr),
- INIT_MEMBER(tp_del , nullptr),
- INIT_MEMBER(tp_version_tag , 0),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(tp_finalize , nullptr),
- #endif
- #if PY_VERSION_HEX >= 0x030800b1
- INIT_MEMBER(tp_vectorcall , nullptr),
- #endif
- #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
- INIT_MEMBER(tp_print , nullptr),
- #endif
- };
- //////////////////////////////////////////////////////////////////////////////
- // TPyThinListIterator interface
- //////////////////////////////////////////////////////////////////////////////
- struct TPyThinListIterator
- {
- PyObject_HEAD;
- TPyThinList::TPtr List;
- const NUdf::TUnboxedValue* Elements;
- Py_ssize_t Count;
- inline static TPyThinListIterator* Cast(PyObject* o) {
- return reinterpret_cast<TPyThinListIterator*>(o);
- }
- inline static void Dealloc(PyObject* self) {
- delete Cast(self);
- }
- inline static PyObject* Repr(PyObject* self) {
- Y_UNUSED(self);
- return PyRepr("<yql.TListIterator>").Release();
- }
- static PyObject* New(TPyThinList* list);
- static PyObject* Next(PyObject* self);
- };
- PyTypeObject PyThinListIteratorType = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- INIT_MEMBER(tp_name , "yql.TListIterator"),
- INIT_MEMBER(tp_basicsize , sizeof(TPyThinListIterator)),
- INIT_MEMBER(tp_itemsize , 0),
- INIT_MEMBER(tp_dealloc , TPyThinListIterator::Dealloc),
- #if PY_VERSION_HEX < 0x030800b4
- INIT_MEMBER(tp_print , nullptr),
- #else
- INIT_MEMBER(tp_vectorcall_offset, 0),
- #endif
- INIT_MEMBER(tp_getattr , nullptr),
- INIT_MEMBER(tp_setattr , nullptr),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(tp_as_async , nullptr),
- #else
- INIT_MEMBER(tp_compare , nullptr),
- #endif
- INIT_MEMBER(tp_repr , TPyThinListIterator::Repr),
- INIT_MEMBER(tp_as_number , nullptr),
- INIT_MEMBER(tp_as_sequence , nullptr),
- INIT_MEMBER(tp_as_mapping , nullptr),
- INIT_MEMBER(tp_hash , nullptr),
- INIT_MEMBER(tp_call , nullptr),
- INIT_MEMBER(tp_str , nullptr),
- INIT_MEMBER(tp_getattro , nullptr),
- INIT_MEMBER(tp_setattro , nullptr),
- INIT_MEMBER(tp_as_buffer , nullptr),
- INIT_MEMBER(tp_flags , Py_TPFLAGS_HAVE_ITER),
- INIT_MEMBER(tp_doc , "yql.ListIterator object"),
- INIT_MEMBER(tp_traverse , nullptr),
- INIT_MEMBER(tp_clear , nullptr),
- INIT_MEMBER(tp_richcompare , nullptr),
- INIT_MEMBER(tp_weaklistoffset , 0),
- INIT_MEMBER(tp_iter , PyObject_SelfIter),
- INIT_MEMBER(tp_iternext , TPyThinListIterator::Next),
- INIT_MEMBER(tp_methods , nullptr),
- INIT_MEMBER(tp_members , nullptr),
- INIT_MEMBER(tp_getset , nullptr),
- INIT_MEMBER(tp_base , nullptr),
- INIT_MEMBER(tp_dict , nullptr),
- INIT_MEMBER(tp_descr_get , nullptr),
- INIT_MEMBER(tp_descr_set , nullptr),
- INIT_MEMBER(tp_dictoffset , 0),
- INIT_MEMBER(tp_init , nullptr),
- INIT_MEMBER(tp_alloc , nullptr),
- INIT_MEMBER(tp_new , nullptr),
- INIT_MEMBER(tp_free , nullptr),
- INIT_MEMBER(tp_is_gc , nullptr),
- INIT_MEMBER(tp_bases , nullptr),
- INIT_MEMBER(tp_mro , nullptr),
- INIT_MEMBER(tp_cache , nullptr),
- INIT_MEMBER(tp_subclasses , nullptr),
- INIT_MEMBER(tp_weaklist , nullptr),
- INIT_MEMBER(tp_del , nullptr),
- INIT_MEMBER(tp_version_tag , 0),
- #if PY_MAJOR_VERSION >= 3
- INIT_MEMBER(tp_finalize , nullptr),
- #endif
- #if PY_VERSION_HEX >= 0x030800b1
- INIT_MEMBER(tp_vectorcall , nullptr),
- #endif
- #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
- INIT_MEMBER(tp_print , nullptr),
- #endif
- };
- //////////////////////////////////////////////////////////////////////////////
- // TPyThinList implementation
- //////////////////////////////////////////////////////////////////////////////
- PyObject* TPyThinList::New(
- const TPyCastContext::TPtr& castCtx,
- const NUdf::TType* itemType,
- NUdf::IBoxedValuePtr value,
- const NUdf::TUnboxedValue* elements,
- Py_ssize_t length,
- Py_ssize_t step)
- {
- TPyThinList* list = new TPyThinList;
- PyObject_INIT(list, &PyThinListType);
- list->CastCtx = castCtx;
- list->ItemType = itemType;
- list->Value.Set(castCtx->PyCtx, value);
- list->Elements = elements;
- list->Length = length;
- list->Step = step;
- return reinterpret_cast<PyObject*>(list);
- }
- PyObject* TPyThinList::Repr(PyObject*)
- {
- return PyRepr("<yql.TList>").Release();
- }
- PyObject* TPyThinList::Iter(PyObject* self)
- {
- PY_TRY {
- TPyThinList* list = Cast(self);
- return TPyThinListIterator::New(list);
- } PY_CATCH(nullptr)
- }
- Py_ssize_t TPyThinList::Len(PyObject* self)
- {
- return Cast(self)->Length;
- }
- PyObject* TPyThinList::Subscript(PyObject* self, PyObject* slice)
- {
- PY_TRY {
- TPyThinList* list = Cast(self);
- const auto vb = list->CastCtx->ValueBuilder;
- if (PyIndex_Check(slice)) {
- Py_ssize_t index = PyNumber_AsSsize_t(slice, PyExc_IndexError);
- if (index < 0) {
- index += list->Length;
- }
- if (index < 0 || index >= list->Length) {
- const TPyObjectPtr error = PyUnicode_FromFormat("index %zd out of bounds, list size: %zd", index, list->Length);
- PyErr_SetObject(PyExc_IndexError, error.Get());
- return nullptr;
- }
- if (list->Step > 0) {
- index *= list->Step;
- } else {
- index = list->Length - ++index;
- index *= -list->Step;
- }
- return ToPyObject(list->CastCtx, list->ItemType, list->Elements[index]).Release();
- }
- if (PySlice_Check(slice)) {
- Py_ssize_t start, stop, step, size;
- if (PySlice_GetIndicesEx(SLICEOBJ(slice), list->Length, &start, &stop, &step, &size) < 0) {
- return nullptr;
- }
- if (!step) {
- PyErr_SetString(PyExc_ValueError, "slice step cannot be zero");
- return nullptr;
- }
- if (size > 0) {
- const Py_ssize_t skip = list->Step * (list->Step > 0 ?
- (step > 0 ? start : start + step * (size - 1)):
- (step > 0 ? stop : start + 1) - list->Length);
- return New(list->CastCtx, list->ItemType, list->Value.Get(), list->Elements + skip, size, step * list->Step);
- } else {
- return New(list->CastCtx, list->ItemType, list->Value.Get());
- }
- }
- const TPyObjectPtr type = PyObject_Type(slice);
- const TPyObjectPtr repr = PyObject_Repr(type.Get());
- const TPyObjectPtr error = PyUnicode_FromFormat("Unsupported slice object type: %R", repr.Get());
- PyErr_SetObject(PyExc_TypeError, error.Get());
- return nullptr;
- } PY_CATCH(nullptr)
- }
- #undef SLICEOBJ
- PyObject* TPyThinList::ToIndexDict(PyObject* self, PyObject* /* arg */)
- {
- PY_TRY {
- TPyThinList* list = Cast(self);
- const auto dict = list->CastCtx->ValueBuilder->ToIndexDict(NUdf::TUnboxedValuePod(list->Value.Get().Get()));
- return ToPyLazyDict(list->CastCtx, nullptr, list->ItemType, dict).Release();
- } PY_CATCH(nullptr)
- }
- PyObject* TPyThinList::Reversed(PyObject* self, PyObject* /* arg */)
- {
- PY_TRY {
- TPyThinList* list = Cast(self);
- return New(list->CastCtx, list->ItemType, list->Value.Get(), list->Elements, list->Length, -list->Step);
- } PY_CATCH(nullptr)
- }
- PyObject* TPyThinList::Take(PyObject* self, PyObject* arg)
- {
- PY_TRY {
- TPyThinList* list = Cast(self);
- const Py_ssize_t count = CastIndex(arg, "take");
- if (count < 0) {
- return nullptr;
- }
- if (const auto size = std::min(count, list->Length)) {
- return New(list->CastCtx, list->ItemType, list->Value.Get(), list->Step > 0 ? list->Elements : list->Elements + list->Length + size * list->Step, size, list->Step);
- } else {
- return New(list->CastCtx, list->ItemType, list->Value.Get());
- }
- } PY_CATCH(nullptr)
- }
- PyObject* TPyThinList::Skip(PyObject* self, PyObject* arg)
- {
- PY_TRY {
- TPyThinList* list = Cast(self);
- const Py_ssize_t count = CastIndex(arg, "skip");
- if (count < 0) {
- return nullptr;
- }
- if (const auto size = std::max(list->Length - count, Py_ssize_t(0))) {
- return New(list->CastCtx, list->ItemType, list->Value.Get(), list->Step > 0 ? list->Elements + count * list->Step : list->Elements, size, list->Step);
- } else {
- return New(list->CastCtx, list->ItemType);
- }
- } PY_CATCH(nullptr)
- }
- PyObject* TPyThinList::HasFastLen(PyObject* self, PyObject* /* arg */)
- {
- Py_RETURN_TRUE;
- }
- PyObject* TPyThinList::HasItems(PyObject* self, PyObject* /* arg */)
- {
- if (Cast(self)->Length > 0)
- Py_RETURN_TRUE;
- else
- Py_RETURN_FALSE;
- }
- int TPyThinList::Bool(PyObject* self)
- {
- return Cast(self)->Length > 0 ? 1 : 0;
- }
- //////////////////////////////////////////////////////////////////////////////
- // TPyThinListIterator implementation
- //////////////////////////////////////////////////////////////////////////////
- PyObject* TPyThinListIterator::New(TPyThinList* list)
- {
- TPyThinListIterator* listIter = new TPyThinListIterator;
- PyObject_INIT(listIter, &PyThinListIteratorType);
- listIter->List.Reset(list);
- listIter->Elements = list->Step > 0 ? list->Elements - list->Step : list->Elements - list->Length * list->Step;
- listIter->Count = list->Length;
- return reinterpret_cast<PyObject*>(listIter);
- }
- PyObject* TPyThinListIterator::Next(PyObject* self)
- {
- PY_TRY {
- TPyThinListIterator* iter = Cast(self);
- if (iter->Count) {
- --iter->Count;
- TPyThinList* list = iter->List.Get();
- return ToPyObject(list->CastCtx, list->ItemType, *(iter->Elements += list->Step)).Release();
- }
- return nullptr;
- } PY_CATCH(nullptr)
- }
- TPyObjectPtr ToPyLazyList(
- const TPyCastContext::TPtr& castCtx,
- const NUdf::TType* itemType,
- const NUdf::TUnboxedValuePod& value)
- {
- if (const auto elements = value.GetElements()) {
- return TPyThinList::New(castCtx, itemType, value.AsBoxed(), elements, value.GetListLength());
- } else {
- return TPyLazyList::New(castCtx, itemType, value.AsBoxed());
- }
- }
- } // namspace NPython
|