Change the _count fields to use pb_size_t datatype.

Update issue 82
Status: FixedInGit
This commit is contained in:
Petteri Aimonen
2014-08-18 20:09:52 +03:00
parent 0b517b0778
commit 1dd9f1900f
8 changed files with 77 additions and 44 deletions

View File

@@ -31,6 +31,21 @@ functionality is not needed.
**Error indications:** Linker error: undefined reference to
*pb_field_iter_begin*, *pb_field_iter_next* or similar.
Change data type of field counts to pb_size_t
---------------------------------------------
**Rationale:** Often nanopb is used with small arrays, such as 255 items or
less. Using a full *size_t* field to store the array count wastes memory if
there are many arrays. There already exists parameters *PB_FIELD_16BIT* and
*PB_FIELD_32BIT* which tell nanopb what is the maximum size of arrays in use.
**Changes:** Generator will now use *pb_size_t* for the array *_count* fields.
The size of the type will be controlled by the *PB_FIELD_16BIT* and
*PB_FIELD_32BIT* compilation time options.
**Required actions:** Regenerate all *.pb.h* files. In some cases casts to the
*pb_size_t* type may need to be added in the user code when accessing the
*_count* fields.
Nanopb-0.2.9 (2014-08-09)
=========================

View File

@@ -261,7 +261,7 @@ class Field:
result = ''
if self.allocation == 'POINTER':
if self.rules == 'REPEATED':
result += ' size_t ' + self.name + '_count;\n'
result += ' pb_size_t ' + self.name + '_count;\n'
if self.pbtype == 'MESSAGE':
# Use struct definition, so recursive submessages are possible
@@ -277,17 +277,14 @@ class Field:
if self.rules == 'OPTIONAL' and self.allocation == 'STATIC':
result += ' bool has_' + self.name + ';\n'
elif self.rules == 'REPEATED' and self.allocation == 'STATIC':
result += ' size_t ' + self.name + '_count;\n'
result += ' pb_size_t ' + self.name + '_count;\n'
result += ' %s %s%s;' % (self.ctype, self.name, self.array_decl)
return result
def types(self):
'''Return definitions for any special types this field might need.'''
if self.pbtype == 'BYTES' and self.allocation == 'STATIC':
result = 'typedef struct {\n'
result += ' size_t size;\n'
result += ' uint8_t bytes[%d];\n' % self.max_size
result += '} %s;\n' % self.ctype
result = 'typedef PB_BYTES_ARRAY_T(%d) %s;\n' % (self.max_size, self.ctype)
else:
result = None
return result

7
pb.h
View File

@@ -187,12 +187,15 @@ typedef uint8_t pb_type_t;
* and array counts.
*/
#if defined(PB_FIELD_32BIT)
#define PB_SIZE_MAX ((uint32_t)-1)
typedef uint32_t pb_size_t;
typedef int32_t pb_ssize_t;
#elif defined(PB_FIELD_16BIT)
#define PB_SIZE_MAX ((uint16_t)-1)
typedef uint16_t pb_size_t;
typedef int16_t pb_ssize_t;
#else
#define PB_SIZE_MAX ((uint8_t)-1)
typedef uint8_t pb_size_t;
typedef int8_t pb_ssize_t;
#endif
@@ -241,11 +244,11 @@ STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE)
* It has the number of bytes in the beginning, and after that an array.
* Note that actual structs used will have a different length of bytes array.
*/
#define PB_BYTES_ARRAY_T(n) struct { size_t size; uint8_t bytes[n]; }
#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; uint8_t bytes[n]; }
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes))
struct _pb_bytes_array_t {
size_t size;
pb_size_t size;
uint8_t bytes[1];
};
typedef struct _pb_bytes_array_t pb_bytes_array_t;

View File

