Commit ae8d8675 authored by Damien George's avatar Damien George
Browse files

py: Add iter_buf to getiter type method.

Allows to iterate over the following without allocating on the heap:
- tuple
- list
- string, bytes
- bytearray, array
- dict (not dict.keys, dict.values, dict.items)
- set, frozenset

Allows to call the following without heap memory:
- all, any, min, max, sum

TODO: still need to allocate stack memory in bytecode for iter_buf.
parent 101886f5
......@@ -38,7 +38,7 @@
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict);
STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str);
STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);
STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in);
/******************************************************************************/
......@@ -231,7 +231,8 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size
vstr_init(&vstr, len);
}
mp_obj_t iterable = mp_getiter(args[0]);
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(args[0], &iter_buf);
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
mp_int_t val = mp_obj_get_int(item);
......@@ -1942,7 +1943,7 @@ STATIC const mp_rom_map_elem_t str8_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(str8_locals_dict, str8_locals_dict_table);
#if !MICROPY_PY_BUILTINS_STR_UNICODE
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);
const mp_obj_type_t mp_type_str = {
{ &mp_type_type },
......@@ -2142,8 +2143,9 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {
}
}
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) {
mp_obj_str8_it_t *o = m_new_obj(mp_obj_str8_it_t);
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) {
assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t));
mp_obj_str8_it_t *o = (mp_obj_str8_it_t*)iter_buf;
o->base.type = &mp_type_polymorph_iter;
o->iternext = str_it_iternext;
o->str = str;
......@@ -2164,8 +2166,9 @@ STATIC mp_obj_t bytes_it_iternext(mp_obj_t self_in) {
}
}
mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str) {
mp_obj_str8_it_t *o = m_new_obj(mp_obj_str8_it_t);
mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) {
assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t));
mp_obj_str8_it_t *o = (mp_obj_str8_it_t*)iter_buf;
o->base.type = &mp_type_polymorph_iter;
o->iternext = bytes_it_iternext;
o->str = str;
......
......@@ -215,7 +215,7 @@ const mp_obj_type_t mp_type_stringio = {
.name = MP_QSTR_StringIO,
.print = stringio_print,
.make_new = stringio_make_new,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &stringio_stream_p,
.locals_dict = (mp_obj_dict_t*)&stringio_locals_dict,
......@@ -227,7 +227,7 @@ const mp_obj_type_t mp_type_bytesio = {
.name = MP_QSTR_BytesIO,
.print = stringio_print,
.make_new = stringio_make_new,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &bytesio_stream_p,
.locals_dict = (mp_obj_dict_t*)&stringio_locals_dict,
......
......@@ -36,7 +36,7 @@
#if MICROPY_PY_BUILTINS_STR_UNICODE
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);
/******************************************************************************/
/* str */
......@@ -301,8 +301,9 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {
}
}
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) {
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) {
assert(sizeof(mp_obj_str_it_t) <= sizeof(mp_obj_iter_buf_t));
mp_obj_str_it_t *o = (mp_obj_str_it_t*)iter_buf;
o->base.type = &mp_type_polymorph_iter;
o->iternext = str_it_iternext;
o->str = str;
......
......@@ -32,8 +32,6 @@
#include "py/runtime0.h"
#include "py/runtime.h"
STATIC mp_obj_t mp_obj_new_tuple_iterator(mp_obj_tuple_t *tuple, size_t cur);
/******************************************************************************/
/* tuple */
......@@ -84,7 +82,8 @@ STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg
size_t len = 0;
mp_obj_t *items = m_new(mp_obj_t, alloc);
mp_obj_t iterable = mp_getiter(args[0]);
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(args[0], &iter_buf);
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (len >= alloc) {
......@@ -195,10 +194,6 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
}
}
mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in) {
return mp_obj_new_tuple_iterator(MP_OBJ_TO_PTR(o_in), 0);
}
STATIC mp_obj_t tuple_count(mp_obj_t self_in, mp_obj_t value) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple));
mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);
......@@ -284,11 +279,12 @@ STATIC mp_obj_t tuple_it_iternext(mp_obj_t self_in) {
}
}
STATIC mp_obj_t mp_obj_new_tuple_iterator(mp_obj_tuple_t *tuple, size_t cur) {
mp_obj_tuple_it_t *o = m_new_obj(mp_obj_tuple_it_t);
mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
assert(sizeof(mp_obj_tuple_it_t) <= sizeof(mp_obj_iter_buf_t));
mp_obj_tuple_it_t *o = (mp_obj_tuple_it_t*)iter_buf;
o->base.type = &mp_type_polymorph_iter;
o->iternext = tuple_it_iternext;
o->tuple = tuple;
o->cur = cur;
o->tuple = MP_OBJ_TO_PTR(o_in);
o->cur = 0;
return MP_OBJ_FROM_PTR(o);
}
......@@ -44,7 +44,7 @@ void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t
mp_obj_t mp_obj_tuple_unary_op(mp_uint_t op, mp_obj_t self_in);
mp_obj_t mp_obj_tuple_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs);
mp_obj_t mp_obj_tuple_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value);
mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in);
mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf);
extern const mp_obj_type_t mp_type_attrtuple;
......
......@@ -758,7 +758,7 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons
return mp_call_method_self_n_kw(member[0], member[1], n_args, n_kw, args);
}
STATIC mp_obj_t instance_getiter(mp_obj_t self_in) {
STATIC mp_obj_t instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
mp_obj_t member[2] = {MP_OBJ_NULL};
struct class_lookup_data lookup = {
......@@ -773,7 +773,7 @@ STATIC mp_obj_t instance_getiter(mp_obj_t self_in) {
return MP_OBJ_NULL;
} else if (member[0] == MP_OBJ_SENTINEL) {
mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]);
return type->getiter(self->subobj[0]);
return type->getiter(self->subobj[0], iter_buf);
} else {
return mp_call_method_n_kw(0, 0, member);
}
......
......@@ -43,7 +43,7 @@ STATIC mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
o->base.type = type;
o->n_iters = n_args;
for (mp_uint_t i = 0; i < n_args; i++) {
o->iters[i] = mp_getiter(args[i]);
o->iters[i] = mp_getiter(args[i], NULL);
}
return MP_OBJ_FROM_PTR(o);
}
......@@ -71,6 +71,6 @@ const mp_obj_type_t mp_type_zip = {
{ &mp_type_type },
.name = MP_QSTR_zip,
.make_new = zip_make_new,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = zip_iternext,
};
......@@ -520,7 +520,8 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) {
}
if (type->getiter != NULL) {
/* second attempt, walk the iterator */
mp_obj_t iter = mp_getiter(rhs);
mp_obj_iter_buf_t iter_buf;
mp_obj_t iter = mp_getiter(rhs, &iter_buf);
mp_obj_t next;
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
if (mp_obj_equal(next, lhs)) {
......@@ -698,7 +699,8 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
args2_len += n_args;
// extract the variable position args from the iterator
mp_obj_t iterable = mp_getiter(pos_seq);
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(pos_seq, &iter_buf);
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (args2_len >= args2_alloc) {
......@@ -743,7 +745,8 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
// get the keys iterable
mp_obj_t dest[3];
mp_load_method(kw_dict, MP_QSTR_keys, dest);
mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest));
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest), &iter_buf);
mp_obj_t key;
while ((key = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
......@@ -809,7 +812,8 @@ void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) {
items[i] = seq_items[num - 1 - i];
}
} else {
mp_obj_t iterable = mp_getiter(seq_in);
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(seq_in, &iter_buf);
for (seq_len = 0; seq_len < num; seq_len++) {
mp_obj_t el = mp_iternext(iterable);
......@@ -873,7 +877,8 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) {
// items destination array, then the rest to a dynamically created list. Once the
// iterable is exhausted, we take from this list for the right part of the items.
// TODO Improve to waste less memory in the dynamically created list.
mp_obj_t iterable = mp_getiter(seq_in);
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(seq_in, &iter_buf);
mp_obj_t item;
for (seq_len = 0; seq_len < num_left; seq_len++) {
item = mp_iternext(iterable);
......@@ -1096,13 +1101,18 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
}
}
mp_obj_t mp_getiter(mp_obj_t o_in) {
mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
assert(o_in);
// if caller did not provide a buffer then allocate one on the heap
if (iter_buf == NULL) {
iter_buf = m_new_obj(mp_obj_iter_buf_t);
}
// check for native getiter (corresponds to __iter__)
mp_obj_type_t *type = mp_obj_get_type(o_in);
if (type->getiter != NULL) {
mp_obj_t iter = type->getiter(o_in);
mp_obj_t iter = type->getiter(o_in, iter_buf);
if (iter != MP_OBJ_NULL) {
return iter;
}
......@@ -1113,7 +1123,7 @@ mp_obj_t mp_getiter(mp_obj_t o_in) {
mp_load_method_maybe(o_in, MP_QSTR___getitem__, dest);
if (dest[0] != MP_OBJ_NULL) {
// __getitem__ exists, create and return an iterator
return mp_obj_new_getitem_iter(dest);
return mp_obj_new_getitem_iter(dest, iter_buf);
}
// object not iterable
......
......@@ -123,7 +123,7 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest);
void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest);
void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val);
mp_obj_t mp_getiter(mp_obj_t o);
mp_obj_t mp_getiter(mp_obj_t o, mp_obj_iter_buf_t *iter_buf);
mp_obj_t mp_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_STOP_ITERATION instead of raising StopIteration()
mp_obj_t mp_iternext(mp_obj_t o); // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration(...)
mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val);
......
......@@ -723,7 +723,7 @@ unwind_jump:;
ENTRY(MP_BC_GET_ITER):
MARK_EXC_IP_SELECTIVE();
SET_TOP(mp_getiter(TOP()));
SET_TOP(mp_getiter(TOP(), NULL));
DISPATCH();
ENTRY(MP_BC_FOR_ITER): {
......
......@@ -120,7 +120,7 @@ STATIC const mp_obj_type_t stdio_obj_type = {
.name = MP_QSTR_FileIO,
// TODO .make_new?
.print = stdio_obj_print,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &stdio_obj_stream_p,
.locals_dict = (mp_obj_t)&stdio_locals_dict,
......@@ -153,7 +153,7 @@ STATIC const mp_obj_type_t stdio_buffer_obj_type = {
{ &mp_type_type },
.name = MP_QSTR_FileIO,
.print = stdio_obj_print,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &stdio_buffer_obj_stream_p,
.locals_dict = (mp_obj_t)&stdio_locals_dict,
......
......@@ -1037,7 +1037,7 @@ const mp_obj_type_t pyb_uart_type = {
.name = MP_QSTR_UART,
.print = pyb_uart_print,
.make_new = pyb_uart_make_new,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &uart_stream_p,
.locals_dict = (mp_obj_t)&pyb_uart_locals_dict,
......
......@@ -518,7 +518,7 @@ const mp_obj_type_t pyb_usb_vcp_type = {
.name = MP_QSTR_USB_VCP,
.print = pyb_usb_vcp_print,
.make_new = pyb_usb_vcp_make_new,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &pyb_usb_vcp_stream_p,
.locals_dict = (mp_obj_t)&pyb_usb_vcp_locals_dict,
......
......@@ -244,7 +244,7 @@ const mp_obj_type_t mp_type_fileio = {
.name = MP_QSTR_FileIO,
.print = fdfile_print,
.make_new = fdfile_make_new,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &fileio_stream_p,
.locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
......@@ -263,7 +263,7 @@ const mp_obj_type_t mp_type_textio = {
.name = MP_QSTR_TextIOWrapper,
.print = fdfile_print,
.make_new = fdfile_make_new,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &textio_stream_p,
.locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
......
......@@ -194,7 +194,8 @@ STATIC mp_obj_t make_func(mp_obj_t rettype_in, void *func, mp_obj_t argtypes_in)
o->rettype = *rettype;
o->argtypes = argtypes;
mp_obj_t iterable = mp_getiter(argtypes_in);
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(argtypes_in, &iter_buf);
mp_obj_t item;
int i = 0;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
......@@ -251,7 +252,8 @@ STATIC mp_obj_t mod_ffi_callback(mp_obj_t rettype_in, mp_obj_t func_in, mp_obj_t
o->rettype = *rettype;
mp_obj_t iterable = mp_getiter(paramtypes_in);
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(paramtypes_in, &iter_buf);
mp_obj_t item;
int i = 0;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
......
......@@ -288,7 +288,7 @@ STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table);
STATIC const mp_obj_type_t mp_type_poll = {
{ &mp_type_type },
.name = MP_QSTR_poll,
.getiter = mp_identity,
.getiter = mp_identity_getiter,
.iternext = poll_iternext,
.locals_dict = (void*)&poll_locals_dict,
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment