Skip to content

Commit 46db036

Browse files
committed
OrderedDict.move_to_end: alternate implementation of adafruit#8234
this implementation is hoped to be smaller. (feather_m4_express/fr fits unlike the other PR; approximate savings ~600 bytes) Minor difference to standard Python: A `dict` object has a `move_to_end` method. However, calling this method always results in TypeError. Implementing it this way means that the method table can still be shared between OrderedDict and builtin dict. Closes adafruit#4408.
1 parent 394ed2a commit 46db036

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

py/objdict.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,53 @@ STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwarg
421421
}
422422
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dict_update_obj, 1, dict_update);
423423

424+
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
425+
STATIC mp_obj_t dict_move_to_end(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
426+
mp_obj_dict_t *self = MP_OBJ_TO_PTR(pos_args[0]);
427+
mp_arg_validate_type(self, &mp_type_ordereddict, MP_QSTR_self);
428+
429+
// parse args
430+
enum { ARG_key, ARG_last };
431+
static const mp_arg_t allowed_args[] = {
432+
{ MP_QSTR_key, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
433+
{ MP_QSTR_last, MP_ARG_BOOL, {.u_bool = true } }
434+
};
435+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
436+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
437+
438+
mp_obj_t *key = args[ARG_key].u_obj;
439+
bool last = args[ARG_last].u_bool;
440+
441+
mp_map_elem_t *elem = mp_map_lookup(&self->map, key, MP_MAP_LOOKUP);
442+
if (!elem) {
443+
mp_raise_type_arg(&mp_type_KeyError, key);
444+
}
445+
446+
mp_map_elem_t tmp = *elem;
447+
mp_map_elem_t *table = self->map.table;
448+
mp_map_elem_t *dest, *move_begin, *move_dest;
449+
size_t move_count;
450+
451+
if (last) {
452+
mp_map_elem_t *top = &table[self->map.used];
453+
dest = top - 1;
454+
move_begin = elem + 1;
455+
move_dest = elem;
456+
move_count = top - move_begin;
457+
} else {
458+
dest = &table[0];
459+
move_begin = table;
460+
move_dest = table + 1;
461+
move_count = elem - table;
462+
}
463+
memmove(move_dest, move_begin, move_count * sizeof(*elem));
464+
*dest = tmp;
465+
466+
return mp_const_none;
467+
}
468+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dict_move_to_end_obj, 1, dict_move_to_end);
469+
#endif
470+
424471

425472
/******************************************************************************/
426473
/* dict views */
@@ -590,6 +637,9 @@ STATIC const mp_rom_map_elem_t dict_locals_dict_table[] = {
590637
{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&dict_get_obj) },
591638
{ MP_ROM_QSTR(MP_QSTR_items), MP_ROM_PTR(&dict_items_obj) },
592639
{ MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&dict_keys_obj) },
640+
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
641+
{ MP_ROM_QSTR(MP_QSTR_move_to_end), MP_ROM_PTR(&dict_move_to_end_obj) },
642+
#endif
593643
{ MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&dict_pop_obj) },
594644
{ MP_ROM_QSTR(MP_QSTR_popitem), MP_ROM_PTR(&dict_popitem_obj) },
595645
{ MP_ROM_QSTR(MP_QSTR_setdefault), MP_ROM_PTR(&dict_setdefault_obj) },

tests/basics/ordereddict2.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
try:
2+
from collections import OrderedDict
3+
except ImportError:
4+
print("SKIP")
5+
raise SystemExit
6+
7+
try:
8+
{'a': None}.move_to_end('a')
9+
except (TypeError, AttributeError):
10+
print("Exception")
11+
12+
d = OrderedDict(a=1, b=2, c=3)
13+
d.move_to_end('a')
14+
print(list(d.items()))
15+
16+
d = OrderedDict(a=1, b=2, c=3)
17+
d.move_to_end('b')
18+
print(list(d.items()))
19+
20+
d = OrderedDict(a=1, b=2, c=3)
21+
d.move_to_end('c')
22+
print(list(d.items()))
23+
24+
try:
25+
d.move_to_end('x')
26+
except KeyError:
27+
print("KeyError")
28+
29+
d = OrderedDict(a=1, b=2, c=3)
30+
d.move_to_end('a', last=False)
31+
print(list(d.items()))
32+
33+
d = OrderedDict(a=1, b=2, c=3)
34+
d.move_to_end('b', last=False)
35+
print(list(d.items()))
36+
37+
d = OrderedDict(a=1, b=2, c=3)
38+
d.move_to_end('c', last=False)
39+
print(list(d.items()))
40+
41+
try:
42+
d.move_to_end('x', last=False)
43+
except KeyError:
44+
print("KeyError")

0 commit comments

Comments
 (0)