@@ -352,7 +352,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
{
/* Packed array */
bool status = true;
size_t *size = (size_t*)iter->pSize;
pb_size_t *size = (pb_size_t*)iter->pSize;
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
return false;
@@ -377,7 +377,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
else
{
/* Repeated field */
size_t *size = (size_t*)iter->pSize;
pb_size_t *size = (pb_size_t*)iter->pSize;
void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size);
if (*size >= iter->pos->array_size)
PB_RETURN_ERROR(stream, "array overflow");
@@ -478,7 +478,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
{
/* Packed array, multiple items come in at once. */
bool status = true;
size_t *size = (size_t*)iter->pSize;
pb_size_t *size = (pb_size_t*)iter->pSize;
size_t allocated_size = *size;
void *pItem;
pb_istream_t substream;
@@ -488,7 +488,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
while (substream.bytes_left)
{
if (*size + 1 > allocated_size)
if ((size_t)*size + 1 > allocated_size)
{
/* Allocate more storage. This tries to guess the
* number of remaining entries. Round the division
@@ -510,6 +510,16 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
status = false;
break;
}
if (*size == PB_SIZE_MAX)
{
#ifndef PB_NO_ERRMSG
stream->errmsg = "too many array entries";
#endif
status = false;
break;
}
(*size)++;
}
pb_close_string_substream(stream, &substream);
@@ -519,9 +529,12 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
else
{
/* Normal repeated field, i.e. only one item at a time. */
size_t *size = (size_t*)iter->pSize;
pb_size_t *size = (pb_size_t*)iter->pSize;
void *pItem;
if (*size == PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "too many array entries");
(*size)++;
if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size))
return false;
@@ -688,7 +701,7 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str
else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
/* Set array count to 0, no need to initialize contents. */
*(size_t*)iter.pSize = 0;
*(pb_size_t*)iter.pSize = 0;
continue;
}
@@ -716,7 +729,7 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str
/* Initialize array count to 0. */
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
*(size_t*)iter.pSize = 0;
*(pb_size_t*)iter.pSize = 0;
}
}
else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
@@ -876,7 +889,7 @@ void pb_release(const pb_field_t fields[], void *dest_struct)
{
/* Release entries in repeated string or bytes array */
void **pItem = *(void***)iter.pData;
size_t count = *(size_t*)iter.pSize;
pb_size_t count = *(pb_size_t*)iter.pSize;
while (count--)
{
pb_free(*pItem);
@@ -887,11 +900,11 @@ void pb_release(const pb_field_t fields[], void *dest_struct)
{
/* Release fields in submessages */
void *pItem = *(void**)iter.pData;
size_t count = (pItem ? 1 : 0);
pb_size_t count = (pItem ? 1 : 0);
if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
{
count = *(size_t*)iter.pSize;
count = *(pb_size_t*)iter.pSize;
}
while (count--)
@@ -1054,7 +1067,12 @@ static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *fie
bdest = (pb_bytes_array_t*)dest;
}
bdest->size = size;
if (size > PB_SIZE_MAX)
{
PB_RETURN_ERROR(stream, "bytes overflow");
}
bdest->size = (pb_size_t)size;
return pb_read(stream, bdest->bytes, size);
}

View File

@@ -246,7 +246,7 @@ static bool checkreturn encode_basic_field(pb_ostream_t *stream,
break;
case PB_HTYPE_REPEATED:
if (!encode_array(stream, field, pData, *(const size_t*)pSize, func))
if (!encode_array(stream, field, pData, *(const pb_size_t*)pSize, func))
return false;
break;
@@ -630,7 +630,6 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *fie
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
/* strnlen() is not always available, so just use a loop */
size_t size = 0;
size_t max_size = field->data_size;
const char *p = (const char*)src;
@@ -644,6 +643,7 @@ static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *fi
}
else
{
/* strnlen() is not always available, so just use a loop */
while (size < max_size && *p != '\0')
{
size++;

View File

@@ -29,17 +29,17 @@ typedef struct _SubMessage {
} SubMessage;
typedef struct {
size_t size;
pb_size_t size;
uint8_t bytes[16];
} AllTypes_req_bytes_t;
typedef struct {
size_t size;
pb_size_t size;
uint8_t bytes[16];
} AllTypes_rep_bytes_t;
typedef struct {
size_t size;
pb_size_t size;
uint8_t bytes[16];
} AllTypes_opt_bytes_t;
@@ -61,39 +61,39 @@ typedef struct _AllTypes {
AllTypes_req_bytes_t req_bytes;
SubMessage req_submsg;
MyEnum req_enum;
size_t rep_int32_count;
pb_size_t rep_int32_count;
int32_t rep_int32[5];
size_t rep_int64_count;
pb_size_t rep_int64_count;
int64_t rep_int64[5];
size_t rep_uint32_count;
pb_size_t rep_uint32_count;
uint32_t rep_uint32[5];
size_t rep_uint64_count;
pb_size_t rep_uint64_count;
uint64_t rep_uint64[5];
size_t rep_sint32_count;
pb_size_t rep_sint32_count;
int32_t rep_sint32[5];
size_t rep_sint64_count;
pb_size_t rep_sint64_count;
int64_t rep_sint64[5];
size_t rep_bool_count;
pb_size_t rep_bool_count;
bool rep_bool[5];
size_t rep_fixed32_count;
pb_size_t rep_fixed32_count;
uint32_t rep_fixed32[5];
size_t rep_sfixed32_count;
pb_size_t rep_sfixed32_count;
int32_t rep_sfixed32[5];
size_t rep_float_count;
pb_size_t rep_float_count;
float rep_float[5];
size_t rep_fixed64_count;
pb_size_t rep_fixed64_count;
uint64_t rep_fixed64[5];
size_t rep_sfixed64_count;
pb_size_t rep_sfixed64_count;
int64_t rep_sfixed64[5];
size_t rep_double_count;
pb_size_t rep_double_count;
double rep_double[5];
size_t rep_string_count;
pb_size_t rep_string_count;
char rep_string[5][16];
size_t rep_bytes_count;
pb_size_t rep_bytes_count;
AllTypes_rep_bytes_t rep_bytes[5];
size_t rep_submsg_count;
pb_size_t rep_submsg_count;
SubMessage rep_submsg[5];
size_t rep_enum_count;
pb_size_t rep_enum_count;
MyEnum rep_enum[5];
bool has_opt_int32;
int32_t opt_int32;

View File

@@ -170,7 +170,7 @@ int main()
{
pb_istream_t s;
struct { size_t size; uint8_t bytes[5]; } d;
struct { pb_size_t size; uint8_t bytes[5]; } d;
pb_field_t f = {1, PB_LTYPE_BYTES, 0, 0, sizeof(d), 0, 0};
COMMENT("Test pb_dec_bytes")
@@ -251,7 +251,7 @@ int main()
{
pb_istream_t s;
CallbackArray dest;
struct { size_t size; uint8_t bytes[10]; } ref;
struct { pb_size_t size; uint8_t bytes[10]; } ref;
dest.data.funcs.decode = &callback_check;
dest.data.arg = &ref;

View File

@@ -170,7 +170,7 @@ int main()
{
uint8_t buffer[30];
pb_ostream_t s;
struct { size_t size; uint8_t bytes[5]; } value = {5, {'x', 'y', 'z', 'z', 'y'}};
struct { pb_size_t size; uint8_t bytes[5]; } value = {5, {'x', 'y', 'z', 'z', 'y'}};
COMMENT("Test pb_enc_bytes")
TEST(WRITES(pb_enc_bytes(&s, &BytesMessage_fields[0], &value), "\x05xyzzy"))