diff --git a/src/upb_decoder.c b/src/upb_decoder.c index 1f70afcd48..9c216d5024 100644 --- a/src/upb_decoder.c +++ b/src/upb_decoder.c @@ -81,6 +81,33 @@ done: return true; } +typedef struct { + const char *newbuf; + uint64_t val; +} retval; + +retval upb_decode_varint_fast64(const char *p) { + uint64_t ret; + uint64_t b; + retval r = {(void*)0, 0}; + b = *(p++); ret = (b & 0x7f) ; if(!(b & 0x80)) goto done; + b = *(p++); ret |= (b & 0x7f) << 7; if(!(b & 0x80)) goto done; + b = *(p++); ret |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done; + b = *(p++); ret |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done; + b = *(p++); ret |= (b & 0x7f) << 28; if(!(b & 0x80)) goto done; + b = *(p++); ret |= (b & 0x7f) << 35; if(!(b & 0x80)) goto done; + b = *(p++); ret |= (b & 0x7f) << 42; if(!(b & 0x80)) goto done; + b = *(p++); ret |= (b & 0x7f) << 49; if(!(b & 0x80)) goto done; + b = *(p++); ret |= (b & 0x7f) << 56; if(!(b & 0x80)) goto done; + b = *(p++); ret |= (b & 0x7f) << 63; if(!(b & 0x80)) goto done; + return r; + +done: + r.val = ret; + r.newbuf = p; + return r; +} + #endif @@ -98,7 +125,10 @@ INLINE int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); } INLINE void upb_decoder_advance(upb_decoder *d, size_t len) { d->ptr += len; - d->len -= len; +} + +INLINE size_t upb_decoder_bufleft(upb_decoder *d) { + return d->end - d->ptr; } INLINE void upb_dstate_setmsgend(upb_decoder *d) { @@ -113,7 +143,7 @@ static upb_flow_t upb_pop(upb_decoder *d); // from the stream to "data", adjusting the dstate appropriately. static bool upb_getbuf(upb_decoder *d, void *data, size_t bytes_wanted) { while (1) { - size_t to_copy = UPB_MIN(bytes_wanted, d->len); + size_t to_copy = UPB_MIN(bytes_wanted, upb_decoder_bufleft(d)); memcpy(data, d->ptr, to_copy); upb_decoder_advance(d, to_copy); bytes_wanted -= to_copy; @@ -127,7 +157,7 @@ static bool upb_getbuf(upb_decoder *d, void *data, size_t bytes_wanted) { upb_string_recycle(&d->buf); if (!upb_bytesrc_getstr(d->bytesrc, d->buf, d->status)) return false; d->ptr = upb_string_getrobuf(d->buf); - d->len = upb_string_len(d->buf); + d->end = d->ptr + upb_string_len(d->buf); } } @@ -171,7 +201,7 @@ INLINE bool upb_decode_tag(upb_decoder *d, upb_tag *tag) { uint32_t tag_int; upb_value val; // Nearly all tag varints will be either 1 byte (1-16) or 2 bytes (17-2048). - if (d->len < 2) goto slow; // unlikely. + if (upb_decoder_bufleft(d) < 2) goto slow; // unlikely. tag_int = *p & 0x7f; if ((*(p++) & 0x80) == 0) goto done; // predictable if fields are in order tag_int |= (*p & 0x7f) << 7; @@ -189,7 +219,7 @@ done: } INLINE bool upb_decode_varint(upb_decoder *d, upb_value *val) { - if (d->len >= 16) { + if (upb_decoder_bufleft(d) >= 16) { // Common (fast) case. uint64_t val64; const char *p = d->ptr; @@ -203,7 +233,7 @@ INLINE bool upb_decode_varint(upb_decoder *d, upb_value *val) { } INLINE bool upb_decode_fixed(upb_decoder *d, size_t bytes, upb_value *val) { - if (d->len >= bytes) { + if (upb_decoder_bufleft(d) >= bytes) { // Common (fast) case. memcpy(val, d->ptr, bytes); upb_decoder_advance(d, bytes); @@ -219,7 +249,7 @@ INLINE bool upb_decode_string(upb_decoder *d, upb_value *val, upb_string **str) { upb_string_recycle(str); uint32_t strlen = upb_value_getint32(*val); - if (d->len >= strlen) { + if (upb_decoder_bufleft(d) >= strlen) { // Common (fast) case. upb_string_substr(*str, d->buf, d->ptr - upb_string_getrobuf(d->buf), strlen); upb_decoder_advance(d, strlen); @@ -278,7 +308,7 @@ void upb_decoder_run(upb_src *src, upb_status *status) { upb_decoder *d = (upb_decoder*)src; d->status = status; d->ptr = NULL; - d->len = 0; // Force a buffer pull. + d->end = NULL; // Force a buffer pull. d->submsg_end = (void*)0x1; // But don't let end-of-message get triggered. d->msgdef = d->top->msgdef; diff --git a/src/upb_decoder.h b/src/upb_decoder.h index 9cebe0cb8b..5662c9c3fb 100644 --- a/src/upb_decoder.h +++ b/src/upb_decoder.h @@ -62,12 +62,12 @@ struct _upb_decoder { // Our current position in the data buffer. const char *ptr; + // End of this buffer, relative to *ptr. + const char *end; + // End of this submessage, relative to *ptr. const char *submsg_end; - // Number of bytes available at ptr. - size_t len; - // Msgdef for the current level. upb_msgdef *msgdef; }; diff --git a/src/upb_def.h b/src/upb_def.h index 28cc2586a0..6e4bc258e6 100644 --- a/src/upb_def.h +++ b/src/upb_def.h @@ -88,29 +88,26 @@ INLINE void upb_def_unref(upb_def *def) { // is either a field of a upb_msgdef or contained inside a upb_extensiondef. // It is also reference-counted. typedef struct _upb_fielddef { - upb_value default_value; + uint8_t type; + uint8_t label; + // True if we own a ref on "def" (above). This is true unless this edge is + // part of a cycle. + bool owned; + uint8_t set_bit_mask; - upb_string *name; + int32_t number; + int16_t field_index; // Indicates set bit. + uint16_t set_bit_offset; + uint32_t byte_offset; // Where in a upb_msg to find the data. + + upb_value default_value; + upb_string *name; struct _upb_msgdef *msgdef; // For the case of an enum or a submessage, points to the def for that type. upb_def *def; - upb_atomic_refcount_t refcount; - uint32_t byte_offset; // Where in a upb_msg to find the data. - - // These are set only when this fielddef is part of a msgdef. - upb_field_number_t number; - upb_field_count_t field_index; // Indicates set bit. - - upb_fieldtype_t type; - upb_label_t label; - // True if we own a ref on "def" (above). This is true unless this edge is - // part of a cycle. - bool owned; - uint8_t set_bit_mask; - uint16_t set_bit_offset; } upb_fielddef; // A variety of tests about the type of a field. diff --git a/src/upb_stream.h b/src/upb_stream.h index fe66c638fd..229cf86cd2 100644 --- a/src/upb_stream.h +++ b/src/upb_stream.h @@ -60,7 +60,7 @@ struct _upb_fielddef; // continue or not. typedef enum { // Caller should continue sending values to the sink. - UPB_CONTINUE, + UPB_CONTINUE = 0, // Stop processing for now; check status for details. If no status was set, // a generic error will be returned. If the error is resumable, it is not