diff options
Diffstat (limited to 'upb')
-rw-r--r-- | upb/decode.c | 28 | ||||
-rw-r--r-- | upb/encode.c | 68 | ||||
-rw-r--r-- | upb/msg.c | 36 | ||||
-rw-r--r-- | upb/msg.h | 25 | ||||
-rw-r--r-- | upb/msgfactory.c | 102 |
5 files changed, 59 insertions, 200 deletions
diff --git a/upb/decode.c b/upb/decode.c index b3de9b1..cd13125 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -200,19 +200,9 @@ static void *upb_array_add(upb_array *arr, size_t elements) { return ret; } -static size_t get_field_offset(const upb_decframe *frame, - const upb_msglayout_field *field) { - if (field->oneof_index == UPB_NOT_IN_ONEOF) { - return field->offset; - } else { - return frame->m->oneofs[field->oneof_index].data_offset; - } -} - static upb_array *upb_getarr(upb_decframe *frame, const upb_msglayout_field *field) { UPB_ASSERT(field->label == UPB_LABEL_REPEATED); - UPB_ASSERT(field->oneof_index == UPB_NOT_IN_ONEOF); return *(upb_array**)&frame->msg[field->offset]; } @@ -234,20 +224,20 @@ static upb_array *upb_getorcreatearr(upb_decframe *frame, static void upb_sethasbit(upb_decframe *frame, const upb_msglayout_field *field) { - UPB_ASSERT(field->hasbit != UPB_NO_HASBIT); - frame->msg[field->hasbit / 8] |= (1 << (field->hasbit % 8)); + int32_t hasbit = field->presence; + UPB_ASSERT(field->presence > 0); + frame->msg[hasbit / 8] |= (1 << (hasbit % 8)); } static void upb_setoneofcase(upb_decframe *frame, const upb_msglayout_field *field) { - UPB_ASSERT(field->oneof_index != UPB_NOT_IN_ONEOF); - upb_set32(frame->msg, frame->m->oneofs[field->oneof_index].case_offset, - field->number); + UPB_ASSERT(field->presence < 0); + upb_set32(frame->msg, ~field->presence, field->number); } static char *upb_decode_prepareslot(upb_decframe *frame, const upb_msglayout_field *field) { - char *field_mem = frame->msg + get_field_offset(frame, field); + char *field_mem = frame->msg + field->offset; upb_array *arr; if (field->label == UPB_LABEL_REPEATED) { @@ -264,9 +254,9 @@ static void upb_decode_setpresent(upb_decframe *frame, upb_array *arr = upb_getarr(frame, field); UPB_ASSERT(arr->len < arr->size); arr->len++; - } else if (field->oneof_index != UPB_NOT_IN_ONEOF) { + } else if (field->presence < 0) { upb_setoneofcase(frame, field); - } else if (field->hasbit != UPB_NO_HASBIT) { + } else if (field->presence > 0) { upb_sethasbit(frame, field); } } @@ -279,7 +269,6 @@ static bool upb_decode_submsg(upb_decstate *d, upb_decframe *frame, char *submsg = *(void **)submsg_slot; const upb_msglayout *subm; - UPB_ASSERT(field->submsg_index != UPB_NO_SUBMSG); subm = frame->m->submsgs[field->submsg_index]; UPB_ASSERT(subm); @@ -460,7 +449,6 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame, d->ptr -= val.size; /* Create elemente message. */ - UPB_ASSERT(field->submsg_index != UPB_NO_SUBMSG); subm = frame->m->submsgs[field->submsg_index]; UPB_ASSERT(subm); diff --git a/upb/encode.c b/upb/encode.c index 034a90d..a9f2c0d 100644 --- a/upb/encode.c +++ b/upb/encode.c @@ -126,16 +126,17 @@ static bool upb_put_float(upb_encstate *e, float d) { return upb_put_fixed32(e, u32); } -static uint32_t upb_readcase(const char *msg, const upb_msglayout *m, - int oneof_index) { +static uint32_t upb_readcase(const char *msg, const upb_msglayout_field *f) { uint32_t ret; - memcpy(&ret, msg + m->oneofs[oneof_index].case_offset, sizeof(ret)); + uint32_t offset = ~f->presence; + memcpy(&ret, msg + offset, sizeof(ret)); return ret; } static bool upb_readhasbit(const char *msg, const upb_msglayout_field *f) { - UPB_ASSERT(f->hasbit != UPB_NO_HASBIT); - return msg[f->hasbit / 8] & (1 << (f->hasbit % 8)); + uint32_t hasbit = f->presence; + UPB_ASSERT(f->presence > 0); + return msg[hasbit / 8] & (1 << (hasbit % 8)); } static bool upb_put_tag(upb_encstate *e, int field_number, int wire_type) { @@ -254,9 +255,7 @@ do { ; } while(0) static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem, const upb_msglayout *m, const upb_msglayout_field *f, - bool is_proto3) { - bool skip_zero_value = is_proto3 && f->oneof_index == UPB_NOT_IN_ONEOF; - + bool skip_zero_value) { #define CASE(ctype, type, wire_type, encodeval) do { \ ctype val = *(ctype*)field_mem; \ if (skip_zero_value && val == 0) { \ @@ -305,7 +304,7 @@ static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem, size_t size; void *submsg = *(void **)field_mem; const upb_msglayout *subm = m->submsgs[f->submsg_index]; - if (skip_zero_value && submsg == NULL) { + if (submsg == NULL) { return true; } return upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) && @@ -316,7 +315,7 @@ static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem, size_t size; void *submsg = *(void **)field_mem; const upb_msglayout *subm = m->submsgs[f->submsg_index]; - if (skip_zero_value && submsg == NULL) { + if (submsg == NULL) { return true; } return upb_encode_message(e, submsg, subm, &size) && @@ -328,52 +327,33 @@ static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem, UPB_UNREACHABLE(); } -bool upb_encode_hasscalarfield(const char *msg, const upb_msglayout *m, - const upb_msglayout_field *f) { - if (f->oneof_index != UPB_NOT_IN_ONEOF) { - return upb_readcase(msg, m, f->oneof_index) == f->number; - } else if (m->is_proto2) { - return upb_readhasbit(msg, f); - } else { - /* For proto3, we'll test for the field being empty later. */ - return true; - } -} - -static size_t get_field_offset2(const upb_msglayout *m, - const upb_msglayout_field *field) { - if (field->oneof_index == UPB_NOT_IN_ONEOF) { - return field->offset; - } else { - return m->oneofs[field->oneof_index].data_offset; - } -} - bool upb_encode_message(upb_encstate *e, const char *msg, const upb_msglayout *m, size_t *size) { int i; size_t pre_len = e->limit - e->ptr; - if (msg == NULL) { - return true; - } - for (i = m->field_count - 1; i >= 0; i--) { const upb_msglayout_field *f = &m->fields[i]; - size_t offset = get_field_offset2(m, f); if (f->label == UPB_LABEL_REPEATED) { - CHK(upb_encode_array(e, msg + offset, m, f)); + CHK(upb_encode_array(e, msg + f->offset, m, f)); } else { - if (upb_encode_hasscalarfield(msg, m, f)) { - if (f->oneof_index == UPB_NOT_IN_ONEOF) { - CHK(upb_encode_scalarfield(e, msg + offset, m, f, !m->is_proto2)); - } else { - const upb_msglayout_oneof *o = &m->oneofs[f->oneof_index]; - CHK(upb_encode_scalarfield(e, msg + o->data_offset, - m, f, !m->is_proto2)); + bool skip_empty = false; + if (f->presence == 0) { + /* Proto3 presence. */ + skip_empty = true; + } else if (f->presence > 0) { + /* Proto2 presence: hasbit. */ + if (!upb_readhasbit(msg, f)) { + continue; + } + } else { + /* Field is in a oneof. */ + if (upb_readcase(msg, f) != f->number) { + continue; } } + CHK(upb_encode_scalarfield(e, msg + f->offset, m, f, skip_empty)); } } @@ -148,14 +148,14 @@ static const upb_msglayout_field *upb_msg_checkfield(int field_index, } static bool upb_msg_inoneof(const upb_msglayout_field *field) { - return field->oneof_index != UPB_NOT_IN_ONEOF; + return field->presence < 0; } static uint32_t *upb_msg_oneofcase(const upb_msg *msg, int field_index, const upb_msglayout *l) { const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); UPB_ASSERT(upb_msg_inoneof(field)); - return PTR_AT(msg, l->oneofs[field->oneof_index].case_offset, uint32_t); + return PTR_AT(msg, ~field->presence, uint32_t); } static size_t upb_msg_sizeof(const upb_msglayout *l) { @@ -174,11 +174,7 @@ upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) { msg = VOIDPTR_AT(mem, upb_msg_internalsize(l)); /* Initialize normal members. */ - if (l->default_msg) { - memcpy(msg, l->default_msg, l->size); - } else { - memset(msg, 0, l->size); - } + memset(msg, 0, l->size); /* Initialize internal members. */ upb_msg_getinternal(msg)->arena = a; @@ -199,14 +195,14 @@ bool upb_msg_has(const upb_msg *msg, const upb_msglayout *l) { const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); - UPB_ASSERT(l->is_proto2); + UPB_ASSERT(field->presence); if (upb_msg_inoneof(field)) { /* Oneofs are set when the oneof number is set to this field. */ return *upb_msg_oneofcase(msg, field_index, l) == field->number; } else { /* Other fields are set when their hasbit is set. */ - uint32_t hasbit = l->fields[field_index].hasbit; + uint32_t hasbit = field->presence; return DEREF(msg, hasbit / 8, char) | (1 << (hasbit % 8)); } } @@ -215,32 +211,14 @@ upb_msgval upb_msg_get(const upb_msg *msg, int field_index, const upb_msglayout *l) { const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); int size = upb_msg_fieldsize(field); - - if (upb_msg_inoneof(field)) { - if (*upb_msg_oneofcase(msg, field_index, l) == field->number) { - size_t ofs = l->oneofs[field->oneof_index].data_offset; - return upb_msgval_read(msg, ofs, size); - } else { - /* Return default. */ - return upb_msgval_read(l->default_msg, field->offset, size); - } - } else { - return upb_msgval_read(msg, field->offset, size); - } + return upb_msgval_read(msg, field->offset, size); } void upb_msg_set(upb_msg *msg, int field_index, upb_msgval val, const upb_msglayout *l) { const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); int size = upb_msg_fieldsize(field); - - if (upb_msg_inoneof(field)) { - size_t ofs = l->oneofs[field->oneof_index].data_offset; - *upb_msg_oneofcase(msg, field_index, l) = field->number; - upb_msgval_write(msg, ofs, val, size); - } else { - upb_msgval_write(msg, field->offset, val, size); - } + upb_msgval_write(msg, field->offset, val, size); } @@ -53,42 +53,25 @@ typedef void upb_msg; * members are public so generated code can initialize them, but users MUST NOT * read or write any of its members. */ -#define UPB_NOT_IN_ONEOF UINT16_MAX -#define UPB_NO_HASBIT UINT16_MAX -#define UPB_NO_SUBMSG UINT16_MAX - typedef struct { uint32_t number; - uint32_t offset; /* If in a oneof, offset of default in default_msg below. */ - uint16_t hasbit; /* UPB_NO_HASBIT if no hasbit. */ - uint16_t oneof_index; /* UPB_NOT_IN_ONEOF if not in a oneof. */ - uint16_t submsg_index; /* UPB_NO_SUBMSG if no submsg. */ + uint16_t offset; + int16_t presence; /* If >0, hasbit_index+1. If <0, oneof_index+1. */ + uint16_t submsg_index; /* undefined if descriptortype != MESSAGE or GROUP. */ uint8_t descriptortype; uint8_t label; } upb_msglayout_field; -typedef struct { - uint32_t data_offset; - uint32_t case_offset; -} upb_msglayout_oneof; - typedef struct upb_msglayout { const struct upb_msglayout *const* submsgs; const upb_msglayout_field *fields; - const upb_msglayout_oneof *oneofs; - void *default_msg; /* Must be aligned to sizeof(void*). Doesn't include internal members like * unknown fields, extension dict, pointer to msglayout, etc. */ - uint32_t size; + uint16_t size; uint16_t field_count; - uint16_t oneof_count; bool extendable; - bool is_proto2; } upb_msglayout; -#define UPB_ALIGN_UP_TO(val, align) ((val + (align - 1)) & -align) -#define UPB_ALIGNED_SIZEOF(type) UPB_ALIGN_UP_TO(sizeof(type), sizeof(void*)) - /** upb_stringview ************************************************************/ diff --git a/upb/msgfactory.c b/upb/msgfactory.c index b544967..593c9dc 100644 --- a/upb/msgfactory.c +++ b/upb/msgfactory.c @@ -45,42 +45,10 @@ static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { } } -static upb_msgval upb_msgval_fromdefault(const upb_fielddef *f) { - switch (upb_fielddef_type(f)) { - case UPB_TYPE_FLOAT: - return upb_msgval_float(upb_fielddef_defaultfloat(f)); - case UPB_TYPE_DOUBLE: - return upb_msgval_double(upb_fielddef_defaultdouble(f)); - case UPB_TYPE_BOOL: - return upb_msgval_bool(upb_fielddef_defaultbool(f)); - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - size_t len; - const char *ptr = upb_fielddef_defaultstr(f, &len); - return upb_msgval_makestr(ptr, len); - } - case UPB_TYPE_MESSAGE: - return upb_msgval_msg(NULL); - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: - return upb_msgval_int32(upb_fielddef_defaultint32(f)); - case UPB_TYPE_UINT32: - return upb_msgval_uint32(upb_fielddef_defaultuint32(f)); - case UPB_TYPE_INT64: - return upb_msgval_int64(upb_fielddef_defaultint64(f)); - case UPB_TYPE_UINT64: - return upb_msgval_uint64(upb_fielddef_defaultuint64(f)); - default: - UPB_ASSERT(false); - return upb_msgval_msg(NULL); - } -} - /** upb_msglayout *************************************************************/ static void upb_msglayout_free(upb_msglayout *l) { - upb_gfree(l->default_msg); upb_gfree(l); } @@ -93,38 +61,6 @@ static size_t upb_msglayout_place(upb_msglayout *l, size_t size) { return ret; } -static bool upb_msglayout_initdefault(upb_msglayout *l, const upb_msgdef *m) { - upb_msg_field_iter it; - - if (upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2 && l->size) { - /* Allocate default message and set default values in it. */ - l->default_msg = upb_gmalloc(l->size); - if (!l->default_msg) { - return false; - } - - memset(l->default_msg, 0, l->size); - - for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef *f = upb_msg_iter_field(&it); - - if (upb_fielddef_containingoneof(f)) { - continue; - } - - /* TODO(haberman): handle strings. */ - if (!upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f) && - !upb_fielddef_isseq(f)) { - upb_msg_set(l->default_msg, upb_fielddef_index(f), - upb_msgval_fromdefault(f), l); - } - } - } - - return true; -} - static bool upb_msglayout_init(const upb_msgdef *m, upb_msglayout *l, upb_msgfactory *factory) { @@ -134,7 +70,6 @@ static bool upb_msglayout_init(const upb_msgdef *m, size_t submsg_count = 0; const upb_msglayout **submsgs; upb_msglayout_field *fields; - upb_msglayout_oneof *oneofs; for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); @@ -149,24 +84,18 @@ static bool upb_msglayout_init(const upb_msgdef *m, fields = upb_gmalloc(upb_msgdef_numfields(m) * sizeof(*fields)); submsgs = upb_gmalloc(submsg_count * sizeof(*submsgs)); - oneofs = upb_gmalloc(upb_msgdef_numoneofs(m) * sizeof(*oneofs)); if ((!fields && upb_msgdef_numfields(m)) || - (!submsgs && submsg_count) || - (!oneofs && upb_msgdef_numoneofs(m))) { + (!submsgs && submsg_count)) { /* OOM. */ upb_gfree(fields); upb_gfree(submsgs); - upb_gfree(oneofs); return false; } l->field_count = upb_msgdef_numfields(m); - l->oneof_count = upb_msgdef_numoneofs(m); l->fields = fields; l->submsgs = submsgs; - l->oneofs = oneofs; - l->is_proto2 = (upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2); /* Allocate data offsets in three stages: * @@ -189,25 +118,17 @@ static bool upb_msglayout_init(const upb_msgdef *m, field->descriptortype = upb_fielddef_descriptortype(f); field->label = upb_fielddef_label(f); - if (upb_fielddef_containingoneof(f)) { - field->oneof_index = upb_oneofdef_index(upb_fielddef_containingoneof(f)); - } else { - field->oneof_index = UPB_NOT_IN_ONEOF; - } - if (upb_fielddef_issubmsg(f)) { const upb_msglayout *sub_layout = upb_msgfactory_getlayout(factory, upb_fielddef_msgsubdef(f)); field->submsg_index = submsg_count++; submsgs[field->submsg_index] = sub_layout; - } else { - field->submsg_index = UPB_NO_SUBMSG; } if (upb_fielddef_haspresence(f) && !upb_fielddef_containingoneof(f)) { - field->hasbit = hasbit++; + field->presence = (hasbit++); } else { - field->hasbit = UPB_NO_HASBIT; + field->presence = 0; } } @@ -237,8 +158,9 @@ static bool upb_msglayout_init(const upb_msgdef *m, upb_oneof_iter fit; size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ - upb_msglayout_oneof *oneof = &oneofs[upb_oneofdef_index(o)]; size_t field_size = 0; + uint32_t case_offset; + uint32_t data_offset; /* Calculate field size: the max of all field sizes. */ for (upb_oneof_begin(&fit, o); @@ -249,15 +171,23 @@ static bool upb_msglayout_init(const upb_msgdef *m, } /* Align and allocate case offset. */ - oneof->case_offset = upb_msglayout_place(l, case_size); - oneof->data_offset = upb_msglayout_place(l, field_size); + case_offset = upb_msglayout_place(l, case_size); + data_offset = upb_msglayout_place(l, field_size); + + for (upb_oneof_begin(&fit, o); + !upb_oneof_done(&fit); + upb_oneof_next(&fit)) { + const upb_fielddef* f = upb_oneof_iter_field(&fit); + fields[upb_fielddef_index(f)].offset = data_offset; + fields[upb_fielddef_index(f)].presence = ~case_offset; + } } /* Size of the entire structure should be a multiple of its greatest * alignment. TODO: track overall alignment for real? */ l->size = align_up(l->size, 8); - return upb_msglayout_initdefault(l, m); + return true; } |