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

Generated by: LCOV version 1.15-5-g462f71d