1 /*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
7 * Copyright (c) 2014 Paul Sokolovsky
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28 #include <string.h>
29 #include <assert.h>
30 #include <stdint.h>
31
32 #include "py/runtime.h"
33 #include "py/binary.h"
34 #include "py/objstr.h"
35 #include "py/objarray.h"
36
37 #if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW
38
39 // About memoryview object: We want to reuse as much code as possible from
40 // array, and keep the memoryview object 4 words in size so it fits in 1 GC
41 // block. Also, memoryview must keep a pointer to the base of the buffer so
42 // that the buffer is not GC'd if the original parent object is no longer
43 // around (we are assuming that all memoryview'able objects return a pointer
44 // which points to the start of a GC chunk). Given the above constraints we
45 // do the following:
46 // - typecode high bit is set if the buffer is read-write (else read-only)
47 // - free is the offset in elements to the first item in the memoryview
48 // - len is the length in elements
49 // - items points to the start of the original buffer
50 // Note that we don't handle the case where the original buffer might change
51 // size due to a resize of the original parent object.
52
53 #if MICROPY_PY_BUILTINS_MEMORYVIEW
54 #define TYPECODE_MASK (0x7f)
55 #define memview_offset free
56 #else
57 // make (& TYPECODE_MASK) a null operation if memorview not enabled
58 #define TYPECODE_MASK (~(size_t)0)
59 // memview_offset should not be accessed if memoryview is not enabled,
60 // so not defined to catch errors
61 #endif
62
63 STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf);
64 STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
65 STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in);
66 STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
67
68 /******************************************************************************/
69 // array
70
71 #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
array_print(const mp_print_t * print,mp_obj_t o_in,mp_print_kind_t kind)72 STATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
73 (void)kind;
74 mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);
75 if (o->typecode == BYTEARRAY_TYPECODE) {
76 mp_print_str(print, "bytearray(b");
77 mp_str_print_quoted(print, o->items, o->len, true);
78 } else {
79 mp_printf(print, "array('%c'", o->typecode);
80 if (o->len > 0) {
81 mp_print_str(print, ", [");
82 for (size_t i = 0; i < o->len; i++) {
83 if (i > 0) {
84 mp_print_str(print, ", ");
85 }
86 mp_obj_print_helper(print, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR);
87 }
88 mp_print_str(print, "]");
89 }
90 }
91 mp_print_str(print, ")");
92 }
93 #endif
94
95 #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
array_new(char typecode,size_t n)96 STATIC mp_obj_array_t *array_new(char typecode, size_t n) {
97 int typecode_size = mp_binary_get_size('@', typecode, NULL);
98 mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
99 #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY
100 o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;
101 #elif MICROPY_PY_BUILTINS_BYTEARRAY
102 o->base.type = &mp_type_bytearray;
103 #else
104 o->base.type = &mp_type_array;
105 #endif
106 o->typecode = typecode;
107 o->free = 0;
108 o->len = n;
109 o->items = m_new(byte, typecode_size * o->len);
110 return o;
111 }
112 #endif
113
114 #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
array_construct(char typecode,mp_obj_t initializer)115 STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
116 // bytearrays can be raw-initialised from anything with the buffer protocol
117 // other arrays can only be raw-initialised from bytes and bytearray objects
118 mp_buffer_info_t bufinfo;
119 if (((MICROPY_PY_BUILTINS_BYTEARRAY
120 && typecode == BYTEARRAY_TYPECODE)
121 || (MICROPY_PY_ARRAY
122 && (mp_obj_is_type(initializer, &mp_type_bytes)
123 || (MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(initializer, &mp_type_bytearray)))))
124 && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) {
125 // construct array from raw bytes
126 // we round-down the len to make it a multiple of sz (CPython raises error)
127 size_t sz = mp_binary_get_size('@', typecode, NULL);
128 size_t len = bufinfo.len / sz;
129 mp_obj_array_t *o = array_new(typecode, len);
130 memcpy(o->items, bufinfo.buf, len * sz);
131 return MP_OBJ_FROM_PTR(o);
132 }
133
134 size_t len;
135 // Try to create array of exact len if initializer len is known
136 mp_obj_t len_in = mp_obj_len_maybe(initializer);
137 if (len_in == MP_OBJ_NULL) {
138 len = 0;
139 } else {
140 len = MP_OBJ_SMALL_INT_VALUE(len_in);
141 }
142
143 mp_obj_array_t *array = array_new(typecode, len);
144
145 mp_obj_t iterable = mp_getiter(initializer, NULL);
146 mp_obj_t item;
147 size_t i = 0;
148 while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
149 if (len == 0) {
150 array_append(MP_OBJ_FROM_PTR(array), item);
151 } else {
152 mp_binary_set_val_array(typecode, array->items, i++, item);
153 }
154 }
155
156 return MP_OBJ_FROM_PTR(array);
157 }
158 #endif
159
160 #if MICROPY_PY_ARRAY
array_make_new(const mp_obj_type_t * type_in,size_t n_args,size_t n_kw,const mp_obj_t * args)161 STATIC mp_obj_t array_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
162 (void)type_in;
163 mp_arg_check_num(n_args, n_kw, 1, 2, false);
164
165 // get typecode
166 const char *typecode = mp_obj_str_get_str(args[0]);
167
168 if (n_args == 1) {
169 // 1 arg: make an empty array
170 return MP_OBJ_FROM_PTR(array_new(*typecode, 0));
171 } else {
172 // 2 args: construct the array from the given object
173 return array_construct(*typecode, args[1]);
174 }
175 }
176 #endif
177
178 #if MICROPY_PY_BUILTINS_BYTEARRAY
bytearray_make_new(const mp_obj_type_t * type_in,size_t n_args,size_t n_kw,const mp_obj_t * args)179 STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
180 (void)type_in;
181 // Can take 2nd/3rd arg if constructs from str
182 mp_arg_check_num(n_args, n_kw, 0, 3, false);
183
184 if (n_args == 0) {
185 // no args: construct an empty bytearray
186 return MP_OBJ_FROM_PTR(array_new(BYTEARRAY_TYPECODE, 0));
187 } else if (mp_obj_is_int(args[0])) {
188 // 1 arg, an integer: construct a blank bytearray of that length
189 mp_uint_t len = mp_obj_get_int(args[0]);
190 mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len);
191 memset(o->items, 0, len);
192 return MP_OBJ_FROM_PTR(o);
193 } else {
194 // 1 arg: construct the bytearray from that
195 return array_construct(BYTEARRAY_TYPECODE, args[0]);
196 }
197 }
198 #endif
199
200 #if MICROPY_PY_BUILTINS_MEMORYVIEW
201
mp_obj_new_memoryview(byte typecode,size_t nitems,void * items)202 mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) {
203 mp_obj_array_t *self = m_new_obj(mp_obj_array_t);
204 mp_obj_memoryview_init(self, typecode, 0, nitems, items);
205 return MP_OBJ_FROM_PTR(self);
206 }
207
memoryview_make_new(const mp_obj_type_t * type_in,size_t n_args,size_t n_kw,const mp_obj_t * args)208 STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
209 (void)type_in;
210
211 // TODO possibly allow memoryview constructor to take start/stop so that one
212 // can do memoryview(b, 4, 8) instead of memoryview(b)[4:8] (uses less RAM)
213
214 mp_arg_check_num(n_args, n_kw, 1, 1, false);
215
216 mp_buffer_info_t bufinfo;
217 mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
218
219 mp_obj_array_t *self = MP_OBJ_TO_PTR(mp_obj_new_memoryview(bufinfo.typecode,
220 bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL),
221 bufinfo.buf));
222
223 // If the input object is a memoryview then need to point the items of the
224 // new memoryview to the start of the buffer so the GC can trace it.
225 if (mp_obj_get_type(args[0]) == &mp_type_memoryview) {
226 mp_obj_array_t *other = MP_OBJ_TO_PTR(args[0]);
227 self->memview_offset = other->memview_offset;
228 self->items = other->items;
229 }
230
231 // test if the object can be written to
232 if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {
233 self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer
234 }
235
236 return MP_OBJ_FROM_PTR(self);
237 }
238
239 #if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE
memoryview_attr(mp_obj_t self_in,qstr attr,mp_obj_t * dest)240 STATIC void memoryview_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
241 if (dest[0] != MP_OBJ_NULL) {
242 return;
243 }
244 if (attr == MP_QSTR_itemsize) {
245 mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in);
246 dest[0] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->typecode & TYPECODE_MASK, NULL));
247 }
248 }
249 #endif
250
251 #endif
252
array_unary_op(mp_unary_op_t op,mp_obj_t o_in)253 STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
254 mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);
255 switch (op) {
256 case MP_UNARY_OP_BOOL:
257 return mp_obj_new_bool(o->len != 0);
258 case MP_UNARY_OP_LEN:
259 return MP_OBJ_NEW_SMALL_INT(o->len);
260 default:
261 return MP_OBJ_NULL; // op not supported
262 }
263 }
264
typecode_for_comparison(int typecode,bool * is_unsigned)265 STATIC int typecode_for_comparison(int typecode, bool *is_unsigned) {
266 if (typecode == BYTEARRAY_TYPECODE) {
267 typecode = 'B';
268 }
269 if (typecode <= 'Z') {
270 typecode += 32; // to lowercase
271 *is_unsigned = true;
272 }
273 return typecode;
274 }
275
array_binary_op(mp_binary_op_t op,mp_obj_t lhs_in,mp_obj_t rhs_in)276 STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
277 mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in);
278 switch (op) {
279 case MP_BINARY_OP_ADD: {
280 // allow to add anything that has the buffer protocol (extension to CPython)
281 mp_buffer_info_t lhs_bufinfo;
282 mp_buffer_info_t rhs_bufinfo;
283 array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
284 mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ);
285
286 size_t sz = mp_binary_get_size('@', lhs_bufinfo.typecode, NULL);
287
288 // convert byte count to element count (in case rhs is not multiple of sz)
289 size_t rhs_len = rhs_bufinfo.len / sz;
290
291 // note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count
292 mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len);
293 mp_seq_cat((byte *)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte);
294 return MP_OBJ_FROM_PTR(res);
295 }
296
297 case MP_BINARY_OP_INPLACE_ADD: {
298 #if MICROPY_PY_BUILTINS_MEMORYVIEW
299 if (lhs->base.type == &mp_type_memoryview) {
300 return MP_OBJ_NULL; // op not supported
301 }
302 #endif
303 array_extend(lhs_in, rhs_in);
304 return lhs_in;
305 }
306
307 case MP_BINARY_OP_CONTAINS: {
308 #if MICROPY_PY_BUILTINS_BYTEARRAY
309 // Can search string only in bytearray
310 mp_buffer_info_t lhs_bufinfo;
311 mp_buffer_info_t rhs_bufinfo;
312 if (mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
313 if (!mp_obj_is_type(lhs_in, &mp_type_bytearray)) {
314 return mp_const_false;
315 }
316 array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
317 return mp_obj_new_bool(
318 find_subbytes(lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len, 1) != NULL);
319 }
320 #endif
321
322 // Otherwise, can only look for a scalar numeric value in an array
323 if (mp_obj_is_int(rhs_in) || mp_obj_is_float(rhs_in)) {
324 mp_raise_NotImplementedError(NULL);
325 }
326
327 return mp_const_false;
328 }
329
330 case MP_BINARY_OP_EQUAL:
331 case MP_BINARY_OP_LESS:
332 case MP_BINARY_OP_LESS_EQUAL:
333 case MP_BINARY_OP_MORE:
334 case MP_BINARY_OP_MORE_EQUAL: {
335 mp_buffer_info_t lhs_bufinfo;
336 mp_buffer_info_t rhs_bufinfo;
337 array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
338 if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
339 return mp_const_false;
340 }
341 // mp_seq_cmp_bytes is used so only compatible representations can be correctly compared.
342 // The type doesn't matter: array/bytearray/str/bytes all have the same buffer layout, so
343 // just check if the typecodes are compatible; for testing equality the types should have the
344 // same code except for signedness, and not be floating point because nan never equals nan.
345 // For > and < the types should be the same and unsigned.
346 // Note that typecode_for_comparison always returns lowercase letters to save code size.
347 // No need for (& TYPECODE_MASK) here: xxx_get_buffer already takes care of that.
348 bool is_unsigned = false;
349 const int lhs_code = typecode_for_comparison(lhs_bufinfo.typecode, &is_unsigned);
350 const int rhs_code = typecode_for_comparison(rhs_bufinfo.typecode, &is_unsigned);
351 if (lhs_code == rhs_code && lhs_code != 'f' && lhs_code != 'd' && (op == MP_BINARY_OP_EQUAL || is_unsigned)) {
352 return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
353 }
354 // mp_obj_equal_not_equal treats returning MP_OBJ_NULL as 'fall back to pointer comparison'
355 // for MP_BINARY_OP_EQUAL but that is incompatible with CPython.
356 mp_raise_NotImplementedError(NULL);
357 }
358
359 default:
360 return MP_OBJ_NULL; // op not supported
361 }
362 }
363
364 #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
array_append(mp_obj_t self_in,mp_obj_t arg)365 STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {
366 // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)
367 assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray))
368 || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array)));
369 mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in);
370
371 if (self->free == 0) {
372 size_t item_sz = mp_binary_get_size('@', self->typecode, NULL);
373 // TODO: alloc policy
374 self->free = 8;
375 self->items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + self->free));
376 mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz);
377 }
378 mp_binary_set_val_array(self->typecode, self->items, self->len, arg);
379 // only update length/free if set succeeded
380 self->len++;
381 self->free--;
382 return mp_const_none; // return None, as per CPython
383 }
384 STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append);
385
array_extend(mp_obj_t self_in,mp_obj_t arg_in)386 STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) {
387 // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)
388 assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray))
389 || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array)));
390 mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in);
391
392 // allow to extend by anything that has the buffer protocol (extension to CPython)
393 mp_buffer_info_t arg_bufinfo;
394 mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ);
395
396 size_t sz = mp_binary_get_size('@', self->typecode, NULL);
397
398 // convert byte count to element count
399 size_t len = arg_bufinfo.len / sz;
400
401 // make sure we have enough room to extend
402 // TODO: alloc policy; at the moment we go conservative
403 if (self->free < len) {
404 self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz);
405 self->free = 0;
406 } else {
407 self->free -= len;
408 }
409
410 // extend
411 mp_seq_copy((byte *)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte);
412 self->len += len;
413
414 return mp_const_none;
415 }
416 STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_extend_obj, array_extend);
417 #endif
418
array_subscr(mp_obj_t self_in,mp_obj_t index_in,mp_obj_t value)419 STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
420 if (value == MP_OBJ_NULL) {
421 // delete item
422 // TODO implement
423 // TODO: confirmed that both bytearray and array.array support
424 // slice deletion
425 return MP_OBJ_NULL; // op not supported
426 } else {
427 mp_obj_array_t *o = MP_OBJ_TO_PTR(self_in);
428 #if MICROPY_PY_BUILTINS_SLICE
429 if (mp_obj_is_type(index_in, &mp_type_slice)) {
430 mp_bound_slice_t slice;
431 if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
432 mp_raise_NotImplementedError(MP_ERROR_TEXT("only slices with step=1 (aka None) are supported"));
433 }
434 if (value != MP_OBJ_SENTINEL) {
435 #if MICROPY_PY_ARRAY_SLICE_ASSIGN
436 // Assign
437 size_t src_len;
438 void *src_items;
439 size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
440 if (mp_obj_is_obj(value) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) {
441 // value is array, bytearray or memoryview
442 mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value);
443 if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) {
444 compat_error:
445 mp_raise_ValueError(MP_ERROR_TEXT("lhs and rhs should be compatible"));
446 }
447 src_len = src_slice->len;
448 src_items = src_slice->items;
449 #if MICROPY_PY_BUILTINS_MEMORYVIEW
450 if (mp_obj_is_type(value, &mp_type_memoryview)) {
451 src_items = (uint8_t *)src_items + (src_slice->memview_offset * item_sz);
452 }
453 #endif
454 } else if (mp_obj_is_type(value, &mp_type_bytes)) {
455 if (item_sz != 1) {
456 goto compat_error;
457 }
458 mp_buffer_info_t bufinfo;
459 mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ);
460 src_len = bufinfo.len;
461 src_items = bufinfo.buf;
462 } else {
463 mp_raise_NotImplementedError(MP_ERROR_TEXT("array/bytes required on right side"));
464 }
465
466 // TODO: check src/dst compat
467 mp_int_t len_adj = src_len - (slice.stop - slice.start);
468 uint8_t *dest_items = o->items;
469 #if MICROPY_PY_BUILTINS_MEMORYVIEW
470 if (o->base.type == &mp_type_memoryview) {
471 if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
472 // store to read-only memoryview not allowed
473 return MP_OBJ_NULL;
474 }
475 if (len_adj != 0) {
476 goto compat_error;
477 }
478 dest_items += o->memview_offset * item_sz;
479 }
480 #endif
481 if (len_adj > 0) {
482 if ((size_t)len_adj > o->free) {
483 // TODO: alloc policy; at the moment we go conservative
484 o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz);
485 o->free = len_adj;
486 dest_items = o->items;
487 }
488 mp_seq_replace_slice_grow_inplace(dest_items, o->len,
489 slice.start, slice.stop, src_items, src_len, len_adj, item_sz);
490 } else {
491 mp_seq_replace_slice_no_grow(dest_items, o->len,
492 slice.start, slice.stop, src_items, src_len, item_sz);
493 // Clear "freed" elements at the end of list
494 // TODO: This is actually only needed for typecode=='O'
495 mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz);
496 // TODO: alloc policy after shrinking
497 }
498 o->free -= len_adj;
499 o->len += len_adj;
500 return mp_const_none;
501 #else
502 return MP_OBJ_NULL; // op not supported
503 #endif
504 }
505
506 mp_obj_array_t *res;
507 size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
508 assert(sz > 0);
509 #if MICROPY_PY_BUILTINS_MEMORYVIEW
510 if (o->base.type == &mp_type_memoryview) {
511 res = m_new_obj(mp_obj_array_t);
512 *res = *o;
513 res->memview_offset += slice.start;
514 res->len = slice.stop - slice.start;
515 } else
516 #endif
517 {
518 res = array_new(o->typecode, slice.stop - slice.start);
519 memcpy(res->items, (uint8_t *)o->items + slice.start * sz, (slice.stop - slice.start) * sz);
520 }
521 return MP_OBJ_FROM_PTR(res);
522 } else
523 #endif
524 {
525 size_t index = mp_get_index(o->base.type, o->len, index_in, false);
526 #if MICROPY_PY_BUILTINS_MEMORYVIEW
527 if (o->base.type == &mp_type_memoryview) {
528 index += o->memview_offset;
529 if (value != MP_OBJ_SENTINEL && !(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
530 // store to read-only memoryview
531 return MP_OBJ_NULL;
532 }
533 }
534 #endif
535 if (value == MP_OBJ_SENTINEL) {
536 // load
537 return mp_binary_get_val_array(o->typecode & TYPECODE_MASK, o->items, index);
538 } else {
539 // store
540 mp_binary_set_val_array(o->typecode & TYPECODE_MASK, o->items, index, value);
541 return mp_const_none;
542 }
543 }
544 }
545 }
546
array_get_buffer(mp_obj_t o_in,mp_buffer_info_t * bufinfo,mp_uint_t flags)547 STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
548 mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);
549 size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
550 bufinfo->buf = o->items;
551 bufinfo->len = o->len * sz;
552 bufinfo->typecode = o->typecode & TYPECODE_MASK;
553 #if MICROPY_PY_BUILTINS_MEMORYVIEW
554 if (o->base.type == &mp_type_memoryview) {
555 if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW) && (flags & MP_BUFFER_WRITE)) {
556 // read-only memoryview
557 return 1;
558 }
559 bufinfo->buf = (uint8_t *)bufinfo->buf + (size_t)o->memview_offset * sz;
560 }
561 #else
562 (void)flags;
563 #endif
564 return 0;
565 }
566
567 #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
568 STATIC const mp_rom_map_elem_t array_locals_dict_table[] = {
569 { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&array_append_obj) },
570 { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&array_extend_obj) },
571 #if MICROPY_CPYTHON_COMPAT
572 { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&bytes_decode_obj) },
573 #endif
574 };
575
576 STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table);
577 #endif
578
579 #if MICROPY_PY_ARRAY
580 const mp_obj_type_t mp_type_array = {
581 { &mp_type_type },
582 .name = MP_QSTR_array,
583 .print = array_print,
584 .make_new = array_make_new,
585 .getiter = array_iterator_new,
586 .unary_op = array_unary_op,
587 .binary_op = array_binary_op,
588 .subscr = array_subscr,
589 .buffer_p = { .get_buffer = array_get_buffer },
590 .locals_dict = (mp_obj_dict_t *)&array_locals_dict,
591 };
592 #endif
593
594 #if MICROPY_PY_BUILTINS_BYTEARRAY
595 const mp_obj_type_t mp_type_bytearray = {
596 { &mp_type_type },
597 .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,
598 .name = MP_QSTR_bytearray,
599 .print = array_print,
600 .make_new = bytearray_make_new,
601 .getiter = array_iterator_new,
602 .unary_op = array_unary_op,
603 .binary_op = array_binary_op,
604 .subscr = array_subscr,
605 .buffer_p = { .get_buffer = array_get_buffer },
606 .locals_dict = (mp_obj_dict_t *)&array_locals_dict,
607 };
608 #endif
609
610 #if MICROPY_PY_BUILTINS_MEMORYVIEW
611 const mp_obj_type_t mp_type_memoryview = {
612 { &mp_type_type },
613 .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,
614 .name = MP_QSTR_memoryview,
615 .make_new = memoryview_make_new,
616 .getiter = array_iterator_new,
617 .unary_op = array_unary_op,
618 .binary_op = array_binary_op,
619 #if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE
620 .attr = memoryview_attr,
621 #endif
622 .subscr = array_subscr,
623 .buffer_p = { .get_buffer = array_get_buffer },
624 };
625 #endif
626
627 /* unused
628 size_t mp_obj_array_len(mp_obj_t self_in) {
629 return ((mp_obj_array_t *)self_in)->len;
630 }
631 */
632
633 #if MICROPY_PY_BUILTINS_BYTEARRAY
mp_obj_new_bytearray(size_t n,void * items)634 mp_obj_t mp_obj_new_bytearray(size_t n, void *items) {
635 mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
636 memcpy(o->items, items, n);
637 return MP_OBJ_FROM_PTR(o);
638 }
639
640 // Create bytearray which references specified memory area
mp_obj_new_bytearray_by_ref(size_t n,void * items)641 mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items) {
642 mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
643 o->base.type = &mp_type_bytearray;
644 o->typecode = BYTEARRAY_TYPECODE;
645 o->free = 0;
646 o->len = n;
647 o->items = items;
648 return MP_OBJ_FROM_PTR(o);
649 }
650 #endif
651
652 /******************************************************************************/
653 // array iterator
654
655 typedef struct _mp_obj_array_it_t {
656 mp_obj_base_t base;
657 mp_obj_array_t *array;
658 size_t offset;
659 size_t cur;
660 } mp_obj_array_it_t;
661
array_it_iternext(mp_obj_t self_in)662 STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
663 mp_obj_array_it_t *self = MP_OBJ_TO_PTR(self_in);
664 if (self->cur < self->array->len) {
665 return mp_binary_get_val_array(self->array->typecode & TYPECODE_MASK, self->array->items, self->offset + self->cur++);
666 } else {
667 return MP_OBJ_STOP_ITERATION;
668 }
669 }
670
671 STATIC const mp_obj_type_t mp_type_array_it = {
672 { &mp_type_type },
673 .name = MP_QSTR_iterator,
674 .getiter = mp_identity_getiter,
675 .iternext = array_it_iternext,
676 };
677
array_iterator_new(mp_obj_t array_in,mp_obj_iter_buf_t * iter_buf)678 STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf) {
679 assert(sizeof(mp_obj_array_t) <= sizeof(mp_obj_iter_buf_t));
680 mp_obj_array_t *array = MP_OBJ_TO_PTR(array_in);
681 mp_obj_array_it_t *o = (mp_obj_array_it_t *)iter_buf;
682 o->base.type = &mp_type_array_it;
683 o->array = array;
684 o->offset = 0;
685 o->cur = 0;
686 #if MICROPY_PY_BUILTINS_MEMORYVIEW
687 if (array->base.type == &mp_type_memoryview) {
688 o->offset = array->memview_offset;
689 }
690 #endif
691 return MP_OBJ_FROM_PTR(o);
692 }
693
694 #endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW
695