LCOV - code coverage report
Current view: top level - py - objarray.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.19.1-724-gfb7d21153.info Lines: 270 270 100.0 %
Date: 2022-12-01 09:37:31 Functions: 19 19 100.0 %
Branches: 174 210 82.9 %

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

Generated by: LCOV version 1.15-5-g462f71d