From 9ec3a871892efe70f17957f87b7967e99209ce9a Mon Sep 17 00:00:00 2001 From: "John R. Lenton" Date: Fri, 10 Jan 2014 01:00:20 +0000 Subject: [PATCH] dict views now, refactoring later. --- py/objdict.c | 133 +++++++++++++++++++++++++++++++ tests/basics/tests/dict_views.py | 6 ++ 2 files changed, 139 insertions(+) create mode 100644 tests/basics/tests/dict_views.py diff --git a/py/objdict.c b/py/objdict.c index 1c90998585..6acee3fa78 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -246,6 +246,136 @@ static mp_obj_t dict_update(mp_obj_t self_in, mp_obj_t iterable) { static MP_DEFINE_CONST_FUN_OBJ_2(dict_update_obj, dict_update); +/******************************************************************************/ +/* dict views */ + +static const mp_obj_type_t dict_view_type; +static const mp_obj_type_t dict_view_it_type; + +typedef enum _mp_dict_view_kind_t { + MP_DICT_VIEW_ITEMS, + MP_DICT_VIEW_KEYS, + MP_DICT_VIEW_VALUES, +} mp_dict_view_kind_t; + +static char *mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"}; + +typedef struct _mp_obj_dict_view_it_t { + mp_obj_base_t base; + mp_dict_view_kind_t kind; + mp_obj_dict_it_t *iter; + machine_uint_t cur; +} mp_obj_dict_view_it_t; + +typedef struct _mp_obj_dict_view_t { + mp_obj_base_t base; + mp_obj_dict_t *dict; + mp_dict_view_kind_t kind; +} mp_obj_dict_view_t; + +static mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &dict_view_it_type)); + mp_obj_dict_view_it_t *self = self_in; + mp_map_elem_t *next = dict_it_iternext_elem(self->iter); + + if (next != NULL) { + switch (self->kind) { + case MP_DICT_VIEW_ITEMS: + { + mp_obj_t items[] = {next->key, next->value}; + return mp_obj_new_tuple(2, items); + } + case MP_DICT_VIEW_KEYS: + { + return next->key; + } + case MP_DICT_VIEW_VALUES: + { + return next->value; + } + default: + { + assert(0); /* can't happen */ + } + } + } else { + return mp_const_stop_iteration; + } +} + +static const mp_obj_type_t dict_view_it_type = { + { &mp_const_type }, + "dict_view_iterator", + .iternext = dict_view_it_iternext, + .methods = NULL, /* set operations still to come */ +}; + +static mp_obj_t dict_view_getiter(mp_obj_t view_in) { + assert(MP_OBJ_IS_TYPE(view_in, &dict_view_type)); + mp_obj_dict_view_t *view = view_in; + mp_obj_dict_view_it_t *o = m_new_obj(mp_obj_dict_view_it_t); + o->base.type = &dict_view_it_type; + o->kind = view->kind; + o->iter = mp_obj_new_dict_iterator(view->dict, 0); + return o; +} + + +static void dict_view_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &dict_view_type)); + mp_obj_dict_view_t *self = self_in; + bool first = true; + print(env, mp_dict_view_names[self->kind]); + print(env, "(["); + mp_obj_t *self_iter = dict_view_getiter(self); + mp_obj_t *next = NULL; + while ((next = dict_view_it_iternext(self_iter)) != mp_const_stop_iteration) { + if (!first) { + print(env, ", "); + } + first = false; + mp_obj_print_helper(print, env, next); + } + print(env, "])"); +} + +static const mp_obj_type_t dict_view_type = { + { &mp_const_type }, + "dict_view", + .print = dict_view_print, + .getiter = dict_view_getiter, +}; + +mp_obj_t mp_obj_new_dict_view(mp_obj_dict_t *dict, mp_dict_view_kind_t kind) { + mp_obj_dict_view_t *o = m_new_obj(mp_obj_dict_view_t); + o->base.type = &dict_view_type; + o->dict = dict; + o->kind = kind; + return o; +} + + +static mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) { + assert(MP_OBJ_IS_TYPE(self_in, &dict_type)); + mp_obj_dict_t *self = self_in; + return mp_obj_new_dict_view(self, kind); +} + +static mp_obj_t dict_items(mp_obj_t self_in) { + return dict_view(self_in, MP_DICT_VIEW_ITEMS); +} +static MP_DEFINE_CONST_FUN_OBJ_1(dict_items_obj, dict_items); + +static mp_obj_t dict_keys(mp_obj_t self_in) { + return dict_view(self_in, MP_DICT_VIEW_KEYS); +} +static MP_DEFINE_CONST_FUN_OBJ_1(dict_keys_obj, dict_keys); + +static mp_obj_t dict_values(mp_obj_t self_in) { + return dict_view(self_in, MP_DICT_VIEW_VALUES); +} +static MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values); + /******************************************************************************/ /* dict constructors & etc */ @@ -253,10 +383,13 @@ static const mp_method_t dict_type_methods[] = { { "clear", &dict_clear_obj }, { "copy", &dict_copy_obj }, { "get", &dict_get_obj }, + { "items", &dict_items_obj }, + { "keys", &dict_keys_obj }, { "pop", &dict_pop_obj }, { "popitem", &dict_popitem_obj }, { "setdefault", &dict_setdefault_obj }, { "update", &dict_update_obj }, + { "values", &dict_values_obj }, { NULL, NULL }, // end-of-list sentinel }; diff --git a/tests/basics/tests/dict_views.py b/tests/basics/tests/dict_views.py new file mode 100644 index 0000000000..fbf63fa0ac --- /dev/null +++ b/tests/basics/tests/dict_views.py @@ -0,0 +1,6 @@ +d = {1: 2} +for m in d.items, d.values, d.keys: + print(m()) + print(list(m())) + +# set operations still to come