diff options
Diffstat (limited to 'upb/encode.c')
-rw-r--r-- | upb/encode.c | 68 |
1 files changed, 24 insertions, 44 deletions
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)); } } |