From 928ef7f2c02f18d9945dd750884dffbdebef1b98 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Wed, 27 Mar 2019 12:52:33 -0700 Subject: Removed reflection and other extraneous things from the core library. (#158) * Removed reflection and other extraneous things from the core library. * Added missing files and ran buildifier. * New CMakeLists.txt. * Made table its own cc_library() for internal usage. --- upb/bindings/lua/msg.c | 2 + upb/decode.c | 158 +++++++--------- upb/def.c | 66 +++---- upb/encode.c | 6 +- upb/generated_util.h | 1 - upb/handlers.c | 19 -- upb/handlers.h | 6 +- upb/json/parser.c | 140 +++++++------- upb/json/parser.rl | 2 - upb/legacy_msg_reflection.c | 401 ++++++++++++++++++++++++++++++++++++++++ upb/legacy_msg_reflection.h | 186 +++++++++++++++++++ upb/msg.c | 437 +++----------------------------------------- upb/msg.h | 248 ++----------------------- upb/msgfactory.c | 1 - upb/structs.int.h | 20 -- upb/upb.h | 28 +++ 16 files changed, 815 insertions(+), 906 deletions(-) create mode 100644 upb/legacy_msg_reflection.c create mode 100644 upb/legacy_msg_reflection.h delete mode 100644 upb/structs.int.h (limited to 'upb') diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index df5a143..1e5e47c 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -7,9 +7,11 @@ #include #include #include + #include "lauxlib.h" #include "upb/bindings/lua/upb.h" #include "upb/handlers.h" +#include "upb/legacy_msg_reflection.h" #include "upb/msg.h" /* diff --git a/upb/decode.c b/upb/decode.c index 8ea0573..996f36a 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -2,7 +2,6 @@ #include #include "upb/upb.h" #include "upb/decode.h" -#include "upb/structs.int.h" /* Maps descriptor type -> upb field type. */ const uint8_t upb_desctype_to_fieldtype[] = { @@ -164,7 +163,7 @@ static bool upb_skip_unknownfielddata(upb_decstate *d, upb_decframe *frame, return false; } -static bool upb_array_grow(upb_array *arr, size_t elements) { +static bool upb_array_grow(upb_array *arr, size_t elements, size_t elem_size) { size_t needed = arr->len + elements; size_t new_size = UPB_MAX(arr->size, 8); size_t new_bytes; @@ -176,8 +175,8 @@ static bool upb_array_grow(upb_array *arr, size_t elements) { new_size *= 2; } - old_bytes = arr->len * arr->element_size; - new_bytes = new_size * arr->element_size; + old_bytes = arr->len * elem_size; + new_bytes = new_size * elem_size; new_data = upb_realloc(alloc, arr->data, old_bytes, new_bytes); CHK(new_data); @@ -186,17 +185,23 @@ static bool upb_array_grow(upb_array *arr, size_t elements) { return true; } -static void *upb_array_reserve(upb_array *arr, size_t elements) { +static void *upb_array_reserve(upb_array *arr, size_t elements, + size_t elem_size) { if (arr->size - arr->len < elements) { - CHK(upb_array_grow(arr, elements)); + if (!upb_array_grow(arr, elements, elem_size)) return NULL; } - return (char*)arr->data + (arr->len * arr->element_size); + return (char*)arr->data + (arr->len * elem_size); } -static void *upb_array_add(upb_array *arr, size_t elements) { - void *ret = upb_array_reserve(arr, elements); +bool upb_array_add(upb_array *arr, size_t elements, size_t elem_size, + const void *data) { + void *dest = upb_array_reserve(arr, elements, elem_size); + + CHK(dest); arr->len += elements; - return ret; + memcpy(dest, data, elements * elem_size); + + return true; } static upb_array *upb_getarr(upb_decframe *frame, @@ -234,17 +239,20 @@ static void upb_setoneofcase(upb_decframe *frame, upb_set32(frame->msg, ~field->presence, field->number); } -static char *upb_decode_prepareslot(upb_decframe *frame, - const upb_msglayout_field *field) { +static bool upb_decode_addval(upb_decframe *frame, + const upb_msglayout_field *field, void *val, + size_t size) { char *field_mem = frame->msg + field->offset; upb_array *arr; if (field->label == UPB_LABEL_REPEATED) { arr = upb_getorcreatearr(frame, field); - field_mem = upb_array_reserve(arr, 1); + field_mem = upb_array_reserve(arr, 1, size); + CHK(field_mem); } - return field_mem; + memcpy(field_mem, val, size); + return true; } static void upb_decode_setpresent(upb_decframe *frame, @@ -264,21 +272,15 @@ static bool upb_decode_submsg(upb_decstate *d, upb_decframe *frame, const char *limit, const upb_msglayout_field *field, int group_number) { - char *submsg_slot = upb_decode_prepareslot(frame, field); - char *submsg = *(void **)submsg_slot; - const upb_msglayout *subm; - - subm = frame->m->submsgs[field->submsg_index]; - UPB_ASSERT(subm); + upb_msg **submsg = (void*)(frame->msg + field->offset); + const upb_msglayout *subm = frame->m->submsgs[field->submsg_index]; - if (!submsg) { - submsg = upb_msg_new(subm, upb_msg_arena(frame->msg)); - CHK(submsg); - *(void**)submsg_slot = submsg; + if (!*submsg) { + *submsg = upb_msg_new(subm, upb_msg_arena(frame->msg)); + CHK(*submsg); } - upb_decode_message(d, limit, group_number, submsg, subm); - + upb_decode_message(d, limit, group_number, *submsg, subm); return true; } @@ -286,37 +288,33 @@ static bool upb_decode_varintfield(upb_decstate *d, upb_decframe *frame, const char *field_start, const upb_msglayout_field *field) { uint64_t val; - void *field_mem; - - field_mem = upb_decode_prepareslot(frame, field); - CHK(field_mem); CHK(upb_decode_varint(&d->ptr, frame->limit, &val)); - switch ((upb_descriptortype_t)field->descriptortype) { + switch (field->descriptortype) { case UPB_DESCRIPTOR_TYPE_INT64: case UPB_DESCRIPTOR_TYPE_UINT64: - memcpy(field_mem, &val, sizeof(val)); + CHK(upb_decode_addval(frame, field, &val, sizeof(val))); break; case UPB_DESCRIPTOR_TYPE_INT32: case UPB_DESCRIPTOR_TYPE_UINT32: case UPB_DESCRIPTOR_TYPE_ENUM: { uint32_t val32 = val; - memcpy(field_mem, &val32, sizeof(val32)); + CHK(upb_decode_addval(frame, field, &val32, sizeof(val32))); break; } case UPB_DESCRIPTOR_TYPE_BOOL: { bool valbool = val != 0; - memcpy(field_mem, &valbool, sizeof(valbool)); + CHK(upb_decode_addval(frame, field, &valbool, sizeof(valbool))); break; } case UPB_DESCRIPTOR_TYPE_SINT32: { int32_t decoded = upb_zzdecode_32(val); - memcpy(field_mem, &decoded, sizeof(decoded)); + CHK(upb_decode_addval(frame, field, &decoded, sizeof(decoded))); break; } case UPB_DESCRIPTOR_TYPE_SINT64: { int64_t decoded = upb_zzdecode_64(val); - memcpy(field_mem, &decoded, sizeof(decoded)); + CHK(upb_decode_addval(frame, field, &decoded, sizeof(decoded))); break; } default: @@ -330,18 +328,14 @@ 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_field *field) { - void *field_mem; uint64_t val; - - field_mem = upb_decode_prepareslot(frame, field); - CHK(field_mem); CHK(upb_decode_64bit(&d->ptr, frame->limit, &val)); - switch ((upb_descriptortype_t)field->descriptortype) { + switch (field->descriptortype) { case UPB_DESCRIPTOR_TYPE_DOUBLE: case UPB_DESCRIPTOR_TYPE_FIXED64: case UPB_DESCRIPTOR_TYPE_SFIXED64: - memcpy(field_mem, &val, sizeof(val)); + CHK(upb_decode_addval(frame, field, &val, sizeof(val))); break; default: return upb_append_unknown(d, frame, field_start); @@ -354,18 +348,14 @@ 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_field *field) { - void *field_mem; uint32_t val; - - field_mem = upb_decode_prepareslot(frame, field); - CHK(field_mem); CHK(upb_decode_32bit(&d->ptr, frame->limit, &val)); - switch ((upb_descriptortype_t)field->descriptortype) { + switch (field->descriptortype) { case UPB_DESCRIPTOR_TYPE_FLOAT: case UPB_DESCRIPTOR_TYPE_FIXED32: case UPB_DESCRIPTOR_TYPE_SFIXED32: - memcpy(field_mem, &val, sizeof(val)); + CHK(upb_decode_addval(frame, field, &val, sizeof(val))); break; default: return upb_append_unknown(d, frame, field_start); @@ -377,13 +367,11 @@ static bool upb_decode_32bitfield(upb_decstate *d, upb_decframe *frame, static bool upb_decode_fixedpacked(upb_array *arr, upb_strview data, int elem_size) { - int elements = data.size / elem_size; - void *field_mem; + size_t elements = data.size / elem_size; CHK((size_t)(elements * elem_size) == data.size); - field_mem = upb_array_add(arr, elements); - CHK(field_mem); - memcpy(field_mem, data.data, data.size); + CHK(upb_array_add(arr, elements, elem_size, data.data)); + return true; } @@ -393,29 +381,24 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame, upb_strview val) { upb_array *arr = upb_getorcreatearr(frame, field); -#define VARINT_CASE(ctype, decode) { \ - const char *ptr = val.data; \ - const char *limit = ptr + val.size; \ - while (ptr < limit) { \ - uint64_t val; \ - void *field_mem; \ - ctype decoded; \ - CHK(upb_decode_varint(&ptr, limit, &val)); \ - decoded = (decode)(val); \ - field_mem = upb_array_add(arr, 1); \ - CHK(field_mem); \ - memcpy(field_mem, &decoded, sizeof(ctype)); \ - } \ - return true; \ -} - - switch ((upb_descriptortype_t)field->descriptortype) { +#define VARINT_CASE(ctype, decode) \ + { \ + const char *ptr = val.data; \ + const char *limit = ptr + val.size; \ + while (ptr < limit) { \ + uint64_t val; \ + ctype decoded; \ + CHK(upb_decode_varint(&ptr, limit, &val)); \ + decoded = (decode)(val); \ + CHK(upb_array_add(arr, 1, sizeof(decoded), &decoded)); \ + } \ + return true; \ + } + + switch (field->descriptortype) { case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_BYTES: { - void *field_mem = upb_array_add(arr, 1); - CHK(field_mem); - memcpy(field_mem, &val, sizeof(val)); - return true; + return upb_array_add(arr, 1, sizeof(val), &val); } case UPB_DESCRIPTOR_TYPE_FLOAT: case UPB_DESCRIPTOR_TYPE_FIXED32: @@ -428,7 +411,6 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame, case UPB_DESCRIPTOR_TYPE_INT32: case UPB_DESCRIPTOR_TYPE_UINT32: case UPB_DESCRIPTOR_TYPE_ENUM: - /* TODO: proto2 enum field that isn't in the enum. */ VARINT_CASE(uint32_t, uint32_t); case UPB_DESCRIPTOR_TYPE_INT64: case UPB_DESCRIPTOR_TYPE_UINT64: @@ -440,24 +422,14 @@ 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 *subm; - char *submsg; - void *field_mem; - - CHK(val.size <= (size_t)(frame->limit - val.data)); - d->ptr -= val.size; - - /* Create elemente message. */ - subm = frame->m->submsgs[field->submsg_index]; - UPB_ASSERT(subm); + const upb_msglayout *subm = frame->m->submsgs[field->submsg_index]; + upb_msg *submsg = upb_msg_new(subm, upb_msg_arena(frame->msg)); - submsg = upb_msg_new(subm, upb_msg_arena(frame->msg)); CHK(submsg); + CHK(val.size <= (size_t)(frame->limit - val.data)); + upb_array_add(arr, 1, sizeof(submsg), &submsg); - field_mem = upb_array_add(arr, 1); - CHK(field_mem); - *(void**)field_mem = submsg; - + d->ptr -= val.size; return upb_decode_message( d, val.data + val.size, frame->group_number, submsg, subm); } @@ -478,12 +450,10 @@ static bool upb_decode_delimitedfield(upb_decstate *d, upb_decframe *frame, if (field->label == UPB_LABEL_REPEATED) { return upb_decode_toarray(d, frame, field_start, field, val); } else { - switch ((upb_descriptortype_t)field->descriptortype) { + switch (field->descriptortype) { case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_BYTES: { - void *field_mem = upb_decode_prepareslot(frame, field); - CHK(field_mem); - memcpy(field_mem, &val, sizeof(val)); + CHK(upb_decode_addval(frame, field, &val, sizeof(val))); break; } case UPB_DESCRIPTOR_TYPE_MESSAGE: diff --git a/upb/def.c b/upb/def.c index 8d40b8e..6721bcb 100644 --- a/upb/def.c +++ b/upb/def.c @@ -6,7 +6,6 @@ #include #include #include "google/protobuf/descriptor.upb.h" -#include "upb/handlers.h" typedef struct { size_t len; @@ -206,6 +205,30 @@ int cmp_fields(const void *p1, const void *p2) { return field_rank(f1) - field_rank(f2); } +/* A few implementation details of handlers. We put these here to avoid + * a def -> handlers dependency. */ + +#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/handlers.h. */ + +static uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { + return upb_fielddef_isseq(f) ? 2 : 0; +} + +static uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { + uint32_t ret = 1; + if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */ + if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */ + if (upb_fielddef_issubmsg(f)) { + /* ENDSUBMSG (STARTSUBMSG is at table beginning) */ + ret += 0; + if (upb_fielddef_lazy(f)) { + /* STARTSTR/ENDSTR/STRING (for lazy) */ + ret += 3; + } + } + return ret; +} + static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { /* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the * lowest indexes, but we do not publicly guarantee this. */ @@ -251,47 +274,6 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { } m->selector_count = selector; -#ifndef NDEBUG - { - /* Verify that all selectors for the message are distinct. */ -#define TRY(type) \ - if (upb_handlers_getselector(f, type, &sel)) { upb_inttable_insert(&t, sel, v); } - - upb_inttable t; - upb_value v; - upb_selector_t sel; - - upb_inttable_init(&t, UPB_CTYPE_BOOL); - v = upb_value_bool(true); - upb_inttable_insert(&t, UPB_STARTMSG_SELECTOR, v); - upb_inttable_insert(&t, UPB_ENDMSG_SELECTOR, v); - upb_inttable_insert(&t, UPB_UNKNOWN_SELECTOR, v); - for(upb_msg_field_begin(&j, m); - !upb_msg_field_done(&j); - upb_msg_field_next(&j)) { - upb_fielddef *f = upb_msg_iter_field(&j); - /* These calls will assert-fail in upb_table if the value already - * exists. */ - TRY(UPB_HANDLER_INT32); - TRY(UPB_HANDLER_INT64) - TRY(UPB_HANDLER_UINT32) - TRY(UPB_HANDLER_UINT64) - TRY(UPB_HANDLER_FLOAT) - TRY(UPB_HANDLER_DOUBLE) - TRY(UPB_HANDLER_BOOL) - TRY(UPB_HANDLER_STARTSTR) - TRY(UPB_HANDLER_STRING) - TRY(UPB_HANDLER_ENDSTR) - TRY(UPB_HANDLER_STARTSUBMSG) - TRY(UPB_HANDLER_ENDSUBMSG) - TRY(UPB_HANDLER_STARTSEQ) - TRY(UPB_HANDLER_ENDSEQ) - } - upb_inttable_uninit(&t); - } -#undef TRY -#endif - for(upb_msg_oneof_begin(&k, m), i = 0; !upb_msg_oneof_done(&k); upb_msg_oneof_next(&k), i++) { diff --git a/upb/encode.c b/upb/encode.c index 18b35d9..2bcf550 100644 --- a/upb/encode.c +++ b/upb/encode.c @@ -1,9 +1,11 @@ /* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ +#include "upb/encode.h" + #include + +#include "upb/msg.h" #include "upb/upb.h" -#include "upb/encode.h" -#include "upb/structs.int.h" #define UPB_PB_VARINT_MAX_LEN 10 #define CHK(x) do { if (!(x)) { return false; } } while(0) diff --git a/upb/generated_util.h b/upb/generated_util.h index 657280f..0d5e6ba 100644 --- a/upb/generated_util.h +++ b/upb/generated_util.h @@ -8,7 +8,6 @@ #include #include "upb/msg.h" -#include "upb/structs.int.h" #define PTR_AT(msg, ofs, type) (type*)((const char*)msg + ofs) diff --git a/upb/handlers.c b/upb/handlers.c index 7abf948..a452663 100644 --- a/upb/handlers.c +++ b/upb/handlers.c @@ -368,25 +368,6 @@ bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, return true; } -uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { - return upb_fielddef_isseq(f) ? 2 : 0; -} - -uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { - uint32_t ret = 1; - if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */ - if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */ - if (upb_fielddef_issubmsg(f)) { - /* ENDSUBMSG (STARTSUBMSG is at table beginning) */ - ret += 0; - if (upb_fielddef_lazy(f)) { - /* STARTSTR/ENDSTR/STRING (for lazy) */ - ret += 3; - } - } - return ret; -} - /* upb_handlercache ***********************************************************/ struct upb_handlercache { diff --git a/upb/handlers.h b/upb/handlers.h index e267f12..cedd977 100644 --- a/upb/handlers.h +++ b/upb/handlers.h @@ -76,7 +76,7 @@ typedef int32_t upb_selector_t; #define UPB_STARTMSG_SELECTOR 0 #define UPB_ENDMSG_SELECTOR 1 #define UPB_UNKNOWN_SELECTOR 2 -#define UPB_STATIC_SELECTOR_COUNT 3 +#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/def.c. */ /* Static selectors for upb::BytesHandler. */ #define UPB_STARTSTR_SELECTOR 0 @@ -233,10 +233,6 @@ UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) { return start + 1; } -/* Internal-only. */ -uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f); -uint32_t upb_handlers_selectorcount(const upb_fielddef *f); - #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/json/parser.c b/upb/json/parser.c index db7f14f..4040370 100644 --- a/upb/json/parser.c +++ b/upb/json/parser.c @@ -1533,7 +1533,6 @@ static bool end_duration_base(upb_json_parser *p, const char *ptr) { static int parse_timestamp_number(upb_json_parser *p) { size_t len; const char *buf; - char *end; int val; /* atoi() and friends unfortunately do not support specifying the length of @@ -2009,7 +2008,6 @@ static void end_any_member(upb_json_parser *p, const char *ptr) { static bool start_subobject(upb_json_parser *p) { if (p->top->is_unknown_field) { - upb_jsonparser_frame *inner; if (!check_stack(p)) return false; p->top = start_jsonparser_frame(p); @@ -2544,11 +2542,11 @@ static bool does_fieldmask_end(upb_json_parser *p) { * final state once, when the closing '"' is seen. */ -#line 2749 "upb/json/parser.rl" +#line 2747 "upb/json/parser.rl" -#line 2552 "upb/json/parser.c" +#line 2550 "upb/json/parser.c" static const char _json_actions[] = { 0, 1, 0, 1, 1, 1, 3, 1, 4, 1, 6, 1, 7, 1, 8, 1, @@ -2803,7 +2801,7 @@ static const int json_en_value_machine = 78; static const int json_en_main = 1; -#line 2752 "upb/json/parser.rl" +#line 2750 "upb/json/parser.rl" size_t parse(void *closure, const void *hd, const char *buf, size_t size, const upb_bufhandle *handle) { @@ -2826,7 +2824,7 @@ size_t parse(void *closure, const void *hd, const char *buf, size_t size, capture_resume(parser, buf); -#line 2830 "upb/json/parser.c" +#line 2828 "upb/json/parser.c" { int _klen; unsigned int _trans; @@ -2901,147 +2899,147 @@ _match: switch ( *_acts++ ) { case 1: -#line 2557 "upb/json/parser.rl" +#line 2555 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; case 2: -#line 2559 "upb/json/parser.rl" +#line 2557 "upb/json/parser.rl" { p--; {stack[top++] = cs; cs = 23;goto _again;} } break; case 3: -#line 2563 "upb/json/parser.rl" +#line 2561 "upb/json/parser.rl" { start_text(parser, p); } break; case 4: -#line 2564 "upb/json/parser.rl" +#line 2562 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_text(parser, p)); } break; case 5: -#line 2570 "upb/json/parser.rl" +#line 2568 "upb/json/parser.rl" { start_hex(parser); } break; case 6: -#line 2571 "upb/json/parser.rl" +#line 2569 "upb/json/parser.rl" { hexdigit(parser, p); } break; case 7: -#line 2572 "upb/json/parser.rl" +#line 2570 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_hex(parser)); } break; case 8: -#line 2578 "upb/json/parser.rl" +#line 2576 "upb/json/parser.rl" { CHECK_RETURN_TOP(escape(parser, p)); } break; case 9: -#line 2584 "upb/json/parser.rl" +#line 2582 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; case 10: -#line 2589 "upb/json/parser.rl" +#line 2587 "upb/json/parser.rl" { start_year(parser, p); } break; case 11: -#line 2590 "upb/json/parser.rl" +#line 2588 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_year(parser, p)); } break; case 12: -#line 2594 "upb/json/parser.rl" +#line 2592 "upb/json/parser.rl" { start_month(parser, p); } break; case 13: -#line 2595 "upb/json/parser.rl" +#line 2593 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_month(parser, p)); } break; case 14: -#line 2599 "upb/json/parser.rl" +#line 2597 "upb/json/parser.rl" { start_day(parser, p); } break; case 15: -#line 2600 "upb/json/parser.rl" +#line 2598 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_day(parser, p)); } break; case 16: -#line 2604 "upb/json/parser.rl" +#line 2602 "upb/json/parser.rl" { start_hour(parser, p); } break; case 17: -#line 2605 "upb/json/parser.rl" +#line 2603 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_hour(parser, p)); } break; case 18: -#line 2609 "upb/json/parser.rl" +#line 2607 "upb/json/parser.rl" { start_minute(parser, p); } break; case 19: -#line 2610 "upb/json/parser.rl" +#line 2608 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_minute(parser, p)); } break; case 20: -#line 2614 "upb/json/parser.rl" +#line 2612 "upb/json/parser.rl" { start_second(parser, p); } break; case 21: -#line 2615 "upb/json/parser.rl" +#line 2613 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_second(parser, p)); } break; case 22: -#line 2620 "upb/json/parser.rl" +#line 2618 "upb/json/parser.rl" { start_duration_base(parser, p); } break; case 23: -#line 2621 "upb/json/parser.rl" +#line 2619 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_duration_base(parser, p)); } break; case 24: -#line 2623 "upb/json/parser.rl" +#line 2621 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; case 25: -#line 2628 "upb/json/parser.rl" +#line 2626 "upb/json/parser.rl" { start_timestamp_base(parser); } break; case 26: -#line 2630 "upb/json/parser.rl" +#line 2628 "upb/json/parser.rl" { start_timestamp_fraction(parser, p); } break; case 27: -#line 2631 "upb/json/parser.rl" +#line 2629 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_timestamp_fraction(parser, p)); } break; case 28: -#line 2633 "upb/json/parser.rl" +#line 2631 "upb/json/parser.rl" { start_timestamp_zone(parser, p); } break; case 29: -#line 2634 "upb/json/parser.rl" +#line 2632 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_timestamp_zone(parser, p)); } break; case 30: -#line 2636 "upb/json/parser.rl" +#line 2634 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; case 31: -#line 2641 "upb/json/parser.rl" +#line 2639 "upb/json/parser.rl" { start_fieldmask_path_text(parser, p); } break; case 32: -#line 2642 "upb/json/parser.rl" +#line 2640 "upb/json/parser.rl" { end_fieldmask_path_text(parser, p); } break; case 33: -#line 2647 "upb/json/parser.rl" +#line 2645 "upb/json/parser.rl" { start_fieldmask_path(parser); } break; case 34: -#line 2648 "upb/json/parser.rl" +#line 2646 "upb/json/parser.rl" { end_fieldmask_path(parser); } break; case 35: -#line 2654 "upb/json/parser.rl" +#line 2652 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; case 36: -#line 2659 "upb/json/parser.rl" +#line 2657 "upb/json/parser.rl" { if (is_wellknown_msg(parser, UPB_WELLKNOWN_TIMESTAMP)) { {stack[top++] = cs; cs = 47;goto _again;} @@ -3055,11 +3053,11 @@ _match: } break; case 37: -#line 2672 "upb/json/parser.rl" +#line 2670 "upb/json/parser.rl" { p--; {stack[top++] = cs; cs = 78;goto _again;} } break; case 38: -#line 2677 "upb/json/parser.rl" +#line 2675 "upb/json/parser.rl" { if (is_wellknown_msg(parser, UPB_WELLKNOWN_ANY)) { start_any_member(parser, p); @@ -3069,11 +3067,11 @@ _match: } break; case 39: -#line 2684 "upb/json/parser.rl" +#line 2682 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_membername(parser)); } break; case 40: -#line 2687 "upb/json/parser.rl" +#line 2685 "upb/json/parser.rl" { if (is_wellknown_msg(parser, UPB_WELLKNOWN_ANY)) { end_any_member(parser, p); @@ -3083,7 +3081,7 @@ _match: } break; case 41: -#line 2698 "upb/json/parser.rl" +#line 2696 "upb/json/parser.rl" { if (is_wellknown_msg(parser, UPB_WELLKNOWN_ANY)) { start_any_object(parser, p); @@ -3093,7 +3091,7 @@ _match: } break; case 42: -#line 2707 "upb/json/parser.rl" +#line 2705 "upb/json/parser.rl" { if (is_wellknown_msg(parser, UPB_WELLKNOWN_ANY)) { CHECK_RETURN_TOP(end_any_object(parser, p)); @@ -3103,54 +3101,54 @@ _match: } break; case 43: -#line 2719 "upb/json/parser.rl" +#line 2717 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_array(parser)); } break; case 44: -#line 2723 "upb/json/parser.rl" +#line 2721 "upb/json/parser.rl" { end_array(parser); } break; case 45: -#line 2728 "upb/json/parser.rl" +#line 2726 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_number(parser, p)); } break; case 46: -#line 2729 "upb/json/parser.rl" +#line 2727 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_number(parser, p)); } break; case 47: -#line 2731 "upb/json/parser.rl" +#line 2729 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_stringval(parser)); } break; case 48: -#line 2732 "upb/json/parser.rl" +#line 2730 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_stringval(parser)); } break; case 49: -#line 2734 "upb/json/parser.rl" +#line 2732 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_bool(parser, true)); } break; case 50: -#line 2736 "upb/json/parser.rl" +#line 2734 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_bool(parser, false)); } break; case 51: -#line 2738 "upb/json/parser.rl" +#line 2736 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_null(parser)); } break; case 52: -#line 2740 "upb/json/parser.rl" +#line 2738 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_subobject_full(parser)); } break; case 53: -#line 2741 "upb/json/parser.rl" +#line 2739 "upb/json/parser.rl" { end_subobject_full(parser); } break; case 54: -#line 2746 "upb/json/parser.rl" +#line 2744 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; -#line 3154 "upb/json/parser.c" +#line 3152 "upb/json/parser.c" } } @@ -3167,32 +3165,32 @@ _again: while ( __nacts-- > 0 ) { switch ( *__acts++ ) { case 0: -#line 2555 "upb/json/parser.rl" +#line 2553 "upb/json/parser.rl" { p--; {cs = stack[--top]; if ( p == pe ) goto _test_eof; goto _again;} } break; case 46: -#line 2729 "upb/json/parser.rl" +#line 2727 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_number(parser, p)); } break; case 49: -#line 2734 "upb/json/parser.rl" +#line 2732 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_bool(parser, true)); } break; case 50: -#line 2736 "upb/json/parser.rl" +#line 2734 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_bool(parser, false)); } break; case 51: -#line 2738 "upb/json/parser.rl" +#line 2736 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_null(parser)); } break; case 53: -#line 2741 "upb/json/parser.rl" +#line 2739 "upb/json/parser.rl" { end_subobject_full(parser); } break; -#line 3196 "upb/json/parser.c" +#line 3194 "upb/json/parser.c" } } } @@ -3200,7 +3198,7 @@ goto _again;} } _out: {} } -#line 2774 "upb/json/parser.rl" +#line 2772 "upb/json/parser.rl" if (p != pe) { upb_status_seterrf(parser->status, "Parse error at '%.*s'\n", pe - p, p); @@ -3243,13 +3241,13 @@ static void json_parser_reset(upb_json_parser *p) { /* Emit Ragel initialization of the parser. */ -#line 3247 "upb/json/parser.c" +#line 3245 "upb/json/parser.c" { cs = json_start; top = 0; } -#line 2816 "upb/json/parser.rl" +#line 2814 "upb/json/parser.rl" p->current_state = cs; p->parser_top = top; accumulate_clear(p); diff --git a/upb/json/parser.rl b/upb/json/parser.rl index e7c456a..a48a47d 100644 --- a/upb/json/parser.rl +++ b/upb/json/parser.rl @@ -1531,7 +1531,6 @@ static bool end_duration_base(upb_json_parser *p, const char *ptr) { static int parse_timestamp_number(upb_json_parser *p) { size_t len; const char *buf; - char *end; int val; /* atoi() and friends unfortunately do not support specifying the length of @@ -2007,7 +2006,6 @@ static void end_any_member(upb_json_parser *p, const char *ptr) { static bool start_subobject(upb_json_parser *p) { if (p->top->is_unknown_field) { - upb_jsonparser_frame *inner; if (!check_stack(p)) return false; p->top = start_jsonparser_frame(p); diff --git a/upb/legacy_msg_reflection.c b/upb/legacy_msg_reflection.c new file mode 100644 index 0000000..0140533 --- /dev/null +++ b/upb/legacy_msg_reflection.c @@ -0,0 +1,401 @@ + +#include "upb/legacy_msg_reflection.h" + +#include +#include "upb/table.int.h" +#include "upb/msg.h" + +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 || + type == UPB_TYPE_UINT64 || type == UPB_TYPE_STRING; +} + +#define PTR_AT(msg, ofs, type) (type*)((char*)msg + ofs) +#define VOIDPTR_AT(msg, ofs) PTR_AT(msg, ofs, void) +#define ENCODE_MAX_NESTING 64 +#define CHECK_TRUE(x) if (!(x)) { return false; } + +/** upb_msgval ****************************************************************/ + +/* These functions will generate real memcpy() calls on ARM sadly, because + * the compiler assumes they might not be aligned. */ + +static upb_msgval upb_msgval_read(const void *p, size_t ofs, + uint8_t size) { + upb_msgval val; + p = (char*)p + ofs; + memcpy(&val, p, size); + return val; +} + +static void upb_msgval_write(void *p, size_t ofs, upb_msgval val, + uint8_t size) { + p = (char*)p + ofs; + memcpy(p, &val, size); +} + +static size_t upb_msgval_sizeof(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_strview); + } + UPB_UNREACHABLE(); +} + +static uint8_t upb_msg_fieldsize(const upb_msglayout_field *field) { + if (field->label == UPB_LABEL_REPEATED) { + return sizeof(void*); + } else { + return upb_msgval_sizeof(upb_desctype_to_fieldtype[field->descriptortype]); + } +} + +/* 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 + * pointer to that in the tables for extensions/maps. */ +static upb_value upb_toval(upb_msgval val) { + upb_value ret; + UPB_UNUSED(val); + memset(&ret, 0, sizeof(upb_value)); /* XXX */ + return ret; +} + +static upb_msgval upb_msgval_fromval(upb_value val) { + upb_msgval ret; + UPB_UNUSED(val); + memset(&ret, 0, sizeof(upb_msgval)); /* XXX */ + return ret; +} + +static upb_ctype_t upb_fieldtotabtype(upb_fieldtype_t type) { + switch (type) { + case UPB_TYPE_FLOAT: return UPB_CTYPE_FLOAT; + case UPB_TYPE_DOUBLE: return UPB_CTYPE_DOUBLE; + case UPB_TYPE_BOOL: return UPB_CTYPE_BOOL; + case UPB_TYPE_BYTES: + case UPB_TYPE_MESSAGE: + case UPB_TYPE_STRING: return UPB_CTYPE_CONSTPTR; + case UPB_TYPE_ENUM: + case UPB_TYPE_INT32: return UPB_CTYPE_INT32; + case UPB_TYPE_UINT32: return UPB_CTYPE_UINT32; + case UPB_TYPE_INT64: return UPB_CTYPE_INT64; + case UPB_TYPE_UINT64: return UPB_CTYPE_UINT64; + default: UPB_ASSERT(false); return 0; + } +} + + +/** upb_msg *******************************************************************/ + +/* If we always read/write as a consistent type to each address, this shouldn't + * violate aliasing. + */ +#define DEREF(msg, ofs, type) *PTR_AT(msg, ofs, type) + +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_field *field) { + 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, ~field->presence, uint32_t); +} + +bool upb_msg_has(const upb_msg *msg, + int field_index, + const upb_msglayout *l) { + const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); + + 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 = field->presence; + 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_field *field = upb_msg_checkfield(field_index, l); + int size = upb_msg_fieldsize(field); + 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); + upb_msgval_write(msg, field->offset, val, size); +} + + +/** upb_array *****************************************************************/ + +#define DEREF_ARR(arr, i, type) ((type*)arr->data)[i] + +size_t upb_array_size(const upb_array *arr) { + return arr->len; +} + +upb_fieldtype_t upb_array_type(const upb_array *arr) { + return arr->type; +} + +upb_msgval upb_array_get(const upb_array *arr, size_t i) { + size_t element_size = upb_msgval_sizeof(arr->type); + UPB_ASSERT(i < arr->len); + return upb_msgval_read(arr->data, i * element_size, element_size); +} + +bool upb_array_set(upb_array *arr, size_t i, upb_msgval val) { + size_t element_size = upb_msgval_sizeof(arr->type); + UPB_ASSERT(i <= arr->len); + + if (i == arr->len) { + /* Extending the array. */ + + if (i == arr->size) { + /* Need to reallocate. */ + size_t new_size = UPB_MAX(arr->size * 2, 8); + size_t new_bytes = new_size * element_size; + size_t old_bytes = arr->size * element_size; + upb_alloc *alloc = upb_arena_alloc(arr->arena); + upb_msgval *new_data = + upb_realloc(alloc, arr->data, old_bytes, new_bytes); + + if (!new_data) { + return false; + } + + arr->data = new_data; + arr->size = new_size; + } + + arr->len = i + 1; + } + + upb_msgval_write(arr->data, i * element_size, val, element_size); + return true; +} + + +/** upb_map *******************************************************************/ + +struct upb_map { + upb_fieldtype_t key_type; + upb_fieldtype_t val_type; + /* We may want to optimize this to use inttable where possible, for greater + * efficiency and lower memory footprint. */ + upb_strtable strtab; + upb_arena *arena; +}; + +static void upb_map_tokey(upb_fieldtype_t type, upb_msgval *key, + const char **out_key, size_t *out_len) { + switch (type) { + case UPB_TYPE_STRING: + /* Point to string data of the input key. */ + *out_key = key->str.data; + *out_len = key->str.size; + return; + case UPB_TYPE_BOOL: + case UPB_TYPE_INT32: + case UPB_TYPE_UINT32: + case UPB_TYPE_INT64: + case UPB_TYPE_UINT64: + /* Point to the key itself. XXX: big-endian. */ + *out_key = (const char*)key; + *out_len = upb_msgval_sizeof(type); + return; + case UPB_TYPE_BYTES: + case UPB_TYPE_DOUBLE: + case UPB_TYPE_ENUM: + case UPB_TYPE_FLOAT: + case UPB_TYPE_MESSAGE: + break; /* Cannot be a map key. */ + } + UPB_UNREACHABLE(); +} + +static upb_msgval upb_map_fromkey(upb_fieldtype_t type, const char *key, + size_t len) { + switch (type) { + case UPB_TYPE_STRING: + return upb_msgval_makestr(key, len); + case UPB_TYPE_BOOL: + case UPB_TYPE_INT32: + case UPB_TYPE_UINT32: + case UPB_TYPE_INT64: + case UPB_TYPE_UINT64: + return upb_msgval_read(key, 0, upb_msgval_sizeof(type)); + case UPB_TYPE_BYTES: + case UPB_TYPE_DOUBLE: + case UPB_TYPE_ENUM: + case UPB_TYPE_FLOAT: + case UPB_TYPE_MESSAGE: + break; /* Cannot be a map key. */ + } + UPB_UNREACHABLE(); +} + +upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, + upb_arena *a) { + upb_ctype_t vtabtype = upb_fieldtotabtype(vtype); + upb_alloc *alloc = upb_arena_alloc(a); + upb_map *map = upb_malloc(alloc, sizeof(upb_map)); + + if (!map) { + return NULL; + } + + UPB_ASSERT(upb_fieldtype_mapkeyok(ktype)); + map->key_type = ktype; + map->val_type = vtype; + map->arena = a; + + if (!upb_strtable_init2(&map->strtab, vtabtype, alloc)) { + return NULL; + } + + return map; +} + +size_t upb_map_size(const upb_map *map) { + return upb_strtable_count(&map->strtab); +} + +upb_fieldtype_t upb_map_keytype(const upb_map *map) { + return map->key_type; +} + +upb_fieldtype_t upb_map_valuetype(const upb_map *map) { + return map->val_type; +} + +bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { + upb_value tabval; + const char *key_str; + size_t key_len; + bool ret; + + upb_map_tokey(map->key_type, &key, &key_str, &key_len); + ret = upb_strtable_lookup2(&map->strtab, key_str, key_len, &tabval); + if (ret) { + memcpy(val, &tabval, sizeof(tabval)); + } + + return ret; +} + +bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, + upb_msgval *removed) { + const char *key_str; + size_t key_len; + upb_value tabval = upb_toval(val); + upb_value removedtabval; + upb_alloc *a = upb_arena_alloc(map->arena); + + upb_map_tokey(map->key_type, &key, &key_str, &key_len); + + /* TODO(haberman): add overwrite operation to minimize number of lookups. */ + if (upb_strtable_lookup2(&map->strtab, key_str, key_len, NULL)) { + upb_strtable_remove3(&map->strtab, key_str, key_len, &removedtabval, a); + memcpy(&removed, &removedtabval, sizeof(removed)); + } + + return upb_strtable_insert3(&map->strtab, key_str, key_len, tabval, a); +} + +bool upb_map_del(upb_map *map, upb_msgval key) { + const char *key_str; + size_t key_len; + upb_alloc *a = upb_arena_alloc(map->arena); + + upb_map_tokey(map->key_type, &key, &key_str, &key_len); + return upb_strtable_remove3(&map->strtab, key_str, key_len, NULL, a); +} + + +/** upb_mapiter ***************************************************************/ + +struct upb_mapiter { + upb_strtable_iter iter; + upb_fieldtype_t key_type; +}; + +size_t upb_mapiter_sizeof() { + return sizeof(upb_mapiter); +} + +void upb_mapiter_begin(upb_mapiter *i, const upb_map *map) { + upb_strtable_begin(&i->iter, &map->strtab); + i->key_type = map->key_type; +} + +upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a) { + upb_mapiter *ret = upb_malloc(a, upb_mapiter_sizeof()); + + if (!ret) { + return NULL; + } + + upb_mapiter_begin(ret, t); + return ret; +} + +void upb_mapiter_free(upb_mapiter *i, upb_alloc *a) { + upb_free(a, i); +} + +void upb_mapiter_next(upb_mapiter *i) { + upb_strtable_next(&i->iter); +} + +bool upb_mapiter_done(const upb_mapiter *i) { + return upb_strtable_done(&i->iter); +} + +upb_msgval upb_mapiter_key(const upb_mapiter *i) { + return upb_map_fromkey(i->key_type, upb_strtable_iter_key(&i->iter), + upb_strtable_iter_keylength(&i->iter)); +} + +upb_msgval upb_mapiter_value(const upb_mapiter *i) { + return upb_msgval_fromval(upb_strtable_iter_value(&i->iter)); +} + +void upb_mapiter_setdone(upb_mapiter *i) { + upb_strtable_iter_setdone(&i->iter); +} + +bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2) { + return upb_strtable_iter_isequal(&i1->iter, &i2->iter); +} diff --git a/upb/legacy_msg_reflection.h b/upb/legacy_msg_reflection.h new file mode 100644 index 0000000..66d3fba --- /dev/null +++ b/upb/legacy_msg_reflection.h @@ -0,0 +1,186 @@ + +#ifndef UPB_LEGACY_MSG_REFLECTION_H_ +#define UPB_LEGACY_MSG_REFLECTION_H_ + +#include "upb/upb.h" +#include "upb/msg.h" + +struct upb_map; +typedef struct upb_map upb_map; + +struct upb_mapiter; +typedef struct upb_mapiter upb_mapiter; + +/** upb_msgval ****************************************************************/ + +/* A union representing all possible protobuf values. Used for generic get/set + * operations. */ + +typedef union { + bool b; + float flt; + double dbl; + int32_t i32; + int64_t i64; + uint32_t u32; + uint64_t u64; + const upb_map* map; + const upb_msg* msg; + const upb_array* arr; + const void* ptr; + upb_strview str; +} upb_msgval; + +#define ACCESSORS(name, membername, ctype) \ + UPB_INLINE ctype upb_msgval_get ## name(upb_msgval v) { \ + return v.membername; \ + } \ + UPB_INLINE void upb_msgval_set ## name(upb_msgval *v, ctype cval) { \ + v->membername = cval; \ + } \ + UPB_INLINE upb_msgval upb_msgval_ ## name(ctype v) { \ + upb_msgval ret; \ + ret.membername = v; \ + return ret; \ + } + +ACCESSORS(bool, b, bool) +ACCESSORS(float, flt, float) +ACCESSORS(double, dbl, double) +ACCESSORS(int32, i32, int32_t) +ACCESSORS(int64, i64, int64_t) +ACCESSORS(uint32, u32, uint32_t) +ACCESSORS(uint64, u64, uint64_t) +ACCESSORS(map, map, const upb_map*) +ACCESSORS(msg, msg, const upb_msg*) +ACCESSORS(ptr, ptr, const void*) +ACCESSORS(arr, arr, const upb_array*) +ACCESSORS(str, str, upb_strview) + +#undef ACCESSORS + +UPB_INLINE upb_msgval upb_msgval_makestr(const char *data, size_t size) { + return upb_msgval_str(upb_strview_make(data, size)); +} + +/** upb_msg *******************************************************************/ + +/* A upb_msg represents a protobuf message. It always corresponds to a specific + * upb_msglayout, which describes how it is laid out in memory. */ + +/* Read-only message API. Can be safely called by anyone. */ + +/* Returns the value associated with this field: + * - for scalar fields (including strings), the value directly. + * - return upb_msg*, or upb_map* for msg/map. + * If the field is unset for these field types, returns NULL. + * + * TODO(haberman): should we let users store cached array/map/msg + * pointers here for fields that are unset? Could be useful for the + * strongly-owned submessage model (ie. generated C API that doesn't use + * arenas). + */ +upb_msgval upb_msg_get(const upb_msg *msg, + int field_index, + const upb_msglayout *l); + +/* May only be called for fields where upb_fielddef_haspresence(f) == true. */ +bool upb_msg_has(const upb_msg *msg, + int field_index, + const upb_msglayout *l); + +/* Mutable message API. May only be called by the owner of the message who + * knows its ownership scheme and how to keep it consistent. */ + +/* Sets the given field to the given value. Does not perform any memory + * management: if you overwrite a pointer to a msg/array/map/string without + * cleaning it up (or using an arena) it will leak. + */ +void upb_msg_set(upb_msg *msg, + int field_index, + upb_msgval val, + const upb_msglayout *l); + +/* For a primitive field, set it back to its default. For repeated, string, and + * submessage fields set it back to NULL. This could involve releasing some + * internal memory (for example, from an extension dictionary), but it is not + * recursive in any way and will not recover any memory that may be used by + * arrays/maps/strings/msgs that this field may have pointed to. + */ +bool upb_msg_clearfield(upb_msg *msg, + int field_index, + const upb_msglayout *l); + +/* TODO(haberman): copyfrom()/mergefrom()? */ + +/** upb_array *****************************************************************/ + +/* A upb_array stores data for a repeated field. The memory management + * semantics are the same as upb_msg. A upb_array allocates dynamic + * memory internally for the array elements. */ + +upb_fieldtype_t upb_array_type(const upb_array *arr); + +/* Read-only interface. Safe for anyone to call. */ + +size_t upb_array_size(const upb_array *arr); +upb_msgval upb_array_get(const upb_array *arr, size_t i); + +/* Write interface. May only be called by the message's owner who can enforce + * its memory management invariants. */ + +bool upb_array_set(upb_array *arr, size_t i, upb_msgval val); + +/** upb_map *******************************************************************/ + +/* A upb_map stores data for a map field. The memory management semantics are + * the same as upb_msg, with one notable exception. upb_map will internally + * store a copy of all string keys, but *not* any string values or submessages. + * So you must ensure that any string or message values outlive the map, and you + * must delete them manually when they are no longer required. */ + +upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, + upb_arena *a); + +/* Read-only interface. Safe for anyone to call. */ + +size_t upb_map_size(const upb_map *map); +upb_fieldtype_t upb_map_keytype(const upb_map *map); +upb_fieldtype_t upb_map_valuetype(const upb_map *map); +bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val); + +/* Write interface. May only be called by the message's owner who can enforce + * its memory management invariants. */ + +/* Sets or overwrites an entry in the map. Return value indicates whether + * the operation succeeded or failed with OOM, and also whether an existing + * key was replaced or not. */ +bool upb_map_set(upb_map *map, + upb_msgval key, upb_msgval val, + upb_msgval *valremoved); + +/* Deletes an entry in the map. Returns true if the key was present. */ +bool upb_map_del(upb_map *map, upb_msgval key); + +/** upb_mapiter ***************************************************************/ + +/* For iterating over a map. Map iterators are invalidated by mutations to the + * map, but an invalidated iterator will never return junk or crash the process. + * An invalidated iterator may return entries that were already returned though, + * and if you keep invalidating the iterator during iteration, the program may + * enter an infinite loop. */ + +size_t upb_mapiter_sizeof(); + +void upb_mapiter_begin(upb_mapiter *i, const upb_map *t); +upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a); +void upb_mapiter_free(upb_mapiter *i, upb_alloc *a); +void upb_mapiter_next(upb_mapiter *i); +bool upb_mapiter_done(const upb_mapiter *i); + +upb_msgval upb_mapiter_key(const upb_mapiter *i); +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); + +#endif // UPB_LEGACY_MSG_REFLECTION_H_ diff --git a/upb/msg.c b/upb/msg.c index b46d41c..d6ad8df 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -1,111 +1,9 @@ -#include -#include "upb/table.int.h" #include "upb/msg.h" -#include "upb/structs.int.h" - -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 || - type == UPB_TYPE_UINT64 || type == UPB_TYPE_STRING; -} - -#define PTR_AT(msg, ofs, type) (type*)((char*)msg + ofs) -#define VOIDPTR_AT(msg, ofs) PTR_AT(msg, ofs, void) -#define ENCODE_MAX_NESTING 64 -#define CHECK_TRUE(x) if (!(x)) { return false; } - -/** upb_msgval ****************************************************************/ - -/* These functions will generate real memcpy() calls on ARM sadly, because - * the compiler assumes they might not be aligned. */ - -static upb_msgval upb_msgval_read(const void *p, size_t ofs, - uint8_t size) { - upb_msgval val; - p = (char*)p + ofs; - memcpy(&val, p, size); - return val; -} - -static void upb_msgval_write(void *p, size_t ofs, upb_msgval val, - uint8_t size) { - p = (char*)p + ofs; - memcpy(p, &val, size); -} - -static size_t upb_msgval_sizeof(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_strview); - } - UPB_UNREACHABLE(); -} - -static uint8_t upb_msg_fieldsize(const upb_msglayout_field *field) { - if (field->label == UPB_LABEL_REPEATED) { - return sizeof(void*); - } else { - return upb_msgval_sizeof(upb_desctype_to_fieldtype[field->descriptortype]); - } -} - -/* 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 - * pointer to that in the tables for extensions/maps. */ -static upb_value upb_toval(upb_msgval val) { - upb_value ret; - UPB_UNUSED(val); - memset(&ret, 0, sizeof(upb_value)); /* XXX */ - return ret; -} - -static upb_msgval upb_msgval_fromval(upb_value val) { - upb_msgval ret; - UPB_UNUSED(val); - memset(&ret, 0, sizeof(upb_msgval)); /* XXX */ - return ret; -} -static upb_ctype_t upb_fieldtotabtype(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_FLOAT: return UPB_CTYPE_FLOAT; - case UPB_TYPE_DOUBLE: return UPB_CTYPE_DOUBLE; - case UPB_TYPE_BOOL: return UPB_CTYPE_BOOL; - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - case UPB_TYPE_STRING: return UPB_CTYPE_CONSTPTR; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: return UPB_CTYPE_INT32; - case UPB_TYPE_UINT32: return UPB_CTYPE_UINT32; - case UPB_TYPE_INT64: return UPB_CTYPE_INT64; - case UPB_TYPE_UINT64: return UPB_CTYPE_UINT64; - default: UPB_ASSERT(false); return 0; - } -} - - -/** upb_msg *******************************************************************/ +#include "upb/table.int.h" -/* If we always read/write as a consistent type to each address, this shouldn't - * violate aliasing. - */ -#define DEREF(msg, ofs, type) *PTR_AT(msg, ofs, type) +#define VOIDPTR_AT(msg, ofs) (void*)((char*)msg + ofs) /* Internal members of a upb_msg. We can change this without breaking binary * compatibility. We put these before the user's data. The user's upb_msg* @@ -131,6 +29,10 @@ static int upb_msg_internalsize(const upb_msglayout *l) { return sizeof(upb_msg_internal) - l->extendable * sizeof(void *); } +static size_t upb_msg_sizeof(const upb_msglayout *l) { + return l->size + upb_msg_internalsize(l); +} + static upb_msg_internal *upb_msg_getinternal(upb_msg *msg) { return VOIDPTR_AT(msg, -sizeof(upb_msg_internal)); } @@ -145,44 +47,8 @@ static upb_msg_internal_withext *upb_msg_getinternalwithext( return VOIDPTR_AT(msg, -sizeof(upb_msg_internal_withext)); } -void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len) { - upb_msg_internal* in = upb_msg_getinternal(msg); - if (len > in->unknown_size - in->unknown_len) { - upb_alloc *alloc = upb_arena_alloc(in->arena); - size_t need = in->unknown_size + len; - size_t newsize = UPB_MAX(in->unknown_size * 2, need); - in->unknown = upb_realloc(alloc, in->unknown, in->unknown_size, newsize); - in->unknown_size = newsize; - } - memcpy(in->unknown + in->unknown_len, data, len); - in->unknown_len += len; -} - -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) { - const upb_msg_internal* in = upb_msg_getinternal_const(msg); - *len = in->unknown_len; - return in->unknown; -} - -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_field *field) { - 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, ~field->presence, uint32_t); -} - -static size_t upb_msg_sizeof(const upb_msglayout *l) { - return l->size + upb_msg_internalsize(l); +upb_arena *upb_msg_arena(const upb_msg *msg) { + return upb_msg_getinternal_const(msg)->arena; } upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) { @@ -214,46 +80,6 @@ upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a) { return msg; } -upb_arena *upb_msg_arena(const upb_msg *msg) { - return upb_msg_getinternal_const(msg)->arena; -} - -bool upb_msg_has(const upb_msg *msg, - int field_index, - const upb_msglayout *l) { - const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); - - 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 = field->presence; - 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_field *field = upb_msg_checkfield(field_index, l); - int size = upb_msg_fieldsize(field); - 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); - upb_msgval_write(msg, field->offset, val, size); -} - - -/** upb_array *****************************************************************/ - -#define DEREF_ARR(arr, i, type) ((type*)arr->data)[i] - upb_array *upb_array_new(upb_fieldtype_t type, upb_arena *a) { upb_alloc *alloc = upb_arena_alloc(a); upb_array *ret = upb_malloc(alloc, sizeof(upb_array)); @@ -266,245 +92,28 @@ upb_array *upb_array_new(upb_fieldtype_t type, upb_arena *a) { ret->data = NULL; ret->len = 0; ret->size = 0; - ret->element_size = upb_msgval_sizeof(type); ret->arena = a; return ret; } -size_t upb_array_size(const upb_array *arr) { - return arr->len; -} - -upb_fieldtype_t upb_array_type(const upb_array *arr) { - return arr->type; -} - -upb_msgval upb_array_get(const upb_array *arr, size_t i) { - UPB_ASSERT(i < arr->len); - return upb_msgval_read(arr->data, i * arr->element_size, arr->element_size); -} - -bool upb_array_set(upb_array *arr, size_t i, upb_msgval val) { - UPB_ASSERT(i <= arr->len); - - if (i == arr->len) { - /* Extending the array. */ - - if (i == arr->size) { - /* Need to reallocate. */ - size_t new_size = UPB_MAX(arr->size * 2, 8); - size_t new_bytes = new_size * arr->element_size; - size_t old_bytes = arr->size * arr->element_size; - upb_alloc *alloc = upb_arena_alloc(arr->arena); - upb_msgval *new_data = - upb_realloc(alloc, arr->data, old_bytes, new_bytes); - - if (!new_data) { - return false; - } - - arr->data = new_data; - arr->size = new_size; - } - - arr->len = i + 1; - } - - upb_msgval_write(arr->data, i * arr->element_size, val, arr->element_size); - return true; -} - - -/** upb_map *******************************************************************/ - -struct upb_map { - upb_fieldtype_t key_type; - upb_fieldtype_t val_type; - /* We may want to optimize this to use inttable where possible, for greater - * efficiency and lower memory footprint. */ - upb_strtable strtab; - upb_arena *arena; -}; - -static void upb_map_tokey(upb_fieldtype_t type, upb_msgval *key, - const char **out_key, size_t *out_len) { - switch (type) { - case UPB_TYPE_STRING: - /* Point to string data of the input key. */ - *out_key = key->str.data; - *out_len = key->str.size; - return; - case UPB_TYPE_BOOL: - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: - /* Point to the key itself. XXX: big-endian. */ - *out_key = (const char*)key; - *out_len = upb_msgval_sizeof(type); - return; - case UPB_TYPE_BYTES: - case UPB_TYPE_DOUBLE: - case UPB_TYPE_ENUM: - case UPB_TYPE_FLOAT: - case UPB_TYPE_MESSAGE: - break; /* Cannot be a map key. */ - } - UPB_UNREACHABLE(); -} - -static upb_msgval upb_map_fromkey(upb_fieldtype_t type, const char *key, - size_t len) { - switch (type) { - case UPB_TYPE_STRING: - return upb_msgval_makestr(key, len); - case UPB_TYPE_BOOL: - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: - return upb_msgval_read(key, 0, upb_msgval_sizeof(type)); - case UPB_TYPE_BYTES: - case UPB_TYPE_DOUBLE: - case UPB_TYPE_ENUM: - case UPB_TYPE_FLOAT: - case UPB_TYPE_MESSAGE: - break; /* Cannot be a map key. */ - } - UPB_UNREACHABLE(); -} - -upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, - upb_arena *a) { - upb_ctype_t vtabtype = upb_fieldtotabtype(vtype); - upb_alloc *alloc = upb_arena_alloc(a); - upb_map *map = upb_malloc(alloc, sizeof(upb_map)); - - if (!map) { - return NULL; - } - - UPB_ASSERT(upb_fieldtype_mapkeyok(ktype)); - map->key_type = ktype; - map->val_type = vtype; - map->arena = a; - - if (!upb_strtable_init2(&map->strtab, vtabtype, alloc)) { - return NULL; - } - - return map; -} - -size_t upb_map_size(const upb_map *map) { - return upb_strtable_count(&map->strtab); -} - -upb_fieldtype_t upb_map_keytype(const upb_map *map) { - return map->key_type; -} - -upb_fieldtype_t upb_map_valuetype(const upb_map *map) { - return map->val_type; -} - -bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { - upb_value tabval; - const char *key_str; - size_t key_len; - bool ret; - - upb_map_tokey(map->key_type, &key, &key_str, &key_len); - ret = upb_strtable_lookup2(&map->strtab, key_str, key_len, &tabval); - if (ret) { - memcpy(val, &tabval, sizeof(tabval)); - } - - return ret; -} - -bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, - upb_msgval *removed) { - const char *key_str; - size_t key_len; - upb_value tabval = upb_toval(val); - upb_value removedtabval; - upb_alloc *a = upb_arena_alloc(map->arena); - - upb_map_tokey(map->key_type, &key, &key_str, &key_len); - - /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - if (upb_strtable_lookup2(&map->strtab, key_str, key_len, NULL)) { - upb_strtable_remove3(&map->strtab, key_str, key_len, &removedtabval, a); - memcpy(&removed, &removedtabval, sizeof(removed)); - } - - return upb_strtable_insert3(&map->strtab, key_str, key_len, tabval, a); -} - -bool upb_map_del(upb_map *map, upb_msgval key) { - const char *key_str; - size_t key_len; - upb_alloc *a = upb_arena_alloc(map->arena); - - upb_map_tokey(map->key_type, &key, &key_str, &key_len); - return upb_strtable_remove3(&map->strtab, key_str, key_len, NULL, a); -} - - -/** upb_mapiter ***************************************************************/ - -struct upb_mapiter { - upb_strtable_iter iter; - upb_fieldtype_t key_type; -}; - -size_t upb_mapiter_sizeof() { - return sizeof(upb_mapiter); -} - -void upb_mapiter_begin(upb_mapiter *i, const upb_map *map) { - upb_strtable_begin(&i->iter, &map->strtab); - i->key_type = map->key_type; -} - -upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a) { - upb_mapiter *ret = upb_malloc(a, upb_mapiter_sizeof()); - - if (!ret) { - return NULL; +void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len) { + upb_msg_internal* in = upb_msg_getinternal(msg); + if (len > in->unknown_size - in->unknown_len) { + upb_alloc *alloc = upb_arena_alloc(in->arena); + size_t need = in->unknown_size + len; + size_t newsize = UPB_MAX(in->unknown_size * 2, need); + in->unknown = upb_realloc(alloc, in->unknown, in->unknown_size, newsize); + in->unknown_size = newsize; } - - upb_mapiter_begin(ret, t); - return ret; -} - -void upb_mapiter_free(upb_mapiter *i, upb_alloc *a) { - upb_free(a, i); -} - -void upb_mapiter_next(upb_mapiter *i) { - upb_strtable_next(&i->iter); -} - -bool upb_mapiter_done(const upb_mapiter *i) { - return upb_strtable_done(&i->iter); -} - -upb_msgval upb_mapiter_key(const upb_mapiter *i) { - return upb_map_fromkey(i->key_type, upb_strtable_iter_key(&i->iter), - upb_strtable_iter_keylength(&i->iter)); -} - -upb_msgval upb_mapiter_value(const upb_mapiter *i) { - return upb_msgval_fromval(upb_strtable_iter_value(&i->iter)); + memcpy(in->unknown + in->unknown_len, data, len); + in->unknown_len += len; } -void upb_mapiter_setdone(upb_mapiter *i) { - upb_strtable_iter_setdone(&i->iter); +const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) { + const upb_msg_internal* in = upb_msg_getinternal_const(msg); + *len = in->unknown_len; + return in->unknown; } -bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2) { - return upb_strtable_iter_isequal(&i1->iter, &i2->iter); -} +#undef VOIDPTR_AT diff --git a/upb/msg.h b/upb/msg.h index 78c3633..e46733f 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -1,21 +1,9 @@ /* -** upb::Message is a representation for protobuf messages. +** Data structures for message tables, used for parsing and serialization. +** This are much lighter-weight than full reflection, but they are do not +** have enough information to convert to text format, JSON, etc. ** -** However it differs from other common representations like -** google::protobuf::Message in one key way: it does not prescribe any -** ownership between messages and submessages, and it relies on the -** client to ensure that each submessage/array/map outlives its parent. -** -** All messages, arrays, and maps live in an Arena. If the entire message -** tree is in the same arena, ensuring proper lifetimes is simple. However -** the client can mix arenas as long as they ensure that there are no -** dangling pointers. -** -** A client can access a upb::Message without knowing anything about -** ownership semantics, but to create or mutate a message a user needs -** to implement the memory management themselves. -** -** TODO: UTF-8 checking? +** The definitions in this file are internal to upb. **/ #ifndef UPB_MSG_H_ @@ -24,20 +12,6 @@ #include #include #include "upb/upb.h" -#include "upb/structs.int.h" - -#ifdef __cplusplus - -namespace upb { -class Array; -class Map; -class MapIterator; -class MessageLayout; -} - -#endif - -/* TODO(haberman): C++ accessors */ #ifdef __cplusplus extern "C" { @@ -45,15 +19,6 @@ extern "C" { typedef void upb_msg; -struct upb_array; -typedef struct upb_array upb_array; - -struct upb_map; -typedef struct upb_map upb_map; - -struct upb_mapiter; -typedef struct upb_mapiter upb_mapiter; - /** upb_msglayout *************************************************************/ /* upb_msglayout represents the memory layout of a given upb_msgdef. The @@ -79,91 +44,18 @@ typedef struct upb_msglayout { bool extendable; } upb_msglayout; -/** upb_strview ************************************************************/ +/** Message internal representation *******************************************/ +/* Our internal representation for repeated fields. */ typedef struct { - const char *data; - size_t size; -} upb_strview; - -UPB_INLINE upb_strview upb_strview_make(const char *data, size_t size) { - upb_strview ret; - ret.data = data; - ret.size = size; - return ret; -} - -UPB_INLINE upb_strview upb_strview_makez(const char *data) { - return upb_strview_make(data, strlen(data)); -} + upb_fieldtype_t type; + void *data; /* Each element is element_size. */ + size_t len; /* Measured in elements. */ + size_t size; /* Measured in elements. */ + upb_arena *arena; +} upb_array; -UPB_INLINE bool upb_strview_eql(upb_strview a, upb_strview b) { - return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; -} - -#define UPB_STRVIEW_INIT(ptr, len) {ptr, len} - -#define UPB_STRVIEW_FORMAT "%.*s" -#define UPB_STRVIEW_ARGS(view) (int)(view).size, (view).data - -/** upb_msgval ****************************************************************/ - -/* A union representing all possible protobuf values. Used for generic get/set - * operations. */ - -typedef union { - bool b; - float flt; - double dbl; - int32_t i32; - int64_t i64; - uint32_t u32; - uint64_t u64; - const upb_map* map; - const upb_msg* msg; - const upb_array* arr; - const void* ptr; - upb_strview str; -} upb_msgval; - -#define ACCESSORS(name, membername, ctype) \ - UPB_INLINE ctype upb_msgval_get ## name(upb_msgval v) { \ - return v.membername; \ - } \ - UPB_INLINE void upb_msgval_set ## name(upb_msgval *v, ctype cval) { \ - v->membername = cval; \ - } \ - UPB_INLINE upb_msgval upb_msgval_ ## name(ctype v) { \ - upb_msgval ret; \ - ret.membername = v; \ - return ret; \ - } - -ACCESSORS(bool, b, bool) -ACCESSORS(float, flt, float) -ACCESSORS(double, dbl, double) -ACCESSORS(int32, i32, int32_t) -ACCESSORS(int64, i64, int64_t) -ACCESSORS(uint32, u32, uint32_t) -ACCESSORS(uint64, u64, uint64_t) -ACCESSORS(map, map, const upb_map*) -ACCESSORS(msg, msg, const upb_msg*) -ACCESSORS(ptr, ptr, const void*) -ACCESSORS(arr, arr, const upb_array*) -ACCESSORS(str, str, upb_strview) - -#undef ACCESSORS - -UPB_INLINE upb_msgval upb_msgval_makestr(const char *data, size_t size) { - return upb_msgval_str(upb_strview_make(data, size)); -} - -/** upb_msg *******************************************************************/ - -/* A upb_msg represents a protobuf message. It always corresponds to a specific - * upb_msglayout, which describes how it is laid out in memory. */ - -/* Creates a new message of the given type/layout in this arena. */ +upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); upb_msg *upb_msg_new(const upb_msglayout *l, upb_arena *a); /* Returns the arena for the given message. */ @@ -172,121 +64,7 @@ upb_arena *upb_msg_arena(const upb_msg *msg); void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len); const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); -/* Read-only message API. Can be safely called by anyone. */ - -/* Returns the value associated with this field: - * - for scalar fields (including strings), the value directly. - * - return upb_msg*, or upb_map* for msg/map. - * If the field is unset for these field types, returns NULL. - * - * TODO(haberman): should we let users store cached array/map/msg - * pointers here for fields that are unset? Could be useful for the - * strongly-owned submessage model (ie. generated C API that doesn't use - * arenas). - */ -upb_msgval upb_msg_get(const upb_msg *msg, - int field_index, - const upb_msglayout *l); - -/* May only be called for fields where upb_fielddef_haspresence(f) == true. */ -bool upb_msg_has(const upb_msg *msg, - int field_index, - const upb_msglayout *l); - -/* Mutable message API. May only be called by the owner of the message who - * knows its ownership scheme and how to keep it consistent. */ - -/* Sets the given field to the given value. Does not perform any memory - * management: if you overwrite a pointer to a msg/array/map/string without - * cleaning it up (or using an arena) it will leak. - */ -void upb_msg_set(upb_msg *msg, - int field_index, - upb_msgval val, - const upb_msglayout *l); - -/* For a primitive field, set it back to its default. For repeated, string, and - * submessage fields set it back to NULL. This could involve releasing some - * internal memory (for example, from an extension dictionary), but it is not - * recursive in any way and will not recover any memory that may be used by - * arrays/maps/strings/msgs that this field may have pointed to. - */ -bool upb_msg_clearfield(upb_msg *msg, - int field_index, - const upb_msglayout *l); - -/* TODO(haberman): copyfrom()/mergefrom()? */ - -/** upb_array *****************************************************************/ - -/* A upb_array stores data for a repeated field. The memory management - * semantics are the same as upb_msg. A upb_array allocates dynamic - * memory internally for the array elements. */ - upb_array *upb_array_new(upb_fieldtype_t type, upb_arena *a); -upb_fieldtype_t upb_array_type(const upb_array *arr); - -/* Read-only interface. Safe for anyone to call. */ - -size_t upb_array_size(const upb_array *arr); -upb_msgval upb_array_get(const upb_array *arr, size_t i); - -/* Write interface. May only be called by the message's owner who can enforce - * its memory management invariants. */ - -bool upb_array_set(upb_array *arr, size_t i, upb_msgval val); - -/** upb_map *******************************************************************/ - -/* A upb_map stores data for a map field. The memory management semantics are - * the same as upb_msg, with one notable exception. upb_map will internally - * store a copy of all string keys, but *not* any string values or submessages. - * So you must ensure that any string or message values outlive the map, and you - * must delete them manually when they are no longer required. */ - -upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, - upb_arena *a); - -/* Read-only interface. Safe for anyone to call. */ - -size_t upb_map_size(const upb_map *map); -upb_fieldtype_t upb_map_keytype(const upb_map *map); -upb_fieldtype_t upb_map_valuetype(const upb_map *map); -bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val); - -/* Write interface. May only be called by the message's owner who can enforce - * its memory management invariants. */ - -/* Sets or overwrites an entry in the map. Return value indicates whether - * the operation succeeded or failed with OOM, and also whether an existing - * key was replaced or not. */ -bool upb_map_set(upb_map *map, - upb_msgval key, upb_msgval val, - upb_msgval *valremoved); - -/* Deletes an entry in the map. Returns true if the key was present. */ -bool upb_map_del(upb_map *map, upb_msgval key); - -/** upb_mapiter ***************************************************************/ - -/* For iterating over a map. Map iterators are invalidated by mutations to the - * map, but an invalidated iterator will never return junk or crash the process. - * An invalidated iterator may return entries that were already returned though, - * and if you keep invalidating the iterator during iteration, the program may - * enter an infinite loop. */ - -size_t upb_mapiter_sizeof(); - -void upb_mapiter_begin(upb_mapiter *i, const upb_map *t); -upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a); -void upb_mapiter_free(upb_mapiter *i, upb_alloc *a); -void upb_mapiter_next(upb_mapiter *i); -bool upb_mapiter_done(const upb_mapiter *i); - -upb_msgval upb_mapiter_key(const upb_mapiter *i); -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); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/msgfactory.c b/upb/msgfactory.c index f082042..2e13199 100644 --- a/upb/msgfactory.c +++ b/upb/msgfactory.c @@ -1,5 +1,4 @@ -#include "upb/handlers.h" #include "upb/msgfactory.h" static bool is_power_of_two(size_t val) { diff --git a/upb/structs.int.h b/upb/structs.int.h deleted file mode 100644 index ec7a4ae..0000000 --- a/upb/structs.int.h +++ /dev/null @@ -1,20 +0,0 @@ -/* -** structs.int.h: structures definitions that are internal to upb. -*/ - -#ifndef UPB_STRUCTS_H_ -#define UPB_STRUCTS_H_ - -#include "upb/upb.h" - -struct upb_array { - upb_fieldtype_t type; - uint8_t element_size; - void *data; /* Each element is element_size. */ - size_t len; /* Measured in elements. */ - size_t size; /* Measured in elements. */ - upb_arena *arena; -}; - -#endif /* UPB_STRUCTS_H_ */ - diff --git a/upb/upb.h b/upb/upb.h index 92db893..49bb757 100644 --- a/upb/upb.h +++ b/upb/upb.h @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef __cplusplus #include @@ -170,6 +171,33 @@ class upb::Status { #endif /* __cplusplus */ +/** upb_strview ************************************************************/ + +typedef struct { + const char *data; + size_t size; +} upb_strview; + +UPB_INLINE upb_strview upb_strview_make(const char *data, size_t size) { + upb_strview ret; + ret.data = data; + ret.size = size; + return ret; +} + +UPB_INLINE upb_strview upb_strview_makez(const char *data) { + return upb_strview_make(data, strlen(data)); +} + +UPB_INLINE bool upb_strview_eql(upb_strview a, upb_strview b) { + return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; +} + +#define UPB_STRVIEW_INIT(ptr, len) {ptr, len} + +#define UPB_STRVIEW_FORMAT "%.*s" +#define UPB_STRVIEW_ARGS(view) (int)(view).size, (view).data + /** upb_alloc *****************************************************************/ /* A upb_alloc is a possibly-stateful allocator object. -- cgit v1.2.3