Skip to content

Commit c7ca01a

Browse files
committed
py: Generalise and reduce code size of array +, += and .extend().
By using the buffer protocol for these array operations, we now allow addition of memoryview objects, and objects with "incompatible" typecodes (in this case it just adds bytes naively). This is an extension to CPython which seems sensible. It also reduces the code size.
1 parent d8c2b2a commit c7ca01a

1 file changed

Lines changed: 28 additions & 35 deletions

File tree

py/objarray.c

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -229,22 +229,20 @@ STATIC mp_obj_t array_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in)
229229
mp_obj_array_t *lhs = lhs_in;
230230
switch (op) {
231231
case MP_BINARY_OP_ADD: {
232-
#if MICROPY_PY_BUILTINS_MEMORYVIEW
233-
if (lhs->base.type == &mp_type_memoryview) {
234-
return MP_OBJ_NULL; // op not supported
235-
}
236-
#endif
237-
// if we get here then lhs is not a memoryview, so we don't need to use (& TYPECODE_MASK)
238-
if (mp_obj_get_type(rhs_in) != lhs->base.type) {
239-
return MP_OBJ_NULL; // op not supported
240-
}
241-
mp_obj_array_t *rhs = rhs_in;
242-
if (lhs->typecode != rhs->typecode) {
243-
return MP_OBJ_NULL; // op not supported
244-
}
245-
int sz = mp_binary_get_size('@', lhs->typecode, NULL);
246-
mp_obj_array_t *res = array_new(lhs->typecode, lhs->len + rhs->len);
247-
mp_seq_cat((byte*)res->items, lhs->items, lhs->len * sz, rhs->items, rhs->len * sz, byte);
232+
// allow to add anything that has the buffer protocol (extension to CPython)
233+
mp_buffer_info_t lhs_bufinfo;
234+
mp_buffer_info_t rhs_bufinfo;
235+
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
236+
mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ);
237+
238+
int sz = mp_binary_get_size('@', lhs_bufinfo.typecode, NULL);
239+
240+
// convert byte count to element count (in case rhs is not multiple of sz)
241+
mp_uint_t rhs_len = rhs_bufinfo.len / sz;
242+
243+
// note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count
244+
mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len);
245+
mp_seq_cat((byte*)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte);
248246
return res;
249247
}
250248

@@ -297,32 +295,27 @@ STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) {
297295
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray));
298296
mp_obj_array_t *self = self_in;
299297

300-
// check for compatible types (array & array, or bytearray & bytearray)
301-
if (mp_obj_get_type(arg_in) != self->base.type) {
302-
type_error:
303-
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
304-
"incompatible type for array operation"));
305-
}
306-
307-
// check for compatible typecode
308-
mp_obj_array_t *arg = arg_in;
309-
if (self->typecode != arg->typecode) {
310-
goto type_error;
311-
}
298+
// allow to extend by anything that has the buffer protocol (extension to CPython)
299+
mp_buffer_info_t arg_bufinfo;
300+
mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ);
312301

313302
int sz = mp_binary_get_size('@', self->typecode, NULL);
314303

304+
// convert byte count to element count
305+
mp_uint_t len = arg_bufinfo.len / sz;
306+
315307
// make sure we have enough room to extend
316-
if (self->free < arg->len) {
317-
// TODO: alloc policy; at the moment we go conservative
318-
self->items = m_realloc(self->items, (self->len + self->free) * sz, (self->len + arg->len) * sz);
319-
self->free += arg->len;
308+
// TODO: alloc policy; at the moment we go conservative
309+
if (self->free < len) {
310+
self->items = m_realloc(self->items, (self->len + self->free) * sz, (self->len + len) * sz);
311+
self->free = 0;
312+
} else {
313+
self->free -= len;
320314
}
321315

322316
// extend
323-
mp_seq_copy((byte*)self->items + self->len * sz, arg->items, arg->len * sz, byte);
324-
self->len += arg->len;
325-
self->free -= arg->len;
317+
mp_seq_copy((byte*)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte);
318+
self->len += len;
326319

327320
return mp_const_none;
328321
}

0 commit comments

Comments
 (0)