diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index f6c8f19c23..0fe2f774af 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -38,93 +38,41 @@ typedef struct _mp_obj_namedtuple_type_t { mp_obj_type_t base; - const char *fields; + mp_uint_t n_fields; + mp_obj_t fields[]; } mp_obj_namedtuple_type_t; typedef struct _mp_obj_namedtuple_t { mp_obj_tuple_t tuple; } mp_obj_namedtuple_t; -static inline bool is_end_tok(char c) { - return c == ' ' || c == ','; -} - -static inline const char *skip_to_next(const char *p) { - while (!is_end_tok(*p)) { - if (*p == 0) { - return NULL; - } - p++; - } - while (is_end_tok(*p)) { - if (*p == 0) { - return NULL; - } - p++; - } - return p; -} - -STATIC uint namedtuple_count_fields(const char *namedef) { - uint cnt = 0; - while (*namedef != 0) { - cnt++; - while (!is_end_tok(*namedef) && *namedef != 0) { - namedef++; - } - while (is_end_tok(*namedef) && *namedef != 0) { - namedef++; +STATIC mp_uint_t namedtuple_find_field(mp_obj_namedtuple_type_t *type, qstr name) { + for (mp_uint_t i = 0; i < type->n_fields; i++) { + if (MP_OBJ_QSTR_VALUE(type->fields[i]) == name) { + return i; } } - return cnt; -} - -STATIC int namedtuple_find_field(const char *name, const char *namedef) { - int id = 0; - size_t len = strlen(name); - while (namedef) { - if (memcmp(name, namedef, len) == 0) { - namedef += len; - if (*namedef == 0 || is_end_tok(*namedef)) { - return id; - } - } - namedef = skip_to_next(namedef); - id++; - } - return -1; } STATIC void namedtuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_namedtuple_t *o = o_in; print(env, "%s(", qstr_str(o->tuple.base.type->name)); - const char *fields = ((mp_obj_namedtuple_type_t*)o->tuple.base.type)->fields; - + const mp_obj_t *fields = ((mp_obj_namedtuple_type_t*)o->tuple.base.type)->fields; for (mp_uint_t i = 0; i < o->tuple.len; i++) { if (i > 0) { print(env, ", "); } - const char *next = fields; - - while (!is_end_tok(*next) && *next != 0) { - next++; - } - print(env, "%.*s=", next - fields, fields); + print(env, "%s=", qstr_str(MP_OBJ_QSTR_VALUE(fields[i]))); mp_obj_print_helper(print, env, o->tuple.items[i], PRINT_REPR); - while (is_end_tok(*next) && *next != 0) { - next++; - } - fields = next; } print(env, ")"); } STATIC void namedtuple_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_namedtuple_t *self = self_in; - const char *fields = ((mp_obj_namedtuple_type_t*)self->tuple.base.type)->fields; - int id = namedtuple_find_field(qstr_str(attr), fields); - if (id < 0) { + int id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); + if (id == -1) { return; } dest[0] = self->tuple.items[id]; @@ -136,8 +84,8 @@ STATIC bool namedtuple_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { STATIC mp_obj_t namedtuple_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { mp_obj_namedtuple_type_t *type = type_in; - uint num_fields = namedtuple_count_fields(type->fields); - if (n_args != num_fields) { + mp_uint_t num_fields = type->n_fields; + if (n_args + n_kw != num_fields) { // Counts include implicit "self" nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__new__() takes %d positional arguments but %d were given", @@ -150,8 +98,8 @@ STATIC mp_obj_t namedtuple_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_ STATIC const mp_obj_tuple_t namedtuple_base_tuple = {{&mp_type_tuple}, 1, {(mp_obj_t)&mp_type_tuple}}; -STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, const char *fields) { - mp_obj_namedtuple_type_t *o = m_new0(mp_obj_namedtuple_type_t, 1); +STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, mp_uint_t n_fields, mp_obj_t *fields) { + mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, mp_obj_t, n_fields); o->base.base.type = &mp_type_type; o->base.name = name; o->base.print = namedtuple_print; @@ -163,14 +111,17 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, const char *fields) { o->base.subscr = mp_obj_tuple_subscr; o->base.getiter = mp_obj_tuple_getiter; o->base.bases_tuple = (mp_obj_t)&namedtuple_base_tuple; - o->fields = fields; + o->n_fields = n_fields; + memcpy(o->fields, fields, sizeof(mp_obj_t) * n_fields); return o; } STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { qstr name = MP_OBJ_QSTR_VALUE(name_in); - const char *fields = mp_obj_str_get_str(fields_in); - return mp_obj_new_namedtuple_type(name, fields); + mp_uint_t n_fields; + mp_obj_t *fields; + mp_obj_list_get(fields_in, &n_fields, &fields); + return mp_obj_new_namedtuple_type(name, n_fields, fields); } MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type); diff --git a/tests/basics/class_store_class.py b/tests/basics/class_store_class.py index 60f65220d9..09a8e8bc4d 100644 --- a/tests/basics/class_store_class.py +++ b/tests/basics/class_store_class.py @@ -7,7 +7,7 @@ try: except ImportError: from _collections import namedtuple -_DefragResultBase = namedtuple('DefragResult', 'foo bar') +_DefragResultBase = namedtuple('DefragResult', [ 'foo', 'bar' ]) class _ResultMixinStr(object): def encode(self): diff --git a/tests/basics/namedtuple1.py b/tests/basics/namedtuple1.py index 05dd15bd17..a94b7e7ab0 100644 --- a/tests/basics/namedtuple1.py +++ b/tests/basics/namedtuple1.py @@ -3,7 +3,7 @@ try: except ImportError: from _collections import namedtuple -T = namedtuple("Tup", "foo bar") +T = namedtuple("Tup", ["foo", "bar"]) # CPython prints fully qualified name, what we don't bother to do so far #print(T) t = T(1, 2) @@ -27,7 +27,7 @@ except TypeError: try: t.bar = 200 except AttributeError: - print("AttribiteError") + print("AttributeError") try: t = T(1) @@ -39,13 +39,12 @@ try: except TypeError: print("TypeError") -# Try comma field separator -T2 = namedtuple("TupComma", "foo,bar") -t = T2(1, 2) -print(t) -print(t.foo, t.bar) - -# Try list of fields +# Try single string # Not implemented so far -#T3 = namedtuple("TupComma", ["foo", "bar"]) +#T3 = namedtuple("TupComma", "foo bar") #t = T3(1, 2) + +# Try single string with comma field seperator +# Not implemented so far +#T2 = namedtuple("TupComma", "foo,bar") +#t = T2(1, 2) diff --git a/tests/bench/var-8-namedtuple-1st.py b/tests/bench/var-8-namedtuple-1st.py index 7c4099ac62..f3f36f415a 100644 --- a/tests/bench/var-8-namedtuple-1st.py +++ b/tests/bench/var-8-namedtuple-1st.py @@ -1,7 +1,7 @@ import bench from _collections import namedtuple -T = namedtuple("Tup", "num bar") +T = namedtuple("Tup", ["num", "bar"]) def test(num): t = T(20000000, 0) diff --git a/tests/bench/var-8.1-namedtuple-5th.py b/tests/bench/var-8.1-namedtuple-5th.py index 2cd6d15a0d..b6bdc8d795 100644 --- a/tests/bench/var-8.1-namedtuple-5th.py +++ b/tests/bench/var-8.1-namedtuple-5th.py @@ -1,7 +1,7 @@ import bench from _collections import namedtuple -T = namedtuple("Tup", "foo1 foo2 foo3 foo4 num") +T = namedtuple("Tup", ["foo1", "foo2", "foo3", "foo4", "num"]) def test(num): t = T(0, 0, 0, 0, 20000000)