LCOV - code coverage report
Current view: top level - py - objstr.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.19.1-992-g38e7b842c.info Lines: 1121 1122 99.9 %
Date: 2023-03-23 12:38:05 Functions: 73 73 100.0 %
Branches: 814 876 92.9 %

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

Generated by: LCOV version 1.15-5-g462f71d