From 5aa311d33084c24262780cae0a65d748990ce7e1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 21 Apr 2015 14:14:24 +0000 Subject: [PATCH] py: Add attrtuple object, for space-efficient tuples with attr access. If you need the functionality of a namedtuple but will only make 1 or a few instances, then use an attrtuple instead. --- bare-arm/mpconfigport.h | 1 + minimal/mpconfigport.h | 1 + py/mpconfig.h | 6 +++ py/objattrtuple.c | 94 +++++++++++++++++++++++++++++++++++++++++ py/objnamedtuple.c | 11 +---- py/objtuple.h | 15 +++++++ py/py.mk | 1 + 7 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 py/objattrtuple.c diff --git a/bare-arm/mpconfigport.h b/bare-arm/mpconfigport.h index 7b8f8168b3..41fe5dacef 100644 --- a/bare-arm/mpconfigport.h +++ b/bare-arm/mpconfigport.h @@ -27,6 +27,7 @@ #define MICROPY_PY___FILE__ (0) #define MICROPY_PY_GC (0) #define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_ATTRTUPLE (0) #define MICROPY_PY_COLLECTIONS (0) #define MICROPY_PY_MATH (0) #define MICROPY_PY_CMATH (0) diff --git a/minimal/mpconfigport.h b/minimal/mpconfigport.h index b08bdf8b7d..ef4fc00b40 100644 --- a/minimal/mpconfigport.h +++ b/minimal/mpconfigport.h @@ -30,6 +30,7 @@ #define MICROPY_PY___FILE__ (0) #define MICROPY_PY_GC (0) #define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_ATTRTUPLE (0) #define MICROPY_PY_COLLECTIONS (0) #define MICROPY_PY_MATH (0) #define MICROPY_PY_CMATH (0) diff --git a/py/mpconfig.h b/py/mpconfig.h index a403a66633..df18290a20 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -502,6 +502,12 @@ typedef double mp_float_t; #define MICROPY_PY_ARRAY_SLICE_ASSIGN (0) #endif +// Whether to support attrtuple type (MicroPython extension) +// It provides space-efficient tuples with attribute access +#ifndef MICROPY_PY_ATTRTUPLE +#define MICROPY_PY_ATTRTUPLE (1) +#endif + // Whether to provide "collections" module #ifndef MICROPY_PY_COLLECTIONS #define MICROPY_PY_COLLECTIONS (1) diff --git a/py/objattrtuple.c b/py/objattrtuple.c new file mode 100644 index 0000000000..223c4c5810 --- /dev/null +++ b/py/objattrtuple.c @@ -0,0 +1,94 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objtuple.h" + +#if MICROPY_PY_ATTRTUPLE || MICROPY_PY_COLLECTIONS + +// this helper function is used by collections.namedtuple +#if !MICROPY_PY_COLLECTIONS +STATIC +#endif +void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_tuple_t *o) { + mp_print_str(print, "("); + for (mp_uint_t i = 0; i < o->len; i++) { + if (i > 0) { + mp_print_str(print, ", "); + } + mp_printf(print, "%q=", fields[i]); + mp_obj_print_helper(print, o->items[i], PRINT_REPR); + } + mp_print_str(print, ")"); +} + +#endif + +#if MICROPY_PY_ATTRTUPLE + +STATIC void mp_obj_attrtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_tuple_t *o = o_in; + const qstr *fields = (const qstr*)o->items[o->len]; + mp_obj_attrtuple_print_helper(print, fields, o); +} + +STATIC void mp_obj_attrtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_obj_tuple_t *self = self_in; + mp_uint_t len = self->len; + const qstr *fields = (const qstr*)self->items[len]; + for (mp_uint_t i = 0; i < len; i++) { + if (fields[i] == attr) { + dest[0] = self->items[i]; + return; + } + } + } +} + +mp_obj_t mp_obj_new_attrtuple(const qstr *fields, mp_uint_t n, const mp_obj_t *items) { + mp_obj_tuple_t *o = mp_obj_new_tuple(n + 1, NULL); + o->base.type = &mp_type_attrtuple; + for (mp_uint_t i = 0; i < n; i++) { + o->items[i] = items[i]; + } + o->items[n] = (void*)fields; + return o; +} + +const mp_obj_type_t mp_type_attrtuple = { + { &mp_type_type }, + .name = MP_QSTR_tuple, // reuse tuple to save on a qstr + .print = mp_obj_attrtuple_print, + .unary_op = mp_obj_tuple_unary_op, + .binary_op = mp_obj_tuple_binary_op, + .attr = mp_obj_attrtuple_attr, + .subscr = mp_obj_tuple_subscr, + .getiter = mp_obj_tuple_getiter, +}; + +#endif // MICROPY_PY_ATTRTUPLE diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 0d14635447..59678afe3a 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -56,16 +56,9 @@ STATIC mp_uint_t namedtuple_find_field(mp_obj_namedtuple_type_t *type, qstr name STATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_namedtuple_t *o = o_in; - mp_printf(print, "%q(", o->tuple.base.type->name); + mp_printf(print, "%q", o->tuple.base.type->name); const qstr *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) { - mp_print_str(print, ", "); - } - mp_printf(print, "%q=", fields[i]); - mp_obj_print_helper(print, o->tuple.items[i], PRINT_REPR); - } - mp_print_str(print, ")"); + mp_obj_attrtuple_print_helper(print, fields, &o->tuple); } STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { diff --git a/py/objtuple.h b/py/objtuple.h index 5fb82ba529..8c4d41ed32 100644 --- a/py/objtuple.h +++ b/py/objtuple.h @@ -40,4 +40,19 @@ mp_obj_t mp_obj_tuple_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs); mp_obj_t mp_obj_tuple_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value); mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in); +extern const mp_obj_type_t mp_type_attrtuple; + +#define MP_DEFINE_ATTRTUPLE(tuple_obj_name, fields, nitems, ...) \ + const mp_obj_tuple_t tuple_obj_name = { \ + .base = {&mp_type_attrtuple}, \ + .len = nitems, \ + .items = { __VA_ARGS__ , (void*)fields } \ + } + +#if MICROPY_PY_COLLECTIONS +void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_tuple_t *o); +#endif + +mp_obj_t mp_obj_new_attrtuple(const qstr *fields, mp_uint_t n, const mp_obj_t *items); + #endif // __MICROPY_INCLUDED_PY_OBJTUPLE_H__ diff --git a/py/py.mk b/py/py.mk index 98c6041156..8960fa4b42 100644 --- a/py/py.mk +++ b/py/py.mk @@ -55,6 +55,7 @@ PY_O_BASENAME = \ map.o \ obj.o \ objarray.o \ + objattrtuple.o \ objbool.o \ objboundmeth.o \ objcell.o \