LCOV - code coverage report
Current view: top level - py - objstr.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-342-g49af8cad4.info Lines: 1119 1120 99.9 %
Date: 2024-04-25 10:54:52 Functions: 73 73 100.0 %
Branches: 811 872 93.0 %

           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-2018 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                 :            : 
      31                 :            : #include "py/unicode.h"
      32                 :            : #include "py/objstr.h"
      33                 :            : #include "py/objlist.h"
      34                 :            : #include "py/runtime.h"
      35                 :            : #include "py/stackctrl.h"
      36                 :            : 
      37                 :            : #if MICROPY_PY_BUILTINS_STR_OP_MODULO
      38                 :            : static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict);
      39                 :            : #endif
      40                 :            : 
      41                 :            : static mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);
      42                 :            : static NORETURN void bad_implicit_conversion(mp_obj_t self_in);
      43                 :            : 
      44                 :            : static mp_obj_t mp_obj_new_str_type_from_vstr(const mp_obj_type_t *type, vstr_t *vstr);
      45                 :            : 
      46                 :       1624 : static void str_check_arg_type(const mp_obj_type_t *self_type, const mp_obj_t arg) {
      47                 :            :     // String operations generally need the args type to match the object they're called on,
      48                 :            :     // e.g. str.find(str), byte.startswith(byte)
      49                 :            :     // with the exception that bytes may be used for bytearray and vice versa.
      50                 :       1624 :     const mp_obj_type_t *arg_type = mp_obj_get_type(arg);
      51                 :            : 
      52                 :            :     #if MICROPY_PY_BUILTINS_BYTEARRAY
      53         [ -  + ]:       1624 :     if (arg_type == &mp_type_bytearray) {
      54                 :          0 :         arg_type = &mp_type_bytes;
      55                 :            :     }
      56         [ +  + ]:       1624 :     if (self_type == &mp_type_bytearray) {
      57                 :         48 :         self_type = &mp_type_bytes;
      58                 :            :     }
      59                 :            :     #endif
      60                 :            : 
      61         [ +  + ]:       1624 :     if (arg_type != self_type) {
      62                 :         48 :         bad_implicit_conversion(arg);
      63                 :            :     }
      64                 :       1576 : }
      65                 :            : 
      66                 :            : static void check_is_str_or_bytes(mp_obj_t self_in) {
      67                 :            :     mp_check_self(mp_obj_is_str_or_bytes(self_in));
      68                 :            : }
      69                 :            : 
      70                 :            : /******************************************************************************/
      71                 :            : /* str                                                                        */
      72                 :            : 
      73                 :       2754 : void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes) {
      74                 :            :     // this escapes characters, but it will be very slow to print (calling print many times)
      75                 :       2754 :     bool has_single_quote = false;
      76                 :       2754 :     bool has_double_quote = false;
      77         [ +  + ]:      27784 :     for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) {
      78         [ +  + ]:      25030 :         if (*s == '\'') {
      79                 :            :             has_single_quote = true;
      80         [ +  + ]:      25012 :         } else if (*s == '"') {
      81                 :         16 :             has_double_quote = true;
      82                 :            :         }
      83                 :            :     }
      84                 :       2754 :     int quote_char = '\'';
      85         [ +  + ]:       2754 :     if (has_single_quote && !has_double_quote) {
      86                 :         10 :         quote_char = '"';
      87                 :            :     }
      88                 :       2754 :     mp_printf(print, "%c", quote_char);
      89         [ +  + ]:      29514 :     for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
      90         [ +  + ]:      26760 :         if (*s == quote_char) {
      91                 :         14 :             mp_printf(print, "\\%c", quote_char);
      92         [ +  + ]:      26746 :         } else if (*s == '\\') {
      93                 :          6 :             mp_print_str(print, "\\\\");
      94   [ +  +  +  -  :      26740 :         } else if (*s >= 0x20 && *s != 0x7f && (!is_bytes || *s < 0x80)) {
                   +  + ]
      95                 :            :             // In strings, anything which is not ascii control character
      96                 :            :             // is printed as is, this includes characters in range 0x80-0xff
      97                 :            :             // (which can be non-Latin letters, etc.)
      98                 :      17080 :             mp_printf(print, "%c", *s);
      99         [ +  + ]:       9660 :         } else if (*s == '\n') {
     100                 :        164 :             mp_print_str(print, "\\n");
     101         [ +  + ]:       9496 :         } else if (*s == '\r') {
     102                 :         52 :             mp_print_str(print, "\\r");
     103         [ +  + ]:       9444 :         } else if (*s == '\t') {
     104                 :         88 :             mp_print_str(print, "\\t");
     105                 :            :         } else {
     106                 :       9356 :             mp_printf(print, "\\x%02x", *s);
     107                 :            :         }
     108                 :            :     }
     109                 :       2754 :     mp_printf(print, "%c", quote_char);
     110                 :       2754 : }
     111                 :            : 
     112                 :            : #if MICROPY_PY_JSON
     113                 :        116 : void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len) {
     114                 :            :     // for JSON spec, see http://www.ietf.org/rfc/rfc4627.txt
     115                 :            :     // if we are given a valid utf8-encoded string, we will print it in a JSON-conforming way
     116                 :        116 :     mp_print_str(print, "\"");
     117         [ +  + ]:        608 :     for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
     118         [ +  + ]:        492 :         if (*s == '"' || *s == '\\') {
     119                 :         32 :             mp_printf(print, "\\%c", *s);
     120         [ +  + ]:        460 :         } else if (*s >= 32) {
     121                 :            :             // this will handle normal and utf-8 encoded chars
     122                 :        380 :             mp_printf(print, "%c", *s);
     123         [ +  + ]:         80 :         } else if (*s == '\n') {
     124                 :         16 :             mp_print_str(print, "\\n");
     125         [ +  + ]:         64 :         } else if (*s == '\r') {
     126                 :         16 :             mp_print_str(print, "\\r");
     127         [ +  + ]:         48 :         } else if (*s == '\t') {
     128                 :         16 :             mp_print_str(print, "\\t");
     129                 :            :         } else {
     130                 :            :             // this will handle control chars
     131                 :         32 :             mp_printf(print, "\\u%04x", *s);
     132                 :            :         }
     133                 :            :     }
     134                 :        116 :     mp_print_str(print, "\"");
     135                 :        116 : }
     136                 :            : #endif
     137                 :            : 
     138                 :       1804 : static void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     139         [ -  + ]:       1804 :     GET_STR_DATA_LEN(self_in, str_data, str_len);
     140                 :            :     #if MICROPY_PY_JSON
     141         [ +  + ]:       1804 :     if (kind == PRINT_JSON) {
     142                 :          2 :         mp_str_print_json(print, str_data, str_len);
     143                 :          2 :         return;
     144                 :            :     }
     145                 :            :     #endif
     146                 :            :     #if !MICROPY_PY_BUILTINS_STR_UNICODE
     147                 :            :     bool is_bytes = mp_obj_is_type(self_in, &mp_type_bytes);
     148                 :            :     #else
     149                 :       1802 :     bool is_bytes = true;
     150                 :            :     #endif
     151         [ +  + ]:       1802 :     if (kind == PRINT_RAW || (!MICROPY_PY_BUILTINS_STR_UNICODE && kind == PRINT_STR && !is_bytes)) {
     152                 :          4 :         print->print_strn(print->data, (const char *)str_data, str_len);
     153                 :            :     } else {
     154                 :       1798 :         if (is_bytes) {
     155                 :       1798 :             print->print_strn(print->data, "b", 1);
     156                 :            :         }
     157                 :       1798 :         mp_str_print_quoted(print, str_data, str_len, is_bytes);
     158                 :            :     }
     159                 :            : }
     160                 :            : 
     161                 :      50090 : mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     162                 :            :     #if MICROPY_CPYTHON_COMPAT
     163         [ +  + ]:      50090 :     if (n_kw != 0) {
     164                 :          2 :         mp_arg_error_unimpl_kw();
     165                 :            :     }
     166                 :            :     #endif
     167                 :            : 
     168                 :      50088 :     mp_arg_check_num(n_args, n_kw, 0, 3, false);
     169                 :            : 
     170      [ +  +  + ]:      50084 :     switch (n_args) {
     171                 :            :         case 0:
     172                 :            :             return MP_OBJ_NEW_QSTR(MP_QSTR_);
     173                 :            : 
     174                 :      50030 :         case 1: {
     175                 :      50030 :             vstr_t vstr;
     176                 :      50030 :             mp_print_t print;
     177                 :      50030 :             vstr_init_print(&vstr, 16, &print);
     178                 :      50030 :             mp_obj_print_helper(&print, args[0], PRINT_STR);
     179                 :      50030 :             return mp_obj_new_str_type_from_vstr(type, &vstr);
     180                 :            :         }
     181                 :            : 
     182                 :            :         default: // 2 or 3 args
     183                 :            :             // TODO: validate 2nd/3rd args
     184   [ +  -  +  + ]:         50 :             if (mp_obj_is_type(args[0], &mp_type_bytes)) {
     185         [ -  + ]:         24 :                 GET_STR_DATA_LEN(args[0], str_data, str_len);
     186         [ -  + ]:         24 :                 GET_STR_HASH(args[0], str_hash);
     187         [ +  + ]:         24 :                 if (str_hash == 0) {
     188                 :          6 :                     str_hash = qstr_compute_hash(str_data, str_len);
     189                 :            :                 }
     190                 :            :                 #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
     191         [ +  + ]:         24 :                 if (!utf8_check(str_data, str_len)) {
     192                 :          6 :                     mp_raise_msg(&mp_type_UnicodeError, NULL);
     193                 :            :                 }
     194                 :            :                 #endif
     195                 :            : 
     196                 :            :                 // Check if a qstr with this data already exists
     197                 :         18 :                 qstr q = qstr_find_strn((const char *)str_data, str_len);
     198         [ +  + ]:         18 :                 if (q != MP_QSTRnull) {
     199                 :          4 :                     return MP_OBJ_NEW_QSTR(q);
     200                 :            :                 }
     201                 :            : 
     202                 :         14 :                 mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len));
     203                 :         14 :                 o->data = str_data;
     204                 :         14 :                 o->hash = str_hash;
     205                 :         14 :                 return MP_OBJ_FROM_PTR(o);
     206                 :            :             } else {
     207                 :         26 :                 mp_buffer_info_t bufinfo;
     208                 :         26 :                 mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
     209                 :            :                 // This will utf-8 check the input.
     210                 :         26 :                 return mp_obj_new_str(bufinfo.buf, bufinfo.len);
     211                 :            :             }
     212                 :            :     }
     213                 :            : }
     214                 :            : 
     215                 :        263 : static mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     216                 :        263 :     (void)type_in;
     217                 :            : 
     218                 :            :     #if MICROPY_CPYTHON_COMPAT
     219         [ +  + ]:        263 :     if (n_kw != 0) {
     220                 :          2 :         mp_arg_error_unimpl_kw();
     221                 :            :     }
     222                 :            :     #else
     223                 :            :     (void)n_kw;
     224                 :            :     #endif
     225                 :            : 
     226         [ +  + ]:        261 :     if (n_args == 0) {
     227                 :            :         return mp_const_empty_bytes;
     228                 :            :     }
     229                 :            : 
     230   [ +  +  +  + ]:        253 :     if (mp_obj_is_type(args[0], &mp_type_bytes)) {
     231                 :            :         return args[0];
     232                 :            :     }
     233                 :            : 
     234   [ +  +  +  +  :        243 :     if (mp_obj_is_str(args[0])) {
                   +  + ]
     235         [ +  + ]:         32 :         if (n_args < 2 || n_args > 3) {
     236                 :            :             #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
     237                 :            :             goto wrong_args;
     238                 :            :             #else
     239                 :          8 :             mp_raise_TypeError(MP_ERROR_TEXT("string argument without an encoding"));
     240                 :            :             #endif
     241                 :            :         }
     242         [ +  + ]:         24 :         GET_STR_DATA_LEN(args[0], str_data, str_len);
     243         [ +  + ]:         24 :         GET_STR_HASH(args[0], str_hash);
     244         [ +  + ]:         24 :         if (str_hash == 0) {
     245                 :          2 :             str_hash = qstr_compute_hash(str_data, str_len);
     246                 :            :         }
     247                 :         24 :         mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(&mp_type_bytes, NULL, str_len));
     248                 :         24 :         o->data = str_data;
     249                 :         24 :         o->hash = str_hash;
     250                 :         24 :         return MP_OBJ_FROM_PTR(o);
     251                 :            :     }
     252                 :            : 
     253         [ +  + ]:        211 :     if (n_args > 1) {
     254                 :          4 :         goto wrong_args;
     255                 :            :     }
     256                 :            : 
     257         [ +  + ]:        207 :     if (mp_obj_is_small_int(args[0])) {
     258                 :         20 :         mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]);
     259         [ +  + ]:         20 :         if (len < 0) {
     260                 :          4 :             mp_raise_ValueError(NULL);
     261                 :            :         }
     262                 :         16 :         vstr_t vstr;
     263                 :         16 :         vstr_init_len(&vstr, len);
     264                 :         16 :         memset(vstr.buf, 0, len);
     265                 :         16 :         return mp_obj_new_bytes_from_vstr(&vstr);
     266                 :            :     }
     267                 :            : 
     268                 :            :     // check if argument has the buffer protocol
     269                 :        187 :     mp_buffer_info_t bufinfo;
     270         [ +  + ]:        187 :     if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {
     271                 :         92 :         return mp_obj_new_bytes(bufinfo.buf, bufinfo.len);
     272                 :            :     }
     273                 :            : 
     274                 :         95 :     vstr_t vstr;
     275                 :            :     // Try to create array of exact len if initializer len is known
     276                 :         95 :     mp_obj_t len_in = mp_obj_len_maybe(args[0]);
     277         [ +  + ]:         95 :     if (len_in == MP_OBJ_NULL) {
     278                 :         12 :         vstr_init(&vstr, 16);
     279                 :            :     } else {
     280                 :         83 :         mp_int_t len = MP_OBJ_SMALL_INT_VALUE(len_in);
     281                 :         83 :         vstr_init(&vstr, len);
     282                 :            :     }
     283                 :            : 
     284                 :         95 :     mp_obj_iter_buf_t iter_buf;
     285                 :         95 :     mp_obj_t iterable = mp_getiter(args[0], &iter_buf);
     286                 :         95 :     mp_obj_t item;
     287         [ +  + ]:       1451 :     while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
     288                 :       1364 :         mp_int_t val = mp_obj_get_int(item);
     289                 :            :         #if MICROPY_FULL_CHECKS
     290         [ +  + ]:       1364 :         if (val < 0 || val > 255) {
     291                 :          8 :             mp_raise_ValueError(MP_ERROR_TEXT("bytes value out of range"));
     292                 :            :         }
     293                 :            :         #endif
     294                 :       1356 :         vstr_add_byte(&vstr, val);
     295                 :            :     }
     296                 :            : 
     297                 :         83 :     return mp_obj_new_bytes_from_vstr(&vstr);
     298                 :            : 
     299                 :          4 : wrong_args:
     300                 :          4 :     mp_raise_TypeError(MP_ERROR_TEXT("wrong number of arguments"));
     301                 :            : }
     302                 :            : 
     303                 :            : // like strstr but with specified length and allows \0 bytes
     304                 :            : // TODO replace with something more efficient/standard
     305                 :       2380 : const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction) {
     306         [ +  + ]:       2380 :     if (hlen >= nlen) {
     307                 :       1916 :         size_t str_index, str_index_end;
     308         [ +  + ]:       1916 :         if (direction > 0) {
     309                 :       1720 :             str_index = 0;
     310                 :       1720 :             str_index_end = hlen - nlen;
     311                 :            :         } else {
     312                 :        196 :             str_index = hlen - nlen;
     313                 :        196 :             str_index_end = 0;
     314                 :            :         }
     315                 :     289560 :         for (;;) {
     316         [ +  + ]:     145738 :             if (memcmp(&haystack[str_index], needle, nlen) == 0) {
     317                 :            :                 // found
     318                 :            :                 return haystack + str_index;
     319                 :            :             }
     320         [ +  + ]:     144224 :             if (str_index == str_index_end) {
     321                 :            :                 // not found
     322                 :            :                 break;
     323                 :            :             }
     324                 :     143822 :             str_index += direction;
     325                 :            :         }
     326                 :            :     }
     327                 :            :     return NULL;
     328                 :            : }
     329                 :            : 
     330                 :            : // Note: this function is used to check if an object is a str or bytes, which
     331                 :            : // works because both those types use it as their binary_op method.  Revisit
     332                 :            : // mp_obj_is_str_or_bytes if this fact changes.
     333                 :     202047 : mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
     334                 :            :     // check for modulo
     335         [ +  + ]:     202047 :     if (op == MP_BINARY_OP_MODULO) {
     336                 :            :         #if MICROPY_PY_BUILTINS_STR_OP_MODULO
     337                 :      88160 :         mp_obj_t *args = &rhs_in;
     338                 :      88160 :         size_t n_args = 1;
     339                 :      88160 :         mp_obj_t dict = MP_OBJ_NULL;
     340   [ -  +  -  +  :      88160 :         if (mp_obj_is_type(rhs_in, &mp_type_tuple)) {
          -  +  -  +  +  
                +  +  + ]
     341                 :            :             // TODO: Support tuple subclasses?
     342                 :       6578 :             mp_obj_tuple_get(rhs_in, &n_args, &args);
     343   [ -  +  -  +  :      81582 :         } else if (mp_obj_is_type(rhs_in, &mp_type_dict)) {
          -  +  -  +  +  
                +  +  + ]
     344                 :         42 :             dict = rhs_in;
     345                 :            :         }
     346                 :      88160 :         return str_modulo_format(lhs_in, n_args, args, dict);
     347                 :            :         #else
     348                 :            :         return MP_OBJ_NULL;
     349                 :            :         #endif
     350                 :            :     }
     351                 :            : 
     352                 :            :     // from now on we need lhs type and data, so extract them
     353                 :     113887 :     const mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in);
     354         [ +  + ]:     113887 :     GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len);
     355                 :            : 
     356                 :            :     // check for multiply
     357         [ +  + ]:     113887 :     if (op == MP_BINARY_OP_MULTIPLY) {
     358                 :        330 :         mp_int_t n;
     359         [ +  + ]:        330 :         if (!mp_obj_get_int_maybe(rhs_in, &n)) {
     360                 :            :             return MP_OBJ_NULL; // op not supported
     361                 :            :         }
     362         [ +  + ]:        318 :         if (n <= 0) {
     363         [ +  + ]:         48 :             if (lhs_type == &mp_type_str) {
     364                 :            :                 return MP_OBJ_NEW_QSTR(MP_QSTR_); // empty str
     365                 :            :             } else {
     366                 :         24 :                 return mp_const_empty_bytes;
     367                 :            :             }
     368                 :            :         }
     369                 :        270 :         vstr_t vstr;
     370                 :        270 :         vstr_init_len(&vstr, lhs_len * n);
     371                 :        270 :         mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, vstr.buf);
     372                 :        270 :         return mp_obj_new_str_type_from_vstr(lhs_type, &vstr);
     373                 :            :     }
     374                 :            : 
     375                 :            :     // From now on all operations allow:
     376                 :            :     //    - str with str
     377                 :            :     //    - bytes with bytes
     378                 :            :     //    - bytes with bytearray
     379                 :            :     //    - bytes with array.array
     380                 :            :     // To do this efficiently we use the buffer protocol to extract the raw
     381                 :            :     // data for the rhs, but only if the lhs is a bytes object.
     382                 :            :     //
     383                 :            :     // NOTE: CPython does not allow comparison between bytes ard array.array
     384                 :            :     // (even if the array is of type 'b'), even though it allows addition of
     385                 :            :     // such types.  We are not compatible with this (we do allow comparison
     386                 :            :     // of bytes with anything that has the buffer protocol).  It would be
     387                 :            :     // easy to "fix" this with a bit of extra logic below, but it costs code
     388                 :            :     // size and execution time so we don't.
     389                 :            : 
     390                 :     113557 :     const byte *rhs_data;
     391                 :     113557 :     size_t rhs_len;
     392         [ +  + ]:     113557 :     if (lhs_type == mp_obj_get_type(rhs_in)) {
     393         [ +  + ]:     112955 :         GET_STR_DATA_LEN(rhs_in, rhs_data_, rhs_len_);
     394                 :     112955 :         rhs_data = rhs_data_;
     395                 :     112955 :         rhs_len = rhs_len_;
     396         [ +  + ]:        602 :     } else if (lhs_type == &mp_type_bytes) {
     397                 :        550 :         mp_buffer_info_t bufinfo;
     398         [ +  + ]:        550 :         if (!mp_get_buffer(rhs_in, &bufinfo, MP_BUFFER_READ)) {
     399                 :         22 :             return MP_OBJ_NULL; // op not supported
     400                 :            :         }
     401                 :        528 :         rhs_data = bufinfo.buf;
     402                 :        528 :         rhs_len = bufinfo.len;
     403                 :            :     } else {
     404                 :            :         // LHS is str and RHS has an incompatible type
     405                 :            :         // (except if operation is EQUAL, but that's handled by mp_obj_equal)
     406                 :            : 
     407                 :            :         // CONTAINS must fail with a bad-implicit-conversion exception, because
     408                 :            :         // otherwise mp_binary_op() will fallback to `list(lhs).__contains__(rhs)`.
     409         [ +  + ]:         52 :         if (op == MP_BINARY_OP_CONTAINS) {
     410                 :          4 :             bad_implicit_conversion(rhs_in);
     411                 :            :         }
     412                 :            : 
     413                 :            :         // All other operations are not supported, and may be handled by another
     414                 :            :         // type, eg for reverse operations.
     415                 :            :         return MP_OBJ_NULL;
     416                 :            :     }
     417                 :            : 
     418   [ +  +  +  + ]:     113483 :     switch (op) {
     419                 :      81900 :         case MP_BINARY_OP_ADD:
     420                 :            :         case MP_BINARY_OP_INPLACE_ADD: {
     421   [ +  +  +  + ]:      81900 :             if (lhs_len == 0 && mp_obj_get_type(rhs_in) == lhs_type) {
     422                 :         24 :                 return rhs_in;
     423                 :            :             }
     424         [ +  + ]:      81876 :             if (rhs_len == 0) {
     425                 :            :                 return lhs_in;
     426                 :            :             }
     427                 :            : 
     428                 :      73656 :             vstr_t vstr;
     429                 :      73656 :             vstr_init_len(&vstr, lhs_len + rhs_len);
     430                 :      73656 :             memcpy(vstr.buf, lhs_data, lhs_len);
     431                 :      73656 :             memcpy(vstr.buf + lhs_len, rhs_data, rhs_len);
     432                 :      73656 :             return mp_obj_new_str_type_from_vstr(lhs_type, &vstr);
     433                 :            :         }
     434                 :            : 
     435                 :        690 :         case MP_BINARY_OP_CONTAINS:
     436         [ +  + ]:        690 :             return mp_obj_new_bool(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL);
     437                 :            : 
     438                 :            :         // case MP_BINARY_OP_NOT_EQUAL: // This is never passed here
     439                 :      30879 :         case MP_BINARY_OP_EQUAL: // This will be passed only for bytes, str is dealt with in mp_obj_equal()
     440                 :            :         case MP_BINARY_OP_LESS:
     441                 :            :         case MP_BINARY_OP_LESS_EQUAL:
     442                 :            :         case MP_BINARY_OP_MORE:
     443                 :            :         case MP_BINARY_OP_MORE_EQUAL:
     444         [ +  + ]:      30879 :             return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len));
     445                 :            : 
     446                 :            :         default:
     447                 :            :             return MP_OBJ_NULL; // op not supported
     448                 :            :     }
     449                 :            : }
     450                 :            : 
     451                 :            : #if !MICROPY_PY_BUILTINS_STR_UNICODE
     452                 :            : // objstrunicode defines own version
     453                 :            : const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len,
     454                 :            :     mp_obj_t index, bool is_slice) {
     455                 :            :     size_t index_val = mp_get_index(type, self_len, index, is_slice);
     456                 :            :     return self_data + index_val;
     457                 :            : }
     458                 :            : #endif
     459                 :            : 
     460                 :            : // This is used for both bytes and 8-bit strings. This is not used for unicode strings.
     461                 :    2645703 : static mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
     462                 :    2645703 :     const mp_obj_type_t *type = mp_obj_get_type(self_in);
     463         [ -  + ]:    2645835 :     GET_STR_DATA_LEN(self_in, self_data, self_len);
     464         [ +  + ]:    2645835 :     if (value == MP_OBJ_SENTINEL) {
     465                 :            :         // load
     466                 :            :         #if MICROPY_PY_BUILTINS_SLICE
     467   [ -  +  -  +  :    2645827 :         if (mp_obj_is_type(index, &mp_type_slice)) {
          -  +  -  +  +  
                +  +  - ]
     468                 :         16 :             mp_bound_slice_t slice;
     469         [ +  + ]:         16 :             if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) {
     470                 :          2 :                 mp_raise_NotImplementedError(MP_ERROR_TEXT("only slices with step=1 (aka None) are supported"));
     471                 :            :             }
     472                 :         14 :             return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start);
     473                 :            :         }
     474                 :            :         #endif
     475                 :    2645811 :         size_t index_val = mp_get_index(type, self_len, index, false);
     476                 :            :         // If we have unicode enabled the type will always be bytes, so take the short cut.
     477                 :    2603861 :         if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) {
     478                 :    2603861 :             return MP_OBJ_NEW_SMALL_INT(self_data[index_val]);
     479                 :            :         } else {
     480                 :            :             return mp_obj_new_str_via_qstr((char *)&self_data[index_val], 1);
     481                 :            :         }
     482                 :            :     } else {
     483                 :            :         return MP_OBJ_NULL; // op not supported
     484                 :            :     }
     485                 :            : }
     486                 :            : 
     487                 :        422 : static mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
     488                 :        422 :     check_is_str_or_bytes(self_in);
     489                 :        422 :     const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
     490                 :        422 :     const mp_obj_type_t *ret_type = self_type;
     491                 :            : 
     492                 :            :     // get separation string
     493         [ +  + ]:        422 :     GET_STR_DATA_LEN(self_in, sep_str, sep_len);
     494                 :            : 
     495                 :            :     // process args
     496                 :        422 :     size_t seq_len;
     497                 :        422 :     mp_obj_t *seq_items;
     498                 :            : 
     499   [ -  +  -  +  :        422 :     if (!mp_obj_is_type(arg, &mp_type_list) && !mp_obj_is_type(arg, &mp_type_tuple)) {
          -  +  -  +  +  
          +  +  +  -  +  
          -  +  -  +  -  
             +  +  +  +  
                      + ]
     500                 :            :         // arg is not a list nor a tuple, try to convert it to a list
     501                 :            :         // TODO: Try to optimize?
     502                 :        194 :         arg = mp_obj_list_make_new(&mp_type_list, 1, 0, &arg);
     503                 :            :     }
     504                 :        418 :     mp_obj_get_array(arg, &seq_len, &seq_items);
     505                 :            : 
     506                 :            :     // count required length
     507                 :        418 :     size_t required_len = 0;
     508                 :            :     #if MICROPY_PY_BUILTINS_BYTEARRAY
     509         [ +  + ]:        418 :     if (self_type == &mp_type_bytearray) {
     510                 :          8 :         self_type = &mp_type_bytes;
     511                 :            :     }
     512                 :            :     #endif
     513         [ +  + ]:      25254 :     for (size_t i = 0; i < seq_len; i++) {
     514                 :      24844 :         const mp_obj_type_t *seq_type = mp_obj_get_type(seq_items[i]);
     515                 :            :         #if MICROPY_PY_BUILTINS_BYTEARRAY
     516         [ +  + ]:      24844 :         if (seq_type == &mp_type_bytearray) {
     517                 :          8 :             seq_type = &mp_type_bytes;
     518                 :            :         }
     519                 :            :         #endif
     520         [ +  + ]:      24844 :         if (seq_type != self_type) {
     521                 :          8 :             mp_raise_TypeError(
     522                 :          8 :                 MP_ERROR_TEXT("join expects a list of str/bytes objects consistent with self object"));
     523                 :            :         }
     524         [ +  + ]:      24836 :         if (i > 0) {
     525                 :      24438 :             required_len += sep_len;
     526                 :            :         }
     527         [ +  + ]:      24836 :         GET_STR_LEN(seq_items[i], l);
     528                 :      24836 :         required_len += l;
     529                 :            :     }
     530                 :            : 
     531                 :            :     // make joined string
     532                 :        410 :     vstr_t vstr;
     533                 :        410 :     vstr_init_len(&vstr, required_len);
     534                 :        410 :     byte *data = (byte *)vstr.buf;
     535         [ +  + ]:      25246 :     for (size_t i = 0; i < seq_len; i++) {
     536         [ +  + ]:      24836 :         if (i > 0) {
     537                 :      24438 :             memcpy(data, sep_str, sep_len);
     538                 :      24438 :             data += sep_len;
     539                 :            :         }
     540         [ +  + ]:      24836 :         GET_STR_DATA_LEN(seq_items[i], s, l);
     541                 :      24836 :         memcpy(data, s, l);
     542                 :      24836 :         data += l;
     543                 :            :     }
     544                 :            : 
     545                 :            :     // return joined string
     546                 :        410 :     return mp_obj_new_str_type_from_vstr(ret_type, &vstr);
     547                 :            : }
     548                 :            : MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);
     549                 :            : 
     550                 :        313 : mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) {
     551                 :        313 :     const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
     552                 :        313 :     mp_int_t splits = -1;
     553                 :        313 :     mp_obj_t sep = mp_const_none;
     554         [ +  + ]:        313 :     if (n_args > 1) {
     555                 :        289 :         sep = args[1];
     556         [ +  + ]:        289 :         if (n_args > 2) {
     557                 :         76 :             splits = mp_obj_get_int(args[2]);
     558                 :            :         }
     559                 :            :     }
     560                 :            : 
     561                 :        313 :     mp_obj_t res = mp_obj_new_list(0, NULL);
     562         [ +  + ]:        313 :     GET_STR_DATA_LEN(args[0], s, len);
     563                 :        313 :     const byte *top = s + len;
     564                 :            : 
     565         [ +  + ]:        313 :     if (sep == mp_const_none) {
     566                 :            :         // sep not given, so separate on whitespace
     567                 :            : 
     568                 :            :         // Initial whitespace is not counted as split, so we pre-do it
     569   [ +  -  +  + ]:        216 :         while (s < top && unichar_isspace(*s)) {
     570                 :        144 :             s++;
     571                 :            :         }
     572         [ +  + ]:        176 :         while (s < top && splits != 0) {
     573                 :            :             const byte *start = s;
     574   [ +  +  +  + ]:        296 :             while (s < top && !unichar_isspace(*s)) {
     575                 :        172 :                 s++;
     576                 :            :             }
     577                 :        124 :             mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start));
     578         [ +  + ]:        124 :             if (s >= top) {
     579                 :            :                 break;
     580                 :            :             }
     581   [ +  +  +  + ]:        360 :             while (s < top && unichar_isspace(*s)) {
     582                 :        256 :                 s++;
     583                 :            :             }
     584         [ +  + ]:        104 :             if (splits > 0) {
     585                 :         32 :                 splits--;
     586                 :            :             }
     587                 :            :         }
     588                 :            : 
     589         [ +  + ]:         72 :         if (s < top) {
     590                 :         24 :             mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, s, top - s));
     591                 :            :         }
     592                 :            : 
     593                 :            :     } else {
     594                 :            :         // sep given
     595                 :        241 :         str_check_arg_type(self_type, sep);
     596                 :            : 
     597                 :        237 :         size_t sep_len;
     598                 :        237 :         const char *sep_str = mp_obj_str_get_data(sep, &sep_len);
     599                 :            : 
     600         [ +  + ]:        237 :         if (sep_len == 0) {
     601                 :         12 :             mp_raise_ValueError(MP_ERROR_TEXT("empty separator"));
     602                 :            :         }
     603                 :            : 
     604                 :        580 :         for (;;) {
     605                 :        580 :             const byte *start = s;
     606                 :      19176 :             for (;;) {
     607   [ +  +  +  + ]:       9878 :                 if (splits == 0 || s + sep_len > top) {
     608                 :            :                     s = top;
     609                 :            :                     break;
     610         [ +  + ]:       9653 :                 } else if (memcmp(s, sep_str, sep_len) == 0) {
     611                 :            :                     break;
     612                 :            :                 }
     613                 :       9298 :                 s++;
     614                 :            :             }
     615                 :        580 :             mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start));
     616         [ +  + ]:        580 :             if (s >= top) {
     617                 :            :                 break;
     618                 :            :             }
     619                 :        355 :             s += sep_len;
     620         [ +  + ]:        355 :             if (splits > 0) {
     621                 :         32 :                 splits--;
     622                 :            :             }
     623                 :            :         }
     624                 :            :     }
     625                 :            : 
     626                 :        297 :     return res;
     627                 :            : }
     628                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, mp_obj_str_split);
     629                 :            : 
     630                 :            : #if MICROPY_PY_BUILTINS_STR_SPLITLINES
     631                 :         80 : static mp_obj_t str_splitlines(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     632                 :         80 :     enum { ARG_keepends };
     633                 :         80 :     static const mp_arg_t allowed_args[] = {
     634                 :            :         { MP_QSTR_keepends, MP_ARG_BOOL, {.u_bool = false} },
     635                 :            :     };
     636                 :            : 
     637                 :            :     // parse args
     638                 :         80 :     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
     639                 :         80 :     mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
     640                 :            : 
     641                 :         80 :     const mp_obj_type_t *self_type = mp_obj_get_type(pos_args[0]);
     642                 :         80 :     mp_obj_t res = mp_obj_new_list(0, NULL);
     643                 :            : 
     644         [ +  + ]:         80 :     GET_STR_DATA_LEN(pos_args[0], s, len);
     645                 :         80 :     const byte *top = s + len;
     646                 :            : 
     647         [ +  + ]:        288 :     while (s < top) {
     648                 :            :         const byte *start = s;
     649                 :        736 :         size_t match = 0;
     650         [ +  + ]:        736 :         while (s < top) {
     651         [ +  + ]:        716 :             if (*s == '\n') {
     652                 :            :                 match = 1;
     653                 :            :                 break;
     654         [ +  + ]:        620 :             } else if (*s == '\r') {
     655         [ +  + ]:         92 :                 if (s[1] == '\n') {
     656                 :            :                     match = 2;
     657                 :            :                 } else {
     658                 :         40 :                     match = 1;
     659                 :            :                 }
     660                 :            :                 break;
     661                 :            :             }
     662                 :        528 :             s++;
     663                 :            :         }
     664                 :        208 :         size_t sub_len = s - start;
     665         [ +  + ]:        208 :         if (args[ARG_keepends].u_bool) {
     666                 :         80 :             sub_len += match;
     667                 :            :         }
     668                 :        208 :         mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, sub_len));
     669                 :        208 :         s += match;
     670                 :            :     }
     671                 :            : 
     672                 :         80 :     return res;
     673                 :            : }
     674                 :            : MP_DEFINE_CONST_FUN_OBJ_KW(str_splitlines_obj, 1, str_splitlines);
     675                 :            : #endif
     676                 :            : 
     677                 :        124 : static mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) {
     678         [ +  + ]:        124 :     if (n_args < 3) {
     679                 :            :         // If we don't have split limit, it doesn't matter from which side
     680                 :            :         // we split.
     681                 :         52 :         return mp_obj_str_split(n_args, args);
     682                 :            :     }
     683                 :         72 :     const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
     684                 :         72 :     mp_obj_t sep = args[1];
     685         [ +  + ]:         72 :     GET_STR_DATA_LEN(args[0], s, len);
     686                 :            : 
     687                 :         72 :     mp_int_t splits = mp_obj_get_int(args[2]);
     688         [ +  + ]:         72 :     if (splits < 0) {
     689                 :            :         // Negative limit means no limit, so delegate to split().
     690                 :          8 :         return mp_obj_str_split(n_args, args);
     691                 :            :     }
     692                 :            : 
     693                 :         64 :     mp_int_t org_splits = splits;
     694                 :            :     // Preallocate list to the max expected # of elements, as we
     695                 :            :     // will fill it from the end.
     696                 :         64 :     mp_obj_list_t *res = MP_OBJ_TO_PTR(mp_obj_new_list(splits + 1, NULL));
     697                 :         64 :     mp_int_t idx = splits;
     698                 :            : 
     699         [ +  + ]:         64 :     if (sep == mp_const_none) {
     700                 :          2 :         mp_raise_NotImplementedError(MP_ERROR_TEXT("rsplit(None,n)"));
     701                 :            :     } else {
     702                 :         62 :         size_t sep_len;
     703                 :         62 :         const char *sep_str = mp_obj_str_get_data(sep, &sep_len);
     704                 :            : 
     705         [ +  + ]:         62 :         if (sep_len == 0) {
     706                 :          4 :             mp_raise_ValueError(MP_ERROR_TEXT("empty separator"));
     707                 :            :         }
     708                 :            : 
     709                 :         58 :         const byte *beg = s;
     710                 :         58 :         const byte *last = s + len;
     711                 :        286 :         for (;;) {
     712                 :        172 :             s = last - sep_len;
     713                 :        572 :             for (;;) {
     714         [ +  + ]:        372 :                 if (splits == 0 || s < beg) {
     715                 :            :                     break;
     716         [ +  + ]:        314 :                 } else if (memcmp(s, sep_str, sep_len) == 0) {
     717                 :            :                     break;
     718                 :            :                 }
     719                 :        200 :                 s--;
     720                 :            :             }
     721         [ +  + ]:        172 :             if (s < beg || splits == 0) {
     722                 :         58 :                 res->items[idx] = mp_obj_new_str_of_type(self_type, beg, last - beg);
     723                 :         58 :                 break;
     724                 :            :             }
     725                 :        114 :             res->items[idx--] = mp_obj_new_str_of_type(self_type, s + sep_len, last - s - sep_len);
     726                 :        114 :             last = s;
     727                 :        114 :             splits--;
     728                 :            :         }
     729         [ +  + ]:         58 :         if (idx != 0) {
     730                 :            :             // We split less parts than split limit, now go cleanup surplus
     731                 :         16 :             size_t used = org_splits + 1 - idx;
     732                 :         16 :             memmove(res->items, &res->items[idx], used * sizeof(mp_obj_t));
     733                 :         16 :             mp_seq_clear(res->items, used, res->alloc, sizeof(*res->items));
     734                 :         16 :             res->len = used;
     735                 :            :         }
     736                 :            :     }
     737                 :            : 
     738                 :         58 :     return MP_OBJ_FROM_PTR(res);
     739                 :            : }
     740                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit);
     741                 :            : 
     742                 :        534 : static mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, bool is_index) {
     743                 :        534 :     const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
     744                 :        534 :     check_is_str_or_bytes(args[0]);
     745                 :            : 
     746                 :            :     // check argument type
     747                 :        534 :     str_check_arg_type(self_type, args[1]);
     748                 :            : 
     749         [ +  + ]:        530 :     GET_STR_DATA_LEN(args[0], haystack, haystack_len);
     750         [ +  + ]:        530 :     GET_STR_DATA_LEN(args[1], needle, needle_len);
     751                 :            : 
     752                 :        530 :     const byte *start = haystack;
     753                 :        530 :     const byte *end = haystack + haystack_len;
     754   [ +  +  +  + ]:        530 :     if (n_args >= 3 && args[2] != mp_const_none) {
     755                 :        412 :         start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true);
     756                 :            :     }
     757   [ +  +  +  + ]:        452 :     if (n_args >= 4 && args[3] != mp_const_none) {
     758                 :        130 :         end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true);
     759                 :            :     }
     760                 :            : 
     761         [ +  + ]:        530 :     if (end < start) {
     762                 :          8 :         goto out_error;
     763                 :            :     }
     764                 :            : 
     765                 :        522 :     const byte *p = find_subbytes(start, end - start, needle, needle_len, direction);
     766         [ +  + ]:        522 :     if (p == NULL) {
     767                 :        184 :     out_error:
     768                 :            :         // not found
     769         [ +  + ]:        192 :         if (is_index) {
     770                 :         72 :             mp_raise_ValueError(MP_ERROR_TEXT("substring not found"));
     771                 :            :         } else {
     772                 :            :             return MP_OBJ_NEW_SMALL_INT(-1);
     773                 :            :         }
     774                 :            :     } else {
     775                 :            :         // found
     776                 :            :         #if MICROPY_PY_BUILTINS_STR_UNICODE
     777         [ +  + ]:        338 :         if (self_type == &mp_type_str) {
     778                 :        270 :             return MP_OBJ_NEW_SMALL_INT(utf8_ptr_to_index(haystack, p));
     779                 :            :         }
     780                 :            :         #endif
     781                 :         68 :         return MP_OBJ_NEW_SMALL_INT(p - haystack);
     782                 :            :     }
     783                 :            : }
     784                 :            : 
     785                 :        226 : static mp_obj_t str_find(size_t n_args, const mp_obj_t *args) {
     786                 :        226 :     return str_finder(n_args, args, 1, false);
     787                 :            : }
     788                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find);
     789                 :            : 
     790                 :        104 : static mp_obj_t str_rfind(size_t n_args, const mp_obj_t *args) {
     791                 :        104 :     return str_finder(n_args, args, -1, false);
     792                 :            : }
     793                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind);
     794                 :            : 
     795                 :        104 : static mp_obj_t str_index(size_t n_args, const mp_obj_t *args) {
     796                 :        104 :     return str_finder(n_args, args, 1, true);
     797                 :            : }
     798                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index);
     799                 :            : 
     800                 :        100 : static mp_obj_t str_rindex(size_t n_args, const mp_obj_t *args) {
     801                 :        100 :     return str_finder(n_args, args, -1, true);
     802                 :            : }
     803                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex);
     804                 :            : 
     805                 :            : // TODO: (Much) more variety in args
     806                 :        253 : static mp_obj_t str_startswith(size_t n_args, const mp_obj_t *args) {
     807                 :        253 :     const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
     808         [ +  + ]:        253 :     GET_STR_DATA_LEN(args[0], str, str_len);
     809                 :        253 :     size_t prefix_len;
     810                 :        253 :     const char *prefix = mp_obj_str_get_data(args[1], &prefix_len);
     811                 :        245 :     const byte *start = str;
     812         [ +  + ]:        245 :     if (n_args > 2) {
     813                 :         26 :         start = str_index_to_ptr(self_type, str, str_len, args[2], true);
     814                 :            :     }
     815         [ +  + ]:        245 :     if (prefix_len + (start - str) > str_len) {
     816                 :            :         return mp_const_false;
     817                 :            :     }
     818         [ +  + ]:        189 :     return mp_obj_new_bool(memcmp(start, prefix, prefix_len) == 0);
     819                 :            : }
     820                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith);
     821                 :            : 
     822                 :         38 : static mp_obj_t str_endswith(size_t n_args, const mp_obj_t *args) {
     823         [ +  + ]:         38 :     GET_STR_DATA_LEN(args[0], str, str_len);
     824                 :         38 :     size_t suffix_len;
     825                 :         38 :     const char *suffix = mp_obj_str_get_data(args[1], &suffix_len);
     826         [ +  + ]:         30 :     if (n_args > 2) {
     827                 :          2 :         mp_raise_NotImplementedError(MP_ERROR_TEXT("start/end indices"));
     828                 :            :     }
     829                 :            : 
     830         [ +  + ]:         28 :     if (suffix_len > str_len) {
     831                 :            :         return mp_const_false;
     832                 :            :     }
     833         [ +  + ]:         24 :     return mp_obj_new_bool(memcmp(str + (str_len - suffix_len), suffix, suffix_len) == 0);
     834                 :            : }
     835                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith);
     836                 :            : 
     837                 :            : enum { LSTRIP, RSTRIP, STRIP };
     838                 :            : 
     839                 :        172 : static mp_obj_t str_uni_strip(int type, size_t n_args, const mp_obj_t *args) {
     840                 :        172 :     check_is_str_or_bytes(args[0]);
     841                 :        172 :     const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
     842                 :            : 
     843                 :        172 :     const byte *chars_to_del;
     844                 :        172 :     uint chars_to_del_len;
     845                 :        172 :     static const byte whitespace[] = " \t\n\r\v\f";
     846                 :            : 
     847         [ +  + ]:        172 :     if (n_args == 1) {
     848                 :            :         chars_to_del = whitespace;
     849                 :            :         chars_to_del_len = sizeof(whitespace) - 1;
     850                 :            :     } else {
     851                 :         68 :         str_check_arg_type(self_type, args[1]);
     852         [ +  + ]:         60 :         GET_STR_DATA_LEN(args[1], s, l);
     853                 :         60 :         chars_to_del = s;
     854                 :         60 :         chars_to_del_len = l;
     855                 :            :     }
     856                 :            : 
     857         [ +  + ]:        164 :     GET_STR_DATA_LEN(args[0], orig_str, orig_str_len);
     858                 :            : 
     859                 :        164 :     size_t first_good_char_pos = 0;
     860                 :        164 :     bool first_good_char_pos_set = false;
     861                 :        164 :     size_t last_good_char_pos = 0;
     862                 :        164 :     size_t i = 0;
     863                 :        164 :     int delta = 1;
     864         [ +  + ]:        164 :     if (type == RSTRIP) {
     865                 :         44 :         i = orig_str_len - 1;
     866                 :         44 :         delta = -1;
     867                 :            :     }
     868         [ +  + ]:        732 :     for (size_t len = orig_str_len; len > 0; len--) {
     869         [ +  + ]:        652 :         if (find_subbytes(chars_to_del, chars_to_del_len, &orig_str[i], 1, 1) == NULL) {
     870         [ +  + ]:        288 :             if (!first_good_char_pos_set) {
     871                 :        148 :                 first_good_char_pos_set = true;
     872                 :        148 :                 first_good_char_pos = i;
     873         [ +  + ]:        148 :                 if (type == LSTRIP) {
     874                 :         40 :                     last_good_char_pos = orig_str_len - 1;
     875                 :         40 :                     break;
     876         [ +  + ]:        108 :                 } else if (type == RSTRIP) {
     877                 :            :                     first_good_char_pos = 0;
     878                 :            :                     last_good_char_pos = i;
     879                 :            :                     break;
     880                 :            :                 }
     881                 :            :             }
     882                 :            :             last_good_char_pos = i;
     883                 :            :         }
     884                 :        568 :         i += delta;
     885                 :            :     }
     886                 :            : 
     887         [ +  + ]:        164 :     if (!first_good_char_pos_set) {
     888                 :            :         // string is all whitespace, return ''
     889         [ +  + ]:         16 :         if (self_type == &mp_type_str) {
     890                 :            :             return MP_OBJ_NEW_QSTR(MP_QSTR_);
     891                 :            :         } else {
     892                 :          8 :             return mp_const_empty_bytes;
     893                 :            :         }
     894                 :            :     }
     895                 :            : 
     896         [ -  + ]:        148 :     assert(last_good_char_pos >= first_good_char_pos);
     897                 :            :     // +1 to accommodate the last character
     898                 :        148 :     size_t stripped_len = last_good_char_pos - first_good_char_pos + 1;
     899         [ +  + ]:        148 :     if (stripped_len == orig_str_len) {
     900                 :            :         // If nothing was stripped, don't bother to dup original string
     901                 :            :         // TODO: watch out for this case when we'll get to bytearray.strip()
     902         [ -  + ]:         48 :         assert(first_good_char_pos == 0);
     903                 :         48 :         return args[0];
     904                 :            :     }
     905                 :        100 :     return mp_obj_new_str_of_type(self_type, orig_str + first_good_char_pos, stripped_len);
     906                 :            : }
     907                 :            : 
     908                 :         80 : static mp_obj_t str_strip(size_t n_args, const mp_obj_t *args) {
     909                 :         80 :     return str_uni_strip(STRIP, n_args, args);
     910                 :            : }
     911                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
     912                 :            : 
     913                 :         40 : static mp_obj_t str_lstrip(size_t n_args, const mp_obj_t *args) {
     914                 :         40 :     return str_uni_strip(LSTRIP, n_args, args);
     915                 :            : }
     916                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip);
     917                 :            : 
     918                 :         52 : static mp_obj_t str_rstrip(size_t n_args, const mp_obj_t *args) {
     919                 :         52 :     return str_uni_strip(RSTRIP, n_args, args);
     920                 :            : }
     921                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip);
     922                 :            : 
     923                 :            : #if MICROPY_PY_BUILTINS_STR_CENTER
     924                 :         64 : static mp_obj_t str_center(mp_obj_t str_in, mp_obj_t width_in) {
     925         [ +  + ]:         64 :     GET_STR_DATA_LEN(str_in, str, str_len);
     926                 :         64 :     mp_uint_t width = mp_obj_get_int(width_in);
     927         [ +  + ]:         64 :     if (str_len >= width) {
     928                 :            :         return str_in;
     929                 :            :     }
     930                 :            : 
     931                 :         40 :     vstr_t vstr;
     932                 :         40 :     vstr_init_len(&vstr, width);
     933                 :         40 :     memset(vstr.buf, ' ', width);
     934                 :         40 :     int left = (width - str_len) / 2;
     935                 :         40 :     memcpy(vstr.buf + left, str, str_len);
     936                 :         40 :     return mp_obj_new_str_type_from_vstr(mp_obj_get_type(str_in), &vstr);
     937                 :            : }
     938                 :            : MP_DEFINE_CONST_FUN_OBJ_2(str_center_obj, str_center);
     939                 :            : #endif
     940                 :            : 
     941                 :            : // Takes an int arg, but only parses unsigned numbers, and only changes
     942                 :            : // *num if at least one digit was parsed.
     943                 :     173128 : static const char *str_to_int(const char *str, const char *top, int *num) {
     944   [ +  +  +  +  :     173128 :     if (str < top && '0' <= *str && *str <= '9') {
                   +  + ]
     945                 :      99178 :         *num = 0;
     946                 :     129726 :         do {
     947                 :     129726 :             *num = *num * 10 + (*str - '0');
     948                 :     129726 :             str++;
     949                 :            :         }
     950   [ +  +  +  +  :     129726 :         while (str < top && '0' <= *str && *str <= '9');
                   +  + ]
     951                 :            :     }
     952                 :     173128 :     return str;
     953                 :            : }
     954                 :            : 
     955                 :      56900 : static bool isalignment(char ch) {
     956   [ +  +  +  + ]:      56900 :     return ch && strchr("<>=^", ch) != NULL;
     957                 :            : }
     958                 :            : 
     959                 :      28784 : static bool istype(char ch) {
     960   [ +  +  +  + ]:      28784 :     return ch && strchr("bcdeEfFgGnosxX%", ch) != NULL;
     961                 :            : }
     962                 :            : 
     963                 :     155874 : static bool arg_looks_integer(mp_obj_t arg) {
     964   [ +  +  +  +  :     155874 :     return mp_obj_is_bool(arg) || mp_obj_is_int(arg);
             +  +  +  + ]
     965                 :            : }
     966                 :            : 
     967                 :      97648 : static bool arg_looks_numeric(mp_obj_t arg) {
     968                 :      97648 :     return arg_looks_integer(arg)
     969                 :            :            #if MICROPY_PY_BUILTINS_FLOAT
     970   [ +  +  -  +  :      97648 :            || mp_obj_is_float(arg)
          -  +  -  +  -  
             +  +  +  +  
                      + ]
     971                 :            :            #endif
     972                 :            :     ;
     973                 :            : }
     974                 :            : 
     975                 :            : #if MICROPY_PY_BUILTINS_STR_OP_MODULO
     976                 :      22442 : static mp_obj_t arg_as_int(mp_obj_t arg) {
     977                 :            :     #if MICROPY_PY_BUILTINS_FLOAT
     978   [ -  +  -  +  :      22442 :     if (mp_obj_is_float(arg)) {
          -  +  -  +  +  
                +  +  + ]
     979                 :         32 :         return mp_obj_new_int_from_float(mp_obj_float_get(arg));
     980                 :            :     }
     981                 :            :     #endif
     982                 :            :     return arg;
     983                 :            : }
     984                 :            : #endif
     985                 :            : 
     986                 :            : #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
     987                 :            : static NORETURN void terse_str_format_value_error(void) {
     988                 :            :     mp_raise_ValueError(MP_ERROR_TEXT("bad format string"));
     989                 :            : }
     990                 :            : #else
     991                 :            : // define to nothing to improve coverage
     992                 :            : #define terse_str_format_value_error()
     993                 :            : #endif
     994                 :            : 
     995                 :      66746 : static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *arg_i, size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
     996                 :      66746 :     vstr_t vstr;
     997                 :      66746 :     mp_print_t print;
     998                 :      66746 :     vstr_init_print(&vstr, 16, &print);
     999                 :            : 
    1000         [ +  + ]:     351306 :     for (; str < top; str++) {
    1001         [ +  + ]:     217896 :         if (*str == '}') {
    1002                 :         20 :             str++;
    1003   [ +  +  +  - ]:         20 :             if (str < top && *str == '}') {
    1004                 :         12 :                 vstr_add_byte(&vstr, '}');
    1005                 :     175834 :                 continue;
    1006                 :            :             }
    1007                 :            :             #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1008                 :            :             terse_str_format_value_error();
    1009                 :            :             #else
    1010                 :          8 :             mp_raise_ValueError(MP_ERROR_TEXT("single '}' encountered in format string"));
    1011                 :            :             #endif
    1012                 :            :         }
    1013         [ +  + ]:     217876 :         if (*str != '{') {
    1014                 :     159594 :             vstr_add_byte(&vstr, *str);
    1015                 :     159594 :             continue;
    1016                 :            :         }
    1017                 :            : 
    1018                 :      58282 :         str++;
    1019   [ +  -  +  + ]:      58282 :         if (str < top && *str == '{') {
    1020                 :         16 :             vstr_add_byte(&vstr, '{');
    1021                 :         16 :             continue;
    1022                 :            :         }
    1023                 :            : 
    1024                 :            :         // replacement_field ::=  "{" [field_name] ["!" conversion] [":" format_spec] "}"
    1025                 :            : 
    1026                 :      58266 :         const char *field_name = NULL;
    1027                 :      58266 :         const char *field_name_top = NULL;
    1028                 :      58266 :         char conversion = '\0';
    1029                 :      58266 :         const char *format_spec = NULL;
    1030                 :            : 
    1031   [ +  -  +  +  :      58266 :         if (str < top && *str != '}' && *str != '!' && *str != ':') {
             +  +  +  + ]
    1032                 :       1442 :             field_name = (const char *)str;
    1033   [ +  +  +  +  :       1442 :             while (str < top && *str != '}' && *str != '!' && *str != ':') {
             +  +  +  + ]
    1034                 :       1314 :                 ++str;
    1035                 :            :             }
    1036                 :            :             field_name_top = (const char *)str;
    1037                 :            :         }
    1038                 :            : 
    1039                 :            :         // conversion ::=  "r" | "s"
    1040                 :            : 
    1041   [ +  +  +  + ]:      58266 :         if (str < top && *str == '!') {
    1042                 :       2104 :             str++;
    1043   [ +  +  +  + ]:       2104 :             if (str < top && (*str == 'r' || *str == 's')) {
    1044                 :       2096 :                 conversion = *str++;
    1045                 :            :             } else {
    1046                 :            :                 #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1047                 :            :                 terse_str_format_value_error();
    1048                 :            :                 #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
    1049                 :            :                 mp_raise_ValueError(MP_ERROR_TEXT("bad conversion specifier"));
    1050                 :            :                 #else
    1051         [ +  + ]:          8 :                 if (str >= top) {
    1052                 :          4 :                     mp_raise_ValueError(
    1053                 :          4 :                         MP_ERROR_TEXT("end of format while looking for conversion specifier"));
    1054                 :            :                 } else {
    1055                 :          4 :                     mp_raise_msg_varg(&mp_type_ValueError,
    1056                 :          4 :                         MP_ERROR_TEXT("unknown conversion specifier %c"), *str);
    1057                 :            :                 }
    1058                 :            :                 #endif
    1059                 :            :             }
    1060                 :            :         }
    1061                 :            : 
    1062   [ +  +  +  + ]:      58258 :         if (str < top && *str == ':') {
    1063                 :      28796 :             str++;
    1064                 :            :             // {:} is the same as {}, which is the same as {!s}
    1065                 :            :             // This makes a difference when passing in a True or False
    1066                 :            :             // '{}'.format(True) returns 'True'
    1067                 :            :             // '{:d}'.format(True) returns '1'
    1068                 :            :             // So we treat {:} as {} and this later gets treated to be {!s}
    1069         [ +  + ]:      28796 :             if (*str != '}') {
    1070                 :     107564 :                 format_spec = str;
    1071         [ +  - ]:     107564 :                 for (int nest = 1; str < top;) {
    1072         [ +  + ]:     107564 :                     if (*str == '{') {
    1073                 :         48 :                         ++nest;
    1074         [ +  + ]:     107516 :                     } else if (*str == '}') {
    1075         [ +  + ]:      28836 :                         if (--nest == 0) {
    1076                 :            :                             break;
    1077                 :            :                         }
    1078                 :            :                     }
    1079                 :      78776 :                     ++str;
    1080                 :            :                 }
    1081                 :            :             }
    1082                 :            :         }
    1083         [ +  + ]:      58258 :         if (str >= top) {
    1084                 :            :             #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1085                 :            :             terse_str_format_value_error();
    1086                 :            :             #else
    1087                 :          4 :             mp_raise_ValueError(MP_ERROR_TEXT("unmatched '{' in format"));
    1088                 :            :             #endif
    1089                 :            :         }
    1090         [ +  + ]:      58254 :         if (*str != '}') {
    1091                 :            :             #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1092                 :            :             terse_str_format_value_error();
    1093                 :            :             #else
    1094                 :          4 :             mp_raise_ValueError(MP_ERROR_TEXT("expected ':' after format specifier"));
    1095                 :            :             #endif
    1096                 :            :         }
    1097                 :            : 
    1098                 :      58250 :         mp_obj_t arg = mp_const_none;
    1099                 :            : 
    1100         [ +  + ]:      58250 :         if (field_name) {
    1101                 :        124 :             int index = 0;
    1102         [ +  + ]:        124 :             if (MP_LIKELY(unichar_isdigit(*field_name))) {
    1103         [ +  + ]:         68 :                 if (*arg_i > 0) {
    1104                 :            :                     #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1105                 :            :                     terse_str_format_value_error();
    1106                 :            :                     #else
    1107                 :          4 :                     mp_raise_ValueError(
    1108                 :          4 :                         MP_ERROR_TEXT("can't switch from automatic field numbering to manual field specification"));
    1109                 :            :                     #endif
    1110                 :            :                 }
    1111                 :         64 :                 field_name = str_to_int(field_name, field_name_top, &index);
    1112         [ +  + ]:         64 :                 if ((uint)index >= n_args - 1) {
    1113                 :          8 :                     mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("tuple index out of range"));
    1114                 :            :                 }
    1115                 :         56 :                 arg = args[index + 1];
    1116                 :         56 :                 *arg_i = -1;
    1117                 :            :             } else {
    1118                 :            :                 const char *lookup;
    1119   [ +  +  +  -  :       1284 :                 for (lookup = field_name; lookup < field_name_top && *lookup != '.' && *lookup != '['; lookup++) {;
                   +  + ]
    1120                 :            :                 }
    1121                 :         56 :                 mp_obj_t field_q = mp_obj_new_str_via_qstr(field_name, lookup - field_name); // should it be via qstr?
    1122                 :         56 :                 field_name = lookup;
    1123                 :         56 :                 mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP);
    1124         [ +  + ]:         56 :                 if (key_elem == NULL) {
    1125                 :          4 :                     mp_raise_type_arg(&mp_type_KeyError, field_q);
    1126                 :            :                 }
    1127                 :         52 :                 arg = key_elem->value;
    1128                 :            :             }
    1129         [ +  + ]:        108 :             if (field_name < field_name_top) {
    1130                 :          2 :                 mp_raise_NotImplementedError(MP_ERROR_TEXT("attributes not supported"));
    1131                 :            :             }
    1132                 :            :         } else {
    1133         [ +  + ]:      58126 :             if (*arg_i < 0) {
    1134                 :            :                 #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1135                 :            :                 terse_str_format_value_error();
    1136                 :            :                 #else
    1137                 :          4 :                 mp_raise_ValueError(
    1138                 :          4 :                     MP_ERROR_TEXT("can't switch from manual field specification to automatic field numbering"));
    1139                 :            :                 #endif
    1140                 :            :             }
    1141         [ +  + ]:      58122 :             if ((uint)*arg_i >= n_args - 1) {
    1142                 :          4 :                 mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("tuple index out of range"));
    1143                 :            :             }
    1144                 :      58118 :             arg = args[(*arg_i) + 1];
    1145                 :      58118 :             (*arg_i)++;
    1146                 :            :         }
    1147         [ +  + ]:      58224 :         if (!format_spec && !conversion) {
    1148                 :            :             conversion = 's';
    1149                 :            :         }
    1150         [ +  + ]:      28804 :         if (conversion) {
    1151                 :      31512 :             mp_print_kind_t print_kind;
    1152         [ +  + ]:      31512 :             if (conversion == 's') {
    1153                 :            :                 print_kind = PRINT_STR;
    1154                 :            :             } else {
    1155         [ -  + ]:       1048 :                 assert(conversion == 'r');
    1156                 :            :                 print_kind = PRINT_REPR;
    1157                 :            :             }
    1158                 :      31512 :             vstr_t arg_vstr;
    1159                 :      31512 :             mp_print_t arg_print;
    1160                 :      31512 :             vstr_init_print(&arg_vstr, 16, &arg_print);
    1161                 :      31512 :             mp_obj_print_helper(&arg_print, arg, print_kind);
    1162                 :      31512 :             arg = mp_obj_new_str_type_from_vstr(&mp_type_str, &arg_vstr);
    1163                 :            :         }
    1164                 :            : 
    1165                 :      58224 :         char fill = '\0';
    1166                 :      58224 :         char align = '\0';
    1167                 :      58224 :         int width = -1;
    1168                 :      58224 :         int precision = -1;
    1169                 :      58224 :         char type = '\0';
    1170                 :      58224 :         int flags = 0;
    1171                 :            : 
    1172         [ +  + ]:      58224 :         if (format_spec) {
    1173                 :            :             // The format specifier (from http://docs.python.org/2/library/string.html#formatspec)
    1174                 :            :             //
    1175                 :            :             // [[fill]align][sign][#][0][width][,][.precision][type]
    1176                 :            :             // fill        ::=  <any character>
    1177                 :            :             // align       ::=  "<" | ">" | "=" | "^"
    1178                 :            :             // sign        ::=  "+" | "-" | " "
    1179                 :            :             // width       ::=  integer
    1180                 :            :             // precision   ::=  integer
    1181                 :            :             // type        ::=  "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"
    1182                 :            : 
    1183                 :            :             // recursively call the formatter to format any nested specifiers
    1184                 :      28784 :             MP_STACK_CHECK();
    1185                 :      28784 :             vstr_t format_spec_vstr = mp_obj_str_format_helper(format_spec, str, arg_i, n_args, args, kwargs);
    1186                 :      28784 :             const char *s = vstr_null_terminated_str(&format_spec_vstr);
    1187                 :      28784 :             const char *stop = s + format_spec_vstr.len;
    1188         [ +  + ]:      28784 :             if (isalignment(*s)) {
    1189                 :        668 :                 align = *s++;
    1190   [ +  -  +  + ]:      28116 :             } else if (*s && isalignment(s[1])) {
    1191                 :       1908 :                 fill = *s++;
    1192                 :       1908 :                 align = *s++;
    1193                 :            :             }
    1194         [ +  + ]:      28784 :             if (*s == '+' || *s == '-' || *s == ' ') {
    1195         [ +  + ]:         32 :                 if (*s == '+') {
    1196                 :            :                     flags |= PF_FLAG_SHOW_SIGN;
    1197         [ +  + ]:         16 :                 } else if (*s == ' ') {
    1198                 :          8 :                     flags |= PF_FLAG_SPACE_SIGN;
    1199                 :            :                 }
    1200                 :         32 :                 s++;
    1201                 :            :             }
    1202         [ +  + ]:      28784 :             if (*s == '#') {
    1203                 :       5184 :                 flags |= PF_FLAG_SHOW_PREFIX;
    1204                 :       5184 :                 s++;
    1205                 :            :             }
    1206         [ +  + ]:      28784 :             if (*s == '0') {
    1207   [ +  +  +  + ]:      10748 :                 if (!align && arg_looks_numeric(arg)) {
    1208                 :      10732 :                     align = '=';
    1209                 :            :                 }
    1210         [ +  - ]:      10748 :                 if (!fill) {
    1211                 :      10748 :                     fill = '0';
    1212                 :            :                 }
    1213                 :            :             }
    1214                 :      28784 :             s = str_to_int(s, stop, &width);
    1215         [ +  + ]:      28784 :             if (*s == ',') {
    1216                 :          8 :                 flags |= PF_FLAG_SHOW_COMMA;
    1217                 :          8 :                 s++;
    1218                 :            :             }
    1219         [ +  + ]:      28784 :             if (*s == '.') {
    1220                 :       5664 :                 s++;
    1221                 :       5664 :                 s = str_to_int(s, stop, &precision);
    1222                 :            :             }
    1223         [ +  + ]:      28784 :             if (istype(*s)) {
    1224                 :      28720 :                 type = *s++;
    1225                 :            :             }
    1226         [ +  + ]:      28784 :             if (*s) {
    1227                 :            :                 #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1228                 :            :                 terse_str_format_value_error();
    1229                 :            :                 #else
    1230                 :          4 :                 mp_raise_ValueError(MP_ERROR_TEXT("invalid format specifier"));
    1231                 :            :                 #endif
    1232                 :            :             }
    1233                 :      28780 :             vstr_clear(&format_spec_vstr);
    1234                 :            :         }
    1235         [ +  + ]:      58220 :         if (!align) {
    1236         [ +  + ]:      44912 :             if (arg_looks_numeric(arg)) {
    1237                 :            :                 align = '>';
    1238                 :            :             } else {
    1239                 :      33916 :                 align = '<';
    1240                 :            :             }
    1241                 :            :         }
    1242         [ +  + ]:      58220 :         if (!fill) {
    1243                 :      45564 :             fill = ' ';
    1244                 :            :         }
    1245                 :            : 
    1246         [ +  + ]:      58220 :         if (flags & (PF_FLAG_SHOW_SIGN | PF_FLAG_SPACE_SIGN)) {
    1247         [ +  + ]:         24 :             if (type == 's') {
    1248                 :            :                 #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1249                 :            :                 terse_str_format_value_error();
    1250                 :            :                 #else
    1251                 :          4 :                 mp_raise_ValueError(MP_ERROR_TEXT("sign not allowed in string format specifier"));
    1252                 :            :                 #endif
    1253                 :            :             }
    1254         [ +  + ]:         20 :             if (type == 'c') {
    1255                 :            :                 #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1256                 :            :                 terse_str_format_value_error();
    1257                 :            :                 #else
    1258                 :          4 :                 mp_raise_ValueError(
    1259                 :          4 :                     MP_ERROR_TEXT("sign not allowed with integer format specifier 'c'"));
    1260                 :            :                 #endif
    1261                 :            :             }
    1262                 :            :         }
    1263                 :            : 
    1264   [ +  +  +  + ]:      58212 :         switch (align) {
    1265                 :      34796 :             case '<':
    1266                 :      34796 :                 flags |= PF_FLAG_LEFT_ADJUST;
    1267                 :      34796 :                 break;
    1268                 :      10740 :             case '=':
    1269                 :      10740 :                 flags |= PF_FLAG_PAD_AFTER_SIGN;
    1270                 :      10740 :                 break;
    1271                 :        828 :             case '^':
    1272                 :        828 :                 flags |= PF_FLAG_CENTER_ADJUST;
    1273                 :        828 :                 break;
    1274                 :            :         }
    1275                 :            : 
    1276         [ +  + ]:      58212 :         if (arg_looks_integer(arg)) {
    1277   [ +  +  +  +  :      18668 :             switch (type) {
                +  +  + ]
    1278                 :       5156 :                 case 'b':
    1279                 :       5156 :                     mp_print_mp_int(&print, arg, 2, 'a', flags, fill, width, 0);
    1280                 :       5156 :                     continue;
    1281                 :            : 
    1282                 :        392 :                 case 'c': {
    1283                 :        196 :                     char ch = mp_obj_get_int(arg);
    1284                 :        196 :                     mp_print_strn(&print, &ch, 1, flags, fill, width);
    1285                 :        196 :                     continue;
    1286                 :            :                 }
    1287                 :            : 
    1288                 :        112 :                 case '\0':  // No explicit format type implies 'd'
    1289                 :            :                 case 'n':   // I don't think we support locales in uPy so use 'd'
    1290                 :            :                 case 'd':
    1291                 :        112 :                     mp_print_mp_int(&print, arg, 10, 'a', flags, fill, width, 0);
    1292                 :        112 :                     continue;
    1293                 :            : 
    1294                 :         12 :                 case 'o':
    1295         [ +  + ]:         12 :                     if (flags & PF_FLAG_SHOW_PREFIX) {
    1296                 :          8 :                         flags |= PF_FLAG_SHOW_OCTAL_LETTER;
    1297                 :            :                     }
    1298                 :            : 
    1299                 :         12 :                     mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, 0);
    1300                 :         12 :                     continue;
    1301                 :            : 
    1302                 :      10736 :                 case 'X':
    1303                 :            :                 case 'x':
    1304                 :      10736 :                     mp_print_mp_int(&print, arg, 16, type - ('X' - 'A'), flags, fill, width, 0);
    1305                 :      10736 :                     continue;
    1306                 :            : 
    1307                 :            :                 case 'e':
    1308                 :            :                 case 'E':
    1309                 :            :                 case 'f':
    1310                 :            :                 case 'F':
    1311                 :            :                 case 'g':
    1312                 :            :                 case 'G':
    1313                 :            :                 case '%':
    1314                 :            :                     // The floating point formatters all work with anything that
    1315                 :            :                     // looks like an integer
    1316                 :            :                     break;
    1317                 :            : 
    1318                 :          4 :                 default:
    1319                 :            :                     #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1320                 :            :                     terse_str_format_value_error();
    1321                 :            :                     #else
    1322                 :          4 :                     mp_raise_msg_varg(&mp_type_ValueError,
    1323                 :          4 :                         MP_ERROR_TEXT("unknown format code '%c' for object of type '%s'"),
    1324                 :            :                         type, mp_obj_get_type_str(arg));
    1325                 :            :                     #endif
    1326                 :            :             }
    1327                 :            :         }
    1328                 :            : 
    1329                 :            :         // NOTE: no else here. We need the e, f, g etc formats for integer
    1330                 :            :         //       arguments (from above if) to take this if.
    1331         [ +  + ]:      41996 :         if (arg_looks_numeric(arg)) {
    1332         [ +  + ]:       5724 :             if (!type) {
    1333                 :            : 
    1334                 :            :                 // Even though the docs say that an unspecified type is the same
    1335                 :            :                 // as 'g', there is one subtle difference, when the exponent
    1336                 :            :                 // is one less than the precision.
    1337                 :            :                 //
    1338                 :            :                 // '{:10.1}'.format(0.0) ==> '0e+00'
    1339                 :            :                 // '{:10.1g}'.format(0.0) ==> '0'
    1340                 :            :                 //
    1341                 :            :                 // TODO: Figure out how to deal with this.
    1342                 :            :                 //
    1343                 :            :                 // A proper solution would involve adding a special flag
    1344                 :            :                 // or something to format_float, and create a format_double
    1345                 :            :                 // to deal with doubles. In order to fix this when using
    1346                 :            :                 // sprintf, we'd need to use the e format and tweak the
    1347                 :            :                 // returned result to strip trailing zeros like the g format
    1348                 :            :                 // does.
    1349                 :            :                 //
    1350                 :            :                 // {:10.3} and {:10.2e} with 1.23e2 both produce 1.23e+02
    1351                 :            :                 // but with 1.e2 you get 1e+02 and 1.00e+02
    1352                 :            :                 //
    1353                 :            :                 // Stripping the trailing 0's (like g) does would make the
    1354                 :            :                 // e format give us the right format.
    1355                 :            :                 //
    1356                 :            :                 // CPython sources say:
    1357                 :            :                 //   Omitted type specifier.  Behaves in the same way as repr(x)
    1358                 :            :                 //   and str(x) if no precision is given, else like 'g', but with
    1359                 :            :                 //   at least one digit after the decimal point. */
    1360                 :            : 
    1361                 :            :                 type = 'g';
    1362                 :            :             }
    1363         [ +  + ]:       5716 :             if (type == 'n') {
    1364                 :            :                 type = 'g';
    1365                 :            :             }
    1366                 :            : 
    1367      [ +  +  + ]:       5716 :             switch (type) {
    1368                 :            :                 #if MICROPY_PY_BUILTINS_FLOAT
    1369                 :       5692 :                 case 'e':
    1370                 :            :                 case 'E':
    1371                 :            :                 case 'f':
    1372                 :            :                 case 'F':
    1373                 :            :                 case 'g':
    1374                 :            :                 case 'G':
    1375                 :       5692 :                     mp_print_float(&print, mp_obj_get_float(arg), type, flags, fill, width, precision);
    1376                 :       5692 :                     break;
    1377                 :            : 
    1378                 :         24 :                 case '%':
    1379                 :         24 :                     flags |= PF_FLAG_ADD_PERCENT;
    1380                 :            :                     #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
    1381                 :            :                     #define F100 100.0F
    1382                 :            :                     #else
    1383                 :            :                     #define F100 100.0
    1384                 :            :                     #endif
    1385                 :         24 :                     mp_print_float(&print, mp_obj_get_float(arg) * F100, 'f', flags, fill, width, precision);
    1386                 :            : #undef F100
    1387                 :         24 :                     break;
    1388                 :            :                 #endif
    1389                 :            : 
    1390                 :          8 :                 default:
    1391                 :            :                     #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1392                 :            :                     terse_str_format_value_error();
    1393                 :            :                     #else
    1394                 :          8 :                     mp_raise_msg_varg(&mp_type_ValueError,
    1395                 :          8 :                         MP_ERROR_TEXT("unknown format code '%c' for object of type '%s'"),
    1396                 :            :                         type, mp_obj_get_type_str(arg));
    1397                 :            :                     #endif
    1398                 :            :             }
    1399                 :            :         } else {
    1400                 :            :             // arg doesn't look like a number
    1401                 :            : 
    1402         [ +  + ]:      36272 :             if (align == '=') {
    1403                 :            :                 #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1404                 :            :                 terse_str_format_value_error();
    1405                 :            :                 #else
    1406                 :          4 :                 mp_raise_ValueError(
    1407                 :          4 :                     MP_ERROR_TEXT("'=' alignment not allowed in string format specifier"));
    1408                 :            :                 #endif
    1409                 :            :             }
    1410                 :            : 
    1411         [ +  + ]:      36268 :             switch (type) {
    1412                 :      36264 :                 case '\0': // no explicit format type implies 's'
    1413                 :            :                 case 's': {
    1414                 :      36264 :                     size_t slen;
    1415                 :      36264 :                     const char *s = mp_obj_str_get_data(arg, &slen);
    1416         [ +  + ]:      36264 :                     if (precision < 0) {
    1417                 :      36260 :                         precision = slen;
    1418                 :            :                     }
    1419         [ +  + ]:      36264 :                     if (slen > (size_t)precision) {
    1420                 :          4 :                         slen = precision;
    1421                 :            :                     }
    1422                 :      36264 :                     mp_print_strn(&print, s, slen, flags, fill, width);
    1423                 :      36264 :                     break;
    1424                 :            :                 }
    1425                 :            : 
    1426                 :          4 :                 default:
    1427                 :            :                     #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1428                 :            :                     terse_str_format_value_error();
    1429                 :            :                     #else
    1430                 :          4 :                     mp_raise_msg_varg(&mp_type_ValueError,
    1431                 :          4 :                         MP_ERROR_TEXT("unknown format code '%c' for object of type '%s'"),
    1432                 :            :                         type, mp_obj_get_type_str(arg));
    1433                 :            :                     #endif
    1434                 :            :             }
    1435                 :            :         }
    1436                 :            :     }
    1437                 :            : 
    1438                 :      66664 :     return vstr;
    1439                 :            : }
    1440                 :            : 
    1441                 :      37962 : mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
    1442                 :      37962 :     check_is_str_or_bytes(args[0]);
    1443                 :            : 
    1444         [ +  + ]:      37962 :     GET_STR_DATA_LEN(args[0], str, len);
    1445                 :      37962 :     int arg_i = 0;
    1446                 :      37962 :     vstr_t vstr = mp_obj_str_format_helper((const char *)str, (const char *)str + len, &arg_i, n_args, args, kwargs);
    1447                 :      37880 :     return mp_obj_new_str_type_from_vstr(mp_obj_get_type(args[0]), &vstr);
    1448                 :            : }
    1449                 :            : MP_DEFINE_CONST_FUN_OBJ_KW(str_format_obj, 1, mp_obj_str_format);
    1450                 :            : 
    1451                 :            : #if MICROPY_PY_BUILTINS_STR_OP_MODULO
    1452                 :      88160 : static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict) {
    1453                 :      88160 :     check_is_str_or_bytes(pattern);
    1454                 :            : 
    1455         [ +  + ]:      88160 :     GET_STR_DATA_LEN(pattern, str, len);
    1456                 :            :     #if MICROPY_ERROR_REPORTING > MICROPY_ERROR_REPORTING_TERSE
    1457                 :      88160 :     const byte *start_str = str;
    1458                 :            :     #endif
    1459   [ +  +  +  + ]:      88160 :     bool is_bytes = mp_obj_is_type(pattern, &mp_type_bytes);
    1460                 :      88160 :     size_t arg_i = 0;
    1461                 :      88160 :     vstr_t vstr;
    1462                 :      88160 :     mp_print_t print;
    1463                 :      88160 :     vstr_init_print(&vstr, 16, &print);
    1464                 :            : 
    1465         [ +  + ]:     235554 :     for (const byte *top = str + len; str < top; str++) {
    1466                 :     147462 :         mp_obj_t arg = MP_OBJ_NULL;
    1467         [ +  + ]:     147462 :         if (*str != '%') {
    1468                 :      44642 :             vstr_add_byte(&vstr, *str);
    1469                 :      44682 :             continue;
    1470                 :            :         }
    1471         [ +  + ]:     102820 :         if (++str >= top) {
    1472                 :          4 :             goto incomplete_format;
    1473                 :            :         }
    1474         [ +  + ]:     102816 :         if (*str == '%') {
    1475                 :         40 :             vstr_add_byte(&vstr, '%');
    1476                 :         40 :             continue;
    1477                 :            :         }
    1478                 :            : 
    1479                 :            :         // Dictionary value lookup
    1480         [ +  + ]:     102776 :         if (*str == '(') {
    1481         [ +  + ]:         46 :             if (dict == MP_OBJ_NULL) {
    1482                 :          8 :                 mp_raise_TypeError(MP_ERROR_TEXT("format needs a dict"));
    1483                 :            :             }
    1484                 :         38 :             arg_i = 1; // we used up the single dict argument
    1485                 :         38 :             const byte *key = ++str;
    1486         [ +  + ]:       2674 :             while (*str != ')') {
    1487         [ +  + ]:       2640 :                 if (str >= top) {
    1488                 :            :                     #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1489                 :            :                     terse_str_format_value_error();
    1490                 :            :                     #else
    1491                 :          4 :                     mp_raise_ValueError(MP_ERROR_TEXT("incomplete format key"));
    1492                 :            :                     #endif
    1493                 :            :                 }
    1494                 :       2636 :                 ++str;
    1495                 :            :             }
    1496                 :         34 :             mp_obj_t k_obj = mp_obj_new_str_via_qstr((const char *)key, str - key);
    1497                 :         28 :             arg = mp_obj_dict_get(dict, k_obj);
    1498                 :         24 :             str++;
    1499                 :            :         }
    1500                 :            : 
    1501                 :     102754 :         int flags = 0;
    1502                 :     102754 :         char fill = ' ';
    1503                 :     102754 :         int alt = 0;
    1504         [ +  - ]:     143458 :         while (str < top) {
    1505   [ +  +  +  +  :     143458 :             if (*str == '-') {
                   +  + ]
    1506                 :         28 :                 flags |= PF_FLAG_LEFT_ADJUST;
    1507                 :            :             } else if (*str == '+') {
    1508                 :        136 :                 flags |= PF_FLAG_SHOW_SIGN;
    1509                 :            :             } else if (*str == ' ') {
    1510                 :         56 :                 flags |= PF_FLAG_SPACE_SIGN;
    1511                 :            :             } else if (*str == '#') {
    1512                 :            :                 alt = PF_FLAG_SHOW_PREFIX;
    1513                 :            :             } else if (*str == '0') {
    1514                 :      40244 :                 flags |= PF_FLAG_PAD_AFTER_SIGN;
    1515                 :      40244 :                 fill = '0';
    1516                 :            :             } else {
    1517                 :            :                 break;
    1518                 :            :             }
    1519                 :      40704 :             str++;
    1520                 :            :         }
    1521                 :            :         // parse width, if it exists
    1522                 :     102754 :         int width = 0;
    1523         [ +  - ]:     102754 :         if (str < top) {
    1524         [ +  + ]:     102754 :             if (*str == '*') {
    1525         [ +  + ]:         28 :                 if (arg_i >= n_args) {
    1526                 :          4 :                     goto not_enough_args;
    1527                 :            :                 }
    1528                 :         24 :                 width = mp_obj_get_int(args[arg_i++]);
    1529                 :         24 :                 str++;
    1530                 :            :             } else {
    1531                 :     102726 :                 str = (const byte *)str_to_int((const char *)str, (const char *)top, &width);
    1532                 :            :             }
    1533                 :            :         }
    1534                 :     102750 :         int prec = -1;
    1535   [ +  +  +  + ]:     102750 :         if (str < top && *str == '.') {
    1536         [ +  - ]:      35910 :             if (++str < top) {
    1537         [ +  + ]:      35910 :                 if (*str == '*') {
    1538         [ +  + ]:         20 :                     if (arg_i >= n_args) {
    1539                 :          4 :                         goto not_enough_args;
    1540                 :            :                     }
    1541                 :         16 :                     prec = mp_obj_get_int(args[arg_i++]);
    1542                 :         16 :                     str++;
    1543                 :            :                 } else {
    1544                 :      35890 :                     prec = 0;
    1545                 :      35890 :                     str = (const byte *)str_to_int((const char *)str, (const char *)top, &prec);
    1546                 :            :                 }
    1547                 :            :             }
    1548                 :            :         }
    1549                 :            : 
    1550         [ +  + ]:     102746 :         if (str >= top) {
    1551                 :          4 :         incomplete_format:
    1552                 :            :             #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1553                 :            :             terse_str_format_value_error();
    1554                 :            :             #else
    1555                 :          8 :             mp_raise_ValueError(MP_ERROR_TEXT("incomplete format"));
    1556                 :            :             #endif
    1557                 :            :         }
    1558                 :            : 
    1559                 :            :         // Tuple value lookup
    1560         [ +  + ]:     102742 :         if (arg == MP_OBJ_NULL) {
    1561         [ +  + ]:     102722 :             if (arg_i >= n_args) {
    1562                 :         20 :             not_enough_args:
    1563                 :         28 :                 mp_raise_TypeError(MP_ERROR_TEXT("format string needs more arguments"));
    1564                 :            :             }
    1565                 :     102702 :             arg = args[arg_i++];
    1566                 :            :         }
    1567   [ +  +  +  +  :     102722 :         switch (*str) {
                +  +  + ]
    1568                 :         22 :             case 'c':
    1569   [ +  +  +  +  :         26 :                 if (mp_obj_is_str(arg)) {
                   -  + ]
    1570                 :          8 :                     size_t slen;
    1571                 :          8 :                     const char *s = mp_obj_str_get_data(arg, &slen);
    1572         [ +  + ]:          8 :                     if (slen != 1) {
    1573                 :          4 :                         mp_raise_TypeError(MP_ERROR_TEXT("%c needs int or char"));
    1574                 :            :                     }
    1575                 :          4 :                     mp_print_strn(&print, s, 1, flags, ' ', width);
    1576         [ +  + ]:         14 :                 } else if (arg_looks_integer(arg)) {
    1577                 :         12 :                     char ch = mp_obj_get_int(arg);
    1578                 :         12 :                     mp_print_strn(&print, &ch, 1, flags, ' ', width);
    1579                 :            :                 } else {
    1580                 :          2 :                     mp_raise_TypeError(MP_ERROR_TEXT("integer needed"));
    1581                 :            :                 }
    1582                 :            :                 break;
    1583                 :            : 
    1584                 :      22442 :             case 'd':
    1585                 :            :             case 'i':
    1586                 :            :             case 'u':
    1587                 :      22442 :                 mp_print_mp_int(&print, arg_as_int(arg), 10, 'a', flags, fill, width, prec);
    1588                 :      22442 :                 break;
    1589                 :            : 
    1590                 :            :             #if MICROPY_PY_BUILTINS_FLOAT
    1591                 :      35902 :             case 'e':
    1592                 :            :             case 'E':
    1593                 :            :             case 'f':
    1594                 :            :             case 'F':
    1595                 :            :             case 'g':
    1596                 :            :             case 'G':
    1597                 :      35902 :                 mp_print_float(&print, mp_obj_get_float(arg), *str, flags, fill, width, prec);
    1598                 :      35902 :                 break;
    1599                 :            :             #endif
    1600                 :            : 
    1601                 :         40 :             case 'o':
    1602         [ +  + ]:         40 :                 if (alt) {
    1603                 :         36 :                     flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER);
    1604                 :            :                 }
    1605                 :         40 :                 mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, prec);
    1606                 :         40 :                 break;
    1607                 :            : 
    1608                 :       3894 :             case 'r':
    1609                 :            :             case 's': {
    1610                 :       3894 :                 vstr_t arg_vstr;
    1611                 :       3894 :                 mp_print_t arg_print;
    1612                 :       3894 :                 vstr_init_print(&arg_vstr, 16, &arg_print);
    1613                 :       3894 :                 mp_print_kind_t print_kind = (*str == 'r' ? PRINT_REPR : PRINT_STR);
    1614   [ +  +  +  -  :       3894 :                 if (print_kind == PRINT_STR && is_bytes && mp_obj_is_type(arg, &mp_type_bytes)) {
                   +  - ]
    1615                 :            :                     // If we have something like b"%s" % b"1", bytes arg should be
    1616                 :            :                     // printed undecorated.
    1617                 :          4 :                     print_kind = PRINT_RAW;
    1618                 :            :                 }
    1619                 :       3894 :                 mp_obj_print_helper(&arg_print, arg, print_kind);
    1620                 :       3894 :                 uint vlen = arg_vstr.len;
    1621         [ +  + ]:       3894 :                 if (prec < 0) {
    1622                 :       3890 :                     prec = vlen;
    1623                 :            :                 }
    1624         [ +  + ]:       3894 :                 if (vlen > (uint)prec) {
    1625                 :          4 :                     vlen = prec;
    1626                 :            :                 }
    1627                 :       3894 :                 mp_print_strn(&print, arg_vstr.buf, vlen, flags, ' ', width);
    1628                 :       3894 :                 vstr_clear(&arg_vstr);
    1629                 :       3894 :                 break;
    1630                 :            :             }
    1631                 :            : 
    1632                 :      40418 :             case 'X':
    1633                 :            :             case 'x':
    1634                 :      40418 :                 mp_print_mp_int(&print, arg, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec);
    1635                 :      40418 :                 break;
    1636                 :            : 
    1637                 :          4 :             default:
    1638                 :            :                 #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    1639                 :            :                 terse_str_format_value_error();
    1640                 :            :                 #else
    1641                 :          4 :                 mp_raise_msg_varg(&mp_type_ValueError,
    1642                 :          4 :                     MP_ERROR_TEXT("unsupported format character '%c' (0x%x) at index %d"),
    1643                 :            :                     *str, *str, str - start_str);
    1644                 :            :                 #endif
    1645                 :            :         }
    1646                 :            :     }
    1647                 :            : 
    1648         [ +  + ]:      88092 :     if (dict == MP_OBJ_NULL && arg_i != n_args) {
    1649                 :            :         // NOTE: if `dict` exists, then `n_args` is 1 and the dict is always consumed; either
    1650                 :            :         // positionally, or as a map of named args, even if none were actually referenced.
    1651                 :          4 :         mp_raise_TypeError(MP_ERROR_TEXT("format string didn't convert all arguments"));
    1652                 :            :     }
    1653                 :            : 
    1654         [ +  + ]:     176152 :     return mp_obj_new_str_type_from_vstr(is_bytes ? &mp_type_bytes : &mp_type_str, &vstr);
    1655                 :            : }
    1656                 :            : #endif
    1657                 :            : 
    1658                 :            : // The implementation is optimized, returning the original string if there's
    1659                 :            : // nothing to replace.
    1660                 :        116 : static mp_obj_t str_replace(size_t n_args, const mp_obj_t *args) {
    1661                 :        116 :     check_is_str_or_bytes(args[0]);
    1662                 :            : 
    1663                 :        116 :     mp_int_t max_rep = -1;
    1664         [ +  + ]:        116 :     if (n_args == 4) {
    1665                 :         24 :         max_rep = mp_obj_get_int(args[3]);
    1666         [ +  + ]:         24 :         if (max_rep == 0) {
    1667                 :          8 :             return args[0];
    1668         [ +  + ]:         16 :         } else if (max_rep < 0) {
    1669                 :          8 :             max_rep = -1;
    1670                 :            :         }
    1671                 :            :     }
    1672                 :            : 
    1673                 :            :     // if max_rep is still -1 by this point we will need to do all possible replacements
    1674                 :            : 
    1675                 :            :     // check argument types
    1676                 :            : 
    1677                 :        108 :     const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
    1678                 :            : 
    1679                 :        108 :     str_check_arg_type(self_type, args[1]);
    1680                 :        104 :     str_check_arg_type(self_type, args[2]);
    1681                 :            : 
    1682                 :            :     // extract string data
    1683                 :            : 
    1684         [ +  + ]:        100 :     GET_STR_DATA_LEN(args[0], str, str_len);
    1685         [ +  + ]:        100 :     GET_STR_DATA_LEN(args[1], old, old_len);
    1686         [ +  + ]:        100 :     GET_STR_DATA_LEN(args[2], new, new_len);
    1687                 :            : 
    1688                 :            :     // old won't exist in str if it's longer, so nothing to replace
    1689         [ +  + ]:        100 :     if (old_len > str_len) {
    1690                 :         16 :         return args[0];
    1691                 :            :     }
    1692                 :            : 
    1693                 :            :     // data for the replaced string
    1694                 :            :     byte *data = NULL;
    1695                 :        160 :     vstr_t vstr;
    1696                 :            : 
    1697                 :            :     // do 2 passes over the string:
    1698                 :            :     //   first pass computes the required length of the replaced string
    1699                 :            :     //   second pass does the replacements
    1700                 :        160 :     for (;;) {
    1701                 :        160 :         size_t replaced_str_index = 0;
    1702                 :        160 :         size_t num_replacements_done = 0;
    1703                 :        160 :         const byte *old_occurrence;
    1704                 :        160 :         const byte *offset_ptr = str;
    1705                 :        160 :         size_t str_len_remain = str_len;
    1706         [ +  + ]:        160 :         if (old_len == 0) {
    1707                 :            :             // if old_str is empty, copy new_str to start of replaced string
    1708                 :            :             // copy the replacement string
    1709         [ +  + ]:         64 :             if (data != NULL) {
    1710                 :         32 :                 memcpy(data, new, new_len);
    1711                 :            :             }
    1712                 :         64 :             replaced_str_index += new_len;
    1713                 :         64 :             num_replacements_done++;
    1714                 :            :         }
    1715   [ +  +  +  + ]:        432 :         while (num_replacements_done != (size_t)max_rep && str_len_remain > 0 && (old_occurrence = find_subbytes(offset_ptr, str_len_remain, old, old_len, 1)) != NULL) {
    1716         [ +  + ]:        272 :             if (old_len == 0) {
    1717                 :         80 :                 old_occurrence += 1;
    1718                 :            :             }
    1719                 :            :             // copy from just after end of last occurrence of to-be-replaced string to right before start of next occurrence
    1720         [ +  + ]:        272 :             if (data != NULL) {
    1721                 :        136 :                 memcpy(data + replaced_str_index, offset_ptr, old_occurrence - offset_ptr);
    1722                 :            :             }
    1723                 :        272 :             replaced_str_index += old_occurrence - offset_ptr;
    1724                 :            :             // copy the replacement string
    1725         [ +  + ]:        272 :             if (data != NULL) {
    1726                 :        136 :                 memcpy(data + replaced_str_index, new, new_len);
    1727                 :            :             }
    1728                 :        272 :             replaced_str_index += new_len;
    1729                 :        272 :             offset_ptr = old_occurrence + old_len;
    1730                 :        272 :             str_len_remain = str + str_len - offset_ptr;
    1731                 :        272 :             num_replacements_done++;
    1732                 :            :         }
    1733                 :            : 
    1734                 :            :         // copy from just after end of last occurrence of to-be-replaced string to end of old string
    1735         [ +  + ]:        160 :         if (data != NULL) {
    1736                 :         76 :             memcpy(data + replaced_str_index, offset_ptr, str_len_remain);
    1737                 :            :         }
    1738                 :        160 :         replaced_str_index += str_len_remain;
    1739                 :            : 
    1740                 :        160 :         if (data == NULL) {
    1741                 :            :             // first pass
    1742         [ +  + ]:         84 :             if (num_replacements_done == 0) {
    1743                 :            :                 // no substr found, return original string
    1744                 :          8 :                 return args[0];
    1745                 :            :             } else {
    1746                 :            :                 // substr found, allocate new string
    1747                 :         76 :                 vstr_init_len(&vstr, replaced_str_index);
    1748                 :         76 :                 data = (byte *)vstr.buf;
    1749         [ +  - ]:         76 :                 assert(data != NULL);
    1750                 :            :             }
    1751                 :            :         } else {
    1752                 :            :             // second pass, we are done
    1753                 :            :             break;
    1754                 :            :         }
    1755                 :            :     }
    1756                 :            : 
    1757                 :         76 :     return mp_obj_new_str_type_from_vstr(self_type, &vstr);
    1758                 :            : }
    1759                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace);
    1760                 :            : 
    1761                 :            : #if MICROPY_PY_BUILTINS_STR_COUNT
    1762                 :        345 : static mp_obj_t str_count(size_t n_args, const mp_obj_t *args) {
    1763                 :        345 :     const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
    1764                 :        345 :     check_is_str_or_bytes(args[0]);
    1765                 :            : 
    1766                 :            :     // check argument type
    1767                 :        345 :     str_check_arg_type(self_type, args[1]);
    1768                 :            : 
    1769         [ +  + ]:        341 :     GET_STR_DATA_LEN(args[0], haystack, haystack_len);
    1770         [ +  + ]:        341 :     GET_STR_DATA_LEN(args[1], needle, needle_len);
    1771                 :            : 
    1772                 :        341 :     const byte *start = haystack;
    1773                 :        341 :     const byte *end = haystack + haystack_len;
    1774   [ +  +  +  - ]:        341 :     if (n_args >= 3 && args[2] != mp_const_none) {
    1775                 :        152 :         start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true);
    1776                 :            :     }
    1777   [ +  +  +  - ]:        152 :     if (n_args >= 4 && args[3] != mp_const_none) {
    1778                 :         56 :         end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true);
    1779                 :            :     }
    1780                 :            : 
    1781                 :            :     // if needle_len is zero then we count each gap between characters as an occurrence
    1782         [ +  + ]:        341 :     if (needle_len == 0) {
    1783                 :         64 :         return MP_OBJ_NEW_SMALL_INT(utf8_charlen(start, end - start) + 1);
    1784                 :            :     }
    1785                 :            : 
    1786                 :            :     bool is_str = self_type == &mp_type_str;
    1787                 :            : 
    1788                 :            :     // count the occurrences
    1789                 :       1134 :     mp_int_t num_occurrences = 0;
    1790         [ +  + ]:       1134 :     for (const byte *haystack_ptr = start; haystack_ptr + needle_len <= end;) {
    1791         [ +  + ]:        857 :         if (memcmp(haystack_ptr, needle, needle_len) == 0) {
    1792                 :        505 :             num_occurrences++;
    1793                 :        505 :             haystack_ptr += needle_len;
    1794                 :            :         } else {
    1795         [ +  + ]:        352 :             haystack_ptr = is_str ? utf8_next_char(haystack_ptr) : haystack_ptr + 1;
    1796                 :            :         }
    1797                 :            :     }
    1798                 :            : 
    1799                 :        277 :     return MP_OBJ_NEW_SMALL_INT(num_occurrences);
    1800                 :            : }
    1801                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count);
    1802                 :            : #endif
    1803                 :            : 
    1804                 :            : #if MICROPY_PY_BUILTINS_STR_PARTITION
    1805                 :        224 : static mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, int direction) {
    1806                 :        224 :     check_is_str_or_bytes(self_in);
    1807                 :        224 :     const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
    1808                 :        224 :     str_check_arg_type(self_type, arg);
    1809                 :            : 
    1810         [ +  + ]:        204 :     GET_STR_DATA_LEN(self_in, str, str_len);
    1811         [ +  + ]:        204 :     GET_STR_DATA_LEN(arg, sep, sep_len);
    1812                 :            : 
    1813         [ +  + ]:        204 :     if (sep_len == 0) {
    1814                 :         12 :         mp_raise_ValueError(MP_ERROR_TEXT("empty separator"));
    1815                 :            :     }
    1816                 :            : 
    1817                 :        192 :     mp_obj_t result[3];
    1818         [ +  + ]:        192 :     if (self_type == &mp_type_str) {
    1819                 :        120 :         result[0] = MP_OBJ_NEW_QSTR(MP_QSTR_);
    1820                 :        120 :         result[1] = MP_OBJ_NEW_QSTR(MP_QSTR_);
    1821                 :        120 :         result[2] = MP_OBJ_NEW_QSTR(MP_QSTR_);
    1822                 :            :     } else {
    1823                 :         72 :         result[0] = mp_const_empty_bytes;
    1824                 :         72 :         result[1] = mp_const_empty_bytes;
    1825                 :         72 :         result[2] = mp_const_empty_bytes;
    1826                 :            :     }
    1827                 :            : 
    1828         [ +  + ]:        192 :     if (direction > 0) {
    1829                 :        128 :         result[0] = self_in;
    1830                 :            :     } else {
    1831                 :         64 :         result[2] = self_in;
    1832                 :            :     }
    1833                 :            : 
    1834                 :            :     #if MICROPY_PY_BUILTINS_BYTEARRAY
    1835         [ +  + ]:        192 :     if (mp_obj_get_type(arg) != self_type) {
    1836                 :          8 :         arg = mp_obj_new_str_of_type(self_type, sep, sep_len);
    1837                 :            :     }
    1838                 :            :     #endif
    1839                 :            : 
    1840                 :        192 :     const byte *position_ptr = find_subbytes(str, str_len, sep, sep_len, direction);
    1841         [ +  + ]:        192 :     if (position_ptr != NULL) {
    1842                 :        144 :         size_t position = position_ptr - str;
    1843                 :        144 :         result[0] = mp_obj_new_str_of_type(self_type, str, position);
    1844                 :        144 :         result[1] = arg;
    1845                 :        144 :         result[2] = mp_obj_new_str_of_type(self_type, str + position + sep_len, str_len - position - sep_len);
    1846                 :            :     }
    1847                 :            : 
    1848                 :        192 :     return mp_obj_new_tuple(3, result);
    1849                 :            : }
    1850                 :            : 
    1851                 :        152 : static mp_obj_t str_partition(mp_obj_t self_in, mp_obj_t arg) {
    1852                 :        152 :     return str_partitioner(self_in, arg, 1);
    1853                 :            : }
    1854                 :            : MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
    1855                 :            : 
    1856                 :         72 : static mp_obj_t str_rpartition(mp_obj_t self_in, mp_obj_t arg) {
    1857                 :         72 :     return str_partitioner(self_in, arg, -1);
    1858                 :            : }
    1859                 :            : MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
    1860                 :            : #endif
    1861                 :            : 
    1862                 :            : // Supposedly not too critical operations, so optimize for code size
    1863                 :         46 : static mp_obj_t str_caseconv(unichar (*op)(unichar), mp_obj_t self_in) {
    1864         [ +  + ]:         46 :     GET_STR_DATA_LEN(self_in, self_data, self_len);
    1865                 :         46 :     vstr_t vstr;
    1866                 :         46 :     vstr_init_len(&vstr, self_len);
    1867                 :         46 :     byte *data = (byte *)vstr.buf;
    1868         [ +  + ]:        280 :     for (size_t i = 0; i < self_len; i++) {
    1869                 :        234 :         *data++ = op(*self_data++);
    1870                 :            :     }
    1871                 :         46 :     return mp_obj_new_str_type_from_vstr(mp_obj_get_type(self_in), &vstr);
    1872                 :            : }
    1873                 :            : 
    1874                 :         14 : static mp_obj_t str_lower(mp_obj_t self_in) {
    1875                 :         14 :     return str_caseconv(unichar_tolower, self_in);
    1876                 :            : }
    1877                 :            : MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower);
    1878                 :            : 
    1879                 :         32 : static mp_obj_t str_upper(mp_obj_t self_in) {
    1880                 :         32 :     return str_caseconv(unichar_toupper, self_in);
    1881                 :            : }
    1882                 :            : MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper);
    1883                 :            : 
    1884                 :        102 : static mp_obj_t str_uni_istype(bool (*f)(unichar), mp_obj_t self_in) {
    1885         [ +  + ]:        102 :     GET_STR_DATA_LEN(self_in, self_data, self_len);
    1886                 :            : 
    1887         [ +  + ]:        102 :     if (self_len == 0) {
    1888                 :            :         return mp_const_false; // default to False for empty str
    1889                 :            :     }
    1890                 :            : 
    1891   [ +  +  +  + ]:         82 :     if (f != unichar_isupper && f != unichar_islower) {
    1892         [ +  + ]:        528 :         for (size_t i = 0; i < self_len; i++) {
    1893         [ +  + ]:        506 :             if (!f(*self_data++)) {
    1894                 :            :                 return mp_const_false;
    1895                 :            :             }
    1896                 :            :         }
    1897                 :            :     } else {
    1898                 :            :         bool contains_alpha = false;
    1899                 :            : 
    1900         [ +  + ]:        388 :         for (size_t i = 0; i < self_len; i++) { // only check alphanumeric characters
    1901         [ +  + ]:        364 :             if (unichar_isalpha(*self_data++)) {
    1902                 :        240 :                 contains_alpha = true;
    1903         [ +  + ]:        240 :                 if (!f(*(self_data - 1))) { // -1 because we already incremented above
    1904                 :            :                     return mp_const_false;
    1905                 :            :                 }
    1906                 :            :             }
    1907                 :            :         }
    1908                 :            : 
    1909         [ +  + ]:         24 :         if (!contains_alpha) {
    1910                 :          4 :             return mp_const_false;
    1911                 :            :         }
    1912                 :            :     }
    1913                 :            : 
    1914                 :            :     return mp_const_true;
    1915                 :            : }
    1916                 :            : 
    1917                 :         20 : static mp_obj_t str_isspace(mp_obj_t self_in) {
    1918                 :         20 :     return str_uni_istype(unichar_isspace, self_in);
    1919                 :            : }
    1920                 :            : MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace);
    1921                 :            : 
    1922                 :         20 : static mp_obj_t str_isalpha(mp_obj_t self_in) {
    1923                 :         20 :     return str_uni_istype(unichar_isalpha, self_in);
    1924                 :            : }
    1925                 :            : MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha);
    1926                 :            : 
    1927                 :         22 : static mp_obj_t str_isdigit(mp_obj_t self_in) {
    1928                 :         22 :     return str_uni_istype(unichar_isdigit, self_in);
    1929                 :            : }
    1930                 :            : MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit);
    1931                 :            : 
    1932                 :         16 : static mp_obj_t str_isupper(mp_obj_t self_in) {
    1933                 :         16 :     return str_uni_istype(unichar_isupper, self_in);
    1934                 :            : }
    1935                 :            : MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper);
    1936                 :            : 
    1937                 :         24 : static mp_obj_t str_islower(mp_obj_t self_in) {
    1938                 :         24 :     return str_uni_istype(unichar_islower, self_in);
    1939                 :            : }
    1940                 :            : MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower);
    1941                 :            : 
    1942                 :            : #if MICROPY_CPYTHON_COMPAT
    1943                 :            : // These methods are superfluous in the presence of str() and bytes()
    1944                 :            : // constructors.
    1945                 :            : // TODO: should accept kwargs too
    1946                 :         10 : static mp_obj_t bytes_decode(size_t n_args, const mp_obj_t *args) {
    1947                 :         10 :     mp_obj_t new_args[2];
    1948         [ +  - ]:         10 :     if (n_args == 1) {
    1949                 :         10 :         new_args[0] = args[0];
    1950                 :         10 :         new_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_utf_hyphen_8);
    1951                 :         10 :         args = new_args;
    1952                 :         10 :         n_args++;
    1953                 :            :     }
    1954                 :         10 :     return mp_obj_str_make_new(&mp_type_str, n_args, 0, args);
    1955                 :            : }
    1956                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode);
    1957                 :            : 
    1958                 :            : // TODO: should accept kwargs too
    1959                 :         14 : static mp_obj_t str_encode(size_t n_args, const mp_obj_t *args) {
    1960                 :         14 :     mp_obj_t new_args[2];
    1961         [ +  + ]:         14 :     if (n_args == 1) {
    1962                 :         10 :         new_args[0] = args[0];
    1963                 :         10 :         new_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_utf_hyphen_8);
    1964                 :         10 :         args = new_args;
    1965                 :         10 :         n_args++;
    1966                 :            :     }
    1967                 :         14 :     return bytes_make_new(NULL, n_args, 0, args);
    1968                 :            : }
    1969                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode);
    1970                 :            : #endif
    1971                 :            : 
    1972                 :            : #if MICROPY_PY_BUILTINS_BYTES_HEX
    1973                 :        108 : mp_obj_t mp_obj_bytes_hex(size_t n_args, const mp_obj_t *args, const mp_obj_type_t *type) {
    1974                 :            :     // First argument is the data to convert.
    1975                 :            :     // Second argument is an optional separator to be used between values.
    1976                 :        108 :     const char *sep = NULL;
    1977                 :        108 :     mp_buffer_info_t bufinfo;
    1978                 :        108 :     mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
    1979                 :            : 
    1980                 :            :     // Code below assumes non-zero buffer length when computing size with
    1981                 :            :     // separator, so handle the zero-length case here.
    1982         [ +  + ]:        108 :     if (bufinfo.len == 0) {
    1983                 :            :         return mp_const_empty_bytes;
    1984                 :            :     }
    1985                 :            : 
    1986                 :        106 :     vstr_t vstr;
    1987                 :        106 :     size_t out_len = bufinfo.len * 2;
    1988         [ +  + ]:        106 :     if (n_args > 1) {
    1989                 :            :         // 1-char separator between hex numbers
    1990                 :         50 :         out_len += bufinfo.len - 1;
    1991                 :         50 :         sep = mp_obj_str_get_str(args[1]);
    1992                 :            :     }
    1993                 :        106 :     vstr_init_len(&vstr, out_len);
    1994                 :        106 :     byte *in = bufinfo.buf, *out = (byte *)vstr.buf;
    1995         [ +  + ]:        918 :     for (mp_uint_t i = bufinfo.len; i--;) {
    1996                 :        812 :         byte d = (*in >> 4);
    1997         [ +  + ]:        812 :         if (d > 9) {
    1998                 :         26 :             d += 'a' - '9' - 1;
    1999                 :            :         }
    2000                 :        812 :         *out++ = d + '0';
    2001                 :        812 :         d = (*in++ & 0xf);
    2002         [ +  + ]:        812 :         if (d > 9) {
    2003                 :        208 :             d += 'a' - '9' - 1;
    2004                 :            :         }
    2005                 :        812 :         *out++ = d + '0';
    2006         [ +  + ]:        812 :         if (sep != NULL && i != 0) {
    2007                 :        328 :             *out++ = *sep;
    2008                 :            :         }
    2009                 :            :     }
    2010                 :        106 :     return mp_obj_new_str_type_from_vstr(type, &vstr);
    2011                 :            : }
    2012                 :            : 
    2013                 :         32 : mp_obj_t mp_obj_bytes_fromhex(mp_obj_t type_in, mp_obj_t data) {
    2014                 :         32 :     mp_buffer_info_t bufinfo;
    2015                 :         32 :     mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
    2016                 :            : 
    2017         [ +  + ]:         32 :     if ((bufinfo.len & 1) != 0) {
    2018                 :          2 :         mp_raise_ValueError(MP_ERROR_TEXT("odd-length string"));
    2019                 :            :     }
    2020                 :         30 :     vstr_t vstr;
    2021                 :         30 :     vstr_init_len(&vstr, bufinfo.len / 2);
    2022                 :         30 :     byte *in = bufinfo.buf, *out = (byte *)vstr.buf;
    2023                 :         30 :     byte hex_byte = 0;
    2024         [ +  + ]:       3570 :     for (mp_uint_t i = bufinfo.len; i--;) {
    2025                 :       3542 :         byte hex_ch = *in++;
    2026         [ +  + ]:       3542 :         if (unichar_isxdigit(hex_ch)) {
    2027                 :       3540 :             hex_byte += unichar_xdigit_value(hex_ch);
    2028                 :            :         } else {
    2029                 :          2 :             mp_raise_ValueError(MP_ERROR_TEXT("non-hex digit found"));
    2030                 :            :         }
    2031         [ +  + ]:       3540 :         if (i & 1) {
    2032                 :       1770 :             hex_byte <<= 4;
    2033                 :            :         } else {
    2034                 :       1770 :             *out++ = hex_byte;
    2035                 :       1770 :             hex_byte = 0;
    2036                 :            :         }
    2037                 :            :     }
    2038                 :         28 :     return mp_obj_new_str_type_from_vstr(MP_OBJ_TO_PTR(type_in), &vstr);
    2039                 :            : }
    2040                 :            : 
    2041                 :         96 : static mp_obj_t bytes_hex_as_str(size_t n_args, const mp_obj_t *args) {
    2042                 :         96 :     return mp_obj_bytes_hex(n_args, args, &mp_type_str);
    2043                 :            : }
    2044                 :            : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_hex_as_str_obj, 1, 2, bytes_hex_as_str);
    2045                 :            : 
    2046                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(bytes_fromhex_obj, mp_obj_bytes_fromhex);
    2047                 :            : static MP_DEFINE_CONST_CLASSMETHOD_OBJ(bytes_fromhex_classmethod_obj, MP_ROM_PTR(&bytes_fromhex_obj));
    2048                 :            : #endif // MICROPY_PY_BUILTINS_BYTES_HEX
    2049                 :            : 
    2050                 :      30441 : mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
    2051         [ +  + ]:      30441 :     if (flags == MP_BUFFER_READ) {
    2052         [ +  + ]:      30225 :         GET_STR_DATA_LEN(self_in, str_data, str_len);
    2053                 :      30225 :         bufinfo->buf = (void *)str_data;
    2054                 :      30225 :         bufinfo->len = str_len;
    2055                 :      30225 :         bufinfo->typecode = 'B'; // bytes should be unsigned, so should unicode byte-access
    2056                 :      30225 :         return 0;
    2057                 :            :     } else {
    2058                 :            :         // can't write to a string
    2059                 :            :         return 1;
    2060                 :            :     }
    2061                 :            : }
    2062                 :            : 
    2063                 :       3312 : void mp_obj_str_set_data(mp_obj_str_t *str, const byte *data, size_t len) {
    2064                 :       3312 :     str->data = data;
    2065                 :       3312 :     str->len = len;
    2066                 :       3312 :     str->hash = qstr_compute_hash(data, len);
    2067                 :       3312 : }
    2068                 :            : 
    2069                 :            : // This locals table is used for the following types: str, bytes, bytearray, array.array.
    2070                 :            : // Each type takes a different section (start to end offset) of this table.
    2071                 :            : static const mp_rom_map_elem_t array_bytearray_str_bytes_locals_table[] = {
    2072                 :            :     #if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
    2073                 :            :     { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&mp_obj_array_append_obj) },
    2074                 :            :     { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&mp_obj_array_extend_obj) },
    2075                 :            :     #endif
    2076                 :            :     #if MICROPY_PY_BUILTINS_BYTES_HEX
    2077                 :            :     { MP_ROM_QSTR(MP_QSTR_hex), MP_ROM_PTR(&bytes_hex_as_str_obj) },
    2078                 :            :     { MP_ROM_QSTR(MP_QSTR_fromhex), MP_ROM_PTR(&bytes_fromhex_classmethod_obj) },
    2079                 :            :     #endif
    2080                 :            :     #if MICROPY_CPYTHON_COMPAT
    2081                 :            :     { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&bytes_decode_obj) },
    2082                 :            :     #endif
    2083                 :            :     { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&str_find_obj) },
    2084                 :            :     { MP_ROM_QSTR(MP_QSTR_rfind), MP_ROM_PTR(&str_rfind_obj) },
    2085                 :            :     { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&str_index_obj) },
    2086                 :            :     { MP_ROM_QSTR(MP_QSTR_rindex), MP_ROM_PTR(&str_rindex_obj) },
    2087                 :            :     { MP_ROM_QSTR(MP_QSTR_join), MP_ROM_PTR(&str_join_obj) },
    2088                 :            :     { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&str_split_obj) },
    2089                 :            :     #if MICROPY_PY_BUILTINS_STR_SPLITLINES
    2090                 :            :     { MP_ROM_QSTR(MP_QSTR_splitlines), MP_ROM_PTR(&str_splitlines_obj) },
    2091                 :            :     #endif
    2092                 :            :     { MP_ROM_QSTR(MP_QSTR_rsplit), MP_ROM_PTR(&str_rsplit_obj) },
    2093                 :            :     { MP_ROM_QSTR(MP_QSTR_startswith), MP_ROM_PTR(&str_startswith_obj) },
    2094                 :            :     { MP_ROM_QSTR(MP_QSTR_endswith), MP_ROM_PTR(&str_endswith_obj) },
    2095                 :            :     { MP_ROM_QSTR(MP_QSTR_strip), MP_ROM_PTR(&str_strip_obj) },
    2096                 :            :     { MP_ROM_QSTR(MP_QSTR_lstrip), MP_ROM_PTR(&str_lstrip_obj) },
    2097                 :            :     { MP_ROM_QSTR(MP_QSTR_rstrip), MP_ROM_PTR(&str_rstrip_obj) },
    2098                 :            :     { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&str_format_obj) },
    2099                 :            :     { MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&str_replace_obj) },
    2100                 :            :     #if MICROPY_PY_BUILTINS_STR_COUNT
    2101                 :            :     { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) },
    2102                 :            :     #endif
    2103                 :            :     #if MICROPY_PY_BUILTINS_STR_PARTITION
    2104                 :            :     { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) },
    2105                 :            :     { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) },
    2106                 :            :     #endif
    2107                 :            :     #if MICROPY_PY_BUILTINS_STR_CENTER
    2108                 :            :     { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) },
    2109                 :            :     #endif
    2110                 :            :     { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) },
    2111                 :            :     { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) },
    2112                 :            :     { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) },
    2113                 :            :     { MP_ROM_QSTR(MP_QSTR_isalpha), MP_ROM_PTR(&str_isalpha_obj) },
    2114                 :            :     { MP_ROM_QSTR(MP_QSTR_isdigit), MP_ROM_PTR(&str_isdigit_obj) },
    2115                 :            :     { MP_ROM_QSTR(MP_QSTR_isupper), MP_ROM_PTR(&str_isupper_obj) },
    2116                 :            :     { MP_ROM_QSTR(MP_QSTR_islower), MP_ROM_PTR(&str_islower_obj) },
    2117                 :            :     #if MICROPY_CPYTHON_COMPAT
    2118                 :            :     { MP_ROM_QSTR(MP_QSTR_encode), MP_ROM_PTR(&str_encode_obj) },
    2119                 :            :     #endif
    2120                 :            : };
    2121                 :            : 
    2122                 :            : #if MICROPY_CPYTHON_COMPAT
    2123                 :            : #define TABLE_ENTRIES_COMPAT 1
    2124                 :            : #else
    2125                 :            : #define TABLE_ENTRIES_COMPAT 0
    2126                 :            : #endif
    2127                 :            : 
    2128                 :            : #if MICROPY_PY_BUILTINS_BYTES_HEX
    2129                 :            : #define TABLE_ENTRIES_HEX 2
    2130                 :            : #else
    2131                 :            : #define TABLE_ENTRIES_HEX 0
    2132                 :            : #endif
    2133                 :            : 
    2134                 :            : #if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
    2135                 :            : #define TABLE_ENTRIES_ARRAY 2
    2136                 :            : #else
    2137                 :            : #define TABLE_ENTRIES_ARRAY 0
    2138                 :            : #endif
    2139                 :            : 
    2140                 :            : MP_DEFINE_CONST_DICT_WITH_SIZE(mp_obj_str_locals_dict,
    2141                 :            :     array_bytearray_str_bytes_locals_table + TABLE_ENTRIES_ARRAY + TABLE_ENTRIES_HEX + TABLE_ENTRIES_COMPAT,
    2142                 :            :     MP_ARRAY_SIZE(array_bytearray_str_bytes_locals_table) - (TABLE_ENTRIES_ARRAY + TABLE_ENTRIES_HEX + TABLE_ENTRIES_COMPAT));
    2143                 :            : 
    2144                 :            : #if TABLE_ENTRIES_COMPAT == 0
    2145                 :            : #define mp_obj_bytes_locals_dict mp_obj_str_locals_dict
    2146                 :            : #else
    2147                 :            : MP_DEFINE_CONST_DICT_WITH_SIZE(mp_obj_bytes_locals_dict,
    2148                 :            :     array_bytearray_str_bytes_locals_table + TABLE_ENTRIES_ARRAY,
    2149                 :            :     MP_ARRAY_SIZE(array_bytearray_str_bytes_locals_table) - (TABLE_ENTRIES_ARRAY + TABLE_ENTRIES_COMPAT));
    2150                 :            : #endif
    2151                 :            : 
    2152                 :            : #if MICROPY_PY_BUILTINS_BYTEARRAY
    2153                 :            : MP_DEFINE_CONST_DICT_WITH_SIZE(mp_obj_bytearray_locals_dict,
    2154                 :            :     array_bytearray_str_bytes_locals_table,
    2155                 :            :     MP_ARRAY_SIZE(array_bytearray_str_bytes_locals_table) - TABLE_ENTRIES_COMPAT);
    2156                 :            : #endif
    2157                 :            : 
    2158                 :            : #if MICROPY_PY_ARRAY
    2159                 :            : MP_DEFINE_CONST_DICT_WITH_SIZE(mp_obj_array_locals_dict,
    2160                 :            :     array_bytearray_str_bytes_locals_table,
    2161                 :            :     TABLE_ENTRIES_ARRAY);
    2162                 :            : #endif
    2163                 :            : 
    2164                 :            : #if MICROPY_PY_BUILTINS_MEMORYVIEW && MICROPY_PY_BUILTINS_BYTES_HEX
    2165                 :            : MP_DEFINE_CONST_DICT_WITH_SIZE(mp_obj_memoryview_locals_dict,
    2166                 :            :     array_bytearray_str_bytes_locals_table + TABLE_ENTRIES_ARRAY,
    2167                 :            :     1); // Just the "hex" entry.
    2168                 :            : #endif
    2169                 :            : 
    2170                 :            : #if !MICROPY_PY_BUILTINS_STR_UNICODE
    2171                 :            : static mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);
    2172                 :            : 
    2173                 :            : MP_DEFINE_CONST_OBJ_TYPE(
    2174                 :            :     mp_type_str,
    2175                 :            :     MP_QSTR_str,
    2176                 :            :     MP_TYPE_FLAG_NONE,
    2177                 :            :     make_new, mp_obj_str_make_new,
    2178                 :            :     print, str_print,
    2179                 :            :     binary_op, mp_obj_str_binary_op,
    2180                 :            :     subscr, bytes_subscr,
    2181                 :            :     iter, mp_obj_new_str_iterator,
    2182                 :            :     buffer, mp_obj_str_get_buffer,
    2183                 :            :     locals_dict, &mp_obj_str_locals_dict
    2184                 :            :     );
    2185                 :            : #endif // !MICROPY_PY_BUILTINS_STR_UNICODE
    2186                 :            : 
    2187                 :            : // Reuses most methods from str
    2188                 :            : MP_DEFINE_CONST_OBJ_TYPE(
    2189                 :            :     mp_type_bytes,
    2190                 :            :     MP_QSTR_bytes,
    2191                 :            :     MP_TYPE_FLAG_NONE,
    2192                 :            :     make_new, bytes_make_new,
    2193                 :            :     print, str_print,
    2194                 :            :     binary_op, mp_obj_str_binary_op,
    2195                 :            :     subscr, bytes_subscr,
    2196                 :            :     iter, mp_obj_new_bytes_iterator,
    2197                 :            :     buffer, mp_obj_str_get_buffer,
    2198                 :            :     locals_dict, &mp_obj_bytes_locals_dict
    2199                 :            :     );
    2200                 :            : 
    2201                 :            : // The zero-length bytes object, with data that includes a null-terminating byte
    2202                 :            : const mp_obj_str_t mp_const_empty_bytes_obj = {{&mp_type_bytes}, 0, 0, (const byte *)""};
    2203                 :            : 
    2204                 :            : // Create a str/bytes object using the given data.  New memory is allocated and
    2205                 :            : // the data is copied across.  This function should only be used if the type is bytes,
    2206                 :            : // or if the type is str and the string data is known to be not interned.
    2207                 :       9789 : mp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte *data, size_t len) {
    2208                 :       9789 :     mp_obj_str_t *o = mp_obj_malloc(mp_obj_str_t, type);
    2209                 :       9789 :     o->len = len;
    2210         [ +  + ]:       9789 :     if (data) {
    2211                 :       9751 :         o->hash = qstr_compute_hash(data, len);
    2212                 :       9751 :         byte *p = m_new(byte, len + 1);
    2213                 :       9751 :         o->data = p;
    2214                 :       9751 :         memcpy(p, data, len * sizeof(byte));
    2215                 :       9751 :         p[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings
    2216                 :            :     }
    2217                 :       9789 :     return MP_OBJ_FROM_PTR(o);
    2218                 :            : }
    2219                 :            : 
    2220                 :            : // Create a str/bytes object using the given data.  If the type is str and the string
    2221                 :            : // data is already interned, then a qstr object is returned.  Otherwise new memory is
    2222                 :            : // allocated for the object and the data is copied across.
    2223                 :       6784 : mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte *data, size_t len) {
    2224         [ +  + ]:       6784 :     if (type == &mp_type_str) {
    2225                 :       6240 :         return mp_obj_new_str((const char *)data, len);
    2226                 :            :     #if MICROPY_PY_BUILTINS_BYTEARRAY
    2227         [ +  + ]:        544 :     } else if (type == &mp_type_bytearray) {
    2228                 :         64 :         return mp_obj_new_bytearray(len, data);
    2229                 :            :     #endif
    2230                 :            :     } else {
    2231                 :        480 :         return mp_obj_new_bytes(data, len);
    2232                 :            :     }
    2233                 :            : }
    2234                 :            : 
    2235                 :            : // Create a str using a qstr to store the data; may use existing or new qstr.
    2236                 :      29954 : mp_obj_t mp_obj_new_str_via_qstr(const char *data, size_t len) {
    2237                 :      29954 :     return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len));
    2238                 :            : }
    2239                 :            : 
    2240                 :            : // Create a str/bytes object from the given vstr.  The vstr buffer is resized to
    2241                 :            : // the exact length required and then reused for the str/bytes object.  The vstr
    2242                 :            : // is cleared and can safely be passed to vstr_free if it was heap allocated.
    2243                 :     289095 : static mp_obj_t mp_obj_new_str_type_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) {
    2244                 :            :     // if not a bytes object, look if a qstr with this data already exists
    2245         [ +  + ]:     289095 :     if (type == &mp_type_str) {
    2246                 :     286810 :         qstr q = qstr_find_strn(vstr->buf, vstr->len);
    2247         [ +  + ]:     286810 :         if (q != MP_QSTRnull) {
    2248                 :       8975 :             vstr_clear(vstr);
    2249                 :       8975 :             vstr->alloc = 0;
    2250                 :       8975 :             return MP_OBJ_NEW_QSTR(q);
    2251                 :            :         }
    2252                 :            :     }
    2253                 :            : 
    2254                 :     280120 :     byte *data;
    2255         [ +  + ]:     280120 :     if (vstr->len + 1 == vstr->alloc) {
    2256                 :      76246 :         data = (byte *)vstr->buf;
    2257                 :            :     } else {
    2258                 :     203874 :         data = (byte *)m_renew(char, vstr->buf, vstr->alloc, vstr->len + 1);
    2259                 :            :     }
    2260                 :     280120 :     data[vstr->len] = '\0'; // add null byte
    2261                 :     280120 :     vstr->buf = NULL;
    2262                 :     280120 :     vstr->alloc = 0;
    2263                 :            :     #if MICROPY_PY_BUILTINS_BYTEARRAY
    2264         [ +  + ]:     280120 :     if (type == &mp_type_bytearray) {
    2265                 :         28 :         return mp_obj_new_bytearray_by_ref(vstr->len, data);
    2266                 :            :     }
    2267                 :            :     #endif
    2268                 :     280092 :     mp_obj_str_t *o = mp_obj_malloc(mp_obj_str_t, type);
    2269                 :     280092 :     o->len = vstr->len;
    2270                 :     280092 :     o->hash = qstr_compute_hash(data, vstr->len);
    2271                 :     280092 :     o->data = data;
    2272                 :     280092 :     return MP_OBJ_FROM_PTR(o);
    2273                 :            : }
    2274                 :            : 
    2275                 :        209 : mp_obj_t mp_obj_new_str_from_vstr(vstr_t *vstr) {
    2276                 :            :     #if MICROPY_PY_BUILTINS_STR_UNICODE && MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
    2277         [ +  + ]:        209 :     if (!utf8_check((byte *)vstr->buf, vstr->len)) {
    2278                 :          2 :         mp_raise_msg(&mp_type_UnicodeError, NULL);
    2279                 :            :     }
    2280                 :            :     #endif // MICROPY_PY_BUILTINS_STR_UNICODE && MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
    2281                 :        207 :     return mp_obj_new_str_type_from_vstr(&mp_type_str, vstr);
    2282                 :            : }
    2283                 :            : 
    2284                 :            : #if MICROPY_PY_BUILTINS_STR_UNICODE && MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
    2285                 :       5271 : mp_obj_t mp_obj_new_str_from_utf8_vstr(vstr_t *vstr) {
    2286                 :            :     // bypasses utf8_check.
    2287                 :       5271 :     return mp_obj_new_str_type_from_vstr(&mp_type_str, vstr);
    2288                 :            : }
    2289                 :            : #endif // MICROPY_PY_BUILTINS_STR_UNICODE && MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
    2290                 :            : 
    2291                 :       1475 : mp_obj_t mp_obj_new_bytes_from_vstr(vstr_t *vstr) {
    2292                 :       1475 :     return mp_obj_new_str_type_from_vstr(&mp_type_bytes, vstr);
    2293                 :            : }
    2294                 :            : 
    2295                 :       9683 : mp_obj_t mp_obj_new_str(const char *data, size_t len) {
    2296                 :            :     #if MICROPY_PY_BUILTINS_STR_UNICODE && MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
    2297         [ +  + ]:       9683 :     if (!utf8_check((byte *)data, len)) {
    2298                 :          2 :         mp_raise_msg(&mp_type_UnicodeError, NULL);
    2299                 :            :     }
    2300                 :            :     #endif
    2301                 :       9681 :     qstr q = qstr_find_strn(data, len);
    2302         [ +  + ]:       9681 :     if (q != MP_QSTRnull) {
    2303                 :            :         // qstr with this data already exists
    2304                 :       5142 :         return MP_OBJ_NEW_QSTR(q);
    2305                 :            :     } else {
    2306                 :            :         // no existing qstr, don't make one
    2307                 :       4539 :         return mp_obj_new_str_copy(&mp_type_str, (const byte *)data, len);
    2308                 :            :     }
    2309                 :            : }
    2310                 :            : 
    2311                 :          2 : mp_obj_t mp_obj_str_intern(mp_obj_t str) {
    2312         [ -  + ]:          2 :     GET_STR_DATA_LEN(str, data, len);
    2313                 :          2 :     return mp_obj_new_str_via_qstr((const char *)data, len);
    2314                 :            : }
    2315                 :            : 
    2316                 :        426 : mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj) {
    2317                 :        426 :     size_t len;
    2318                 :        426 :     const char *data = mp_obj_str_get_data(obj, &len);
    2319                 :        418 :     return mp_obj_new_str_via_qstr((const char *)data, len);
    2320                 :            : }
    2321                 :            : 
    2322                 :       2780 : mp_obj_t mp_obj_new_bytes(const byte *data, size_t len) {
    2323                 :       2780 :     return mp_obj_new_str_copy(&mp_type_bytes, data, len);
    2324                 :            : }
    2325                 :            : 
    2326                 :     271518 : bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
    2327   [ +  +  +  + ]:     271518 :     if (mp_obj_is_qstr(s1) && mp_obj_is_qstr(s2)) {
    2328                 :       4631 :         return s1 == s2;
    2329                 :            :     } else {
    2330         [ +  + ]:     266887 :         GET_STR_HASH(s1, h1);
    2331         [ +  + ]:     266887 :         GET_STR_HASH(s2, h2);
    2332                 :            :         // If any of hashes is 0, it means it's not valid
    2333   [ +  +  +  + ]:     266887 :         if (h1 != 0 && h2 != 0 && h1 != h2) {
    2334                 :            :             return false;
    2335                 :            :         }
    2336         [ +  + ]:      21286 :         GET_STR_DATA_LEN(s1, d1, l1);
    2337         [ +  + ]:      21286 :         GET_STR_DATA_LEN(s2, d2, l2);
    2338         [ +  + ]:      21286 :         if (l1 != l2) {
    2339                 :            :             return false;
    2340                 :            :         }
    2341                 :      21280 :         return memcmp(d1, d2, l1) == 0;
    2342                 :            :     }
    2343                 :            : }
    2344                 :            : 
    2345                 :        110 : static NORETURN void bad_implicit_conversion(mp_obj_t self_in) {
    2346                 :            :     #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
    2347                 :            :     mp_raise_TypeError(MP_ERROR_TEXT("can't convert to str implicitly"));
    2348                 :            :     #else
    2349                 :        110 :     const qstr src_name = mp_obj_get_type(self_in)->name;
    2350         [ +  + ]:        110 :     mp_raise_msg_varg(&mp_type_TypeError,
    2351                 :        110 :         MP_ERROR_TEXT("can't convert '%q' object to %q implicitly"),
    2352                 :            :         src_name, src_name == MP_QSTR_str ? MP_QSTR_bytes : MP_QSTR_str);
    2353                 :            :     #endif
    2354                 :            : }
    2355                 :            : 
    2356                 :            : // use this if you will anyway convert the string to a qstr
    2357                 :            : // will be more efficient for the case where it's already a qstr
    2358                 :       4824 : qstr mp_obj_str_get_qstr(mp_obj_t self_in) {
    2359         [ +  + ]:       4824 :     if (mp_obj_is_qstr(self_in)) {
    2360                 :       4774 :         return MP_OBJ_QSTR_VALUE(self_in);
    2361   [ +  +  +  + ]:         50 :     } else if (mp_obj_is_exact_type(self_in, &mp_type_str)) {
    2362                 :         34 :         mp_obj_str_t *self = MP_OBJ_TO_PTR(self_in);
    2363                 :         34 :         return qstr_from_strn((char *)self->data, self->len);
    2364                 :            :     } else {
    2365                 :         16 :         bad_implicit_conversion(self_in);
    2366                 :            :     }
    2367                 :            : }
    2368                 :            : 
    2369                 :            : // only use this function if you need the str data to be zero terminated
    2370                 :            : // at the moment all strings are zero terminated to help with C ASCIIZ compatibility
    2371                 :      30284 : const char *mp_obj_str_get_str(mp_obj_t self_in) {
    2372   [ +  +  +  +  :      30284 :     if (mp_obj_is_str_or_bytes(self_in)) {
             +  -  +  - ]
    2373         [ +  + ]:      30274 :         GET_STR_DATA_LEN(self_in, s, l);
    2374                 :      30274 :         (void)l; // len unused
    2375                 :      30274 :         return (const char *)s;
    2376                 :            :     } else {
    2377                 :         10 :         bad_implicit_conversion(self_in);
    2378                 :            :     }
    2379                 :            : }
    2380                 :            : 
    2381                 :     434069 : const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) {
    2382   [ +  +  +  +  :     434069 :     if (mp_obj_is_str_or_bytes(self_in)) {
             +  +  +  + ]
    2383         [ +  + ]:     434037 :         GET_STR_DATA_LEN(self_in, s, l);
    2384                 :     434037 :         *len = l;
    2385                 :     434037 :         return (const char *)s;
    2386                 :            :     } else {
    2387                 :         32 :         bad_implicit_conversion(self_in);
    2388                 :            :     }
    2389                 :            : }
    2390                 :            : 
    2391                 :            : #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
    2392                 :            : const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len) {
    2393                 :            :     if (mp_obj_is_qstr(self_in)) {
    2394                 :            :         return qstr_data(MP_OBJ_QSTR_VALUE(self_in), len);
    2395                 :            :     } else {
    2396                 :            :         MP_STATIC_ASSERT_STR_ARRAY_COMPATIBLE;
    2397                 :            :         *len = ((mp_obj_str_t *)MP_OBJ_TO_PTR(self_in))->len;
    2398                 :            :         return ((mp_obj_str_t *)MP_OBJ_TO_PTR(self_in))->data;
    2399                 :            :     }
    2400                 :            : }
    2401                 :            : #endif
    2402                 :            : 
    2403                 :            : /******************************************************************************/
    2404                 :            : /* str iterator                                                               */
    2405                 :            : 
    2406                 :            : typedef struct _mp_obj_str8_it_t {
    2407                 :            :     mp_obj_base_t base;
    2408                 :            :     mp_fun_1_t iternext;
    2409                 :            :     mp_obj_t str;
    2410                 :            :     size_t cur;
    2411                 :            : } mp_obj_str8_it_t;
    2412                 :            : 
    2413                 :            : #if !MICROPY_PY_BUILTINS_STR_UNICODE
    2414                 :            : static mp_obj_t str_it_iternext(mp_obj_t self_in) {
    2415                 :            :     mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in);
    2416                 :            :     GET_STR_DATA_LEN(self->str, str, len);
    2417                 :            :     if (self->cur < len) {
    2418                 :            :         mp_obj_t o_out = mp_obj_new_str_via_qstr((const char *)str + self->cur, 1);
    2419                 :            :         self->cur += 1;
    2420                 :            :         return o_out;
    2421                 :            :     } else {
    2422                 :            :         return MP_OBJ_STOP_ITERATION;
    2423                 :            :     }
    2424                 :            : }
    2425                 :            : 
    2426                 :            : static mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) {
    2427                 :            :     assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t));
    2428                 :            :     mp_obj_str8_it_t *o = (mp_obj_str8_it_t *)iter_buf;
    2429                 :            :     o->base.type = &mp_type_polymorph_iter;
    2430                 :            :     o->iternext = str_it_iternext;
    2431                 :            :     o->str = str;
    2432                 :            :     o->cur = 0;
    2433                 :            :     return MP_OBJ_FROM_PTR(o);
    2434                 :            : }
    2435                 :            : #endif
    2436                 :            : 
    2437                 :         92 : static mp_obj_t bytes_it_iternext(mp_obj_t self_in) {
    2438                 :         92 :     mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in);
    2439         [ -  + ]:         92 :     GET_STR_DATA_LEN(self->str, str, len);
    2440         [ +  + ]:         92 :     if (self->cur < len) {
    2441                 :         72 :         mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(str[self->cur]);
    2442                 :         72 :         self->cur += 1;
    2443                 :         72 :         return o_out;
    2444                 :            :     } else {
    2445                 :            :         return MP_OBJ_STOP_ITERATION;
    2446                 :            :     }
    2447                 :            : }
    2448                 :            : 
    2449                 :         32 : mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) {
    2450                 :         32 :     assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t));
    2451                 :         32 :     mp_obj_str8_it_t *o = (mp_obj_str8_it_t *)iter_buf;
    2452                 :         32 :     o->base.type = &mp_type_polymorph_iter;
    2453                 :         32 :     o->iternext = bytes_it_iternext;
    2454                 :         32 :     o->str = str;
    2455                 :         32 :     o->cur = 0;
    2456                 :         32 :     return MP_OBJ_FROM_PTR(o);
    2457                 :            : }

Generated by: LCOV version 1.15-5-g462f71d