@@ -73,6 +73,7 @@ typedef struct _mp_obj_array_t {
7373
7474STATIC mp_obj_t array_iterator_new (mp_obj_t array_in );
7575STATIC mp_obj_t array_append (mp_obj_t self_in , mp_obj_t arg );
76+ STATIC mp_obj_t array_extend (mp_obj_t self_in , mp_obj_t arg_in );
7677STATIC mp_int_t array_get_buffer (mp_obj_t o_in , mp_buffer_info_t * bufinfo , mp_uint_t flags );
7778
7879/******************************************************************************/
@@ -225,7 +226,38 @@ STATIC mp_obj_t array_unary_op(mp_uint_t op, mp_obj_t o_in) {
225226}
226227
227228STATIC mp_obj_t array_binary_op (mp_uint_t op , mp_obj_t lhs_in , mp_obj_t rhs_in ) {
229+ mp_obj_array_t * lhs = lhs_in ;
228230 switch (op ) {
231+ 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 );
248+ return res ;
249+ }
250+
251+ case MP_BINARY_OP_INPLACE_ADD : {
252+ #if MICROPY_PY_BUILTINS_MEMORYVIEW
253+ if (lhs -> base .type == & mp_type_memoryview ) {
254+ return MP_OBJ_NULL ; // op not supported
255+ }
256+ #endif
257+ array_extend (lhs , rhs_in );
258+ return lhs ;
259+ }
260+
229261 case MP_BINARY_OP_EQUAL : {
230262 mp_buffer_info_t lhs_bufinfo ;
231263 mp_buffer_info_t rhs_bufinfo ;
@@ -235,14 +267,18 @@ STATIC mp_obj_t array_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in)
235267 }
236268 return MP_BOOL (mp_seq_cmp_bytes (op , lhs_bufinfo .buf , lhs_bufinfo .len , rhs_bufinfo .buf , rhs_bufinfo .len ));
237269 }
270+
238271 default :
239272 return MP_OBJ_NULL ; // op not supported
240273 }
241274}
242275
276+ #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
243277STATIC mp_obj_t array_append (mp_obj_t self_in , mp_obj_t arg ) {
278+ // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)
244279 assert (MP_OBJ_IS_TYPE (self_in , & mp_type_array ) || MP_OBJ_IS_TYPE (self_in , & mp_type_bytearray ));
245280 mp_obj_array_t * self = self_in ;
281+
246282 if (self -> free == 0 ) {
247283 int item_sz = mp_binary_get_size ('@' , self -> typecode , NULL );
248284 // TODO: alloc policy
@@ -256,6 +292,43 @@ STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {
256292}
257293STATIC MP_DEFINE_CONST_FUN_OBJ_2 (array_append_obj , array_append );
258294
295+ STATIC mp_obj_t array_extend (mp_obj_t self_in , mp_obj_t arg_in ) {
296+ // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)
297+ assert (MP_OBJ_IS_TYPE (self_in , & mp_type_array ) || MP_OBJ_IS_TYPE (self_in , & mp_type_bytearray ));
298+ mp_obj_array_t * self = self_in ;
299+
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+ }
312+
313+ int sz = mp_binary_get_size ('@' , self -> typecode , NULL );
314+
315+ // 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 ;
320+ }
321+
322+ // 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 ;
326+
327+ return mp_const_none ;
328+ }
329+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (array_extend_obj , array_extend );
330+ #endif
331+
259332STATIC mp_obj_t array_subscr (mp_obj_t self_in , mp_obj_t index_in , mp_obj_t value ) {
260333 if (value == MP_OBJ_NULL ) {
261334 // delete item
@@ -341,6 +414,7 @@ STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_ui
341414#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
342415STATIC const mp_map_elem_t array_locals_dict_table [] = {
343416 { MP_OBJ_NEW_QSTR (MP_QSTR_append ), (mp_obj_t )& array_append_obj },
417+ { MP_OBJ_NEW_QSTR (MP_QSTR_extend ), (mp_obj_t )& array_extend_obj },
344418};
345419
346420STATIC MP_DEFINE_CONST_DICT (array_locals_dict , array_locals_dict_table );
0 commit comments