summaryrefslogtreecommitdiffstats
path: root/pb_decode.c
diff options
context:
space:
mode:
authorPetteri Aimonen <jpa@git.mail.kapsi.fi>2013-02-06 21:44:40 +0200
committerPetteri Aimonen <jpa@git.mail.kapsi.fi>2013-02-06 21:52:59 +0200
commitd23939d688b36bf9b474ab9077d4a42b69b8442d (patch)
treea56aa54751c3a40cde82bab72d53804795456e9c /pb_decode.c
parent4ba6a3027d7a5d8c17abeb031622389f8be234fe (diff)
Avoid unnecessary looping in required fields check.
Results for ARM: -6% execution time, -1% code size
Diffstat (limited to 'pb_decode.c')
-rw-r--r--pb_decode.c33
1 files changed, 26 insertions, 7 deletions
diff --git a/pb_decode.c b/pb_decode.c
index b664fe1..7c3407c 100644
--- a/pb_decode.c
+++ b/pb_decode.c
@@ -501,15 +501,34 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
}
/* Check that all required fields were present. */
- pb_field_init(&iter, fields, dest_struct);
- do {
- if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED &&
- iter.required_field_index < PB_MAX_REQUIRED_FIELDS &&
- !(fields_seen[iter.required_field_index >> 3] & (1 << (iter.required_field_index & 7))))
+ {
+ /* First figure out the number of required fields by
+ * seeking to the end of the field array. Usually we
+ * are already close to end after decoding.
+ */
+ int req_field_count;
+ uint8_t last_type;
+ int i;
+ do {
+ req_field_count = iter.required_field_index;
+ last_type = iter.current->type;
+ } while (pb_field_next(&iter));
+
+ /* Fixup if last field was also required. */
+ if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED)
+ req_field_count++;
+
+ /* Check the whole bytes */
+ for (i = 0; i < (req_field_count >> 3); i++)
{
- PB_RETURN_ERROR(stream, "missing required field");
+ if (fields_seen[i] != 0xFF)
+ PB_RETURN_ERROR(stream, "missing required field");
}
- } while (pb_field_next(&iter));
+
+ /* Check the remaining bits */
+ if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7))))
+ PB_RETURN_ERROR(stream, "missing required field");
+ }
return true;
}