modstruct: Fix .calcsize() to account for struct type/alignment.

This commit is contained in:
Paul Sokolovsky 2014-04-19 01:25:49 +03:00
parent 5695e07256
commit 1355cf42f2
4 changed files with 65 additions and 80 deletions

View File

@ -1,4 +1,5 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <assert.h> #include <assert.h>
#include "misc.h" #include "misc.h"
@ -9,34 +10,52 @@
// Helpers to work with binary-encoded data // Helpers to work with binary-encoded data
int mp_binary_get_size(char typecode) { int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
// This assumes that unsigned and signed types are of the same type, int size = 0;
// which is invariant for [u]intN_t. int align = 1;
switch (typecode) { switch (struct_type) {
case BYTEARRAY_TYPECODE: case '<': case '>':
case 'b': switch (val_type) {
case 'B': case 'b': case 'B':
return sizeof(int8_t); size = 1; break;
case 'h': case 'h': case 'H':
case 'H': size = 2; break;
return sizeof(int16_t); case 'i': case 'I':
case 'i': size = 4; break;
case 'I': case 'l': case 'L':
return sizeof(int32_t); size = 4; break;
case 'l': case 'q': case 'Q':
case 'L': size = 8; break;
return sizeof(int32_t); }
case 'q': break;
case 'Q': case '@': {
return sizeof(long long); // TODO:
#if MICROPY_ENABLE_FLOAT // The simplest heuristic for alignment is to align by value
case 'f': // size, but that doesn't work for "bigger than int" types,
return sizeof(float); // for example, long long may very well have long alignment
case 'd': // So, we introduce separate alignment handling, but having
return sizeof(double); // formal support for that is different from actually supporting
#endif // particular (or any) ABI.
switch (val_type) {
case BYTEARRAY_TYPECODE:
case 'b': case 'B':
align = size = 1; break;
case 'h': case 'H':
align = size = sizeof(short); break;
case 'i': case 'I':
align = size = sizeof(int); break;
case 'l': case 'L':
align = size = sizeof(long); break;
case 'q': case 'Q':
// TODO: This is for x86
align = sizeof(int); size = sizeof(long long); break;
}
}
} }
return -1; if (palign != NULL) {
*palign = align;
}
return size;
} }
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) { mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
@ -80,53 +99,17 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
#define is_signed(typecode) (typecode > 'Z') #define is_signed(typecode) (typecode > 'Z')
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
byte *p = *ptr; byte *p = *ptr;
uint size = 0; uint align;
switch (struct_type) {
case '<': case '>': int size = mp_binary_get_size(struct_type, val_type, &align);
switch (val_type) { if (struct_type == '@') {
case 'b': case 'B': // Make pointer aligned
size = 1; break; p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
case 'h': case 'H': #if MP_ENDIANNESS_LITTLE
size = 2; break; struct_type = '<';
case 'i': case 'I': #else
size = 4; break; struct_type = '>';
case 'l': case 'L': #endif
size = 4; break;
case 'q': case 'Q':
size = 8; break;
}
break;
case '@': {
// TODO:
// The simplest heuristic for alignment is to align by value
// size, but that doesn't work for "bigger than int" types,
// for example, long long may very well have long alignment
// So, we introduce separate alignment handling, but having
// formal support for that is different from actually supporting
// particular (or any) ABI.
uint align = 0;
switch (val_type) {
case 'b': case 'B':
align = size = 1; break;
case 'h': case 'H':
align = size = sizeof(short); break;
case 'i': case 'I':
align = size = sizeof(int); break;
case 'l': case 'L':
align = size = sizeof(long); break;
case 'q': case 'Q':
// TODO: This is for x86
align = sizeof(int); size = sizeof(long long); break;
}
// Make pointer aligned
p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
#if MP_ENDIANNESS_LITTLE
struct_type = '<';
#else
struct_type = '>';
#endif
break;
}
} }
int delta; int delta;

View File

@ -2,7 +2,7 @@
// (underlyingly they're same). // (underlyingly they're same).
#define BYTEARRAY_TYPECODE 0 #define BYTEARRAY_TYPECODE 0
int mp_binary_get_size(char typecode); int mp_binary_get_size(char struct_type, char val_type, uint *palign);
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index); mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index);
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr); mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr);
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in); void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in);

View File

@ -37,12 +37,14 @@ STATIC uint calcsize_items(const char *fmt) {
STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
const char *fmt = mp_obj_str_get_str(fmt_in); const char *fmt = mp_obj_str_get_str(fmt_in);
char fmt_type = get_fmt_type(&fmt); char fmt_type = get_fmt_type(&fmt);
(void)fmt_type;
machine_uint_t size; machine_uint_t size;
for (size = 0; *fmt; fmt++) { for (size = 0; *fmt; fmt++) {
int sz = mp_binary_get_size(*fmt); uint align;
int sz = mp_binary_get_size(fmt_type, *fmt, &align);
// TODO // TODO
assert(sz != -1); assert(sz != -1);
// Apply alignment
size = (size + align - 1) & ~(align - 1);
size += sz; size += sz;
} }
return MP_OBJ_NEW_SMALL_INT(size); return MP_OBJ_NEW_SMALL_INT(size);

View File

@ -121,7 +121,7 @@ STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)); assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray));
mp_obj_array_t *self = self_in; mp_obj_array_t *self = self_in;
if (self->free == 0) { if (self->free == 0) {
int item_sz = mp_binary_get_size(self->typecode); int item_sz = mp_binary_get_size('@', self->typecode, NULL);
// TODO: alloc policy // TODO: alloc policy
self->free = 8; self->free = 8;
self->items = m_realloc(self->items, item_sz * self->len, item_sz * (self->len + self->free)); self->items = m_realloc(self->items, item_sz * self->len, item_sz * (self->len + self->free));
@ -154,7 +154,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
STATIC machine_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) { STATIC machine_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) {
mp_obj_array_t *o = o_in; mp_obj_array_t *o = o_in;
bufinfo->buf = o->items; bufinfo->buf = o->items;
bufinfo->len = o->len * mp_binary_get_size(o->typecode); bufinfo->len = o->len * mp_binary_get_size('@', o->typecode, NULL);
bufinfo->typecode = o->typecode; bufinfo->typecode = o->typecode;
return 0; return 0;
} }
@ -190,7 +190,7 @@ const mp_obj_type_t mp_type_bytearray = {
}; };
STATIC mp_obj_array_t *array_new(char typecode, uint n) { STATIC mp_obj_array_t *array_new(char typecode, uint n) {
int typecode_size = mp_binary_get_size(typecode); int typecode_size = mp_binary_get_size('@', typecode, NULL);
if (typecode_size <= 0) { if (typecode_size <= 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode")); nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode"));
} }