summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extmod/moductypes.c101
-rw-r--r--tests/extmod/uctypes_sizeof.py26
-rw-r--r--tests/extmod/uctypes_sizeof.py.exp4
3 files changed, 90 insertions, 41 deletions
diff --git a/extmod/moductypes.c b/extmod/moductypes.c
index bc1824765..6010e77aa 100644
--- a/extmod/moductypes.c
+++ b/extmod/moductypes.c
@@ -106,6 +106,7 @@ enum {
#define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1))
#define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits)
+// "struct" in uctypes context means "structural", i.e. aggregate, type.
STATIC const mp_obj_type_t uctypes_struct_type;
typedef struct _mp_obj_uctypes_struct_t {
@@ -153,6 +154,10 @@ STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...),
print(env, "<struct %s %p>", typen, self->addr);
}
+// Get size of any type descriptor
+STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size);
+
+// Get size of scalar type descriptor
static inline mp_uint_t uctypes_struct_scalar_size(int val_type) {
if (val_type == FLOAT32) {
return 4;
@@ -161,11 +166,60 @@ static inline mp_uint_t uctypes_struct_scalar_size(int val_type) {
}
}
+// Get size of aggregate type descriptor
+STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, mp_uint_t *max_field_size) {
+ mp_uint_t total_size = 0;
+
+ mp_int_t offset_ = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
+ mp_uint_t agg_type = GET_TYPE(offset_, AGG_TYPE_BITS);
+
+ switch (agg_type) {
+ case STRUCT:
+ return uctypes_struct_size(t->items[1], max_field_size);
+ case PTR:
+ if (sizeof(void*) > *max_field_size) {
+ *max_field_size = sizeof(void*);
+ }
+ return sizeof(void*);
+ case ARRAY: {
+ mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
+ uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
+ arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
+ mp_uint_t item_s;
+ if (t->len == 2) {
+ // Elements of array are scalar
+ item_s = GET_SCALAR_SIZE(val_type);
+ if (item_s > *max_field_size) {
+ *max_field_size = item_s;
+ }
+ } else {
+ // Elements of array are aggregates
+ item_s = uctypes_struct_size(t->items[2], max_field_size);
+ }
+
+ return item_s * arr_sz;
+ }
+ default:
+ assert(0);
+ }
+
+ return total_size;
+}
+
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size) {
mp_obj_dict_t *d = desc_in;
mp_uint_t total_size = 0;
if (!MP_OBJ_IS_TYPE(desc_in, &mp_type_dict)) {
+ if (MP_OBJ_IS_TYPE(desc_in, &mp_type_tuple)) {
+ return uctypes_struct_agg_size((mp_obj_tuple_t*)desc_in, max_field_size);
+ } else if (MP_OBJ_IS_SMALL_INT(desc_in)) {
+ // We allow sizeof on both type definitions and structures/structure fields,
+ // but scalar structure field is lowered into native Python int, so all
+ // type info is lost. So, we cannot say if it's scalar type description,
+ // or such lowered scalar.
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Cannot unambiguously get sizeof scalar"));
+ }
syntax_error();
}
@@ -189,48 +243,10 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size
}
mp_obj_tuple_t *t = (mp_obj_tuple_t*)v;
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
- mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
offset &= VALUE_MASK(AGG_TYPE_BITS);
-
- switch (agg_type) {
- case STRUCT: {
- mp_uint_t s = uctypes_struct_size(t->items[1], max_field_size);
- if (offset + s > total_size) {
- total_size = offset + s;
- }
- break;
- }
- case PTR: {
- if (offset + sizeof(void*) > total_size) {
- total_size = offset + sizeof(void*);
- }
- if (sizeof(void*) > *max_field_size) {
- *max_field_size = sizeof(void*);
- }
- break;
- }
- case ARRAY: {
- mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
- uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
- arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
- mp_uint_t item_s;
- if (t->len == 2) {
- item_s = GET_SCALAR_SIZE(val_type);
- if (item_s > *max_field_size) {
- *max_field_size = item_s;
- }
- } else {
- item_s = uctypes_struct_size(t->items[2], max_field_size);
- }
-
- mp_uint_t byte_sz = item_s * arr_sz;
- if (offset + byte_sz > total_size) {
- total_size = offset + byte_sz;
- }
- break;
- }
- default:
- assert(0);
+ mp_uint_t s = uctypes_struct_agg_size(t, max_field_size);
+ if (offset + s > total_size) {
+ total_size = offset + s;
}
}
}
@@ -243,7 +259,10 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size
STATIC mp_obj_t uctypes_struct_sizeof(mp_obj_t obj_in) {
mp_uint_t max_field_size = 0;
+ // We can apply sizeof either to structure definition (a dict)
+ // or to instantiated structure
if (MP_OBJ_IS_TYPE(obj_in, &uctypes_struct_type)) {
+ // Extract structure definition
mp_obj_uctypes_struct_t *obj = obj_in;
obj_in = obj->desc;
}
diff --git a/tests/extmod/uctypes_sizeof.py b/tests/extmod/uctypes_sizeof.py
new file mode 100644
index 000000000..f6551a738
--- /dev/null
+++ b/tests/extmod/uctypes_sizeof.py
@@ -0,0 +1,26 @@
+import uctypes
+
+desc = {
+ # arr is array at offset 0, of UINT8 elements, array size is 2
+ "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2),
+ # arr2 is array at offset 0, size 2, of structures defined recursively
+ "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}),
+ "arr3": (uctypes.ARRAY | 2, uctypes.UINT16 | 2),
+}
+
+data = bytearray(b"01234567")
+
+S = uctypes.struct(desc, uctypes.addressof(data), uctypes.LITTLE_ENDIAN)
+
+print(uctypes.sizeof(S.arr))
+assert uctypes.sizeof(S.arr) == 2
+
+print(uctypes.sizeof(S.arr2))
+assert uctypes.sizeof(S.arr2) == 2
+
+print(uctypes.sizeof(S.arr3))
+
+try:
+ print(uctypes.sizeof(S.arr3[0]))
+except TypeError:
+ print("TypeError")
diff --git a/tests/extmod/uctypes_sizeof.py.exp b/tests/extmod/uctypes_sizeof.py.exp
new file mode 100644
index 000000000..d1e81238b
--- /dev/null
+++ b/tests/extmod/uctypes_sizeof.py.exp
@@ -0,0 +1,4 @@
+2
+2
+4
+TypeError