summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Haberman <jhaberman@gmail.com>2011-03-21 10:44:19 -0700
committerJoshua Haberman <jhaberman@gmail.com>2011-03-21 10:44:19 -0700
commit484809c272df7b1f05e56d09f6a5e8e0f340cac4 (patch)
tree3b8c70dc4b14e68dc3e1c34024fd795b69af7715
parentb796c1b31729e3e8f2501c30c0b8856f773b555c (diff)
Key dispatch table by (num x type), for modest perf improvement.
This allows us to remove one type check in the critical path.
-rw-r--r--src/upb_decoder.c34
-rw-r--r--src/upb_stream.c13
-rw-r--r--src/upb_stream.h1
3 files changed, 17 insertions, 31 deletions
diff --git a/src/upb_decoder.c b/src/upb_decoder.c
index a3d00bb..6c23c22 100644
--- a/src/upb_decoder.c
+++ b/src/upb_decoder.c
@@ -111,25 +111,22 @@ typedef struct {
upb_field_number_t field_number;
} upb_tag;
-INLINE bool upb_decode_tag(upb_decoder *d, upb_tag *tag) {
+INLINE bool upb_decode_tag(upb_decoder *d, uint32_t *tag) {
const char *p = d->ptr;
- uint32_t tag_int;
upb_value val;
// Nearly all tag varints will be either 1 byte (1-16) or 2 bytes (17-2048).
if (upb_decoder_bufleft(d) < 2) goto slow; // unlikely.
- tag_int = *p & 0x7f;
+ *tag = *p & 0x7f;
if ((*(p++) & 0x80) == 0) goto done; // predictable if fields are in order
- tag_int |= (*p & 0x7f) << 7;
+ *tag |= (*p & 0x7f) << 7;
if ((*(p++) & 0x80) == 0) goto done; // likely
slow:
// Decode a full varint starting over from ptr.
if (!upb_decode_varint_slow(d, &val)) return false;
- tag_int = upb_value_getint64(val);
+ *tag = upb_value_getint64(val);
p = d->ptr; // Trick the next line into not overwriting us.
done:
upb_decoder_advance(d, p - d->ptr);
- tag->wire_type = (upb_wire_type_t)(tag_int & 0x07);
- tag->field_number = tag_int >> 3;
return true;
}
@@ -251,7 +248,7 @@ void upb_decoder_decode(upb_decoder *d, upb_status *status) {
#endif
// Parse/handle tag.
- upb_tag tag;
+ uint32_t tag;
if (!upb_decode_tag(d, &tag)) {
if (status->code == UPB_EOF && upb_dispatcher_stackempty(&d->dispatcher)) {
// Normal end-of-file.
@@ -270,7 +267,8 @@ void upb_decoder_decode(upb_decoder *d, upb_status *status) {
// Decode wire data. Hopefully this branch will predict pretty well
// since most types will read a varint here.
upb_value val;
- switch (tag.wire_type) {
+ uint8_t wire_type = tag & 0x7;
+ switch (wire_type) {
case UPB_WIRE_TYPE_START_GROUP:
break; // Nothing to do now, below we will push appropriately.
case UPB_WIRE_TYPE_END_GROUP:
@@ -294,26 +292,16 @@ void upb_decoder_decode(upb_decoder *d, upb_status *status) {
}
// Look up field by tag number.
- upb_dispatcher_field *f =
- upb_dispatcher_lookup(&d->dispatcher, tag.field_number);
+ upb_dispatcher_field *f = upb_dispatcher_lookup(&d->dispatcher, tag);
if (!f) {
- if (tag.wire_type == UPB_WIRE_TYPE_DELIMITED)
+ if (wire_type == UPB_WIRE_TYPE_DELIMITED)
CHECK(upb_decode_string(d, &val, &d->tmp));
- CHECK_FLOW(upb_dispatch_unknownval(&d->dispatcher, tag.field_number, val));
+ // TODO.
+ CHECK_FLOW(upb_dispatch_unknownval(&d->dispatcher, 0, UPB_NO_VALUE));
continue;
}
- if (tag.wire_type != f->native_wire_type) {
- // TODO: Support packed fields.
- upb_seterr(status, UPB_ERROR, "Field had incorrect type, field number: %d"
- ", field type: %d, expected wire type: %d, "
- "actual wire type: %d, offset: %d",
- tag.field_number, f->type, upb_types[f->type].native_wire_type,
- tag.wire_type, upb_decoder_offset(d));
- goto err;
- }
-
// Perform any further massaging of the data now that we have the field's
// type. Now we can distinguish strings from submessages, and we know
// about zig-zag-encoded types.
diff --git a/src/upb_stream.c b/src/upb_stream.c
index af266dc..3b0119c 100644
--- a/src/upb_stream.c
+++ b/src/upb_stream.c
@@ -77,17 +77,16 @@ void upb_handlers_uninit(upb_handlers *h) {
static upb_handlers_fieldent *upb_handlers_getorcreate_without_fval(
upb_handlers *h, upb_field_number_t fieldnum, upb_fieldtype_t type) {
+ uint32_t tag = fieldnum << 3 | upb_types[type].native_wire_type;
upb_handlers_fieldent *f =
- upb_inttable_lookup(&h->msgent->fieldtab, fieldnum);
+ upb_inttable_lookup(&h->msgent->fieldtab, tag);
if (!f) {
- upb_wire_type_t native_wire_type = upb_types[type].native_wire_type;
- upb_handlers_fieldent new_f = {
- false, type, native_wire_type, -1, UPB_NO_VALUE,
+ upb_handlers_fieldent new_f = {false, type, -1, UPB_NO_VALUE,
{&upb_value_nop}, &upb_endsubmsg_nop};
if (upb_issubmsgtype(type)) new_f.cb.startsubmsg = &upb_startsubmsg_nop;
- upb_inttable_insert(&h->msgent->fieldtab, fieldnum, &new_f);
+ upb_inttable_insert(&h->msgent->fieldtab, tag, &new_f);
- f = upb_inttable_lookup(&h->msgent->fieldtab, fieldnum);
+ f = upb_inttable_lookup(&h->msgent->fieldtab, tag);
assert(f);
}
assert(f->type == type);
@@ -223,7 +222,7 @@ void upb_handlers_pop(upb_handlers *h, upb_fielddef *f) {
/* upb_dispatcher *************************************************************/
static upb_handlers_fieldent toplevel_f = {
- false, 0, 0, 0, // The one value that is actually read
+ false, 0, 0, // The one value that is actually read
#ifdef NDEBUG
{{0}},
#else
diff --git a/src/upb_stream.h b/src/upb_stream.h
index f2ae11c..783f6c8 100644
--- a/src/upb_stream.h
+++ b/src/upb_stream.h
@@ -84,7 +84,6 @@ typedef upb_flow_t (*upb_unknownval_handler_t)(
typedef struct {
bool junk;
upb_fieldtype_t type;
- upb_wire_type_t native_wire_type;
// For upb_issubmsg(f) only, the index into the msgdef array of the submsg.
// -1 if unset (indicates that submsg should be skipped).
int32_t msgent_index;
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback