Branch data Line data Source code
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 : : #define memview_offset_max ((1LL << MP_OBJ_ARRAY_FREE_SIZE_BITS) - 1)
57 : : #else
58 : : // make (& TYPECODE_MASK) a null operation if memorview not enabled
59 : : #define TYPECODE_MASK (~(size_t)0)
60 : : // memview_offset should not be accessed if memoryview is not enabled,
61 : : // so not defined to catch errors
62 : : #endif
63 : :
64 : : STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf);
65 : : STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
66 : : STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in);
67 : : STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
68 : :
69 : : /******************************************************************************/
70 : : // array
71 : :
72 : : #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
73 : 944 : STATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
74 : 944 : (void)kind;
75 : 944 : mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);
76 [ + + ]: 944 : if (o->typecode == BYTEARRAY_TYPECODE) {
77 : 820 : mp_print_str(print, "bytearray(b");
78 : 820 : mp_str_print_quoted(print, o->items, o->len, true);
79 : : } else {
80 : 124 : mp_printf(print, "array('%c'", o->typecode);
81 [ + + ]: 124 : if (o->len > 0) {
82 : 104 : mp_print_str(print, ", [");
83 [ + + ]: 452 : for (size_t i = 0; i < o->len; i++) {
84 [ + + ]: 348 : if (i > 0) {
85 : 244 : mp_print_str(print, ", ");
86 : : }
87 : 348 : mp_obj_print_helper(print, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR);
88 : : }
89 : 104 : mp_print_str(print, "]");
90 : : }
91 : : }
92 : 944 : mp_print_str(print, ")");
93 : 944 : }
94 : : #endif
95 : :
96 : : #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
97 : 4808 : STATIC mp_obj_array_t *array_new(char typecode, size_t n) {
98 : 4808 : int typecode_size = mp_binary_get_size('@', typecode, NULL);
99 : 4804 : mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
100 : : #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY
101 [ + + ]: 4784 : o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;
102 : : #elif MICROPY_PY_BUILTINS_BYTEARRAY
103 : : o->base.type = &mp_type_bytearray;
104 : : #else
105 : : o->base.type = &mp_type_array;
106 : : #endif
107 : 4784 : o->typecode = typecode;
108 : 4784 : o->free = 0;
109 : 4784 : o->len = n;
110 : 4784 : o->items = m_new(byte, typecode_size * o->len);
111 : 4784 : return o;
112 : : }
113 : : #endif
114 : :
115 : : #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
116 : 960 : STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
117 : : // bytearrays can be raw-initialised from anything with the buffer protocol
118 : : // other arrays can only be raw-initialised from bytes and bytearray objects
119 : 960 : mp_buffer_info_t bufinfo;
120 [ + + ]: 960 : if (((MICROPY_PY_BUILTINS_BYTEARRAY
121 : : && typecode == BYTEARRAY_TYPECODE)
122 : : || (MICROPY_PY_ARRAY
123 [ - + - + : 496 : && (mp_obj_is_type(initializer, &mp_type_bytes)
- + - + +
- + + ]
124 [ + - + + ]: 466 : || (MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(initializer, &mp_type_bytearray)))))
125 [ + + ]: 502 : && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) {
126 : : // construct array from raw bytes
127 : : // we round-down the len to make it a multiple of sz (CPython raises error)
128 : 404 : size_t sz = mp_binary_get_size('@', typecode, NULL);
129 : 404 : size_t len = bufinfo.len / sz;
130 : 404 : mp_obj_array_t *o = array_new(typecode, len);
131 : 400 : memcpy(o->items, bufinfo.buf, len * sz);
132 : 400 : return MP_OBJ_FROM_PTR(o);
133 : : }
134 : :
135 : 556 : size_t len;
136 : : // Try to create array of exact len if initializer len is known
137 : 556 : mp_obj_t len_in = mp_obj_len_maybe(initializer);
138 [ + + ]: 556 : if (len_in == MP_OBJ_NULL) {
139 : : len = 0;
140 : : } else {
141 : 534 : len = MP_OBJ_SMALL_INT_VALUE(len_in);
142 : : }
143 : :
144 : 556 : mp_obj_array_t *array = array_new(typecode, len);
145 : :
146 : 552 : mp_obj_t iterable = mp_getiter(initializer, NULL);
147 : 552 : mp_obj_t item;
148 : 552 : size_t i = 0;
149 [ + + ]: 5802 : while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
150 [ + + ]: 5245 : if (len == 0) {
151 : 3799 : array_append(MP_OBJ_FROM_PTR(array), item);
152 : : } else {
153 : 1446 : mp_binary_set_val_array(typecode, array->items, i++, item);
154 : : }
155 : : }
156 : :
157 : : return MP_OBJ_FROM_PTR(array);
158 : : }
159 : : #endif
160 : :
161 : : #if MICROPY_PY_ARRAY
162 : 1306 : 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) {
163 : 1306 : (void)type_in;
164 : 1306 : mp_arg_check_num(n_args, n_kw, 1, 2, false);
165 : :
166 : : // get typecode
167 : 1306 : const char *typecode = mp_obj_str_get_str(args[0]);
168 : :
169 [ + + ]: 1306 : if (n_args == 1) {
170 : : // 1 arg: make an empty array
171 : 810 : return MP_OBJ_FROM_PTR(array_new(*typecode, 0));
172 : : } else {
173 : : // 2 args: construct the array from the given object
174 : 496 : return array_construct(*typecode, args[1]);
175 : : }
176 : : }
177 : : #endif
178 : :
179 : : #if MICROPY_PY_BUILTINS_BYTEARRAY
180 : 3140 : 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) {
181 : 3140 : (void)type_in;
182 : : // Can take 2nd/3rd arg if constructs from str
183 : 3140 : mp_arg_check_num(n_args, n_kw, 0, 3, false);
184 : :
185 [ + + ]: 3140 : if (n_args == 0) {
186 : : // no args: construct an empty bytearray
187 : 52 : return MP_OBJ_FROM_PTR(array_new(BYTEARRAY_TYPECODE, 0));
188 [ + + + + : 3088 : } else if (mp_obj_is_int(args[0])) {
+ + ]
189 : : // 1 arg, an integer: construct a blank bytearray of that length
190 : 2620 : mp_uint_t len = mp_obj_get_int(args[0]);
191 : 2616 : mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len);
192 : 2612 : memset(o->items, 0, len);
193 : 2612 : return MP_OBJ_FROM_PTR(o);
194 : : } else {
195 : : // 1 arg: construct the bytearray from that
196 [ + + + - : 468 : if (mp_obj_is_str(args[0]) && n_args == 1) {
- + + + ]
197 : : #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
198 : : // Match bytes_make_new.
199 : : mp_raise_TypeError(MP_ERROR_TEXT("wrong number of arguments"));
200 : : #else
201 : 4 : mp_raise_TypeError(MP_ERROR_TEXT("string argument without an encoding"));
202 : : #endif
203 : : }
204 : 464 : return array_construct(BYTEARRAY_TYPECODE, args[0]);
205 : : }
206 : : }
207 : : #endif
208 : :
209 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW
210 : :
211 : 642 : mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) {
212 : 642 : mp_obj_array_t *self = m_new_obj(mp_obj_array_t);
213 : 638 : mp_obj_memoryview_init(self, typecode, 0, nitems, items);
214 : 638 : return MP_OBJ_FROM_PTR(self);
215 : : }
216 : :
217 : 642 : 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) {
218 : 642 : (void)type_in;
219 : :
220 : : // TODO possibly allow memoryview constructor to take start/stop so that one
221 : : // can do memoryview(b, 4, 8) instead of memoryview(b)[4:8] (uses less RAM)
222 : :
223 : 642 : mp_arg_check_num(n_args, n_kw, 1, 1, false);
224 : :
225 : 642 : mp_buffer_info_t bufinfo;
226 : 642 : mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
227 : :
228 : 642 : mp_obj_array_t *self = MP_OBJ_TO_PTR(mp_obj_new_memoryview(bufinfo.typecode,
229 : : bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL),
230 : : bufinfo.buf));
231 : :
232 : : // If the input object is a memoryview then need to point the items of the
233 : : // new memoryview to the start of the buffer so the GC can trace it.
234 [ + + ]: 638 : if (mp_obj_get_type(args[0]) == &mp_type_memoryview) {
235 : 8 : mp_obj_array_t *other = MP_OBJ_TO_PTR(args[0]);
236 : 8 : self->memview_offset = other->memview_offset;
237 : 8 : self->items = other->items;
238 : : }
239 : :
240 : : // test if the object can be written to
241 [ + + ]: 638 : if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {
242 : 432 : self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer
243 : : }
244 : :
245 : 638 : return MP_OBJ_FROM_PTR(self);
246 : : }
247 : :
248 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE
249 : 72 : STATIC void memoryview_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
250 [ + + ]: 72 : if (dest[0] != MP_OBJ_NULL) {
251 : : return;
252 : : }
253 [ + + ]: 68 : if (attr == MP_QSTR_itemsize) {
254 : 32 : mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in);
255 : 32 : dest[0] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->typecode & TYPECODE_MASK, NULL));
256 : : }
257 : : #if MICROPY_PY_BUILTINS_BYTES_HEX
258 : : else {
259 : : // Need to forward to locals dict.
260 : 36 : dest[1] = MP_OBJ_SENTINEL;
261 : : }
262 : : #endif
263 : : }
264 : : #endif
265 : :
266 : : #endif
267 : :
268 : 20577 : STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
269 : 20577 : mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);
270 [ + + + ]: 20577 : switch (op) {
271 : 8 : case MP_UNARY_OP_BOOL:
272 [ + + ]: 8 : return mp_obj_new_bool(o->len != 0);
273 : 20565 : case MP_UNARY_OP_LEN:
274 : 20565 : return MP_OBJ_NEW_SMALL_INT(o->len);
275 : : default:
276 : : return MP_OBJ_NULL; // op not supported
277 : : }
278 : : }
279 : :
280 : 1660 : STATIC int typecode_for_comparison(int typecode, bool *is_unsigned) {
281 [ + + ]: 1660 : if (typecode == BYTEARRAY_TYPECODE) {
282 : : typecode = 'B';
283 : : }
284 [ + + ]: 1478 : if (typecode <= 'Z') {
285 : 1060 : typecode += 32; // to lowercase
286 : 1060 : *is_unsigned = true;
287 : : }
288 : 1660 : return typecode;
289 : : }
290 : :
291 : 904 : STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
292 : 904 : mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in);
293 [ + + + + : 904 : switch (op) {
+ ]
294 : 16 : case MP_BINARY_OP_ADD: {
295 : : // allow to add anything that has the buffer protocol (extension to CPython)
296 : 16 : mp_buffer_info_t lhs_bufinfo;
297 : 16 : mp_buffer_info_t rhs_bufinfo;
298 : 16 : array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
299 : 16 : mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ);
300 : :
301 : 12 : size_t sz = mp_binary_get_size('@', lhs_bufinfo.typecode, NULL);
302 : :
303 : : // convert byte count to element count (in case rhs is not multiple of sz)
304 : 12 : size_t rhs_len = rhs_bufinfo.len / sz;
305 : :
306 : : // note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count
307 : 12 : mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len);
308 : 8 : mp_seq_cat((byte *)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte);
309 : 8 : return MP_OBJ_FROM_PTR(res);
310 : : }
311 : :
312 : 20 : case MP_BINARY_OP_INPLACE_ADD: {
313 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW
314 [ + + ]: 20 : if (lhs->base.type == &mp_type_memoryview) {
315 : : return MP_OBJ_NULL; // op not supported
316 : : }
317 : : #endif
318 : 16 : array_extend(lhs_in, rhs_in);
319 : 16 : return lhs_in;
320 : : }
321 : :
322 : 30 : case MP_BINARY_OP_CONTAINS: {
323 : : #if MICROPY_PY_BUILTINS_BYTEARRAY
324 : : // Can search string only in bytearray
325 : 30 : mp_buffer_info_t lhs_bufinfo;
326 : 30 : mp_buffer_info_t rhs_bufinfo;
327 [ + + ]: 30 : if (mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
328 [ + - + + ]: 24 : if (!mp_obj_is_type(lhs_in, &mp_type_bytearray)) {
329 : : return mp_const_false;
330 : : }
331 : 20 : array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
332 [ + + ]: 28 : return mp_obj_new_bool(
333 : 20 : find_subbytes(lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len, 1) != NULL);
334 : : }
335 : : #endif
336 : :
337 : : // Otherwise, can only look for a scalar numeric value in an array
338 [ + + + - : 6 : if (mp_obj_is_int(rhs_in) || mp_obj_is_float(rhs_in)) {
+ - - + -
+ - + - +
+ - - + ]
339 : 2 : mp_raise_NotImplementedError(NULL);
340 : : }
341 : :
342 : : return mp_const_false;
343 : : }
344 : :
345 : 834 : case MP_BINARY_OP_EQUAL:
346 : : case MP_BINARY_OP_LESS:
347 : : case MP_BINARY_OP_LESS_EQUAL:
348 : : case MP_BINARY_OP_MORE:
349 : : case MP_BINARY_OP_MORE_EQUAL: {
350 : 834 : mp_buffer_info_t lhs_bufinfo;
351 : 834 : mp_buffer_info_t rhs_bufinfo;
352 : 834 : array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
353 [ + + ]: 834 : if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
354 : : return mp_const_false;
355 : : }
356 : : // mp_seq_cmp_bytes is used so only compatible representations can be correctly compared.
357 : : // The type doesn't matter: array/bytearray/str/bytes all have the same buffer layout, so
358 : : // just check if the typecodes are compatible; for testing equality the types should have the
359 : : // same code except for signedness, and not be floating point because nan never equals nan.
360 : : // For > and < the types should be the same and unsigned.
361 : : // Note that typecode_for_comparison always returns lowercase letters to save code size.
362 : : // No need for (& TYPECODE_MASK) here: xxx_get_buffer already takes care of that.
363 : 830 : bool is_unsigned = false;
364 : 830 : const int lhs_code = typecode_for_comparison(lhs_bufinfo.typecode, &is_unsigned);
365 : 830 : const int rhs_code = typecode_for_comparison(rhs_bufinfo.typecode, &is_unsigned);
366 [ + + + + : 830 : if (lhs_code == rhs_code && lhs_code != 'f' && lhs_code != 'd' && (op == MP_BINARY_OP_EQUAL || is_unsigned)) {
+ + + - ]
367 [ + + ]: 658 : return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
368 : : }
369 : : // mp_obj_equal_not_equal treats returning MP_OBJ_NULL as 'fall back to pointer comparison'
370 : : // for MP_BINARY_OP_EQUAL but that is incompatible with CPython.
371 : 368 : mp_raise_NotImplementedError(NULL);
372 : : }
373 : :
374 : : default:
375 : : return MP_OBJ_NULL; // op not supported
376 : : }
377 : : }
378 : :
379 : : #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
380 : 3847 : STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {
381 : : // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)
382 [ + # + + : 3847 : assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray))
+ - - + ]
383 : : || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array)));
384 : 3847 : mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in);
385 : :
386 [ + + ]: 3847 : if (self->free == 0) {
387 : 514 : size_t item_sz = mp_binary_get_size('@', self->typecode, NULL);
388 : : // TODO: alloc policy
389 : 514 : self->free = 8;
390 : 514 : self->items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + self->free));
391 : 512 : mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz);
392 : : }
393 : 3845 : mp_binary_set_val_array(self->typecode, self->items, self->len, arg);
394 : : // only update length/free if set succeeded
395 : 3847 : self->len++;
396 : 3847 : self->free--;
397 : 3847 : return mp_const_none; // return None, as per CPython
398 : : }
399 : : MP_DEFINE_CONST_FUN_OBJ_2(mp_obj_array_append_obj, array_append);
400 : :
401 : 28 : STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) {
402 : : // self is not a memoryview, so we don't need to use (& TYPECODE_MASK)
403 [ + - + + : 28 : assert((MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(self_in, &mp_type_bytearray))
+ - - + ]
404 : : || (MICROPY_PY_ARRAY && mp_obj_is_type(self_in, &mp_type_array)));
405 : 28 : mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in);
406 : :
407 : : // allow to extend by anything that has the buffer protocol (extension to CPython)
408 : 28 : mp_buffer_info_t arg_bufinfo;
409 : 28 : mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ);
410 : :
411 : 28 : size_t sz = mp_binary_get_size('@', self->typecode, NULL);
412 : :
413 : : // convert byte count to element count
414 : 28 : size_t len = arg_bufinfo.len / sz;
415 : :
416 : : // make sure we have enough room to extend
417 : : // TODO: alloc policy; at the moment we go conservative
418 [ + + ]: 28 : if (self->free < len) {
419 : 24 : self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz);
420 : 16 : self->free = 0;
421 : : } else {
422 : 4 : self->free -= len;
423 : : }
424 : :
425 : : // extend
426 : 20 : mp_seq_copy((byte *)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte);
427 : 20 : self->len += len;
428 : :
429 : 20 : return mp_const_none;
430 : : }
431 : : MP_DEFINE_CONST_FUN_OBJ_2(mp_obj_array_extend_obj, array_extend);
432 : : #endif
433 : :
434 : 18917208 : STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
435 [ + + ]: 18917208 : if (value == MP_OBJ_NULL) {
436 : : // delete item
437 : : // TODO implement
438 : : // TODO: confirmed that both bytearray and array.array support
439 : : // slice deletion
440 : : return MP_OBJ_NULL; // op not supported
441 : : } else {
442 : 18917206 : mp_obj_array_t *o = MP_OBJ_TO_PTR(self_in);
443 : : #if MICROPY_PY_BUILTINS_SLICE
444 [ - + - + : 18917206 : if (mp_obj_is_type(index_in, &mp_type_slice)) {
- + - + +
+ + - ]
445 : 6804 : mp_bound_slice_t slice;
446 [ + + ]: 6804 : if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
447 : 2 : mp_raise_NotImplementedError(MP_ERROR_TEXT("only slices with step=1 (aka None) are supported"));
448 : : }
449 [ + + ]: 6802 : if (value != MP_OBJ_SENTINEL) {
450 : : #if MICROPY_PY_ARRAY_SLICE_ASSIGN
451 : : // Assign
452 : 4056 : size_t src_len;
453 : 4056 : void *src_items;
454 : 4056 : size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
455 [ + - + - : 4056 : if (mp_obj_is_obj(value) && MP_OBJ_TYPE_GET_SLOT_OR_NULL(((mp_obj_base_t *)MP_OBJ_TO_PTR(value))->type, subscr) == array_subscr) {
+ + ]
456 : : // value is array, bytearray or memoryview
457 : 2438 : mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value);
458 [ + + ]: 2438 : if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) {
459 : 4 : compat_error:
460 : 20 : mp_raise_ValueError(MP_ERROR_TEXT("lhs and rhs should be compatible"));
461 : : }
462 : 2434 : src_len = src_slice->len;
463 : 2434 : src_items = src_slice->items;
464 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW
465 [ + + ]: 2434 : if (mp_obj_is_type(value, &mp_type_memoryview)) {
466 : 2364 : src_items = (uint8_t *)src_items + (src_slice->memview_offset * item_sz);
467 : : }
468 : : #endif
469 [ - + - + : 1618 : } else if (mp_obj_is_type(value, &mp_type_bytes)) {
- + - + +
- + + ]
470 [ + + ]: 1616 : if (item_sz != 1) {
471 : 4 : goto compat_error;
472 : : }
473 : 1612 : mp_buffer_info_t bufinfo;
474 : 1612 : mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ);
475 : 1612 : src_len = bufinfo.len;
476 : 1612 : src_items = bufinfo.buf;
477 : : } else {
478 : 2 : mp_raise_NotImplementedError(MP_ERROR_TEXT("array/bytes required on right side"));
479 : : }
480 : :
481 : : // TODO: check src/dst compat
482 : 4046 : mp_int_t len_adj = src_len - (slice.stop - slice.start);
483 : 4046 : uint8_t *dest_items = o->items;
484 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW
485 [ + + ]: 4046 : if (o->base.type == &mp_type_memoryview) {
486 [ + + ]: 48 : if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
487 : : // store to read-only memoryview not allowed
488 : : return MP_OBJ_NULL;
489 : : }
490 [ + + ]: 44 : if (len_adj != 0) {
491 : 12 : goto compat_error;
492 : : }
493 : 32 : dest_items += o->memview_offset * item_sz;
494 : : }
495 : : #endif
496 [ + + ]: 4030 : if (len_adj > 0) {
497 [ + + ]: 1620 : if ((size_t)len_adj > o->free) {
498 : : // TODO: alloc policy; at the moment we go conservative
499 : 1592 : o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz);
500 : 1588 : o->free = len_adj;
501 : 1588 : dest_items = o->items;
502 : : }
503 : 1616 : mp_seq_replace_slice_grow_inplace(dest_items, o->len,
504 : 1616 : slice.start, slice.stop, src_items, src_len, len_adj, item_sz);
505 : : } else {
506 : 2410 : mp_seq_replace_slice_no_grow(dest_items, o->len,
507 : 2410 : slice.start, slice.stop, src_items, src_len, item_sz);
508 : : // Clear "freed" elements at the end of list
509 : : // TODO: This is actually only needed for typecode=='O'
510 : 2410 : mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz);
511 : : // TODO: alloc policy after shrinking
512 : : }
513 : 4026 : o->free -= len_adj;
514 : 4026 : o->len += len_adj;
515 : 4026 : return mp_const_none;
516 : : #else
517 : : return MP_OBJ_NULL; // op not supported
518 : : #endif
519 : : }
520 : :
521 : 2746 : mp_obj_array_t *res;
522 : 2746 : size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
523 [ - + ]: 2746 : assert(sz > 0);
524 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW
525 [ + + ]: 2746 : if (o->base.type == &mp_type_memoryview) {
526 [ + + ]: 2466 : if (slice.start > memview_offset_max) {
527 : 4 : mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("memoryview offset too large"));
528 : : }
529 : 2462 : res = m_new_obj(mp_obj_array_t);
530 : 2458 : *res = *o;
531 : 2458 : res->memview_offset += slice.start;
532 : 2458 : res->len = slice.stop - slice.start;
533 : : } else
534 : : #endif
535 : : {
536 : 280 : res = array_new(o->typecode, slice.stop - slice.start);
537 : 276 : memcpy(res->items, (uint8_t *)o->items + slice.start * sz, (slice.stop - slice.start) * sz);
538 : : }
539 : 2734 : return MP_OBJ_FROM_PTR(res);
540 : : } else
541 : : #endif
542 : : {
543 : 18910402 : size_t index = mp_get_index(o->base.type, o->len, index_in, false);
544 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW
545 [ + + ]: 19712403 : if (o->base.type == &mp_type_memoryview) {
546 : 66 : index += o->memview_offset;
547 [ + + + + ]: 66 : if (value != MP_OBJ_SENTINEL && !(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
548 : : // store to read-only memoryview
549 : : return MP_OBJ_NULL;
550 : : }
551 : : }
552 : : #endif
553 [ + + ]: 19712381 : if (value == MP_OBJ_SENTINEL) {
554 : : // load
555 : 11331442 : return mp_binary_get_val_array(o->typecode & TYPECODE_MASK, o->items, index);
556 : : } else {
557 : : // store
558 : 8380957 : mp_binary_set_val_array(o->typecode & TYPECODE_MASK, o->items, index, value);
559 : 8380957 : return mp_const_none;
560 : : }
561 : : }
562 : : }
563 : : }
564 : :
565 : 3208 : STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
566 : 3208 : mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);
567 : 3208 : size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
568 : 3208 : bufinfo->buf = o->items;
569 : 3208 : bufinfo->len = o->len * sz;
570 : 3208 : bufinfo->typecode = o->typecode & TYPECODE_MASK;
571 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW
572 [ + + ]: 3208 : if (o->base.type == &mp_type_memoryview) {
573 [ + + + + ]: 132 : if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW) && (flags & MP_BUFFER_WRITE)) {
574 : : // read-only memoryview
575 : : return 1;
576 : : }
577 : 128 : bufinfo->buf = (uint8_t *)bufinfo->buf + (size_t)o->memview_offset * sz;
578 : : }
579 : : #else
580 : : (void)flags;
581 : : #endif
582 : : return 0;
583 : : }
584 : :
585 : : #if MICROPY_PY_ARRAY
586 : : MP_DEFINE_CONST_OBJ_TYPE(
587 : : mp_type_array,
588 : : MP_QSTR_array,
589 : : MP_TYPE_FLAG_ITER_IS_GETITER,
590 : : make_new, array_make_new,
591 : : print, array_print,
592 : : iter, array_iterator_new,
593 : : unary_op, array_unary_op,
594 : : binary_op, array_binary_op,
595 : : subscr, array_subscr,
596 : : buffer, array_get_buffer,
597 : : locals_dict, &mp_obj_array_locals_dict
598 : : );
599 : : #endif
600 : :
601 : : #if MICROPY_PY_BUILTINS_BYTEARRAY
602 : : MP_DEFINE_CONST_OBJ_TYPE(
603 : : mp_type_bytearray,
604 : : MP_QSTR_bytearray,
605 : : MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER,
606 : : make_new, bytearray_make_new,
607 : : print, array_print,
608 : : iter, array_iterator_new,
609 : : unary_op, array_unary_op,
610 : : binary_op, array_binary_op,
611 : : subscr, array_subscr,
612 : : buffer, array_get_buffer,
613 : : locals_dict, &mp_obj_bytearray_locals_dict
614 : : );
615 : : #endif
616 : :
617 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW
618 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW_ITEMSIZE
619 : : #define MEMORYVIEW_TYPE_ATTR attr, memoryview_attr,
620 : : #else
621 : : #define MEMORYVIEW_TYPE_ATTR
622 : : #endif
623 : :
624 : : #if MICROPY_PY_BUILTINS_BYTES_HEX
625 : : #define MEMORYVIEW_TYPE_LOCALS_DICT locals_dict, &mp_obj_memoryview_locals_dict,
626 : : #else
627 : : #define MEMORYVIEW_TYPE_LOCALS_DICT
628 : : #endif
629 : :
630 : : MP_DEFINE_CONST_OBJ_TYPE(
631 : : mp_type_memoryview,
632 : : MP_QSTR_memoryview,
633 : : MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER,
634 : : make_new, memoryview_make_new,
635 : : iter, array_iterator_new,
636 : : unary_op, array_unary_op,
637 : : binary_op, array_binary_op,
638 : : MEMORYVIEW_TYPE_LOCALS_DICT
639 : : MEMORYVIEW_TYPE_ATTR
640 : : subscr, array_subscr,
641 : : buffer, array_get_buffer
642 : : );
643 : : #endif // MICROPY_PY_BUILTINS_MEMORYVIEW
644 : :
645 : : /* unused
646 : : size_t mp_obj_array_len(mp_obj_t self_in) {
647 : : return ((mp_obj_array_t *)self_in)->len;
648 : : }
649 : : */
650 : :
651 : : #if MICROPY_PY_BUILTINS_BYTEARRAY
652 : 78 : mp_obj_t mp_obj_new_bytearray(size_t n, const void *items) {
653 : 78 : mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
654 : 78 : memcpy(o->items, items, n);
655 : 78 : return MP_OBJ_FROM_PTR(o);
656 : : }
657 : :
658 : : // Create bytearray which references specified memory area
659 : 194 : mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items) {
660 : 194 : mp_obj_array_t *o = mp_obj_malloc(mp_obj_array_t, &mp_type_bytearray);
661 : 194 : o->typecode = BYTEARRAY_TYPECODE;
662 : 194 : o->free = 0;
663 : 194 : o->len = n;
664 : 194 : o->items = items;
665 : 194 : return MP_OBJ_FROM_PTR(o);
666 : : }
667 : : #endif
668 : :
669 : : /******************************************************************************/
670 : : // array iterator
671 : :
672 : : typedef struct _mp_obj_array_it_t {
673 : : mp_obj_base_t base;
674 : : mp_obj_array_t *array;
675 : : size_t offset;
676 : : size_t cur;
677 : : } mp_obj_array_it_t;
678 : :
679 : 4386 : STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
680 : 4386 : mp_obj_array_it_t *self = MP_OBJ_TO_PTR(self_in);
681 [ + + ]: 4386 : if (self->cur < self->array->len) {
682 : 4268 : return mp_binary_get_val_array(self->array->typecode & TYPECODE_MASK, self->array->items, self->offset + self->cur++);
683 : : } else {
684 : : return MP_OBJ_STOP_ITERATION;
685 : : }
686 : : }
687 : :
688 : : STATIC MP_DEFINE_CONST_OBJ_TYPE(
689 : : mp_type_array_it,
690 : : MP_QSTR_iterator,
691 : : MP_TYPE_FLAG_ITER_IS_ITERNEXT,
692 : : iter, array_it_iternext
693 : : );
694 : :
695 : 118 : STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf) {
696 : 118 : assert(sizeof(mp_obj_array_t) <= sizeof(mp_obj_iter_buf_t));
697 : 118 : mp_obj_array_t *array = MP_OBJ_TO_PTR(array_in);
698 : 118 : mp_obj_array_it_t *o = (mp_obj_array_it_t *)iter_buf;
699 : 118 : o->base.type = &mp_type_array_it;
700 : 118 : o->array = array;
701 : 118 : o->offset = 0;
702 : 118 : o->cur = 0;
703 : : #if MICROPY_PY_BUILTINS_MEMORYVIEW
704 [ + + ]: 118 : if (array->base.type == &mp_type_memoryview) {
705 : 76 : o->offset = array->memview_offset;
706 : : }
707 : : #endif
708 : 118 : return MP_OBJ_FROM_PTR(o);
709 : : }
710 : :
711 : : #endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW
|