Track buffer end instead of buffer length, for a small perf improvement.

pull/13171/head
Joshua Haberman 14 years ago
parent 5edfe9a4c9
commit f9a6f67e27
  1. 46
      src/upb_decoder.c
  2. 6
      src/upb_decoder.h
  3. 29
      src/upb_def.h
  4. 2
      src/upb_stream.h

@ -81,6 +81,33 @@ done:
return true; 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 #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) { INLINE void upb_decoder_advance(upb_decoder *d, size_t len) {
d->ptr += 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) { 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. // from the stream to "data", adjusting the dstate appropriately.
static bool upb_getbuf(upb_decoder *d, void *data, size_t bytes_wanted) { static bool upb_getbuf(upb_decoder *d, void *data, size_t bytes_wanted) {
while (1) { 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); memcpy(data, d->ptr, to_copy);
upb_decoder_advance(d, to_copy); upb_decoder_advance(d, to_copy);
bytes_wanted -= 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); upb_string_recycle(&d->buf);
if (!upb_bytesrc_getstr(d->bytesrc, d->buf, d->status)) return false; if (!upb_bytesrc_getstr(d->bytesrc, d->buf, d->status)) return false;
d->ptr = upb_string_getrobuf(d->buf); 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; uint32_t tag_int;
upb_value val; upb_value val;
// Nearly all tag varints will be either 1 byte (1-16) or 2 bytes (17-2048). // 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; tag_int = *p & 0x7f;
if ((*(p++) & 0x80) == 0) goto done; // predictable if fields are in order if ((*(p++) & 0x80) == 0) goto done; // predictable if fields are in order
tag_int |= (*p & 0x7f) << 7; tag_int |= (*p & 0x7f) << 7;
@ -189,7 +219,7 @@ done:
} }
INLINE bool upb_decode_varint(upb_decoder *d, upb_value *val) { INLINE bool upb_decode_varint(upb_decoder *d, upb_value *val) {
if (d->len >= 16) { if (upb_decoder_bufleft(d) >= 16) {
// Common (fast) case. // Common (fast) case.
uint64_t val64; uint64_t val64;
const char *p = d->ptr; 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) { 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. // Common (fast) case.
memcpy(val, d->ptr, bytes); memcpy(val, d->ptr, bytes);
upb_decoder_advance(d, 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 **str) {
upb_string_recycle(str); upb_string_recycle(str);
uint32_t strlen = upb_value_getint32(*val); uint32_t strlen = upb_value_getint32(*val);
if (d->len >= strlen) { if (upb_decoder_bufleft(d) >= strlen) {
// Common (fast) case. // Common (fast) case.
upb_string_substr(*str, d->buf, d->ptr - upb_string_getrobuf(d->buf), strlen); upb_string_substr(*str, d->buf, d->ptr - upb_string_getrobuf(d->buf), strlen);
upb_decoder_advance(d, 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; upb_decoder *d = (upb_decoder*)src;
d->status = status; d->status = status;
d->ptr = NULL; 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->submsg_end = (void*)0x1; // But don't let end-of-message get triggered.
d->msgdef = d->top->msgdef; d->msgdef = d->top->msgdef;

@ -62,12 +62,12 @@ struct _upb_decoder {
// Our current position in the data buffer. // Our current position in the data buffer.
const char *ptr; const char *ptr;
// End of this buffer, relative to *ptr.
const char *end;
// End of this submessage, relative to *ptr. // End of this submessage, relative to *ptr.
const char *submsg_end; const char *submsg_end;
// Number of bytes available at ptr.
size_t len;
// Msgdef for the current level. // Msgdef for the current level.
upb_msgdef *msgdef; upb_msgdef *msgdef;
}; };

@ -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. // is either a field of a upb_msgdef or contained inside a upb_extensiondef.
// It is also reference-counted. // It is also reference-counted.
typedef struct _upb_fielddef { 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; struct _upb_msgdef *msgdef;
// For the case of an enum or a submessage, points to the def for that type. // For the case of an enum or a submessage, points to the def for that type.
upb_def *def; upb_def *def;
upb_atomic_refcount_t refcount; 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; } upb_fielddef;
// A variety of tests about the type of a field. // A variety of tests about the type of a field.

@ -60,7 +60,7 @@ struct _upb_fielddef;
// continue or not. // continue or not.
typedef enum { typedef enum {
// Caller should continue sending values to the sink. // 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, // 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 // a generic error will be returned. If the error is resumable, it is not

Loading…
Cancel
Save