blob: 3f1b2087f30f1b12e6e53be18bdece7ec596a2e8 [file] [log] [blame]
Damiend99b0522013-12-21 18:17:45 +00001#include <stdlib.h>
2#include <stdint.h>
3#include <string.h>
4#include <assert.h>
5
6#include "nlr.h"
7#include "misc.h"
8#include "mpconfig.h"
Damien George55baff42014-01-21 21:40:13 +00009#include "qstr.h"
Damiend99b0522013-12-21 18:17:45 +000010#include "obj.h"
11#include "runtime0.h"
12#include "runtime.h"
13#include "map.h"
14
15typedef struct _mp_obj_dict_t {
16 mp_obj_base_t base;
17 mp_map_t map;
18} mp_obj_dict_t;
19
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020020STATIC mp_obj_t mp_obj_new_dict_iterator(mp_obj_dict_t *dict, int cur);
21STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in);
John R. Lentona41fe312014-01-06 17:17:02 +000022
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020023STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
Damiend99b0522013-12-21 18:17:45 +000024 mp_obj_dict_t *self = self_in;
25 bool first = true;
26 print(env, "{");
John R. Lentona41fe312014-01-06 17:17:02 +000027 mp_obj_t *dict_iter = mp_obj_new_dict_iterator(self, 0);
28 mp_map_elem_t *next = NULL;
29 while ((next = dict_it_iternext_elem(dict_iter)) != NULL) {
30 if (!first) {
31 print(env, ", ");
Damiend99b0522013-12-21 18:17:45 +000032 }
John R. Lentona41fe312014-01-06 17:17:02 +000033 first = false;
Paul Sokolovsky76d982e2014-01-13 19:19:16 +020034 mp_obj_print_helper(print, env, next->key, PRINT_REPR);
John R. Lentona41fe312014-01-06 17:17:02 +000035 print(env, ": ");
Paul Sokolovsky76d982e2014-01-13 19:19:16 +020036 mp_obj_print_helper(print, env, next->value, PRINT_REPR);
Damiend99b0522013-12-21 18:17:45 +000037 }
38 print(env, "}");
39}
40
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020041STATIC mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damien George71c51812014-01-04 20:21:15 +000042 // TODO create from an iterable!
43 return rt_build_map(0);
44}
45
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020046STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
Damien George4e8dc8c2014-01-27 23:15:32 +000047 mp_obj_dict_t *self = self_in;
48 switch (op) {
Paul Sokolovskyc1d9bbc2014-01-30 04:37:19 +020049 case RT_UNARY_OP_BOOL: return MP_BOOL(self->map.used != 0);
Damien George09a0c642014-01-30 10:05:33 +000050 case RT_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->map.used);
Damien George4e8dc8c2014-01-27 23:15:32 +000051 default: return MP_OBJ_NULL; // op not supported for None
52 }
53}
54
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020055STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
Damiend99b0522013-12-21 18:17:45 +000056 mp_obj_dict_t *o = lhs_in;
57 switch (op) {
58 case RT_BINARY_OP_SUBSCR:
59 {
60 // dict load
Damien George38a2da62014-01-08 17:33:12 +000061 mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP);
Damiend99b0522013-12-21 18:17:45 +000062 if (elem == NULL) {
Damien Georgeeb7bfcb2014-01-04 15:57:35 +000063 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "<value>"));
Damiend99b0522013-12-21 18:17:45 +000064 } else {
65 return elem->value;
66 }
67 }
Damien George9aa2a522014-02-01 23:04:09 +000068 case RT_BINARY_OP_IN:
John R. Lentonc1bef212014-01-11 12:39:33 +000069 {
70 mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP);
Damien George9aa2a522014-02-01 23:04:09 +000071 return MP_BOOL(elem != NULL);
John R. Lentonc1bef212014-01-11 12:39:33 +000072 }
Damiend99b0522013-12-21 18:17:45 +000073 default:
74 // op not supported
75 return NULL;
76 }
77}
78
John R. Lentona41fe312014-01-06 17:17:02 +000079
80/******************************************************************************/
81/* dict iterator */
82
83typedef struct _mp_obj_dict_it_t {
84 mp_obj_base_t base;
85 mp_obj_dict_t *dict;
86 machine_uint_t cur;
87} mp_obj_dict_it_t;
88
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +020089STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in) {
John R. Lentona41fe312014-01-06 17:17:02 +000090 mp_obj_dict_it_t *self = self_in;
91 machine_uint_t max = self->dict->map.alloc;
92 mp_map_elem_t *table = self->dict->map.table;
93
94 for (int i = self->cur; i < max; i++) {
95 if (table[i].key != NULL) {
96 self->cur = i + 1;
97 return &(table[i]);
98 }
99 }
100
101 return NULL;
102}
103
104mp_obj_t dict_it_iternext(mp_obj_t self_in) {
105 mp_map_elem_t *next = dict_it_iternext_elem(self_in);
106
107 if (next != NULL) {
108 return next->key;
109 } else {
110 return mp_const_stop_iteration;
111 }
112}
113
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200114STATIC const mp_obj_type_t dict_it_type = {
John R. Lentona41fe312014-01-06 17:17:02 +0000115 { &mp_const_type },
116 "dict_iterator",
117 .iternext = dict_it_iternext,
John R. Lentona41fe312014-01-06 17:17:02 +0000118};
119
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200120STATIC mp_obj_t mp_obj_new_dict_iterator(mp_obj_dict_t *dict, int cur) {
John R. Lentona41fe312014-01-06 17:17:02 +0000121 mp_obj_dict_it_t *o = m_new_obj(mp_obj_dict_it_t);
122 o->base.type = &dict_it_type;
123 o->dict = dict;
124 o->cur = cur;
125 return o;
126}
127
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200128STATIC mp_obj_t dict_getiter(mp_obj_t o_in) {
John R. Lentona41fe312014-01-06 17:17:02 +0000129 return mp_obj_new_dict_iterator(o_in, 0);
130}
131
132/******************************************************************************/
133/* dict methods */
134
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200135STATIC mp_obj_t dict_clear(mp_obj_t self_in) {
John R. Lenton4ce6cea2014-01-06 17:38:47 +0000136 assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
137 mp_obj_dict_t *self = self_in;
138
139 mp_map_clear(&self->map);
140
141 return mp_const_none;
142}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200143STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear);
John R. Lenton7d21d512014-01-06 17:54:04 +0000144
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200145STATIC mp_obj_t dict_copy(mp_obj_t self_in) {
John R. Lentond90b19e2014-01-06 18:11:20 +0000146 assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
147 mp_obj_dict_t *self = self_in;
148 mp_obj_dict_t *other = mp_obj_new_dict(self->map.alloc);
149 other->map.used = self->map.used;
150 memcpy(other->map.table, self->map.table, self->map.alloc * sizeof(mp_map_elem_t));
151 return other;
152}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200153STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy);
John R. Lenton4ce6cea2014-01-06 17:38:47 +0000154
Damien Georgeeae16442014-01-11 19:22:29 +0000155// this is a classmethod
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200156STATIC mp_obj_t dict_fromkeys(uint n_args, const mp_obj_t *args) {
Damien Georgeeae16442014-01-11 19:22:29 +0000157 assert(2 <= n_args && n_args <= 3);
158 mp_obj_t iter = rt_getiter(args[1]);
159 mp_obj_t len = mp_obj_len_maybe(iter);
160 mp_obj_t value = mp_const_none;
161 mp_obj_t next = NULL;
162 mp_obj_dict_t *self = NULL;
163
164 if (n_args > 2) {
165 value = args[2];
166 }
167
168 if (len == MP_OBJ_NULL) {
169 /* object's type doesn't have a __len__ slot */
170 self = mp_obj_new_dict(0);
171 } else {
172 self = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len));
173 }
174
175 while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
176 mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
177 }
178
179 return self;
180}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200181STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_fun_obj, 2, 3, dict_fromkeys);
182STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, (const mp_obj_t)&dict_fromkeys_fun_obj);
Damien Georgeeae16442014-01-11 19:22:29 +0000183
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200184STATIC mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp_map_lookup_kind_t lookup_kind) {
Damien George38a2da62014-01-08 17:33:12 +0000185 mp_map_elem_t *elem = mp_map_lookup(self, key, lookup_kind);
John R. Lentonbe8fe5b2014-01-06 20:25:51 +0000186 mp_obj_t value;
187 if (elem == NULL || elem->value == NULL) {
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000188 if (deflt == NULL) {
Damien George38a2da62014-01-08 17:33:12 +0000189 if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000190 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "<value>"));
191 } else {
John R. Lentonbe8fe5b2014-01-06 20:25:51 +0000192 value = mp_const_none;
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000193 }
194 } else {
John R. Lentonbe8fe5b2014-01-06 20:25:51 +0000195 value = deflt;
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000196 }
197 } else {
John R. Lentonbe8fe5b2014-01-06 20:25:51 +0000198 value = elem->value;
Damien George38a2da62014-01-08 17:33:12 +0000199 if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
200 // catch the leak (from mp_map_lookup)
John R. Lenton88f30432014-01-06 22:58:17 +0000201 m_free(elem, sizeof(mp_map_elem_t));
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000202 }
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000203 }
Damien George38a2da62014-01-08 17:33:12 +0000204 if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
John R. Lentonbe8fe5b2014-01-06 20:25:51 +0000205 elem->value = value;
206 }
207 return value;
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000208}
209
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200210STATIC mp_obj_t dict_get(uint n_args, const mp_obj_t *args) {
John R. Lentoncd088732014-01-06 18:53:16 +0000211 assert(2 <= n_args && n_args <= 3);
212 assert(MP_OBJ_IS_TYPE(args[0], &dict_type));
213
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000214 return dict_get_helper(&((mp_obj_dict_t *)args[0])->map,
215 args[1],
216 n_args == 3 ? args[2] : NULL,
Damien George38a2da62014-01-08 17:33:12 +0000217 MP_MAP_LOOKUP);
John R. Lentoncd088732014-01-06 18:53:16 +0000218}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200219STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_get_obj, 2, 3, dict_get);
John R. Lentoncd088732014-01-06 18:53:16 +0000220
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200221STATIC mp_obj_t dict_pop(uint n_args, const mp_obj_t *args) {
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000222 assert(2 <= n_args && n_args <= 3);
223 assert(MP_OBJ_IS_TYPE(args[0], &dict_type));
224
225 return dict_get_helper(&((mp_obj_dict_t *)args[0])->map,
226 args[1],
227 n_args == 3 ? args[2] : NULL,
Damien George38a2da62014-01-08 17:33:12 +0000228 MP_MAP_LOOKUP_REMOVE_IF_FOUND);
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000229}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200230STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_pop_obj, 2, 3, dict_pop);
John R. Lenton0fcbaa42014-01-06 19:48:34 +0000231
232
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200233STATIC mp_obj_t dict_setdefault(uint n_args, const mp_obj_t *args) {
John R. Lentonbe8fe5b2014-01-06 20:25:51 +0000234 assert(2 <= n_args && n_args <= 3);
235 assert(MP_OBJ_IS_TYPE(args[0], &dict_type));
236
237 return dict_get_helper(&((mp_obj_dict_t *)args[0])->map,
238 args[1],
239 n_args == 3 ? args[2] : NULL,
Damien George38a2da62014-01-08 17:33:12 +0000240 MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
John R. Lentonbe8fe5b2014-01-06 20:25:51 +0000241}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200242STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault);
John R. Lentonbe8fe5b2014-01-06 20:25:51 +0000243
John R. Lentonf77dce82014-01-06 20:08:52 +0000244
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200245STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
John R. Lentonf77dce82014-01-06 20:08:52 +0000246 assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
247 mp_obj_dict_t *self = self_in;
248 if (self->map.used == 0) {
249 nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "popitem(): dictionary is empty"));
250 }
251 mp_obj_dict_it_t *iter = mp_obj_new_dict_iterator(self, 0);
252
253 mp_map_elem_t *next = dict_it_iternext_elem(iter);
254 self->map.used--;
255 mp_obj_t items[] = {next->key, next->value};
256 next->key = NULL;
John R. Lentonbe8fe5b2014-01-06 20:25:51 +0000257 next->value = NULL;
John R. Lentonf77dce82014-01-06 20:08:52 +0000258 mp_obj_t tuple = mp_obj_new_tuple(2, items);
259
260 return tuple;
261}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200262STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
John R. Lentonf77dce82014-01-06 20:08:52 +0000263
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200264STATIC mp_obj_t dict_update(mp_obj_t self_in, mp_obj_t iterable) {
John R. Lenton88f30432014-01-06 22:58:17 +0000265 assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
266 mp_obj_dict_t *self = self_in;
267 /* TODO: check for the "keys" method */
268 mp_obj_t iter = rt_getiter(iterable);
269 mp_obj_t next = NULL;
270 while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
271 mp_obj_t inneriter = rt_getiter(next);
272 mp_obj_t key = rt_iternext(inneriter);
273 mp_obj_t value = rt_iternext(inneriter);
274 mp_obj_t stop = rt_iternext(inneriter);
275 if (key == mp_const_stop_iteration
276 || value == mp_const_stop_iteration
277 || stop != mp_const_stop_iteration) {
278 nlr_jump(mp_obj_new_exception_msg(
279 MP_QSTR_ValueError,
280 "dictionary update sequence has the wrong length"));
281 } else {
Damien George38a2da62014-01-08 17:33:12 +0000282 mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
John R. Lenton88f30432014-01-06 22:58:17 +0000283 }
284 }
285
286 return mp_const_none;
287}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200288STATIC MP_DEFINE_CONST_FUN_OBJ_2(dict_update_obj, dict_update);
John R. Lenton88f30432014-01-06 22:58:17 +0000289
John R. Lentonf77dce82014-01-06 20:08:52 +0000290
John R. Lentona41fe312014-01-06 17:17:02 +0000291/******************************************************************************/
John R. Lenton9ec3a872014-01-10 01:00:20 +0000292/* dict views */
293
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200294STATIC const mp_obj_type_t dict_view_type;
295STATIC const mp_obj_type_t dict_view_it_type;
John R. Lenton9ec3a872014-01-10 01:00:20 +0000296
297typedef enum _mp_dict_view_kind_t {
298 MP_DICT_VIEW_ITEMS,
299 MP_DICT_VIEW_KEYS,
300 MP_DICT_VIEW_VALUES,
301} mp_dict_view_kind_t;
302
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200303STATIC char *mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"};
John R. Lenton9ec3a872014-01-10 01:00:20 +0000304
305typedef struct _mp_obj_dict_view_it_t {
306 mp_obj_base_t base;
307 mp_dict_view_kind_t kind;
308 mp_obj_dict_it_t *iter;
309 machine_uint_t cur;
310} mp_obj_dict_view_it_t;
311
312typedef struct _mp_obj_dict_view_t {
313 mp_obj_base_t base;
314 mp_obj_dict_t *dict;
315 mp_dict_view_kind_t kind;
316} mp_obj_dict_view_t;
317
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200318STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) {
John R. Lenton9ec3a872014-01-10 01:00:20 +0000319 assert(MP_OBJ_IS_TYPE(self_in, &dict_view_it_type));
320 mp_obj_dict_view_it_t *self = self_in;
321 mp_map_elem_t *next = dict_it_iternext_elem(self->iter);
322
323 if (next != NULL) {
324 switch (self->kind) {
Damien Georgeeae16442014-01-11 19:22:29 +0000325 case MP_DICT_VIEW_ITEMS:
326 {
327 mp_obj_t items[] = {next->key, next->value};
328 return mp_obj_new_tuple(2, items);
329 }
330 case MP_DICT_VIEW_KEYS:
331 return next->key;
332 case MP_DICT_VIEW_VALUES:
333 return next->value;
334 default:
335 assert(0); /* can't happen */
336 return mp_const_none;
John R. Lenton9ec3a872014-01-10 01:00:20 +0000337 }
338 } else {
339 return mp_const_stop_iteration;
340 }
341}
342
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200343STATIC const mp_obj_type_t dict_view_it_type = {
John R. Lenton9ec3a872014-01-10 01:00:20 +0000344 { &mp_const_type },
345 "dict_view_iterator",
346 .iternext = dict_view_it_iternext,
347 .methods = NULL, /* set operations still to come */
348};
349
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200350STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in) {
John R. Lenton9ec3a872014-01-10 01:00:20 +0000351 assert(MP_OBJ_IS_TYPE(view_in, &dict_view_type));
352 mp_obj_dict_view_t *view = view_in;
353 mp_obj_dict_view_it_t *o = m_new_obj(mp_obj_dict_view_it_t);
354 o->base.type = &dict_view_it_type;
355 o->kind = view->kind;
356 o->iter = mp_obj_new_dict_iterator(view->dict, 0);
357 return o;
358}
359
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200360STATIC void dict_view_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
John R. Lenton9ec3a872014-01-10 01:00:20 +0000361 assert(MP_OBJ_IS_TYPE(self_in, &dict_view_type));
362 mp_obj_dict_view_t *self = self_in;
363 bool first = true;
364 print(env, mp_dict_view_names[self->kind]);
365 print(env, "([");
366 mp_obj_t *self_iter = dict_view_getiter(self);
367 mp_obj_t *next = NULL;
368 while ((next = dict_view_it_iternext(self_iter)) != mp_const_stop_iteration) {
369 if (!first) {
370 print(env, ", ");
371 }
372 first = false;
Paul Sokolovsky76d982e2014-01-13 19:19:16 +0200373 mp_obj_print_helper(print, env, next, PRINT_REPR);
John R. Lenton9ec3a872014-01-10 01:00:20 +0000374 }
375 print(env, "])");
376}
377
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200378STATIC mp_obj_t dict_view_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
John R. Lentonc1bef212014-01-11 12:39:33 +0000379 /* only supported for the 'keys' kind until sets and dicts are refactored */
380 mp_obj_dict_view_t *o = lhs_in;
381 if (o->kind != MP_DICT_VIEW_KEYS) return NULL;
Damien George9aa2a522014-02-01 23:04:09 +0000382 if (op != RT_BINARY_OP_IN) return NULL;
John R. Lentonc1bef212014-01-11 12:39:33 +0000383 return dict_binary_op(op, o->dict, rhs_in);
384}
385
386
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200387STATIC const mp_obj_type_t dict_view_type = {
John R. Lenton9ec3a872014-01-10 01:00:20 +0000388 { &mp_const_type },
389 "dict_view",
390 .print = dict_view_print,
John R. Lentonc1bef212014-01-11 12:39:33 +0000391 .binary_op = dict_view_binary_op,
John R. Lenton9ec3a872014-01-10 01:00:20 +0000392 .getiter = dict_view_getiter,
393};
394
395mp_obj_t mp_obj_new_dict_view(mp_obj_dict_t *dict, mp_dict_view_kind_t kind) {
396 mp_obj_dict_view_t *o = m_new_obj(mp_obj_dict_view_t);
397 o->base.type = &dict_view_type;
398 o->dict = dict;
399 o->kind = kind;
400 return o;
401}
402
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200403STATIC mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) {
John R. Lenton9ec3a872014-01-10 01:00:20 +0000404 assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
405 mp_obj_dict_t *self = self_in;
406 return mp_obj_new_dict_view(self, kind);
407}
408
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200409STATIC mp_obj_t dict_items(mp_obj_t self_in) {
John R. Lenton9ec3a872014-01-10 01:00:20 +0000410 return dict_view(self_in, MP_DICT_VIEW_ITEMS);
411}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200412STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_items_obj, dict_items);
John R. Lenton9ec3a872014-01-10 01:00:20 +0000413
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200414STATIC mp_obj_t dict_keys(mp_obj_t self_in) {
John R. Lenton9ec3a872014-01-10 01:00:20 +0000415 return dict_view(self_in, MP_DICT_VIEW_KEYS);
416}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200417STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_keys_obj, dict_keys);
John R. Lenton9ec3a872014-01-10 01:00:20 +0000418
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200419STATIC mp_obj_t dict_values(mp_obj_t self_in) {
John R. Lenton9ec3a872014-01-10 01:00:20 +0000420 return dict_view(self_in, MP_DICT_VIEW_VALUES);
421}
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200422STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values);
John R. Lenton9ec3a872014-01-10 01:00:20 +0000423
John R. Lenton4bee76e2014-01-10 11:25:03 +0000424/******************************************************************************/
Damien Georgeeae16442014-01-11 19:22:29 +0000425/* dict constructors & public C API */
John R. Lentona41fe312014-01-06 17:17:02 +0000426
Paul Sokolovskyd5df6cd2014-02-12 18:15:40 +0200427STATIC const mp_method_t dict_type_methods[] = {
John R. Lentonbaa66542014-01-07 23:18:25 +0000428 { "clear", &dict_clear_obj },
429 { "copy", &dict_copy_obj },
Damien Georgeeae16442014-01-11 19:22:29 +0000430 { "fromkeys", &dict_fromkeys_obj },
John R. Lentonbaa66542014-01-07 23:18:25 +0000431 { "get", &dict_get_obj },
John R. Lenton9ec3a872014-01-10 01:00:20 +0000432 { "items", &dict_items_obj },
433 { "keys", &dict_keys_obj },
John R. Lentonbaa66542014-01-07 23:18:25 +0000434 { "pop", &dict_pop_obj },
435 { "popitem", &dict_popitem_obj },
436 { "setdefault", &dict_setdefault_obj },
437 { "update", &dict_update_obj },
John R. Lenton9ec3a872014-01-10 01:00:20 +0000438 { "values", &dict_values_obj },
John R. Lentonbaa66542014-01-07 23:18:25 +0000439 { NULL, NULL }, // end-of-list sentinel
440};
441
Damiend99b0522013-12-21 18:17:45 +0000442const mp_obj_type_t dict_type = {
Damien Georgeeae16442014-01-11 19:22:29 +0000443 { &mp_const_type },
Damiend99b0522013-12-21 18:17:45 +0000444 "dict",
Paul Sokolovsky860ffb02014-01-05 22:34:09 +0200445 .print = dict_print,
446 .make_new = dict_make_new,
Damien George4e8dc8c2014-01-27 23:15:32 +0000447 .unary_op = dict_unary_op,
Paul Sokolovsky860ffb02014-01-05 22:34:09 +0200448 .binary_op = dict_binary_op,
John R. Lentona41fe312014-01-06 17:17:02 +0000449 .getiter = dict_getiter,
John R. Lentonbaa66542014-01-07 23:18:25 +0000450 .methods = dict_type_methods,
Damiend99b0522013-12-21 18:17:45 +0000451};
452
453mp_obj_t mp_obj_new_dict(int n_args) {
454 mp_obj_dict_t *o = m_new_obj(mp_obj_dict_t);
455 o->base.type = &dict_type;
Damien George38a2da62014-01-08 17:33:12 +0000456 mp_map_init(&o->map, n_args);
Damiend99b0522013-12-21 18:17:45 +0000457 return o;
458}
Damiendae7eb72013-12-29 22:32:51 +0000459
460uint mp_obj_dict_len(mp_obj_t self_in) {
John R. Lentoncd088732014-01-06 18:53:16 +0000461 return ((mp_obj_dict_t *)self_in)->map.used;
Damiendae7eb72013-12-29 22:32:51 +0000462}
463
464mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
465 assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
466 mp_obj_dict_t *self = self_in;
Damien George38a2da62014-01-08 17:33:12 +0000467 mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
Damiendae7eb72013-12-29 22:32:51 +0000468 return self_in;
469}
Damien George062478e2014-01-09 20:57:50 +0000470
471mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in) {
472 assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
473 mp_obj_dict_t *self = self_in;
474 return &self->map;
475}