From e94ac4f75717f2bd1a617e5633cd502106748475 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Wed, 22 Aug 2018 23:15:12 -0700 Subject: Moved upb_msg parts that depend on def to a separate msgfactory.{c,h}. Also got rid of the premature "v1" business that was attempting to create a binary compatibility story. Also added an in-progress CMakeLists.txt file. --- upb/bindings/lua/upb.h | 1 + upb/decode.c | 55 ++++---- upb/decode.h | 4 +- upb/encode.c | 46 +++---- upb/encode.h | 4 +- upb/msg.c | 354 ++++--------------------------------------------- upb/msg.h | 115 +++++----------- upb/msgfactory.c | 325 +++++++++++++++++++++++++++++++++++++++++++++ upb/msgfactory.h | 40 ++++++ 9 files changed, 474 insertions(+), 470 deletions(-) create mode 100644 upb/msgfactory.c create mode 100644 upb/msgfactory.h (limited to 'upb') diff --git a/upb/bindings/lua/upb.h b/upb/bindings/lua/upb.h index 52bc5a2..820a317 100644 --- a/upb/bindings/lua/upb.h +++ b/upb/bindings/lua/upb.h @@ -9,6 +9,7 @@ #include "upb/def.h" #include "upb/handlers.h" #include "upb/msg.h" +#include "upb/msgfactory.h" /* Lua 5.1/5.2 compatibility code. */ #if LUA_VERSION_NUM == 501 diff --git a/upb/decode.c b/upb/decode.c index ca18e95..8a29709 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -41,7 +41,7 @@ typedef struct { /* These members are unset for an unknown group frame. */ char *msg; - const upb_msglayout_msginit_v1 *m; + const upb_msglayout *m; } upb_decframe; #define CHK(x) if (!(x)) { return false; } @@ -50,7 +50,7 @@ static bool upb_skip_unknowngroup(upb_decstate *d, int field_number, const char *limit); static bool upb_decode_message(upb_decstate *d, const char *limit, int group_number, char *msg, - const upb_msglayout_msginit_v1 *l); + const upb_msglayout *l); static bool upb_decode_varint(const char **ptr, const char *limit, uint64_t *val) { @@ -202,14 +202,13 @@ static void *upb_array_add(upb_array *arr, size_t elements) { } static upb_array *upb_getarr(upb_decframe *frame, - const upb_msglayout_fieldinit_v1 *field) { + const upb_msglayout_field *field) { UPB_ASSERT(field->label == UPB_LABEL_REPEATED); return *(upb_array**)&frame->msg[field->offset]; } -static upb_array *upb_getorcreatearr(upb_decstate *d, - upb_decframe *frame, - const upb_msglayout_fieldinit_v1 *field) { +static upb_array *upb_getorcreatearr(upb_decstate *d, upb_decframe *frame, + const upb_msglayout_field *field) { upb_array *arr = upb_getarr(frame, field); if (!arr) { @@ -225,21 +224,20 @@ static upb_array *upb_getorcreatearr(upb_decstate *d, } static void upb_sethasbit(upb_decframe *frame, - const upb_msglayout_fieldinit_v1 *field) { + const upb_msglayout_field *field) { UPB_ASSERT(field->hasbit != UPB_NO_HASBIT); frame->msg[field->hasbit / 8] |= (1 << (field->hasbit % 8)); } static void upb_setoneofcase(upb_decframe *frame, - const upb_msglayout_fieldinit_v1 *field) { + 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); } -static char *upb_decode_prepareslot(upb_decstate *d, - upb_decframe *frame, - const upb_msglayout_fieldinit_v1 *field) { +static char *upb_decode_prepareslot(upb_decstate *d, upb_decframe *frame, + const upb_msglayout_field *field) { char *field_mem = frame->msg + field->offset; upb_array *arr; @@ -252,7 +250,7 @@ static char *upb_decode_prepareslot(upb_decstate *d, } static void upb_decode_setpresent(upb_decframe *frame, - const upb_msglayout_fieldinit_v1 *field) { + const upb_msglayout_field *field) { if (field->label == UPB_LABEL_REPEATED) { upb_array *arr = upb_getarr(frame, field); UPB_ASSERT(arr->len < arr->size); @@ -264,14 +262,13 @@ static void upb_decode_setpresent(upb_decframe *frame, } } -static bool upb_decode_submsg(upb_decstate *d, - upb_decframe *frame, +static bool upb_decode_submsg(upb_decstate *d, upb_decframe *frame, const char *limit, - const upb_msglayout_fieldinit_v1 *field, + const upb_msglayout_field *field, int group_number) { char *submsg_slot = upb_decode_prepareslot(d, frame, field); - char *submsg = *(void**)submsg_slot; - const upb_msglayout_msginit_v1 *subm; + char *submsg = *(void **)submsg_slot; + const upb_msglayout *subm; UPB_ASSERT(field->submsg_index != UPB_NO_SUBMSG); subm = frame->m->submsgs[field->submsg_index]; @@ -290,7 +287,7 @@ static bool upb_decode_submsg(upb_decstate *d, static bool upb_decode_varintfield(upb_decstate *d, upb_decframe *frame, const char *field_start, - const upb_msglayout_fieldinit_v1 *field) { + const upb_msglayout_field *field) { uint64_t val; void *field_mem; @@ -335,7 +332,7 @@ static bool upb_decode_varintfield(upb_decstate *d, upb_decframe *frame, static bool upb_decode_64bitfield(upb_decstate *d, upb_decframe *frame, const char *field_start, - const upb_msglayout_fieldinit_v1 *field) { + const upb_msglayout_field *field) { void *field_mem; uint64_t val; @@ -359,7 +356,7 @@ static bool upb_decode_64bitfield(upb_decstate *d, upb_decframe *frame, static bool upb_decode_32bitfield(upb_decstate *d, upb_decframe *frame, const char *field_start, - const upb_msglayout_fieldinit_v1 *field) { + const upb_msglayout_field *field) { void *field_mem; uint32_t val; @@ -395,7 +392,7 @@ static bool upb_decode_fixedpacked(upb_array *arr, upb_stringview data, static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame, const char *field_start, - const upb_msglayout_fieldinit_v1 *field, + const upb_msglayout_field *field, upb_stringview val) { upb_array *arr = upb_getorcreatearr(d, frame, field); @@ -446,7 +443,7 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame, case UPB_DESCRIPTOR_TYPE_SINT64: VARINT_CASE(int64_t, upb_zzdecode_64); case UPB_DESCRIPTOR_TYPE_MESSAGE: { - const upb_msglayout_msginit_v1 *subm; + const upb_msglayout *subm; char *submsg; void *field_mem; @@ -477,7 +474,7 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame, static bool upb_decode_delimitedfield(upb_decstate *d, upb_decframe *frame, const char *field_start, - const upb_msglayout_fieldinit_v1 *field) { + const upb_msglayout_field *field) { upb_stringview val; CHK(upb_decode_string(&d->ptr, frame->limit, &val)); @@ -507,8 +504,8 @@ static bool upb_decode_delimitedfield(upb_decstate *d, upb_decframe *frame, } } -static const upb_msglayout_fieldinit_v1 *upb_find_field( - const upb_msglayout_msginit_v1 *l, uint32_t field_number) { +static const upb_msglayout_field *upb_find_field(const upb_msglayout *l, + uint32_t field_number) { /* Lots of optimization opportunities here. */ int i; for (i = 0; i < l->field_count; i++) { @@ -524,7 +521,7 @@ static bool upb_decode_field(upb_decstate *d, upb_decframe *frame) { int field_number; int wire_type; const char *field_start = d->ptr; - const upb_msglayout_fieldinit_v1 *field; + const upb_msglayout_field *field; CHK(upb_decode_tag(&d->ptr, frame->limit, &field_number, &wire_type)); field = upb_find_field(frame->m, field_number); @@ -576,7 +573,7 @@ static bool upb_skip_unknowngroup(upb_decstate *d, int field_number, static bool upb_decode_message(upb_decstate *d, const char *limit, int group_number, char *msg, - const upb_msglayout_msginit_v1 *l) { + const upb_msglayout *l) { upb_decframe frame; frame.group_number = group_number; frame.limit = limit; @@ -590,8 +587,8 @@ static bool upb_decode_message(upb_decstate *d, const char *limit, return true; } -bool upb_decode(upb_stringview buf, void *msg, - const upb_msglayout_msginit_v1 *l, upb_env *env) { +bool upb_decode(upb_stringview buf, void *msg, const upb_msglayout *l, + upb_env *env) { upb_decstate state; state.ptr = buf.data; state.env = env; diff --git a/upb/decode.h b/upb/decode.h index 2a9e39e..963b399 100644 --- a/upb/decode.h +++ b/upb/decode.h @@ -9,8 +9,8 @@ UPB_BEGIN_EXTERN_C -bool upb_decode(upb_stringview buf, void *msg, - const upb_msglayout_msginit_v1 *l, upb_env *env); +bool upb_decode(upb_stringview buf, void *msg, const upb_msglayout *l, + upb_env *env); UPB_END_EXTERN_C diff --git a/upb/encode.c b/upb/encode.c index a017c46..24d72a8 100644 --- a/upb/encode.c +++ b/upb/encode.c @@ -126,15 +126,14 @@ 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_msginit_v1 *m, +static uint32_t upb_readcase(const char *msg, const upb_msglayout *m, int oneof_index) { uint32_t ret; memcpy(&ret, msg + m->oneofs[oneof_index].case_offset, sizeof(ret)); return ret; } -static bool upb_readhasbit(const char *msg, - const upb_msglayout_fieldinit_v1 *f) { +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)); } @@ -150,12 +149,11 @@ static bool upb_put_fixedarray(upb_encstate *e, const upb_array *arr, } bool upb_encode_message(upb_encstate *e, const char *msg, - const upb_msglayout_msginit_v1 *m, - size_t *size); + const upb_msglayout *m, size_t *size); static bool upb_encode_array(upb_encstate *e, const char *field_mem, - const upb_msglayout_msginit_v1 *m, - const upb_msglayout_fieldinit_v1 *f) { + const upb_msglayout *m, + const upb_msglayout_field *f) { const upb_array *arr = *(const upb_array**)field_mem; if (arr == NULL || arr->len == 0) { @@ -221,7 +219,7 @@ do { ; } while(0) case UPB_DESCRIPTOR_TYPE_GROUP: { void **start = arr->data; void **ptr = start + arr->len; - const upb_msglayout_msginit_v1 *subm = m->submsgs[f->submsg_index]; + const upb_msglayout *subm = m->submsgs[f->submsg_index]; do { size_t size; ptr--; @@ -234,7 +232,7 @@ do { ; } while(0) case UPB_DESCRIPTOR_TYPE_MESSAGE: { void **start = arr->data; void **ptr = start + arr->len; - const upb_msglayout_msginit_v1 *subm = m->submsgs[f->submsg_index]; + const upb_msglayout *subm = m->submsgs[f->submsg_index]; do { size_t size; ptr--; @@ -254,8 +252,8 @@ do { ; } while(0) } static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem, - const upb_msglayout_msginit_v1 *m, - const upb_msglayout_fieldinit_v1 *f, + 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; @@ -305,8 +303,8 @@ static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem, } case UPB_DESCRIPTOR_TYPE_GROUP: { size_t size; - void *submsg = *(void**)field_mem; - const upb_msglayout_msginit_v1 *subm = m->submsgs[f->submsg_index]; + void *submsg = *(void **)field_mem; + const upb_msglayout *subm = m->submsgs[f->submsg_index]; if (skip_zero_value && submsg == NULL) { return true; } @@ -316,8 +314,8 @@ static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem, } case UPB_DESCRIPTOR_TYPE_MESSAGE: { size_t size; - void *submsg = *(void**)field_mem; - const upb_msglayout_msginit_v1 *subm = m->submsgs[f->submsg_index]; + void *submsg = *(void **)field_mem; + const upb_msglayout *subm = m->submsgs[f->submsg_index]; if (skip_zero_value && submsg == NULL) { return true; } @@ -330,9 +328,8 @@ static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem, UPB_UNREACHABLE(); } -bool upb_encode_hasscalarfield(const char *msg, - const upb_msglayout_msginit_v1 *m, - const upb_msglayout_fieldinit_v1 *f) { +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) { @@ -343,9 +340,8 @@ bool upb_encode_hasscalarfield(const char *msg, } } -bool upb_encode_message(upb_encstate* e, const char *msg, - const upb_msglayout_msginit_v1 *m, - size_t *size) { +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; @@ -354,7 +350,7 @@ bool upb_encode_message(upb_encstate* e, const char *msg, } for (i = m->field_count - 1; i >= 0; i--) { - const upb_msglayout_fieldinit_v1 *f = &m->fields[i]; + const upb_msglayout_field *f = &m->fields[i]; if (f->label == UPB_LABEL_REPEATED) { CHK(upb_encode_array(e, msg + f->offset, m, f)); @@ -363,7 +359,7 @@ bool upb_encode_message(upb_encstate* e, const char *msg, if (f->oneof_index == UPB_NOT_IN_ONEOF) { CHK(upb_encode_scalarfield(e, msg + f->offset, m, f, !m->is_proto2)); } else { - const upb_msglayout_oneofinit_v1 *o = &m->oneofs[f->oneof_index]; + const upb_msglayout_oneof *o = &m->oneofs[f->oneof_index]; CHK(upb_encode_scalarfield(e, msg + o->data_offset, m, f, !m->is_proto2)); } @@ -375,8 +371,8 @@ bool upb_encode_message(upb_encstate* e, const char *msg, return true; } -char *upb_encode(const void *msg, const upb_msglayout_msginit_v1 *m, - upb_env *env, size_t *size) { +char *upb_encode(const void *msg, const upb_msglayout *m, upb_env *env, + size_t *size) { upb_encstate e; e.env = env; e.buf = NULL; diff --git a/upb/encode.h b/upb/encode.h index 83908d4..8f42736 100644 --- a/upb/encode.h +++ b/upb/encode.h @@ -9,8 +9,8 @@ UPB_BEGIN_EXTERN_C -char *upb_encode(const void *msg, const upb_msglayout_msginit_v1 *l, - upb_env *env, size_t *size); +char *upb_encode(const void *msg, const upb_msglayout *l, upb_env *env, + size_t *size); UPB_END_EXTERN_C diff --git a/upb/msg.c b/upb/msg.c index 501e4c3..ca05779 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -2,20 +2,6 @@ #include "upb/msg.h" #include "upb/structs.int.h" -static bool is_power_of_two(size_t val) { - return (val & (val - 1)) == 0; -} - -/* Align up to the given power of 2. */ -static size_t align_up(size_t val, size_t align) { - UPB_ASSERT(is_power_of_two(align)); - return (val + align - 1) & ~(align - 1); -} - -static size_t div_round_up(size_t n, size_t d) { - return (n + d - 1) / d; -} - bool upb_fieldtype_mapkeyok(upb_fieldtype_t type) { return type == UPB_TYPE_BOOL || type == UPB_TYPE_INT32 || type == UPB_TYPE_UINT32 || type == UPB_TYPE_INT64 || @@ -70,7 +56,7 @@ static size_t upb_msgval_sizeof(upb_fieldtype_t type) { UPB_UNREACHABLE(); } -static uint8_t upb_msg_fieldsize(const upb_msglayout_fieldinit_v1 *field) { +static uint8_t upb_msg_fieldsize(const upb_msglayout_field *field) { if (field->label == UPB_LABEL_REPEATED) { return sizeof(void*); } else { @@ -78,14 +64,6 @@ static uint8_t upb_msg_fieldsize(const upb_msglayout_fieldinit_v1 *field) { } } -static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { - if (upb_fielddef_isseq(f)) { - return sizeof(void*); - } else { - return upb_msgval_sizeof(upb_fielddef_type(f)); - } -} - /* TODO(haberman): this is broken right now because upb_msgval can contain * a char* / size_t pair, which is too big for a upb_value. To fix this * we'll probably need to dynamically allocate a upb_msgval and store a @@ -121,292 +99,6 @@ static upb_ctype_t upb_fieldtotabtype(upb_fieldtype_t type) { } } -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 *************************************************************/ - -struct upb_msglayout { - struct upb_msglayout_msginit_v1 data; -}; - -static void upb_msglayout_free(upb_msglayout *l) { - upb_gfree(l->data.default_msg); - upb_gfree(l); -} - -static size_t upb_msglayout_place(upb_msglayout *l, size_t size) { - size_t ret; - - l->data.size = align_up(l->data.size, size); - ret = l->data.size; - l->data.size += 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->data.size) { - /* Allocate default message and set default values in it. */ - l->data.default_msg = upb_gmalloc(l->data.size); - if (!l->data.default_msg) { - return false; - } - - memset(l->data.default_msg, 0, l->data.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->data.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) { - upb_msg_field_iter it; - upb_msg_oneof_iter oit; - size_t hasbit; - size_t submsg_count = 0; - const upb_msglayout_msginit_v1 **submsgs; - upb_msglayout_fieldinit_v1 *fields; - upb_msglayout_oneofinit_v1 *oneofs; - - 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_issubmsg(f)) { - submsg_count++; - } - } - - memset(l, 0, sizeof(*l)); - - 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))) { - /* OOM. */ - upb_gfree(fields); - upb_gfree(submsgs); - upb_gfree(oneofs); - return false; - } - - l->data.field_count = upb_msgdef_numfields(m); - l->data.oneof_count = upb_msgdef_numoneofs(m); - l->data.fields = fields; - l->data.submsgs = submsgs; - l->data.oneofs = oneofs; - l->data.is_proto2 = (upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2); - - /* Allocate data offsets in three stages: - * - * 1. hasbits. - * 2. regular fields. - * 3. oneof fields. - * - * OPT: There is a lot of room for optimization here to minimize the size. - */ - - /* Allocate hasbits and set basic field attributes. */ - submsg_count = 0; - for (upb_msg_field_begin(&it, m), hasbit = 0; - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* f = upb_msg_iter_field(&it); - upb_msglayout_fieldinit_v1 *field = &fields[upb_fielddef_index(f)]; - - field->number = upb_fielddef_number(f); - 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->data; - } else { - field->submsg_index = UPB_NO_SUBMSG; - } - - if (upb_fielddef_haspresence(f) && !upb_fielddef_containingoneof(f)) { - field->hasbit = hasbit++; - } else { - field->hasbit = UPB_NO_HASBIT; - } - } - - /* Account for space used by hasbits. */ - l->data.size = div_round_up(hasbit, 8); - - /* Allocate non-oneof fields. */ - 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); - size_t field_size = upb_msg_fielddefsize(f); - size_t index = upb_fielddef_index(f); - - if (upb_fielddef_containingoneof(f)) { - /* Oneofs are handled separately below. */ - continue; - } - - fields[index].offset = upb_msglayout_place(l, field_size); - } - - /* Allocate oneof fields. Each oneof field consists of a uint32 for the case - * and space for the actual data. */ - for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit); - upb_msg_oneof_next(&oit)) { - const upb_oneofdef* o = upb_msg_iter_oneof(&oit); - upb_oneof_iter fit; - - size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ - upb_msglayout_oneofinit_v1 *oneof = &oneofs[upb_oneofdef_index(o)]; - size_t field_size = 0; - - /* Calculate field size: the max of all field sizes. */ - for (upb_oneof_begin(&fit, o); - !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* f = upb_oneof_iter_field(&fit); - field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); - } - - /* Align and allocate case offset. */ - oneof->case_offset = upb_msglayout_place(l, case_size); - oneof->data_offset = upb_msglayout_place(l, field_size); - } - - /* Size of the entire structure should be a multiple of its greatest - * alignment. TODO: track overall alignment for real? */ - l->data.size = align_up(l->data.size, 8); - - return upb_msglayout_initdefault(l, m); -} - - -/** upb_msgfactory ************************************************************/ - -struct upb_msgfactory { - const upb_symtab *symtab; /* We own a ref. */ - upb_inttable layouts; - upb_inttable mergehandlers; -}; - -upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab) { - upb_msgfactory *ret = upb_gmalloc(sizeof(*ret)); - - ret->symtab = symtab; - upb_inttable_init(&ret->layouts, UPB_CTYPE_PTR); - upb_inttable_init(&ret->mergehandlers, UPB_CTYPE_CONSTPTR); - - return ret; -} - -void upb_msgfactory_free(upb_msgfactory *f) { - upb_inttable_iter i; - upb_inttable_begin(&i, &f->layouts); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - upb_msglayout *l = upb_value_getptr(upb_inttable_iter_value(&i)); - upb_msglayout_free(l); - } - - upb_inttable_begin(&i, &f->mergehandlers); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - const upb_handlers *h = upb_value_getconstptr(upb_inttable_iter_value(&i)); - upb_handlers_unref(h, f); - } - - upb_inttable_uninit(&f->layouts); - upb_inttable_uninit(&f->mergehandlers); - upb_gfree(f); -} - -const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f) { - return f->symtab; -} - -const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, - const upb_msgdef *m) { - upb_value v; - UPB_ASSERT(upb_symtab_lookupmsg(f->symtab, upb_msgdef_fullname(m)) == m); - UPB_ASSERT(!upb_msgdef_mapentry(m)); - - if (upb_inttable_lookupptr(&f->layouts, m, &v)) { - UPB_ASSERT(upb_value_getptr(v)); - return upb_value_getptr(v); - } else { - /* In case of circular dependency, layout has to be inserted first. */ - upb_msglayout *l = upb_gmalloc(sizeof(*l)); - upb_msgfactory *mutable_f = (void*)f; - upb_inttable_insertptr(&mutable_f->layouts, m, upb_value_ptr(l)); - UPB_ASSERT(l); - if (!upb_msglayout_init(m, l, f)) { - upb_msglayout_free(l); - } - return l; - } -} - /** upb_msg *******************************************************************/ @@ -432,7 +124,7 @@ typedef struct { } upb_msg_internal_withext; static int upb_msg_internalsize(const upb_msglayout *l) { - return sizeof(upb_msg_internal) - l->data.extendable * sizeof(void*); + return sizeof(upb_msg_internal) - l->extendable * sizeof(void *); } static upb_msg_internal *upb_msg_getinternal(upb_msg *msg) { @@ -445,29 +137,29 @@ static const upb_msg_internal *upb_msg_getinternal_const(const upb_msg *msg) { static upb_msg_internal_withext *upb_msg_getinternalwithext( upb_msg *msg, const upb_msglayout *l) { - UPB_ASSERT(l->data.extendable); + UPB_ASSERT(l->extendable); return VOIDPTR_AT(msg, -sizeof(upb_msg_internal_withext)); } -static const upb_msglayout_fieldinit_v1 *upb_msg_checkfield( - int field_index, const upb_msglayout *l) { - UPB_ASSERT(field_index >= 0 && field_index < l->data.field_count); - return &l->data.fields[field_index]; +static const upb_msglayout_field *upb_msg_checkfield(int field_index, + const upb_msglayout *l) { + UPB_ASSERT(field_index >= 0 && field_index < l->field_count); + return &l->fields[field_index]; } -static bool upb_msg_inoneof(const upb_msglayout_fieldinit_v1 *field) { +static bool upb_msg_inoneof(const upb_msglayout_field *field) { return field->oneof_index != UPB_NOT_IN_ONEOF; } static uint32_t *upb_msg_oneofcase(const upb_msg *msg, int field_index, const upb_msglayout *l) { - const upb_msglayout_fieldinit_v1 *field = upb_msg_checkfield(field_index, l); + const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); UPB_ASSERT(upb_msg_inoneof(field)); - return PTR_AT(msg, l->data.oneofs[field->oneof_index].case_offset, uint32_t); + return PTR_AT(msg, l->oneofs[field->oneof_index].case_offset, uint32_t); } static size_t upb_msg_sizeof(const upb_msglayout *l) { - return l->data.size + upb_msg_internalsize(l); + return l->size + upb_msg_internalsize(l); } upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) { @@ -482,16 +174,16 @@ 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->data.default_msg) { - memcpy(msg, l->data.default_msg, l->data.size); + if (l->default_msg) { + memcpy(msg, l->default_msg, l->size); } else { - memset(msg, 0, l->data.size); + memset(msg, 0, l->size); } /* Initialize internal members. */ upb_msg_getinternal(msg)->arena = a; - if (l->data.extendable) { + if (l->extendable) { upb_msg_getinternalwithext(msg, l)->extdict = NULL; } @@ -505,32 +197,32 @@ upb_arena *upb_msg_arena(const upb_msg *msg) { bool upb_msg_has(const upb_msg *msg, int field_index, const upb_msglayout *l) { - const upb_msglayout_fieldinit_v1 *field = upb_msg_checkfield(field_index, l); + const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); - UPB_ASSERT(l->data.is_proto2); + UPB_ASSERT(l->is_proto2); 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->data.fields[field_index].hasbit; + uint32_t hasbit = l->fields[field_index].hasbit; return DEREF(msg, hasbit / 8, char) | (1 << (hasbit % 8)); } } upb_msgval upb_msg_get(const upb_msg *msg, int field_index, const upb_msglayout *l) { - const upb_msglayout_fieldinit_v1 *field = upb_msg_checkfield(field_index, 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->data.oneofs[field->oneof_index].data_offset; + 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->data.default_msg, field->offset, size); + return upb_msgval_read(l->default_msg, field->offset, size); } } else { return upb_msgval_read(msg, field->offset, size); @@ -539,11 +231,11 @@ upb_msgval upb_msg_get(const upb_msg *msg, int field_index, void upb_msg_set(upb_msg *msg, int field_index, upb_msgval val, const upb_msglayout *l) { - const upb_msglayout_fieldinit_v1 *field = upb_msg_checkfield(field_index, 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->data.oneofs[field->oneof_index].data_offset; + 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 { diff --git a/upb/msg.h b/upb/msg.h index 5472d17..557a1f4 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -31,21 +31,14 @@ namespace upb { class Array; class Map; class MapIterator; -class MessageFactory; class MessageLayout; -class Visitor; -class VisitorPlan; } #endif -UPB_DECLARE_TYPE(upb::MessageFactory, upb_msgfactory) -UPB_DECLARE_TYPE(upb::MessageLayout, upb_msglayout) UPB_DECLARE_TYPE(upb::Array, upb_array) UPB_DECLARE_TYPE(upb::Map, upb_map) UPB_DECLARE_TYPE(upb::MapIterator, upb_mapiter) -UPB_DECLARE_TYPE(upb::Visitor, upb_visitor) -UPB_DECLARE_TYPE(upb::VisitorPlan, upb_visitorplan) /* TODO(haberman): C++ accessors */ @@ -56,39 +49,45 @@ typedef void upb_msg; /** upb_msglayout *************************************************************/ -/* upb_msglayout represents the memory layout of a given upb_msgdef. You get - * instances of this from a upb_msgfactory, and the factory always owns the - * msglayout. */ +/* upb_msglayout represents the memory layout of a given upb_msgdef. The + * 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 -/** upb_msgfactory ************************************************************/ - -/* A upb_msgfactory contains a cache of upb_msglayout, upb_handlers, and - * upb_visitorplan objects. These are the objects necessary to represent, - * populate, and and visit upb_msg objects. - * - * These caches are all populated by upb_msgdef, and lazily created on demand. - */ +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. */ + uint8_t descriptortype; + uint8_t label; +} upb_msglayout_field; -/* Creates and destroys a msgfactory, respectively. The messages for this - * msgfactory must come from |symtab| (which should outlive the msgfactory). */ -upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab); -void upb_msgfactory_free(upb_msgfactory *f); +typedef struct { + uint32_t data_offset; + uint32_t case_offset; +} upb_msglayout_oneof; -const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f); +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 field_count; + uint16_t oneof_count; + bool extendable; + bool is_proto2; +} upb_msglayout; -/* The functions to get cached objects, lazily creating them on demand. These - * all require: - * - * - m is in upb_msgfactory_symtab(f) - * - upb_msgdef_mapentry(m) == false (since map messages can't have layouts). - * - * The returned objects will live for as long as the msgfactory does. - * - * TODO(haberman): consider making this thread-safe and take a const - * upb_msgfactory. */ -const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, - const upb_msgdef *m); +#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 ************************************************************/ @@ -291,52 +290,6 @@ upb_msgval upb_mapiter_value(const upb_mapiter *i); void upb_mapiter_setdone(upb_mapiter *i); bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2); - -/** Interfaces for generated code *********************************************/ - -#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. */ - uint8_t descriptortype; - uint8_t label; -} upb_msglayout_fieldinit_v1; - -typedef struct { - uint32_t data_offset; - uint32_t case_offset; -} upb_msglayout_oneofinit_v1; - -typedef struct upb_msglayout_msginit_v1 { - const struct upb_msglayout_msginit_v1 *const* submsgs; - const upb_msglayout_fieldinit_v1 *fields; - const upb_msglayout_oneofinit_v1 *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 field_count; - uint16_t oneof_count; - bool extendable; - bool is_proto2; -} upb_msglayout_msginit_v1; - -#define UPB_ALIGN_UP_TO(val, align) ((val + (align - 1)) & -align) -#define UPB_ALIGNED_SIZEOF(type) UPB_ALIGN_UP_TO(sizeof(type), sizeof(void*)) - -/* Initialize/uninitialize a msglayout from a msginit. If upb uses v1 - * internally, this will not allocate any memory. Should only be used by - * generated code. */ -upb_msglayout *upb_msglayout_frominit_v1( - const upb_msglayout_msginit_v1 *init, upb_alloc *a); -void upb_msglayout_uninit_v1(upb_msglayout *layout, upb_alloc *a); - UPB_END_EXTERN_C #endif /* UPB_MSG_H_ */ diff --git a/upb/msgfactory.c b/upb/msgfactory.c new file mode 100644 index 0000000..b544967 --- /dev/null +++ b/upb/msgfactory.c @@ -0,0 +1,325 @@ + +#include "upb/msgfactory.h" + +static bool is_power_of_two(size_t val) { + return (val & (val - 1)) == 0; +} + +/* Align up to the given power of 2. */ +static size_t align_up(size_t val, size_t align) { + UPB_ASSERT(is_power_of_two(align)); + return (val + align - 1) & ~(align - 1); +} + +static size_t div_round_up(size_t n, size_t d) { + return (n + d - 1) / d; +} + +static size_t upb_msgval_sizeof2(upb_fieldtype_t type) { + switch (type) { + case UPB_TYPE_DOUBLE: + case UPB_TYPE_INT64: + case UPB_TYPE_UINT64: + return 8; + case UPB_TYPE_ENUM: + case UPB_TYPE_INT32: + case UPB_TYPE_UINT32: + case UPB_TYPE_FLOAT: + return 4; + case UPB_TYPE_BOOL: + return 1; + case UPB_TYPE_MESSAGE: + return sizeof(void*); + case UPB_TYPE_BYTES: + case UPB_TYPE_STRING: + return sizeof(upb_stringview); + } + UPB_UNREACHABLE(); +} + +static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { + if (upb_fielddef_isseq(f)) { + return sizeof(void*); + } else { + return upb_msgval_sizeof2(upb_fielddef_type(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); +} + +static size_t upb_msglayout_place(upb_msglayout *l, size_t size) { + size_t ret; + + l->size = align_up(l->size, size); + ret = l->size; + l->size += 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) { + upb_msg_field_iter it; + upb_msg_oneof_iter oit; + size_t hasbit; + 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); + upb_msg_field_next(&it)) { + const upb_fielddef* f = upb_msg_iter_field(&it); + if (upb_fielddef_issubmsg(f)) { + submsg_count++; + } + } + + memset(l, 0, sizeof(*l)); + + 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))) { + /* 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: + * + * 1. hasbits. + * 2. regular fields. + * 3. oneof fields. + * + * OPT: There is a lot of room for optimization here to minimize the size. + */ + + /* Allocate hasbits and set basic field attributes. */ + submsg_count = 0; + for (upb_msg_field_begin(&it, m), hasbit = 0; + !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + const upb_fielddef* f = upb_msg_iter_field(&it); + upb_msglayout_field *field = &fields[upb_fielddef_index(f)]; + + field->number = upb_fielddef_number(f); + 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++; + } else { + field->hasbit = UPB_NO_HASBIT; + } + } + + /* Account for space used by hasbits. */ + l->size = div_round_up(hasbit, 8); + + /* Allocate non-oneof fields. */ + 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); + size_t field_size = upb_msg_fielddefsize(f); + size_t index = upb_fielddef_index(f); + + if (upb_fielddef_containingoneof(f)) { + /* Oneofs are handled separately below. */ + continue; + } + + fields[index].offset = upb_msglayout_place(l, field_size); + } + + /* Allocate oneof fields. Each oneof field consists of a uint32 for the case + * and space for the actual data. */ + for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit); + upb_msg_oneof_next(&oit)) { + const upb_oneofdef* o = upb_msg_iter_oneof(&oit); + 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; + + /* Calculate field size: the max of all field sizes. */ + for (upb_oneof_begin(&fit, o); + !upb_oneof_done(&fit); + upb_oneof_next(&fit)) { + const upb_fielddef* f = upb_oneof_iter_field(&fit); + field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); + } + + /* Align and allocate case offset. */ + oneof->case_offset = upb_msglayout_place(l, case_size); + oneof->data_offset = upb_msglayout_place(l, field_size); + } + + /* 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); +} + + +/** upb_msgfactory ************************************************************/ + +struct upb_msgfactory { + const upb_symtab *symtab; /* We own a ref. */ + upb_inttable layouts; + upb_inttable mergehandlers; +}; + +upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab) { + upb_msgfactory *ret = upb_gmalloc(sizeof(*ret)); + + ret->symtab = symtab; + upb_inttable_init(&ret->layouts, UPB_CTYPE_PTR); + upb_inttable_init(&ret->mergehandlers, UPB_CTYPE_CONSTPTR); + + return ret; +} + +void upb_msgfactory_free(upb_msgfactory *f) { + upb_inttable_iter i; + upb_inttable_begin(&i, &f->layouts); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_msglayout *l = upb_value_getptr(upb_inttable_iter_value(&i)); + upb_msglayout_free(l); + } + + upb_inttable_begin(&i, &f->mergehandlers); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + const upb_handlers *h = upb_value_getconstptr(upb_inttable_iter_value(&i)); + upb_handlers_unref(h, f); + } + + upb_inttable_uninit(&f->layouts); + upb_inttable_uninit(&f->mergehandlers); + upb_gfree(f); +} + +const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f) { + return f->symtab; +} + +const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, + const upb_msgdef *m) { + upb_value v; + UPB_ASSERT(upb_symtab_lookupmsg(f->symtab, upb_msgdef_fullname(m)) == m); + UPB_ASSERT(!upb_msgdef_mapentry(m)); + + if (upb_inttable_lookupptr(&f->layouts, m, &v)) { + UPB_ASSERT(upb_value_getptr(v)); + return upb_value_getptr(v); + } else { + /* In case of circular dependency, layout has to be inserted first. */ + upb_msglayout *l = upb_gmalloc(sizeof(*l)); + upb_msgfactory *mutable_f = (void*)f; + upb_inttable_insertptr(&mutable_f->layouts, m, upb_value_ptr(l)); + UPB_ASSERT(l); + if (!upb_msglayout_init(m, l, f)) { + upb_msglayout_free(l); + } + return l; + } +} diff --git a/upb/msgfactory.h b/upb/msgfactory.h new file mode 100644 index 0000000..73a26ba --- /dev/null +++ b/upb/msgfactory.h @@ -0,0 +1,40 @@ + +#include "upb/def.h" +#include "upb/msg.h" + +#ifndef UPB_MSGFACTORY_H_ +#define UPB_MSGFACTORY_H_ + +UPB_DECLARE_TYPE(upb::MessageFactory, upb_msgfactory) + +/** upb_msgfactory ************************************************************/ + +/* A upb_msgfactory contains a cache of upb_msglayout, upb_handlers, and + * upb_visitorplan objects. These are the objects necessary to represent, + * populate, and and visit upb_msg objects. + * + * These caches are all populated by upb_msgdef, and lazily created on demand. + */ + +/* Creates and destroys a msgfactory, respectively. The messages for this + * msgfactory must come from |symtab| (which should outlive the msgfactory). */ +upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab); +void upb_msgfactory_free(upb_msgfactory *f); + +const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f); + +/* The functions to get cached objects, lazily creating them on demand. These + * all require: + * + * - m is in upb_msgfactory_symtab(f) + * - upb_msgdef_mapentry(m) == false (since map messages can't have layouts). + * + * The returned objects will live for as long as the msgfactory does. + * + * TODO(haberman): consider making this thread-safe and take a const + * upb_msgfactory. */ +const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, + const upb_msgdef *m); + + +#endif /* UPB_MSGFACTORY_H_ */ -- cgit v1.2.3