LCOV - code coverage report
Current view: top level - py - objdict.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-335-g9c7f0659e.info Lines: 307 307 100.0 %
Date: 2024-04-24 08:31:58 Functions: 34 34 100.0 %
Branches: 144 157 91.7 %

           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-2017 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/runtime.h"
      32                 :            : #include "py/builtin.h"
      33                 :            : #include "py/objtype.h"
      34                 :            : #include "py/objstr.h"
      35                 :            : 
      36                 :    1115623 : bool mp_obj_is_dict_or_ordereddict(mp_obj_t o) {
      37   [ +  +  +  +  :    1115623 :     return mp_obj_is_obj(o) && MP_OBJ_TYPE_GET_SLOT_OR_NULL(((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type, make_new) == mp_obj_dict_make_new;
                   +  + ]
      38                 :            : }
      39                 :            : 
      40                 :            : const mp_obj_dict_t mp_const_empty_dict_obj = {
      41                 :            :     .base = { .type = &mp_type_dict },
      42                 :            :     .map = {
      43                 :            :         .all_keys_are_qstrs = 0,
      44                 :            :         .is_fixed = 1,
      45                 :            :         .is_ordered = 1,
      46                 :            :         .used = 0,
      47                 :            :         .alloc = 0,
      48                 :            :         .table = NULL,
      49                 :            :     }
      50                 :            : };
      51                 :            : 
      52                 :            : static mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
      53                 :            : 
      54                 :            : // This is a helper function to iterate through a dictionary.  The state of
      55                 :            : // the iteration is held in *cur and should be initialised with zero for the
      56                 :            : // first call.  Will return NULL when no more elements are available.
      57                 :       1694 : static mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) {
      58                 :       1694 :     size_t max = dict->map.alloc;
      59                 :       1694 :     mp_map_t *map = &dict->map;
      60                 :            : 
      61                 :       1694 :     size_t i = *cur;
      62         [ +  + ]:       2076 :     for (; i < max; i++) {
      63         [ +  + ]:       1372 :         if (mp_map_slot_is_filled(map, i)) {
      64                 :        990 :             *cur = i + 1;
      65                 :        990 :             return &(map->table[i]);
      66                 :            :         }
      67                 :            :     }
      68                 :            : 
      69   [ +  +  -  + ]:        704 :     assert(map->used == 0 || i == max);
      70                 :            :     return NULL;
      71                 :            : }
      72                 :            : 
      73                 :        416 : static void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
      74                 :        416 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
      75                 :        416 :     bool first = true;
      76                 :        416 :     const char *item_separator = ", ";
      77                 :        416 :     const char *key_separator = ": ";
      78         [ +  + ]:        416 :     if (!(MICROPY_PY_JSON && kind == PRINT_JSON)) {
      79                 :            :         kind = PRINT_REPR;
      80                 :            :     } else {
      81                 :            :         #if MICROPY_PY_JSON_SEPARATORS
      82                 :        134 :         item_separator = MP_PRINT_GET_EXT(print)->item_separator;
      83                 :        134 :         key_separator = MP_PRINT_GET_EXT(print)->key_separator;
      84                 :            :         #endif
      85                 :            :     }
      86   [ +  +  +  + ]:        416 :     if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) {
      87                 :         40 :         mp_printf(print, "%q(", self->base.type->name);
      88                 :            :     }
      89                 :        416 :     mp_print_str(print, "{");
      90                 :        416 :     size_t cur = 0;
      91                 :        416 :     mp_map_elem_t *next = NULL;
      92         [ +  + ]:        760 :     while ((next = dict_iter_next(self, &cur)) != NULL) {
      93         [ +  + ]:        344 :         if (!first) {
      94                 :         34 :             mp_print_str(print, item_separator);
      95                 :            :         }
      96                 :        344 :         first = false;
      97   [ +  +  +  +  :        344 :         bool add_quote = MICROPY_PY_JSON && kind == PRINT_JSON && !mp_obj_is_str_or_bytes(next->key);
          +  +  +  -  +  
                      - ]
      98                 :            :         if (add_quote) {
      99                 :         70 :             mp_print_str(print, "\"");
     100                 :            :         }
     101                 :        344 :         mp_obj_print_helper(print, next->key, kind);
     102         [ +  + ]:        344 :         if (add_quote) {
     103                 :         70 :             mp_print_str(print, "\"");
     104                 :            :         }
     105                 :        344 :         mp_print_str(print, key_separator);
     106                 :        344 :         mp_obj_print_helper(print, next->value, kind);
     107                 :            :     }
     108                 :        416 :     mp_print_str(print, "}");
     109   [ +  +  +  + ]:        416 :     if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) {
     110                 :         40 :         mp_print_str(print, ")");
     111                 :            :     }
     112                 :        416 : }
     113                 :            : 
     114                 :        836 : mp_obj_t mp_obj_dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     115                 :        836 :     mp_obj_t dict_out = mp_obj_new_dict(0);
     116                 :        836 :     mp_obj_dict_t *dict = MP_OBJ_TO_PTR(dict_out);
     117                 :        836 :     dict->base.type = type;
     118                 :            :     #if MICROPY_PY_COLLECTIONS_ORDEREDDICT
     119         [ +  + ]:        836 :     if (type == &mp_type_ordereddict) {
     120                 :         24 :         dict->map.is_ordered = 1;
     121                 :            :     }
     122                 :            :     #endif
     123         [ +  + ]:        836 :     if (n_args > 0 || n_kw > 0) {
     124                 :         50 :         mp_obj_t args2[2] = {dict_out, args[0]}; // args[0] is always valid, even if it's not a positional arg
     125                 :         50 :         mp_map_t kwargs;
     126                 :         50 :         mp_map_init_fixed_table(&kwargs, n_kw, args + n_args);
     127                 :         50 :         dict_update(n_args + 1, args2, &kwargs); // dict_update will check that n_args + 1 == 1 or 2
     128                 :            :     }
     129                 :        828 :     return dict_out;
     130                 :            : }
     131                 :            : 
     132                 :       1639 : static mp_obj_t dict_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
     133                 :       1639 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     134   [ +  +  +  + ]:       1639 :     switch (op) {
     135                 :         17 :         case MP_UNARY_OP_BOOL:
     136         [ +  + ]:         17 :             return mp_obj_new_bool(self->map.used != 0);
     137                 :       1610 :         case MP_UNARY_OP_LEN:
     138                 :       1610 :             return MP_OBJ_NEW_SMALL_INT(self->map.used);
     139                 :            :         #if MICROPY_PY_SYS_GETSIZEOF
     140                 :          4 :         case MP_UNARY_OP_SIZEOF: {
     141                 :          4 :             size_t sz = sizeof(*self) + sizeof(*self->map.table) * self->map.alloc;
     142                 :          4 :             return MP_OBJ_NEW_SMALL_INT(sz);
     143                 :            :         }
     144                 :            :         #endif
     145                 :            :         default:
     146                 :            :             return MP_OBJ_NULL;      // op not supported
     147                 :            :     }
     148                 :            : }
     149                 :            : 
     150                 :      12460 : static mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
     151                 :      12460 :     mp_obj_dict_t *o = MP_OBJ_TO_PTR(lhs_in);
     152   [ +  +  +  + ]:      12460 :     switch (op) {
     153                 :      12356 :         case MP_BINARY_OP_CONTAINS: {
     154                 :      12356 :             mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP);
     155         [ +  + ]:      12356 :             return mp_obj_new_bool(elem != NULL);
     156                 :            :         }
     157                 :            :         case MP_BINARY_OP_EQUAL: {
     158                 :            :             #if MICROPY_PY_COLLECTIONS_ORDEREDDICT
     159   [ +  -  +  +  :         40 :             if (MP_UNLIKELY(mp_obj_is_type(lhs_in, &mp_type_ordereddict) && mp_obj_is_type(rhs_in, &mp_type_ordereddict))) {
             +  -  +  - ]
     160                 :            :                 // Iterate through both dictionaries simultaneously and compare keys and values.
     161                 :         20 :                 mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in);
     162                 :         20 :                 size_t c1 = 0, c2 = 0;
     163                 :         20 :                 mp_map_elem_t *e1 = dict_iter_next(o, &c1), *e2 = dict_iter_next(rhs, &c2);
     164         [ +  + ]:         60 :                 for (; e1 != NULL && e2 != NULL; e1 = dict_iter_next(o, &c1), e2 = dict_iter_next(rhs, &c2)) {
     165   [ +  +  -  + ]:         24 :                     if (!mp_obj_equal(e1->key, e2->key) || !mp_obj_equal(e1->value, e2->value)) {
     166                 :          4 :                         return mp_const_false;
     167                 :            :                     }
     168                 :            :                 }
     169         [ +  + ]:         16 :                 return e1 == NULL && e2 == NULL ? mp_const_true : mp_const_false;
     170                 :            :             }
     171                 :            :             #endif
     172                 :            : 
     173   [ +  -  +  - ]:         20 :             if (mp_obj_is_type(rhs_in, &mp_type_dict)) {
     174                 :         20 :                 mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in);
     175         [ +  + ]:         20 :                 if (o->map.used != rhs->map.used) {
     176                 :            :                     return mp_const_false;
     177                 :            :                 }
     178                 :            : 
     179                 :         16 :                 size_t cur = 0;
     180                 :         16 :                 mp_map_elem_t *next = NULL;
     181         [ +  + ]:        124 :                 while ((next = dict_iter_next(o, &cur)) != NULL) {
     182                 :        112 :                     mp_map_elem_t *elem = mp_map_lookup(&rhs->map, next->key, MP_MAP_LOOKUP);
     183   [ +  +  -  + ]:        112 :                     if (elem == NULL || !mp_obj_equal(next->value, elem->value)) {
     184                 :          4 :                         return mp_const_false;
     185                 :            :                     }
     186                 :            :                 }
     187                 :            :                 return mp_const_true;
     188                 :            :             } else {
     189                 :            :                 // dict is not equal to instance of any other type
     190                 :            :                 return mp_const_false;
     191                 :            :             }
     192                 :            :         }
     193                 :            :         #if MICROPY_CPYTHON_COMPAT
     194                 :         52 :         case MP_BINARY_OP_INPLACE_OR:
     195                 :            :         case MP_BINARY_OP_OR: {
     196         [ +  + ]:         52 :             if (op == MP_BINARY_OP_OR) {
     197                 :         28 :                 lhs_in = mp_obj_dict_copy(lhs_in);
     198                 :            :             }
     199                 :         52 :             mp_obj_t dicts[2] = {lhs_in, rhs_in};
     200                 :         52 :             dict_update(2, dicts, (mp_map_t *)&mp_const_empty_map);
     201                 :         52 :             return lhs_in;
     202                 :            :         }
     203                 :            :         #endif
     204                 :            :         default:
     205                 :            :             // op not supported
     206                 :            :             return MP_OBJ_NULL;
     207                 :            :     }
     208                 :            : }
     209                 :            : 
     210                 :            : // Note: Make sure this is inlined in load part of dict_subscr() below.
     211                 :       1504 : mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) {
     212                 :       1504 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     213                 :       1504 :     mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP);
     214         [ +  + ]:       1504 :     if (elem == NULL) {
     215                 :          6 :         mp_raise_type_arg(&mp_type_KeyError, index);
     216                 :            :     } else {
     217                 :       1498 :         return elem->value;
     218                 :            :     }
     219                 :            : }
     220                 :            : 
     221                 :      69872 : static mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
     222         [ +  + ]:      69872 :     if (value == MP_OBJ_NULL) {
     223                 :            :         // delete
     224                 :        822 :         mp_obj_dict_delete(self_in, index);
     225                 :        822 :         return mp_const_none;
     226         [ +  + ]:      69050 :     } else if (value == MP_OBJ_SENTINEL) {
     227                 :            :         // load
     228                 :       5518 :         mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     229                 :       5518 :         mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP);
     230         [ +  + ]:       5518 :         if (elem == NULL) {
     231                 :         70 :             mp_raise_type_arg(&mp_type_KeyError, index);
     232                 :            :         } else {
     233                 :       5448 :             return elem->value;
     234                 :            :         }
     235                 :            :     } else {
     236                 :            :         // store
     237                 :      63532 :         mp_obj_dict_store(self_in, index, value);
     238                 :      63532 :         return mp_const_none;
     239                 :            :     }
     240                 :            : }
     241                 :            : 
     242                 :            : /******************************************************************************/
     243                 :            : /* dict methods                                                               */
     244                 :            : 
     245                 :     893653 : static void mp_ensure_not_fixed(const mp_obj_dict_t *dict) {
     246         [ +  + ]:     893653 :     if (dict->map.is_fixed) {
     247                 :         28 :         mp_raise_TypeError(NULL);
     248                 :            :     }
     249                 :     893625 : }
     250                 :            : 
     251                 :         12 : static mp_obj_t dict_clear(mp_obj_t self_in) {
     252                 :         12 :     mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     253                 :         12 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     254                 :         12 :     mp_ensure_not_fixed(self);
     255                 :            : 
     256                 :          8 :     mp_map_clear(&self->map);
     257                 :            : 
     258                 :          8 :     return mp_const_none;
     259                 :            : }
     260                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear);
     261                 :            : 
     262                 :         74 : mp_obj_t mp_obj_dict_copy(mp_obj_t self_in) {
     263                 :         74 :     mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     264                 :         74 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     265                 :         74 :     mp_obj_t other_out = mp_obj_new_dict(self->map.alloc);
     266                 :         74 :     mp_obj_dict_t *other = MP_OBJ_TO_PTR(other_out);
     267                 :         74 :     other->base.type = self->base.type;
     268                 :         74 :     other->map.used = self->map.used;
     269                 :         74 :     other->map.all_keys_are_qstrs = self->map.all_keys_are_qstrs;
     270                 :         74 :     other->map.is_fixed = 0;
     271                 :         74 :     other->map.is_ordered = self->map.is_ordered;
     272                 :         74 :     memcpy(other->map.table, self->map.table, self->map.alloc * sizeof(mp_map_elem_t));
     273                 :         74 :     return other_out;
     274                 :            : }
     275                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, mp_obj_dict_copy);
     276                 :            : 
     277                 :            : #if MICROPY_PY_BUILTINS_DICT_FROMKEYS
     278                 :            : // this is a classmethod
     279                 :         12 : static mp_obj_t dict_fromkeys(size_t n_args, const mp_obj_t *args) {
     280                 :         12 :     mp_obj_t iter = mp_getiter(args[1], NULL);
     281                 :         12 :     mp_obj_t value = mp_const_none;
     282                 :         12 :     mp_obj_t next = MP_OBJ_NULL;
     283                 :            : 
     284         [ +  + ]:         12 :     if (n_args > 2) {
     285                 :          4 :         value = args[2];
     286                 :            :     }
     287                 :            : 
     288                 :            :     // optimisation to allocate result based on len of argument
     289                 :         12 :     mp_obj_t self_out;
     290                 :         12 :     mp_obj_t len = mp_obj_len_maybe(args[1]);
     291         [ +  + ]:         12 :     if (len == MP_OBJ_NULL) {
     292                 :            :         /* object's type doesn't have a __len__ slot */
     293                 :          4 :         self_out = mp_obj_new_dict(0);
     294                 :            :     } else {
     295                 :          8 :         self_out = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len));
     296                 :            :     }
     297                 :            : 
     298                 :         12 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_out);
     299         [ +  + ]:         48 :     while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
     300                 :         36 :         mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
     301                 :            :     }
     302                 :            : 
     303                 :         12 :     return self_out;
     304                 :            : }
     305                 :            : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_fun_obj, 2, 3, dict_fromkeys);
     306                 :            : static MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromkeys_fun_obj));
     307                 :            : #endif
     308                 :            : 
     309                 :       1471 : static mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) {
     310                 :       1471 :     mp_check_self(mp_obj_is_dict_or_ordereddict(args[0]));
     311                 :       1471 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
     312         [ +  + ]:       1471 :     if (lookup_kind != MP_MAP_LOOKUP) {
     313                 :       1382 :         mp_ensure_not_fixed(self);
     314                 :            :     }
     315                 :       1459 :     mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind);
     316                 :       1459 :     mp_obj_t value;
     317   [ +  +  +  + ]:       1459 :     if (elem == NULL || elem->value == MP_OBJ_NULL) {
     318         [ +  + ]:         62 :         if (n_args == 2) {
     319         [ +  + ]:         22 :             if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
     320                 :         12 :                 mp_raise_type_arg(&mp_type_KeyError, args[1]);
     321                 :            :             } else {
     322                 :            :                 value = mp_const_none;
     323                 :            :             }
     324                 :            :         } else {
     325                 :         40 :             value = args[2];
     326                 :            :         }
     327         [ +  + ]:         50 :         if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
     328                 :         12 :             elem->value = value;
     329                 :            :         }
     330                 :            :     } else {
     331                 :       1397 :         value = elem->value;
     332         [ +  + ]:       1397 :         if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
     333                 :       1330 :             elem->value = MP_OBJ_NULL; // so that GC can collect the deleted value
     334                 :            :         }
     335                 :            :     }
     336                 :       1447 :     return value;
     337                 :            : }
     338                 :            : 
     339                 :         89 : static mp_obj_t dict_get(size_t n_args, const mp_obj_t *args) {
     340                 :         89 :     return dict_get_helper(n_args, args, MP_MAP_LOOKUP);
     341                 :            : }
     342                 :            : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_get_obj, 2, 3, dict_get);
     343                 :            : 
     344                 :         28 : static mp_obj_t dict_pop(size_t n_args, const mp_obj_t *args) {
     345                 :         28 :     return dict_get_helper(n_args, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND);
     346                 :            : }
     347                 :            : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_pop_obj, 2, 3, dict_pop);
     348                 :            : 
     349                 :         24 : static mp_obj_t dict_setdefault(size_t n_args, const mp_obj_t *args) {
     350                 :         24 :     return dict_get_helper(n_args, args, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
     351                 :            : }
     352                 :            : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault);
     353                 :            : 
     354                 :         32 : static mp_obj_t dict_popitem(mp_obj_t self_in) {
     355                 :         32 :     mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     356                 :         32 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     357                 :         32 :     mp_ensure_not_fixed(self);
     358         [ +  + ]:         28 :     if (self->map.used == 0) {
     359                 :          4 :         mp_raise_msg(&mp_type_KeyError, MP_ERROR_TEXT("popitem(): dictionary is empty"));
     360                 :            :     }
     361                 :         24 :     size_t cur = 0;
     362                 :            :     #if MICROPY_PY_COLLECTIONS_ORDEREDDICT
     363         [ +  + ]:         24 :     if (self->map.is_ordered) {
     364                 :         16 :         cur = self->map.used - 1;
     365                 :            :     }
     366                 :            :     #endif
     367                 :         24 :     mp_map_elem_t *next = dict_iter_next(self, &cur);
     368         [ -  + ]:         24 :     assert(next);
     369                 :         24 :     self->map.used--;
     370                 :         24 :     mp_obj_t items[] = {next->key, next->value};
     371                 :         24 :     next->key = MP_OBJ_SENTINEL; // must mark key as sentinel to indicate that it was deleted
     372                 :         24 :     next->value = MP_OBJ_NULL;
     373                 :         24 :     mp_obj_t tuple = mp_obj_new_tuple(2, items);
     374                 :            : 
     375                 :         24 :     return tuple;
     376                 :            : }
     377                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
     378                 :            : 
     379                 :        122 : static mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
     380                 :        122 :     mp_check_self(mp_obj_is_dict_or_ordereddict(args[0]));
     381                 :        122 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
     382                 :        122 :     mp_ensure_not_fixed(self);
     383                 :            : 
     384                 :        118 :     mp_arg_check_num(n_args, kwargs->used, 1, 2, true);
     385                 :            : 
     386         [ +  + ]:        118 :     if (n_args == 2) {
     387                 :            :         // given a positional argument
     388                 :            : 
     389         [ +  + ]:        106 :         if (mp_obj_is_dict_or_ordereddict(args[1])) {
     390                 :            :             // update from other dictionary (make sure other is not self)
     391         [ +  + ]:         68 :             if (args[1] != args[0]) {
     392                 :         56 :                 size_t cur = 0;
     393                 :         56 :                 mp_map_elem_t *elem = NULL;
     394         [ +  + ]:        124 :                 while ((elem = dict_iter_next((mp_obj_dict_t *)MP_OBJ_TO_PTR(args[1]), &cur)) != NULL) {
     395                 :         68 :                     mp_map_lookup(&self->map, elem->key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = elem->value;
     396                 :            :                 }
     397                 :            :             }
     398                 :            :         } else {
     399                 :            :             // update from a generic iterable of pairs
     400                 :         38 :             mp_obj_t iter = mp_getiter(args[1], NULL);
     401                 :         38 :             mp_obj_t next = MP_OBJ_NULL;
     402         [ +  + ]:         82 :             while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
     403                 :         52 :                 mp_obj_t inneriter = mp_getiter(next, NULL);
     404                 :         52 :                 mp_obj_t key = mp_iternext(inneriter);
     405                 :         52 :                 mp_obj_t value = mp_iternext(inneriter);
     406                 :         52 :                 mp_obj_t stop = mp_iternext(inneriter);
     407                 :         52 :                 if (key == MP_OBJ_STOP_ITERATION
     408         [ +  + ]:         52 :                     || value == MP_OBJ_STOP_ITERATION
     409         [ +  + ]:         48 :                     || stop != MP_OBJ_STOP_ITERATION) {
     410                 :          8 :                     mp_raise_ValueError(MP_ERROR_TEXT("dict update sequence has wrong length"));
     411                 :            :                 } else {
     412                 :         44 :                     mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
     413                 :            :                 }
     414                 :            :             }
     415                 :            :         }
     416                 :            :     }
     417                 :            : 
     418                 :            :     // update the dict with any keyword args
     419         [ +  + ]:        154 :     for (size_t i = 0; i < kwargs->alloc; i++) {
     420         [ +  - ]:         44 :         if (mp_map_slot_is_filled(kwargs, i)) {
     421                 :         44 :             mp_map_lookup(&self->map, kwargs->table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = kwargs->table[i].value;
     422                 :            :         }
     423                 :            :     }
     424                 :            : 
     425                 :        110 :     return mp_const_none;
     426                 :            : }
     427                 :            : static MP_DEFINE_CONST_FUN_OBJ_KW(dict_update_obj, 1, dict_update);
     428                 :            : 
     429                 :            : 
     430                 :            : /******************************************************************************/
     431                 :            : /* dict views                                                                 */
     432                 :            : 
     433                 :            : static const mp_obj_type_t mp_type_dict_view;
     434                 :            : static const mp_obj_type_t mp_type_dict_view_it;
     435                 :            : 
     436                 :            : typedef enum _mp_dict_view_kind_t {
     437                 :            :     MP_DICT_VIEW_ITEMS,
     438                 :            :     MP_DICT_VIEW_KEYS,
     439                 :            :     MP_DICT_VIEW_VALUES,
     440                 :            : } mp_dict_view_kind_t;
     441                 :            : 
     442                 :            : static const char *const mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"};
     443                 :            : 
     444                 :            : typedef struct _mp_obj_dict_view_it_t {
     445                 :            :     mp_obj_base_t base;
     446                 :            :     mp_dict_view_kind_t kind;
     447                 :            :     mp_obj_t dict;
     448                 :            :     size_t cur;
     449                 :            : } mp_obj_dict_view_it_t;
     450                 :            : 
     451                 :            : typedef struct _mp_obj_dict_view_t {
     452                 :            :     mp_obj_base_t base;
     453                 :            :     mp_obj_t dict;
     454                 :            :     mp_dict_view_kind_t kind;
     455                 :            : } mp_obj_dict_view_t;
     456                 :            : 
     457                 :        582 : static mp_obj_t dict_view_it_iternext(mp_obj_t self_in) {
     458                 :        582 :     mp_check_self(mp_obj_is_type(self_in, &mp_type_dict_view_it));
     459                 :        582 :     mp_obj_dict_view_it_t *self = MP_OBJ_TO_PTR(self_in);
     460                 :        582 :     mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur);
     461                 :            : 
     462         [ +  + ]:        582 :     if (next == NULL) {
     463                 :            :         return MP_OBJ_STOP_ITERATION;
     464                 :            :     } else {
     465      [ +  +  + ]:        390 :         switch (self->kind) {
     466                 :        124 :             case MP_DICT_VIEW_ITEMS:
     467                 :            :             default: {
     468                 :        124 :                 mp_obj_t items[] = {next->key, next->value};
     469                 :        124 :                 return mp_obj_new_tuple(2, items);
     470                 :            :             }
     471                 :        162 :             case MP_DICT_VIEW_KEYS:
     472                 :        162 :                 return next->key;
     473                 :        104 :             case MP_DICT_VIEW_VALUES:
     474                 :        104 :                 return next->value;
     475                 :            :         }
     476                 :            :     }
     477                 :            : }
     478                 :            : 
     479                 :            : static MP_DEFINE_CONST_OBJ_TYPE(
     480                 :            :     mp_type_dict_view_it,
     481                 :            :     MP_QSTR_iterator,
     482                 :            :     MP_TYPE_FLAG_ITER_IS_ITERNEXT,
     483                 :            :     iter, dict_view_it_iternext
     484                 :            :     );
     485                 :            : 
     486                 :        180 : static mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) {
     487                 :        180 :     assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t));
     488                 :        180 :     mp_check_self(mp_obj_is_type(view_in, &mp_type_dict_view));
     489                 :        180 :     mp_obj_dict_view_t *view = MP_OBJ_TO_PTR(view_in);
     490                 :        180 :     mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf;
     491                 :        180 :     o->base.type = &mp_type_dict_view_it;
     492                 :        180 :     o->kind = view->kind;
     493                 :        180 :     o->dict = view->dict;
     494                 :        180 :     o->cur = 0;
     495                 :        180 :     return MP_OBJ_FROM_PTR(o);
     496                 :            : }
     497                 :            : 
     498                 :         32 : static void dict_view_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     499                 :         32 :     (void)kind;
     500                 :         32 :     mp_check_self(mp_obj_is_type(self_in, &mp_type_dict_view));
     501                 :         32 :     mp_obj_dict_view_t *self = MP_OBJ_TO_PTR(self_in);
     502                 :         32 :     bool first = true;
     503                 :         32 :     mp_print_str(print, mp_dict_view_names[self->kind]);
     504                 :         32 :     mp_print_str(print, "([");
     505                 :         32 :     mp_obj_iter_buf_t iter_buf;
     506                 :         32 :     mp_obj_t self_iter = dict_view_getiter(self_in, &iter_buf);
     507                 :         32 :     mp_obj_t next = MP_OBJ_NULL;
     508         [ +  + ]:         68 :     while ((next = dict_view_it_iternext(self_iter)) != MP_OBJ_STOP_ITERATION) {
     509         [ +  + ]:         36 :         if (!first) {
     510                 :          4 :             mp_print_str(print, ", ");
     511                 :            :         }
     512                 :         36 :         first = false;
     513                 :         36 :         mp_obj_print_helper(print, next, PRINT_REPR);
     514                 :            :     }
     515                 :         32 :     mp_print_str(print, "])");
     516                 :         32 : }
     517                 :            : 
     518                 :         12 : static mp_obj_t dict_view_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
     519                 :         12 :     mp_obj_dict_view_t *o = MP_OBJ_TO_PTR(o_in);
     520                 :            :     // only dict.values() supports __hash__.
     521   [ +  -  +  + ]:         12 :     if (op == MP_UNARY_OP_HASH && o->kind == MP_DICT_VIEW_VALUES) {
     522                 :          4 :         return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in);
     523                 :            :     }
     524                 :            :     return MP_OBJ_NULL;
     525                 :            : }
     526                 :            : 
     527                 :         24 : static mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
     528                 :            :     // only supported for the 'keys' kind until sets and dicts are refactored
     529                 :         24 :     mp_obj_dict_view_t *o = MP_OBJ_TO_PTR(lhs_in);
     530         [ +  + ]:         24 :     if (o->kind != MP_DICT_VIEW_KEYS) {
     531                 :            :         return MP_OBJ_NULL; // op not supported
     532                 :            :     }
     533         [ +  + ]:         20 :     if (op != MP_BINARY_OP_CONTAINS) {
     534                 :            :         return MP_OBJ_NULL; // op not supported
     535                 :            :     }
     536                 :         16 :     return dict_binary_op(op, o->dict, rhs_in);
     537                 :            : }
     538                 :            : 
     539                 :            : static MP_DEFINE_CONST_OBJ_TYPE(
     540                 :            :     mp_type_dict_view,
     541                 :            :     MP_QSTR_dict_view,
     542                 :            :     MP_TYPE_FLAG_ITER_IS_GETITER,
     543                 :            :     print, dict_view_print,
     544                 :            :     unary_op, dict_view_unary_op,
     545                 :            :     binary_op, dict_view_binary_op,
     546                 :            :     iter, dict_view_getiter
     547                 :            :     );
     548                 :            : 
     549                 :        196 : static mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) {
     550                 :        196 :     mp_obj_dict_view_t *o = mp_obj_malloc(mp_obj_dict_view_t, &mp_type_dict_view);
     551                 :        192 :     o->dict = dict;
     552                 :        192 :     o->kind = kind;
     553                 :        192 :     return MP_OBJ_FROM_PTR(o);
     554                 :            : }
     555                 :            : 
     556                 :        196 : static mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) {
     557                 :        196 :     mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     558                 :        196 :     return mp_obj_new_dict_view(self_in, kind);
     559                 :            : }
     560                 :            : 
     561                 :         82 : static mp_obj_t dict_items(mp_obj_t self_in) {
     562                 :         82 :     return dict_view(self_in, MP_DICT_VIEW_ITEMS);
     563                 :            : }
     564                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(dict_items_obj, dict_items);
     565                 :            : 
     566                 :         62 : static mp_obj_t dict_keys(mp_obj_t self_in) {
     567                 :         62 :     return dict_view(self_in, MP_DICT_VIEW_KEYS);
     568                 :            : }
     569                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(dict_keys_obj, dict_keys);
     570                 :            : 
     571                 :         52 : static mp_obj_t dict_values(mp_obj_t self_in) {
     572                 :         52 :     return dict_view(self_in, MP_DICT_VIEW_VALUES);
     573                 :            : }
     574                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values);
     575                 :            : 
     576                 :            : /******************************************************************************/
     577                 :            : /* dict iterator                                                              */
     578                 :            : 
     579                 :         12 : static mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
     580                 :         12 :     assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t));
     581                 :         12 :     mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     582                 :         12 :     mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf;
     583                 :         12 :     o->base.type = &mp_type_dict_view_it;
     584                 :         12 :     o->kind = MP_DICT_VIEW_KEYS;
     585                 :         12 :     o->dict = self_in;
     586                 :         12 :     o->cur = 0;
     587                 :         12 :     return MP_OBJ_FROM_PTR(o);
     588                 :            : }
     589                 :            : 
     590                 :            : /******************************************************************************/
     591                 :            : /* dict constructors & public C API                                           */
     592                 :            : 
     593                 :            : static const mp_rom_map_elem_t dict_locals_dict_table[] = {
     594                 :            :     { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&dict_clear_obj) },
     595                 :            :     { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&dict_copy_obj) },
     596                 :            :     #if MICROPY_PY_BUILTINS_DICT_FROMKEYS
     597                 :            :     { MP_ROM_QSTR(MP_QSTR_fromkeys), MP_ROM_PTR(&dict_fromkeys_obj) },
     598                 :            :     #endif
     599                 :            :     { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&dict_get_obj) },
     600                 :            :     { MP_ROM_QSTR(MP_QSTR_items), MP_ROM_PTR(&dict_items_obj) },
     601                 :            :     { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&dict_keys_obj) },
     602                 :            :     { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&dict_pop_obj) },
     603                 :            :     { MP_ROM_QSTR(MP_QSTR_popitem), MP_ROM_PTR(&dict_popitem_obj) },
     604                 :            :     { MP_ROM_QSTR(MP_QSTR_setdefault), MP_ROM_PTR(&dict_setdefault_obj) },
     605                 :            :     { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&dict_update_obj) },
     606                 :            :     { MP_ROM_QSTR(MP_QSTR_values), MP_ROM_PTR(&dict_values_obj) },
     607                 :            :     { MP_ROM_QSTR(MP_QSTR___getitem__), MP_ROM_PTR(&mp_op_getitem_obj) },
     608                 :            :     { MP_ROM_QSTR(MP_QSTR___setitem__), MP_ROM_PTR(&mp_op_setitem_obj) },
     609                 :            :     { MP_ROM_QSTR(MP_QSTR___delitem__), MP_ROM_PTR(&mp_op_delitem_obj) },
     610                 :            : };
     611                 :            : 
     612                 :            : static MP_DEFINE_CONST_DICT(dict_locals_dict, dict_locals_dict_table);
     613                 :            : 
     614                 :            : MP_DEFINE_CONST_OBJ_TYPE(
     615                 :            :     mp_type_dict,
     616                 :            :     MP_QSTR_dict,
     617                 :            :     MP_TYPE_FLAG_ITER_IS_GETITER,
     618                 :            :     make_new, mp_obj_dict_make_new,
     619                 :            :     print, dict_print,
     620                 :            :     unary_op, dict_unary_op,
     621                 :            :     binary_op, dict_binary_op,
     622                 :            :     subscr, dict_subscr,
     623                 :            :     iter, dict_getiter,
     624                 :            :     locals_dict, &dict_locals_dict
     625                 :            :     );
     626                 :            : 
     627                 :            : #if MICROPY_PY_COLLECTIONS_ORDEREDDICT
     628                 :            : MP_DEFINE_CONST_OBJ_TYPE(
     629                 :            :     mp_type_ordereddict,
     630                 :            :     MP_QSTR_OrderedDict,
     631                 :            :     MP_TYPE_FLAG_ITER_IS_GETITER,
     632                 :            :     make_new, mp_obj_dict_make_new,
     633                 :            :     print, dict_print,
     634                 :            :     unary_op, dict_unary_op,
     635                 :            :     binary_op, dict_binary_op,
     636                 :            :     subscr, dict_subscr,
     637                 :            :     iter, dict_getiter,
     638                 :            :     parent, &mp_type_dict,
     639                 :            :     locals_dict, &dict_locals_dict
     640                 :            :     );
     641                 :            : #endif
     642                 :            : 
     643                 :      12279 : void mp_obj_dict_init(mp_obj_dict_t *dict, size_t n_args) {
     644                 :      12279 :     dict->base.type = &mp_type_dict;
     645                 :      12279 :     mp_map_init(&dict->map, n_args);
     646                 :      12279 : }
     647                 :            : 
     648                 :       5659 : mp_obj_t mp_obj_new_dict(size_t n_args) {
     649                 :       5659 :     mp_obj_dict_t *o = m_new_obj(mp_obj_dict_t);
     650                 :       5655 :     mp_obj_dict_init(o, n_args);
     651                 :       5655 :     return MP_OBJ_FROM_PTR(o);
     652                 :            : }
     653                 :            : 
     654                 :        356 : size_t mp_obj_dict_len(mp_obj_t self_in) {
     655                 :        356 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     656                 :        356 :     return self->map.used;
     657                 :            : }
     658                 :            : 
     659                 :     892105 : mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
     660                 :     892105 :     mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     661                 :     892105 :     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     662                 :     892105 :     mp_ensure_not_fixed(self);
     663                 :     892101 :     mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
     664                 :     892089 :     return self_in;
     665                 :            : }
     666                 :            : 
     667                 :       1330 : mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key) {
     668                 :       1330 :     mp_obj_t args[2] = {self_in, key};
     669                 :       1330 :     dict_get_helper(2, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND);
     670                 :       1318 :     return self_in;
     671                 :            : }

Generated by: LCOV version 1.15-5-g462f71d