4040
4141STATIC mp_obj_t mp_obj_new_dict_iterator (mp_obj_dict_t * dict , int cur );
4242STATIC mp_map_elem_t * dict_it_iternext_elem (mp_obj_t self_in );
43- STATIC mp_obj_t dict_copy ( mp_obj_t self_in );
43+ STATIC mp_obj_t dict_update ( uint n_args , const mp_obj_t * args , mp_map_t * kwargs );
4444
4545STATIC void dict_print (void (* print )(void * env , const char * fmt , ...), void * env , mp_obj_t self_in , mp_print_kind_t kind ) {
4646 mp_obj_dict_t * self = self_in ;
@@ -61,40 +61,13 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
6161}
6262
6363STATIC mp_obj_t dict_make_new (mp_obj_t type_in , uint n_args , uint n_kw , const mp_obj_t * args ) {
64- mp_obj_t dict ;
65- switch (n_args ) {
66- case 0 :
67- dict = mp_obj_new_dict (0 );
68- break ;
69-
70- case 1 : {
71- if (MP_OBJ_IS_TYPE (args [0 ], & mp_type_dict )) {
72- return dict_copy (args [0 ]);
73- }
74- // TODO create dict from an arbitrary mapping!
75-
76- // Make dict from iterable of pairs
77- mp_obj_t iterable = mp_getiter (args [0 ]);
78- mp_obj_t dict = mp_obj_new_dict (0 );
79- // TODO: support arbitrary seq as a pair
80- mp_obj_t item ;
81- while ((item = mp_iternext (iterable )) != MP_OBJ_STOP_ITERATION ) {
82- mp_obj_t * sub_items ;
83- mp_obj_get_array_fixed_n (item , 2 , & sub_items );
84- mp_obj_dict_store (dict , sub_items [0 ], sub_items [1 ]);
85- }
86- return dict ;
87- }
88-
89- default :
90- nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_TypeError , "dict takes at most 1 argument" ));
91- }
92-
93- // add to the new dict any keyword args
94- for (const mp_obj_t * a = args + n_args ; n_kw > 0 ; n_kw -- , a += 2 ) {
95- mp_obj_dict_store (dict , a [0 ], a [1 ]);
64+ mp_obj_t dict = mp_obj_new_dict (0 );
65+ if (n_args > 0 || n_kw > 0 ) {
66+ mp_obj_t args2 [2 ] = {dict , args [0 ]}; // args[0] is always valid, even if it's not a positional arg
67+ mp_map_t kwargs ;
68+ mp_map_init_fixed_table (& kwargs , n_kw , args + n_args );
69+ dict_update (n_args + 1 , args2 , & kwargs ); // dict_update will check that n_args + 1 == 1 or 2
9670 }
97-
9871 return dict ;
9972}
10073
@@ -348,31 +321,57 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
348321}
349322STATIC MP_DEFINE_CONST_FUN_OBJ_1 (dict_popitem_obj , dict_popitem );
350323
351- STATIC mp_obj_t dict_update (mp_obj_t self_in , mp_obj_t iterable ) {
352- assert (MP_OBJ_IS_TYPE (self_in , & mp_type_dict ));
353- mp_obj_dict_t * self = self_in ;
354- /* TODO: check for the "keys" method */
355- mp_obj_t iter = mp_getiter (iterable );
356- mp_obj_t next = NULL ;
357- while ((next = mp_iternext (iter )) != MP_OBJ_STOP_ITERATION ) {
358- mp_obj_t inneriter = mp_getiter (next );
359- mp_obj_t key = mp_iternext (inneriter );
360- mp_obj_t value = mp_iternext (inneriter );
361- mp_obj_t stop = mp_iternext (inneriter );
362- if (key == MP_OBJ_STOP_ITERATION
363- || value == MP_OBJ_STOP_ITERATION
364- || stop != MP_OBJ_STOP_ITERATION ) {
365- nlr_raise (mp_obj_new_exception_msg (
366- & mp_type_ValueError ,
367- "dictionary update sequence has the wrong length" ));
324+ STATIC mp_obj_t dict_update (uint n_args , const mp_obj_t * args , mp_map_t * kwargs ) {
325+ assert (MP_OBJ_IS_TYPE (args [0 ], & mp_type_dict ));
326+ mp_obj_dict_t * self = args [0 ];
327+
328+ mp_arg_check_num (n_args , kwargs -> used , 1 , 2 , true);
329+
330+ if (n_args == 2 ) {
331+ // given a positional argument
332+
333+ if (MP_OBJ_IS_TYPE (args [1 ], & mp_type_dict )) {
334+ // update from other dictionary (make sure other is not self)
335+ if (args [1 ] != self ) {
336+ // TODO don't allocate heap object for this iterator
337+ mp_obj_t * dict_iter = mp_obj_new_dict_iterator (args [1 ], 0 );
338+ mp_map_elem_t * elem = NULL ;
339+ while ((elem = dict_it_iternext_elem (dict_iter )) != MP_OBJ_STOP_ITERATION ) {
340+ mp_map_lookup (& self -> map , elem -> key , MP_MAP_LOOKUP_ADD_IF_NOT_FOUND )-> value = elem -> value ;
341+ }
342+ }
368343 } else {
369- mp_map_lookup (& self -> map , key , MP_MAP_LOOKUP_ADD_IF_NOT_FOUND )-> value = value ;
344+ // update from a generic iterable of pairs
345+ mp_obj_t iter = mp_getiter (args [1 ]);
346+ mp_obj_t next = NULL ;
347+ while ((next = mp_iternext (iter )) != MP_OBJ_STOP_ITERATION ) {
348+ mp_obj_t inneriter = mp_getiter (next );
349+ mp_obj_t key = mp_iternext (inneriter );
350+ mp_obj_t value = mp_iternext (inneriter );
351+ mp_obj_t stop = mp_iternext (inneriter );
352+ if (key == MP_OBJ_STOP_ITERATION
353+ || value == MP_OBJ_STOP_ITERATION
354+ || stop != MP_OBJ_STOP_ITERATION ) {
355+ nlr_raise (mp_obj_new_exception_msg (
356+ & mp_type_ValueError ,
357+ "dictionary update sequence has the wrong length" ));
358+ } else {
359+ mp_map_lookup (& self -> map , key , MP_MAP_LOOKUP_ADD_IF_NOT_FOUND )-> value = value ;
360+ }
361+ }
362+ }
363+ }
364+
365+ // update the dict with any keyword args
366+ for (machine_uint_t i = 0 ; i < kwargs -> alloc ; i ++ ) {
367+ if (MP_MAP_SLOT_IS_FILLED (kwargs , i )) {
368+ mp_map_lookup (& self -> map , kwargs -> table [i ].key , MP_MAP_LOOKUP_ADD_IF_NOT_FOUND )-> value = kwargs -> table [i ].value ;
370369 }
371370 }
372371
373372 return mp_const_none ;
374373}
375- STATIC MP_DEFINE_CONST_FUN_OBJ_2 (dict_update_obj , dict_update );
374+ STATIC MP_DEFINE_CONST_FUN_OBJ_KW (dict_update_obj , 1 , dict_update );
376375
377376
378377/******************************************************************************/
0 commit comments