From 9d17e97927360a3ce852e68f24acc0d43d3d794f Mon Sep 17 00:00:00 2001 From: Eric Salo Date: Wed, 7 Dec 2022 17:03:05 -0800 Subject: [PATCH 01/10] sync with current 21.x upb --- kokoro/macos/prepare_build_macos_rc | 2 +- php/ext/google/protobuf/php-upb.c | 20417 +++++++++++++----------- php/ext/google/protobuf/php-upb.h | 3064 ++-- protobuf_deps.bzl | 4 +- ruby/ext/google/protobuf_c/ruby-upb.c | 18155 +++++++++++---------- ruby/ext/google/protobuf_c/ruby-upb.h | 2089 ++- 6 files changed, 24179 insertions(+), 19552 deletions(-) diff --git a/kokoro/macos/prepare_build_macos_rc b/kokoro/macos/prepare_build_macos_rc index 9b9b2df7b8..7a150c79fb 100755 --- a/kokoro/macos/prepare_build_macos_rc +++ b/kokoro/macos/prepare_build_macos_rc @@ -36,7 +36,7 @@ pyenv install -v -s 2.7.18 && pyenv global 2.7.18 if [[ "${KOKORO_INSTALL_TOX:-}" == "yes" ]] ; then pyenv install -v -s 3.7.13 pyenv global 3.7.13 - sudo python -m pip install --upgrade pip tox tox-pyenv + sudo python -m pip install --upgrade pip 'tox==3.27.1' tox-pyenv fi ## diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index 1179ac3999..602509a64a 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -90,21 +90,22 @@ #define UPB_INLINE static #endif +#define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) -/* Hints to the compiler about likely/unlikely branches. */ +// Hints to the compiler about likely/unlikely branches. #if defined (__GNUC__) || defined(__clang__) -#define UPB_LIKELY(x) __builtin_expect((x),1) -#define UPB_UNLIKELY(x) __builtin_expect((x),0) +#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) +#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) #else #define UPB_LIKELY(x) (x) #define UPB_UNLIKELY(x) (x) #endif -/* Macros for function attributes on compilers that support them. */ +// Macros for function attributes on compilers that support them. #ifdef __GNUC__ #define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) #define UPB_NOINLINE __attribute__((noinline)) @@ -127,8 +128,7 @@ #define UPB_UNUSED(var) (void)var -/* UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. - */ +// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. #ifdef NDEBUG #ifdef __GNUC__ #define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() @@ -254,4893 +254,759 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #endif -/** upb/decode.c ************************************************************/ +/* Disable proto2 arena behavior (TEMPORARY) **********************************/ -#include -#include +#ifdef UPB_DISABLE_PROTO2_ENUM_CHECKING +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 1 +#else +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 +#endif +/** upb/collections.c ************************************************************/ -/* Must be last. */ +#include -/* Maps descriptor type -> elem_size_lg2. */ -static const uint8_t desctype_to_elem_size_lg2[] = { - -1, /* invalid descriptor type */ - 3, /* DOUBLE */ - 2, /* FLOAT */ - 3, /* INT64 */ - 3, /* UINT64 */ - 2, /* INT32 */ - 3, /* FIXED64 */ - 2, /* FIXED32 */ - 0, /* BOOL */ - UPB_SIZE(3, 4), /* STRING */ - UPB_SIZE(2, 3), /* GROUP */ - UPB_SIZE(2, 3), /* MESSAGE */ - UPB_SIZE(3, 4), /* BYTES */ - 2, /* UINT32 */ - 2, /* ENUM */ - 2, /* SFIXED32 */ - 3, /* SFIXED64 */ - 2, /* SINT32 */ - 3, /* SINT64 */ -}; -/* Maps descriptor type -> upb map size. */ -static const uint8_t desctype_to_mapsize[] = { - -1, /* invalid descriptor type */ - 8, /* DOUBLE */ - 4, /* FLOAT */ - 8, /* INT64 */ - 8, /* UINT64 */ - 4, /* INT32 */ - 8, /* FIXED64 */ - 4, /* FIXED32 */ - 1, /* BOOL */ - UPB_MAPTYPE_STRING, /* STRING */ - sizeof(void*), /* GROUP */ - sizeof(void*), /* MESSAGE */ - UPB_MAPTYPE_STRING, /* BYTES */ - 4, /* UINT32 */ - 4, /* ENUM */ - 4, /* SFIXED32 */ - 8, /* SFIXED64 */ - 4, /* SINT32 */ - 8, /* SINT64 */ +/* Strings/bytes are special-cased in maps. */ +static char _upb_CTypeo_mapsize[12] = { + 0, + 1, /* kUpb_CType_Bool */ + 4, /* kUpb_CType_Float */ + 4, /* kUpb_CType_Int32 */ + 4, /* kUpb_CType_UInt32 */ + 4, /* kUpb_CType_Enum */ + sizeof(void*), /* kUpb_CType_Message */ + 8, /* kUpb_CType_Double */ + 8, /* kUpb_CType_Int64 */ + 8, /* kUpb_CType_UInt64 */ + 0, /* kUpb_CType_String */ + 0, /* kUpb_CType_Bytes */ }; -static const unsigned FIXED32_OK_MASK = (1 << kUpb_FieldType_Float) | - (1 << kUpb_FieldType_Fixed32) | - (1 << kUpb_FieldType_SFixed32); - -static const unsigned FIXED64_OK_MASK = (1 << kUpb_FieldType_Double) | - (1 << kUpb_FieldType_Fixed64) | - (1 << kUpb_FieldType_SFixed64); - -/* Three fake field types for MessageSet. */ -#define TYPE_MSGSET_ITEM 19 -#define TYPE_MSGSET_TYPE_ID 20 -#define TYPE_COUNT 20 - -/* Op: an action to be performed for a wire-type/field-type combination. */ -#define OP_UNKNOWN -1 /* Unknown field. */ -#define OP_MSGSET_ITEM -2 -#define OP_MSGSET_TYPEID -3 -#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */ -#define OP_ENUM 1 -#define OP_STRING 4 -#define OP_BYTES 5 -#define OP_SUBMSG 6 -/* Scalar fields use only ops above. Repeated fields can use any op. */ -#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ -#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ -#define OP_PACKED_ENUM 13 - -static const int8_t varint_ops[] = { - OP_UNKNOWN, /* field not found */ - OP_UNKNOWN, /* DOUBLE */ - OP_UNKNOWN, /* FLOAT */ - OP_SCALAR_LG2(3), /* INT64 */ - OP_SCALAR_LG2(3), /* UINT64 */ - OP_SCALAR_LG2(2), /* INT32 */ - OP_UNKNOWN, /* FIXED64 */ - OP_UNKNOWN, /* FIXED32 */ - OP_SCALAR_LG2(0), /* BOOL */ - OP_UNKNOWN, /* STRING */ - OP_UNKNOWN, /* GROUP */ - OP_UNKNOWN, /* MESSAGE */ - OP_UNKNOWN, /* BYTES */ - OP_SCALAR_LG2(2), /* UINT32 */ - OP_ENUM, /* ENUM */ - OP_UNKNOWN, /* SFIXED32 */ - OP_UNKNOWN, /* SFIXED64 */ - OP_SCALAR_LG2(2), /* SINT32 */ - OP_SCALAR_LG2(3), /* SINT64 */ - OP_UNKNOWN, /* MSGSET_ITEM */ - OP_MSGSET_TYPEID, /* MSGSET TYPEID */ +static const char _upb_CTypeo_sizelg2[12] = { + 0, + 0, /* kUpb_CType_Bool */ + 2, /* kUpb_CType_Float */ + 2, /* kUpb_CType_Int32 */ + 2, /* kUpb_CType_UInt32 */ + 2, /* kUpb_CType_Enum */ + UPB_SIZE(2, 3), /* kUpb_CType_Message */ + 3, /* kUpb_CType_Double */ + 3, /* kUpb_CType_Int64 */ + 3, /* kUpb_CType_UInt64 */ + UPB_SIZE(3, 4), /* kUpb_CType_String */ + UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ }; -static const int8_t delim_ops[] = { - /* For non-repeated field type. */ - OP_UNKNOWN, /* field not found */ - OP_UNKNOWN, /* DOUBLE */ - OP_UNKNOWN, /* FLOAT */ - OP_UNKNOWN, /* INT64 */ - OP_UNKNOWN, /* UINT64 */ - OP_UNKNOWN, /* INT32 */ - OP_UNKNOWN, /* FIXED64 */ - OP_UNKNOWN, /* FIXED32 */ - OP_UNKNOWN, /* BOOL */ - OP_STRING, /* STRING */ - OP_UNKNOWN, /* GROUP */ - OP_SUBMSG, /* MESSAGE */ - OP_BYTES, /* BYTES */ - OP_UNKNOWN, /* UINT32 */ - OP_UNKNOWN, /* ENUM */ - OP_UNKNOWN, /* SFIXED32 */ - OP_UNKNOWN, /* SFIXED64 */ - OP_UNKNOWN, /* SINT32 */ - OP_UNKNOWN, /* SINT64 */ - OP_UNKNOWN, /* MSGSET_ITEM */ - OP_UNKNOWN, /* MSGSET TYPEID */ - /* For repeated field type. */ - OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */ - OP_FIXPCK_LG2(2), /* REPEATED FLOAT */ - OP_VARPCK_LG2(3), /* REPEATED INT64 */ - OP_VARPCK_LG2(3), /* REPEATED UINT64 */ - OP_VARPCK_LG2(2), /* REPEATED INT32 */ - OP_FIXPCK_LG2(3), /* REPEATED FIXED64 */ - OP_FIXPCK_LG2(2), /* REPEATED FIXED32 */ - OP_VARPCK_LG2(0), /* REPEATED BOOL */ - OP_STRING, /* REPEATED STRING */ - OP_SUBMSG, /* REPEATED GROUP */ - OP_SUBMSG, /* REPEATED MESSAGE */ - OP_BYTES, /* REPEATED BYTES */ - OP_VARPCK_LG2(2), /* REPEATED UINT32 */ - OP_PACKED_ENUM, /* REPEATED ENUM */ - OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */ - OP_FIXPCK_LG2(3), /* REPEATED SFIXED64 */ - OP_VARPCK_LG2(2), /* REPEATED SINT32 */ - OP_VARPCK_LG2(3), /* REPEATED SINT64 */ - /* Omitting MSGSET_*, because we never emit a repeated msgset type */ -}; +/** upb_Array *****************************************************************/ -typedef union { - bool bool_val; - uint32_t uint32_val; - uint64_t uint64_val; - uint32_t size; -} wireval; +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { + return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); +} -static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable* layout); +size_t upb_Array_Size(const upb_Array* arr) { return arr->len; } -UPB_NORETURN static void* decode_err(upb_Decoder* d, upb_DecodeStatus status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { + upb_MessageValue ret; + const char* data = _upb_array_constptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); + memcpy(&ret, data + (i << lg2), 1 << lg2); + return ret; } -const char* fastdecode_err(upb_Decoder* d, int status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); - return NULL; -} -static void decode_verifyutf8(upb_Decoder* d, const char* buf, int len) { - if (!decode_verifyutf8_inl(buf, len)) - decode_err(d, kUpb_DecodeStatus_BadUtf8); +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); + memcpy(data + (i << lg2), &val, 1 << lg2); } -static bool decode_reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { - bool need_realloc = arr->size - arr->len < elem; - if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); +bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + if (!upb_Array_Resize(arr, arr->len + 1, arena)) { + return false; } - return need_realloc; + upb_Array_Set(arr, arr->len - 1, val); + return true; } -typedef struct { - const char* ptr; - uint64_t val; -} decode_vret; +void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, + size_t count) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); +} -UPB_NOINLINE -static decode_vret decode_longvarint64(const char* ptr, uint64_t val) { - decode_vret ret = {NULL, 0}; - uint64_t byte; - int i; - for (i = 1; i < 10; i++) { - byte = (uint8_t)ptr[i]; - val += (byte - 1) << (i * 7); - if (!(byte & 0x80)) { - ret.ptr = ptr + i + 1; - ret.val = val; - return ret; - } +bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, + upb_Arena* arena) { + UPB_ASSERT(i <= arr->len); + UPB_ASSERT(count + arr->len >= count); + size_t oldsize = arr->len; + if (!upb_Array_Resize(arr, arr->len + count, arena)) { + return false; } - return ret; + upb_Array_Move(arr, i + count, i, oldsize - i); + return true; } -UPB_FORCEINLINE -static const char* decode_varint64(upb_Decoder* d, const char* ptr, - uint64_t* val) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = byte; - return ptr + 1; - } else { - decode_vret res = decode_longvarint64(ptr, byte); - if (!res.ptr) return decode_err(d, kUpb_DecodeStatus_Malformed); - *val = res.val; - return res.ptr; - } +/* + * i end arr->len + * |------------|XXXXXXXX|--------| + */ +void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { + size_t end = i + count; + UPB_ASSERT(i <= end); + UPB_ASSERT(end <= arr->len); + upb_Array_Move(arr, i, end, arr->len - end); + arr->len -= count; } -UPB_FORCEINLINE -static const char* decode_tag(upb_Decoder* d, const char* ptr, uint32_t* val) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = byte; - return ptr + 1; - } else { - const char* start = ptr; - decode_vret res = decode_longvarint64(ptr, byte); - if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - *val = res.val; - return res.ptr; - } +bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { + return _upb_Array_Resize(arr, size, arena); } -static void decode_munge_int32(wireval* val) { - if (!_upb_IsLittleEndian()) { - /* The next stage will memcpy(dst, &val, 4) */ - val->uint32_val = val->uint64_val; - } -} +/** upb_Map *******************************************************************/ -static void decode_munge(int type, wireval* val) { - switch (type) { - case kUpb_FieldType_Bool: - val->bool_val = val->uint64_val != 0; - break; - case kUpb_FieldType_SInt32: { - uint32_t n = val->uint64_val; - val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); - break; - } - case kUpb_FieldType_SInt64: { - uint64_t n = val->uint64_val; - val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); - break; - } - case kUpb_FieldType_Int32: - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Enum: - decode_munge_int32(val); - break; - } +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { + return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], + _upb_CTypeo_mapsize[value_type]); } -static upb_Message* decode_newsubmsg(upb_Decoder* d, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - return _upb_Message_New_inl(subl, &d->arena); -} +size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } -UPB_NOINLINE -const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, - int overrun) { - int status; - ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); - if (ptr == NULL) { - return decode_err(d, status); - } - return ptr; +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val) { + return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); } -static const char* decode_readstr(upb_Decoder* d, const char* ptr, int size, - upb_StringView* str) { - if (d->options & kUpb_DecodeOption_AliasString) { - str->data = ptr; - } else { - char* data = upb_Arena_Malloc(&d->arena, size); - if (!data) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - memcpy(data, ptr, size); - str->data = data; - } - str->size = size; - return ptr + size; +void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } + +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val, + map->val_size, arena); } -UPB_FORCEINLINE -static const char* decode_tosubmsg2(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable* subl, int size) { - int saved_delta = decode_pushlimit(d, ptr, size); - if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); - ptr = decode_msg(d, ptr, submsg, subl); - if (d->end_group != DECODE_NOGROUP) - return decode_err(d, kUpb_DecodeStatus_Malformed); - decode_poplimit(d, ptr, saved_delta); - d->depth++; - return ptr; +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { + return _upb_Map_Delete(map, &key, map->key_size); } -UPB_FORCEINLINE -static const char* decode_tosubmsg(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, int size) { - return decode_tosubmsg2(d, ptr, submsg, subs[field->submsg_index].submsg, - size); +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { + return _upb_map_next(map, iter); } -UPB_FORCEINLINE -static const char* decode_group(upb_Decoder* d, const char* ptr, - upb_Message* submsg, const upb_MiniTable* subl, - uint32_t number) { - if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); - if (decode_isdone(d, &ptr)) { - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - ptr = decode_msg(d, ptr, submsg, subl); - if (d->end_group != number) return decode_err(d, kUpb_DecodeStatus_Malformed); - d->end_group = DECODE_NOGROUP; - d->depth++; - return ptr; +bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + UPB_ASSERT(iter != kUpb_Map_Begin); + i.t = &map->table; + i.index = iter; + return upb_strtable_done(&i); } -UPB_FORCEINLINE -static const char* decode_togroup(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - return decode_group(d, ptr, submsg, subl, field->number); +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); + return ret; } -static char* encode_varint32(uint32_t val, char* ptr) { - do { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - *(ptr++) = byte; - } while (val); - return ptr; +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); + return ret; } -UPB_NOINLINE -static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, - uint32_t v) { - // OPT: binary search long lists? - int n = e->value_count; - for (int i = 0; i < n; i++) { - if ((uint32_t)e->values[i] == v) return true; - } +/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue + * value); */ - // Unrecognized enum goes into unknown fields. - // For packed fields the tag could be arbitrarily far in the past, so we - // just re-encode the tag here. - char buf[20]; - char* end = buf; - uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; - end = encode_varint32(tag, end); - end = encode_varint32(v, end); +/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upb.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ - if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } +#include - return false; -} -UPB_FORCEINLINE -static bool decode_checkenum(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, wireval* val) { - uint32_t v = val->uint32_val; +static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { + {.submsg = &google_protobuf_FileDescriptorProto_msginit}, +}; - if (UPB_LIKELY(v < 64) && UPB_LIKELY(((1ULL << v) & e->mask))) return true; +static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - return decode_checkenum_slow(d, ptr, msg, e, field, v); -} +const upb_MiniTable google_protobuf_FileDescriptorSet_msginit = { + &google_protobuf_FileDescriptorSet_submsgs[0], + &google_protobuf_FileDescriptorSet__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; -UPB_NOINLINE -static const char* decode_enum_toarray(upb_Decoder* d, const char* ptr, - upb_Message* msg, upb_Array* arr, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; - if (!decode_checkenum(d, ptr, msg, e, field, val)) return ptr; - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - arr->len++; - memcpy(mem, val, 4); - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { + {.submsg = &google_protobuf_DescriptorProto_msginit}, + {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, + {.submsg = &google_protobuf_ServiceDescriptorProto_msginit}, + {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, + {.submsg = &google_protobuf_FileOptions_msginit}, + {.submsg = &google_protobuf_SourceCodeInfo_msginit}, +}; -UPB_FORCEINLINE -static const char* decode_fixed_packed(upb_Decoder* d, const char* ptr, - upb_Array* arr, wireval* val, - const upb_MiniTable_Field* field, - int lg2) { - int mask = (1 << lg2) - 1; - size_t count = val->size >> lg2; - if ((val->size & mask) != 0) { - // Length isn't a round multiple of elem size. - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - decode_reserve(d, arr, count); - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - arr->len += count; - // Note: if/when the decoder supports multi-buffer input, we will need to - // handle buffer seams here. - if (_upb_IsLittleEndian()) { - memcpy(mem, ptr, val->size); - ptr += val->size; - } else { - const char* end = ptr + val->size; - char* dst = mem; - while (ptr < end) { - if (lg2 == 2) { - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap32(val); - memcpy(dst, &val, sizeof(val)); - } else { - UPB_ASSERT(lg2 == 3); - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap64(val); - memcpy(dst, &val, sizeof(val)); - } - ptr += 1 << lg2; - dst += 1 << lg2; - } - } +static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[12] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(24, 48), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(28, 56), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(32, 64), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(36, 72), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(40, 80), UPB_SIZE(3, 3), 4, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(44, 88), UPB_SIZE(4, 4), 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(48, 96), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(52, 104), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {12, UPB_SIZE(56, 112), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}; - return ptr; -} +const upb_MiniTable google_protobuf_FileDescriptorProto_msginit = { + &google_protobuf_FileDescriptorProto_submsgs[0], + &google_protobuf_FileDescriptorProto__fields[0], + UPB_SIZE(64, 128), 12, kUpb_ExtMode_NonExtendable, 12, 255, 0, +}; -UPB_FORCEINLINE -static const char* decode_varint_packed(upb_Decoder* d, const char* ptr, - upb_Array* arr, wireval* val, - const upb_MiniTable_Field* field, - int lg2) { - int scale = 1 << lg2; - int saved_limit = decode_pushlimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - while (!decode_isdone(d, &ptr)) { - wireval elem; - ptr = decode_varint64(d, ptr, &elem.uint64_val); - decode_munge(field->descriptortype, &elem); - if (decode_reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - } - arr->len++; - memcpy(out, &elem, scale); - out += scale; - } - decode_poplimit(d, ptr, saved_limit); - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[8] = { + {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, + {.submsg = &google_protobuf_DescriptorProto_msginit}, + {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, + {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msginit}, + {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, + {.submsg = &google_protobuf_MessageOptions_msginit}, + {.submsg = &google_protobuf_OneofDescriptorProto_msginit}, + {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msginit}, +}; -UPB_NOINLINE -static const char* decode_enum_packed(upb_Decoder* d, const char* ptr, - upb_Message* msg, upb_Array* arr, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; - int saved_limit = decode_pushlimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - while (!decode_isdone(d, &ptr)) { - wireval elem; - ptr = decode_varint64(d, ptr, &elem.uint64_val); - decode_munge_int32(&elem); - if (!decode_checkenum(d, ptr, msg, e, field, &elem)) { - continue; - } - if (decode_reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - } - arr->len++; - memcpy(out, &elem, 4); - out += 4; - } - decode_poplimit(d, ptr, saved_limit); - return ptr; -} +static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 48), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 56), UPB_SIZE(0, 0), 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(32, 64), UPB_SIZE(2, 2), 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(36, 72), UPB_SIZE(0, 0), 6, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(40, 80), UPB_SIZE(0, 0), 7, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(44, 88), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static const char* decode_toarray(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val, int op) { - upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); - upb_Array* arr = *arrp; - void* mem; +const upb_MiniTable google_protobuf_DescriptorProto_msginit = { + &google_protobuf_DescriptorProto_submsgs[0], + &google_protobuf_DescriptorProto__fields[0], + UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, 255, 0, +}; - if (arr) { - decode_reserve(d, arr, 1); - } else { - size_t lg2 = desctype_to_elem_size_lg2[field->descriptortype]; - arr = _upb_Array_New(&d->arena, 4, lg2); - if (!arr) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - *arrp = arr; - } +static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { + {.submsg = &google_protobuf_ExtensionRangeOptions_msginit}, +}; - switch (op) { - case OP_SCALAR_LG2(0): - case OP_SCALAR_LG2(2): - case OP_SCALAR_LG2(3): - /* Append scalar value. */ - mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << op, void); - arr->len++; - memcpy(mem, val, 1 << op); - return ptr; - case OP_STRING: - decode_verifyutf8(d, ptr, val->size); - /* Fallthrough. */ - case OP_BYTES: { - /* Append bytes. */ - upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->len; - arr->len++; - return decode_readstr(d, ptr, val->size, str); - } - case OP_SUBMSG: { - /* Append submessage / group. */ - upb_Message* submsg = decode_newsubmsg(d, subs, field); - *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void*), upb_Message*) = - submsg; - arr->len++; - if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { - return decode_togroup(d, ptr, submsg, subs, field); - } else { - return decode_tosubmsg(d, ptr, submsg, subs, field, val->size); - } - } - case OP_FIXPCK_LG2(2): - case OP_FIXPCK_LG2(3): - return decode_fixed_packed(d, ptr, arr, val, field, - op - OP_FIXPCK_LG2(0)); - case OP_VARPCK_LG2(0): - case OP_VARPCK_LG2(2): - case OP_VARPCK_LG2(3): - return decode_varint_packed(d, ptr, arr, val, field, - op - OP_VARPCK_LG2(0)); - case OP_ENUM: - return decode_enum_toarray(d, ptr, msg, arr, subs, field, val); - case OP_PACKED_ENUM: - return decode_enum_packed(d, ptr, msg, arr, subs, field, val); - default: - UPB_UNREACHABLE(); - } -} +static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 16), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static const char* decode_tomap(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*); - upb_Map* map = *map_p; - upb_MapEntry ent; - const upb_MiniTable* entry = subs[field->submsg_index].submsg; +const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit = { + &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], + &google_protobuf_DescriptorProto_ExtensionRange__fields[0], + UPB_SIZE(16, 24), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; - if (!map) { - /* Lazily create map. */ - const upb_MiniTable_Field* key_field = &entry->fields[0]; - const upb_MiniTable_Field* val_field = &entry->fields[1]; - char key_size = desctype_to_mapsize[key_field->descriptortype]; - char val_size = desctype_to_mapsize[val_field->descriptortype]; - UPB_ASSERT(key_field->offset == 0); - UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); - map = _upb_Map_New(&d->arena, key_size, val_size); - *map_p = map; - } +static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; - /* Parse map entry. */ - memset(&ent, 0, sizeof(ent)); +const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit = { + NULL, + &google_protobuf_DescriptorProto_ReservedRange__fields[0], + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; - if (entry->fields[1].descriptortype == kUpb_FieldType_Message || - entry->fields[1].descriptortype == kUpb_FieldType_Group) { - /* Create proactively to handle the case where it doesn't appear. */ - ent.v.val = - upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); - } +static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size); - _upb_Map_Set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena); - return ptr; -} +static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { + {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static const char* decode_tomsg(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, wireval* val, - int op) { - void* mem = UPB_PTR_AT(msg, field->offset, void); - int type = field->descriptortype; +const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit = { + &google_protobuf_ExtensionRangeOptions_submsgs[0], + &google_protobuf_ExtensionRangeOptions__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - if (UPB_UNLIKELY(op == OP_ENUM) && - !decode_checkenum(d, ptr, msg, subs[field->submsg_index].subenum, field, - val)) { - return ptr; - } +static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { + {.subenum = &google_protobuf_FieldDescriptorProto_Label_enuminit}, + {.subenum = &google_protobuf_FieldDescriptorProto_Type_enuminit}, + {.submsg = &google_protobuf_FieldOptions_msginit}, +}; - /* Set presence if necessary. */ - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (field->presence < 0) { - /* Oneof case */ - uint32_t* oneof_case = _upb_oneofcase_field(msg, field); - if (op == OP_SUBMSG && *oneof_case != field->number) { - memset(mem, 0, sizeof(void*)); - } - *oneof_case = field->number; - } +static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { + {1, UPB_SIZE(24, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(32, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 4), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), UPB_SIZE(4, 4), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(12, 12), UPB_SIZE(5, 5), 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(40, 56), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(48, 72), UPB_SIZE(7, 7), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(56, 88), UPB_SIZE(8, 8), 2, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(16, 16), UPB_SIZE(9, 9), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(60, 96), UPB_SIZE(10, 10), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(20, 20), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; - /* Store into message. */ - switch (op) { - case OP_SUBMSG: { - upb_Message** submsgp = mem; - upb_Message* submsg = *submsgp; - if (!submsg) { - submsg = decode_newsubmsg(d, subs, field); - *submsgp = submsg; - } - if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { - ptr = decode_togroup(d, ptr, submsg, subs, field); - } else { - ptr = decode_tosubmsg(d, ptr, submsg, subs, field, val->size); - } - break; - } - case OP_STRING: - decode_verifyutf8(d, ptr, val->size); - /* Fallthrough. */ - case OP_BYTES: - return decode_readstr(d, ptr, val->size, mem); - case OP_SCALAR_LG2(3): - memcpy(mem, val, 8); - break; - case OP_ENUM: - case OP_SCALAR_LG2(2): - memcpy(mem, val, 4); - break; - case OP_SCALAR_LG2(0): - memcpy(mem, val, 1); - break; - default: - UPB_UNREACHABLE(); - } +const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit = { + &google_protobuf_FieldDescriptorProto_submsgs[0], + &google_protobuf_FieldDescriptorProto__fields[0], + UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, 255, 0, +}; - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_OneofOptions_msginit}, +}; -UPB_NOINLINE -const char* decode_checkrequired(upb_Decoder* d, const char* ptr, - const upb_Message* msg, - const upb_MiniTable* l) { - assert(l->required_count); - if (UPB_LIKELY((d->options & kUpb_DecodeOption_CheckRequired) == 0)) { - return ptr; - } - uint64_t msg_head; - memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); - if (upb_MiniTable_requiredmask(l) & ~msg_head) { - d->missing_required = true; - } - return ptr; -} +static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -UPB_FORCEINLINE -static bool decode_tryfastdispatch(upb_Decoder* d, const char** ptr, - upb_Message* msg, - const upb_MiniTable* layout) { -#if UPB_FASTTABLE - if (layout && layout->table_mask != (unsigned char)-1) { - uint16_t tag = fastdecode_loadtag(*ptr); - intptr_t table = decode_totable(layout); - *ptr = fastdecode_tagdispatch(d, *ptr, msg, table, 0, tag); - return true; - } -#endif - return false; -} +const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit = { + &google_protobuf_OneofDescriptorProto_submsgs[0], + &google_protobuf_OneofDescriptorProto__fields[0], + UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; -static const char* decode_msgset(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable* layout) { - // We create a temporary upb_MiniTable here and abuse its fields as temporary - // storage, to avoid creating lots of MessageSet-specific parsing code-paths: - // 1. We store 'layout' in item_layout.subs. We will need this later as - // a key to look up extensions for this MessageSet. - // 2. We use item_layout.fields as temporary storage to store the extension - // we - // found when parsing the type id. - upb_MiniTable item_layout = { - .subs = (const upb_MiniTable_Sub[]){{.submsg = layout}}, - .fields = NULL, - .size = 0, - .field_count = 0, - .ext = upb_ExtMode_IsMessageSet_ITEM, - .dense_below = 0, - .table_mask = -1}; - return decode_group(d, ptr, msg, &item_layout, 1); -} +static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { + {.submsg = &google_protobuf_EnumValueDescriptorProto_msginit}, + {.submsg = &google_protobuf_EnumOptions_msginit}, + {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit}, +}; -static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d, - const upb_MiniTable* l, - uint32_t field_number, - int* last_field_index) { - static upb_MiniTable_Field none = {0, 0, 0, 0, 0, 0}; - if (l == NULL) return &none; +static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 48), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX - if (idx < l->dense_below) { - /* Fastest case: index into dense fields. */ - goto found; - } +const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit = { + &google_protobuf_EnumDescriptorProto_submsgs[0], + &google_protobuf_EnumDescriptorProto__fields[0], + UPB_SIZE(32, 56), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, +}; - if (l->dense_below < l->field_count) { - /* Linear search non-dense fields. Resume scanning from last_field_index - * since fields are usually in order. */ - int last = *last_field_index; - for (idx = last; idx < l->field_count; idx++) { - if (l->fields[idx].number == field_number) { - goto found; - } - } +static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; - for (idx = l->dense_below; idx < last; idx++) { - if (l->fields[idx].number == field_number) { - goto found; - } - } - } +const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { + NULL, + &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; - if (d->extreg) { - switch (l->ext) { - case upb_ExtMode_Extendable: { - const upb_MiniTable_Extension* ext = - _upb_extreg_get(d->extreg, l, field_number); - if (ext) return &ext->field; - break; - } - case upb_ExtMode_IsMessageSet: - if (field_number == _UPB_MSGSET_ITEM) { - static upb_MiniTable_Field item = {0, 0, 0, 0, TYPE_MSGSET_ITEM, 0}; - return &item; - } - break; - case upb_ExtMode_IsMessageSet_ITEM: - switch (field_number) { - case _UPB_MSGSET_TYPEID: { - static upb_MiniTable_Field type_id = { - 0, 0, 0, 0, TYPE_MSGSET_TYPE_ID, 0}; - return &type_id; - } - case _UPB_MSGSET_MESSAGE: - if (l->fields) { - // We saw type_id previously and succeeded in looking up msg. - return l->fields; - } else { - // TODO: out of order MessageSet. - // This is a very rare case: all serializers will emit in-order - // MessageSets. To hit this case there has to be some kind of - // re-ordering proxy. We should eventually handle this case, but - // not today. - } - break; - } - } - } +static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_EnumValueOptions_msginit}, +}; - return &none; /* Unknown field. */ +static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { + {1, UPB_SIZE(8, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 24), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -found: - UPB_ASSERT(l->fields[idx].number == field_number); - *last_field_index = idx; - return &l->fields[idx]; -} +const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit = { + &google_protobuf_EnumValueDescriptorProto_submsgs[0], + &google_protobuf_EnumValueDescriptorProto__fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; -UPB_FORCEINLINE -static const char* decode_wireval(upb_Decoder* d, const char* ptr, - const upb_MiniTable_Field* field, - int wire_type, wireval* val, int* op) { - switch (wire_type) { - case kUpb_WireType_Varint: - ptr = decode_varint64(d, ptr, &val->uint64_val); - *op = varint_ops[field->descriptortype]; - decode_munge(field->descriptortype, val); - return ptr; - case kUpb_WireType_32Bit: - memcpy(&val->uint32_val, ptr, 4); - val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val); - *op = OP_SCALAR_LG2(2); - if (((1 << field->descriptortype) & FIXED32_OK_MASK) == 0) { - *op = OP_UNKNOWN; - } - return ptr + 4; - case kUpb_WireType_64Bit: - memcpy(&val->uint64_val, ptr, 8); - val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); - *op = OP_SCALAR_LG2(3); - if (((1 << field->descriptortype) & FIXED64_OK_MASK) == 0) { - *op = OP_UNKNOWN; - } - return ptr + 8; - case kUpb_WireType_Delimited: { - int ndx = field->descriptortype; - uint64_t size; - if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += TYPE_COUNT; - ptr = decode_varint64(d, ptr, &size); - if (size >= INT32_MAX || ptr - d->end + (int32_t)size > d->limit) { - break; /* Length overflow. */ - } - *op = delim_ops[ndx]; - val->size = size; - return ptr; - } - case kUpb_WireType_StartGroup: - val->uint32_val = field->number; - if (field->descriptortype == kUpb_FieldType_Group) { - *op = OP_SUBMSG; - } else if (field->descriptortype == TYPE_MSGSET_ITEM) { - *op = OP_MSGSET_ITEM; - } else { - *op = OP_UNKNOWN; - } - return ptr; - default: - break; - } - return decode_err(d, kUpb_DecodeStatus_Malformed); -} +static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { + {.submsg = &google_protobuf_MethodDescriptorProto_msginit}, + {.submsg = &google_protobuf_ServiceOptions_msginit}, +}; -UPB_FORCEINLINE -static const char* decode_known(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable* layout, - const upb_MiniTable_Field* field, int op, - wireval* val) { - const upb_MiniTable_Sub* subs = layout->subs; - uint8_t mode = field->mode; +static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (UPB_UNLIKELY(mode & upb_LabelFlags_IsExtension)) { - const upb_MiniTable_Extension* ext_layout = - (const upb_MiniTable_Extension*)field; - upb_Message_Extension* ext = - _upb_Message_Getorcreateext(msg, ext_layout, &d->arena); - if (UPB_UNLIKELY(!ext)) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - msg = &ext->data; - subs = &ext->ext->sub; - } +const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit = { + &google_protobuf_ServiceDescriptorProto_submsgs[0], + &google_protobuf_ServiceDescriptorProto__fields[0], + UPB_SIZE(24, 40), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; - switch (mode & kUpb_FieldMode_Mask) { - case kUpb_FieldMode_Array: - return decode_toarray(d, ptr, msg, subs, field, val, op); - case kUpb_FieldMode_Map: - return decode_tomap(d, ptr, msg, subs, field, val); - case kUpb_FieldMode_Scalar: - return decode_tomsg(d, ptr, msg, subs, field, val, op); - default: - UPB_UNREACHABLE(); - } -} +static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_MethodOptions_msginit}, +}; -static const char* decode_reverse_skip_varint(const char* ptr, uint32_t val) { - uint32_t seen = 0; - do { - ptr--; - seen <<= 7; - seen |= *ptr & 0x7f; - } while (seen != val); - return ptr; -} +static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), UPB_SIZE(3, 3), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(28, 56), UPB_SIZE(4, 4), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(1, 1), UPB_SIZE(5, 5), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(2, 2), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; -static const char* decode_unknown(upb_Decoder* d, const char* ptr, - upb_Message* msg, int field_number, - int wire_type, wireval val) { - if (field_number == 0) return decode_err(d, kUpb_DecodeStatus_Malformed); +const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit = { + &google_protobuf_MethodDescriptorProto_submsgs[0], + &google_protobuf_MethodDescriptorProto__fields[0], + UPB_SIZE(32, 64), 6, kUpb_ExtMode_NonExtendable, 6, 255, 0, +}; - // Since unknown fields are the uncommon case, we do a little extra work here - // to walk backwards through the buffer to find the field start. This frees - // up a register in the fast paths (when the field is known), which leads to - // significant speedups in benchmarks. - const char* start = ptr; +static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { + {.subenum = &google_protobuf_FileOptions_OptimizeMode_enuminit}, + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - if (wire_type == kUpb_WireType_Delimited) ptr += val.size; - if (msg) { - switch (wire_type) { - case kUpb_WireType_Varint: - case kUpb_WireType_Delimited: - start--; - while (start[-1] & 0x80) start--; - break; - case kUpb_WireType_32Bit: - start -= 4; - break; - case kUpb_WireType_64Bit: - start -= 8; - break; - default: - break; - } +static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { + {1, UPB_SIZE(20, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(28, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(4, 4), UPB_SIZE(3, 3), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(8, 8), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(36, 56), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {16, UPB_SIZE(9, 9), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(10, 10), UPB_SIZE(7, 7), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {18, UPB_SIZE(11, 11), UPB_SIZE(8, 8), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {20, UPB_SIZE(12, 12), UPB_SIZE(9, 9), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {23, UPB_SIZE(13, 13), UPB_SIZE(10, 10), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {27, UPB_SIZE(14, 14), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {31, UPB_SIZE(15, 15), UPB_SIZE(12, 12), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {36, UPB_SIZE(44, 72), UPB_SIZE(13, 13), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {37, UPB_SIZE(52, 88), UPB_SIZE(14, 14), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {39, UPB_SIZE(60, 104), UPB_SIZE(15, 15), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {40, UPB_SIZE(68, 120), UPB_SIZE(16, 16), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {41, UPB_SIZE(76, 136), UPB_SIZE(17, 17), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {42, UPB_SIZE(16, 16), UPB_SIZE(18, 18), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {44, UPB_SIZE(84, 152), UPB_SIZE(19, 19), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {45, UPB_SIZE(92, 168), UPB_SIZE(20, 20), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(100, 184), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - assert(start == d->debug_valstart); - uint32_t tag = ((uint32_t)field_number << 3) | wire_type; - start = decode_reverse_skip_varint(start, tag); - assert(start == d->debug_tagstart); +const upb_MiniTable google_protobuf_FileOptions_msginit = { + &google_protobuf_FileOptions_submsgs[0], + &google_protobuf_FileOptions__fields[0], + UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, 255, 0, +}; - if (wire_type == kUpb_WireType_StartGroup) { - d->unknown = start; - d->unknown_msg = msg; - ptr = decode_group(d, ptr, NULL, NULL, field_number); - start = d->unknown; - d->unknown_msg = NULL; - d->unknown = NULL; - } - if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { - return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - } else if (wire_type == kUpb_WireType_StartGroup) { - ptr = decode_group(d, ptr, NULL, NULL, field_number); - } - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; -UPB_NOINLINE -static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable* layout) { - int last_field_index = 0; +static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = { + {1, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(2, 2), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(3, 3), UPB_SIZE(3, 3), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(4, 4), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(8, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#if UPB_FASTTABLE - // The first time we want to skip fast dispatch, because we may have just been - // invoked by the fast parser to handle a case that it bailed on. - if (!decode_isdone(d, &ptr)) goto nofast; -#endif +const upb_MiniTable google_protobuf_MessageOptions_msginit = { + &google_protobuf_MessageOptions_submsgs[0], + &google_protobuf_MessageOptions__fields[0], + UPB_SIZE(16, 16), 5, kUpb_ExtMode_Extendable, 3, 255, 0, +}; - while (!decode_isdone(d, &ptr)) { - uint32_t tag; - const upb_MiniTable_Field* field; - int field_number; - int wire_type; - wireval val; - int op; +static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { + {.subenum = &google_protobuf_FieldOptions_CType_enuminit}, + {.subenum = &google_protobuf_FieldOptions_JSType_enuminit}, + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - if (decode_tryfastdispatch(d, &ptr, msg, layout)) break; +static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[8] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(9, 9), UPB_SIZE(3, 3), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(10, 10), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(12, 12), UPB_SIZE(5, 5), 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(16, 16), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {15, UPB_SIZE(17, 17), UPB_SIZE(7, 7), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#if UPB_FASTTABLE - nofast: -#endif +const upb_MiniTable google_protobuf_FieldOptions_msginit = { + &google_protobuf_FieldOptions_submsgs[0], + &google_protobuf_FieldOptions__fields[0], + UPB_SIZE(24, 32), 8, kUpb_ExtMode_Extendable, 3, 255, 0, +}; -#ifndef NDEBUG - d->debug_tagstart = ptr; -#endif +static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - UPB_ASSERT(ptr < d->limit_ptr); - ptr = decode_tag(d, ptr, &tag); - field_number = tag >> 3; - wire_type = tag & 7; +static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { + {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#ifndef NDEBUG - d->debug_valstart = ptr; -#endif +const upb_MiniTable google_protobuf_OneofOptions_msginit = { + &google_protobuf_OneofOptions_submsgs[0], + &google_protobuf_OneofOptions__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - if (wire_type == kUpb_WireType_EndGroup) { - d->end_group = field_number; - return ptr; - } +static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - field = decode_findfield(d, layout, field_number, &last_field_index); - ptr = decode_wireval(d, ptr, field, wire_type, &val, &op); +static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = { + {2, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(2, 2), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (op >= 0) { - ptr = decode_known(d, ptr, msg, layout, field, op, &val); - } else { - switch (op) { - case OP_UNKNOWN: - ptr = decode_unknown(d, ptr, msg, field_number, wire_type, val); - break; - case OP_MSGSET_ITEM: - ptr = decode_msgset(d, ptr, msg, layout); - break; - case OP_MSGSET_TYPEID: { - const upb_MiniTable_Extension* ext = _upb_extreg_get( - d->extreg, layout->subs[0].submsg, val.uint64_val); - if (ext) ((upb_MiniTable*)layout)->fields = &ext->field; - break; - } - } - } - } +const upb_MiniTable google_protobuf_EnumOptions_msginit = { + &google_protobuf_EnumOptions_submsgs[0], + &google_protobuf_EnumOptions__fields[0], + UPB_SIZE(8, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - return UPB_UNLIKELY(layout && layout->required_count) - ? decode_checkrequired(d, ptr, msg, layout) - : ptr; -} +static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; -const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - (void)data; - *(uint32_t*)msg |= hasbits; - return decode_msg(d, ptr, msg, decode_totablep(table)); -} +static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = { + {1, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static upb_DecodeStatus decode_top(struct upb_Decoder* d, const char* buf, - void* msg, const upb_MiniTable* l) { - if (!decode_tryfastdispatch(d, &buf, msg, l)) { - decode_msg(d, buf, msg, l); - } - if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; - if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; - return kUpb_DecodeStatus_Ok; -} +const upb_MiniTable google_protobuf_EnumValueOptions_msginit = { + &google_protobuf_EnumValueOptions_submsgs[0], + &google_protobuf_EnumValueOptions__fields[0], + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 1, 255, 0, +}; -upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg, - const upb_MiniTable* l, - const upb_ExtensionRegistry* extreg, int options, - upb_Arena* arena) { - upb_Decoder state; - unsigned depth = (unsigned)options >> 16; +static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - if (size <= 16) { - memset(&state.patch, 0, 32); - if (size) memcpy(&state.patch, buf, size); - buf = state.patch; - state.end = buf + size; - state.limit = 0; - options &= ~kUpb_DecodeOption_AliasString; // Can't alias patch buf. - } else { - state.end = buf + size - 16; - state.limit = 16; - } +static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = { + {33, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - state.extreg = extreg; - state.limit_ptr = state.end; - state.unknown_msg = NULL; - state.depth = depth ? depth : 64; - state.end_group = DECODE_NOGROUP; - state.options = (uint16_t)options; - state.missing_required = false; - state.arena.head = arena->head; - state.arena.last_size = arena->last_size; - state.arena.cleanup_metadata = arena->cleanup_metadata; - state.arena.parent = arena; +const upb_MiniTable google_protobuf_ServiceOptions_msginit = { + &google_protobuf_ServiceOptions_submsgs[0], + &google_protobuf_ServiceOptions__fields[0], + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - upb_DecodeStatus status = UPB_SETJMP(state.err); - if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { - status = decode_top(&state, buf, msg, l); - } +static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { + {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enuminit}, + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - arena->head.ptr = state.arena.head.ptr; - arena->head.end = state.arena.head.end; - arena->cleanup_metadata = state.arena.cleanup_metadata; - return status; -} +static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = { + {33, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, UPB_SIZE(4, 4), UPB_SIZE(2, 2), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(8, 8), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#undef OP_UNKNOWN -#undef OP_SKIP -#undef OP_SCALAR_LG2 -#undef OP_FIXPCK_LG2 -#undef OP_VARPCK_LG2 -#undef OP_STRING -#undef OP_BYTES -#undef OP_SUBMSG +const upb_MiniTable google_protobuf_MethodOptions_msginit = { + &google_protobuf_MethodOptions_submsgs[0], + &google_protobuf_MethodOptions__fields[0], + UPB_SIZE(16, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, +}; -/** upb/encode.c ************************************************************/ -/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ +static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_NamePart_msginit}, +}; +static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { + {2, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 16), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(32, 64), UPB_SIZE(2, 2), kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(40, 72), UPB_SIZE(3, 3), kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(48, 80), UPB_SIZE(4, 4), kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(16, 32), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(24, 48), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}; -#include -#include +const upb_MiniTable google_protobuf_UninterpretedOption_msginit = { + &google_protobuf_UninterpretedOption_submsgs[0], + &google_protobuf_UninterpretedOption__fields[0], + UPB_SIZE(56, 88), 7, kUpb_ExtMode_NonExtendable, 0, 255, 0, +}; +static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(1, 1), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; -/* Must be last. */ +const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit = { + NULL, + &google_protobuf_UninterpretedOption_NamePart__fields[0], + UPB_SIZE(16, 24), 2, kUpb_ExtMode_NonExtendable, 2, 255, 2, +}; -#define UPB_PB_VARINT_MAX_LEN 10 +static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_SourceCodeInfo_Location_msginit}, +}; -UPB_NOINLINE -static size_t encode_varint64(uint64_t val, char* buf) { - size_t i = 0; - do { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - buf[i++] = byte; - } while (val); - return i; -} +static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static uint32_t encode_zz32(int32_t n) { - return ((uint32_t)n << 1) ^ (n >> 31); -} -static uint64_t encode_zz64(int64_t n) { - return ((uint64_t)n << 1) ^ (n >> 63); -} +const upb_MiniTable google_protobuf_SourceCodeInfo_msginit = { + &google_protobuf_SourceCodeInfo_submsgs[0], + &google_protobuf_SourceCodeInfo__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; -typedef struct { - jmp_buf err; - upb_alloc* alloc; - char *buf, *ptr, *limit; - int options; - int depth; - _upb_mapsorter sorter; -} upb_encstate; - -static size_t upb_roundup_pow2(size_t bytes) { - size_t ret = 128; - while (ret < bytes) { - ret *= 2; - } - return ret; -} - -UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); } - -UPB_NOINLINE -static void encode_growbuffer(upb_encstate* e, size_t bytes) { - size_t old_size = e->limit - e->buf; - size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); - char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); - - if (!new_buf) encode_err(e); - - /* We want previous data at the end, realloc() put it at the beginning. */ - if (old_size > 0) { - memmove(new_buf + new_size - old_size, e->buf, old_size); - } +static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 56), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - e->ptr = new_buf + new_size - (e->limit - e->ptr); - e->limit = new_buf + new_size; - e->buf = new_buf; +const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit = { + NULL, + &google_protobuf_SourceCodeInfo_Location__fields[0], + UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 4, 255, 0, +}; - e->ptr -= bytes; -} +static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msginit}, +}; -/* Call to ensure that at least "bytes" bytes are available for writing at - * e->ptr. Returns false if the bytes could not be allocated. */ -UPB_FORCEINLINE -static void encode_reserve(upb_encstate* e, size_t bytes) { - if ((size_t)(e->ptr - e->buf) < bytes) { - encode_growbuffer(e, bytes); - return; - } +static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - e->ptr -= bytes; -} +const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit = { + &google_protobuf_GeneratedCodeInfo_submsgs[0], + &google_protobuf_GeneratedCodeInfo__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; -/* Writes the given bytes to the buffer, handling reserve/advance. */ -static void encode_bytes(upb_encstate* e, const void* data, size_t len) { - if (len == 0) return; /* memcpy() with zero size is UB */ - encode_reserve(e, len); - memcpy(e->ptr, data, len); -} +static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { + {1, UPB_SIZE(12, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(16, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; -static void encode_fixed64(upb_encstate* e, uint64_t val) { - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, sizeof(uint64_t)); -} +const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit = { + NULL, + &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], + UPB_SIZE(24, 40), 4, kUpb_ExtMode_NonExtendable, 4, 255, 0, +}; -static void encode_fixed32(upb_encstate* e, uint32_t val) { - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, sizeof(uint32_t)); -} +static const upb_MiniTable *messages_layout[27] = { + &google_protobuf_FileDescriptorSet_msginit, + &google_protobuf_FileDescriptorProto_msginit, + &google_protobuf_DescriptorProto_msginit, + &google_protobuf_DescriptorProto_ExtensionRange_msginit, + &google_protobuf_DescriptorProto_ReservedRange_msginit, + &google_protobuf_ExtensionRangeOptions_msginit, + &google_protobuf_FieldDescriptorProto_msginit, + &google_protobuf_OneofDescriptorProto_msginit, + &google_protobuf_EnumDescriptorProto_msginit, + &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, + &google_protobuf_EnumValueDescriptorProto_msginit, + &google_protobuf_ServiceDescriptorProto_msginit, + &google_protobuf_MethodDescriptorProto_msginit, + &google_protobuf_FileOptions_msginit, + &google_protobuf_MessageOptions_msginit, + &google_protobuf_FieldOptions_msginit, + &google_protobuf_OneofOptions_msginit, + &google_protobuf_EnumOptions_msginit, + &google_protobuf_EnumValueOptions_msginit, + &google_protobuf_ServiceOptions_msginit, + &google_protobuf_MethodOptions_msginit, + &google_protobuf_UninterpretedOption_msginit, + &google_protobuf_UninterpretedOption_NamePart_msginit, + &google_protobuf_SourceCodeInfo_msginit, + &google_protobuf_SourceCodeInfo_Location_msginit, + &google_protobuf_GeneratedCodeInfo_msginit, + &google_protobuf_GeneratedCodeInfo_Annotation_msginit, +}; -UPB_NOINLINE -static void encode_longvarint(upb_encstate* e, uint64_t val) { - size_t len; - char* start; +const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit = { + NULL, + 0x7fffeULL, + 0, +}; - encode_reserve(e, UPB_PB_VARINT_MAX_LEN); - len = encode_varint64(val, e->ptr); - start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; - memmove(start, e->ptr, len); - e->ptr = start; -} +const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit = { + NULL, + 0xeULL, + 0, +}; -UPB_FORCEINLINE -static void encode_varint(upb_encstate* e, uint64_t val) { - if (val < 128 && e->ptr != e->buf) { - --e->ptr; - *e->ptr = val; - } else { - encode_longvarint(e, val); - } -} +const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit = { + NULL, + 0xeULL, + 0, +}; -static void encode_double(upb_encstate* e, double d) { - uint64_t u64; - UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); - memcpy(&u64, &d, sizeof(uint64_t)); - encode_fixed64(e, u64); -} +const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit = { + NULL, + 0x7ULL, + 0, +}; -static void encode_float(upb_encstate* e, float d) { - uint32_t u32; - UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); - memcpy(&u32, &d, sizeof(uint32_t)); - encode_fixed32(e, u32); -} +const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit = { + NULL, + 0x7ULL, + 0, +}; -static void encode_tag(upb_encstate* e, uint32_t field_number, - uint8_t wire_type) { - encode_varint(e, (field_number << 3) | wire_type); -} +const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit = { + NULL, + 0x7ULL, + 0, +}; -static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, - size_t elem_size, uint32_t tag) { - size_t bytes = arr->len * elem_size; - const char* data = _upb_array_constptr(arr); - const char* ptr = data + bytes - elem_size; +static const upb_MiniTable_Enum *enums_layout[6] = { + &google_protobuf_FieldDescriptorProto_Type_enuminit, + &google_protobuf_FieldDescriptorProto_Label_enuminit, + &google_protobuf_FileOptions_OptimizeMode_enuminit, + &google_protobuf_FieldOptions_CType_enuminit, + &google_protobuf_FieldOptions_JSType_enuminit, + &google_protobuf_MethodOptions_IdempotencyLevel_enuminit, +}; - if (tag || !_upb_IsLittleEndian()) { - while (true) { - if (elem_size == 4) { - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, elem_size); - } else { - UPB_ASSERT(elem_size == 8); - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, elem_size); - } +const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { + messages_layout, + enums_layout, + NULL, + 27, + 6, + 0, +}; - if (tag) encode_varint(e, tag); - if (ptr == data) break; - ptr -= elem_size; - } - } else { - encode_bytes(e, data, bytes); - } -} -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size); -static void encode_scalar(upb_encstate* e, const void* _field_mem, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const char* field_mem = _field_mem; - int wire_type; - -#define CASE(ctype, type, wtype, encodeval) \ - { \ - ctype val = *(ctype*)field_mem; \ - encode_##type(e, encodeval); \ - wire_type = wtype; \ - break; \ - } - - switch (f->descriptortype) { - case kUpb_FieldType_Double: - CASE(double, double, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Float: - CASE(float, float, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - CASE(uint64_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_UInt32: - CASE(uint32_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Bool: - CASE(bool, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_SInt32: - CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); - case kUpb_FieldType_SInt64: - CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - upb_StringView view = *(upb_StringView*)field_mem; - encode_bytes(e, view.data, view.size); - encode_varint(e, view.size); - wire_type = kUpb_WireType_Delimited; - break; - } - case kUpb_FieldType_Group: { - size_t size; - void* submsg = *(void**)field_mem; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (submsg == NULL) { - return; - } - if (--e->depth == 0) encode_err(e); - encode_tag(e, f->number, kUpb_WireType_EndGroup); - encode_message(e, submsg, subm, &size); - wire_type = kUpb_WireType_StartGroup; - e->depth++; - break; - } - case kUpb_FieldType_Message: { - size_t size; - void* submsg = *(void**)field_mem; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (submsg == NULL) { - return; - } - if (--e->depth == 0) encode_err(e); - encode_message(e, submsg, subm, &size); - encode_varint(e, size); - wire_type = kUpb_WireType_Delimited; - e->depth++; - break; - } - default: - UPB_UNREACHABLE(); - } -#undef CASE - - encode_tag(e, f->number, wire_type); -} - -static void encode_array(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); - bool packed = f->mode & upb_LabelFlags_IsPacked; - size_t pre_len = e->limit - e->ptr; - - if (arr == NULL || arr->len == 0) { - return; - } - -#define VARINT_CASE(ctype, encode) \ - { \ - const ctype* start = _upb_array_constptr(arr); \ - const ctype* ptr = start + arr->len; \ - uint32_t tag = packed ? 0 : (f->number << 3) | kUpb_WireType_Varint; \ - do { \ - ptr--; \ - encode_varint(e, encode); \ - if (tag) encode_varint(e, tag); \ - } while (ptr != start); \ - } \ - break; - -#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) - - switch (f->descriptortype) { - case kUpb_FieldType_Double: - encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Float: - encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - VARINT_CASE(uint64_t, *ptr); - case kUpb_FieldType_UInt32: - VARINT_CASE(uint32_t, *ptr); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - VARINT_CASE(int32_t, (int64_t)*ptr); - case kUpb_FieldType_Bool: - VARINT_CASE(bool, *ptr); - case kUpb_FieldType_SInt32: - VARINT_CASE(int32_t, encode_zz32(*ptr)); - case kUpb_FieldType_SInt64: - VARINT_CASE(int64_t, encode_zz64(*ptr)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - const upb_StringView* start = _upb_array_constptr(arr); - const upb_StringView* ptr = start + arr->len; - do { - ptr--; - encode_bytes(e, ptr->data, ptr->size); - encode_varint(e, ptr->size); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } while (ptr != start); - return; - } - case kUpb_FieldType_Group: { - const void* const* start = _upb_array_constptr(arr); - const void* const* ptr = start + arr->len; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); - do { - size_t size; - ptr--; - encode_tag(e, f->number, kUpb_WireType_EndGroup); - encode_message(e, *ptr, subm, &size); - encode_tag(e, f->number, kUpb_WireType_StartGroup); - } while (ptr != start); - e->depth++; - return; - } - case kUpb_FieldType_Message: { - const void* const* start = _upb_array_constptr(arr); - const void* const* ptr = start + arr->len; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); - do { - size_t size; - ptr--; - encode_message(e, *ptr, subm, &size); - encode_varint(e, size); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } while (ptr != start); - e->depth++; - return; - } - } -#undef VARINT_CASE - - if (packed) { - encode_varint(e, e->limit - e->ptr - pre_len); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } -} - -static void encode_mapentry(upb_encstate* e, uint32_t number, - const upb_MiniTable* layout, - const upb_MapEntry* ent) { - const upb_MiniTable_Field* key_field = &layout->fields[0]; - const upb_MiniTable_Field* val_field = &layout->fields[1]; - size_t pre_len = e->limit - e->ptr; - size_t size; - encode_scalar(e, &ent->v, layout->subs, val_field); - encode_scalar(e, &ent->k, layout->subs, key_field); - size = (e->limit - e->ptr) - pre_len; - encode_varint(e, size); - encode_tag(e, number, kUpb_WireType_Delimited); -} - -static void encode_map(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const upb_Map* map = *UPB_PTR_AT(msg, f->offset, const upb_Map*); - const upb_MiniTable* layout = subs[f->submsg_index].submsg; - UPB_ASSERT(layout->field_count == 2); - - if (map == NULL) return; - - if (e->options & kUpb_Encode_Deterministic) { - _upb_sortedmap sorted; - _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, - &sorted); - upb_MapEntry ent; - while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { - encode_mapentry(e, f->number, layout, &ent); - } - _upb_mapsorter_popmap(&e->sorter, &sorted); - } else { - upb_strtable_iter i; - upb_strtable_begin(&i, &map->table); - for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_StringView key = upb_strtable_iter_key(&i); - const upb_value val = upb_strtable_iter_value(&i); - upb_MapEntry ent; - _upb_map_fromkey(key, &ent.k, map->key_size); - _upb_map_fromvalue(val, &ent.v, map->val_size); - encode_mapentry(e, f->number, layout, &ent); - } - } -} - -static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - if (f->presence == 0) { - /* Proto3 presence or map/array. */ - const void* mem = UPB_PTR_AT(msg, f->offset, void); - switch (f->mode >> upb_FieldRep_Shift) { - case upb_FieldRep_1Byte: { - char ch; - memcpy(&ch, mem, 1); - return ch != 0; - } - case upb_FieldRep_4Byte: { - uint32_t u32; - memcpy(&u32, mem, 4); - return u32 != 0; - } - case upb_FieldRep_8Byte: { - uint64_t u64; - memcpy(&u64, mem, 8); - return u64 != 0; - } - case upb_FieldRep_StringView: { - const upb_StringView* str = (const upb_StringView*)mem; - return str->size != 0; - } - default: - UPB_UNREACHABLE(); - } - } else if (f->presence > 0) { - /* Proto2 presence: hasbit. */ - return _upb_hasbit_field(msg, f); - } else { - /* Field is in a oneof. */ - return _upb_getoneofcase_field(msg, f) == f->number; - } -} - -static void encode_field(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - switch (upb_FieldMode_Get(field)) { - case kUpb_FieldMode_Array: - encode_array(e, msg, subs, field); - break; - case kUpb_FieldMode_Map: - encode_map(e, msg, subs, field); - break; - case kUpb_FieldMode_Scalar: - encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field); - break; - default: - UPB_UNREACHABLE(); - } -} - -/* message MessageSet { - * repeated group Item = 1 { - * required int32 type_id = 2; - * required string message = 3; - * } - * } */ -static void encode_msgset_item(upb_encstate* e, - const upb_Message_Extension* ext) { - size_t size; - encode_tag(e, 1, kUpb_WireType_EndGroup); - encode_message(e, ext->data.ptr, ext->ext->sub.submsg, &size); - encode_varint(e, size); - encode_tag(e, 3, kUpb_WireType_Delimited); - encode_varint(e, ext->ext->field.number); - encode_tag(e, 2, kUpb_WireType_Varint); - encode_tag(e, 1, kUpb_WireType_StartGroup); -} - -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size) { - size_t pre_len = e->limit - e->ptr; - - if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) { - uint64_t msg_head; - memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); - if (upb_MiniTable_requiredmask(m) & ~msg_head) { - encode_err(e); - } - } - - if ((e->options & kUpb_Encode_SkipUnknown) == 0) { - size_t unknown_size; - const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); - - if (unknown) { - encode_bytes(e, unknown, unknown_size); - } - } - - if (m->ext != upb_ExtMode_NonExtendable) { - /* Encode all extensions together. Unlike C++, we do not attempt to keep - * these in field number order relative to normal fields or even to each - * other. */ - size_t ext_count; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count); - if (ext_count) { - const upb_Message_Extension* end = ext + ext_count; - for (; ext != end; ext++) { - if (UPB_UNLIKELY(m->ext == upb_ExtMode_IsMessageSet)) { - encode_msgset_item(e, ext); - } else { - encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); - } - } - } - } - - if (m->field_count) { - const upb_MiniTable_Field* f = &m->fields[m->field_count]; - const upb_MiniTable_Field* first = &m->fields[0]; - while (f != first) { - f--; - if (encode_shouldencode(e, msg, m->subs, f)) { - encode_field(e, msg, m->subs, f); - } - } - } - - *size = (e->limit - e->ptr) - pre_len; -} - -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size) { - upb_encstate e; - unsigned depth = (unsigned)options >> 16; - - e.alloc = upb_Arena_Alloc(arena); - e.buf = NULL; - e.limit = NULL; - e.ptr = NULL; - e.depth = depth ? depth : 64; - e.options = options; - _upb_mapsorter_init(&e.sorter); - char* ret = NULL; - - if (UPB_SETJMP(e.err)) { - *size = 0; - ret = NULL; - } else { - encode_message(&e, msg, l, size); - *size = e.limit - e.ptr; - if (*size == 0) { - static char ch; - ret = &ch; - } else { - UPB_ASSERT(e.ptr); - ret = e.ptr; - } - } - - _upb_mapsorter_destroy(&e.sorter); - return ret; -} - -/** upb/msg.c ************************************************************/ - - -/** upb_Message - * *******************************************************************/ - -static const size_t overhead = sizeof(upb_Message_InternalData); - -static const upb_Message_Internal* upb_Message_Getinternal_const( - const upb_Message* msg) { - ptrdiff_t size = sizeof(upb_Message_Internal); - return (upb_Message_Internal*)((char*)msg - size); -} - -upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a) { - return _upb_Message_New_inl(l, a); -} - -void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { - void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char); - memset(mem, 0, upb_msg_sizeof(l)); -} - -static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (!in->internal) { - /* No internal data, allocate from scratch. */ - size_t size = UPB_MAX(128, _upb_Log2Ceilingsize(need + overhead)); - upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); - if (!internal) return false; - internal->size = size; - internal->unknown_end = overhead; - internal->ext_begin = size; - in->internal = internal; - } else if (in->internal->ext_begin - in->internal->unknown_end < need) { - /* Internal data is too small, reallocate. */ - size_t new_size = _upb_Log2Ceilingsize(in->internal->size + need); - size_t ext_bytes = in->internal->size - in->internal->ext_begin; - size_t new_ext_begin = new_size - ext_bytes; - upb_Message_InternalData* internal = - upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size); - if (!internal) return false; - if (ext_bytes) { - /* Need to move extension data to the end. */ - char* ptr = (char*)internal; - memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes); - } - internal->ext_begin = new_ext_begin; - internal->size = new_size; - in->internal = internal; - } - UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); - return true; -} - -bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, - upb_Arena* arena) { - if (!realloc_internal(msg, len, arena)) return false; - upb_Message_Internal* in = upb_Message_Getinternal(msg); - memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len); - in->internal->unknown_end += len; - return true; -} - -void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (in->internal) { - in->internal->unknown_end = overhead; - } -} - -const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { - const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); - if (in->internal) { - *len = in->internal->unknown_end - overhead; - return (char*)(in->internal + 1); - } else { - *len = 0; - return NULL; - } -} - -const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, - size_t* count) { - const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); - if (in->internal) { - *count = (in->internal->size - in->internal->ext_begin) / - sizeof(upb_Message_Extension); - return UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - } else { - *count = 0; - return NULL; - } -} - -const upb_Message_Extension* _upb_Message_Getext( - const upb_Message* msg, const upb_MiniTable_Extension* e) { - size_t n; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); - - /* For now we use linear search exclusively to find extensions. If this - * becomes an issue due to messages with lots of extensions, we can introduce - * a table of some sort. */ - for (size_t i = 0; i < n; i++) { - if (ext[i].ext == e) { - return &ext[i]; - } - } - - return NULL; -} - -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext_l) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (!in->internal) return; - const upb_Message_Extension* base = - UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - upb_Message_Extension* ext = - (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); - if (ext) { - *ext = *base; - in->internal->ext_begin += sizeof(upb_Message_Extension); - } -} - -upb_Message_Extension* _upb_Message_Getorcreateext( - upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) { - upb_Message_Extension* ext = - (upb_Message_Extension*)_upb_Message_Getext(msg, e); - if (ext) return ext; - if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL; - upb_Message_Internal* in = upb_Message_Getinternal(msg); - in->internal->ext_begin -= sizeof(upb_Message_Extension); - ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - memset(ext, 0, sizeof(upb_Message_Extension)); - ext->ext = e; - return ext; -} - -size_t upb_Message_ExtensionCount(const upb_Message* msg) { - size_t count; - _upb_Message_Getexts(msg, &count); - return count; -} - -/** upb_Array *****************************************************************/ - -bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena) { - size_t new_size = UPB_MAX(arr->size, 4); - int elem_size_lg2 = arr->data & 7; - size_t old_bytes = arr->size << elem_size_lg2; - size_t new_bytes; - void* ptr = _upb_array_ptr(arr); - - /* Log2 ceiling of size. */ - while (new_size < min_size) new_size *= 2; - - new_bytes = new_size << elem_size_lg2; - ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); - - if (!ptr) { - return false; - } - - arr->data = _upb_tag_arrptr(ptr, elem_size_lg2); - arr->size = new_size; - return true; -} - -static upb_Array* getorcreate_array(upb_Array** arr_ptr, int elem_size_lg2, - upb_Arena* arena) { - upb_Array* arr = *arr_ptr; - if (!arr) { - arr = _upb_Array_New(arena, 4, elem_size_lg2); - if (!arr) return NULL; - *arr_ptr = arr; - } - return arr; -} - -void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, - int elem_size_lg2, upb_Arena* arena) { - upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); - return arr && _upb_Array_Resize(arr, size, arena) ? _upb_array_ptr(arr) - : NULL; -} - -bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, - int elem_size_lg2, upb_Arena* arena) { - upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); - if (!arr) return false; - - size_t elems = arr->len; - - if (!_upb_Array_Resize(arr, elems + 1, arena)) { - return false; - } - - char* data = _upb_array_ptr(arr); - memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2); - return true; -} - -/** upb_Map *******************************************************************/ - -upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { - upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); - - if (!map) { - return NULL; - } - - upb_strtable_init(&map->table, 4, a); - map->key_size = key_size; - map->val_size = value_size; - - return map; -} - -static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, - void* b_key, size_t size) { - const upb_tabent* const* a = _a; - const upb_tabent* const* b = _b; - upb_StringView a_tabkey = upb_tabstrview((*a)->key); - upb_StringView b_tabkey = upb_tabstrview((*b)->key); - _upb_map_fromkey(a_tabkey, a_key, size); - _upb_map_fromkey(b_tabkey, b_key, size); -} - -#define UPB_COMPARE_INTEGERS(a, b) ((a) < (b) ? -1 : ((a) == (b) ? 0 : 1)) - -static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { - int64_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); - return UPB_COMPARE_INTEGERS(a, b); -} - -static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { - uint64_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); - return UPB_COMPARE_INTEGERS(a, b); -} - -static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { - int32_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); - return UPB_COMPARE_INTEGERS(a, b); -} - -static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { - uint32_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); - return UPB_COMPARE_INTEGERS(a, b); -} - -static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { - bool a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); - return UPB_COMPARE_INTEGERS(a, b); -} - -static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { - upb_StringView a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); - size_t common_size = UPB_MIN(a.size, b.size); - int cmp = memcmp(a.data, b.data, common_size); - if (cmp) return -cmp; - return UPB_COMPARE_INTEGERS(a.size, b.size); -} - -#undef UPB_COMPARE_INTEGERS - -bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, - const upb_Map* map, _upb_sortedmap* sorted) { - int map_size = _upb_Map_Size(map); - sorted->start = s->size; - sorted->pos = sorted->start; - sorted->end = sorted->start + map_size; - - /* Grow s->entries if necessary. */ - if (sorted->end > s->cap) { - s->cap = _upb_Log2Ceilingsize(sorted->end); - s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); - if (!s->entries) return false; - } - - s->size = sorted->end; - - /* Copy non-empty entries from the table to s->entries. */ - upb_tabent const** dst = &s->entries[sorted->start]; - const upb_tabent* src = map->table.t.entries; - const upb_tabent* end = src + upb_table_size(&map->table.t); - for (; src < end; src++) { - if (!upb_tabent_isempty(src)) { - *dst = src; - dst++; - } - } - UPB_ASSERT(dst == &s->entries[sorted->end]); - - /* Sort entries according to the key type. */ - - int (*compar)(const void*, const void*); - - switch (key_type) { - case kUpb_FieldType_Int64: - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_SInt64: - compar = _upb_mapsorter_cmpi64; - break; - case kUpb_FieldType_UInt64: - case kUpb_FieldType_Fixed64: - compar = _upb_mapsorter_cmpu64; - break; - case kUpb_FieldType_Int32: - case kUpb_FieldType_SInt32: - case kUpb_FieldType_SFixed32: - case kUpb_FieldType_Enum: - compar = _upb_mapsorter_cmpi32; - break; - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Fixed32: - compar = _upb_mapsorter_cmpu32; - break; - case kUpb_FieldType_Bool: - compar = _upb_mapsorter_cmpbool; - break; - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: - compar = _upb_mapsorter_cmpstr; - break; - default: - UPB_UNREACHABLE(); - } - - qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); - return true; -} - -/** upb_ExtensionRegistry - * ****************************************************************/ - -struct upb_ExtensionRegistry { - upb_Arena* arena; - upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ -}; - -#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) - -static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { - memcpy(buf, &l, sizeof(l)); - memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); -} - -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { - upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); - if (!r) return NULL; - r->arena = arena; - if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; - return r; -} - -bool _upb_extreg_add(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, size_t count) { - char buf[EXTREG_KEY_SIZE]; - const upb_MiniTable_Extension** start = e; - const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); - for (; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, - upb_value_constptr(ext), r->arena)) { - goto failure; - } - } - return true; - -failure: - /* Back out the entries previously added. */ - for (end = e, e = start; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); - } - return false; -} - -const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, - const upb_MiniTable* l, - uint32_t num) { - char buf[EXTREG_KEY_SIZE]; - upb_value v; - extreg_key(buf, l, num); - if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { - return upb_value_getconstptr(v); - } else { - return NULL; - } -} - -/** upb/table.c ************************************************************/ -/* - * upb_table Implementation - * - * Implementation is heavily inspired by Lua's ltable.c. - */ - -#include - - -/* Must be last. */ - -#define UPB_MAXARRSIZE 16 /* 64k. */ - -/* From Chromium. */ -#define ARRAY_SIZE(x) \ - ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) - -static const double MAX_LOAD = 0.85; - -/* The minimum utilization of the array part of a mixed hash/array table. This - * is a speed/memory-usage tradeoff (though it's not straightforward because of - * cache effects). The lower this is, the more memory we'll use. */ -static const double MIN_DENSITY = 0.1; - -static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } - -static upb_value _upb_value_val(uint64_t val) { - upb_value ret; - _upb_value_setval(&ret, val); - return ret; -} - -static int log2ceil(uint64_t v) { - int ret = 0; - bool pow2 = is_pow2(v); - while (v >>= 1) ret++; - ret = pow2 ? ret : ret + 1; /* Ceiling. */ - return UPB_MIN(UPB_MAXARRSIZE, ret); -} - -char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { - size_t n; - char* p; - - /* Prevent overflow errors. */ - if (len == SIZE_MAX) return NULL; - /* Always null-terminate, even if binary data; but don't rely on the input to - * have a null-terminating byte since it may be a raw binary buffer. */ - n = len + 1; - p = upb_Arena_Malloc(a, n); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; -} - -/* A type to represent the lookup key of either a strtable or an inttable. */ -typedef union { - uintptr_t num; - struct { - const char* str; - size_t len; - } str; -} lookupkey_t; - -static lookupkey_t strkey2(const char* str, size_t len) { - lookupkey_t k; - k.str.str = str; - k.str.len = len; - return k; -} - -static lookupkey_t intkey(uintptr_t key) { - lookupkey_t k; - k.num = key; - return k; -} - -typedef uint32_t hashfunc_t(upb_tabkey key); -typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); - -/* Base table (shared code) ***************************************************/ - -static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } - -static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { - return t->entries + (hash & t->mask); -} - -static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } - -static bool isfull(upb_table* t) { return t->count == t->max_count; } - -static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { - size_t bytes; - - t->count = 0; - t->size_lg2 = size_lg2; - t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; - t->max_count = upb_table_size(t) * MAX_LOAD; - bytes = upb_table_size(t) * sizeof(upb_tabent); - if (bytes > 0) { - t->entries = upb_Arena_Malloc(a, bytes); - if (!t->entries) return false; - memset(t->entries, 0, bytes); - } else { - t->entries = NULL; - } - return true; -} - -static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { - upb_tabent* begin = t->entries; - upb_tabent* end = begin + upb_table_size(t); - for (e = e + 1; e < end; e++) { - if (upb_tabent_isempty(e)) return e; - } - for (e = begin; e < end; e++) { - if (upb_tabent_isempty(e)) return e; - } - UPB_ASSERT(false); - return NULL; -} - -static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { - return (upb_tabent*)upb_getentry(t, hash); -} - -static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e; - - if (t->size_lg2 == 0) return NULL; - e = upb_getentry(t, hash); - if (upb_tabent_isempty(e)) return NULL; - while (1) { - if (eql(e->key, key)) return e; - if ((e = e->next) == NULL) return NULL; - } -} - -static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - return (upb_tabent*)findentry(t, key, hash, eql); -} - -static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e = findentry(t, key, hash, eql); - if (e) { - if (v) { - _upb_value_setval(v, e->val.val); - } - return true; - } else { - return false; - } -} - -/* The given key must not already exist in the table. */ -static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey, - upb_value val, uint32_t hash, hashfunc_t* hashfunc, - eqlfunc_t* eql) { - upb_tabent* mainpos_e; - upb_tabent* our_e; - - UPB_ASSERT(findentry(t, key, hash, eql) == NULL); - - t->count++; - mainpos_e = getentry_mutable(t, hash); - our_e = mainpos_e; - - if (upb_tabent_isempty(mainpos_e)) { - /* Our main position is empty; use it. */ - our_e->next = NULL; - } else { - /* Collision. */ - upb_tabent* new_e = emptyent(t, mainpos_e); - /* Head of collider's chain. */ - upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key)); - if (chain == mainpos_e) { - /* Existing ent is in its main position (it has the same hash as us, and - * is the head of our chain). Insert to new ent and append to this chain. - */ - new_e->next = mainpos_e->next; - mainpos_e->next = new_e; - our_e = new_e; - } else { - /* Existing ent is not in its main position (it is a node in some other - * chain). This implies that no existing ent in the table has our hash. - * Evict it (updating its chain) and use its ent for head of our chain. */ - *new_e = *mainpos_e; /* copies next. */ - while (chain->next != mainpos_e) { - chain = (upb_tabent*)chain->next; - UPB_ASSERT(chain); - } - chain->next = new_e; - our_e = mainpos_e; - our_e->next = NULL; - } - } - our_e->key = tabkey; - our_e->val.val = val.val; - UPB_ASSERT(findentry(t, key, hash, eql) == our_e); -} - -static bool rm(upb_table* t, lookupkey_t key, upb_value* val, - upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) { - upb_tabent* chain = getentry_mutable(t, hash); - if (upb_tabent_isempty(chain)) return false; - if (eql(chain->key, key)) { - /* Element to remove is at the head of its chain. */ - t->count--; - if (val) _upb_value_setval(val, chain->val.val); - if (removed) *removed = chain->key; - if (chain->next) { - upb_tabent* move = (upb_tabent*)chain->next; - *chain = *move; - move->key = 0; /* Make the slot empty. */ - } else { - chain->key = 0; /* Make the slot empty. */ - } - return true; - } else { - /* Element to remove is either in a non-head position or not in the - * table. */ - while (chain->next && !eql(chain->next->key, key)) { - chain = (upb_tabent*)chain->next; - } - if (chain->next) { - /* Found element to remove. */ - upb_tabent* rm = (upb_tabent*)chain->next; - t->count--; - if (val) _upb_value_setval(val, chain->next->val.val); - if (removed) *removed = rm->key; - rm->key = 0; /* Make the slot empty. */ - chain->next = rm->next; - return true; - } else { - /* Element to remove is not in the table. */ - return false; - } - } -} - -static size_t next(const upb_table* t, size_t i) { - do { - if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ - } while (upb_tabent_isempty(&t->entries[i])); - - return i; -} - -static size_t begin(const upb_table* t) { return next(t, -1); } - -/* upb_strtable ***************************************************************/ - -/* A simple "subclass" of upb_table that only adds a hash function for strings. - */ - -static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) { - uint32_t len = (uint32_t)k2.str.len; - char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1); - if (str == NULL) return 0; - memcpy(str, &len, sizeof(uint32_t)); - if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); - str[sizeof(uint32_t) + k2.str.len] = '\0'; - return (uintptr_t)str; -} - -/* Adapted from ABSL's wyhash. */ - -static uint64_t UnalignedLoad64(const void* p) { - uint64_t val; - memcpy(&val, p, 8); - return val; -} - -static uint32_t UnalignedLoad32(const void* p) { - uint32_t val; - memcpy(&val, p, 4); - return val; -} - -#if defined(_MSC_VER) && defined(_M_X64) -#include -#endif - -/* Computes a * b, returning the low 64 bits of the result and storing the high - * 64 bits in |*high|. */ -static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { -#ifdef __SIZEOF_INT128__ - __uint128_t p = v0; - p *= v1; - *out_high = (uint64_t)(p >> 64); - return (uint64_t)p; -#elif defined(_MSC_VER) && defined(_M_X64) - return _umul128(v0, v1, out_high); -#else - uint64_t a32 = v0 >> 32; - uint64_t a00 = v0 & 0xffffffff; - uint64_t b32 = v1 >> 32; - uint64_t b00 = v1 & 0xffffffff; - uint64_t high = a32 * b32; - uint64_t low = a00 * b00; - uint64_t mid1 = a32 * b00; - uint64_t mid2 = a00 * b32; - low += (mid1 << 32) + (mid2 << 32); - // Omit carry bit, for mixing we do not care about exact numerical precision. - high += (mid1 >> 32) + (mid2 >> 32); - *out_high = high; - return low; -#endif -} - -static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { - uint64_t high; - uint64_t low = upb_umul128(v0, v1, &high); - return low ^ high; -} - -static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, - const uint64_t salt[]) { - const uint8_t* ptr = (const uint8_t*)data; - uint64_t starting_length = (uint64_t)len; - uint64_t current_state = seed ^ salt[0]; - - if (len > 64) { - // If we have more than 64 bytes, we're going to handle chunks of 64 - // bytes at a time. We're going to build up two separate hash states - // which we will then hash together. - uint64_t duplicated_state = current_state; - - do { - uint64_t a = UnalignedLoad64(ptr); - uint64_t b = UnalignedLoad64(ptr + 8); - uint64_t c = UnalignedLoad64(ptr + 16); - uint64_t d = UnalignedLoad64(ptr + 24); - uint64_t e = UnalignedLoad64(ptr + 32); - uint64_t f = UnalignedLoad64(ptr + 40); - uint64_t g = UnalignedLoad64(ptr + 48); - uint64_t h = UnalignedLoad64(ptr + 56); - - uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); - current_state = (cs0 ^ cs1); - - uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); - uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); - duplicated_state = (ds0 ^ ds1); - - ptr += 64; - len -= 64; - } while (len > 64); - - current_state = current_state ^ duplicated_state; - } - - // We now have a data `ptr` with at most 64 bytes and the current state - // of the hashing state machine stored in current_state. - while (len > 16) { - uint64_t a = UnalignedLoad64(ptr); - uint64_t b = UnalignedLoad64(ptr + 8); - - current_state = WyhashMix(a ^ salt[1], b ^ current_state); - - ptr += 16; - len -= 16; - } - - // We now have a data `ptr` with at most 16 bytes. - uint64_t a = 0; - uint64_t b = 0; - if (len > 8) { - // When we have at least 9 and at most 16 bytes, set A to the first 64 - // bits of the input and B to the last 64 bits of the input. Yes, they will - // overlap in the middle if we are working with less than the full 16 - // bytes. - a = UnalignedLoad64(ptr); - b = UnalignedLoad64(ptr + len - 8); - } else if (len > 3) { - // If we have at least 4 and at most 8 bytes, set A to the first 32 - // bits and B to the last 32 bits. - a = UnalignedLoad32(ptr); - b = UnalignedLoad32(ptr + len - 4); - } else if (len > 0) { - // If we have at least 1 and at most 3 bytes, read all of the provided - // bits into A, with some adjustments. - a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); - b = 0; - } else { - a = 0; - b = 0; - } - - uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t z = salt[1] ^ starting_length; - return WyhashMix(w, z); -} - -const uint64_t kWyhashSalt[5] = { - 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, - 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, -}; - -static uint32_t table_hash(const char* p, size_t n) { - return Wyhash(p, n, 0, kWyhashSalt); -} - -static uint32_t strhash(upb_tabkey key) { - uint32_t len; - char* str = upb_tabstr(key, &len); - return table_hash(str, len); -} - -static bool streql(upb_tabkey k1, lookupkey_t k2) { - uint32_t len; - char* str = upb_tabstr(k1, &len); - return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); -} - -bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { - // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 - // denominator. - size_t need_entries = (expected_size + 1) * 1204 / 1024; - UPB_ASSERT(need_entries >= expected_size * 0.85); - int size_lg2 = _upb_Log2Ceiling(need_entries); - return init(&t->t, size_lg2, a); -} - -void upb_strtable_clear(upb_strtable* t) { - size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); - t->t.count = 0; - memset((char*)t->t.entries, 0, bytes); -} - -bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { - upb_strtable new_table; - upb_strtable_iter i; - - if (!init(&new_table.t, size_lg2, a)) return false; - upb_strtable_begin(&i, t); - for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_StringView key = upb_strtable_iter_key(&i); - upb_strtable_insert(&new_table, key.data, key.size, - upb_strtable_iter_value(&i), a); - } - *t = new_table; - return true; -} - -bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, - upb_value v, upb_Arena* a) { - lookupkey_t key; - upb_tabkey tabkey; - uint32_t hash; - - if (isfull(&t->t)) { - /* Need to resize. New table of double the size, add old elements to it. */ - if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { - return false; - } - } - - key = strkey2(k, len); - tabkey = strcopy(key, a); - if (tabkey == 0) return false; - - hash = table_hash(key.str.str, key.str.len); - insert(&t->t, key, tabkey, v, hash, &strhash, &streql); - return true; -} - -bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, - upb_value* v) { - uint32_t hash = table_hash(key, len); - return lookup(&t->t, strkey2(key, len), v, hash, &streql); -} - -bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, - upb_value* val) { - uint32_t hash = table_hash(key, len); - upb_tabkey tabkey; - return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); -} - -/* Iteration */ - -void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { - i->t = t; - i->index = begin(&t->t); -} - -void upb_strtable_next(upb_strtable_iter* i) { - i->index = next(&i->t->t, i->index); -} - -bool upb_strtable_done(const upb_strtable_iter* i) { - if (!i->t) return true; - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(str_tabent(i)); -} - -upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { - upb_StringView key; - uint32_t len; - UPB_ASSERT(!upb_strtable_done(i)); - key.data = upb_tabstr(str_tabent(i)->key, &len); - key.size = len; - return key; -} - -upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { - UPB_ASSERT(!upb_strtable_done(i)); - return _upb_value_val(str_tabent(i)->val.val); -} - -void upb_strtable_iter_setdone(upb_strtable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; -} - -bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, - const upb_strtable_iter* i2) { - if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; - return i1->t == i2->t && i1->index == i2->index; -} - -/* upb_inttable ***************************************************************/ - -/* For inttables we use a hybrid structure where small keys are kept in an - * array and large keys are put in the hash table. */ - -static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } - -static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } - -static upb_tabval* mutable_array(upb_inttable* t) { - return (upb_tabval*)t->array; -} - -static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) { - if (key < t->array_size) { - return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; - } else { - upb_tabent* e = - findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); - return e ? &e->val : NULL; - } -} - -static const upb_tabval* inttable_val_const(const upb_inttable* t, - uintptr_t key) { - return inttable_val((upb_inttable*)t, key); -} - -size_t upb_inttable_count(const upb_inttable* t) { - return t->t.count + t->array_count; -} - -static void check(upb_inttable* t) { - UPB_UNUSED(t); -#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) - { - /* This check is very expensive (makes inserts/deletes O(N)). */ - size_t count = 0; - upb_inttable_iter i; - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { - UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); - } - UPB_ASSERT(count == upb_inttable_count(t)); - } -#endif -} - -bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, - upb_Arena* a) { - size_t array_bytes; - - if (!init(&t->t, hsize_lg2, a)) return false; - /* Always make the array part at least 1 long, so that we know key 0 - * won't be in the hash part, which simplifies things. */ - t->array_size = UPB_MAX(1, asize); - t->array_count = 0; - array_bytes = t->array_size * sizeof(upb_value); - t->array = upb_Arena_Malloc(a, array_bytes); - if (!t->array) { - return false; - } - memset(mutable_array(t), 0xff, array_bytes); - check(t); - return true; -} - -bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { - return upb_inttable_sizedinit(t, 0, 4, a); -} - -bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, - upb_Arena* a) { - upb_tabval tabval; - tabval.val = val.val; - UPB_ASSERT( - upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ - - if (key < t->array_size) { - UPB_ASSERT(!upb_arrhas(t->array[key])); - t->array_count++; - mutable_array(t)[key].val = val.val; - } else { - if (isfull(&t->t)) { - /* Need to resize the hash part, but we re-use the array part. */ - size_t i; - upb_table new_table; - - if (!init(&new_table, t->t.size_lg2 + 1, a)) { - return false; - } - - for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { - const upb_tabent* e = &t->t.entries[i]; - uint32_t hash; - upb_value v; - - _upb_value_setval(&v, e->val.val); - hash = upb_inthash(e->key); - insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); - } - - UPB_ASSERT(t->t.count == new_table.count); - - t->t = new_table; - } - insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); - } - check(t); - return true; -} - -bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { - const upb_tabval* table_v = inttable_val_const(t, key); - if (!table_v) return false; - if (v) _upb_value_setval(v, table_v->val); - return true; -} - -bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { - upb_tabval* table_v = inttable_val(t, key); - if (!table_v) return false; - table_v->val = val.val; - return true; -} - -bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { - bool success; - if (key < t->array_size) { - if (upb_arrhas(t->array[key])) { - upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; - t->array_count--; - if (val) { - _upb_value_setval(val, t->array[key].val); - } - mutable_array(t)[key] = empty; - success = true; - } else { - success = false; - } - } else { - success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); - } - check(t); - return success; -} - -void upb_inttable_compact(upb_inttable* t, upb_Arena* a) { - /* A power-of-two histogram of the table keys. */ - size_t counts[UPB_MAXARRSIZE + 1] = {0}; - - /* The max key in each bucket. */ - uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; - - upb_inttable_iter i; - size_t arr_count; - int size_lg2; - upb_inttable new_t; - - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t key = upb_inttable_iter_key(&i); - int bucket = log2ceil(key); - max[bucket] = UPB_MAX(max[bucket], key); - counts[bucket]++; - } - - /* Find the largest power of two that satisfies the MIN_DENSITY - * definition (while actually having some keys). */ - arr_count = upb_inttable_count(t); - - for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { - if (counts[size_lg2] == 0) { - /* We can halve again without losing any entries. */ - continue; - } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { - break; - } - - arr_count -= counts[size_lg2]; - } - - UPB_ASSERT(arr_count <= upb_inttable_count(t)); - - { - /* Insert all elements into new, perfectly-sized table. */ - size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ - size_t hash_count = upb_inttable_count(t) - arr_count; - size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; - int hashsize_lg2 = log2ceil(hash_size); - - upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t k = upb_inttable_iter_key(&i); - upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); - } - UPB_ASSERT(new_t.array_size == arr_size); - UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); - } - *t = new_t; -} - -/* Iteration. */ - -static const upb_tabent* int_tabent(const upb_inttable_iter* i) { - UPB_ASSERT(!i->array_part); - return &i->t->t.entries[i->index]; -} - -static upb_tabval int_arrent(const upb_inttable_iter* i) { - UPB_ASSERT(i->array_part); - return i->t->array[i->index]; -} - -void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) { - i->t = t; - i->index = -1; - i->array_part = true; - upb_inttable_next(i); -} - -void upb_inttable_next(upb_inttable_iter* iter) { - const upb_inttable* t = iter->t; - if (iter->array_part) { - while (++iter->index < t->array_size) { - if (upb_arrhas(int_arrent(iter))) { - return; - } - } - iter->array_part = false; - iter->index = begin(&t->t); - } else { - iter->index = next(&t->t, iter->index); - } -} - -bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, - intptr_t* iter) { - intptr_t i = *iter; - if (i < t->array_size) { - while (++i < t->array_size) { - upb_tabval ent = t->array[i]; - if (upb_arrhas(ent)) { - *key = i; - *val = _upb_value_val(ent.val); - *iter = i; - return true; - } - } - } - - size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size); - if (tab_idx < upb_table_size(&t->t)) { - upb_tabent* ent = &t->t.entries[tab_idx]; - *key = ent->key; - *val = _upb_value_val(ent->val.val); - *iter = tab_idx + t->array_size; - return true; - } - - return false; -} - -void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { - intptr_t i = *iter; - if (i < t->array_size) { - t->array_count--; - mutable_array(t)[i].val = -1; - } else { - upb_tabent* ent = &t->t.entries[i - t->array_size]; - upb_tabent* prev = NULL; - - // Linear search, not great. - upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; - for (upb_tabent* e = t->t.entries; e != end; e++) { - if (e->next == ent) { - prev = e; - break; - } - } - - if (prev) { - prev->next = ent->next; - } - - t->t.count--; - ent->key = 0; - ent->next = NULL; - } -} - -bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, - upb_value* val, intptr_t* iter) { - size_t tab_idx = next(&t->t, *iter); - if (tab_idx < upb_table_size(&t->t)) { - upb_tabent* ent = &t->t.entries[tab_idx]; - uint32_t len; - key->data = upb_tabstr(ent->key, &len); - key->size = len; - *val = _upb_value_val(ent->val.val); - *iter = tab_idx; - return true; - } - - return false; -} - -void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { - intptr_t i = *iter; - upb_tabent* ent = &t->t.entries[i]; - upb_tabent* prev = NULL; - - // Linear search, not great. - upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; - for (upb_tabent* e = t->t.entries; e != end; e++) { - if (e->next == ent) { - prev = e; - break; - } - } - - if (prev) { - prev->next = ent->next; - } - - t->t.count--; - ent->key = 0; - ent->next = NULL; -} - -bool upb_inttable_done(const upb_inttable_iter* i) { - if (!i->t) return true; - if (i->array_part) { - return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i)); - } else { - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(int_tabent(i)); - } -} - -uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) { - UPB_ASSERT(!upb_inttable_done(i)); - return i->array_part ? i->index : int_tabent(i)->key; -} - -upb_value upb_inttable_iter_value(const upb_inttable_iter* i) { - UPB_ASSERT(!upb_inttable_done(i)); - return _upb_value_val(i->array_part ? i->t->array[i->index].val - : int_tabent(i)->val.val); -} - -void upb_inttable_iter_setdone(upb_inttable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; - i->array_part = false; -} - -bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, - const upb_inttable_iter* i2) { - if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true; - return i1->t == i2->t && i1->index == i2->index && - i1->array_part == i2->array_part; -} - -/** upb/upb.c ************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include - - -// Must be last. - -/* upb_Status *****************************************************************/ - -void upb_Status_Clear(upb_Status* status) { - if (!status) return; - status->ok = true; - status->msg[0] = '\0'; -} - -bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } - -const char* upb_Status_ErrorMessage(const upb_Status* status) { - return status->msg; -} - -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { - if (!status) return; - status->ok = false; - strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} - -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - upb_Status_VSetErrorFormat(status, fmt, args); - va_end(args); -} - -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - if (!status) return; - status->ok = false; - vsnprintf(status->msg, sizeof(status->msg), fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} - -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - size_t len; - if (!status) return; - status->ok = false; - len = strlen(status->msg); - vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} - -/* upb_alloc ******************************************************************/ - -static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - UPB_UNUSED(alloc); - UPB_UNUSED(oldsize); - if (size == 0) { - free(ptr); - return NULL; - } else { - return realloc(ptr, size); - } -} - -static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { - return (uint32_t*)(cleanup_metadata & ~0x1); -} - -static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { - return cleanup_metadata & 0x1; -} - -static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, - bool has_initial_block) { - return (uintptr_t)cleanup | has_initial_block; -} - -upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - -/* upb_Arena ******************************************************************/ - -/* Be conservative and choose 16 in case anyone is using SSE. */ - -struct mem_block { - struct mem_block* next; - uint32_t size; - uint32_t cleanups; - /* Data follows. */ -}; - -typedef struct cleanup_ent { - upb_CleanupFunc* cleanup; - void* ud; -} cleanup_ent; - -static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16); - -static upb_Arena* arena_findroot(upb_Arena* a) { - /* Path splitting keeps time complexity down, see: - * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ - while (a->parent != a) { - upb_Arena* next = a->parent; - a->parent = next->parent; - a = next; - } - return a; -} - -static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, - size_t size) { - mem_block* block = ptr; - - /* The block is for arena |a|, but should appear in the freelist of |root|. */ - block->next = root->freelist; - block->size = (uint32_t)size; - block->cleanups = 0; - root->freelist = block; - a->last_size = block->size; - if (!root->freelist_tail) root->freelist_tail = block; - - a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); - a->head.end = UPB_PTR_AT(block, size, char); - a->cleanup_metadata = upb_cleanup_metadata( - &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); - - UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); -} - -static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { - upb_Arena* root = arena_findroot(a); - size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; - mem_block* block = upb_malloc(root->block_alloc, block_size); - - if (!block) return false; - upb_Arena_addblock(a, root, block, block_size); - return true; -} - -void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { - if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= size); - return upb_Arena_Malloc(a, size); -} - -static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ - return upb_Arena_Realloc(a, ptr, oldsize, size); -} - -/* Public Arena API ***********************************************************/ - -upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { - const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; - upb_Arena* a; - - /* We need to malloc the initial block. */ - n = first_block_overhead + 256; - if (!alloc || !(mem = upb_malloc(alloc, n))) { - return NULL; - } - - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - n -= sizeof(*a); - - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->freelist = NULL; - a->freelist_tail = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, false); - - upb_Arena_addblock(a, a, mem, n); - - return a; -} - -upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { - upb_Arena* a; - - if (n) { - /* Align initial pointer up so that we return properly-aligned pointers. */ - void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, 16); - size_t delta = (uintptr_t)aligned - (uintptr_t)mem; - n = delta <= n ? n - delta : 0; - mem = aligned; - } - - /* Round block size down to alignof(*a) since we will allocate the arena - * itself at the end. */ - n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); - - if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { - return arena_initslow(mem, n, alloc); - } - - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->last_size = UPB_MAX(128, n); - a->head.ptr = mem; - a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); - a->freelist = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, true); - - return a; -} - -static void arena_dofree(upb_Arena* a) { - mem_block* block = a->freelist; - UPB_ASSERT(a->parent == a); - UPB_ASSERT(a->refcount == 0); - - while (block) { - /* Load first since we are deleting block. */ - mem_block* next = block->next; - - if (block->cleanups > 0) { - cleanup_ent* end = UPB_PTR_AT(block, block->size, void); - cleanup_ent* ptr = end - block->cleanups; - - for (; ptr < end; ptr++) { - ptr->cleanup(ptr->ud); - } - } - - upb_free(a->block_alloc, block); - block = next; - } -} - -void upb_Arena_Free(upb_Arena* a) { - a = arena_findroot(a); - if (--a->refcount == 0) arena_dofree(a); -} - -bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { - cleanup_ent* ent; - uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); - - if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { - if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); - cleanups = upb_cleanup_pointer(a->cleanup_metadata); - } - - a->head.end -= sizeof(cleanup_ent); - ent = (cleanup_ent*)a->head.end; - (*cleanups)++; - UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); - - ent->cleanup = func; - ent->ud = ud; - - return true; -} - -bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { - upb_Arena* r1 = arena_findroot(a1); - upb_Arena* r2 = arena_findroot(a2); - - if (r1 == r2) return true; /* Already fused. */ - - /* Do not fuse initial blocks since we cannot lifetime extend them. */ - if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; - if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; - - /* Only allow fuse with a common allocator */ - if (r1->block_alloc != r2->block_alloc) return false; - - /* We want to join the smaller tree to the larger tree. - * So swap first if they are backwards. */ - if (r1->refcount < r2->refcount) { - upb_Arena* tmp = r1; - r1 = r2; - r2 = tmp; - } - - /* r1 takes over r2's freelist and refcount. */ - r1->refcount += r2->refcount; - if (r2->freelist_tail) { - UPB_ASSERT(r2->freelist_tail->next == NULL); - r2->freelist_tail->next = r1->freelist; - r1->freelist = r2->freelist; - } - r2->parent = r1; - return true; -} - -/* Miscellaneous utilities ****************************************************/ - -static void upb_FixLocale(char* p) { - /* printf() is dependent on locales; sadly there is no easy and portable way - * to avoid this. This little post-processing step will translate 1,2 -> 1.2 - * since JSON needs the latter. Arguably a hack, but it is simple and the - * alternatives are far more complicated, platform-dependent, and/or larger - * in code size. */ - for (; *p; p++) { - if (*p == ',') *p = '.'; - } -} - -void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { - assert(size >= kUpb_RoundTripBufferSize); - snprintf(buf, size, "%.*g", DBL_DIG, val); - if (strtod(buf, NULL) != val) { - snprintf(buf, size, "%.*g", DBL_DIG + 2, val); - assert(strtod(buf, NULL) == val); - } - upb_FixLocale(buf); -} - -void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { - assert(size >= kUpb_RoundTripBufferSize); - snprintf(buf, size, "%.*g", FLT_DIG, val); - if (strtof(buf, NULL) != val) { - snprintf(buf, size, "%.*g", FLT_DIG + 3, val); - assert(strtof(buf, NULL) == val); - } - upb_FixLocale(buf); -} - -/** upb/decode_fast.c ************************************************************/ -// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. -// Also the table size grows by 2x. -// -// Could potentially be ported to other 64-bit archs that pass at least six -// arguments in registers and have 8 unused high bits in pointers. -// -// The overall design is to create specialized functions for every possible -// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch -// to the specialized function as quickly as possible. - - - -/* Must be last. */ - -#if UPB_FASTTABLE - -// The standard set of arguments passed to each parsing function. -// Thanks to x86-64 calling conventions, these will stay in registers. -#define UPB_PARSE_PARAMS \ - upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ - uint64_t hasbits, uint64_t data - -#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data - -#define RETURN_GENERIC(m) \ - /* Uncomment either of these for debugging purposes. */ \ - /* fprintf(stderr, m); */ \ - /*__builtin_trap(); */ \ - return fastdecode_generic(d, ptr, msg, table, hasbits, 0); - -typedef enum { - CARD_s = 0, /* Singular (optional, non-repeated) */ - CARD_o = 1, /* Oneof */ - CARD_r = 2, /* Repeated */ - CARD_p = 3 /* Packed Repeated */ -} upb_card; - -UPB_NOINLINE -static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { - int overrun = data; - int status; - ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); - if (ptr == NULL) { - return fastdecode_err(d, status); - } - data = fastdecode_loadtag(ptr); - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); -} - -UPB_FORCEINLINE -static const char* fastdecode_dispatch(UPB_PARSE_PARAMS) { - if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { - int overrun = ptr - d->end; - if (UPB_LIKELY(overrun == d->limit)) { - // Parse is finished. - *(uint32_t*)msg |= hasbits; // Sync hasbits. - const upb_MiniTable* l = decode_totablep(table); - return UPB_UNLIKELY(l->required_count) - ? decode_checkrequired(d, ptr, msg, l) - : ptr; - } else { - data = overrun; - UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); - } - } - - // Read two bytes of tag data (for a one-byte tag, the high byte is junk). - data = fastdecode_loadtag(ptr); - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); -} - -UPB_FORCEINLINE -static bool fastdecode_checktag(uint16_t data, int tagbytes) { - if (tagbytes == 1) { - return (data & 0xff) == 0; - } else { - return data == 0; - } -} - -UPB_FORCEINLINE -static const char* fastdecode_longsize(const char* ptr, int* size) { - int i; - UPB_ASSERT(*size & 0x80); - *size &= 0xff; - for (i = 0; i < 3; i++) { - ptr++; - size_t byte = (uint8_t)ptr[-1]; - *size += (byte - 1) << (7 + 7 * i); - if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; - } - ptr++; - size_t byte = (uint8_t)ptr[-1]; - // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected - // for a 32 bit varint. - if (UPB_UNLIKELY(byte >= 8)) return NULL; - *size += (byte - 1) << 28; - return ptr; -} - -UPB_FORCEINLINE -static bool fastdecode_boundscheck(const char* ptr, size_t len, - const char* end) { - uintptr_t uptr = (uintptr_t)ptr; - uintptr_t uend = (uintptr_t)end + 16; - uintptr_t res = uptr + len; - return res < uptr || res > uend; -} - -UPB_FORCEINLINE -static bool fastdecode_boundscheck2(const char* ptr, size_t len, - const char* end) { - // This is one extra branch compared to the more normal: - // return (size_t)(end - ptr) < size; - // However it is one less computation if we are just about to use "ptr + len": - // https://godbolt.org/z/35YGPz - // In microbenchmarks this shows an overall 4% improvement. - uintptr_t uptr = (uintptr_t)ptr; - uintptr_t uend = (uintptr_t)end; - uintptr_t res = uptr + len; - return res < uptr || res > uend; -} - -typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, - void* ctx); - -UPB_FORCEINLINE -static const char* fastdecode_delimited(upb_Decoder* d, const char* ptr, - fastdecode_delimfunc* func, void* ctx) { - ptr++; - int len = (int8_t)ptr[-1]; - if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) { - // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. - // If it exceeds the buffer limit, limit/limit_ptr will change during - // sub-message parsing, so we need to preserve delta, not limit. - if (UPB_UNLIKELY(len & 0x80)) { - // Size varint >1 byte (length >= 128). - ptr = fastdecode_longsize(ptr, &len); - if (!ptr) { - // Corrupt wire format: size exceeded INT_MAX. - return NULL; - } - } - if (ptr - d->end + (int)len > d->limit) { - // Corrupt wire format: invalid limit. - return NULL; - } - int delta = decode_pushlimit(d, ptr, len); - ptr = func(d, ptr, ctx); - decode_poplimit(d, ptr, delta); - } else { - // Fast case: Sub-message is <128 bytes and fits in the current buffer. - // This means we can preserve limit/limit_ptr verbatim. - const char* saved_limit_ptr = d->limit_ptr; - int saved_limit = d->limit; - d->limit_ptr = ptr + len; - d->limit = d->limit_ptr - d->end; - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); - ptr = func(d, ptr, ctx); - d->limit_ptr = saved_limit_ptr; - d->limit = saved_limit; - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); - } - return ptr; -} - -/* singular, oneof, repeated field handling ***********************************/ - -typedef struct { - upb_Array* arr; - void* end; -} fastdecode_arr; - -typedef enum { - FD_NEXT_ATLIMIT, - FD_NEXT_SAMEFIELD, - FD_NEXT_OTHERFIELD -} fastdecode_next; - -typedef struct { - void* dst; - fastdecode_next next; - uint32_t tag; -} fastdecode_nextret; - -UPB_FORCEINLINE -static void* fastdecode_resizearr(upb_Decoder* d, void* dst, - fastdecode_arr* farr, int valbytes) { - if (UPB_UNLIKELY(dst == farr->end)) { - size_t old_size = farr->arr->size; - size_t old_bytes = old_size * valbytes; - size_t new_size = old_size * 2; - size_t new_bytes = new_size * valbytes; - char* old_ptr = _upb_array_ptr(farr->arr); - char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes); - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - farr->arr->size = new_size; - farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2); - dst = (void*)(new_ptr + (old_size * valbytes)); - farr->end = (void*)(new_ptr + (new_size * valbytes)); - } - return dst; -} - -UPB_FORCEINLINE -static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { - if (tagbytes == 1) { - return (uint8_t)tag == (uint8_t)data; - } else { - return (uint16_t)tag == (uint16_t)data; - } -} - -UPB_FORCEINLINE -static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, - int valbytes) { - farr->arr->len = - (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; -} - -UPB_FORCEINLINE -static fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst, - const char** ptr, - fastdecode_arr* farr, - uint64_t data, int tagbytes, - int valbytes) { - fastdecode_nextret ret; - dst = (char*)dst + valbytes; - - if (UPB_LIKELY(!decode_isdone(d, ptr))) { - ret.tag = fastdecode_loadtag(*ptr); - if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { - ret.next = FD_NEXT_SAMEFIELD; - } else { - fastdecode_commitarr(dst, farr, valbytes); - ret.next = FD_NEXT_OTHERFIELD; - } - } else { - fastdecode_commitarr(dst, farr, valbytes); - ret.next = FD_NEXT_ATLIMIT; - } - - ret.dst = dst; - return ret; -} - -UPB_FORCEINLINE -static void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) { - size_t ofs = data >> 48; - return (char*)msg + ofs; -} - -UPB_FORCEINLINE -static void* fastdecode_getfield(upb_Decoder* d, const char* ptr, - upb_Message* msg, uint64_t* data, - uint64_t* hasbits, fastdecode_arr* farr, - int valbytes, upb_card card) { - switch (card) { - case CARD_s: { - uint8_t hasbit_index = *data >> 24; - // Set hasbit and return pointer to scalar field. - *hasbits |= 1ull << hasbit_index; - return fastdecode_fieldmem(msg, *data); - } - case CARD_o: { - uint16_t case_ofs = *data >> 32; - uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); - uint8_t field_number = *data >> 24; - *oneof_case = field_number; - return fastdecode_fieldmem(msg, *data); - } - case CARD_r: { - // Get pointer to upb_Array and allocate/expand if necessary. - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - upb_Array** arr_p = fastdecode_fieldmem(msg, *data); - char* begin; - *(uint32_t*)msg |= *hasbits; - *hasbits = 0; - if (UPB_LIKELY(!*arr_p)) { - farr->arr = _upb_Array_New(&d->arena, 8, elem_size_lg2); - *arr_p = farr->arr; - } else { - farr->arr = *arr_p; - } - begin = _upb_array_ptr(farr->arr); - farr->end = begin + (farr->arr->size * valbytes); - *data = fastdecode_loadtag(ptr); - return begin + (farr->arr->len * valbytes); - } - default: - UPB_UNREACHABLE(); - } -} - -UPB_FORCEINLINE -static bool fastdecode_flippacked(uint64_t* data, int tagbytes) { - *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. - return fastdecode_checktag(*data, tagbytes); -} - -#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ - UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ - } \ - RETURN_GENERIC("packed check tag mismatch\n"); \ - } - -/* varint fields **************************************************************/ - -UPB_FORCEINLINE -static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { - if (valbytes == 1) { - return val != 0; - } else if (zigzag) { - if (valbytes == 4) { - uint32_t n = val; - return (n >> 1) ^ -(int32_t)(n & 1); - } else if (valbytes == 8) { - return (val >> 1) ^ -(int64_t)(val & 1); - } - UPB_UNREACHABLE(); - } - return val; -} - -UPB_FORCEINLINE -static const char* fastdecode_varint64(const char* ptr, uint64_t* val) { - ptr++; - *val = (uint8_t)ptr[-1]; - if (UPB_UNLIKELY(*val & 0x80)) { - int i; - for (i = 0; i < 8; i++) { - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - *val += (byte - 1) << (7 + 7 * i); - if (UPB_LIKELY((byte & 0x80) == 0)) goto done; - } - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - if (byte > 1) { - return NULL; - } - *val += (byte - 1) << 63; - } -done: - UPB_ASSUME(ptr != NULL); - return ptr; -} - -#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, packed) \ - uint64_t val; \ - void* dst; \ - fastdecode_arr farr; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ - card); \ - if (card == CARD_r) { \ - if (UPB_UNLIKELY(!dst)) { \ - RETURN_GENERIC("need array resize\n"); \ - } \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_varint64(ptr, &val); \ - if (ptr == NULL) return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - val = fastdecode_munge(val, valbytes, zigzag); \ - memcpy(dst, &val, valbytes); \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, valbytes); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - -typedef struct { - uint8_t valbytes; - bool zigzag; - void* dst; - fastdecode_arr farr; -} fastdecode_varintdata; - -UPB_FORCEINLINE -static const char* fastdecode_topackedvarint(upb_Decoder* d, const char* ptr, - void* ctx) { - fastdecode_varintdata* data = ctx; - void* dst = data->dst; - uint64_t val; - - while (!decode_isdone(d, &ptr)) { - dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); - ptr = fastdecode_varint64(ptr, &val); - if (ptr == NULL) return NULL; - val = fastdecode_munge(val, data->valbytes, data->zigzag); - memcpy(dst, &val, data->valbytes); - dst = (char*)dst + data->valbytes; - } - - fastdecode_commitarr(dst, &data->farr, data->valbytes); - return ptr; -} - -#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, zigzag, unpacked) \ - fastdecode_varintdata ctx = {valbytes, zigzag}; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ - \ - ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ - valbytes, CARD_r); \ - if (UPB_UNLIKELY(!ctx.dst)) { \ - RETURN_GENERIC("need array resize\n"); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ - \ - if (UPB_UNLIKELY(ptr == NULL)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); - -#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, unpacked, packed) \ - if (card == CARD_p) { \ - FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, zigzag, unpacked); \ - } else { \ - FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, packed); \ - } - -#define z_ZZ true -#define b_ZZ false -#define v_ZZ false - -/* Generate all combinations: - * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ - -#define F(card, type, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ - CARD_##card, type##_ZZ, \ - upb_pr##type##valbytes##_##tagbytes##bt, \ - upb_pp##type##valbytes##_##tagbytes##bt); \ - } - -#define TYPES(card, tagbytes) \ - F(card, b, 1, tagbytes) \ - F(card, v, 4, tagbytes) \ - F(card, v, 8, tagbytes) \ - F(card, z, 4, tagbytes) \ - F(card, z, 8, tagbytes) - -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) - -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) - -#undef z_ZZ -#undef b_ZZ -#undef v_ZZ -#undef o_ONEOF -#undef s_ONEOF -#undef r_ONEOF -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDVARINT -#undef FASTDECODE_PACKEDVARINT -#undef FASTDECODE_VARINT - -/* fixed fields ***************************************************************/ - -#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, packed) \ - void* dst; \ - fastdecode_arr farr; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ - card); \ - if (card == CARD_r) { \ - if (UPB_UNLIKELY(!dst)) { \ - RETURN_GENERIC("couldn't allocate array in arena\n"); \ - } \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ - } \ - \ - ptr += tagbytes; \ - memcpy(dst, ptr, valbytes); \ - ptr += valbytes; \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, valbytes); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - -#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, unpacked) \ - FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ - \ - ptr += tagbytes; \ - int size = (uint8_t)ptr[0]; \ - ptr++; \ - if (size & 0x80) { \ - ptr = fastdecode_longsize(ptr, &size); \ - } \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ - (size % valbytes) != 0)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - upb_Array** arr_p = fastdecode_fieldmem(msg, data); \ - upb_Array* arr = *arr_p; \ - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ - int elems = size / valbytes; \ - \ - if (UPB_LIKELY(!arr)) { \ - *arr_p = arr = _upb_Array_New(&d->arena, elems, elem_size_lg2); \ - if (!arr) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - } else { \ - _upb_Array_Resize(arr, elems, &d->arena); \ - } \ - \ - char* dst = _upb_array_ptr(arr); \ - memcpy(dst, ptr, size); \ - arr->len = elems; \ - \ - ptr += size; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - -#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, unpacked, packed) \ - if (card == CARD_p) { \ - FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, unpacked); \ - } else { \ - FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, packed); \ - } - -/* Generate all combinations: - * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ - -#define F(card, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ - CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ - upb_prf##valbytes##_##tagbytes##bt); \ - } - -#define TYPES(card, tagbytes) \ - F(card, 4, tagbytes) \ - F(card, 8, tagbytes) - -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) - -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) - -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDFIXED -#undef FASTDECODE_PACKEDFIXED - -/* string fields **************************************************************/ - -typedef const char* fastdecode_copystr_func(struct upb_Decoder* d, - const char* ptr, upb_Message* msg, - const upb_MiniTable* table, - uint64_t hasbits, - upb_StringView* dst); - -UPB_NOINLINE -static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - if (!decode_verifyutf8_inl(dst->data, dst->size)) { - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); - } - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); -} - -#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ - int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ - ptr++; \ - if (size & 0x80) { \ - ptr = fastdecode_longsize(ptr, &size); \ - } \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ - dst->size = 0; \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - if (d->options & kUpb_DecodeOption_AliasString) { \ - dst->data = ptr; \ - dst->size = size; \ - } else { \ - char* data = upb_Arena_Malloc(&d->arena, size); \ - if (!data) { \ - return fastdecode_err(d, kUpb_DecodeStatus_OutOfMemory); \ - } \ - memcpy(data, ptr, size); \ - dst->data = data; \ - dst->size = size; \ - } \ - \ - ptr += size; \ - if (validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } else { \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ - } - -UPB_NOINLINE -static const char* fastdecode_longstring_utf8(struct upb_Decoder* d, - const char* ptr, upb_Message* msg, - intptr_t table, uint64_t hasbits, - uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); -} - -UPB_NOINLINE -static const char* fastdecode_longstring_noutf8( - struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); -} - -UPB_FORCEINLINE -static void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size, - int copy, char* data, upb_StringView* dst) { - d->arena.head.ptr += copy; - dst->data = data; - UPB_UNPOISON_MEMORY_REGION(data, copy); - memcpy(data, ptr, copy); - UPB_POISON_MEMORY_REGION(data + size, copy - size); -} - -#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - card, validate_utf8) \ - upb_StringView* dst; \ - fastdecode_arr farr; \ - int64_t size; \ - size_t arena_has; \ - size_t common_has; \ - char* buf; \ - \ - UPB_ASSERT((d->options & kUpb_DecodeOption_AliasString) == 0); \ - UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_StringView), card); \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ - } \ - \ - size = (uint8_t)ptr[tagbytes]; \ - ptr += tagbytes + 1; \ - dst->size = size; \ - \ - buf = d->arena.head.ptr; \ - arena_has = _upb_ArenaHas(&d->arena); \ - common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ - \ - if (UPB_LIKELY(size <= 15 - tagbytes)) { \ - if (arena_has < 16) goto longstr; \ - d->arena.head.ptr += 16; \ - memcpy(buf, ptr - tagbytes - 1, 16); \ - dst->data = buf + tagbytes + 1; \ - } else if (UPB_LIKELY(size <= 32)) { \ - if (UPB_UNLIKELY(common_has < 32)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 32, buf, dst); \ - } else if (UPB_LIKELY(size <= 64)) { \ - if (UPB_UNLIKELY(common_has < 64)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 64, buf, dst); \ - } else if (UPB_LIKELY(size < 128)) { \ - if (UPB_UNLIKELY(common_has < 128)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 128, buf, dst); \ - } else { \ - goto longstr; \ - } \ - \ - ptr += size; \ - \ - if (card == CARD_r) { \ - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ - } \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - if (card != CARD_r && validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ - \ - longstr: \ - if (card == CARD_r) { \ - fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView)); \ - } \ - ptr--; \ - if (validate_utf8) { \ - UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ - hasbits, (uint64_t)dst); \ - } else { \ - UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ - hasbits, (uint64_t)dst); \ - } - -#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ - copyfunc, validate_utf8) \ - upb_StringView* dst; \ - fastdecode_arr farr; \ - int64_t size; \ - \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - RETURN_GENERIC("string field tag mismatch\n"); \ - } \ - \ - if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ - UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ - } \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_StringView), card); \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ - } \ - \ - size = (int8_t)ptr[tagbytes]; \ - ptr += tagbytes + 1; \ - dst->data = ptr; \ - dst->size = size; \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ - ptr--; \ - if (validate_utf8) { \ - return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ - (uint64_t)dst); \ - } else { \ - return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ - (uint64_t)dst); \ - } \ - } \ - \ - ptr += size; \ - \ - if (card == CARD_r) { \ - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ - } \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ - /* Buffer flipped and we can't alias any more. Bounce to */ \ - /* copyfunc(), but via dispatch since we need to reload table */ \ - /* data also. */ \ - fastdecode_commitarr(dst, &farr, sizeof(upb_StringView)); \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - } \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - if (card != CARD_r && validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - -/* Generate all combinations: - * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ - -#define s_VALIDATE true -#define b_VALIDATE false - -#define F(card, tagbytes, type) \ - UPB_NOINLINE \ - const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - CARD_##card, type##_VALIDATE); \ - } \ - const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - CARD_##card, upb_c##card##type##_##tagbytes##bt, \ - type##_VALIDATE); \ - } - -#define UTF8(card, tagbytes) \ - F(card, tagbytes, s) \ - F(card, tagbytes, b) - -#define TAGBYTES(card) \ - UTF8(card, 1) \ - UTF8(card, 2) - -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) - -#undef s_VALIDATE -#undef b_VALIDATE -#undef F -#undef TAGBYTES -#undef FASTDECODE_LONGSTRING -#undef FASTDECODE_COPYSTRING -#undef FASTDECODE_STRING - -/* message fields *************************************************************/ - -UPB_INLINE -upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* l, - int msg_ceil_bytes) { - size_t size = l->size + sizeof(upb_Message_Internal); - char* msg_data; - if (UPB_LIKELY(msg_ceil_bytes > 0 && - _upb_ArenaHas(&d->arena) >= msg_ceil_bytes)) { - UPB_ASSERT(size <= (size_t)msg_ceil_bytes); - msg_data = d->arena.head.ptr; - d->arena.head.ptr += size; - UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); - memset(msg_data, 0, msg_ceil_bytes); - UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); - } else { - msg_data = (char*)upb_Arena_Malloc(&d->arena, size); - memset(msg_data, 0, size); - } - return msg_data + sizeof(upb_Message_Internal); -} - -typedef struct { - intptr_t table; - upb_Message* msg; -} fastdecode_submsgdata; - -UPB_FORCEINLINE -static const char* fastdecode_tosubmsg(upb_Decoder* d, const char* ptr, - void* ctx) { - fastdecode_submsgdata* submsg = ctx; - ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); - UPB_ASSUME(ptr != NULL); - return ptr; -} - -#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ - msg_ceil_bytes, card) \ - \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - RETURN_GENERIC("submessage field tag mismatch\n"); \ - } \ - \ - if (--d->depth == 0) { \ - return fastdecode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); \ - } \ - \ - upb_Message** dst; \ - uint32_t submsg_idx = (data >> 16) & 0xff; \ - const upb_MiniTable* tablep = decode_totablep(table); \ - const upb_MiniTable* subtablep = tablep->subs[submsg_idx].submsg; \ - fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ - fastdecode_arr farr; \ - \ - if (subtablep->table_mask == (uint8_t)-1) { \ - RETURN_GENERIC("submessage doesn't have fast tables."); \ - } \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_Message*), card); \ - \ - if (card == CARD_s) { \ - *(uint32_t*)msg |= hasbits; \ - hasbits = 0; \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ - } \ - \ - submsg.msg = *dst; \ - \ - if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ - *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ - \ - if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - d->depth++; \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - d->depth++; \ - return ptr; \ - } \ - } \ - \ - d->depth++; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - -#define F(card, tagbytes, size_ceil, ceil_arg) \ - const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ - UPB_PARSE_PARAMS) { \ - FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ - CARD_##card); \ - } - -#define SIZES(card, tagbytes) \ - F(card, tagbytes, 64, 64) \ - F(card, tagbytes, 128, 128) \ - F(card, tagbytes, 192, 192) \ - F(card, tagbytes, 256, 256) \ - F(card, tagbytes, max, -1) - -#define TAGBYTES(card) \ - SIZES(card, 1) \ - SIZES(card, 2) - -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) - -#undef TAGBYTES -#undef SIZES -#undef F -#undef FASTDECODE_SUBMSG - -#endif /* UPB_FASTTABLE */ - -/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upb.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#include - - -static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { - {.submsg = &google_protobuf_FileDescriptorProto_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_FileDescriptorSet_msginit = { - &google_protobuf_FileDescriptorSet_submsgs[0], - &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { - {.submsg = &google_protobuf_DescriptorProto_msginit}, - {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, - {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, - {.submsg = &google_protobuf_FileOptions_msginit}, - {.submsg = &google_protobuf_ServiceDescriptorProto_msginit}, - {.submsg = &google_protobuf_SourceCodeInfo_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(36, 72), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {4, UPB_SIZE(40, 80), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(44, 88), 0, 1, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {6, UPB_SIZE(48, 96), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {7, UPB_SIZE(52, 104), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 56), 3, 3, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {9, UPB_SIZE(32, 64), 4, 5, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 112), 0, 0, 5, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {11, UPB_SIZE(60, 120), 0, 0, 5, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {12, UPB_SIZE(20, 40), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_FileDescriptorProto_msginit = { - &google_protobuf_FileDescriptorProto_submsgs[0], - &google_protobuf_FileDescriptorProto__fields[0], - UPB_SIZE(64, 128), 12, upb_ExtMode_NonExtendable, 12, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[7] = { - {.submsg = &google_protobuf_DescriptorProto_msginit}, - {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msginit}, - {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msginit}, - {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, - {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, - {.submsg = &google_protobuf_MessageOptions_msginit}, - {.submsg = &google_protobuf_OneofDescriptorProto_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {4, UPB_SIZE(24, 48), 0, 3, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(28, 56), 0, 1, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {6, UPB_SIZE(32, 64), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {7, UPB_SIZE(12, 24), 2, 5, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {8, UPB_SIZE(36, 72), 0, 6, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {9, UPB_SIZE(40, 80), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {10, UPB_SIZE(44, 88), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_DescriptorProto_msginit = { - &google_protobuf_DescriptorProto_submsgs[0], - &google_protobuf_DescriptorProto__fields[0], - UPB_SIZE(48, 96), 10, upb_ExtMode_NonExtendable, 10, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { - {.submsg = &google_protobuf_ExtensionRangeOptions_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit = { - &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], - &google_protobuf_DescriptorProto_ExtensionRange__fields[0], - UPB_SIZE(16, 24), 3, upb_ExtMode_NonExtendable, 3, 255, 0, -}; - -static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit = { - NULL, - &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(16, 16), 2, upb_ExtMode_NonExtendable, 2, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit = { - &google_protobuf_ExtensionRangeOptions_submsgs[0], - &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_Extendable, 0, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { - {.submsg = &google_protobuf_FieldOptions_msginit}, - {.subenum = &google_protobuf_FieldDescriptorProto_Label_enuminit}, - {.subenum = &google_protobuf_FieldDescriptorProto_Type_enuminit}, -}; - -static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(24, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(32, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 12), 3, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {4, UPB_SIZE(4, 4), 4, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {5, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(40, 56), 6, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {7, UPB_SIZE(48, 72), 7, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {8, UPB_SIZE(64, 104), 8, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {9, UPB_SIZE(16, 16), 9, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 88), 10, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {17, UPB_SIZE(20, 20), 11, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit = { - &google_protobuf_FieldDescriptorProto_submsgs[0], - &google_protobuf_FieldDescriptorProto__fields[0], - UPB_SIZE(72, 112), 11, upb_ExtMode_NonExtendable, 10, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_OneofOptions_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit = { - &google_protobuf_OneofDescriptorProto_submsgs[0], - &google_protobuf_OneofDescriptorProto__fields[0], - UPB_SIZE(16, 32), 2, upb_ExtMode_NonExtendable, 2, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { - {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit}, - {.submsg = &google_protobuf_EnumOptions_msginit}, - {.submsg = &google_protobuf_EnumValueDescriptorProto_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {4, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(24, 48), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit = { - &google_protobuf_EnumDescriptorProto_submsgs[0], - &google_protobuf_EnumDescriptorProto__fields[0], - UPB_SIZE(32, 64), 5, upb_ExtMode_NonExtendable, 5, 255, 0, -}; - -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { - NULL, - &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(16, 16), 2, upb_ExtMode_NonExtendable, 2, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_EnumValueOptions_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(16, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit = { - &google_protobuf_EnumValueDescriptorProto_submsgs[0], - &google_protobuf_EnumValueDescriptorProto__fields[0], - UPB_SIZE(24, 32), 3, upb_ExtMode_NonExtendable, 3, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { - {.submsg = &google_protobuf_MethodDescriptorProto_msginit}, - {.submsg = &google_protobuf_ServiceOptions_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit = { - &google_protobuf_ServiceDescriptorProto_submsgs[0], - &google_protobuf_ServiceDescriptorProto__fields[0], - UPB_SIZE(24, 48), 3, upb_ExtMode_NonExtendable, 3, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_MethodOptions_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 3, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {4, UPB_SIZE(28, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(1, 1), 5, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(2, 2), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit = { - &google_protobuf_MethodDescriptorProto_submsgs[0], - &google_protobuf_MethodDescriptorProto__fields[0], - UPB_SIZE(32, 64), 6, upb_ExtMode_NonExtendable, 6, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_FileOptions_OptimizeMode_enuminit}, -}; - -static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(20, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {9, UPB_SIZE(4, 4), 3, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {10, UPB_SIZE(8, 8), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {11, UPB_SIZE(36, 56), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {16, UPB_SIZE(9, 9), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {17, UPB_SIZE(10, 10), 7, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {18, UPB_SIZE(11, 11), 8, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {20, UPB_SIZE(12, 12), 9, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {23, UPB_SIZE(13, 13), 10, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {27, UPB_SIZE(14, 14), 11, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {31, UPB_SIZE(15, 15), 12, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {36, UPB_SIZE(44, 72), 13, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {37, UPB_SIZE(52, 88), 14, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {39, UPB_SIZE(60, 104), 15, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {40, UPB_SIZE(68, 120), 16, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {41, UPB_SIZE(76, 136), 17, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {42, UPB_SIZE(16, 16), 18, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {44, UPB_SIZE(84, 152), 19, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {45, UPB_SIZE(92, 168), 20, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {999, UPB_SIZE(100, 184), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_FileOptions_msginit = { - &google_protobuf_FileOptions_submsgs[0], - &google_protobuf_FileOptions__fields[0], - UPB_SIZE(104, 192), 21, upb_ExtMode_Extendable, 1, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(3, 3), 3, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {7, UPB_SIZE(4, 4), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(8, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_MessageOptions_msginit = { - &google_protobuf_MessageOptions_submsgs[0], - &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(16, 16), 5, upb_ExtMode_Extendable, 3, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_FieldOptions_CType_enuminit}, - {.subenum = &google_protobuf_FieldOptions_JSType_enuminit}, -}; - -static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[8] = { - {1, UPB_SIZE(4, 4), 1, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 12), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(13, 13), 3, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {5, UPB_SIZE(14, 14), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {10, UPB_SIZE(15, 15), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {15, UPB_SIZE(16, 16), 7, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(20, 24), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_FieldOptions_msginit = { - &google_protobuf_FieldOptions_submsgs[0], - &google_protobuf_FieldOptions__fields[0], - UPB_SIZE(24, 32), 8, upb_ExtMode_Extendable, 3, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_OneofOptions_msginit = { - &google_protobuf_OneofOptions_submsgs[0], - &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_Extendable, 0, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = { - {2, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_EnumOptions_msginit = { - &google_protobuf_EnumOptions_submsgs[0], - &google_protobuf_EnumOptions__fields[0], - UPB_SIZE(8, 16), 3, upb_ExtMode_Extendable, 0, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_EnumValueOptions_msginit = { - &google_protobuf_EnumValueOptions_submsgs[0], - &google_protobuf_EnumValueOptions__fields[0], - UPB_SIZE(8, 16), 2, upb_ExtMode_Extendable, 1, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = { - {33, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_ServiceOptions_msginit = { - &google_protobuf_ServiceOptions_submsgs[0], - &google_protobuf_ServiceOptions__fields[0], - UPB_SIZE(8, 16), 2, upb_ExtMode_Extendable, 0, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enuminit}, -}; - -static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = { - {33, UPB_SIZE(8, 8), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {34, UPB_SIZE(4, 4), 2, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(12, 16), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_MethodOptions_msginit = { - &google_protobuf_MethodOptions_submsgs[0], - &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(16, 24), 3, upb_ExtMode_Extendable, 0, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_NamePart_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { - {2, UPB_SIZE(56, 80), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(32, 32), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 2, 0, 4, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 16), 3, 0, 3, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(24, 24), 4, 0, 1, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)}, - {7, UPB_SIZE(40, 48), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {8, UPB_SIZE(48, 64), 6, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_UninterpretedOption_msginit = { - &google_protobuf_UninterpretedOption_submsgs[0], - &google_protobuf_UninterpretedOption__fields[0], - UPB_SIZE(64, 96), 7, upb_ExtMode_NonExtendable, 0, 255, 0, -}; - -static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(1, 1), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit = { - NULL, - &google_protobuf_UninterpretedOption_NamePart__fields[0], - UPB_SIZE(16, 32), 2, upb_ExtMode_NonExtendable, 2, 255, 2, -}; - -static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { - {.submsg = &google_protobuf_SourceCodeInfo_Location_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_SourceCodeInfo_msginit = { - &google_protobuf_SourceCodeInfo_submsgs[0], - &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0, -}; - -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = { - {1, UPB_SIZE(20, 40), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {2, UPB_SIZE(24, 48), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {6, UPB_SIZE(28, 56), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit = { - NULL, - &google_protobuf_SourceCodeInfo_Location__fields[0], - UPB_SIZE(32, 64), 5, upb_ExtMode_NonExtendable, 4, 255, 0, -}; - -static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { - {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msginit}, -}; - -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit = { - &google_protobuf_GeneratedCodeInfo_submsgs[0], - &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0, -}; - -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { - {1, UPB_SIZE(20, 32), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 16), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 3, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, -}; - -const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit = { - NULL, - &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], - UPB_SIZE(24, 48), 4, upb_ExtMode_NonExtendable, 4, 255, 0, -}; - -static const upb_MiniTable *messages_layout[27] = { - &google_protobuf_FileDescriptorSet_msginit, - &google_protobuf_FileDescriptorProto_msginit, - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_DescriptorProto_ExtensionRange_msginit, - &google_protobuf_DescriptorProto_ReservedRange_msginit, - &google_protobuf_ExtensionRangeOptions_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_OneofDescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, - &google_protobuf_EnumValueDescriptorProto_msginit, - &google_protobuf_ServiceDescriptorProto_msginit, - &google_protobuf_MethodDescriptorProto_msginit, - &google_protobuf_FileOptions_msginit, - &google_protobuf_MessageOptions_msginit, - &google_protobuf_FieldOptions_msginit, - &google_protobuf_OneofOptions_msginit, - &google_protobuf_EnumOptions_msginit, - &google_protobuf_EnumValueOptions_msginit, - &google_protobuf_ServiceOptions_msginit, - &google_protobuf_MethodOptions_msginit, - &google_protobuf_UninterpretedOption_msginit, - &google_protobuf_UninterpretedOption_NamePart_msginit, - &google_protobuf_SourceCodeInfo_msginit, - &google_protobuf_SourceCodeInfo_Location_msginit, - &google_protobuf_GeneratedCodeInfo_msginit, - &google_protobuf_GeneratedCodeInfo_Annotation_msginit, -}; - -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit = { - NULL, - 0x7fffeULL, - 0, -}; - -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit = { - NULL, - 0xeULL, - 0, -}; - -const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit = { - NULL, - 0xeULL, - 0, -}; - -const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit = { - NULL, - 0x7ULL, - 0, -}; - -const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit = { - NULL, - 0x7ULL, - 0, -}; - -const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit = { - NULL, - 0x7ULL, - 0, -}; - -static const upb_MiniTable_Enum *enums_layout[6] = { - &google_protobuf_FieldDescriptorProto_Type_enuminit, - &google_protobuf_FieldDescriptorProto_Label_enuminit, - &google_protobuf_FileOptions_OptimizeMode_enuminit, - &google_protobuf_FieldOptions_CType_enuminit, - &google_protobuf_FieldOptions_JSType_enuminit, - &google_protobuf_MethodOptions_IdempotencyLevel_enuminit, -}; - -const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { - messages_layout, - enums_layout, - NULL, - 27, - 6, - 0, -}; - - - -/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upbdefs.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ +/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upbdefs.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ static const char descriptor[7667] = {'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p', @@ -5452,5919 +1318,11506 @@ static const char descriptor[7667] = {'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', ' 'o', 't', 'o', 'b', 'u', 'f', '.', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n', }; -static _upb_DefPool_Init *deps[1] = { - NULL +static _upb_DefPool_Init *deps[1] = { + NULL +}; + +_upb_DefPool_Init google_protobuf_descriptor_proto_upbdefinit = { + deps, + &google_protobuf_descriptor_proto_upb_file_layout, + "google/protobuf/descriptor.proto", + UPB_STRINGVIEW_INIT(descriptor, 7667) +}; + +/** upb/decode_fast.c ************************************************************/ +// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. +// Also the table size grows by 2x. +// +// Could potentially be ported to other 64-bit archs that pass at least six +// arguments in registers and have 8 unused high bits in pointers. +// +// The overall design is to create specialized functions for every possible +// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch +// to the specialized function as quickly as possible. + + + +/* Must be last. */ + +#if UPB_FASTTABLE + +// The standard set of arguments passed to each parsing function. +// Thanks to x86-64 calling conventions, these will stay in registers. +#define UPB_PARSE_PARAMS \ + upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data + +#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data + +#define RETURN_GENERIC(m) \ + /* Uncomment either of these for debugging purposes. */ \ + /* fprintf(stderr, m); */ \ + /*__builtin_trap(); */ \ + return fastdecode_generic(d, ptr, msg, table, hasbits, 0); + +typedef enum { + CARD_s = 0, /* Singular (optional, non-repeated) */ + CARD_o = 1, /* Oneof */ + CARD_r = 2, /* Repeated */ + CARD_p = 3 /* Packed Repeated */ +} upb_card; + +UPB_NOINLINE +static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { + int overrun = data; + int status; + ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); + if (ptr == NULL) { + return fastdecode_err(d, status); + } + data = fastdecode_loadtag(ptr); + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); +} + +UPB_FORCEINLINE +static const char* fastdecode_dispatch(UPB_PARSE_PARAMS) { + if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { + int overrun = ptr - d->end; + if (UPB_LIKELY(overrun == d->limit)) { + // Parse is finished. + *(uint32_t*)msg |= hasbits; // Sync hasbits. + const upb_MiniTable* l = decode_totablep(table); + return UPB_UNLIKELY(l->required_count) + ? decode_checkrequired(d, ptr, msg, l) + : ptr; + } else { + data = overrun; + UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); + } + } + + // Read two bytes of tag data (for a one-byte tag, the high byte is junk). + data = fastdecode_loadtag(ptr); + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); +} + +UPB_FORCEINLINE +static bool fastdecode_checktag(uint16_t data, int tagbytes) { + if (tagbytes == 1) { + return (data & 0xff) == 0; + } else { + return data == 0; + } +} + +UPB_FORCEINLINE +static const char* fastdecode_longsize(const char* ptr, int* size) { + int i; + UPB_ASSERT(*size & 0x80); + *size &= 0xff; + for (i = 0; i < 3; i++) { + ptr++; + size_t byte = (uint8_t)ptr[-1]; + *size += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; + } + ptr++; + size_t byte = (uint8_t)ptr[-1]; + // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected + // for a 32 bit varint. + if (UPB_UNLIKELY(byte >= 8)) return NULL; + *size += (byte - 1) << 28; + return ptr; +} + +UPB_FORCEINLINE +static bool fastdecode_boundscheck(const char* ptr, size_t len, + const char* end) { + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end + 16; + uintptr_t res = uptr + len; + return res < uptr || res > uend; +} + +UPB_FORCEINLINE +static bool fastdecode_boundscheck2(const char* ptr, size_t len, + const char* end) { + // This is one extra branch compared to the more normal: + // return (size_t)(end - ptr) < size; + // However it is one less computation if we are just about to use "ptr + len": + // https://godbolt.org/z/35YGPz + // In microbenchmarks this shows an overall 4% improvement. + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end; + uintptr_t res = uptr + len; + return res < uptr || res > uend; +} + +typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, + void* ctx); + +UPB_FORCEINLINE +static const char* fastdecode_delimited(upb_Decoder* d, const char* ptr, + fastdecode_delimfunc* func, void* ctx) { + ptr++; + int len = (int8_t)ptr[-1]; + if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) { + // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. + // If it exceeds the buffer limit, limit/limit_ptr will change during + // sub-message parsing, so we need to preserve delta, not limit. + if (UPB_UNLIKELY(len & 0x80)) { + // Size varint >1 byte (length >= 128). + ptr = fastdecode_longsize(ptr, &len); + if (!ptr) { + // Corrupt wire format: size exceeded INT_MAX. + return NULL; + } + } + if (ptr - d->end + (int)len > d->limit) { + // Corrupt wire format: invalid limit. + return NULL; + } + int delta = decode_pushlimit(d, ptr, len); + ptr = func(d, ptr, ctx); + decode_poplimit(d, ptr, delta); + } else { + // Fast case: Sub-message is <128 bytes and fits in the current buffer. + // This means we can preserve limit/limit_ptr verbatim. + const char* saved_limit_ptr = d->limit_ptr; + int saved_limit = d->limit; + d->limit_ptr = ptr + len; + d->limit = d->limit_ptr - d->end; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); + ptr = func(d, ptr, ctx); + d->limit_ptr = saved_limit_ptr; + d->limit = saved_limit; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); + } + return ptr; +} + +/* singular, oneof, repeated field handling ***********************************/ + +typedef struct { + upb_Array* arr; + void* end; +} fastdecode_arr; + +typedef enum { + FD_NEXT_ATLIMIT, + FD_NEXT_SAMEFIELD, + FD_NEXT_OTHERFIELD +} fastdecode_next; + +typedef struct { + void* dst; + fastdecode_next next; + uint32_t tag; +} fastdecode_nextret; + +UPB_FORCEINLINE +static void* fastdecode_resizearr(upb_Decoder* d, void* dst, + fastdecode_arr* farr, int valbytes) { + if (UPB_UNLIKELY(dst == farr->end)) { + size_t old_size = farr->arr->size; + size_t old_bytes = old_size * valbytes; + size_t new_size = old_size * 2; + size_t new_bytes = new_size * valbytes; + char* old_ptr = _upb_array_ptr(farr->arr); + char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes); + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + farr->arr->size = new_size; + farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2); + dst = (void*)(new_ptr + (old_size * valbytes)); + farr->end = (void*)(new_ptr + (new_size * valbytes)); + } + return dst; +} + +UPB_FORCEINLINE +static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { + if (tagbytes == 1) { + return (uint8_t)tag == (uint8_t)data; + } else { + return (uint16_t)tag == (uint16_t)data; + } +} + +UPB_FORCEINLINE +static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, + int valbytes) { + farr->arr->len = + (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; +} + +UPB_FORCEINLINE +static fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst, + const char** ptr, + fastdecode_arr* farr, + uint64_t data, int tagbytes, + int valbytes) { + fastdecode_nextret ret; + dst = (char*)dst + valbytes; + + if (UPB_LIKELY(!decode_isdone(d, ptr))) { + ret.tag = fastdecode_loadtag(*ptr); + if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { + ret.next = FD_NEXT_SAMEFIELD; + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_OTHERFIELD; + } + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_ATLIMIT; + } + + ret.dst = dst; + return ret; +} + +UPB_FORCEINLINE +static void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) { + size_t ofs = data >> 48; + return (char*)msg + ofs; +} + +UPB_FORCEINLINE +static void* fastdecode_getfield(upb_Decoder* d, const char* ptr, + upb_Message* msg, uint64_t* data, + uint64_t* hasbits, fastdecode_arr* farr, + int valbytes, upb_card card) { + switch (card) { + case CARD_s: { + uint8_t hasbit_index = *data >> 24; + // Set hasbit and return pointer to scalar field. + *hasbits |= 1ull << hasbit_index; + return fastdecode_fieldmem(msg, *data); + } + case CARD_o: { + uint16_t case_ofs = *data >> 32; + uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); + uint8_t field_number = *data >> 24; + *oneof_case = field_number; + return fastdecode_fieldmem(msg, *data); + } + case CARD_r: { + // Get pointer to upb_Array and allocate/expand if necessary. + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + upb_Array** arr_p = fastdecode_fieldmem(msg, *data); + char* begin; + *(uint32_t*)msg |= *hasbits; + *hasbits = 0; + if (UPB_LIKELY(!*arr_p)) { + farr->arr = _upb_Array_New(&d->arena, 8, elem_size_lg2); + *arr_p = farr->arr; + } else { + farr->arr = *arr_p; + } + begin = _upb_array_ptr(farr->arr); + farr->end = begin + (farr->arr->size * valbytes); + *data = fastdecode_loadtag(ptr); + return begin + (farr->arr->len * valbytes); + } + default: + UPB_UNREACHABLE(); + } +} + +UPB_FORCEINLINE +static bool fastdecode_flippacked(uint64_t* data, int tagbytes) { + *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. + return fastdecode_checktag(*data, tagbytes); +} + +#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ + UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ + } \ + RETURN_GENERIC("packed check tag mismatch\n"); \ + } + +/* varint fields **************************************************************/ + +UPB_FORCEINLINE +static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { + if (valbytes == 1) { + return val != 0; + } else if (zigzag) { + if (valbytes == 4) { + uint32_t n = val; + return (n >> 1) ^ -(int32_t)(n & 1); + } else if (valbytes == 8) { + return (val >> 1) ^ -(int64_t)(val & 1); + } + UPB_UNREACHABLE(); + } + return val; +} + +UPB_FORCEINLINE +static const char* fastdecode_varint64(const char* ptr, uint64_t* val) { + ptr++; + *val = (uint8_t)ptr[-1]; + if (UPB_UNLIKELY(*val & 0x80)) { + int i; + for (i = 0; i < 8; i++) { + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + *val += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) goto done; + } + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + if (byte > 1) { + return NULL; + } + *val += (byte - 1) << 63; + } +done: + UPB_ASSUME(ptr != NULL); + return ptr; +} + +#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed) \ + uint64_t val; \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_varint64(ptr, &val); \ + if (ptr == NULL) return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + val = fastdecode_munge(val, valbytes, zigzag); \ + memcpy(dst, &val, valbytes); \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +typedef struct { + uint8_t valbytes; + bool zigzag; + void* dst; + fastdecode_arr farr; +} fastdecode_varintdata; + +UPB_FORCEINLINE +static const char* fastdecode_topackedvarint(upb_Decoder* d, const char* ptr, + void* ctx) { + fastdecode_varintdata* data = ctx; + void* dst = data->dst; + uint64_t val; + + while (!decode_isdone(d, &ptr)) { + dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); + ptr = fastdecode_varint64(ptr, &val); + if (ptr == NULL) return NULL; + val = fastdecode_munge(val, data->valbytes, data->zigzag); + memcpy(dst, &val, data->valbytes); + dst = (char*)dst + data->valbytes; + } + + fastdecode_commitarr(dst, &data->farr, data->valbytes); + return ptr; +} + +#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked) \ + fastdecode_varintdata ctx = {valbytes, zigzag}; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ + \ + ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ + valbytes, CARD_r); \ + if (UPB_UNLIKELY(!ctx.dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ + \ + if (UPB_UNLIKELY(ptr == NULL)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); + +#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed); \ + } + +#define z_ZZ true +#define b_ZZ false +#define v_ZZ false + +/* Generate all combinations: + * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ + +#define F(card, type, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, type##_ZZ, \ + upb_pr##type##valbytes##_##tagbytes##bt, \ + upb_pp##type##valbytes##_##tagbytes##bt); \ + } + +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef z_ZZ +#undef b_ZZ +#undef v_ZZ +#undef o_ONEOF +#undef s_ONEOF +#undef r_ONEOF +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDVARINT +#undef FASTDECODE_PACKEDVARINT +#undef FASTDECODE_VARINT + +/* fixed fields ***************************************************************/ + +#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed) \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("couldn't allocate array in arena\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + memcpy(dst, ptr, valbytes); \ + ptr += valbytes; \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked) \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ + \ + ptr += tagbytes; \ + int size = (uint8_t)ptr[0]; \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ + (size % valbytes) != 0)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + upb_Array** arr_p = fastdecode_fieldmem(msg, data); \ + upb_Array* arr = *arr_p; \ + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ + int elems = size / valbytes; \ + \ + if (UPB_LIKELY(!arr)) { \ + *arr_p = arr = _upb_Array_New(&d->arena, elems, elem_size_lg2); \ + if (!arr) { \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + } else { \ + _upb_Array_Resize(arr, elems, &d->arena); \ + } \ + \ + char* dst = _upb_array_ptr(arr); \ + memcpy(dst, ptr, size); \ + arr->len = elems; \ + \ + ptr += size; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed); \ + } + +/* Generate all combinations: + * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ + +#define F(card, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ + upb_prf##valbytes##_##tagbytes##bt); \ + } + +#define TYPES(card, tagbytes) \ + F(card, 4, tagbytes) \ + F(card, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDFIXED +#undef FASTDECODE_PACKEDFIXED + +/* string fields **************************************************************/ + +typedef const char* fastdecode_copystr_func(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + const upb_MiniTable* table, + uint64_t hasbits, + upb_StringView* dst); + +UPB_NOINLINE +static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + if (!decode_verifyutf8_inl(dst->data, dst->size)) { + return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); + } + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +} + +#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ + int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ + dst->size = 0; \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + if (d->options & kUpb_DecodeOption_AliasString) { \ + dst->data = ptr; \ + dst->size = size; \ + } else { \ + char* data = upb_Arena_Malloc(&d->arena, size); \ + if (!data) { \ + return fastdecode_err(d, kUpb_DecodeStatus_OutOfMemory); \ + } \ + memcpy(data, ptr, size); \ + dst->data = data; \ + dst->size = size; \ + } \ + \ + ptr += size; \ + if (validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } else { \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + } + +UPB_NOINLINE +static const char* fastdecode_longstring_utf8(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); +} + +UPB_NOINLINE +static const char* fastdecode_longstring_noutf8( + struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); +} + +UPB_FORCEINLINE +static void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size, + int copy, char* data, upb_StringView* dst) { + d->arena.head.ptr += copy; + dst->data = data; + UPB_UNPOISON_MEMORY_REGION(data, copy); + memcpy(data, ptr, copy); + UPB_POISON_MEMORY_REGION(data + size, copy - size); +} + +#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + card, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + size_t arena_has; \ + size_t common_has; \ + char* buf; \ + \ + UPB_ASSERT((d->options & kUpb_DecodeOption_AliasString) == 0); \ + UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (uint8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->size = size; \ + \ + buf = d->arena.head.ptr; \ + arena_has = _upb_ArenaHas(&d->arena); \ + common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ + \ + if (UPB_LIKELY(size <= 15 - tagbytes)) { \ + if (arena_has < 16) goto longstr; \ + d->arena.head.ptr += 16; \ + memcpy(buf, ptr - tagbytes - 1, 16); \ + dst->data = buf + tagbytes + 1; \ + } else if (UPB_LIKELY(size <= 32)) { \ + if (UPB_UNLIKELY(common_has < 32)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 32, buf, dst); \ + } else if (UPB_LIKELY(size <= 64)) { \ + if (UPB_UNLIKELY(common_has < 64)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 64, buf, dst); \ + } else if (UPB_LIKELY(size < 128)) { \ + if (UPB_UNLIKELY(common_has < 128)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 128, buf, dst); \ + } else { \ + goto longstr; \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + \ + longstr: \ + if (card == CARD_r) { \ + fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView)); \ + } \ + ptr--; \ + if (validate_utf8) { \ + UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } else { \ + UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } + +#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ + copyfunc, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("string field tag mismatch\n"); \ + } \ + \ + if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ + UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (int8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->data = ptr; \ + dst->size = size; \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ + ptr--; \ + if (validate_utf8) { \ + return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } else { \ + return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ + /* Buffer flipped and we can't alias any more. Bounce to */ \ + /* copyfunc(), but via dispatch since we need to reload table */ \ + /* data also. */ \ + fastdecode_commitarr(dst, &farr, sizeof(upb_StringView)); \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + } \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +/* Generate all combinations: + * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ + +#define s_VALIDATE true +#define b_VALIDATE false + +#define F(card, tagbytes, type) \ + UPB_NOINLINE \ + const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, type##_VALIDATE); \ + } \ + const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, upb_c##card##type##_##tagbytes##bt, \ + type##_VALIDATE); \ + } + +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) + +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef s_VALIDATE +#undef b_VALIDATE +#undef F +#undef TAGBYTES +#undef FASTDECODE_LONGSTRING +#undef FASTDECODE_COPYSTRING +#undef FASTDECODE_STRING + +/* message fields *************************************************************/ + +UPB_INLINE +upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* l, + int msg_ceil_bytes) { + size_t size = l->size + sizeof(upb_Message_Internal); + char* msg_data; + if (UPB_LIKELY(msg_ceil_bytes > 0 && + _upb_ArenaHas(&d->arena) >= msg_ceil_bytes)) { + UPB_ASSERT(size <= (size_t)msg_ceil_bytes); + msg_data = d->arena.head.ptr; + d->arena.head.ptr += size; + UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); + memset(msg_data, 0, msg_ceil_bytes); + UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); + } else { + msg_data = (char*)upb_Arena_Malloc(&d->arena, size); + memset(msg_data, 0, size); + } + return msg_data + sizeof(upb_Message_Internal); +} + +typedef struct { + intptr_t table; + upb_Message* msg; +} fastdecode_submsgdata; + +UPB_FORCEINLINE +static const char* fastdecode_tosubmsg(upb_Decoder* d, const char* ptr, + void* ctx) { + fastdecode_submsgdata* submsg = ctx; + ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); + UPB_ASSUME(ptr != NULL); + return ptr; +} + +#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ + msg_ceil_bytes, card) \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("submessage field tag mismatch\n"); \ + } \ + \ + if (--d->depth == 0) { \ + return fastdecode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); \ + } \ + \ + upb_Message** dst; \ + uint32_t submsg_idx = (data >> 16) & 0xff; \ + const upb_MiniTable* tablep = decode_totablep(table); \ + const upb_MiniTable* subtablep = tablep->subs[submsg_idx].submsg; \ + fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ + fastdecode_arr farr; \ + \ + if (subtablep->table_mask == (uint8_t)-1) { \ + RETURN_GENERIC("submessage doesn't have fast tables."); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_Message*), card); \ + \ + if (card == CARD_s) { \ + *(uint32_t*)msg |= hasbits; \ + hasbits = 0; \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ + } \ + \ + submsg.msg = *dst; \ + \ + if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ + *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ + \ + if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + d->depth++; \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + d->depth++; \ + return ptr; \ + } \ + } \ + \ + d->depth++; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ + UPB_PARSE_PARAMS) { \ + FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ + CARD_##card); \ + } + +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) + +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef TAGBYTES +#undef SIZES +#undef F +#undef FASTDECODE_SUBMSG + +#endif /* UPB_FASTTABLE */ + +/** upb/json_decode.c ************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Special header, must be included last. */ + +typedef struct { + const char *ptr, *end; + upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ + const upb_DefPool* symtab; + int depth; + upb_Status* status; + jmp_buf err; + int line; + const char* line_begin; + bool is_first; + int options; + const upb_FieldDef* debug_field; +} jsondec; + +enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; + +/* Forward declarations of mutually-recursive functions. */ +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); + +static bool jsondec_streql(upb_StringView str, const char* lit) { + return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; +} + +static bool jsondec_isnullvalue(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum && + strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), + "google.protobuf.NullValue") == 0; +} + +static bool jsondec_isvalue(const upb_FieldDef* f) { + return (upb_FieldDef_CType(f) == kUpb_CType_Message && + upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == + kUpb_WellKnown_Value) || + jsondec_isnullvalue(f); +} + +UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, + (int)(d->ptr - d->line_begin), msg); + UPB_LONGJMP(d->err, 1); +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, + (int)(d->ptr - d->line_begin)); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); +} + +static void jsondec_skipws(jsondec* d) { + while (d->ptr != d->end) { + switch (*d->ptr) { + case '\n': + d->line++; + d->line_begin = d->ptr; + /* Fallthrough. */ + case '\r': + case '\t': + case ' ': + d->ptr++; + break; + default: + return; + } + } + jsondec_err(d, "Unexpected EOF"); +} + +static bool jsondec_tryparsech(jsondec* d, char ch) { + if (d->ptr == d->end || *d->ptr != ch) return false; + d->ptr++; + return true; +} + +static void jsondec_parselit(jsondec* d, const char* lit) { + size_t avail = d->end - d->ptr; + size_t len = strlen(lit); + if (avail < len || memcmp(d->ptr, lit, len) != 0) { + jsondec_errf(d, "Expected: '%s'", lit); + } + d->ptr += len; +} + +static void jsondec_wsch(jsondec* d, char ch) { + jsondec_skipws(d); + if (!jsondec_tryparsech(d, ch)) { + jsondec_errf(d, "Expected: '%c'", ch); + } +} + +static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } +static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } +static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } + +static void jsondec_entrysep(jsondec* d) { + jsondec_skipws(d); + jsondec_parselit(d, ":"); +} + +static int jsondec_rawpeek(jsondec* d) { + switch (*d->ptr) { + case '{': + return JD_OBJECT; + case '[': + return JD_ARRAY; + case '"': + return JD_STRING; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return JD_NUMBER; + case 't': + return JD_TRUE; + case 'f': + return JD_FALSE; + case 'n': + return JD_NULL; + default: + jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); + } +} + +/* JSON object/array **********************************************************/ + +/* These are used like so: + * + * jsondec_objstart(d); + * while (jsondec_objnext(d)) { + * ... + * } + * jsondec_objend(d) */ + +static int jsondec_peek(jsondec* d) { + jsondec_skipws(d); + return jsondec_rawpeek(d); +} + +static void jsondec_push(jsondec* d) { + if (--d->depth < 0) { + jsondec_err(d, "Recursion limit exceeded"); + } + d->is_first = true; +} + +static bool jsondec_seqnext(jsondec* d, char end_ch) { + bool is_first = d->is_first; + d->is_first = false; + jsondec_skipws(d); + if (*d->ptr == end_ch) return false; + if (!is_first) jsondec_parselit(d, ","); + return true; +} + +static void jsondec_arrstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '['); +} + +static void jsondec_arrend(jsondec* d) { + d->depth++; + jsondec_wsch(d, ']'); +} + +static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } + +static void jsondec_objstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '{'); +} + +static void jsondec_objend(jsondec* d) { + d->depth++; + jsondec_wsch(d, '}'); +} + +static bool jsondec_objnext(jsondec* d) { + if (!jsondec_seqnext(d, '}')) return false; + if (jsondec_peek(d) != JD_STRING) { + jsondec_err(d, "Object must start with string"); + } + return true; +} + +/* JSON number ****************************************************************/ + +static bool jsondec_tryskipdigits(jsondec* d) { + const char* start = d->ptr; + + while (d->ptr < d->end) { + if (*d->ptr < '0' || *d->ptr > '9') { + break; + } + d->ptr++; + } + + return d->ptr != start; +} + +static void jsondec_skipdigits(jsondec* d) { + if (!jsondec_tryskipdigits(d)) { + jsondec_err(d, "Expected one or more digits"); + } +} + +static double jsondec_number(jsondec* d) { + const char* start = d->ptr; + + assert(jsondec_rawpeek(d) == JD_NUMBER); + + /* Skip over the syntax of a number, as specified by JSON. */ + if (*d->ptr == '-') d->ptr++; + + if (jsondec_tryparsech(d, '0')) { + if (jsondec_tryskipdigits(d)) { + jsondec_err(d, "number cannot have leading zero"); + } + } else { + jsondec_skipdigits(d); + } + + if (d->ptr == d->end) goto parse; + if (jsondec_tryparsech(d, '.')) { + jsondec_skipdigits(d); + } + if (d->ptr == d->end) goto parse; + + if (*d->ptr == 'e' || *d->ptr == 'E') { + d->ptr++; + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF in number"); + } + if (*d->ptr == '+' || *d->ptr == '-') { + d->ptr++; + } + jsondec_skipdigits(d); + } + +parse: + /* Having verified the syntax of a JSON number, use strtod() to parse + * (strtod() accepts a superset of JSON syntax). */ + errno = 0; + { + char* end; + double val = strtod(start, &end); + assert(end == d->ptr); + + /* Currently the min/max-val conformance tests fail if we check this. Does + * this mean the conformance tests are wrong or strtod() is wrong, or + * something else? Investigate further. */ + /* + if (errno == ERANGE) { + jsondec_err(d, "Number out of range"); + } + */ + + if (val > DBL_MAX || val < -DBL_MAX) { + jsondec_err(d, "Number out of range"); + } + + return val; + } +} + +/* JSON string ****************************************************************/ + +static char jsondec_escape(jsondec* d) { + switch (*d->ptr++) { + case '"': + return '\"'; + case '\\': + return '\\'; + case '/': + return '/'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + default: + jsondec_err(d, "Invalid escape char"); + } +} + +static uint32_t jsondec_codepoint(jsondec* d) { + uint32_t cp = 0; + const char* end; + + if (d->end - d->ptr < 4) { + jsondec_err(d, "EOF inside string"); + } + + end = d->ptr + 4; + while (d->ptr < end) { + char ch = *d->ptr++; + if (ch >= '0' && ch <= '9') { + ch -= '0'; + } else if (ch >= 'a' && ch <= 'f') { + ch = ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + ch = ch - 'A' + 10; + } else { + jsondec_err(d, "Invalid hex digit"); + } + cp = (cp << 4) | ch; + } + + return cp; +} + +/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ +static size_t jsondec_unicode(jsondec* d, char* out) { + uint32_t cp = jsondec_codepoint(d); + if (cp >= 0xd800 && cp <= 0xdbff) { + /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ + uint32_t high = cp; + uint32_t low; + jsondec_parselit(d, "\\u"); + low = jsondec_codepoint(d); + if (low < 0xdc00 || low > 0xdfff) { + jsondec_err(d, "Invalid low surrogate"); + } + cp = (high & 0x3ff) << 10; + cp |= (low & 0x3ff); + cp += 0x10000; + } else if (cp >= 0xdc00 && cp <= 0xdfff) { + jsondec_err(d, "Unpaired low surrogate"); + } + + /* Write to UTF-8 */ + if (cp <= 0x7f) { + out[0] = cp; + return 1; + } else if (cp <= 0x07FF) { + out[0] = ((cp >> 6) & 0x1F) | 0xC0; + out[1] = ((cp >> 0) & 0x3F) | 0x80; + return 2; + } else if (cp <= 0xFFFF) { + out[0] = ((cp >> 12) & 0x0F) | 0xE0; + out[1] = ((cp >> 6) & 0x3F) | 0x80; + out[2] = ((cp >> 0) & 0x3F) | 0x80; + return 3; + } else if (cp < 0x10FFFF) { + out[0] = ((cp >> 18) & 0x07) | 0xF0; + out[1] = ((cp >> 12) & 0x3f) | 0x80; + out[2] = ((cp >> 6) & 0x3f) | 0x80; + out[3] = ((cp >> 0) & 0x3f) | 0x80; + return 4; + } else { + jsondec_err(d, "Invalid codepoint"); + } +} + +static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { + size_t oldsize = *buf_end - *buf; + size_t len = *end - *buf; + size_t size = UPB_MAX(8, 2 * oldsize); + + *buf = upb_Arena_Realloc(d->arena, *buf, len, size); + if (!*buf) jsondec_err(d, "Out of memory"); + + *end = *buf + len; + *buf_end = *buf + size; +} + +static upb_StringView jsondec_string(jsondec* d) { + char* buf = NULL; + char* end = NULL; + char* buf_end = NULL; + + jsondec_skipws(d); + + if (*d->ptr++ != '"') { + jsondec_err(d, "Expected string"); + } + + while (d->ptr < d->end) { + char ch = *d->ptr++; + + if (end == buf_end) { + jsondec_resize(d, &buf, &end, &buf_end); + } + + switch (ch) { + case '"': { + upb_StringView ret; + ret.data = buf; + ret.size = end - buf; + *end = '\0'; /* Needed for possible strtod(). */ + return ret; + } + case '\\': + if (d->ptr == d->end) goto eof; + if (*d->ptr == 'u') { + d->ptr++; + if (buf_end - end < 4) { + /* Allow space for maximum-sized code point (4 bytes). */ + jsondec_resize(d, &buf, &end, &buf_end); + } + end += jsondec_unicode(d, end); + } else { + *end++ = jsondec_escape(d); + } + break; + default: + if ((unsigned char)*d->ptr < 0x20) { + jsondec_err(d, "Invalid char in JSON string"); + } + *end++ = ch; + break; + } + } + +eof: + jsondec_err(d, "EOF inside string"); +} + +static void jsondec_skipval(jsondec* d) { + switch (jsondec_peek(d)) { + case JD_OBJECT: + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_string(d); + jsondec_entrysep(d); + jsondec_skipval(d); + } + jsondec_objend(d); + break; + case JD_ARRAY: + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + jsondec_skipval(d); + } + jsondec_arrend(d); + break; + case JD_TRUE: + jsondec_true(d); + break; + case JD_FALSE: + jsondec_false(d); + break; + case JD_NULL: + jsondec_null(d); + break; + case JD_STRING: + jsondec_string(d); + break; + case JD_NUMBER: + jsondec_number(d); + break; + } +} + +/* Base64 decoding for bytes fields. ******************************************/ + +static unsigned int jsondec_base64_tablelookup(const char ch) { + /* Table includes the normal base64 chars plus the URL-safe variant. */ + const signed char table[256] = { + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, + 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, + 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, + -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, + 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, + 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, + 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, + -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, + 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, + 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, + 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, + 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; + + /* Sign-extend return value so high bit will be set on any unexpected char. */ + return table[(unsigned)ch]; +} + +static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, + char* out) { + int32_t val = -1; + + switch (end - ptr) { + case 2: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12; + out[0] = val >> 16; + out += 1; + break; + case 3: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6; + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out += 2; + break; + } + + if (val < 0) { + jsondec_err(d, "Corrupt base64"); + } + + return out; +} + +static size_t jsondec_base64(jsondec* d, upb_StringView str) { + /* We decode in place. This is safe because this is a new buffer (not + * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ + char* out = (char*)str.data; + const char* ptr = str.data; + const char* end = ptr + str.size; + const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ + + for (; ptr < end4; ptr += 4, out += 3) { + int val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6 | + jsondec_base64_tablelookup(ptr[3]) << 0; + + if (val < 0) { + /* Junk chars or padding. Remove trailing padding, if any. */ + if (end - ptr == 4 && ptr[3] == '=') { + if (ptr[2] == '=') { + end -= 2; + } else { + end -= 1; + } + } + break; + } + + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; + } + + if (ptr < end) { + /* Process remaining chars. We do not require padding. */ + out = jsondec_partialbase64(d, ptr, end, out); + } + + return out - str.data; +} + +/* Low-level integer parsing **************************************************/ + +/* We use these hand-written routines instead of strto[u]l() because the "long + * long" variants aren't in c89. Also our version allows setting a ptr limit. */ + +static const char* jsondec_buftouint64(jsondec* d, const char* ptr, + const char* end, uint64_t* val) { + uint64_t u64 = 0; + while (ptr < end) { + unsigned ch = *ptr - '0'; + if (ch >= 10) break; + if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { + jsondec_err(d, "Integer overflow"); + } + u64 *= 10; + u64 += ch; + ptr++; + } + + *val = u64; + return ptr; +} + +static const char* jsondec_buftoint64(jsondec* d, const char* ptr, + const char* end, int64_t* val) { + bool neg = false; + uint64_t u64; + + if (ptr != end && *ptr == '-') { + ptr++; + neg = true; + } + + ptr = jsondec_buftouint64(d, ptr, end, &u64); + if (u64 > (uint64_t)INT64_MAX + neg) { + jsondec_err(d, "Integer overflow"); + } + + *val = neg ? -u64 : u64; + return ptr; +} + +static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + uint64_t ret; + if (jsondec_buftouint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; +} + +static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + int64_t ret; + if (jsondec_buftoint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; +} + +/* Primitive value types ******************************************************/ + +/* Parse INT32 or INT64 value. */ +static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { + jsondec_err(d, "JSON number is out of range."); + } + val.int64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.int64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, + val.int64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.int64_val = jsondec_strtoint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || + upb_FieldDef_CType(f) == kUpb_CType_Enum) { + if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { + jsondec_err(d, "Integer out of range."); + } + val.int32_val = (int32_t)val.int64_val; + } + + return val; +} + +/* Parse UINT32 or UINT64 value. */ +static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val = {0}; + + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 18446744073709549568.0 || dbl < 0) { + jsondec_err(d, "JSON number is out of range."); + } + val.uint64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.uint64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, + val.uint64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.uint64_val = jsondec_strtouint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { + if (val.uint64_val > UINT32_MAX) { + jsondec_err(d, "Integer out of range."); + } + val.uint32_val = (uint32_t)val.uint64_val; + } + + return val; +} + +/* Parse DOUBLE or FLOAT value. */ +static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { + upb_StringView str; + upb_MessageValue val = {0}; + + switch (jsondec_peek(d)) { + case JD_NUMBER: + val.double_val = jsondec_number(d); + break; + case JD_STRING: + str = jsondec_string(d); + if (jsondec_streql(str, "NaN")) { + val.double_val = NAN; + } else if (jsondec_streql(str, "Infinity")) { + val.double_val = INFINITY; + } else if (jsondec_streql(str, "-Infinity")) { + val.double_val = -INFINITY; + } else { + val.double_val = strtod(str.data, NULL); + } + break; + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_Float) { + if (val.double_val != INFINITY && val.double_val != -INFINITY && + (val.double_val > FLT_MAX || val.double_val < -FLT_MAX)) { + jsondec_err(d, "Float out of range"); + } + val.float_val = val.double_val; + } + + return val; +} + +/* Parse STRING or BYTES value. */ +static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + val.str_val = jsondec_string(d); + if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { + val.str_val.size = jsondec_base64(d, val.str_val); + } + return val; +} + +static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { + switch (jsondec_peek(d)) { + case JD_STRING: { + upb_StringView str = jsondec_string(d); + const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); + upb_MessageValue val; + if (ev) { + val.int32_val = upb_EnumValueDef_Number(ev); + } else { + if (d->options & upb_JsonDecode_IgnoreUnknown) { + val.int32_val = 0; + } else { + jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(str)); + } + } + return val; + } + case JD_NULL: { + if (jsondec_isnullvalue(f)) { + upb_MessageValue val; + jsondec_null(d); + val.int32_val = 0; + return val; + } + } + /* Fallthrough. */ + default: + return jsondec_int(d, f); + } +} + +static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { + bool is_map_key = upb_FieldDef_Number(f) == 1 && + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); + upb_MessageValue val; + + if (is_map_key) { + upb_StringView str = jsondec_string(d); + if (jsondec_streql(str, "true")) { + val.bool_val = true; + } else if (jsondec_streql(str, "false")) { + val.bool_val = false; + } else { + jsondec_err(d, "Invalid boolean map key"); + } + } else { + switch (jsondec_peek(d)) { + case JD_TRUE: + val.bool_val = true; + jsondec_true(d); + break; + case JD_FALSE: + val.bool_val = false; + jsondec_false(d); + break; + default: + jsondec_err(d, "Expected true or false"); + } + } + + return val; +} + +/* Composite types (array/message/map) ****************************************/ + +static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; + + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_MessageValue elem = jsondec_value(d, f); + upb_Array_Append(arr, elem, d->arena); + } + jsondec_arrend(d); +} + +static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, val; + key = jsondec_value(d, key_f); + jsondec_entrysep(d); + val = jsondec_value(d, val_f); + upb_Map_Set(map, key, val, d->arena); + } + jsondec_objend(d); +} + +static void jsondec_tomsg(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + jsondec_object(d, msg, m); + } else { + jsondec_wellknown(d, msg, m); + } +} + +static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + upb_Message* msg = upb_Message_New(m, d->arena); + upb_MessageValue val; + + jsondec_tomsg(d, msg, m); + val.msg_val = msg; + return val; +} + +static void jsondec_field(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_StringView name; + const upb_FieldDef* f; + const upb_FieldDef* preserved; + + name = jsondec_string(d); + jsondec_entrysep(d); + + if (name.size >= 2 && name.data[0] == '[' && + name.data[name.size - 1] == ']') { + f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, + name.size - 2); + if (f && upb_FieldDef_ContainingType(f) != m) { + jsondec_errf( + d, "Extension %s extends message %s, but was seen in message %s", + upb_FieldDef_FullName(f), + upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), + upb_MessageDef_FullName(m)); + } + } else { + f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); + } + + if (!f) { + if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { + jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + } + jsondec_skipval(d); + return; + } + + if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { + /* JSON "null" indicates a default value, so no need to set anything. */ + jsondec_null(d); + return; + } + + if (upb_FieldDef_RealContainingOneof(f) && + upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { + jsondec_err(d, "More than one field for this oneof."); + } + + preserved = d->debug_field; + d->debug_field = f; + + if (upb_FieldDef_IsMap(f)) { + jsondec_map(d, msg, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsondec_array(d, msg, f); + } else if (upb_FieldDef_IsSubMessage(f)) { + upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + jsondec_tomsg(d, submsg, subm); + } else { + upb_MessageValue val = jsondec_value(d, f); + upb_Message_Set(msg, f, val, d->arena); + } + + d->debug_field = preserved; +} + +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_field(d, msg, m); + } + jsondec_objend(d); +} + +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return jsondec_bool(d, f); + case kUpb_CType_Float: + case kUpb_CType_Double: + return jsondec_double(d, f); + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + return jsondec_uint(d, f); + case kUpb_CType_Int32: + case kUpb_CType_Int64: + return jsondec_int(d, f); + case kUpb_CType_String: + case kUpb_CType_Bytes: + return jsondec_strfield(d, f); + case kUpb_CType_Enum: + return jsondec_enum(d, f); + case kUpb_CType_Message: + return jsondec_msg(d, f); + default: + UPB_UNREACHABLE(); + } +} + +/* Well-known types ***********************************************************/ + +static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, + const char* after) { + uint64_t val; + const char* p = *ptr; + const char* end = p + digits; + size_t after_len = after ? strlen(after) : 0; + + UPB_ASSERT(digits <= 9); /* int can't overflow. */ + + if (jsondec_buftouint64(d, p, end, &val) != end || + (after_len && memcmp(end, after, after_len) != 0)) { + jsondec_err(d, "Malformed timestamp"); + } + + UPB_ASSERT(val < INT_MAX); + + *ptr = end + after_len; + return (int)val; +} + +static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { + uint64_t nanos = 0; + const char* p = *ptr; + + if (p != end && *p == '.') { + const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); + int digits = (int)(nano_end - p - 1); + int exp_lg10 = 9 - digits; + if (digits > 9) { + jsondec_err(d, "Too many digits for partial seconds"); + } + while (exp_lg10--) nanos *= 10; + *ptr = nano_end; + } + + UPB_ASSERT(nanos < INT_MAX); + + return (int)nanos; +} + +/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ +int jsondec_epochdays(int y, int m, int d) { + const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ + const uint32_t m_adj = m - 3; /* March-based month. */ + const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; + const uint32_t adjust = carry ? 12 : 0; + const uint32_t y_adj = y + year_base - carry; + const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; + const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; + return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +} + +static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { + return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; +} + +static void jsondec_timestamp(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + + if (str.size < 20) goto malformed; + + { + /* 1972-01-01T01:00:00 */ + int year = jsondec_tsdigits(d, &ptr, 4, "-"); + int mon = jsondec_tsdigits(d, &ptr, 2, "-"); + int day = jsondec_tsdigits(d, &ptr, 2, "T"); + int hour = jsondec_tsdigits(d, &ptr, 2, ":"); + int min = jsondec_tsdigits(d, &ptr, 2, ":"); + int sec = jsondec_tsdigits(d, &ptr, 2, NULL); + + seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); + } + + nanos.int32_val = jsondec_nanos(d, &ptr, end); + + { + /* [+-]08:00 or Z */ + int ofs_hour = 0; + int ofs_min = 0; + bool neg = false; + + if (ptr == end) goto malformed; + + switch (*ptr++) { + case '-': + neg = true; + /* fallthrough */ + case '+': + if ((end - ptr) != 5) goto malformed; + ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); + ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); + ofs_min = ((ofs_hour * 60) + ofs_min) * 60; + seconds.int64_val += (neg ? ofs_min : -ofs_min); + break; + case 'Z': + if (ptr != end) goto malformed; + break; + default: + goto malformed; + } + } + + if (seconds.int64_val < -62135596800) { + jsondec_err(d, "Timestamp out of range"); + } + + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); + return; + +malformed: + jsondec_err(d, "Malformed timestamp"); +} + +static void jsondec_duration(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + const int64_t max = (uint64_t)3652500 * 86400; + + /* "3.000000001s", "3s", etc. */ + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val); + nanos.int32_val = jsondec_nanos(d, &ptr, end); + + if (end - ptr != 1 || *ptr != 's') { + jsondec_err(d, "Malformed duration"); + } + + if (seconds.int64_val < -max || seconds.int64_val > max) { + jsondec_err(d, "Duration out of range"); + } + + if (seconds.int64_val < 0) { + nanos.int32_val = -nanos.int32_val; + } + + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); +} + +static void jsondec_listvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); + upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; + + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + upb_MessageValue value; + value.msg_val = value_msg; + upb_Array_Append(values, value, d->arena); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_arrend(d); +} + +static void jsondec_struct(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); + upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; + + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, value; + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + key.str_val = jsondec_string(d); + value.msg_val = value_msg; + upb_Map_Set(fields, key, value, d->arena); + jsondec_entrysep(d); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_objend(d); +} + +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue val; + const upb_FieldDef* f; + upb_Message* submsg; + + switch (jsondec_peek(d)) { + case JD_NUMBER: + /* double number_value = 2; */ + f = upb_MessageDef_FindFieldByNumber(m, 2); + val.double_val = jsondec_number(d); + break; + case JD_STRING: + /* string string_value = 3; */ + f = upb_MessageDef_FindFieldByNumber(m, 3); + val.str_val = jsondec_string(d); + break; + case JD_FALSE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = false; + jsondec_false(d); + break; + case JD_TRUE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = true; + jsondec_true(d); + break; + case JD_NULL: + /* NullValue null_value = 1; */ + f = upb_MessageDef_FindFieldByNumber(m, 1); + val.int32_val = 0; + jsondec_null(d); + break; + /* Note: these cases return, because upb_Message_Mutable() is enough. */ + case JD_OBJECT: + /* Struct struct_value = 5; */ + f = upb_MessageDef_FindFieldByNumber(m, 5); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + case JD_ARRAY: + /* ListValue list_value = 6; */ + f = upb_MessageDef_FindFieldByNumber(m, 6); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + default: + UPB_UNREACHABLE(); + } + + upb_Message_Set(msg, f, val, d->arena); +} + +static upb_StringView jsondec_mask(jsondec* d, const char* buf, + const char* end) { + /* FieldMask fields grow due to inserted '_' characters, so we can't do the + * transform in place. */ + const char* ptr = buf; + upb_StringView ret; + char* out; + + ret.size = end - ptr; + while (ptr < end) { + ret.size += (*ptr >= 'A' && *ptr <= 'Z'); + ptr++; + } + + out = upb_Arena_Malloc(d->arena, ret.size); + ptr = buf; + ret.data = out; + + while (ptr < end) { + char ch = *ptr++; + if (ch >= 'A' && ch <= 'Z') { + *out++ = '_'; + *out++ = ch + 32; + } else if (ch == '_') { + jsondec_err(d, "field mask may not contain '_'"); + } else { + *out++ = ch; + } + } + + return ret; +} + +static void jsondec_fieldmask(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + /* repeated string paths = 1; */ + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + upb_MessageValue val; + + while (ptr < end) { + const char* elem_end = memchr(ptr, ',', end - ptr); + if (elem_end) { + val.str_val = jsondec_mask(d, ptr, elem_end); + ptr = elem_end + 1; + } else { + val.str_val = jsondec_mask(d, ptr, end); + ptr = end; + } + upb_Array_Append(arr, val, d->arena); + } +} + +static void jsondec_anyfield(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + /* For regular types: {"@type": "[user type]", "f1": , "f2": } + * where f1, f2, etc. are the normal fields of this type. */ + jsondec_field(d, msg, m); + } else { + /* For well-known types: {"@type": "[well-known type]", "value": } + * where is whatever encoding the WKT normally uses. */ + upb_StringView str = jsondec_string(d); + jsondec_entrysep(d); + if (!jsondec_streql(str, "value")) { + jsondec_err(d, "Key for well-known type must be 'value'"); + } + jsondec_wellknown(d, msg, m); + } +} + +static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* type_m; + upb_StringView type_url = jsondec_string(d); + const char* end = type_url.data + type_url.size; + const char* ptr = end; + upb_MessageValue val; + + val.str_val = type_url; + upb_Message_Set(msg, type_url_f, val, d->arena); + + /* Find message name after the last '/' */ + while (ptr > type_url.data && *--ptr != '/') { + } + + if (ptr == type_url.data || ptr == end) { + jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + } + + ptr++; + type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); + + if (!type_m) { + jsondec_err(d, "Type was not found"); + } + + return type_m; +} + +static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { + /* string type_url = 1; + * bytes value = 2; */ + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_Message* any_msg; + const upb_MessageDef* any_m = NULL; + const char* pre_type_data = NULL; + const char* pre_type_end = NULL; + upb_MessageValue encoded; + + jsondec_objstart(d); + + /* Scan looking for "@type", which is not necessarily first. */ + while (!any_m && jsondec_objnext(d)) { + const char* start = d->ptr; + upb_StringView name = jsondec_string(d); + jsondec_entrysep(d); + if (jsondec_streql(name, "@type")) { + any_m = jsondec_typeurl(d, msg, m); + if (pre_type_data) { + pre_type_end = start; + while (*pre_type_end != ',') pre_type_end--; + } + } else { + if (!pre_type_data) pre_type_data = start; + jsondec_skipval(d); + } + } + + if (!any_m) { + jsondec_err(d, "Any object didn't contain a '@type' field"); + } + + any_msg = upb_Message_New(any_m, d->arena); + + if (pre_type_data) { + size_t len = pre_type_end - pre_type_data + 1; + char* tmp = upb_Arena_Malloc(d->arena, len); + const char* saved_ptr = d->ptr; + const char* saved_end = d->end; + memcpy(tmp, pre_type_data, len - 1); + tmp[len - 1] = '}'; + d->ptr = tmp; + d->end = tmp + len; + d->is_first = true; + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); + } + d->ptr = saved_ptr; + d->end = saved_end; + } + + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); + } + + jsondec_objend(d); + + encoded.str_val.data = upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, + d->arena, &encoded.str_val.size); + upb_Message_Set(msg, value_f, encoded, d->arena); +} + +static void jsondec_wrapper(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = jsondec_value(d, value_f); + upb_Message_Set(msg, value_f, val, d->arena); +} + +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Any: + jsondec_any(d, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsondec_fieldmask(d, msg, m); + break; + case kUpb_WellKnown_Duration: + jsondec_duration(d, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsondec_timestamp(d, msg, m); + break; + case kUpb_WellKnown_Value: + jsondec_wellknownvalue(d, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsondec_listvalue(d, msg, m); + break; + case kUpb_WellKnown_Struct: + jsondec_struct(d, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsondec_wrapper(d, msg, m); + break; + default: + UPB_UNREACHABLE(); + } +} + +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status) { + jsondec d; + + if (size == 0) return true; + + d.ptr = buf; + d.end = buf + size; + d.arena = arena; + d.symtab = symtab; + d.status = status; + d.options = options; + d.depth = 64; + d.line = 1; + d.line_begin = d.ptr; + d.debug_field = NULL; + d.is_first = false; + + if (UPB_SETJMP(d.err)) return false; + + jsondec_tomsg(&d, msg, m); + return true; +} + +/** upb/json_encode.c ************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Must be last. */ + +typedef struct { + char *buf, *ptr, *end; + size_t overflow; + int indent_depth; + int options; + const upb_DefPool* ext_pool; + jmp_buf err; + upb_Status* status; + upb_Arena* arena; +} jsonenc; + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f); +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first); +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); + +UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { + upb_Status_SetErrorMessage(e->status, msg); + longjmp(e->err, 1); +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(e->status, fmt, argp); + va_end(argp); + longjmp(e->err, 1); +} + +static upb_Arena* jsonenc_arena(jsonenc* e) { + /* Create lazily, since it's only needed for Any */ + if (!e->arena) { + e->arena = upb_Arena_New(); + } + return e->arena; +} + +static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { + size_t have = e->end - e->ptr; + if (UPB_LIKELY(have >= len)) { + memcpy(e->ptr, data, len); + e->ptr += len; + } else { + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; + } + e->overflow += (len - have); + } +} + +static void jsonenc_putstr(jsonenc* e, const char* str) { + jsonenc_putbytes(e, str, strlen(str)); +} + +UPB_PRINTF(2, 3) +static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { + size_t n; + size_t have = e->end - e->ptr; + va_list args; + + va_start(args, fmt); + n = _upb_vsnprintf(e->ptr, have, fmt, args); + va_end(args); + + if (UPB_LIKELY(have > n)) { + e->ptr += n; + } else { + e->ptr = UPB_PTRADD(e->ptr, have); + e->overflow += (n - have); + } +} + +static void jsonenc_nanos(jsonenc* e, int32_t nanos) { + int digits = 9; + + if (nanos == 0) return; + if (nanos < 0 || nanos >= 1000000000) { + jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); + } + + while (nanos % 1000 == 0) { + nanos /= 1000; + digits -= 3; + } + + jsonenc_printf(e, ".%.*" PRId32, digits, nanos); +} + +static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + int L, N, I, J, K, hour, min, sec; + + if (seconds < -62135596800) { + jsonenc_err(e, + "error formatting timestamp as JSON: minimum acceptable value " + "is 0001-01-01T00:00:00Z"); + } else if (seconds > 253402300799) { + jsonenc_err(e, + "error formatting timestamp as JSON: maximum acceptable value " + "is 9999-12-31T23:59:59Z"); + } + + /* Julian Day -> Y/M/D, Algorithm from: + * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for + * Processing Calendar Dates," Communications of the Association of + * Computing Machines, vol. 11 (1968), p. 657. */ + seconds += 62135596800; // Ensure seconds is positive. + L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; + N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + I = 4000 * (L + 1) / 1461001; + L = L - 1461 * I / 4 + 31; + J = 80 * L / 2447; + K = L - 2447 * J / 80; + L = J / 11; + J = J + 2 - 12 * L; + I = 100 * (N - 49) + I + L; + + sec = seconds % 60; + min = (seconds / 60) % 60; + hour = (seconds / 3600) % 24; + + jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "Z\""); +} + +static void jsonenc_duration(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + + if (seconds > 315576000000 || seconds < -315576000000 || + (seconds < 0) != (nanos < 0)) { + jsonenc_err(e, "bad duration"); + } + + if (nanos < 0) { + nanos = -nanos; + } + + jsonenc_printf(e, "\"%" PRId64, seconds); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "s\""); +} + +static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { + const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); + + if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { + jsonenc_putstr(e, "null"); + } else { + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e_def, val); + + if (ev) { + jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); + } else { + jsonenc_printf(e, "%" PRId32, val); + } + } +} + +static void jsonenc_bytes(jsonenc* e, upb_StringView str) { + /* This is the regular base64, not the "web-safe" version. */ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const unsigned char* ptr = (unsigned char*)str.data; + const unsigned char* end = UPB_PTRADD(ptr, str.size); + char buf[4]; + + jsonenc_putstr(e, "\""); + + while (end - ptr >= 3) { + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; + buf[3] = base64[ptr[2] & 0x3f]; + jsonenc_putbytes(e, buf, 4); + ptr += 3; + } + + switch (end - ptr) { + case 2: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[(ptr[1] & 0xf) << 2]; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + case 1: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4)]; + buf[2] = '='; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { + const char* ptr = str.data; + const char* end = UPB_PTRADD(ptr, str.size); + + while (ptr < end) { + switch (*ptr) { + case '\n': + jsonenc_putstr(e, "\\n"); + break; + case '\r': + jsonenc_putstr(e, "\\r"); + break; + case '\t': + jsonenc_putstr(e, "\\t"); + break; + case '\"': + jsonenc_putstr(e, "\\\""); + break; + case '\f': + jsonenc_putstr(e, "\\f"); + break; + case '\b': + jsonenc_putstr(e, "\\b"); + break; + case '\\': + jsonenc_putstr(e, "\\\\"); + break; + default: + if ((uint8_t)*ptr < 0x20) { + jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); + } else { + /* This could be a non-ASCII byte. We rely on the string being valid + * UTF-8. */ + jsonenc_putbytes(e, ptr, 1); + } + break; + } + ptr++; + } +} + +static void jsonenc_string(jsonenc* e, upb_StringView str) { + jsonenc_putstr(e, "\""); + jsonenc_stringbody(e, str); + jsonenc_putstr(e, "\""); +} + +static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { + if (val == INFINITY) { + jsonenc_putstr(e, "\"Infinity\""); + } else if (val == -INFINITY) { + jsonenc_putstr(e, "\"-Infinity\""); + } else if (val != val) { + jsonenc_putstr(e, "\"NaN\""); + } else { + return false; + } + return true; +} + +static void upb_JsonEncode_Double(jsonenc* e, double val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void upb_JsonEncode_Float(jsonenc* e, float val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = upb_Message_Get(msg, val_f); + jsonenc_scalar(e, val, val_f); +} + +static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, + upb_StringView type_url) { + /* Find last '/', if any. */ + const char* end = type_url.data + type_url.size; + const char* ptr = end; + const upb_MessageDef* ret; + + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + } + + if (type_url.size == 0) goto badurl; + + while (true) { + if (--ptr == type_url.data) { + /* Type URL must contain at least one '/', with host before. */ + goto badurl; + } + if (*ptr == '/') { + ptr++; + break; + } + } + + ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); + + if (!ret) { + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + } + + return ret; + +badurl: + jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(type_url)); +} + +static void jsonenc_any(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; + upb_StringView value = upb_Message_Get(msg, value_f).str_val; + const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + upb_Arena* arena = jsonenc_arena(e); + upb_Message* any = upb_Message_New(any_m, arena); + + if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + jsonenc_err(e, "Error decoding message in Any"); + } + + jsonenc_putstr(e, "{\"@type\":"); + jsonenc_string(e, type_url); + + if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { + /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ + jsonenc_msgfields(e, any, any_m, false); + } else { + /* Well-known type: {"@type": "...","value": } */ + jsonenc_putstr(e, ",\"value\":"); + jsonenc_msgfield(e, any, any_m); + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { + if (*first) { + *first = false; + } else { + jsonenc_putstr(e, str); + } +} + +static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { + const char* ptr = path.data; + const char* end = ptr + path.size; + + while (ptr < end) { + char ch = *ptr; + + if (ch >= 'A' && ch <= 'Z') { + jsonenc_err(e, "Field mask element may not have upper-case letter."); + } else if (ch == '_') { + if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { + jsonenc_err(e, "Underscore must be followed by a lowercase letter."); + } + ch = *++ptr - 32; + } + + jsonenc_putbytes(e, &ch, 1); + ptr++; + } +} + +static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; + bool first = true; + size_t i, n = 0; + + if (paths) n = upb_Array_Size(paths); + + jsonenc_putstr(e, "\""); + + for (i = 0; i < n; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_struct(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; + + jsonenc_putstr(e, "{"); + + if (fields) { + while (upb_MapIterator_Next(fields, &iter)) { + upb_MessageValue key = upb_MapIterator_Key(fields, iter); + upb_MessageValue val = upb_MapIterator_Value(fields, iter); + + jsonenc_putsep(e, ",", &first); + jsonenc_string(e, key.str_val); + jsonenc_putstr(e, ":"); + jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); + const upb_Array* values = upb_Message_Get(msg, values_f).array_val; + size_t i; + bool first = true; + + jsonenc_putstr(e, "["); + + if (values) { + const size_t size = upb_Array_Size(values); + for (i = 0; i < size; i++) { + upb_MessageValue elem = upb_Array_Get(values, i); + + jsonenc_putsep(e, ",", &first); + jsonenc_value(e, elem.msg_val, values_m); + } + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + /* TODO(haberman): do we want a reflection method to get oneof case? */ + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + + if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { + jsonenc_err(e, "No value set in Value proto"); + } + + switch (upb_FieldDef_Number(f)) { + case 1: + jsonenc_putstr(e, "null"); + break; + case 2: + upb_JsonEncode_Double(e, val.double_val); + break; + case 3: + jsonenc_string(e, val.str_val); + break; + case 4: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case 5: + jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + case 6: + jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Unspecified: + jsonenc_msg(e, msg, m); + break; + case kUpb_WellKnown_Any: + jsonenc_any(e, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsonenc_fieldmask(e, msg, m); + break; + case kUpb_WellKnown_Duration: + jsonenc_duration(e, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsonenc_timestamp(e, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsonenc_wrapper(e, msg, m); + break; + case kUpb_WellKnown_Value: + jsonenc_value(e, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsonenc_listvalue(e, msg, m); + break; + case kUpb_WellKnown_Struct: + jsonenc_struct(e, msg, m); + break; + } +} + +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Float: + upb_JsonEncode_Float(e, val.float_val); + break; + case kUpb_CType_Double: + upb_JsonEncode_Double(e, val.double_val); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_string(e, val.str_val); + break; + case kUpb_CType_Bytes: + jsonenc_bytes(e, val.str_val); + break; + case kUpb_CType_Enum: + jsonenc_enum(val.int32_val, f, e); + break; + case kUpb_CType_Message: + jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + jsonenc_putstr(e, "\""); + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "%" PRId64, val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "%" PRIu64, val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_stringbody(e, val.str_val); + break; + default: + UPB_UNREACHABLE(); + } + + jsonenc_putstr(e, "\":"); +} + +static void jsonenc_array(jsonenc* e, const upb_Array* arr, + const upb_FieldDef* f) { + size_t i; + size_t size = arr ? upb_Array_Size(arr) : 0; + bool first = true; + + jsonenc_putstr(e, "["); + + for (i = 0; i < size; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_scalar(e, upb_Array_Get(arr, i), f); + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; + + jsonenc_putstr(e, "{"); + + if (map) { + while (upb_MapIterator_Next(map, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); + jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, + upb_MessageValue val, bool* first) { + const char* name; + + jsonenc_putsep(e, ",", first); + + if (upb_FieldDef_IsExtension(f)) { + // TODO: For MessageSet, I would have expected this to print the message + // name here, but Python doesn't appear to do this. We should do more + // research here about what various implementations do. + jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); + } else { + if (e->options & upb_JsonEncode_UseProtoNames) { + name = upb_FieldDef_Name(f); + } else { + name = upb_FieldDef_JsonName(f); + } + jsonenc_printf(e, "\"%s\":", name); + } + + if (upb_FieldDef_IsMap(f)) { + jsonenc_map(e, val.map_val, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsonenc_array(e, val.array_val, f); + } else { + jsonenc_scalar(e, val, f); + } +} + +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first) { + upb_MessageValue val; + const upb_FieldDef* f; + + if (e->options & upb_JsonEncode_EmitDefaults) { + /* Iterate over all fields. */ + int i = 0; + int n = upb_MessageDef_FieldCount(m); + for (i = 0; i < n; i++) { + f = upb_MessageDef_Field(m, i); + if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { + jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first); + } + } + } else { + /* Iterate over non-empty fields. */ + size_t iter = kUpb_Message_Begin; + while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { + jsonenc_fieldval(e, f, val, &first); + } + } +} + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); + jsonenc_msgfields(e, msg, m, true); + jsonenc_putstr(e, "}"); +} + +static size_t jsonenc_nullz(jsonenc* e, size_t size) { + size_t ret = e->ptr - e->buf + e->overflow; + + if (size > 0) { + if (e->ptr == e->end) e->ptr--; + *e->ptr = '\0'; + } + + return ret; +} + +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status) { + jsonenc e; + + e.buf = buf; + e.ptr = buf; + e.end = UPB_PTRADD(buf, size); + e.overflow = 0; + e.options = options; + e.ext_pool = ext_pool; + e.status = status; + e.arena = NULL; + + if (setjmp(e.err)) return -1; + + jsonenc_msgfield(&e, msg, m); + if (e.arena) upb_Arena_Free(e.arena); + return jsonenc_nullz(&e, size); +} + +/** upb/mini_table.c ************************************************************/ + +#include +#include + + +// Must be last. + +typedef enum { + kUpb_EncodedType_Double = 0, + kUpb_EncodedType_Float = 1, + kUpb_EncodedType_Fixed32 = 2, + kUpb_EncodedType_Fixed64 = 3, + kUpb_EncodedType_SFixed32 = 4, + kUpb_EncodedType_SFixed64 = 5, + kUpb_EncodedType_Int32 = 6, + kUpb_EncodedType_UInt32 = 7, + kUpb_EncodedType_SInt32 = 8, + kUpb_EncodedType_Int64 = 9, + kUpb_EncodedType_UInt64 = 10, + kUpb_EncodedType_SInt64 = 11, + kUpb_EncodedType_Enum = 12, + kUpb_EncodedType_Bool = 13, + kUpb_EncodedType_Bytes = 14, + kUpb_EncodedType_String = 15, + kUpb_EncodedType_Group = 16, + kUpb_EncodedType_Message = 17, + + kUpb_EncodedType_RepeatedBase = 20, +} upb_EncodedType; + +typedef enum { + kUpb_EncodedFieldModifier_FlipPacked = 1 << 0, + kUpb_EncodedFieldModifier_IsClosedEnum = 1 << 1, + // upb only. + kUpb_EncodedFieldModifier_IsProto3Singular = 1 << 2, + kUpb_EncodedFieldModifier_IsRequired = 1 << 3, +} upb_EncodedFieldModifier; + +enum { + kUpb_EncodedValue_MinField = ' ', + kUpb_EncodedValue_MaxField = 'K', + kUpb_EncodedValue_MinModifier = 'L', + kUpb_EncodedValue_MaxModifier = '[', + kUpb_EncodedValue_End = '^', + kUpb_EncodedValue_MinSkip = '_', + kUpb_EncodedValue_MaxSkip = '~', + kUpb_EncodedValue_OneofSeparator = '~', + kUpb_EncodedValue_FieldSeparator = '|', + kUpb_EncodedValue_MinOneofField = ' ', + kUpb_EncodedValue_MaxOneofField = 'b', + kUpb_EncodedValue_MaxEnumMask = 'A', +}; + +char upb_ToBase92(int8_t ch) { + static const char kUpb_ToBase92[] = { + ' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', + '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '[', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '{', '|', '}', '~', + }; + + UPB_ASSERT(0 <= ch && ch < 92); + return kUpb_ToBase92[ch]; +} + +char upb_FromBase92(uint8_t ch) { + static const int8_t kUpb_FromBase92[] = { + 0, 1, -1, 2, 3, 4, 5, -1, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + }; + + if (' ' > ch || ch > '~') return -1; + return kUpb_FromBase92[ch - ' ']; +} + +bool upb_IsTypePackable(upb_FieldType type) { + // clang-format off + static const unsigned kUnpackableTypes = + (1 << kUpb_FieldType_String) | + (1 << kUpb_FieldType_Bytes) | + (1 << kUpb_FieldType_Message) | + (1 << kUpb_FieldType_Group); + // clang-format on + return (1 << type) & ~kUnpackableTypes; +} + +/** upb_MtDataEncoder *********************************************************/ + +typedef struct { + uint64_t present_values_mask; + uint32_t last_written_value; +} upb_MtDataEncoderInternal_EnumState; + +typedef struct { + uint64_t msg_modifiers; + uint32_t last_field_num; + enum { + kUpb_OneofState_NotStarted, + kUpb_OneofState_StartedOneof, + kUpb_OneofState_EmittedOneofField, + } oneof_state; +} upb_MtDataEncoderInternal_MsgState; + +typedef struct { + char* buf_start; // Only for checking kUpb_MtDataEncoder_MinSize. + union { + upb_MtDataEncoderInternal_EnumState enum_state; + upb_MtDataEncoderInternal_MsgState msg_state; + } state; +} upb_MtDataEncoderInternal; + +static upb_MtDataEncoderInternal* upb_MtDataEncoder_GetInternal( + upb_MtDataEncoder* e, char* buf_start) { + UPB_ASSERT(sizeof(upb_MtDataEncoderInternal) <= sizeof(e->internal)); + upb_MtDataEncoderInternal* ret = (upb_MtDataEncoderInternal*)e->internal; + ret->buf_start = buf_start; + return ret; +} + +static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + UPB_ASSERT(ptr - in->buf_start < kUpb_MtDataEncoder_MinSize); + if (ptr == e->end) return NULL; + *ptr++ = upb_ToBase92(ch); + return ptr; +} + +static char* upb_MtDataEncoder_PutBase92Varint(upb_MtDataEncoder* e, char* ptr, + uint32_t val, int min, int max) { + int shift = _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min) + 1); + UPB_ASSERT(shift <= 6); + uint32_t mask = (1 << shift) - 1; + do { + uint32_t bits = val & mask; + ptr = upb_MtDataEncoder_Put(e, ptr, bits + upb_FromBase92(min)); + if (!ptr) return NULL; + val >>= shift; + } while (val); + return ptr; +} + +char* upb_MtDataEncoder_PutModifier(upb_MtDataEncoder* e, char* ptr, + uint64_t mod) { + if (mod) { + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, mod, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier); + } + return ptr; +} + +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = msg_mod; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); +} + +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + static const char kUpb_TypeToEncoded[] = { + [kUpb_FieldType_Double] = kUpb_EncodedType_Double, + [kUpb_FieldType_Float] = kUpb_EncodedType_Float, + [kUpb_FieldType_Int64] = kUpb_EncodedType_Int64, + [kUpb_FieldType_UInt64] = kUpb_EncodedType_UInt64, + [kUpb_FieldType_Int32] = kUpb_EncodedType_Int32, + [kUpb_FieldType_Fixed64] = kUpb_EncodedType_Fixed64, + [kUpb_FieldType_Fixed32] = kUpb_EncodedType_Fixed32, + [kUpb_FieldType_Bool] = kUpb_EncodedType_Bool, + [kUpb_FieldType_String] = kUpb_EncodedType_String, + [kUpb_FieldType_Group] = kUpb_EncodedType_Group, + [kUpb_FieldType_Message] = kUpb_EncodedType_Message, + [kUpb_FieldType_Bytes] = kUpb_EncodedType_Bytes, + [kUpb_FieldType_UInt32] = kUpb_EncodedType_UInt32, + [kUpb_FieldType_Enum] = kUpb_EncodedType_Enum, + [kUpb_FieldType_SFixed32] = kUpb_EncodedType_SFixed32, + [kUpb_FieldType_SFixed64] = kUpb_EncodedType_SFixed64, + [kUpb_FieldType_SInt32] = kUpb_EncodedType_SInt32, + [kUpb_FieldType_SInt64] = kUpb_EncodedType_SInt64, + }; + + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (field_num <= in->state.msg_state.last_field_num) return NULL; + if (in->state.msg_state.last_field_num + 1 != field_num) { + // Put skip. + UPB_ASSERT(field_num > in->state.msg_state.last_field_num); + uint32_t skip = field_num - in->state.msg_state.last_field_num; + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, skip, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + if (!ptr) return NULL; + } + in->state.msg_state.last_field_num = field_num; + + uint32_t encoded_modifiers = 0; + + // Put field type. + if (type == kUpb_FieldType_Enum && + !(field_mod & kUpb_FieldModifier_IsClosedEnum)) { + type = kUpb_FieldType_Int32; + } + + int encoded_type = kUpb_TypeToEncoded[type]; + if (field_mod & kUpb_FieldModifier_IsRepeated) { + // Repeated fields shift the type number up (unlike other modifiers which + // are bit flags). + encoded_type += kUpb_EncodedType_RepeatedBase; + + if (upb_IsTypePackable(type)) { + bool field_is_packed = field_mod & kUpb_FieldModifier_IsPacked; + bool default_is_packed = in->state.msg_state.msg_modifiers & + kUpb_MessageModifier_DefaultIsPacked; + if (field_is_packed != default_is_packed) { + encoded_modifiers |= kUpb_EncodedFieldModifier_FlipPacked; + } + } + } + ptr = upb_MtDataEncoder_Put(e, ptr, encoded_type); + if (!ptr) return NULL; + + if (field_mod & kUpb_FieldModifier_IsProto3Singular) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; + } + if (field_mod & kUpb_FieldModifier_IsRequired) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; + } + return upb_MtDataEncoder_PutModifier(e, ptr, encoded_modifiers); +} + +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_NotStarted) { + ptr = upb_MtDataEncoder_Put(e, ptr, upb_FromBase92(kUpb_EncodedValue_End)); + } else { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); + } + in->state.msg_state.oneof_state = kUpb_OneofState_StartedOneof; + return ptr; +} + +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_EmittedOneofField) { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_FieldSeparator)); + if (!ptr) return NULL; + } + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, field_num, upb_ToBase92(0), + upb_ToBase92(63)); + in->state.msg_state.oneof_state = kUpb_OneofState_EmittedOneofField; + return ptr; +} + +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, NULL); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value = 0; +} + +static char* upb_MtDataEncoder_FlushDenseEnumMask(upb_MtDataEncoder* e, + char* ptr) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + ptr = upb_MtDataEncoder_Put(e, ptr, in->state.enum_state.present_values_mask); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value += 5; + return ptr; +} + +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val) { + // TODO(b/229641772): optimize this encoding. + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + UPB_ASSERT(val >= in->state.enum_state.last_written_value); + uint32_t delta = val - in->state.enum_state.last_written_value; + if (delta >= 5 && in->state.enum_state.present_values_mask) { + ptr = upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); + delta -= 5; + } + + if (delta >= 5) { + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, delta, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + in->state.enum_state.last_written_value += delta; + delta = 0; + } + + UPB_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); + in->state.enum_state.present_values_mask |= 1ULL << delta; + return ptr; +} + +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (!in->state.enum_state.present_values_mask) return ptr; + return upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); +} + +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number) { + int n = table->field_count; + for (int i = 0; i < n; i++) { + if (table->fields[i].number == number) { + return &table->fields[i]; + } + } + return NULL; +} + +/** Data decoder **************************************************************/ + +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_LayoutItemType_OneofCase, // Oneof case. + kUpb_LayoutItemType_OneofField, // Oneof field data. + kUpb_LayoutItemType_Field, // Non-oneof field data. + + kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, +} upb_LayoutItemType; + +#define kUpb_LayoutItem_IndexSentinel ((uint16_t)-1) + +typedef struct { + // Index of the corresponding field. When this is a oneof field, the field's + // offset will be the index of the next field in a linked list. + uint16_t field_index; + uint16_t offset; + upb_FieldRep rep; + upb_LayoutItemType type; +} upb_LayoutItem; + +typedef struct { + upb_LayoutItem* data; + size_t size; + size_t capacity; +} upb_LayoutItemVector; + +typedef struct { + const char* end; + upb_MiniTable* table; + upb_MiniTable_Field* fields; + upb_MiniTablePlatform platform; + upb_LayoutItemVector vec; + upb_Arena* arena; + upb_Status* status; + jmp_buf err; +} upb_MtDecoder; + +UPB_PRINTF(2, 3) +UPB_NORETURN static void upb_MtDecoder_ErrorFormat(upb_MtDecoder* d, + const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorMessage(d->status, "Error building mini table: "); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); +} + +static void upb_MtDecoder_CheckOutOfMemory(upb_MtDecoder* d, const void* ptr) { + if (!ptr) upb_MtDecoder_ErrorFormat(d, "Out of memory"); +} + +// In each field's offset, we temporarily store a presence classifier: +enum PresenceClass { + kNoPresence = 0, + kHasbitPresence = 1, + kRequiredPresence = 2, + kOneofBase = 3, + // Negative values refer to a specific oneof with that number. Positive + // values >= kOneofBase indicate that this field is in a oneof, and specify + // the next field in this oneof's linked list. +}; + +static const char* upb_MiniTable_DecodeBase92Varint(upb_MtDecoder* d, + const char* ptr, + char first_ch, uint8_t min, + uint8_t max, + uint32_t* out_val) { + uint32_t val = 0; + uint32_t shift = 0; + const int bits_per_char = + _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min)); + char ch = first_ch; + while (1) { + uint32_t bits = upb_FromBase92(ch) - upb_FromBase92(min); + UPB_ASSERT(shift < 32); + val |= bits << shift; + if (ptr == d->end || *ptr < min || max < *ptr) { + *out_val = val; + return ptr; + } + ch = *ptr++; + shift += bits_per_char; + } +} + +static bool upb_MiniTable_HasSub(upb_MiniTable_Field* field, + uint64_t msg_modifiers) { + switch (field->descriptortype) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + return true; + case kUpb_FieldType_String: + if (!(msg_modifiers & kUpb_MessageModifier_ValidateUtf8)) { + field->descriptortype = kUpb_FieldType_Bytes; + } + return false; + default: + return false; + } +} + +static bool upb_MtDecoder_FieldIsPackable(upb_MiniTable_Field* field) { + return (field->mode & kUpb_FieldMode_Array) && + upb_IsTypePackable(field->descriptortype); +} + +static void upb_MiniTable_SetTypeAndSub(upb_MiniTable_Field* field, + upb_FieldType type, uint32_t* sub_count, + uint64_t msg_modifiers) { + field->descriptortype = type; + if (upb_MiniTable_HasSub(field, msg_modifiers)) { + field->submsg_index = sub_count ? (*sub_count)++ : 0; + } else { + field->submsg_index = kUpb_NoSub; + } + + if (upb_MtDecoder_FieldIsPackable(field) && + (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { + field->mode |= kUpb_LabelFlags_IsPacked; + } +} + +static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, + upb_MiniTable_Field* field, + uint64_t msg_modifiers, + uint32_t* sub_count) { + static const char kUpb_EncodedToFieldRep[] = { + [kUpb_EncodedType_Double] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Float] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Int64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_UInt64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Int32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Fixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Fixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Bool] = kUpb_FieldRep_1Byte, + [kUpb_EncodedType_String] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_Group] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Message] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Bytes] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Enum] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_SInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SInt64] = kUpb_FieldRep_8Byte, + }; + + static const char kUpb_EncodedToType[] = { + [kUpb_EncodedType_Double] = kUpb_FieldType_Double, + [kUpb_EncodedType_Float] = kUpb_FieldType_Float, + [kUpb_EncodedType_Int64] = kUpb_FieldType_Int64, + [kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64, + [kUpb_EncodedType_Int32] = kUpb_FieldType_Int32, + [kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64, + [kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32, + [kUpb_EncodedType_Bool] = kUpb_FieldType_Bool, + [kUpb_EncodedType_String] = kUpb_FieldType_String, + [kUpb_EncodedType_Group] = kUpb_FieldType_Group, + [kUpb_EncodedType_Message] = kUpb_FieldType_Message, + [kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes, + [kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32, + [kUpb_EncodedType_Enum] = kUpb_FieldType_Enum, + [kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32, + [kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64, + [kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32, + [kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64, + }; + + int8_t type = upb_FromBase92(ch); + if (ch >= upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { + type -= kUpb_EncodedType_RepeatedBase; + field->mode = kUpb_FieldMode_Array; + field->mode |= kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift; + field->offset = kNoPresence; + } else { + field->mode = kUpb_FieldMode_Scalar; + field->mode |= kUpb_EncodedToFieldRep[type] << kUpb_FieldRep_Shift; + field->offset = kHasbitPresence; + } + if (type >= 18) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); + } + upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_count, + msg_modifiers); +} + +static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, + uint32_t message_modifiers, + uint32_t field_modifiers, + upb_MiniTable_Field* field) { + if (field_modifiers & kUpb_EncodedFieldModifier_FlipPacked) { + if (!upb_MtDecoder_FieldIsPackable(field)) { + upb_MtDecoder_ErrorFormat( + d, "Cannot flip packed on unpackable field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + field->mode ^= kUpb_LabelFlags_IsPacked; + } + + bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; + bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; + + // Validate. + if ((singular || required) && field->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, "Invalid modifier(s) for repeated field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + if (singular && required) { + upb_MtDecoder_ErrorFormat( + d, "Field %" PRIu32 " cannot be both singular and required", + field->number); + UPB_UNREACHABLE(); + } + + if (singular) field->offset = kNoPresence; + if (required) { + field->offset = kRequiredPresence; + } +} + +static void upb_MtDecoder_PushItem(upb_MtDecoder* d, upb_LayoutItem item) { + if (d->vec.size == d->vec.capacity) { + size_t new_cap = UPB_MAX(8, d->vec.size * 2); + d->vec.data = realloc(d->vec.data, new_cap * sizeof(*d->vec.data)); + upb_MtDecoder_CheckOutOfMemory(d, d->vec.data); + d->vec.capacity = new_cap; + } + d->vec.data[d->vec.size++] = item; +} + +static void upb_MtDecoder_PushOneof(upb_MtDecoder* d, upb_LayoutItem item) { + if (item.field_index == kUpb_LayoutItem_IndexSentinel) { + upb_MtDecoder_ErrorFormat(d, "Empty oneof"); + UPB_UNREACHABLE(); + } + item.field_index -= kOneofBase; + + // Push oneof data. + item.type = kUpb_LayoutItemType_OneofField; + upb_MtDecoder_PushItem(d, item); + + // Push oneof case. + item.rep = kUpb_FieldRep_4Byte; // Field Number. + item.type = kUpb_LayoutItemType_OneofCase; + upb_MtDecoder_PushItem(d, item); +} + +size_t upb_MtDecoder_SizeOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToSize32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToSize64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 16, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(sizeof(upb_StringView) == + UPB_SIZE(kRepToSize32, kRepToSize64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToSize32[rep] + : kRepToSize64[rep]; +} + +size_t upb_MtDecoder_AlignOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToAlign32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 4, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToAlign64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(UPB_ALIGN_OF(upb_StringView) == + UPB_SIZE(kRepToAlign32, kRepToAlign64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToAlign32[rep] + : kRepToAlign64[rep]; +} + +static const char* upb_MtDecoder_DecodeOneofField(upb_MtDecoder* d, + const char* ptr, + char first_ch, + upb_LayoutItem* item) { + uint32_t field_num; + ptr = upb_MiniTable_DecodeBase92Varint( + d, ptr, first_ch, kUpb_EncodedValue_MinOneofField, + kUpb_EncodedValue_MaxOneofField, &field_num); + upb_MiniTable_Field* f = + (void*)upb_MiniTable_FindFieldByNumber(d->table, field_num); + + if (!f) { + upb_MtDecoder_ErrorFormat(d, + "Couldn't add field number %" PRIu32 + " to oneof, no such field number.", + field_num); + UPB_UNREACHABLE(); + } + if (f->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, + "Cannot add repeated, required, or singular field %" PRIu32 + " to oneof.", + field_num); + UPB_UNREACHABLE(); + } + + // Oneof storage must be large enough to accommodate the largest member. + int rep = f->mode >> kUpb_FieldRep_Shift; + if (upb_MtDecoder_SizeOfRep(rep, d->platform) > + upb_MtDecoder_SizeOfRep(item->rep, d->platform)) { + item->rep = rep; + } + // Prepend this field to the linked list. + f->offset = item->field_index; + item->field_index = (f - d->fields) + kOneofBase; + return ptr; +} + +static const char* upb_MtDecoder_DecodeOneofs(upb_MtDecoder* d, + const char* ptr) { + upb_LayoutItem item = {.rep = 0, + .field_index = kUpb_LayoutItem_IndexSentinel}; + while (ptr < d->end) { + char ch = *ptr++; + if (ch == kUpb_EncodedValue_FieldSeparator) { + // Field separator, no action needed. + } else if (ch == kUpb_EncodedValue_OneofSeparator) { + // End of oneof. + upb_MtDecoder_PushOneof(d, item); + item.field_index = kUpb_LayoutItem_IndexSentinel; // Move to next oneof. + } else { + ptr = upb_MtDecoder_DecodeOneofField(d, ptr, ch, &item); + } + } + + // Push final oneof. + upb_MtDecoder_PushOneof(d, item); + return ptr; +} + +static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, + const char* ptr, char first_ch, + upb_MiniTable_Field* last_field, + uint64_t* msg_modifiers) { + uint32_t mod; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, first_ch, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier, &mod); + if (last_field) { + upb_MtDecoder_ModifyField(d, *msg_modifiers, mod, last_field); + } else { + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have message modifiers"); + UPB_UNREACHABLE(); + } + *msg_modifiers = mod; + } + + return ptr; +} + +static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, uint32_t sub_count) { + size_t subs_bytes = sizeof(*d->table->subs) * sub_count; + d->table->subs = upb_Arena_Malloc(d->arena, subs_bytes); + upb_MtDecoder_CheckOutOfMemory(d, d->table->subs); +} + +static void upb_MtDecoder_Parse(upb_MtDecoder* d, const char* ptr, size_t len, + void* fields, size_t field_size, + uint16_t* field_count, uint32_t* sub_count) { + uint64_t msg_modifiers = 0; + uint32_t last_field_number = 0; + upb_MiniTable_Field* last_field = NULL; + bool need_dense_below = d->table != NULL; + + d->end = UPB_PTRADD(ptr, len); + + while (ptr < d->end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxField) { + upb_MiniTable_Field* field = fields; + *field_count += 1; + fields = (char*)fields + field_size; + field->number = ++last_field_number; + last_field = field; + upb_MiniTable_SetField(d, ch, field, msg_modifiers, sub_count); + } else if (kUpb_EncodedValue_MinModifier <= ch && + ch <= kUpb_EncodedValue_MaxModifier) { + ptr = upb_MtDecoder_ParseModifier(d, ptr, ch, last_field, &msg_modifiers); + if (msg_modifiers & kUpb_MessageModifier_IsExtendable) { + d->table->ext |= kUpb_ExtMode_Extendable; + } + } else if (ch == kUpb_EncodedValue_End) { + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have oneofs."); + UPB_UNREACHABLE(); + } + ptr = upb_MtDecoder_DecodeOneofs(d, ptr); + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + need_dense_below = false; + } + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + last_field_number += skip; + last_field_number--; // Next field seen will increment. + } + } + + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + } +} + +static void upb_MtDecoder_ParseMessage(upb_MtDecoder* d, const char* data, + size_t len) { + // Buffer length is an upper bound on the number of fields. We will return + // what we don't use. + d->fields = upb_Arena_Malloc(d->arena, sizeof(*d->fields) * len); + upb_MtDecoder_CheckOutOfMemory(d, d->fields); + + uint32_t sub_count = 0; + d->table->field_count = 0; + d->table->fields = d->fields; + upb_MtDecoder_Parse(d, data, len, d->fields, sizeof(*d->fields), + &d->table->field_count, &sub_count); + + upb_Arena_ShrinkLast(d->arena, d->fields, sizeof(*d->fields) * len, + sizeof(*d->fields) * d->table->field_count); + d->table->fields = d->fields; + upb_MtDecoder_AllocateSubs(d, sub_count); +} + +int upb_MtDecoder_CompareFields(const void* _a, const void* _b) { + const upb_LayoutItem* a = _a; + const upb_LayoutItem* b = _b; + // Currently we just sort by: + // 1. rep (smallest fields first) + // 2. type (oneof cases first) + // 2. field_index (smallest numbers first) + // The main goal of this is to reduce space lost to padding. + // Later we may have more subtle reasons to prefer a different ordering. + const int rep_bits = _upb_Log2Ceiling(kUpb_FieldRep_Max); + const int type_bits = _upb_Log2Ceiling(kUpb_LayoutItemType_Max); + const int idx_bits = (sizeof(a->field_index) * 8); + UPB_ASSERT(idx_bits + rep_bits + type_bits < 32); +#define UPB_COMBINE(rep, ty, idx) (((rep << type_bits) | ty) << idx_bits) | idx + uint32_t a_packed = UPB_COMBINE(a->rep, a->type, a->field_index); + uint32_t b_packed = UPB_COMBINE(b->rep, b->type, b->field_index); + assert(a_packed != b_packed); +#undef UPB_COMBINE + return a_packed < b_packed ? -1 : 1; +} + +static bool upb_MtDecoder_SortLayoutItems(upb_MtDecoder* d) { + // Add items for all non-oneof fields (oneofs were already added). + int n = d->table->field_count; + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* f = &d->fields[i]; + if (f->offset >= kOneofBase) continue; + upb_LayoutItem item = {.field_index = i, + .rep = f->mode >> kUpb_FieldRep_Shift, + .type = kUpb_LayoutItemType_Field}; + upb_MtDecoder_PushItem(d, item); + } + + if (d->vec.size) { + qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), + upb_MtDecoder_CompareFields); + } + + return true; +} + +static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { + return (n + d - 1) / d; +} + +static void upb_MtDecoder_AssignHasbits(upb_MiniTable* ret) { + int n = ret->field_count; + int last_hasbit = 0; // 0 cannot be used. + + // First assign required fields, which must have the lowest hasbits. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kRequiredPresence) { + field->presence = ++last_hasbit; + } else if (field->offset == kNoPresence) { + field->presence = 0; + } + } + ret->required_count = last_hasbit; + + // Next assign non-required hasbit fields. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kHasbitPresence) { + field->presence = ++last_hasbit; + } + } + + ret->size = last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; +} + +size_t upb_MtDecoder_Place(upb_MtDecoder* d, upb_FieldRep rep) { + size_t size = upb_MtDecoder_SizeOfRep(rep, d->platform); + size_t align = upb_MtDecoder_AlignOfRep(rep, d->platform); + size_t ret = UPB_ALIGN_UP(d->table->size, align); + d->table->size = ret + size; + return ret; +} + +static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { + upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); + + // Compute offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + item->offset = upb_MtDecoder_Place(d, item->rep); + } + + // Assign oneof case offsets. We must do these first, since assigning + // actual offsets will overwrite the links of the linked list. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + if (item->type != kUpb_LayoutItemType_OneofCase) continue; + upb_MiniTable_Field* f = &d->fields[item->field_index]; + while (true) { + f->presence = ~item->offset; + if (f->offset == kUpb_LayoutItem_IndexSentinel) break; + UPB_ASSERT(f->offset - kOneofBase < d->table->field_count); + f = &d->fields[f->offset - kOneofBase]; + } + } + + // Assign offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + upb_MiniTable_Field* f = &d->fields[item->field_index]; + switch (item->type) { + case kUpb_LayoutItemType_OneofField: + while (true) { + uint16_t next_offset = f->offset; + f->offset = item->offset; + if (next_offset == kUpb_LayoutItem_IndexSentinel) break; + f = &d->fields[next_offset - kOneofBase]; + } + break; + case kUpb_LayoutItemType_Field: + f->offset = item->offset; + break; + default: + break; + } + } + + // The fasttable parser (supported on 64-bit only) depends on this being a + // multiple of 8 in order to satisfy UPB_MALLOC_ALIGN, which is also 8. + // + // On 32-bit we could potentially make this smaller, but there is no + // compelling reason to optimize this right now. + d->table->size = UPB_ALIGN_UP(d->table->size, 8); +} + +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, + upb_Status* status) { + upb_MtDecoder decoder = { + .platform = platform, + .vec = + { + .data = *buf, + .capacity = *buf_size / sizeof(*decoder.vec.data), + .size = 0, + }, + .arena = arena, + .status = status, + .table = upb_Arena_Malloc(arena, sizeof(*decoder.table)), + }; + + if (UPB_SETJMP(decoder.err)) { + decoder.table = NULL; + goto done; + } + + upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table); + + decoder.table->size = 0; + decoder.table->field_count = 0; + decoder.table->ext = kUpb_ExtMode_NonExtendable; + decoder.table->dense_below = 0; + decoder.table->table_mask = -1; + decoder.table->required_count = 0; + + upb_MtDecoder_ParseMessage(&decoder, data, len); + upb_MtDecoder_AssignHasbits(decoder.table); + upb_MtDecoder_SortLayoutItems(&decoder); + upb_MtDecoder_AssignOffsets(&decoder); + +done: + *buf = decoder.vec.data; + *buf_size = decoder.vec.capacity / sizeof(*decoder.vec.data); + return decoder.table; +} + +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + if (!ret) return NULL; + + ret->size = 0; + ret->field_count = 0; + ret->ext = kUpb_ExtMode_IsMessageSet; + ret->dense_below = 0; + ret->table_mask = -1; + ret->required_count = 0; + return ret; +} + +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + upb_MiniTable_Field* fields = upb_Arena_Malloc(arena, sizeof(*fields) * 2); + if (!ret || !fields) return NULL; + + upb_MiniTable_Sub* subs = NULL; + if (value_is_proto3_enum) value_type = kUpb_FieldType_Int32; + if (value_type == kUpb_FieldType_Message || + value_type == kUpb_FieldType_Group || value_type == kUpb_FieldType_Enum) { + subs = upb_Arena_Malloc(arena, sizeof(*subs)); + if (!subs) return NULL; + } + + size_t field_size = + upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, platform); + + fields[0].number = 1; + fields[1].number = 2; + fields[0].mode = kUpb_FieldMode_Scalar; + fields[1].mode = kUpb_FieldMode_Scalar; + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].offset = 0; + fields[1].offset = field_size; + + upb_MiniTable_SetTypeAndSub(&fields[0], key_type, NULL, 0); + upb_MiniTable_SetTypeAndSub(&fields[1], value_type, NULL, 0); + + ret->size = UPB_ALIGN_UP(2 * field_size, 8); + ret->field_count = 2; + ret->ext = kUpb_ExtMode_NonExtendable | kUpb_ExtMode_IsMapEntry; + ret->dense_below = 2; + ret->table_mask = -1; + ret->required_count = 0; + ret->subs = subs; + ret->fields = fields; + return ret; +} + +static bool upb_MiniTable_BuildEnumValue(upb_MtDecoder* d, + upb_MiniTable_Enum* table, + uint32_t val, upb_Arena* arena) { + if (val < 64) { + table->mask |= 1ULL << val; + return true; + } + + int32_t* values = (void*)table->values; + values = upb_Arena_Realloc(arena, values, table->value_count * 4, + (table->value_count + 1) * 4); + upb_MtDecoder_CheckOutOfMemory(d, values); + values[table->value_count++] = (int32_t)val; + table->values = values; + return true; +} + +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + upb_MtDecoder d = { + .status = status, + .end = UPB_PTRADD(data, len), + }; + + if (UPB_SETJMP(d.err)) { + return NULL; + } + + upb_MiniTable_Enum* table = upb_Arena_Malloc(arena, sizeof(*table)); + upb_MtDecoder_CheckOutOfMemory(&d, table); + + table->mask = 0; + table->value_count = 0; + table->values = NULL; + + const char* ptr = data; + uint32_t base = 0; + + while (ptr < d.end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxEnumMask) { + uint32_t mask = upb_FromBase92(ch); + for (int i = 0; i < 5; i++, base++, mask >>= 1) { + if (mask & 1) { + if (!upb_MiniTable_BuildEnumValue(&d, table, base, arena)) { + return NULL; + } + } + } + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(&d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + base += skip; + } else { + upb_Status_SetErrorFormat(status, "Unexpected character: %c", ch); + return NULL; + } + } + + return table; +} + +bool upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + upb_MiniTable_Sub sub, upb_Status* status) { + upb_MtDecoder decoder = { + .arena = NULL, + .status = status, + .table = NULL, + }; + + if (UPB_SETJMP(decoder.err)) { + return false; + } + + uint16_t count = 0; + upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); + ext->field.mode |= kUpb_LabelFlags_IsExtension; + ext->field.offset = 0; + return true; +} + +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status) { + void* buf = NULL; + size_t size = 0; + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf(data, len, platform, arena, + &buf, &size, status); + free(buf); + return ret; +} + +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + if (sub->ext & kUpb_ExtMode_IsMapEntry) { + field->mode = + (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift) | kUpb_FieldMode_Map; + } + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->submsg = sub; +} + +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->subenum = sub; +} + +/** upb/def.c ************************************************************/ + +#include +#include +#include +#include +#include + + +/* Must be last. */ + +typedef struct { + size_t len; + char str[1]; /* Null-terminated string data follows. */ +} str_t; + +/* The upb core does not generally have a concept of default instances. However + * for descriptor options we make an exception since the max size is known and + * modest (<200 bytes). All types can share a default instance since it is + * initialized to zeroes. + * + * We have to allocate an extra pointer for upb's internal metadata. */ +static const char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; +static const char* opt_default = &opt_default_buf[sizeof(void*)]; + +struct upb_FieldDef { + const google_protobuf_FieldOptions* opts; + const upb_FileDef* file; + const upb_MessageDef* msgdef; + const char* full_name; + const char* json_name; + union { + int64_t sint; + uint64_t uint; + double dbl; + float flt; + bool boolean; + str_t* str; + } defaultval; + union { + const upb_OneofDef* oneof; + const upb_MessageDef* extension_scope; + } scope; + union { + const upb_MessageDef* msgdef; + const upb_EnumDef* enumdef; + const google_protobuf_FieldDescriptorProto* unresolved; + } sub; + uint32_t number_; + uint16_t index_; + uint16_t layout_index; /* Index into msgdef->layout->fields or file->exts */ + bool has_default; + bool is_extension_; + bool packed_; + bool proto3_optional_; + bool has_json_name_; + upb_FieldType type_; + upb_Label label_; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +struct upb_ExtensionRange { + const google_protobuf_ExtensionRangeOptions* opts; + int32_t start; + int32_t end; +}; + +struct upb_MessageDef { + const google_protobuf_MessageOptions* opts; + const upb_MiniTable* layout; + const upb_FileDef* file; + const upb_MessageDef* containing_type; + const char* full_name; + + /* Tables for looking up fields by number and name. */ + upb_inttable itof; + upb_strtable ntof; + + /* All nested defs. + * MEM: We could save some space here by putting nested defs in a contiguous + * region and calculating counts from offsets or vice-versa. */ + const upb_FieldDef* fields; + const upb_OneofDef* oneofs; + const upb_ExtensionRange* ext_ranges; + const upb_StringView* res_names; + const upb_MessageDef* nested_msgs; + const upb_MessageReservedRange* res_ranges; + const upb_EnumDef* nested_enums; + const upb_FieldDef* nested_exts; + int field_count; + int real_oneof_count; + int oneof_count; + int ext_range_count; + int res_range_count; + int res_name_count; + int nested_msg_count; + int nested_enum_count; + int nested_ext_count; + bool in_message_set; + upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +struct upb_EnumDef { + const google_protobuf_EnumOptions* opts; + const upb_MiniTable_Enum* layout; // Only for proto2. + const upb_FileDef* file; + const upb_MessageDef* containing_type; // Could be merged with "file". + const char* full_name; + upb_strtable ntoi; + upb_inttable iton; + const upb_EnumValueDef* values; + const upb_EnumReservedRange* res_ranges; + const upb_StringView* res_names; + int value_count; + int res_range_count; + int res_name_count; + int32_t defaultval; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +struct upb_EnumValueDef { + const google_protobuf_EnumValueOptions* opts; + const upb_EnumDef* parent; + const char* full_name; + int32_t number; +}; + +struct upb_OneofDef { + const google_protobuf_OneofOptions* opts; + const upb_MessageDef* parent; + const char* full_name; + int field_count; + bool synthetic; + const upb_FieldDef** fields; + upb_strtable ntof; + upb_inttable itof; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +struct upb_FileDef { + const google_protobuf_FileOptions* opts; + const char* name; + const char* package; + + const upb_FileDef** deps; + const int32_t* public_deps; + const int32_t* weak_deps; + const upb_MessageDef* top_lvl_msgs; + const upb_EnumDef* top_lvl_enums; + const upb_FieldDef* top_lvl_exts; + const upb_ServiceDef* services; + const upb_MiniTable_Extension** ext_layouts; + const upb_DefPool* symtab; + + int dep_count; + int public_dep_count; + int weak_dep_count; + int top_lvl_msg_count; + int top_lvl_enum_count; + int top_lvl_ext_count; + int service_count; + int ext_count; /* All exts in the file. */ + upb_Syntax syntax; +}; + +struct upb_MethodDef { + const google_protobuf_MethodOptions* opts; + upb_ServiceDef* service; + const char* full_name; + const upb_MessageDef* input_type; + const upb_MessageDef* output_type; + int index; + bool client_streaming; + bool server_streaming; +}; + +struct upb_ServiceDef { + const google_protobuf_ServiceOptions* opts; + const upb_FileDef* file; + const char* full_name; + upb_MethodDef* methods; + int method_count; + int index; +}; + +struct upb_DefPool { + upb_Arena* arena; + upb_strtable syms; /* full_name -> packed def ptr */ + upb_strtable files; /* file_name -> upb_FileDef* */ + upb_inttable exts; /* upb_MiniTable_Extension* -> upb_FieldDef* */ + upb_ExtensionRegistry* extreg; + size_t bytes_loaded; +}; + +/* Inside a symtab we store tagged pointers to specific def types. */ +typedef enum { + UPB_DEFTYPE_MASK = 7, + + /* Only inside symtab table. */ + UPB_DEFTYPE_EXT = 0, + UPB_DEFTYPE_MSG = 1, + UPB_DEFTYPE_ENUM = 2, + UPB_DEFTYPE_ENUMVAL = 3, + UPB_DEFTYPE_SERVICE = 4, + + /* Only inside message table. */ + UPB_DEFTYPE_FIELD = 0, + UPB_DEFTYPE_ONEOF = 1, + UPB_DEFTYPE_FIELD_JSONNAME = 2, + + /* Only inside file table. */ + UPB_DEFTYPE_FILE = 0, + UPB_DEFTYPE_LAYOUT = 1 +} upb_deftype_t; + +#define FIELD_TYPE_UNSPECIFIED 0 + +struct upb_MessageReservedRange { + int32_t start; + int32_t end; +}; + +struct symtab_addctx { + upb_DefPool* symtab; + upb_FileDef* file; /* File we are building. */ + upb_Arena* arena; /* Allocate defs here. */ + upb_Arena* tmp_arena; /* For temporary allocations. */ + const upb_MiniTable_File* layout; /* NULL if we should build layouts. */ + int enum_count; /* Count of enums built so far. */ + int msg_count; /* Count of messages built so far. */ + int ext_count; /* Count of extensions built so far. */ + upb_Status* status; /* Record errors here. */ + jmp_buf err; /* longjmp() on error. */ +}; + +static upb_deftype_t deftype(upb_value v) { + uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return num & UPB_DEFTYPE_MASK; +} + +static const void* unpack_def(upb_value v, upb_deftype_t type) { + uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return (num & UPB_DEFTYPE_MASK) == type + ? (const void*)(num & ~UPB_DEFTYPE_MASK) + : NULL; +} + +static upb_value pack_def(const void* ptr, upb_deftype_t type) { + // Our 3-bit pointer tagging requires all pointers to be multiples of 8. + // The arena will always yield 8-byte-aligned addresses, however we put + // the defs into arrays. For each element in the array to be 8-byte-aligned, + // the sizes of each def type must also be a multiple of 8. + // + // If any of these asserts fail, we need to add or remove padding on 32-bit + // machines (64-bit machines will have 8-byte alignment already due to + // pointers, which all of these structs have). + UPB_ASSERT((sizeof(upb_FieldDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_MessageDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_EnumDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_EnumValueDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_ServiceDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_OneofDef) & UPB_DEFTYPE_MASK) == 0); + uintptr_t num = (uintptr_t)ptr; + UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); + num |= type; + return upb_value_constptr((const void*)num); +} + +/* isalpha() etc. from are locale-dependent, which we don't want. */ +static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { + return c >= low && c <= high; +} + +static char upb_ascii_lower(char ch) { + // Per ASCII this will lower-case a letter. If the result is a letter, the + // input was definitely a letter. If the output is not a letter, this may + // have transformed the character unpredictably. + return ch | 0x20; +} + +static bool upb_isletter(char c) { + char lower = upb_ascii_lower(c); + return upb_isbetween(lower, 'a', 'z') || c == '_'; +} + +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} + +static const char* shortdefname(const char* fullname) { + const char* p; + + if (fullname == NULL) { + return NULL; + } else if ((p = strrchr(fullname, '.')) == NULL) { + /* No '.' in the name, return the full string. */ + return fullname; + } else { + /* Return one past the last '.'. */ + return p + 1; + } +} + +/* All submessage fields are lower than all other fields. + * Secondly, fields are increasing in order. */ +uint32_t field_rank(const upb_FieldDef* f) { + uint32_t ret = upb_FieldDef_Number(f); + const uint32_t high_bit = 1 << 30; + UPB_ASSERT(ret < high_bit); + if (!upb_FieldDef_IsSubMessage(f)) ret |= high_bit; + return ret; +} + +int cmp_fields(const void* p1, const void* p2) { + const upb_FieldDef* f1 = *(upb_FieldDef* const*)p1; + const upb_FieldDef* f2 = *(upb_FieldDef* const*)p2; + return field_rank(f1) - field_rank(f2); +} + +static void upb_Status_setoom(upb_Status* status) { + upb_Status_SetErrorMessage(status, "out of memory"); +} + +static void assign_msg_wellknowntype(upb_MessageDef* m) { + const char* name = upb_MessageDef_FullName(m); + if (name == NULL) { + m->well_known_type = kUpb_WellKnown_Unspecified; + return; + } + if (!strcmp(name, "google.protobuf.Any")) { + m->well_known_type = kUpb_WellKnown_Any; + } else if (!strcmp(name, "google.protobuf.FieldMask")) { + m->well_known_type = kUpb_WellKnown_FieldMask; + } else if (!strcmp(name, "google.protobuf.Duration")) { + m->well_known_type = kUpb_WellKnown_Duration; + } else if (!strcmp(name, "google.protobuf.Timestamp")) { + m->well_known_type = kUpb_WellKnown_Timestamp; + } else if (!strcmp(name, "google.protobuf.DoubleValue")) { + m->well_known_type = kUpb_WellKnown_DoubleValue; + } else if (!strcmp(name, "google.protobuf.FloatValue")) { + m->well_known_type = kUpb_WellKnown_FloatValue; + } else if (!strcmp(name, "google.protobuf.Int64Value")) { + m->well_known_type = kUpb_WellKnown_Int64Value; + } else if (!strcmp(name, "google.protobuf.UInt64Value")) { + m->well_known_type = kUpb_WellKnown_UInt64Value; + } else if (!strcmp(name, "google.protobuf.Int32Value")) { + m->well_known_type = kUpb_WellKnown_Int32Value; + } else if (!strcmp(name, "google.protobuf.UInt32Value")) { + m->well_known_type = kUpb_WellKnown_UInt32Value; + } else if (!strcmp(name, "google.protobuf.BoolValue")) { + m->well_known_type = kUpb_WellKnown_BoolValue; + } else if (!strcmp(name, "google.protobuf.StringValue")) { + m->well_known_type = kUpb_WellKnown_StringValue; + } else if (!strcmp(name, "google.protobuf.BytesValue")) { + m->well_known_type = kUpb_WellKnown_BytesValue; + } else if (!strcmp(name, "google.protobuf.Value")) { + m->well_known_type = kUpb_WellKnown_Value; + } else if (!strcmp(name, "google.protobuf.ListValue")) { + m->well_known_type = kUpb_WellKnown_ListValue; + } else if (!strcmp(name, "google.protobuf.Struct")) { + m->well_known_type = kUpb_WellKnown_Struct; + } else { + m->well_known_type = kUpb_WellKnown_Unspecified; + } +} + +/* upb_EnumDef ****************************************************************/ + +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { + return e->opts; +} + +bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { + return e->opts != (void*)opt_default; +} + +const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } + +const char* upb_EnumDef_Name(const upb_EnumDef* e) { + return shortdefname(e->full_name); +} + +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } + +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { + return e->containing_type; +} + +int32_t upb_EnumDef_Default(const upb_EnumDef* e) { + UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); + return e->defaultval; +} + +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e) { + return e->res_range_count; +} + +/* upb_EnumReservedRange ******************************************************/ + +struct upb_EnumReservedRange { + int32_t start; + int32_t end; }; -_upb_DefPool_Init google_protobuf_descriptor_proto_upbdefinit = { - deps, - &google_protobuf_descriptor_proto_upb_file_layout, - "google/protobuf/descriptor.proto", - UPB_STRINGVIEW_INIT(descriptor, 7667) -}; +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i) { + return (upb_EnumReservedRange*)&r[i]; +} + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r) { + return r->start; +} +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r) { + return r->end; +} + +UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3) static void symtab_errf( + symtab_addctx* ctx, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(ctx->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(ctx->err, 1); +} + +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + symtab_addctx* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e) { + upb_EnumReservedRange* r = + upb_Arena_Malloc(ctx->arena, sizeof(upb_EnumReservedRange) * n); + + for (int i = 0; i < n; i++) { + const int32_t start = + google_protobuf_EnumDescriptorProto_EnumReservedRange_start(protos[i]); + const int32_t end = + google_protobuf_EnumDescriptorProto_EnumReservedRange_end(protos[i]); + const int32_t max = kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + + // Note: Not a typo! Unlike extension ranges and message reserved ranges, + // the end value of an enum reserved range is *inclusive*! + if (start < 1 || end < start || end > max) { + symtab_errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", + (int)start, (int)end, upb_EnumDef_FullName(e)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i) { + UPB_ASSERT(0 <= i && i < e->res_range_count); + return _upb_EnumReservedRange_At(e->res_ranges, i); +} + +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e) { + return e->res_name_count; +} + +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->res_name_count); + return e->res_names[i]; +} + +int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } + +const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* def, const char* name, size_t len) { + upb_value v; + return upb_strtable_lookup2(&def->ntoi, name, len, &v) + ? upb_value_getconstptr(v) + : NULL; +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* def, + int32_t num) { + upb_value v; + return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getconstptr(v) + : NULL; +} + +bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { + // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect + // this to be faster (especially for small numbers). + return upb_MiniTable_Enum_CheckValue(e->layout, num); +} + +const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->value_count); + return &e->values[i]; +} + +/* upb_EnumValueDef ***********************************************************/ + +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* e) { + return e->opts; +} + +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e) { + return e->opts != (void*)opt_default; +} + +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* ev) { + return ev->parent; +} + +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* ev) { + return ev->full_name; +} + +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* ev) { + return shortdefname(ev->full_name); +} + +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* ev) { + return ev->number; +} + +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* ev) { + // Compute index in our parent's array. + return ev - ev->parent->values; +} + +/* upb_ExtensionRange + * ***************************************************************/ + +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r) { + return r->opts; +} + +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { + return r->opts != (void*)opt_default; +} + +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* e) { + return e->start; +} + +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* e) { return e->end; } + +/* upb_FieldDef ***************************************************************/ + +const google_protobuf_FieldOptions* upb_FieldDef_Options( + const upb_FieldDef* f) { + return f->opts; +} + +bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { + return f->opts != (void*)opt_default; +} + +const char* upb_FieldDef_FullName(const upb_FieldDef* f) { + return f->full_name; +} + +upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { + switch (f->type_) { + case kUpb_FieldType_Double: + return kUpb_CType_Double; + case kUpb_FieldType_Float: + return kUpb_CType_Float; + case kUpb_FieldType_Int64: + case kUpb_FieldType_SInt64: + case kUpb_FieldType_SFixed64: + return kUpb_CType_Int64; + case kUpb_FieldType_Int32: + case kUpb_FieldType_SFixed32: + case kUpb_FieldType_SInt32: + return kUpb_CType_Int32; + case kUpb_FieldType_UInt64: + case kUpb_FieldType_Fixed64: + return kUpb_CType_UInt64; + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Fixed32: + return kUpb_CType_UInt32; + case kUpb_FieldType_Enum: + return kUpb_CType_Enum; + case kUpb_FieldType_Bool: + return kUpb_CType_Bool; + case kUpb_FieldType_String: + return kUpb_CType_String; + case kUpb_FieldType_Bytes: + return kUpb_CType_Bytes; + case kUpb_FieldType_Group: + case kUpb_FieldType_Message: + return kUpb_CType_Message; + } + UPB_UNREACHABLE(); +} + +upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } + +uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } -/** upb/def.c ************************************************************/ +upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } -#include -#include -#include -#include -#include +uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } +bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { + return f->is_extension_; +} -/* Must be last. */ +bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->packed_; } -typedef struct { - size_t len; - char str[1]; /* Null-terminated string data follows. */ -} str_t; +const char* upb_FieldDef_Name(const upb_FieldDef* f) { + return shortdefname(f->full_name); +} -/* The upb core does not generally have a concept of default instances. However - * for descriptor options we make an exception since the max size is known and - * modest (<200 bytes). All types can share a default instance since it is - * initialized to zeroes. - * - * We have to allocate an extra pointer for upb's internal metadata. */ -static const char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; -static const char* opt_default = &opt_default_buf[sizeof(void*)]; +const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { + return f->json_name; +} -struct upb_FieldDef { - const google_protobuf_FieldOptions* opts; - const upb_FileDef* file; - const upb_MessageDef* msgdef; - const char* full_name; - const char* json_name; - union { - int64_t sint; - uint64_t uint; - double dbl; - float flt; - bool boolean; - str_t* str; - } defaultval; - union { - const upb_OneofDef* oneof; - const upb_MessageDef* extension_scope; - } scope; - union { - const upb_MessageDef* msgdef; - const upb_EnumDef* enumdef; - const google_protobuf_FieldDescriptorProto* unresolved; - } sub; - uint32_t number_; - uint16_t index_; - uint16_t layout_index; /* Index into msgdef->layout->fields or file->exts */ - bool has_default; - bool is_extension_; - bool packed_; - bool proto3_optional_; - bool has_json_name_; - upb_FieldType type_; - upb_Label label_; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { + return f->has_json_name_; +} -struct upb_ExtensionRange { - const google_protobuf_ExtensionRangeOptions* opts; - int32_t start; - int32_t end; -}; +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } -struct upb_MessageDef { - const google_protobuf_MessageOptions* opts; - const upb_MiniTable* layout; - const upb_FileDef* file; - const upb_MessageDef* containing_type; - const char* full_name; +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { + return f->msgdef; +} - /* Tables for looking up fields by number and name. */ - upb_inttable itof; - upb_strtable ntof; +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { + return f->is_extension_ ? f->scope.extension_scope : NULL; +} - /* All nested defs. - * MEM: We could save some space here by putting nested defs in a contiguous - * region and calculating counts from offsets or vice-versa. */ - const upb_FieldDef* fields; - const upb_OneofDef* oneofs; - const upb_ExtensionRange* ext_ranges; - const upb_MessageDef* nested_msgs; - const upb_EnumDef* nested_enums; - const upb_FieldDef* nested_exts; - int field_count; - int real_oneof_count; - int oneof_count; - int ext_range_count; - int nested_msg_count; - int nested_enum_count; - int nested_ext_count; - bool in_message_set; - upb_WellKnown well_known_type; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; +const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { + return f->is_extension_ ? NULL : f->scope.oneof; +} -struct upb_EnumDef { - const google_protobuf_EnumOptions* opts; - const upb_MiniTable_Enum* layout; // Only for proto2. - const upb_FileDef* file; - const upb_MessageDef* containing_type; // Could be merged with "file". - const char* full_name; - upb_strtable ntoi; - upb_inttable iton; - const upb_EnumValueDef* values; - int value_count; - int32_t defaultval; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; +const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { + const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); + if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; + return oneof; +} -struct upb_EnumValueDef { - const google_protobuf_EnumValueOptions* opts; - const upb_EnumDef* parent; - const char* full_name; - int32_t number; -}; +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { + UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); + upb_MessageValue ret; -struct upb_OneofDef { - const google_protobuf_OneofOptions* opts; - const upb_MessageDef* parent; - const char* full_name; - int field_count; - bool synthetic; - const upb_FieldDef** fields; - upb_strtable ntof; - upb_inttable itof; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return (upb_MessageValue){.bool_val = f->defaultval.boolean}; + case kUpb_CType_Int64: + return (upb_MessageValue){.int64_val = f->defaultval.sint}; + case kUpb_CType_UInt64: + return (upb_MessageValue){.uint64_val = f->defaultval.uint}; + case kUpb_CType_Enum: + case kUpb_CType_Int32: + return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; + case kUpb_CType_UInt32: + return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; + case kUpb_CType_Float: + return (upb_MessageValue){.float_val = f->defaultval.flt}; + case kUpb_CType_Double: + return (upb_MessageValue){.double_val = f->defaultval.dbl}; + case kUpb_CType_String: + case kUpb_CType_Bytes: { + str_t* str = f->defaultval.str; + if (str) { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = str->str, .size = str->len}}; + } else { + return (upb_MessageValue){ + .str_val = (upb_StringView){.data = NULL, .size = 0}}; + } + } + default: + UPB_UNREACHABLE(); + } -struct upb_FileDef { - const google_protobuf_FileOptions* opts; - const char* name; - const char* package; + return ret; +} - const upb_FileDef** deps; - const int32_t* public_deps; - const int32_t* weak_deps; - const upb_MessageDef* top_lvl_msgs; - const upb_EnumDef* top_lvl_enums; - const upb_FieldDef* top_lvl_exts; - const upb_ServiceDef* services; - const upb_MiniTable_Extension** ext_layouts; - const upb_DefPool* symtab; +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; +} - int dep_count; - int public_dep_count; - int weak_dep_count; - int top_lvl_msg_count; - int top_lvl_enum_count; - int top_lvl_ext_count; - int service_count; - int ext_count; /* All exts in the file. */ - upb_Syntax syntax; -}; +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; +} -struct upb_MethodDef { - const google_protobuf_MethodOptions* opts; - upb_ServiceDef* service; - const char* full_name; - const upb_MessageDef* input_type; - const upb_MessageDef* output_type; - int index; - bool client_streaming; - bool server_streaming; -}; +const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { + UPB_ASSERT(!upb_FieldDef_IsExtension(f)); + return &f->msgdef->layout->fields[f->layout_index]; +} -struct upb_ServiceDef { - const google_protobuf_ServiceOptions* opts; - const upb_FileDef* file; - const char* full_name; - upb_MethodDef* methods; - int method_count; - int index; -}; +const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( + const upb_FieldDef* f) { + UPB_ASSERT(upb_FieldDef_IsExtension(f)); + return f->file->ext_layouts[f->layout_index]; +} + +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { + return f->proto3_optional_; +} -struct upb_DefPool { - upb_Arena* arena; - upb_strtable syms; /* full_name -> packed def ptr */ - upb_strtable files; /* file_name -> upb_FileDef* */ - upb_inttable exts; /* upb_MiniTable_Extension* -> upb_FieldDef* */ - upb_ExtensionRegistry* extreg; - size_t bytes_loaded; -}; +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message; +} -/* Inside a symtab we store tagged pointers to specific def types. */ -typedef enum { - UPB_DEFTYPE_MASK = 7, +bool upb_FieldDef_IsString(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_String || + upb_FieldDef_CType(f) == kUpb_CType_Bytes; +} - /* Only inside symtab table. */ - UPB_DEFTYPE_EXT = 0, - UPB_DEFTYPE_MSG = 1, - UPB_DEFTYPE_ENUM = 2, - UPB_DEFTYPE_ENUMVAL = 3, - UPB_DEFTYPE_SERVICE = 4, +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Repeated; +} - /* Only inside message table. */ - UPB_DEFTYPE_FIELD = 0, - UPB_DEFTYPE_ONEOF = 1, - UPB_DEFTYPE_FIELD_JSONNAME = 2, +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { + return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); +} - /* Only inside file table. */ - UPB_DEFTYPE_FILE = 0, - UPB_DEFTYPE_LAYOUT = 1 -} upb_deftype_t; +bool upb_FieldDef_IsMap(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && + upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); +} -#define FIELD_TYPE_UNSPECIFIED 0 +bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } -static upb_deftype_t deftype(upb_value v) { - uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return num & UPB_DEFTYPE_MASK; +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) || + upb_FieldDef_CType(f) == kUpb_CType_Enum; } -static const void* unpack_def(upb_value v, upb_deftype_t type) { - uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return (num & UPB_DEFTYPE_MASK) == type - ? (const void*)(num & ~UPB_DEFTYPE_MASK) - : NULL; +bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { + if (upb_FieldDef_IsRepeated(f)) return false; + return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || + f->file->syntax == kUpb_Syntax_Proto2; } -static upb_value pack_def(const void* ptr, upb_deftype_t type) { - // Our 3-bit pointer tagging requires all pointers to be multiples of 8. - // The arena will always yield 8-byte-aligned addresses, however we put - // the defs into arrays. For each element in the array to be 8-byte-aligned, - // the sizes of each def type must also be a multiple of 8. - // - // If any of these asserts fail, we need to add or remove padding on 32-bit - // machines (64-bit machines will have 8-byte alignment already due to - // pointers, which all of these structs have). - UPB_ASSERT((sizeof(upb_FieldDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_MessageDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_EnumDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_EnumValueDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_ServiceDef) & UPB_DEFTYPE_MASK) == 0); - UPB_ASSERT((sizeof(upb_OneofDef) & UPB_DEFTYPE_MASK) == 0); - uintptr_t num = (uintptr_t)ptr; - UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); - num |= type; - return upb_value_constptr((const void*)num); +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; } -/* isalpha() etc. from are locale-dependent, which we don't want. */ -static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { - return c >= low && c <= high; +bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } +bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } +bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } + +bool upb_FieldDef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); } -static char upb_ascii_lower(char ch) { - // Per ASCII this will lower-case a letter. If the result is a letter, the - // input was definitely a letter. If the output is not a letter, this may - // have transformed the character unpredictably. - return ch | 0x20; +/* upb_MessageDef + * *****************************************************************/ + +const google_protobuf_MessageOptions* upb_MessageDef_Options( + const upb_MessageDef* m) { + return m->opts; } -static bool upb_isletter(char c) { - char lower = upb_ascii_lower(c); - return upb_isbetween(lower, 'a', 'z') || c == '_'; +bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { + return m->opts != (void*)opt_default; } -static bool upb_isalphanum(char c) { - return upb_isletter(c) || upb_isbetween(c, '0', '9'); +const char* upb_MessageDef_FullName(const upb_MessageDef* m) { + return m->full_name; } -static const char* shortdefname(const char* fullname) { - const char* p; +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { + return m->file; +} - if (fullname == NULL) { - return NULL; - } else if ((p = strrchr(fullname, '.')) == NULL) { - /* No '.' in the name, return the full string. */ - return fullname; - } else { - /* Return one past the last '.'. */ - return p + 1; - } +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { + return m->containing_type; } -/* All submessage fields are lower than all other fields. - * Secondly, fields are increasing in order. */ -uint32_t field_rank(const upb_FieldDef* f) { - uint32_t ret = upb_FieldDef_Number(f); - const uint32_t high_bit = 1 << 30; - UPB_ASSERT(ret < high_bit); - if (!upb_FieldDef_IsSubMessage(f)) ret |= high_bit; - return ret; +const char* upb_MessageDef_Name(const upb_MessageDef* m) { + return shortdefname(m->full_name); } -int cmp_fields(const void* p1, const void* p2) { - const upb_FieldDef* f1 = *(upb_FieldDef* const*)p1; - const upb_FieldDef* f2 = *(upb_FieldDef* const*)p2; - return field_rank(f1) - field_rank(f2); +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { + return m->file->syntax; } -static void upb_Status_setoom(upb_Status* status) { - upb_Status_SetErrorMessage(status, "out of memory"); +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i) { + upb_value val; + return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) + : NULL; } -static void assign_msg_wellknowntype(upb_MessageDef* m) { - const char* name = upb_MessageDef_FullName(m); - if (name == NULL) { - m->well_known_type = kUpb_WellKnown_Unspecified; - return; - } - if (!strcmp(name, "google.protobuf.Any")) { - m->well_known_type = kUpb_WellKnown_Any; - } else if (!strcmp(name, "google.protobuf.FieldMask")) { - m->well_known_type = kUpb_WellKnown_FieldMask; - } else if (!strcmp(name, "google.protobuf.Duration")) { - m->well_known_type = kUpb_WellKnown_Duration; - } else if (!strcmp(name, "google.protobuf.Timestamp")) { - m->well_known_type = kUpb_WellKnown_Timestamp; - } else if (!strcmp(name, "google.protobuf.DoubleValue")) { - m->well_known_type = kUpb_WellKnown_DoubleValue; - } else if (!strcmp(name, "google.protobuf.FloatValue")) { - m->well_known_type = kUpb_WellKnown_FloatValue; - } else if (!strcmp(name, "google.protobuf.Int64Value")) { - m->well_known_type = kUpb_WellKnown_Int64Value; - } else if (!strcmp(name, "google.protobuf.UInt64Value")) { - m->well_known_type = kUpb_WellKnown_UInt64Value; - } else if (!strcmp(name, "google.protobuf.Int32Value")) { - m->well_known_type = kUpb_WellKnown_Int32Value; - } else if (!strcmp(name, "google.protobuf.UInt32Value")) { - m->well_known_type = kUpb_WellKnown_UInt32Value; - } else if (!strcmp(name, "google.protobuf.BoolValue")) { - m->well_known_type = kUpb_WellKnown_BoolValue; - } else if (!strcmp(name, "google.protobuf.StringValue")) { - m->well_known_type = kUpb_WellKnown_StringValue; - } else if (!strcmp(name, "google.protobuf.BytesValue")) { - m->well_known_type = kUpb_WellKnown_BytesValue; - } else if (!strcmp(name, "google.protobuf.Value")) { - m->well_known_type = kUpb_WellKnown_Value; - } else if (!strcmp(name, "google.protobuf.ListValue")) { - m->well_known_type = kUpb_WellKnown_ListValue; - } else if (!strcmp(name, "google.protobuf.Struct")) { - m->well_known_type = kUpb_WellKnown_Struct; - } else { - m->well_known_type = kUpb_WellKnown_Unspecified; +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t len) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return NULL; } + + return unpack_def(val, UPB_DEFTYPE_FIELD); } -/* upb_EnumDef ****************************************************************/ +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t len) { + upb_value val; -const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { - return e->opts; + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return NULL; + } + + return unpack_def(val, UPB_DEFTYPE_ONEOF); } -bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { - return e->opts != (void*)opt_default; +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t len, + const upb_FieldDef** out_f, + const upb_OneofDef** out_o) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; + } + + const upb_FieldDef* f = unpack_def(val, UPB_DEFTYPE_FIELD); + const upb_OneofDef* o = unpack_def(val, UPB_DEFTYPE_ONEOF); + if (out_f) *out_f = f; + if (out_o) *out_o = o; + return f || o; /* False if this was a JSON name. */ } -const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t len) { + upb_value val; + const upb_FieldDef* f; -const char* upb_EnumDef_Name(const upb_EnumDef* e) { - return shortdefname(e->full_name); + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return NULL; + } + + f = unpack_def(val, UPB_DEFTYPE_FIELD); + if (!f) f = unpack_def(val, UPB_DEFTYPE_FIELD_JSONNAME); + + return f; } -const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } +int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; } -const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { - return e->containing_type; +int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; } + +int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) { + return m->real_oneof_count; } -int32_t upb_EnumDef_Default(const upb_EnumDef* e) { - UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); - return e->defaultval; +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { + return m->ext_range_count; +} + +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m) { + return m->res_range_count; } -int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m) { + return m->res_name_count; +} -const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( - const upb_EnumDef* def, const char* name, size_t len) { - upb_value v; - return upb_strtable_lookup2(&def->ntoi, name, len, &v) - ? upb_value_getconstptr(v) - : NULL; +int upb_MessageDef_FieldCount(const upb_MessageDef* m) { + return m->field_count; } -const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* def, - int32_t num) { - upb_value v; - return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getconstptr(v) - : NULL; +int upb_MessageDef_OneofCount(const upb_MessageDef* m) { + return m->oneof_count; } -bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { - // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect - // this to be faster (especially for small numbers). - return upb_MiniTable_Enum_CheckValue(e->layout, num); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { + return m->nested_msg_count; } -const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { - UPB_ASSERT(0 <= i && i < e->value_count); - return &e->values[i]; +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { + return m->nested_enum_count; } -/* upb_EnumValueDef ***********************************************************/ +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { + return m->nested_ext_count; +} -const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( - const upb_EnumValueDef* e) { - return e->opts; +int upb_MessageDef_realoneofcount(const upb_MessageDef* m) { + return m->real_oneof_count; } -bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e) { - return e->opts != (void*)opt_default; +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { + return m->layout; } -const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* ev) { - return ev->parent; +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->ext_range_count); + return &m->ext_ranges[i]; } -const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* ev) { - return ev->full_name; +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i) { + return (upb_MessageReservedRange*)&r[i]; } -const char* upb_EnumValueDef_Name(const upb_EnumValueDef* ev) { - return shortdefname(ev->full_name); +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_range_count); + return _upb_MessageReservedRange_At(m->res_ranges, i); } -int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* ev) { - return ev->number; +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_name_count); + return m->res_names[i]; } -uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* ev) { - // Compute index in our parent's array. - return ev - ev->parent->values; +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r) { + return r->start; +} +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r) { + return r->end; } -/* upb_ExtensionRange - * ***************************************************************/ +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + symtab_addctx* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m) { + upb_MessageReservedRange* r = + upb_Arena_Malloc(ctx->arena, sizeof(upb_MessageReservedRange) * n); -const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( - const upb_ExtensionRange* r) { - return r->opts; -} + for (int i = 0; i < n; i++) { + const int32_t start = google_protobuf_DescriptorProto_ReservedRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ReservedRange_end(protos[i]); + const int32_t max = kUpb_MaxFieldNumber + 1; -bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { - return r->opts != (void*)opt_default; + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + symtab_errf(ctx, + "Reserved range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; } -int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* e) { - return e->start; +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->field_count); + return &m->fields[i]; } -int32_t upb_ExtensionRange_End(const upb_ExtensionRange* e) { return e->end; } +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->oneof_count); + return &m->oneofs[i]; +} -/* upb_FieldDef ***************************************************************/ +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_msg_count); + return &m->nested_msgs[i]; +} -const google_protobuf_FieldOptions* upb_FieldDef_Options( - const upb_FieldDef* f) { - return f->opts; +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->nested_enum_count); + return &m->nested_enums[i]; } -bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { - return f->opts != (void*)opt_default; +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_ext_count); + return &m->nested_exts[i]; } -const char* upb_FieldDef_FullName(const upb_FieldDef* f) { - return f->full_name; +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { + return m->well_known_type; } -upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { - switch (f->type_) { - case kUpb_FieldType_Double: - return kUpb_CType_Double; - case kUpb_FieldType_Float: - return kUpb_CType_Float; - case kUpb_FieldType_Int64: - case kUpb_FieldType_SInt64: - case kUpb_FieldType_SFixed64: - return kUpb_CType_Int64; - case kUpb_FieldType_Int32: - case kUpb_FieldType_SFixed32: - case kUpb_FieldType_SInt32: - return kUpb_CType_Int32; - case kUpb_FieldType_UInt64: - case kUpb_FieldType_Fixed64: - return kUpb_CType_UInt64; - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Fixed32: - return kUpb_CType_UInt32; - case kUpb_FieldType_Enum: - return kUpb_CType_Enum; - case kUpb_FieldType_Bool: - return kUpb_CType_Bool; - case kUpb_FieldType_String: - return kUpb_CType_String; - case kUpb_FieldType_Bytes: - return kUpb_CType_Bytes; - case kUpb_FieldType_Group: - case kUpb_FieldType_Message: - return kUpb_CType_Message; - } - UPB_UNREACHABLE(); +/* upb_OneofDef ***************************************************************/ + +const google_protobuf_OneofOptions* upb_OneofDef_Options( + const upb_OneofDef* o) { + return o->opts; } -upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } +bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { + return o->opts != (void*)opt_default; +} -uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } +const char* upb_OneofDef_Name(const upb_OneofDef* o) { + return shortdefname(o->full_name); +} -upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { + return o->parent; +} -uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } +int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } -bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { - return f->is_extension_; +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; } -bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->packed_; } +int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } -const char* upb_FieldDef_Name(const upb_FieldDef* f) { - return shortdefname(f->full_name); +uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { + // Compute index in our parent's array. + return o - o->parent->oneofs; } -const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { - return f->json_name; +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } + +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t length) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, length, &val) + ? upb_value_getptr(val) + : NULL; } -bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { - return f->has_json_name_; +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num) { + upb_value val; + return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) + : NULL; } -const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } +/* upb_FileDef ****************************************************************/ -const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { - return f->msgdef; +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { + return f->opts; } -const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { - return f->is_extension_ ? f->scope.extension_scope : NULL; +bool upb_FileDef_HasOptions(const upb_FileDef* f) { + return f->opts != (void*)opt_default; } -const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { - return f->is_extension_ ? NULL : f->scope.oneof; +const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } + +const char* upb_FileDef_Package(const upb_FileDef* f) { + return f->package ? f->package : ""; } -const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { - const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); - if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; - return oneof; +upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } + +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { + return f->top_lvl_msg_count; } -upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); - upb_MessageValue ret; +int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - return (upb_MessageValue){.bool_val = f->defaultval.boolean}; - case kUpb_CType_Int64: - return (upb_MessageValue){.int64_val = f->defaultval.sint}; - case kUpb_CType_UInt64: - return (upb_MessageValue){.uint64_val = f->defaultval.uint}; - case kUpb_CType_Enum: - case kUpb_CType_Int32: - return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; - case kUpb_CType_UInt32: - return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; - case kUpb_CType_Float: - return (upb_MessageValue){.float_val = f->defaultval.flt}; - case kUpb_CType_Double: - return (upb_MessageValue){.double_val = f->defaultval.dbl}; - case kUpb_CType_String: - case kUpb_CType_Bytes: { - str_t* str = f->defaultval.str; - if (str) { - return (upb_MessageValue){ - .str_val = (upb_StringView){.data = str->str, .size = str->len}}; - } else { - return (upb_MessageValue){ - .str_val = (upb_StringView){.data = NULL, .size = 0}}; - } - } - default: - UPB_UNREACHABLE(); - } +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { + return f->public_dep_count; +} - return ret; +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { + return f->weak_dep_count; +} + +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { + return f->public_deps; } -const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { + return f->weak_deps; } -const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { + return f->top_lvl_enum_count; } -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsExtension(f)); - return &f->msgdef->layout->fields[f->layout_index]; +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { + return f->top_lvl_ext_count; } -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( - const upb_FieldDef* f) { - UPB_ASSERT(upb_FieldDef_IsExtension(f)); - return f->file->ext_layouts[f->layout_index]; +int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } + +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->dep_count); + return f->deps[i]; } -bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { - return f->proto3_optional_; +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->public_deps[i]]; } -bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message; +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->weak_deps[i]]; } -bool upb_FieldDef_IsString(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_String || - upb_FieldDef_CType(f) == kUpb_CType_Bytes; +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); + return &f->top_lvl_msgs[i]; } -bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Repeated; +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); + return &f->top_lvl_enums[i]; } -bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { - return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); + return &f->top_lvl_exts[i]; } -bool upb_FieldDef_IsMap(const upb_FieldDef* f) { - return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && - upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->service_count); + return &f->services[i]; } -bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } -bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { - return upb_FieldDef_IsSubMessage(f) || - upb_FieldDef_CType(f) == kUpb_CType_Enum; +/* upb_MethodDef **************************************************************/ + +const google_protobuf_MethodOptions* upb_MethodDef_Options( + const upb_MethodDef* m) { + return m->opts; } -bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { - if (upb_FieldDef_IsRepeated(f)) return false; - return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || - f->file->syntax == kUpb_Syntax_Proto2; +bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { + return m->opts != (void*)opt_default; } -static bool between(int32_t x, int32_t low, int32_t high) { - return x >= low && x <= high; +const char* upb_MethodDef_FullName(const upb_MethodDef* m) { + return m->full_name; } -bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } -bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } -bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } -bool upb_FieldDef_checkdescriptortype(int32_t type) { - return between(type, 1, 18); +const char* upb_MethodDef_Name(const upb_MethodDef* m) { + return shortdefname(m->full_name); } -/* upb_MessageDef - * *****************************************************************/ +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { + return m->service; +} -const google_protobuf_MessageOptions* upb_MessageDef_Options( - const upb_MessageDef* m) { - return m->opts; +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { + return m->input_type; } -bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { - return m->opts != (void*)opt_default; +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { + return m->output_type; } -const char* upb_MessageDef_FullName(const upb_MessageDef* m) { - return m->full_name; +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { + return m->client_streaming; } -const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { - return m->file; +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { + return m->server_streaming; } -const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { - return m->containing_type; +/* upb_ServiceDef *************************************************************/ + +const google_protobuf_ServiceOptions* upb_ServiceDef_Options( + const upb_ServiceDef* s) { + return s->opts; } -const char* upb_MessageDef_Name(const upb_MessageDef* m) { - return shortdefname(m->full_name); +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { + return s->opts != (void*)opt_default; } -upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { - return m->file->syntax; +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { + return s->full_name; } -const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, - uint32_t i) { - upb_value val; - return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) - : NULL; +const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { + return shortdefname(s->full_name); } -const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; +int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { + return s->file; +} + +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { + return s->method_count; +} + +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { + return i < 0 || i >= s->method_count ? NULL : &s->methods[i]; +} + +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name) { + for (int i = 0; i < s->method_count; i++) { + if (strcmp(name, upb_MethodDef_Name(&s->methods[i])) == 0) { + return &s->methods[i]; + } } + return NULL; +} - return unpack_def(val, UPB_DEFTYPE_FIELD); +/* upb_DefPool ****************************************************************/ + +void upb_DefPool_Free(upb_DefPool* s) { + upb_Arena_Free(s->arena); + upb_gfree(s); } -const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; +upb_DefPool* upb_DefPool_New(void) { + upb_DefPool* s = upb_gmalloc(sizeof(*s)); - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + if (!s) { return NULL; } - return unpack_def(val, UPB_DEFTYPE_ONEOF); + s->arena = upb_Arena_New(); + s->bytes_loaded = 0; + + if (!upb_strtable_init(&s->syms, 32, s->arena) || + !upb_strtable_init(&s->files, 4, s->arena) || + !upb_inttable_init(&s->exts, s->arena)) { + goto err; + } + + s->extreg = upb_ExtensionRegistry_New(s->arena); + if (!s->extreg) goto err; + return s; + +err: + upb_Arena_Free(s->arena); + upb_gfree(s); + return NULL; } -bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, - const char* name, size_t len, - const upb_FieldDef** out_f, - const upb_OneofDef** out_o) { - upb_value val; +static const void* symtab_lookup(const upb_DefPool* s, const char* sym, + upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup(&s->syms, sym, &v) ? unpack_def(v, type) : NULL; +} - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return false; - } +static const void* symtab_lookup2(const upb_DefPool* s, const char* sym, + size_t size, upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup2(&s->syms, sym, size, &v) ? unpack_def(v, type) + : NULL; +} - const upb_FieldDef* f = unpack_def(val, UPB_DEFTYPE_FIELD); - const upb_OneofDef* o = unpack_def(val, UPB_DEFTYPE_ONEOF); - if (out_f) *out_f = f; - if (out_o) *out_o = o; - return f || o; /* False if this was a JSON name. */ +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym) { + return symtab_lookup(s, sym, UPB_DEFTYPE_MSG); } -const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; - const upb_FieldDef* f; +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return symtab_lookup2(s, sym, len, UPB_DEFTYPE_MSG); +} - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym) { + return symtab_lookup(s, sym, UPB_DEFTYPE_ENUM); +} + +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym) { + return symtab_lookup(s, sym, UPB_DEFTYPE_ENUMVAL); +} + +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) + ? unpack_def(v, UPB_DEFTYPE_FILE) + : NULL; +} + +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len) { + upb_value v; + return upb_strtable_lookup2(&s->files, name, len, &v) + ? unpack_def(v, UPB_DEFTYPE_FILE) + : NULL; +} + +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + upb_value v; + if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; + + switch (deftype(v)) { + case UPB_DEFTYPE_FIELD: + return unpack_def(v, UPB_DEFTYPE_FIELD); + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); + return m->in_message_set ? &m->nested_exts[0] : NULL; + } + default: + break; } - f = unpack_def(val, UPB_DEFTYPE_FIELD); - if (!f) f = unpack_def(val, UPB_DEFTYPE_FIELD_JSONNAME); - - return f; + return NULL; } -int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; } - -int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; } - -int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) { - return m->real_oneof_count; +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); } -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { - return m->ext_range_count; +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name) { + return symtab_lookup(s, name, UPB_DEFTYPE_SERVICE); } -int upb_MessageDef_FieldCount(const upb_MessageDef* m) { - return m->field_count; +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + return symtab_lookup2(s, name, size, UPB_DEFTYPE_SERVICE); } -int upb_MessageDef_OneofCount(const upb_MessageDef* m) { - return m->oneof_count; -} +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name) { + upb_value v; + // TODO(haberman): non-extension fields and oneofs. + if (upb_strtable_lookup(&s->syms, name, &v)) { + switch (deftype(v)) { + case UPB_DEFTYPE_EXT: { + const upb_FieldDef* f = unpack_def(v, UPB_DEFTYPE_EXT); + return upb_FieldDef_File(f); + } + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); + return upb_MessageDef_File(m); + } + case UPB_DEFTYPE_ENUM: { + const upb_EnumDef* e = unpack_def(v, UPB_DEFTYPE_ENUM); + return upb_EnumDef_File(e); + } + case UPB_DEFTYPE_ENUMVAL: { + const upb_EnumValueDef* ev = unpack_def(v, UPB_DEFTYPE_ENUMVAL); + return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); + } + case UPB_DEFTYPE_SERVICE: { + const upb_ServiceDef* service = unpack_def(v, UPB_DEFTYPE_SERVICE); + return upb_ServiceDef_File(service); + } + default: + UPB_UNREACHABLE(); + } + } -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { - return m->nested_msg_count; -} + const char* last_dot = strrchr(name, '.'); + if (last_dot) { + const upb_MessageDef* parent = + upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); + if (parent) { + const char* shortname = last_dot + 1; + if (upb_MessageDef_FindByNameWithSize(parent, shortname, + strlen(shortname), NULL, NULL)) { + return upb_MessageDef_File(parent); + } + } + } -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { - return m->nested_enum_count; + return NULL; } -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { - return m->nested_ext_count; -} +/* Code to build defs from descriptor protos. *********************************/ -int upb_MessageDef_realoneofcount(const upb_MessageDef* m) { - return m->real_oneof_count; -} +/* There is a question of how much validation to do here. It will be difficult + * to perfectly match the amount of validation performed by proto2. But since + * this code is used to directly build defs from Ruby (for example) we do need + * to validate important constraints like uniqueness of names and numbers. */ -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { - return m->layout; -} +#define CHK_OOM(x) \ + if (!(x)) { \ + symtab_oomerr(ctx); \ + } -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->ext_range_count); - return &m->ext_ranges[i]; +UPB_NORETURN UPB_NOINLINE static void symtab_oomerr(symtab_addctx* ctx) { + upb_Status_setoom(ctx->status); + UPB_LONGJMP(ctx->err, 1); } -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->field_count); - return &m->fields[i]; +void* symtab_alloc(symtab_addctx* ctx, size_t bytes) { + if (bytes == 0) return NULL; + void* ret = upb_Arena_Malloc(ctx->arena, bytes); + if (!ret) symtab_oomerr(ctx); + return ret; } -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->oneof_count); - return &m->oneofs[i]; -} +// We want to copy the options verbatim into the destination options proto. +// We use serialize+parse as our deep copy. +#define SET_OPTIONS(target, desc_type, options_type, proto) \ + if (google_protobuf_##desc_type##_has_options(proto)) { \ + size_t size; \ + char* pb = google_protobuf_##options_type##_serialize( \ + google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ + CHK_OOM(pb); \ + target = google_protobuf_##options_type##_parse(pb, size, ctx->arena); \ + CHK_OOM(target); \ + } else { \ + target = (const google_protobuf_##options_type*)opt_default; \ + } -const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_msg_count); - return &m->nested_msgs[i]; +static void check_ident(symtab_addctx* ctx, upb_StringView name, bool full) { + const char* str = name.data; + size_t len = name.size; + bool start = true; + size_t i; + for (i = 0; i < len; i++) { + char c = str[i]; + if (c == '.') { + if (start || !full) { + symtab_errf(ctx, "invalid name: unexpected '.' (%.*s)", (int)len, str); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + symtab_errf( + ctx, + "invalid name: path components must start with a letter (%.*s)", + (int)len, str); + } + start = false; + } else { + if (!upb_isalphanum(c)) { + symtab_errf(ctx, "invalid name: non-alphanumeric character (%.*s)", + (int)len, str); + } + } + } + if (start) { + symtab_errf(ctx, "invalid name: empty part (%.*s)", (int)len, str); + } } -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->nested_enum_count); - return &m->nested_enums[i]; -} +static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_ext_count); - return &m->nested_exts[i]; +static size_t upb_MessageValue_sizeof(upb_CType type) { + switch (type) { + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return 8; + case kUpb_CType_Enum: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Float: + return 4; + case kUpb_CType_Bool: + return 1; + case kUpb_CType_Message: + return sizeof(void*); + case kUpb_CType_Bytes: + case kUpb_CType_String: + return sizeof(upb_StringView); + } + UPB_UNREACHABLE(); } -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { - return m->well_known_type; +static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) { + if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { + upb_MapEntry ent; + UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); + return sizeof(ent.k); + } else if (upb_FieldDef_IsRepeated(f)) { + return sizeof(void*); + } else { + return upb_MessageValue_sizeof(upb_FieldDef_CType(f)); + } } -/* upb_OneofDef ***************************************************************/ +static uint32_t upb_MiniTable_place(symtab_addctx* ctx, upb_MiniTable* l, + size_t size, const upb_MessageDef* m) { + size_t ofs = UPB_ALIGN_UP(l->size, size); + size_t next = ofs + size; -const google_protobuf_OneofOptions* upb_OneofDef_Options( - const upb_OneofDef* o) { - return o->opts; -} + if (next > UINT16_MAX) { + symtab_errf(ctx, "size of message %s exceeded max size of %zu bytes", + upb_MessageDef_FullName(m), (size_t)UINT16_MAX); + } -bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { - return o->opts != (void*)opt_default; + l->size = next; + return ofs; } -const char* upb_OneofDef_Name(const upb_OneofDef* o) { - return shortdefname(o->full_name); +static int field_number_cmp(const void* p1, const void* p2) { + const upb_MiniTable_Field* f1 = p1; + const upb_MiniTable_Field* f2 = p2; + return f1->number - f2->number; } -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { - return o->parent; +static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l, + upb_MiniTable_Field* fields) { + int i; + int n = upb_MessageDef_numfields(m); + int dense_below = 0; + for (i = 0; i < n; i++) { + upb_FieldDef* f = + (upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number); + UPB_ASSERT(f); + f->layout_index = i; + if (i < UINT8_MAX && fields[i].number == i + 1 && + (i == 0 || fields[i - 1].number == i)) { + dense_below = i + 1; + } + } + l->dense_below = dense_below; } -int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } - -const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { - UPB_ASSERT(i < o->field_count); - return o->fields[i]; +static uint8_t map_descriptortype(const upb_FieldDef* f) { + uint8_t type = upb_FieldDef_Type(f); + /* See TableDescriptorType() in upbc/generator.cc for details and + * rationale of these exceptions. */ + if (type == kUpb_FieldType_String && f->file->syntax == kUpb_Syntax_Proto2) { + return kUpb_FieldType_Bytes; + } else if (type == kUpb_FieldType_Enum && + (f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3 || + UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 || + // TODO(https://github.com/protocolbuffers/upb/issues/541): + // fix map enum values to check for unknown enum values and put + // them in the unknown field set. + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)))) { + return kUpb_FieldType_Int32; + } + return type; } -int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } +static void fill_fieldlayout(upb_MiniTable_Field* field, + const upb_FieldDef* f) { + field->number = upb_FieldDef_Number(f); + field->descriptortype = map_descriptortype(f); -uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { - // Compute index in our parent's array. - return o - o->parent->oneofs; -} + if (upb_FieldDef_IsMap(f)) { + field->mode = + kUpb_FieldMode_Map | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); + } else if (upb_FieldDef_IsRepeated(f)) { + field->mode = + kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); + } else { + /* Maps descriptor type -> elem_size_lg2. */ + static const uint8_t sizes[] = { + -1, /* invalid descriptor type */ + kUpb_FieldRep_8Byte, /* DOUBLE */ + kUpb_FieldRep_4Byte, /* FLOAT */ + kUpb_FieldRep_8Byte, /* INT64 */ + kUpb_FieldRep_8Byte, /* UINT64 */ + kUpb_FieldRep_4Byte, /* INT32 */ + kUpb_FieldRep_8Byte, /* FIXED64 */ + kUpb_FieldRep_4Byte, /* FIXED32 */ + kUpb_FieldRep_1Byte, /* BOOL */ + kUpb_FieldRep_StringView, /* STRING */ + kUpb_FieldRep_Pointer, /* GROUP */ + kUpb_FieldRep_Pointer, /* MESSAGE */ + kUpb_FieldRep_StringView, /* BYTES */ + kUpb_FieldRep_4Byte, /* UINT32 */ + kUpb_FieldRep_4Byte, /* ENUM */ + kUpb_FieldRep_4Byte, /* SFIXED32 */ + kUpb_FieldRep_8Byte, /* SFIXED64 */ + kUpb_FieldRep_4Byte, /* SINT32 */ + kUpb_FieldRep_8Byte, /* SINT64 */ + }; + field->mode = kUpb_FieldMode_Scalar | + (sizes[field->descriptortype] << kUpb_FieldRep_Shift); + } -bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } + if (upb_FieldDef_IsPacked(f)) { + field->mode |= kUpb_LabelFlags_IsPacked; + } -const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, - const char* name, - size_t length) { - upb_value val; - return upb_strtable_lookup2(&o->ntof, name, length, &val) - ? upb_value_getptr(val) - : NULL; + if (upb_FieldDef_IsExtension(f)) { + field->mode |= kUpb_LabelFlags_IsExtension; + } } -const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, - uint32_t num) { - upb_value val; - return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) - : NULL; -} +/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. + * It computes a dynamic layout for all of the fields in |m|. */ +static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { + upb_MiniTable* l = (upb_MiniTable*)m->layout; + size_t field_count = upb_MessageDef_numfields(m); + size_t sublayout_count = 0; + upb_MiniTable_Sub* subs; + upb_MiniTable_Field* fields; -/* upb_FileDef ****************************************************************/ + memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry)); -const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { - return f->opts; -} + /* Count sub-messages. */ + for (size_t i = 0; i < field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + if (upb_FieldDef_IsSubMessage(f)) { + sublayout_count++; + } + if (upb_FieldDef_CType(f) == kUpb_CType_Enum && + f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2) { + sublayout_count++; + } + } -bool upb_FileDef_HasOptions(const upb_FileDef* f) { - return f->opts != (void*)opt_default; -} + fields = symtab_alloc(ctx, field_count * sizeof(*fields)); + subs = symtab_alloc(ctx, sublayout_count * sizeof(*subs)); -const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } + l->field_count = upb_MessageDef_numfields(m); + l->fields = fields; + l->subs = subs; + l->table_mask = 0; + l->required_count = 0; -const char* upb_FileDef_Package(const upb_FileDef* f) { return f->package; } + if (upb_MessageDef_ExtensionRangeCount(m) > 0) { + if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { + l->ext = kUpb_ExtMode_IsMessageSet; + } else { + l->ext = kUpb_ExtMode_Extendable; + } + } else { + l->ext = kUpb_ExtMode_NonExtendable; + } -upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } + /* TODO(haberman): initialize fast tables so that reflection-based parsing + * can get the same speeds as linked-in types. */ + l->fasttable[0].field_parser = &fastdecode_generic; + l->fasttable[0].field_data = 0; -int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { - return f->top_lvl_msg_count; -} + if (upb_MessageDef_IsMapEntry(m)) { + /* TODO(haberman): refactor this method so this special case is more + * elegant. */ + const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2); + if (key == NULL || val == NULL) { + symtab_errf(ctx, "Malformed map entry from message: %s", + upb_MessageDef_FullName(m)); + } + fields[0].number = 1; + fields[1].number = 2; + fields[0].mode = kUpb_FieldMode_Scalar; + fields[1].mode = kUpb_FieldMode_Scalar; + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].descriptortype = map_descriptortype(key); + fields[1].descriptortype = map_descriptortype(val); + fields[0].offset = 0; + fields[1].offset = sizeof(upb_StringView); + fields[1].submsg_index = 0; -int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } + if (upb_FieldDef_CType(val) == kUpb_CType_Message) { + subs[0].submsg = upb_FieldDef_MessageSubDef(val)->layout; + } -int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { - return f->public_dep_count; -} + upb_FieldDef* fielddefs = (upb_FieldDef*)&m->fields[0]; + UPB_ASSERT(fielddefs[0].number_ == 1); + UPB_ASSERT(fielddefs[1].number_ == 2); + fielddefs[0].layout_index = 0; + fielddefs[1].layout_index = 1; -int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { - return f->weak_dep_count; -} + l->field_count = 2; + l->size = 2 * sizeof(upb_StringView); + l->size = UPB_ALIGN_UP(l->size, 8); + l->dense_below = 2; + return; + } -const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { - return f->public_deps; -} + /* 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. + */ -const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { - return f->weak_deps; -} + /* Assign hasbits for required fields first. */ + size_t hasbit = 0; -int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { - return f->top_lvl_enum_count; -} + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; + if (upb_FieldDef_Label(f) == kUpb_Label_Required) { + field->presence = ++hasbit; + if (hasbit >= 63) { + symtab_errf(ctx, "Message with >=63 required fields: %s", + upb_MessageDef_FullName(m)); + } + l->required_count++; + } + } -int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { - return f->top_lvl_ext_count; -} + /* Allocate hasbits and set basic field attributes. */ + sublayout_count = 0; + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; -int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } + fill_fieldlayout(field, f); -const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->dep_count); - return f->deps[i]; -} + if (field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group) { + field->submsg_index = sublayout_count++; + subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout; + } else if (field->descriptortype == kUpb_FieldType_Enum) { + field->submsg_index = sublayout_count++; + subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout; + UPB_ASSERT(subs[field->submsg_index].subenum); + } -const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->public_dep_count); - return f->deps[f->public_deps[i]]; -} + if (upb_FieldDef_Label(f) == kUpb_Label_Required) { + /* Hasbit was already assigned. */ + } else if (upb_FieldDef_HasPresence(f) && + !upb_FieldDef_RealContainingOneof(f)) { + /* We don't use hasbit 0, so that 0 can indicate "no presence" in the + * table. This wastes one hasbit, but we don't worry about it for now. */ + field->presence = ++hasbit; + } else { + field->presence = 0; + } + } -const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->public_dep_count); - return f->deps[f->weak_deps[i]]; -} + /* Account for space used by hasbits. */ + l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0; -const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); - return &f->top_lvl_msgs[i]; -} + /* Allocate non-oneof fields. */ + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + size_t field_size = upb_msg_fielddefsize(f); + size_t index = upb_FieldDef_Index(f); -const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); - return &f->top_lvl_enums[i]; -} + if (upb_FieldDef_RealContainingOneof(f)) { + /* Oneofs are handled separately below. */ + continue; + } -const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); - return &f->top_lvl_exts[i]; -} + fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m); + } -const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->service_count); - return &f->services[i]; -} + /* Allocate oneof fields. Each oneof field consists of a uint32 for the case + * and space for the actual data. */ + for (int i = 0; i < m->oneof_count; i++) { + const upb_OneofDef* o = &m->oneofs[i]; + size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ + size_t field_size = 0; + uint32_t case_offset; + uint32_t data_offset; -const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } + if (upb_OneofDef_IsSynthetic(o)) continue; -/* upb_MethodDef **************************************************************/ + if (o->field_count == 0) { + symtab_errf(ctx, "Oneof must have at least one field (%s)", o->full_name); + } -const google_protobuf_MethodOptions* upb_MethodDef_Options( - const upb_MethodDef* m) { - return m->opts; -} + /* Calculate field size: the max of all field sizes. */ + for (int j = 0; j < o->field_count; j++) { + const upb_FieldDef* f = o->fields[j]; + field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); + } -bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { - return m->opts != (void*)opt_default; -} + /* Align and allocate case offset. */ + case_offset = upb_MiniTable_place(ctx, l, case_size, m); + data_offset = upb_MiniTable_place(ctx, l, field_size, m); -const char* upb_MethodDef_FullName(const upb_MethodDef* m) { - return m->full_name; -} + for (int i = 0; i < o->field_count; i++) { + const upb_FieldDef* f = o->fields[i]; + fields[upb_FieldDef_Index(f)].offset = data_offset; + fields[upb_FieldDef_Index(f)].presence = ~case_offset; + } + } -int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } + /* Size of the entire structure should be a multiple of its greatest + * alignment. TODO: track overall alignment for real? */ + l->size = UPB_ALIGN_UP(l->size, 8); -const char* upb_MethodDef_Name(const upb_MethodDef* m) { - return shortdefname(m->full_name); + /* Sort fields by number. */ + if (fields) { + qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), + field_number_cmp); + } + assign_layout_indices(m, l, fields); } -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { - return m->service; +static char* strviewdup(symtab_addctx* ctx, upb_StringView view) { + char* ret = upb_strdup2(view.data, view.size, ctx->arena); + CHK_OOM(ret); + return ret; } -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { - return m->input_type; +static bool streql2(const char* a, size_t n, const char* b) { + return n == strlen(b) && memcmp(a, b, n) == 0; } -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { - return m->output_type; +static bool streql_view(upb_StringView view, const char* b) { + return streql2(view.data, view.size, b); } -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { - return m->client_streaming; +static const char* makefullname(symtab_addctx* ctx, const char* prefix, + upb_StringView name) { + if (prefix) { + /* ret = prefix + '.' + name; */ + size_t n = strlen(prefix); + char* ret = symtab_alloc(ctx, n + name.size + 2); + strcpy(ret, prefix); + ret[n] = '.'; + memcpy(&ret[n + 1], name.data, name.size); + ret[n + 1 + name.size] = '\0'; + return ret; + } else { + return strviewdup(ctx, name); + } } -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { - return m->server_streaming; -} +static void finalize_oneofs(symtab_addctx* ctx, upb_MessageDef* m) { + int i; + int synthetic_count = 0; + upb_OneofDef* mutable_oneofs = (upb_OneofDef*)m->oneofs; -/* upb_ServiceDef *************************************************************/ + for (i = 0; i < m->oneof_count; i++) { + upb_OneofDef* o = &mutable_oneofs[i]; -const google_protobuf_ServiceOptions* upb_ServiceDef_Options( - const upb_ServiceDef* s) { - return s->opts; -} + if (o->synthetic && o->field_count != 1) { + symtab_errf(ctx, "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_OneofDef_Name(o)); + } -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { - return s->opts != (void*)opt_default; -} + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + symtab_errf(ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_OneofDef_Name(o)); + } -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { - return s->full_name; -} + o->fields = symtab_alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); + o->field_count = 0; + } -const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { - return shortdefname(s->full_name); + for (i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); + if (o) { + o->fields[o->field_count++] = f; + } + } + + m->real_oneof_count = m->oneof_count - synthetic_count; } -int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } +size_t getjsonname(const char* name, char* buf, size_t len) { + size_t src, dst = 0; + bool ucase_next = false; -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { - return s->file; -} +#define WRITE(byte) \ + ++dst; \ + if (dst < len) \ + buf[dst - 1] = byte; \ + else if (dst == len) \ + buf[dst - 1] = '\0' -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { - return s->method_count; -} + if (!name) { + WRITE('\0'); + return 0; + } -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { - return i < 0 || i >= s->method_count ? NULL : &s->methods[i]; -} + /* Implement the transformation as described in the spec: + * 1. upper case all letters after an underscore. + * 2. remove all underscores. + */ + for (src = 0; name[src]; src++) { + if (name[src] == '_') { + ucase_next = true; + continue; + } -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name) { - for (int i = 0; i < s->method_count; i++) { - if (strcmp(name, upb_MethodDef_Name(&s->methods[i])) == 0) { - return &s->methods[i]; + if (ucase_next) { + WRITE(toupper(name[src])); + ucase_next = false; + } else { + WRITE(name[src]); } } - return NULL; -} -/* upb_DefPool ****************************************************************/ + WRITE('\0'); + return dst; -void upb_DefPool_Free(upb_DefPool* s) { - upb_Arena_Free(s->arena); - upb_gfree(s); +#undef WRITE } -upb_DefPool* upb_DefPool_New(void) { - upb_DefPool* s = upb_gmalloc(sizeof(*s)); +static char* makejsonname(symtab_addctx* ctx, const char* name) { + size_t size = getjsonname(name, NULL, 0); + char* json_name = symtab_alloc(ctx, size); + getjsonname(name, json_name, size); + return json_name; +} - if (!s) { - return NULL; +/* Adds a symbol |v| to the symtab, which must be a def pointer previously + * packed with pack_def(). The def's pointer to upb_FileDef* must be set before + * adding, so we know which entries to remove if building this file fails. */ +static void symtab_add(symtab_addctx* ctx, const char* name, upb_value v) { + // TODO: table should support an operation "tryinsert" to avoid the double + // lookup. + if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { + symtab_errf(ctx, "duplicate symbol '%s'", name); } + size_t len = strlen(name); + CHK_OOM(upb_strtable_insert(&ctx->symtab->syms, name, len, v, + ctx->symtab->arena)); +} - s->arena = upb_Arena_New(); - s->bytes_loaded = 0; +static bool remove_component(char* base, size_t* len) { + if (*len == 0) return false; - if (!upb_strtable_init(&s->syms, 32, s->arena) || - !upb_strtable_init(&s->files, 4, s->arena) || - !upb_inttable_init(&s->exts, s->arena)) { - goto err; + for (size_t i = *len - 1; i > 0; i--) { + if (base[i] == '.') { + *len = i; + return true; + } } - s->extreg = upb_ExtensionRegistry_New(s->arena); - if (!s->extreg) goto err; - return s; - -err: - upb_Arena_Free(s->arena); - upb_gfree(s); - return NULL; -} - -static const void* symtab_lookup(const upb_DefPool* s, const char* sym, - upb_deftype_t type) { - upb_value v; - return upb_strtable_lookup(&s->syms, sym, &v) ? unpack_def(v, type) : NULL; + *len = 0; + return true; } -static const void* symtab_lookup2(const upb_DefPool* s, const char* sym, - size_t size, upb_deftype_t type) { +/* Given a symbol and the base symbol inside which it is defined, find the + * symbol's definition in t. */ +static const void* symtab_resolveany(symtab_addctx* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type) { + const upb_strtable* t = &ctx->symtab->syms; + if (sym.size == 0) goto notfound; upb_value v; - return upb_strtable_lookup2(&s->syms, sym, size, &v) ? unpack_def(v, type) - : NULL; -} - -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_MSG); -} + if (sym.data[0] == '.') { + /* Symbols starting with '.' are absolute, so we do a single lookup. + * Slice to omit the leading '.' */ + if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) { + goto notfound; + } + } else { + /* Remove components from base until we find an entry or run out. */ + size_t baselen = base ? strlen(base) : 0; + char* tmp = malloc(sym.size + baselen + 1); + while (1) { + char* p = tmp; + if (baselen) { + memcpy(p, base, baselen); + p[baselen] = '.'; + p += baselen + 1; + } + memcpy(p, sym.data, sym.size); + p += sym.size; + if (upb_strtable_lookup2(t, tmp, p - tmp, &v)) { + break; + } + if (!remove_component(tmp, &baselen)) { + free(tmp); + goto notfound; + } + } + free(tmp); + } -const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len) { - return symtab_lookup2(s, sym, len, UPB_DEFTYPE_MSG); -} + *type = deftype(v); + return unpack_def(v, *type); -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUM); +notfound: + symtab_errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(sym)); } -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUMVAL); +static const void* symtab_resolve(symtab_addctx* ctx, const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t type) { + upb_deftype_t found_type; + const void* ret = + symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type); + if (ret && found_type != type) { + symtab_errf(ctx, + "type mismatch when resolving %s: couldn't find " + "name " UPB_STRINGVIEW_FORMAT " with type=%d", + from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); + } + return ret; } -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name) { +static void create_oneofdef( + symtab_addctx* ctx, upb_MessageDef* m, + const google_protobuf_OneofDescriptorProto* oneof_proto, + const upb_OneofDef* _o) { + upb_OneofDef* o = (upb_OneofDef*)_o; + upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); upb_value v; - return upb_strtable_lookup(&s->files, name, &v) - ? unpack_def(v, UPB_DEFTYPE_FILE) - : NULL; -} -const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, - const char* name, - size_t len) { - upb_value v; - return upb_strtable_lookup2(&s->files, name, len, &v) - ? unpack_def(v, UPB_DEFTYPE_FILE) - : NULL; -} + o->parent = m; + o->full_name = makefullname(ctx, m->full_name, name); + o->field_count = 0; + o->synthetic = false; -const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - upb_value v; - if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; + SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); - switch (deftype(v)) { - case UPB_DEFTYPE_FIELD: - return unpack_def(v, UPB_DEFTYPE_FIELD); - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); - return m->in_message_set ? &m->nested_exts[0] : NULL; - } - default: - break; + upb_value existing_v; + if (upb_strtable_lookup2(&m->ntof, name.data, name.size, &existing_v)) { + symtab_errf(ctx, "duplicate oneof name (%s)", o->full_name); } - return NULL; -} + v = pack_def(o, UPB_DEFTYPE_ONEOF); + CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); -const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, - const char* sym) { - return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); + CHK_OOM(upb_inttable_init(&o->itof, ctx->arena)); + CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena)); } -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name) { - return symtab_lookup(s, name, UPB_DEFTYPE_SERVICE); +static str_t* newstr(symtab_addctx* ctx, const char* data, size_t len) { + str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); + CHK_OOM(ret); + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; } -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - return symtab_lookup2(s, name, size, UPB_DEFTYPE_SERVICE); +static bool upb_DefPool_TryGetChar(const char** src, const char* end, + char* ch) { + if (*src == end) return false; + *ch = **src; + *src += 1; + return true; } -const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, - const char* name) { - upb_value v; - // TODO(haberman): non-extension fields and oneofs. - if (upb_strtable_lookup(&s->syms, name, &v)) { - switch (deftype(v)) { - case UPB_DEFTYPE_EXT: { - const upb_FieldDef* f = unpack_def(v, UPB_DEFTYPE_EXT); - return upb_FieldDef_File(f); - } - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); - return upb_MessageDef_File(m); - } - case UPB_DEFTYPE_ENUM: { - const upb_EnumDef* e = unpack_def(v, UPB_DEFTYPE_ENUM); - return upb_EnumDef_File(e); - } - case UPB_DEFTYPE_ENUMVAL: { - const upb_EnumValueDef* ev = unpack_def(v, UPB_DEFTYPE_ENUMVAL); - return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); - } - case UPB_DEFTYPE_SERVICE: { - const upb_ServiceDef* service = unpack_def(v, UPB_DEFTYPE_SERVICE); - return upb_ServiceDef_File(service); - } - default: - UPB_UNREACHABLE(); - } +static char upb_DefPool_TryGetHexDigit(symtab_addctx* ctx, + const upb_FieldDef* f, const char** src, + const char* end) { + char ch; + if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '9') { + return ch - '0'; } - - const char* last_dot = strrchr(name, '.'); - if (last_dot) { - const upb_MessageDef* parent = - upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); - if (parent) { - const char* shortname = last_dot + 1; - if (upb_MessageDef_FindByNameWithSize(parent, shortname, - strlen(shortname), NULL, NULL)) { - return upb_MessageDef_File(parent); - } - } + ch = upb_ascii_lower(ch); + if ('a' <= ch && ch <= 'f') { + return ch - 'a' + 0xa; } - - return NULL; + *src -= 1; // Char wasn't actually a hex digit. + return -1; } -/* Code to build defs from descriptor protos. *********************************/ - -/* There is a question of how much validation to do here. It will be difficult - * to perfectly match the amount of validation performed by proto2. But since - * this code is used to directly build defs from Ruby (for example) we do need - * to validate important constraints like uniqueness of names and numbers. */ - -#define CHK_OOM(x) \ - if (!(x)) { \ - symtab_oomerr(ctx); \ +static char upb_DefPool_ParseHexEscape(symtab_addctx* ctx, + const upb_FieldDef* f, const char** src, + const char* end) { + char hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end); + if (hex_digit < 0) { + symtab_errf(ctx, + "\\x cannot be followed by non-hex digit in field '%s' default", + upb_FieldDef_FullName(f)); + return 0; } + unsigned int ret = hex_digit; + while ((hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end)) >= 0) { + ret = (ret << 4) | hex_digit; + } + if (ret > 0xff) { + symtab_errf(ctx, "Value of hex escape in field %s exceeds 8 bits", + upb_FieldDef_FullName(f)); + return 0; + } + return ret; +} -typedef struct { - upb_DefPool* symtab; - upb_FileDef* file; /* File we are building. */ - upb_Arena* arena; /* Allocate defs here. */ - upb_Arena* tmp_arena; /* For temporary allocations. */ - const upb_MiniTable_File* layout; /* NULL if we should build layouts. */ - int enum_count; /* Count of enums built so far. */ - int msg_count; /* Count of messages built so far. */ - int ext_count; /* Count of extensions built so far. */ - upb_Status* status; /* Record errors here. */ - jmp_buf err; /* longjmp() on error. */ -} symtab_addctx; - -UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3) static void symtab_errf( - symtab_addctx* ctx, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(ctx->status, fmt, argp); - va_end(argp); - UPB_LONGJMP(ctx->err, 1); +char upb_DefPool_TryGetOctalDigit(const char** src, const char* end) { + char ch; + if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '7') { + return ch - '0'; + } + *src -= 1; // Char wasn't actually an octal digit. + return -1; } -UPB_NORETURN UPB_NOINLINE static void symtab_oomerr(symtab_addctx* ctx) { - upb_Status_setoom(ctx->status); - UPB_LONGJMP(ctx->err, 1); +static char upb_DefPool_ParseOctalEscape(symtab_addctx* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char ch = 0; + for (int i = 0; i < 3; i++) { + char digit; + if ((digit = upb_DefPool_TryGetOctalDigit(src, end)) >= 0) { + ch = (ch << 3) | digit; + } + } + return ch; } -void* symtab_alloc(symtab_addctx* ctx, size_t bytes) { - if (bytes == 0) return NULL; - void* ret = upb_Arena_Malloc(ctx->arena, bytes); - if (!ret) symtab_oomerr(ctx); - return ret; +static char upb_DefPool_ParseEscape(symtab_addctx* ctx, const upb_FieldDef* f, + const char** src, const char* end) { + char ch; + if (!upb_DefPool_TryGetChar(src, end, &ch)) { + symtab_errf(ctx, "unterminated escape sequence in field %s", + upb_FieldDef_FullName(f)); + return 0; + } + switch (ch) { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '\"': + return '\"'; + case '?': + return '\?'; + case 'x': + case 'X': + return upb_DefPool_ParseHexEscape(ctx, f, src, end); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + *src -= 1; + return upb_DefPool_ParseOctalEscape(ctx, f, src, end); + } + symtab_errf(ctx, "Unknown escape sequence: \\%c", ch); } -// We want to copy the options verbatim into the destination options proto. -// We use serialize+parse as our deep copy. -#define SET_OPTIONS(target, desc_type, options_type, proto) \ - if (google_protobuf_##desc_type##_has_options(proto)) { \ - size_t size; \ - char* pb = google_protobuf_##options_type##_serialize( \ - google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ - CHK_OOM(pb); \ - target = google_protobuf_##options_type##_parse(pb, size, ctx->arena); \ - CHK_OOM(target); \ - } else { \ - target = (const google_protobuf_##options_type*)opt_default; \ - } +static str_t* unescape(symtab_addctx* ctx, const upb_FieldDef* f, + const char* data, size_t len) { + // Size here is an upper bound; escape sequences could ultimately shrink it. + str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); + char* dst = &ret->str[0]; + const char* src = data; + const char* end = data + len; -static void check_ident(symtab_addctx* ctx, upb_StringView name, bool full) { - const char* str = name.data; - size_t len = name.size; - bool start = true; - size_t i; - for (i = 0; i < len; i++) { - char c = str[i]; - if (c == '.') { - if (start || !full) { - symtab_errf(ctx, "invalid name: unexpected '.' (%.*s)", (int)len, str); - } - start = true; - } else if (start) { - if (!upb_isletter(c)) { - symtab_errf( - ctx, - "invalid name: path components must start with a letter (%.*s)", - (int)len, str); - } - start = false; + while (src < end) { + if (*src == '\\') { + src++; + *dst++ = upb_DefPool_ParseEscape(ctx, f, &src, end); } else { - if (!upb_isalphanum(c)) { - symtab_errf(ctx, "invalid name: non-alphanumeric character (%.*s)", - (int)len, str); - } + *dst++ = *src++; } } - if (start) { - symtab_errf(ctx, "invalid name: empty part (%.*s)", (int)len, str); - } + + ret->len = dst - &ret->str[0]; + return ret; } -static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } +static void parse_default(symtab_addctx* ctx, const char* str, size_t len, + upb_FieldDef* f) { + char* end; + char nullz[64]; + errno = 0; -static size_t upb_MessageValue_sizeof(upb_CType type) { - switch (type) { - case kUpb_CType_Double: - case kUpb_CType_Int64: - case kUpb_CType_UInt64: - return 8; - case kUpb_CType_Enum: + switch (upb_FieldDef_CType(f)) { case kUpb_CType_Int32: + case kUpb_CType_Int64: case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + case kUpb_CType_Double: case kUpb_CType_Float: - return 4; - case kUpb_CType_Bool: - return 1; - case kUpb_CType_Message: - return sizeof(void*); - case kUpb_CType_Bytes: - case kUpb_CType_String: - return sizeof(upb_StringView); - } - UPB_UNREACHABLE(); -} - -static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) { - if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { - upb_MapEntry ent; - UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); - return sizeof(ent.k); - } else if (upb_FieldDef_IsRepeated(f)) { - return sizeof(void*); - } else { - return upb_MessageValue_sizeof(upb_FieldDef_CType(f)); + /* Standard C number parsing functions expect null-terminated strings. */ + if (len >= sizeof(nullz) - 1) { + symtab_errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; } -} -static uint32_t upb_MiniTable_place(symtab_addctx* ctx, upb_MiniTable* l, - size_t size, const upb_MessageDef* m) { - size_t ofs = UPB_ALIGN_UP(l->size, size); - size_t next = ofs + size; - - if (next > UINT16_MAX) { - symtab_errf(ctx, "size of message %s exceeded max size of %zu bytes", - upb_MessageDef_FullName(m), (size_t)UINT16_MAX); + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_Enum: { + const upb_EnumDef* e = f->sub.enumdef; + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str, len); + if (!ev) { + goto invalid; + } + f->defaultval.sint = ev->number; + break; + } + case kUpb_CType_Int64: { + long long val = strtoll(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_UInt32: { + unsigned long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_UInt64: { + unsigned long long val = strtoull(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_Double: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.dbl = val; + break; + } + case kUpb_CType_Float: { + float val = strtof(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.flt = val; + break; + } + case kUpb_CType_Bool: { + if (streql2(str, len, "false")) { + f->defaultval.boolean = false; + } else if (streql2(str, len, "true")) { + f->defaultval.boolean = true; + } else { + goto invalid; + } + break; + } + case kUpb_CType_String: + f->defaultval.str = newstr(ctx, str, len); + break; + case kUpb_CType_Bytes: + f->defaultval.str = unescape(ctx, f, str, len); + break; + case kUpb_CType_Message: + /* Should not have a default value. */ + symtab_errf(ctx, "Message should not have a default (%s)", + upb_FieldDef_FullName(f)); } - l->size = next; - return ofs; -} - -static int field_number_cmp(const void* p1, const void* p2) { - const upb_MiniTable_Field* f1 = p1; - const upb_MiniTable_Field* f2 = p2; - return f1->number - f2->number; -} + return; -static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l, - upb_MiniTable_Field* fields) { - int i; - int n = upb_MessageDef_numfields(m); - int dense_below = 0; - for (i = 0; i < n; i++) { - upb_FieldDef* f = - (upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number); - UPB_ASSERT(f); - f->layout_index = i; - if (i < UINT8_MAX && fields[i].number == i + 1 && - (i == 0 || fields[i - 1].number == i)) { - dense_below = i + 1; - } - } - l->dense_below = dense_below; +invalid: + symtab_errf(ctx, "Invalid default '%.*s' for field %s of type %d", (int)len, + str, upb_FieldDef_FullName(f), (int)upb_FieldDef_Type(f)); } -static uint8_t map_descriptortype(const upb_FieldDef* f) { - uint8_t type = upb_FieldDef_Type(f); - /* See TableDescriptorType() in upbc/generator.cc for details and - * rationale of these exceptions. */ - if (type == kUpb_FieldType_String && f->file->syntax == kUpb_Syntax_Proto2) { - return kUpb_FieldType_Bytes; - } else if (type == kUpb_FieldType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3) { - return kUpb_FieldType_Int32; +static void set_default_default(symtab_addctx* ctx, upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + f->defaultval.sint = 0; + break; + case kUpb_CType_UInt64: + case kUpb_CType_UInt32: + f->defaultval.uint = 0; + break; + case kUpb_CType_Double: + case kUpb_CType_Float: + f->defaultval.dbl = 0; + break; + case kUpb_CType_String: + case kUpb_CType_Bytes: + f->defaultval.str = newstr(ctx, NULL, 0); + break; + case kUpb_CType_Bool: + f->defaultval.boolean = false; + break; + case kUpb_CType_Enum: + f->defaultval.sint = f->sub.enumdef->values[0].number; + case kUpb_CType_Message: + break; } - return type; } -static void fill_fieldlayout(upb_MiniTable_Field* field, - const upb_FieldDef* f) { - field->number = upb_FieldDef_Number(f); - field->descriptortype = map_descriptortype(f); +static void create_fielddef( + symtab_addctx* ctx, const char* prefix, upb_MessageDef* m, + const google_protobuf_FieldDescriptorProto* field_proto, + const upb_FieldDef* _f, bool is_extension) { + upb_FieldDef* f = (upb_FieldDef*)_f; + upb_StringView name; + const char* full_name; + const char* json_name; + const char* shortname; + int32_t field_number; - if (upb_FieldDef_IsMap(f)) { - field->mode = - kUpb_FieldMode_Map | (upb_FieldRep_Pointer << upb_FieldRep_Shift); - } else if (upb_FieldDef_IsRepeated(f)) { - field->mode = - kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift); - } else { - /* Maps descriptor type -> elem_size_lg2. */ - static const uint8_t sizes[] = { - -1, /* invalid descriptor type */ - upb_FieldRep_8Byte, /* DOUBLE */ - upb_FieldRep_4Byte, /* FLOAT */ - upb_FieldRep_8Byte, /* INT64 */ - upb_FieldRep_8Byte, /* UINT64 */ - upb_FieldRep_4Byte, /* INT32 */ - upb_FieldRep_8Byte, /* FIXED64 */ - upb_FieldRep_4Byte, /* FIXED32 */ - upb_FieldRep_1Byte, /* BOOL */ - upb_FieldRep_StringView, /* STRING */ - upb_FieldRep_Pointer, /* GROUP */ - upb_FieldRep_Pointer, /* MESSAGE */ - upb_FieldRep_StringView, /* BYTES */ - upb_FieldRep_4Byte, /* UINT32 */ - upb_FieldRep_4Byte, /* ENUM */ - upb_FieldRep_4Byte, /* SFIXED32 */ - upb_FieldRep_8Byte, /* SFIXED64 */ - upb_FieldRep_4Byte, /* SINT32 */ - upb_FieldRep_8Byte, /* SINT64 */ - }; - field->mode = kUpb_FieldMode_Scalar | - (sizes[field->descriptortype] << upb_FieldRep_Shift); - } + f->file = ctx->file; /* Must happen prior to symtab_add(). */ - if (upb_FieldDef_IsPacked(f)) { - field->mode |= upb_LabelFlags_IsPacked; + if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { + symtab_errf(ctx, "field has no name"); } - if (upb_FieldDef_IsExtension(f)) { - field->mode |= upb_LabelFlags_IsExtension; - } -} + name = google_protobuf_FieldDescriptorProto_name(field_proto); + check_ident(ctx, name, false); + full_name = makefullname(ctx, prefix, name); + shortname = shortdefname(full_name); -/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. - * It computes a dynamic layout for all of the fields in |m|. */ -static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { - upb_MiniTable* l = (upb_MiniTable*)m->layout; - size_t field_count = upb_MessageDef_numfields(m); - size_t sublayout_count = 0; - upb_MiniTable_Sub* subs; - upb_MiniTable_Field* fields; + if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { + json_name = strviewdup( + ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto)); + f->has_json_name_ = true; + } else { + json_name = makejsonname(ctx, shortname); + f->has_json_name_ = false; + } - memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry)); + field_number = google_protobuf_FieldDescriptorProto_number(field_proto); - /* Count sub-messages. */ - for (size_t i = 0; i < field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - if (upb_FieldDef_IsSubMessage(f)) { - sublayout_count++; - } - if (upb_FieldDef_CType(f) == kUpb_CType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2) { - sublayout_count++; - } - } + f->full_name = full_name; + f->json_name = json_name; + f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); + f->number_ = field_number; + f->scope.oneof = NULL; + f->proto3_optional_ = + google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); - fields = symtab_alloc(ctx, field_count * sizeof(*fields)); - subs = symtab_alloc(ctx, sublayout_count * sizeof(*subs)); + bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); + bool has_type_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); - l->field_count = upb_MessageDef_numfields(m); - l->fields = fields; - l->subs = subs; - l->table_mask = 0; - l->required_count = 0; + f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); - if (upb_MessageDef_ExtensionRangeCount(m) > 0) { - if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { - l->ext = upb_ExtMode_IsMessageSet; - } else { - l->ext = upb_ExtMode_Extendable; + if (has_type) { + switch (f->type_) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + if (!has_type_name) { + symtab_errf(ctx, "field of type %d requires type name (%s)", + (int)f->type_, full_name); + } + break; + default: + if (has_type_name) { + symtab_errf(ctx, "invalid type for field with type_name set (%s, %d)", + full_name, (int)f->type_); + } } - } else { - l->ext = upb_ExtMode_NonExtendable; + } else if (has_type_name) { + f->type_ = + FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef(). } - /* TODO(haberman): initialize fast tables so that reflection-based parsing - * can get the same speeds as linked-in types. */ - l->fasttable[0].field_parser = &fastdecode_generic; - l->fasttable[0].field_data = 0; - - if (upb_MessageDef_IsMapEntry(m)) { - /* TODO(haberman): refactor this method so this special case is more - * elegant. */ - const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2); - fields[0].number = 1; - fields[1].number = 2; - fields[0].mode = kUpb_FieldMode_Scalar; - fields[1].mode = kUpb_FieldMode_Scalar; - fields[0].presence = 0; - fields[1].presence = 0; - fields[0].descriptortype = map_descriptortype(key); - fields[1].descriptortype = map_descriptortype(val); - fields[0].offset = 0; - fields[1].offset = sizeof(upb_StringView); - fields[1].submsg_index = 0; + if (!is_extension) { + /* direct message field. */ + upb_value v, field_v, json_v, existing_v; + size_t json_size; - if (upb_FieldDef_CType(val) == kUpb_CType_Message) { - subs[0].submsg = upb_FieldDef_MessageSubDef(val)->layout; + if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { + symtab_errf(ctx, "invalid field number (%u)", field_number); } - upb_FieldDef* fielddefs = (upb_FieldDef*)&m->fields[0]; - UPB_ASSERT(fielddefs[0].number_ == 1); - UPB_ASSERT(fielddefs[1].number_ == 2); - fielddefs[0].layout_index = 0; - fielddefs[1].layout_index = 1; + f->index_ = f - m->fields; + f->msgdef = m; + f->is_extension_ = false; - l->field_count = 2; - l->size = 2 * sizeof(upb_StringView); - l->size = UPB_ALIGN_UP(l->size, 8); - l->dense_below = 2; - return; - } + field_v = pack_def(f, UPB_DEFTYPE_FIELD); + json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME); + v = upb_value_constptr(f); + json_size = strlen(json_name); - /* 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. - */ + if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { + symtab_errf(ctx, "duplicate field name (%s)", shortname); + } - /* Assign hasbits for required fields first. */ - size_t hasbit = 0; + CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v, + ctx->arena)); - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - field->presence = ++hasbit; - if (hasbit >= 63) { - symtab_errf(ctx, "Message with >=63 required fields: %s", - upb_MessageDef_FullName(m)); + if (strcmp(shortname, json_name) != 0) { + if (upb_strtable_lookup(&m->ntof, json_name, &v)) { + symtab_errf(ctx, "duplicate json_name (%s)", json_name); + } else { + CHK_OOM(upb_strtable_insert(&m->ntof, json_name, json_size, json_v, + ctx->arena)); } - l->required_count++; } - } - /* Allocate hasbits and set basic field attributes. */ - sublayout_count = 0; - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + symtab_errf(ctx, "duplicate field number (%u)", field_number); + } - fill_fieldlayout(field, f); + CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena)); - if (upb_FieldDef_IsSubMessage(f)) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout; - } else if (upb_FieldDef_CType(f) == kUpb_CType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout; - UPB_ASSERT(subs[field->submsg_index].subenum); + if (ctx->layout) { + const upb_MiniTable_Field* fields = m->layout->fields; + int count = m->layout->field_count; + bool found = false; + for (int i = 0; i < count; i++) { + if (fields[i].number == field_number) { + f->layout_index = i; + found = true; + break; + } + } + UPB_ASSERT(found); } - - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - /* Hasbit was already assigned. */ - } else if (upb_FieldDef_HasPresence(f) && - !upb_FieldDef_RealContainingOneof(f)) { - /* We don't use hasbit 0, so that 0 can indicate "no presence" in the - * table. This wastes one hasbit, but we don't worry about it for now. */ - field->presence = ++hasbit; - } else { - field->presence = 0; + } else { + /* extension field. */ + f->is_extension_ = true; + f->scope.extension_scope = m; + symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_EXT)); + f->layout_index = ctx->ext_count++; + if (ctx->layout) { + UPB_ASSERT(ctx->file->ext_layouts[f->layout_index]->field.number == + field_number); } } - /* Account for space used by hasbits. */ - l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0; + if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { + symtab_errf(ctx, "invalid type for field %s (%d)", f->full_name, f->type_); + } - /* Allocate non-oneof fields. */ - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - size_t field_size = upb_msg_fielddefsize(f); - size_t index = upb_FieldDef_Index(f); + if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { + symtab_errf(ctx, "invalid label for field %s (%d)", f->full_name, + f->label_); + } - if (upb_FieldDef_RealContainingOneof(f)) { - /* Oneofs are handled separately below. */ - continue; - } + /* We can't resolve the subdef or (in the case of extensions) the containing + * message yet, because it may not have been defined yet. We stash a pointer + * to the field_proto until later when we can properly resolve it. */ + f->sub.unresolved = field_proto; - fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m); + if (f->label_ == kUpb_Label_Required && + f->file->syntax == kUpb_Syntax_Proto3) { + symtab_errf(ctx, "proto3 fields cannot be required (%s)", f->full_name); } - /* Allocate oneof fields. Each oneof field consists of a uint32 for the case - * and space for the actual data. */ - for (int i = 0; i < m->oneof_count; i++) { - const upb_OneofDef* o = &m->oneofs[i]; - size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ - size_t field_size = 0; - uint32_t case_offset; - uint32_t data_offset; + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); + upb_OneofDef* oneof; + upb_value v = upb_value_constptr(f); - if (upb_OneofDef_IsSynthetic(o)) continue; + if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { + symtab_errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } - if (o->field_count == 0) { - symtab_errf(ctx, "Oneof must have at least one field (%s)", o->full_name); + if (!m) { + symtab_errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); } - /* Calculate field size: the max of all field sizes. */ - for (int j = 0; j < o->field_count; j++) { - const upb_FieldDef* f = o->fields[j]; - field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); + if (oneof_index >= m->oneof_count) { + symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name); } - /* Align and allocate case offset. */ - case_offset = upb_MiniTable_place(ctx, l, case_size, m); - data_offset = upb_MiniTable_place(ctx, l, field_size, m); + oneof = (upb_OneofDef*)&m->oneofs[oneof_index]; + f->scope.oneof = oneof; - for (int i = 0; i < o->field_count; i++) { - const upb_FieldDef* f = o->fields[i]; - fields[upb_FieldDef_Index(f)].offset = data_offset; - fields[upb_FieldDef_Index(f)].presence = ~case_offset; + oneof->field_count++; + if (f->proto3_optional_) { + oneof->synthetic = true; + } + CHK_OOM(upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena)); + CHK_OOM( + upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); + } else { + if (f->proto3_optional_) { + symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)", + f->full_name); } } - /* Size of the entire structure should be a multiple of its greatest - * alignment. TODO: track overall alignment for real? */ - l->size = UPB_ALIGN_UP(l->size, 8); + SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); - /* Sort fields by number. */ - if (fields) { - qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), - field_number_cmp); + if (google_protobuf_FieldOptions_has_packed(f->opts)) { + f->packed_ = google_protobuf_FieldOptions_packed(f->opts); + } else { + /* Repeated fields default to packed for proto3 only. */ + f->packed_ = upb_FieldDef_IsPrimitive(f) && + f->label_ == kUpb_Label_Repeated && + f->file->syntax == kUpb_Syntax_Proto3; } - assign_layout_indices(m, l, fields); } -static char* strviewdup(symtab_addctx* ctx, upb_StringView view) { - char* ret = upb_strdup2(view.data, view.size, ctx->arena); - CHK_OOM(ret); - return ret; -} +static void create_service( + symtab_addctx* ctx, const google_protobuf_ServiceDescriptorProto* svc_proto, + const upb_ServiceDef* _s) { + upb_ServiceDef* s = (upb_ServiceDef*)_s; + upb_StringView name; + const google_protobuf_MethodDescriptorProto* const* methods; + size_t i, n; -static bool streql2(const char* a, size_t n, const char* b) { - return n == strlen(b) && memcmp(a, b, n) == 0; -} + s->file = ctx->file; /* Must happen prior to symtab_add. */ -static bool streql_view(upb_StringView view, const char* b) { - return streql2(view.data, view.size, b); + name = google_protobuf_ServiceDescriptorProto_name(svc_proto); + check_ident(ctx, name, false); + s->full_name = makefullname(ctx, ctx->file->package, name); + symtab_add(ctx, s->full_name, pack_def(s, UPB_DEFTYPE_SERVICE)); + + methods = google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); + + s->method_count = n; + s->methods = symtab_alloc(ctx, sizeof(*s->methods) * n); + + SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, svc_proto); + + for (i = 0; i < n; i++) { + const google_protobuf_MethodDescriptorProto* method_proto = methods[i]; + upb_MethodDef* m = (upb_MethodDef*)&s->methods[i]; + upb_StringView name = + google_protobuf_MethodDescriptorProto_name(method_proto); + + m->service = s; + m->full_name = makefullname(ctx, s->full_name, name); + m->index = i; + m->client_streaming = + google_protobuf_MethodDescriptorProto_client_streaming(method_proto); + m->server_streaming = + google_protobuf_MethodDescriptorProto_server_streaming(method_proto); + m->input_type = symtab_resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_input_type(method_proto), + UPB_DEFTYPE_MSG); + m->output_type = symtab_resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_output_type(method_proto), + UPB_DEFTYPE_MSG); + + SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, method_proto); + } } -static const char* makefullname(symtab_addctx* ctx, const char* prefix, - upb_StringView name) { - if (prefix) { - /* ret = prefix + '.' + name; */ - size_t n = strlen(prefix); - char* ret = symtab_alloc(ctx, n + name.size + 2); - strcpy(ret, prefix); - ret[n] = '.'; - memcpy(&ret[n + 1], name.data, name.size); - ret[n + 1 + name.size] = '\0'; - return ret; - } else { - return strviewdup(ctx, name); +static int count_bits_debug(uint64_t x) { + // For assertions only, speed does not matter. + int n = 0; + while (x) { + if (x & 1) n++; + x >>= 1; } + return n; } -static void finalize_oneofs(symtab_addctx* ctx, upb_MessageDef* m) { - int i; - int synthetic_count = 0; - upb_OneofDef* mutable_oneofs = (upb_OneofDef*)m->oneofs; +static int compare_int32(const void* a_ptr, const void* b_ptr) { + int32_t a = *(int32_t*)a_ptr; + int32_t b = *(int32_t*)b_ptr; + return a < b ? -1 : (a == b ? 0 : 1); +} - for (i = 0; i < m->oneof_count; i++) { - upb_OneofDef* o = &mutable_oneofs[i]; +upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, + const upb_EnumDef* e) { + int n = 0; + uint64_t mask = 0; - if (o->synthetic && o->field_count != 1) { - symtab_errf(ctx, "Synthetic oneofs must have one field, not %d: %s", - o->field_count, upb_OneofDef_Name(o)); + for (int i = 0; i < e->value_count; i++) { + uint32_t val = (uint32_t)e->values[i].number; + if (val < 64) { + mask |= 1ULL << val; + } else { + n++; } + } - if (o->synthetic) { - synthetic_count++; - } else if (synthetic_count != 0) { - symtab_errf(ctx, "Synthetic oneofs must be after all other oneofs: %s", - upb_OneofDef_Name(o)); - } + int32_t* values = symtab_alloc(ctx, sizeof(*values) * n); - o->fields = symtab_alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); - o->field_count = 0; - } + if (n) { + int32_t* p = values; - for (i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); - if (o) { - o->fields[o->field_count++] = f; + // Add values outside the bitmask range to the list, as described in the + // comments for upb_MiniTable_Enum. + for (int i = 0; i < e->value_count; i++) { + int32_t val = e->values[i].number; + if ((uint32_t)val >= 64) { + *p++ = val; + } } + UPB_ASSERT(p == values + n); } - m->real_oneof_count = m->oneof_count - synthetic_count; -} + // Enums can have duplicate values; we must sort+uniq them. + if (values) qsort(values, n, sizeof(*values), &compare_int32); -size_t getjsonname(const char* name, char* buf, size_t len) { - size_t src, dst = 0; - bool ucase_next = false; + int dst = 0; + for (int i = 0; i < n; dst++) { + int32_t val = values[i]; + while (i < n && values[i] == val) i++; // Skip duplicates. + values[dst] = val; + } + n = dst; -#define WRITE(byte) \ - ++dst; \ - if (dst < len) \ - buf[dst - 1] = byte; \ - else if (dst == len) \ - buf[dst - 1] = '\0' + UPB_ASSERT(upb_inttable_count(&e->iton) == n + count_bits_debug(mask)); - if (!name) { - WRITE('\0'); - return 0; - } + upb_MiniTable_Enum* layout = symtab_alloc(ctx, sizeof(*layout)); + layout->value_count = n; + layout->mask = mask; + layout->values = values; - /* Implement the transformation as described in the spec: - * 1. upper case all letters after an underscore. - * 2. remove all underscores. - */ - for (src = 0; name[src]; src++) { - if (name[src] == '_') { - ucase_next = true; - continue; - } + return layout; +} - if (ucase_next) { - WRITE(toupper(name[src])); - ucase_next = false; - } else { - WRITE(name[src]); - } +static void create_enumvaldef( + symtab_addctx* ctx, const char* prefix, + const google_protobuf_EnumValueDescriptorProto* val_proto, upb_EnumDef* e, + int i) { + upb_EnumValueDef* val = (upb_EnumValueDef*)&e->values[i]; + upb_StringView name = + google_protobuf_EnumValueDescriptorProto_name(val_proto); + upb_value v = upb_value_constptr(val); + + val->parent = e; /* Must happen prior to symtab_add(). */ + val->full_name = makefullname(ctx, prefix, name); + val->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); + symtab_add(ctx, val->full_name, pack_def(val, UPB_DEFTYPE_ENUMVAL)); + + SET_OPTIONS(val->opts, EnumValueDescriptorProto, EnumValueOptions, val_proto); + + if (i == 0 && e->file->syntax == kUpb_Syntax_Proto3 && val->number != 0) { + symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)", + e->full_name); } - WRITE('\0'); - return dst; - -#undef WRITE -} + CHK_OOM(upb_strtable_insert(&e->ntoi, name.data, name.size, v, ctx->arena)); -static char* makejsonname(symtab_addctx* ctx, const char* name) { - size_t size = getjsonname(name, NULL, 0); - char* json_name = symtab_alloc(ctx, size); - getjsonname(name, json_name, size); - return json_name; + // Multiple enumerators can have the same number, first one wins. + if (!upb_inttable_lookup(&e->iton, val->number, NULL)) { + CHK_OOM(upb_inttable_insert(&e->iton, val->number, v, ctx->arena)); + } } -/* Adds a symbol |v| to the symtab, which must be a def pointer previously - * packed with pack_def(). The def's pointer to upb_FileDef* must be set before - * adding, so we know which entries to remove if building this file fails. */ -static void symtab_add(symtab_addctx* ctx, const char* name, upb_value v) { - // TODO: table should support an operation "tryinsert" to avoid the double - // lookup. - if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { - symtab_errf(ctx, "duplicate symbol '%s'", name); +static upb_StringView* _upb_EnumReservedNames_New( + symtab_addctx* ctx, int n, const upb_StringView* protos) { + upb_StringView* sv = + upb_Arena_Malloc(ctx->arena, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, ctx->arena); + sv[i].size = protos[i].size; } - size_t len = strlen(name); - CHK_OOM(upb_strtable_insert(&ctx->symtab->syms, name, len, v, - ctx->symtab->arena)); + return sv; } -static bool remove_component(char* base, size_t* len) { - if (*len == 0) return false; +static void create_enumdef( + symtab_addctx* ctx, const char* prefix, + const google_protobuf_EnumDescriptorProto* enum_proto, + const upb_MessageDef* containing_type, const upb_EnumDef* _e) { + upb_EnumDef* e = (upb_EnumDef*)_e; + ; + const google_protobuf_EnumValueDescriptorProto* const* values; + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* res_ranges; + const upb_StringView* res_names; + upb_StringView name; + size_t i, n, n_res_range, n_res_name; - for (size_t i = *len - 1; i > 0; i--) { - if (base[i] == '.') { - *len = i; - return true; - } - } + e->file = ctx->file; /* Must happen prior to symtab_add() */ + e->containing_type = containing_type; - *len = 0; - return true; -} + name = google_protobuf_EnumDescriptorProto_name(enum_proto); + check_ident(ctx, name, false); -/* Given a symbol and the base symbol inside which it is defined, find the - * symbol's definition in t. */ -static const void* symtab_resolveany(symtab_addctx* ctx, - const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t* type) { - const upb_strtable* t = &ctx->symtab->syms; - if (sym.size == 0) goto notfound; - upb_value v; - if (sym.data[0] == '.') { - /* Symbols starting with '.' are absolute, so we do a single lookup. - * Slice to omit the leading '.' */ - if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) { - goto notfound; - } - } else { - /* Remove components from base until we find an entry or run out. */ - size_t baselen = base ? strlen(base) : 0; - char* tmp = malloc(sym.size + baselen + 1); - while (1) { - char* p = tmp; - if (baselen) { - memcpy(p, base, baselen); - p[baselen] = '.'; - p += baselen + 1; - } - memcpy(p, sym.data, sym.size); - p += sym.size; - if (upb_strtable_lookup2(t, tmp, p - tmp, &v)) { - break; - } - if (!remove_component(tmp, &baselen)) { - free(tmp); - goto notfound; - } - } - free(tmp); - } + e->full_name = makefullname(ctx, prefix, name); + symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); - *type = deftype(v); - return unpack_def(v, *type); + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); + CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena)); + CHK_OOM(upb_inttable_init(&e->iton, ctx->arena)); -notfound: - symtab_errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(sym)); -} + e->defaultval = 0; + e->value_count = n; + e->values = symtab_alloc(ctx, sizeof(*e->values) * n); -static const void* symtab_resolve(symtab_addctx* ctx, const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t type) { - upb_deftype_t found_type; - const void* ret = - symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type); - if (ret && found_type != type) { - symtab_errf(ctx, - "type mismatch when resolving %s: couldn't find " - "name " UPB_STRINGVIEW_FORMAT " with type=%d", - from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); + if (n == 0) { + symtab_errf(ctx, "enums must contain at least one value (%s)", + e->full_name); } - return ret; -} -static void create_oneofdef( - symtab_addctx* ctx, upb_MessageDef* m, - const google_protobuf_OneofDescriptorProto* oneof_proto, - const upb_OneofDef* _o) { - upb_OneofDef* o = (upb_OneofDef*)_o; - upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); - upb_value v; + res_ranges = + google_protobuf_EnumDescriptorProto_reserved_range(enum_proto, &n_res_range); + e->res_range_count = n_res_range; + e->res_ranges = _upb_EnumReservedRanges_New(ctx, n_res_range, res_ranges, e); - o->parent = m; - o->full_name = makefullname(ctx, m->full_name, name); - o->field_count = 0; - o->synthetic = false; + res_names = google_protobuf_EnumDescriptorProto_reserved_name(enum_proto, &n_res_name); + e->res_name_count = n_res_name; + e->res_names = _upb_EnumReservedNames_New(ctx, n_res_name, res_names); - SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); - upb_value existing_v; - if (upb_strtable_lookup2(&m->ntof, name.data, name.size, &existing_v)) { - symtab_errf(ctx, "duplicate oneof name (%s)", o->full_name); + for (i = 0; i < n; i++) { + create_enumvaldef(ctx, prefix, values[i], e, i); } - v = pack_def(o, UPB_DEFTYPE_ONEOF); - CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); - - CHK_OOM(upb_inttable_init(&o->itof, ctx->arena)); - CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena)); -} + upb_inttable_compact(&e->iton, ctx->arena); -static str_t* newstr(symtab_addctx* ctx, const char* data, size_t len) { - str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); - CHK_OOM(ret); - ret->len = len; - if (len) memcpy(ret->str, data, len); - ret->str[len] = '\0'; - return ret; + if (e->file->syntax == kUpb_Syntax_Proto2) { + if (ctx->layout) { + UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); + e->layout = ctx->layout->enums[ctx->enum_count++]; + UPB_ASSERT(upb_inttable_count(&e->iton) == + e->layout->value_count + count_bits_debug(e->layout->mask)); + } else { + e->layout = create_enumlayout(ctx, e); + } + } else { + e->layout = NULL; + } } -static bool upb_DefPool_TryGetChar(const char** src, const char* end, - char* ch) { - if (*src == end) return false; - *ch = **src; - *src += 1; - return true; -} +static void msgdef_create_nested( + symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, + upb_MessageDef* m); -static char upb_DefPool_TryGetHexDigit(symtab_addctx* ctx, - const upb_FieldDef* f, const char** src, - const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '9') { - return ch - '0'; - } - ch = upb_ascii_lower(ch); - if ('a' <= ch && ch <= 'f') { - return ch - 'a' + 0xa; +static upb_StringView* _upb_ReservedNames_New(symtab_addctx* ctx, int n, + const upb_StringView* protos) { + upb_StringView* sv = upb_Arena_Malloc(ctx->arena, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, ctx->arena); + sv[i].size = protos[i].size; } - *src -= 1; // Char wasn't actually a hex digit. - return -1; + return sv; } -static char upb_DefPool_ParseHexEscape(symtab_addctx* ctx, - const upb_FieldDef* f, const char** src, - const char* end) { - char hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end); - if (hex_digit < 0) { - symtab_errf(ctx, - "\\x cannot be followed by non-hex digit in field '%s' default", - upb_FieldDef_FullName(f)); - return 0; - } - unsigned int ret = hex_digit; - while ((hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end)) >= 0) { - ret = (ret << 4) | hex_digit; - } - if (ret > 0xff) { - symtab_errf(ctx, "Value of hex escape in field %s exceeds 8 bits", - upb_FieldDef_FullName(f)); - return 0; - } - return ret; -} +static void create_msgdef(symtab_addctx* ctx, const char* prefix, + const google_protobuf_DescriptorProto* msg_proto, + const upb_MessageDef* containing_type, + const upb_MessageDef* _m) { + upb_MessageDef* m = (upb_MessageDef*)_m; + const google_protobuf_OneofDescriptorProto* const* oneofs; + const google_protobuf_FieldDescriptorProto* const* fields; + const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; -char upb_DefPool_TryGetOctalDigit(const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '7') { - return ch - '0'; - } - *src -= 1; // Char wasn't actually an octal digit. - return -1; -} + const google_protobuf_DescriptorProto_ReservedRange* const* res_ranges; + const upb_StringView* res_names; + size_t i, n_oneof, n_field, n_ext_range; + size_t n_res_range, n_res_name; + upb_StringView name; -static char upb_DefPool_ParseOctalEscape(symtab_addctx* ctx, - const upb_FieldDef* f, - const char** src, const char* end) { - char ch = 0; - for (int i = 0; i < 3; i++) { - char digit; - if ((digit = upb_DefPool_TryGetOctalDigit(src, end)) >= 0) { - ch = (ch << 3) | digit; - } + m->file = ctx->file; /* Must happen prior to symtab_add(). */ + m->containing_type = containing_type; + + name = google_protobuf_DescriptorProto_name(msg_proto); + check_ident(ctx, name, false); + + m->full_name = makefullname(ctx, prefix, name); + symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG)); + + oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); + fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); + ext_ranges = + google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); + res_ranges = google_protobuf_DescriptorProto_reserved_range(msg_proto, &n_res_range); + res_names = google_protobuf_DescriptorProto_reserved_name(msg_proto, &n_res_name); + + CHK_OOM(upb_inttable_init(&m->itof, ctx->arena)); + CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena)); + + if (ctx->layout) { + /* create_fielddef() below depends on this being set. */ + UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count); + m->layout = ctx->layout->msgs[ctx->msg_count++]; + UPB_ASSERT(n_field == m->layout->field_count); + } else { + /* Allocate now (to allow cross-linking), populate later. */ + m->layout = + symtab_alloc(ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); } - return ch; -} -static char upb_DefPool_ParseEscape(symtab_addctx* ctx, const upb_FieldDef* f, - const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) { - symtab_errf(ctx, "unterminated escape sequence in field %s", - upb_FieldDef_FullName(f)); - return 0; + SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); + + m->oneof_count = n_oneof; + m->oneofs = symtab_alloc(ctx, sizeof(*m->oneofs) * n_oneof); + for (i = 0; i < n_oneof; i++) { + create_oneofdef(ctx, m, oneofs[i], &m->oneofs[i]); } - switch (ch) { - case 'a': - return '\a'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - case 'v': - return '\v'; - case '\\': - return '\\'; - case '\'': - return '\''; - case '\"': - return '\"'; - case '?': - return '\?'; - case 'x': - case 'X': - return upb_DefPool_ParseHexEscape(ctx, f, src, end); - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - *src -= 1; - return upb_DefPool_ParseOctalEscape(ctx, f, src, end); + + m->field_count = n_field; + m->fields = symtab_alloc(ctx, sizeof(*m->fields) * n_field); + for (i = 0; i < n_field; i++) { + create_fielddef(ctx, m->full_name, m, fields[i], &m->fields[i], + /* is_extension= */ false); } - symtab_errf(ctx, "Unknown escape sequence: \\%c", ch); -} -static str_t* unescape(symtab_addctx* ctx, const upb_FieldDef* f, - const char* data, size_t len) { - // Size here is an upper bound; escape sequences could ultimately shrink it. - str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); - char* dst = &ret->str[0]; - const char* src = data; - const char* end = data + len; + m->ext_range_count = n_ext_range; + m->ext_ranges = symtab_alloc(ctx, sizeof(*m->ext_ranges) * n_ext_range); + for (i = 0; i < n_ext_range; i++) { + const google_protobuf_DescriptorProto_ExtensionRange* r = ext_ranges[i]; + upb_ExtensionRange* r_def = (upb_ExtensionRange*)&m->ext_ranges[i]; + int32_t start = google_protobuf_DescriptorProto_ExtensionRange_start(r); + int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(r); + int32_t max = + google_protobuf_MessageOptions_message_set_wire_format(m->opts) + ? INT32_MAX + : kUpb_MaxFieldNumber + 1; - while (src < end) { - if (*src == '\\') { - src++; - *dst++ = upb_DefPool_ParseEscape(ctx, f, &src, end); - } else { - *dst++ = *src++; + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + symtab_errf(ctx, "Extension range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, m->full_name); } + + r_def->start = start; + r_def->end = end; + SET_OPTIONS(r_def->opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, r); } - ret->len = dst - &ret->str[0]; - return ret; + m->res_range_count = n_res_range; + m->res_ranges = + _upb_MessageReservedRanges_New(ctx, n_res_range, res_ranges, m); + + m->res_name_count = n_res_name; + m->res_names = _upb_ReservedNames_New(ctx, n_res_name, res_names); + + finalize_oneofs(ctx, m); + assign_msg_wellknowntype(m); + upb_inttable_compact(&m->itof, ctx->arena); + msgdef_create_nested(ctx, msg_proto, m); } -static void parse_default(symtab_addctx* ctx, const char* str, size_t len, - upb_FieldDef* f) { - char* end; - char nullz[64]; - errno = 0; +static void msgdef_create_nested( + symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, + upb_MessageDef* m) { + size_t n; - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - case kUpb_CType_UInt32: - case kUpb_CType_UInt64: - case kUpb_CType_Double: - case kUpb_CType_Float: - /* Standard C number parsing functions expect null-terminated strings. */ - if (len >= sizeof(nullz) - 1) { - symtab_errf(ctx, "Default too long: %.*s", (int)len, str); - } - memcpy(nullz, str, len); - nullz[len] = '\0'; - str = nullz; - break; - default: - break; + const google_protobuf_EnumDescriptorProto* const* enums = + google_protobuf_DescriptorProto_enum_type(msg_proto, &n); + m->nested_enum_count = n; + m->nested_enums = symtab_alloc(ctx, sizeof(*m->nested_enums) * n); + for (size_t i = 0; i < n; i++) { + m->nested_enum_count = i + 1; + create_enumdef(ctx, m->full_name, enums[i], m, &m->nested_enums[i]); } - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: { - long val = strtol(str, &end, 0); - if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.sint = val; - break; - } - case kUpb_CType_Enum: { - const upb_EnumDef* e = f->sub.enumdef; - const upb_EnumValueDef* ev = - upb_EnumDef_FindValueByNameWithSize(e, str, len); - if (!ev) { - goto invalid; - } - f->defaultval.sint = ev->number; - break; - } - case kUpb_CType_Int64: { - long long val = strtoll(str, &end, 0); - if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.sint = val; - break; - } - case kUpb_CType_UInt32: { - unsigned long val = strtoul(str, &end, 0); - if (val > UINT32_MAX || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.uint = val; - break; - } - case kUpb_CType_UInt64: { - unsigned long long val = strtoull(str, &end, 0); - if (val > UINT64_MAX || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.uint = val; - break; - } - case kUpb_CType_Double: { - double val = strtod(str, &end); - if (errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.dbl = val; - break; - } - case kUpb_CType_Float: { - float val = strtof(str, &end); - if (errno == ERANGE || *end) { - goto invalid; + const google_protobuf_FieldDescriptorProto* const* exts = + google_protobuf_DescriptorProto_extension(msg_proto, &n); + m->nested_ext_count = n; + m->nested_exts = symtab_alloc(ctx, sizeof(*m->nested_exts) * n); + for (size_t i = 0; i < n; i++) { + create_fielddef(ctx, m->full_name, m, exts[i], &m->nested_exts[i], + /* is_extension= */ true); + ((upb_FieldDef*)&m->nested_exts[i])->index_ = i; + } + + const google_protobuf_DescriptorProto* const* msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + m->nested_msg_count = n; + m->nested_msgs = symtab_alloc(ctx, sizeof(*m->nested_msgs) * n); + for (size_t i = 0; i < n; i++) { + create_msgdef(ctx, m->full_name, msgs[i], m, &m->nested_msgs[i]); + } +} + +static void resolve_subdef(symtab_addctx* ctx, const char* prefix, + upb_FieldDef* f) { + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; + upb_StringView name = + google_protobuf_FieldDescriptorProto_type_name(field_proto); + bool has_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); + switch ((int)f->type_) { + case FIELD_TYPE_UNSPECIFIED: { + // Type was not specified and must be inferred. + UPB_ASSERT(has_name); + upb_deftype_t type; + const void* def = + symtab_resolveany(ctx, f->full_name, prefix, name, &type); + switch (type) { + case UPB_DEFTYPE_ENUM: + f->sub.enumdef = def; + f->type_ = kUpb_FieldType_Enum; + break; + case UPB_DEFTYPE_MSG: + f->sub.msgdef = def; + f->type_ = kUpb_FieldType_Message; // It appears there is no way of + // this being a group. + break; + default: + symtab_errf(ctx, "Couldn't resolve type name for field %s", + f->full_name); } - f->defaultval.flt = val; - break; } - case kUpb_CType_Bool: { - if (streql2(str, len, "false")) { - f->defaultval.boolean = false; - } else if (streql2(str, len, "true")) { - f->defaultval.boolean = true; - } else { - goto invalid; - } + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + UPB_ASSERT(has_name); + f->sub.msgdef = + symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); break; - } - case kUpb_CType_String: - f->defaultval.str = newstr(ctx, str, len); + case kUpb_FieldType_Enum: + UPB_ASSERT(has_name); + f->sub.enumdef = + symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_ENUM); break; - case kUpb_CType_Bytes: - f->defaultval.str = unescape(ctx, f, str, len); + default: + // No resolution necessary. break; - case kUpb_CType_Message: - /* Should not have a default value. */ - symtab_errf(ctx, "Message should not have a default (%s)", - upb_FieldDef_FullName(f)); } - - return; - -invalid: - symtab_errf(ctx, "Invalid default '%.*s' for field %s of type %d", (int)len, - str, upb_FieldDef_FullName(f), (int)upb_FieldDef_Type(f)); } -static void set_default_default(symtab_addctx* ctx, upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - f->defaultval.sint = 0; - break; - case kUpb_CType_UInt64: - case kUpb_CType_UInt32: - f->defaultval.uint = 0; - break; - case kUpb_CType_Double: - case kUpb_CType_Float: - f->defaultval.dbl = 0; - break; - case kUpb_CType_String: - case kUpb_CType_Bytes: - f->defaultval.str = newstr(ctx, NULL, 0); - break; - case kUpb_CType_Bool: - f->defaultval.boolean = false; - break; - case kUpb_CType_Enum: - f->defaultval.sint = f->sub.enumdef->values[0].number; - case kUpb_CType_Message: - break; +static void resolve_extension( + symtab_addctx* ctx, const char* prefix, upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { + symtab_errf(ctx, "extension for field '%s' had no extendee", f->full_name); } -} -static void create_fielddef( - symtab_addctx* ctx, const char* prefix, upb_MessageDef* m, - const google_protobuf_FieldDescriptorProto* field_proto, - const upb_FieldDef* _f, bool is_extension) { - upb_FieldDef* f = (upb_FieldDef*)_f; - upb_StringView name; - const char* full_name; - const char* json_name; - const char* shortname; - int32_t field_number; + upb_StringView name = + google_protobuf_FieldDescriptorProto_extendee(field_proto); + const upb_MessageDef* m = + symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); + f->msgdef = m; - f->file = ctx->file; /* Must happen prior to symtab_add(). */ + bool found = false; - if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - symtab_errf(ctx, "field has no name"); + for (int i = 0, n = m->ext_range_count; i < n; i++) { + const upb_ExtensionRange* r = &m->ext_ranges[i]; + if (r->start <= f->number_ && f->number_ < r->end) { + found = true; + break; + } } - name = google_protobuf_FieldDescriptorProto_name(field_proto); - check_ident(ctx, name, false); - full_name = makefullname(ctx, prefix, name); - shortname = shortdefname(full_name); + if (!found) { + symtab_errf(ctx, + "field number %u in extension %s has no extension range in " + "message %s", + (unsigned)f->number_, f->full_name, f->msgdef->full_name); + } - if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { - json_name = strviewdup( - ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto)); - f->has_json_name_ = true; + const upb_MiniTable_Extension* ext = ctx->file->ext_layouts[f->layout_index]; + if (ctx->layout) { + UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); } else { - json_name = makejsonname(ctx, shortname); - f->has_json_name_ = false; + upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; + fill_fieldlayout(&mut_ext->field, f); + mut_ext->field.presence = 0; + mut_ext->field.offset = 0; + mut_ext->field.submsg_index = 0; + mut_ext->extendee = f->msgdef->layout; + mut_ext->sub.submsg = f->sub.msgdef->layout; } - field_number = google_protobuf_FieldDescriptorProto_number(field_proto); - - f->full_name = full_name; - f->json_name = json_name; - f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); - f->number_ = field_number; - f->scope.oneof = NULL; - f->proto3_optional_ = - google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + CHK_OOM(upb_inttable_insert(&ctx->symtab->exts, (uintptr_t)ext, + upb_value_constptr(f), ctx->arena)); +} - bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); - bool has_type_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); +static void resolve_default( + symtab_addctx* ctx, upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + // Have to delay resolving of the default value until now because of the enum + // case, since enum defaults are specified with a label. + if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { + upb_StringView defaultval = + google_protobuf_FieldDescriptorProto_default_value(field_proto); - f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); + if (f->file->syntax == kUpb_Syntax_Proto3) { + symtab_errf(ctx, "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } - if (has_type) { - switch (f->type_) { - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - case kUpb_FieldType_Enum: - if (!has_type_name) { - symtab_errf(ctx, "field of type %d requires type name (%s)", - (int)f->type_, full_name); - } - break; - default: - if (has_type_name) { - symtab_errf(ctx, "invalid type for field with type_name set (%s, %d)", - full_name, (int)f->type_); - } + if (upb_FieldDef_IsSubMessage(f)) { + symtab_errf(ctx, "message fields cannot have explicit defaults (%s)", + f->full_name); } - } else if (has_type_name) { - f->type_ = - FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef(). + + parse_default(ctx, defaultval.data, defaultval.size, f); + f->has_default = true; + } else { + set_default_default(ctx, f); + f->has_default = false; } +} - if (!is_extension) { - /* direct message field. */ - upb_value v, field_v, json_v, existing_v; - size_t json_size; +static void resolve_fielddef(symtab_addctx* ctx, const char* prefix, + upb_FieldDef* f) { + // We have to stash this away since resolve_subdef() may overwrite it. + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; - if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { - symtab_errf(ctx, "invalid field number (%u)", field_number); - } + resolve_subdef(ctx, prefix, f); + resolve_default(ctx, f, field_proto); - f->index_ = f - m->fields; - f->msgdef = m; - f->is_extension_ = false; + if (f->is_extension_) { + resolve_extension(ctx, prefix, f, field_proto); + } +} - field_v = pack_def(f, UPB_DEFTYPE_FIELD); - json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME); - v = upb_value_constptr(f); - json_size = strlen(json_name); +static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]); + } - if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { - symtab_errf(ctx, "duplicate field name (%s)", shortname); + m->in_message_set = false; + for (int i = 0; i < m->nested_ext_count; i++) { + upb_FieldDef* ext = (upb_FieldDef*)&m->nested_exts[i]; + resolve_fielddef(ctx, m->full_name, ext); + if (ext->type_ == kUpb_FieldType_Message && + ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m && + google_protobuf_MessageOptions_message_set_wire_format( + ext->msgdef->opts)) { + m->in_message_set = true; } + } - CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v, - ctx->arena)); + if (!ctx->layout) make_layout(ctx, m); - if (strcmp(shortname, json_name) != 0) { - if (upb_strtable_lookup(&m->ntof, json_name, &v)) { - symtab_errf(ctx, "duplicate json_name (%s)", json_name); - } else { - CHK_OOM(upb_strtable_insert(&m->ntof, json_name, json_size, json_v, - ctx->arena)); - } - } + for (int i = 0; i < m->nested_msg_count; i++) { + resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]); + } +} - if (upb_inttable_lookup(&m->itof, field_number, NULL)) { - symtab_errf(ctx, "duplicate field number (%u)", field_number); - } +static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { + size_t n; + google_protobuf_DescriptorProto_extension(msg_proto, &n); + int ext_count = n; - CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena)); + const google_protobuf_DescriptorProto* const* nested_msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + for (size_t i = 0; i < n; i++) { + ext_count += count_exts_in_msg(nested_msgs[i]); + } - if (ctx->layout) { - const upb_MiniTable_Field* fields = m->layout->fields; - int count = m->layout->field_count; - bool found = false; - for (int i = 0; i < count; i++) { - if (fields[i].number == field_number) { - f->layout_index = i; - found = true; - break; - } - } - UPB_ASSERT(found); + return ext_count; +} + +static void build_filedef( + symtab_addctx* ctx, upb_FileDef* file, + const google_protobuf_FileDescriptorProto* file_proto) { + const google_protobuf_DescriptorProto* const* msgs; + const google_protobuf_EnumDescriptorProto* const* enums; + const google_protobuf_FieldDescriptorProto* const* exts; + const google_protobuf_ServiceDescriptorProto* const* services; + const upb_StringView* strs; + const int32_t* public_deps; + const int32_t* weak_deps; + size_t i, n; + + file->symtab = ctx->symtab; + + /* Count all extensions in the file, to build a flat array of layouts. */ + google_protobuf_FileDescriptorProto_extension(file_proto, &n); + int ext_count = n; + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + for (int i = 0; i < n; i++) { + ext_count += count_exts_in_msg(msgs[i]); + } + file->ext_count = ext_count; + + if (ctx->layout) { + /* We are using the ext layouts that were passed in. */ + file->ext_layouts = ctx->layout->exts; + if (ctx->layout->ext_count != file->ext_count) { + symtab_errf(ctx, "Extension count did not match layout (%d vs %d)", + ctx->layout->ext_count, file->ext_count); } } else { - /* extension field. */ - f->is_extension_ = true; - f->scope.extension_scope = m; - symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_EXT)); - f->layout_index = ctx->ext_count++; - if (ctx->layout) { - UPB_ASSERT(ctx->file->ext_layouts[f->layout_index]->field.number == - field_number); + /* We are building ext layouts from scratch. */ + file->ext_layouts = + symtab_alloc(ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_MiniTable_Extension* ext = + symtab_alloc(ctx, sizeof(*ext) * file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; } } - if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { - symtab_errf(ctx, "invalid type for field %s (%d)", f->full_name, f->type_); + if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { + symtab_errf(ctx, "File has no name"); } - if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { - symtab_errf(ctx, "invalid label for field %s (%d)", f->full_name, - f->label_); + file->name = + strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); + + upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); + if (package.size) { + check_ident(ctx, package, true); + file->package = strviewdup(ctx, package); + } else { + file->package = NULL; } - /* We can't resolve the subdef or (in the case of extensions) the containing - * message yet, because it may not have been defined yet. We stash a pointer - * to the field_proto until later when we can properly resolve it. */ - f->sub.unresolved = field_proto; + if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { + upb_StringView syntax = + google_protobuf_FileDescriptorProto_syntax(file_proto); - if (f->label_ == kUpb_Label_Required && - f->file->syntax == kUpb_Syntax_Proto3) { - symtab_errf(ctx, "proto3 fields cannot be required (%s)", f->full_name); + if (streql_view(syntax, "proto2")) { + file->syntax = kUpb_Syntax_Proto2; + } else if (streql_view(syntax, "proto3")) { + file->syntax = kUpb_Syntax_Proto3; + } else { + symtab_errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(syntax)); + } + } else { + file->syntax = kUpb_Syntax_Proto2; } - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - int oneof_index = - google_protobuf_FieldDescriptorProto_oneof_index(field_proto); - upb_OneofDef* oneof; - upb_value v = upb_value_constptr(f); + /* Read options. */ + SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); - if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { - symtab_errf(ctx, "fields in oneof must have OPTIONAL label (%s)", - f->full_name); - } + /* Verify dependencies. */ + strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); + file->dep_count = n; + file->deps = symtab_alloc(ctx, sizeof(*file->deps) * n); - if (!m) { - symtab_errf(ctx, "oneof_index provided for extension field (%s)", - f->full_name); + for (i = 0; i < n; i++) { + upb_StringView str = strs[i]; + file->deps[i] = + upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); + if (!file->deps[i]) { + symtab_errf(ctx, + "Depends on file '" UPB_STRINGVIEW_FORMAT + "', but it has not been loaded", + UPB_STRINGVIEW_ARGS(str)); } + } - if (oneof_index >= m->oneof_count) { - symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name); + public_deps = + google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); + file->public_dep_count = n; + file->public_deps = symtab_alloc(ctx, sizeof(*file->public_deps) * n); + int32_t* mutable_public_deps = (int32_t*)file->public_deps; + for (i = 0; i < n; i++) { + if (public_deps[i] >= file->dep_count) { + symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]); } + mutable_public_deps[i] = public_deps[i]; + } - oneof = (upb_OneofDef*)&m->oneofs[oneof_index]; - f->scope.oneof = oneof; - - oneof->field_count++; - if (f->proto3_optional_) { - oneof->synthetic = true; - } - CHK_OOM(upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena)); - CHK_OOM( - upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); - } else { - if (f->proto3_optional_) { - symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)", - f->full_name); + weak_deps = + google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); + file->weak_dep_count = n; + file->weak_deps = symtab_alloc(ctx, sizeof(*file->weak_deps) * n); + int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; + for (i = 0; i < n; i++) { + if (weak_deps[i] >= file->dep_count) { + symtab_errf(ctx, "weak_dep %d is out of range", (int)weak_deps[i]); } + mutable_weak_deps[i] = weak_deps[i]; } - SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); - - if (google_protobuf_FieldOptions_has_packed(f->opts)) { - f->packed_ = google_protobuf_FieldOptions_packed(f->opts); - } else { - /* Repeated fields default to packed for proto3 only. */ - f->packed_ = upb_FieldDef_IsPrimitive(f) && - f->label_ == kUpb_Label_Repeated && - f->file->syntax == kUpb_Syntax_Proto3; + /* Create enums. */ + enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + file->top_lvl_enum_count = n; + file->top_lvl_enums = symtab_alloc(ctx, sizeof(*file->top_lvl_enums) * n); + for (i = 0; i < n; i++) { + create_enumdef(ctx, file->package, enums[i], NULL, &file->top_lvl_enums[i]); } -} - -static void create_service( - symtab_addctx* ctx, const google_protobuf_ServiceDescriptorProto* svc_proto, - const upb_ServiceDef* _s) { - upb_ServiceDef* s = (upb_ServiceDef*)_s; - upb_StringView name; - const google_protobuf_MethodDescriptorProto* const* methods; - size_t i, n; - - s->file = ctx->file; /* Must happen prior to symtab_add. */ - - name = google_protobuf_ServiceDescriptorProto_name(svc_proto); - check_ident(ctx, name, false); - s->full_name = makefullname(ctx, ctx->file->package, name); - symtab_add(ctx, s->full_name, pack_def(s, UPB_DEFTYPE_SERVICE)); - - methods = google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); - - s->method_count = n; - s->methods = symtab_alloc(ctx, sizeof(*s->methods) * n); - SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, svc_proto); + /* Create extensions. */ + exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->top_lvl_ext_count = n; + file->top_lvl_exts = symtab_alloc(ctx, sizeof(*file->top_lvl_exts) * n); + for (i = 0; i < n; i++) { + create_fielddef(ctx, file->package, NULL, exts[i], &file->top_lvl_exts[i], + /* is_extension= */ true); + ((upb_FieldDef*)&file->top_lvl_exts[i])->index_ = i; + } + /* Create messages. */ + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + file->top_lvl_msg_count = n; + file->top_lvl_msgs = symtab_alloc(ctx, sizeof(*file->top_lvl_msgs) * n); for (i = 0; i < n; i++) { - const google_protobuf_MethodDescriptorProto* method_proto = methods[i]; - upb_MethodDef* m = (upb_MethodDef*)&s->methods[i]; - upb_StringView name = - google_protobuf_MethodDescriptorProto_name(method_proto); + create_msgdef(ctx, file->package, msgs[i], NULL, &file->top_lvl_msgs[i]); + } - m->service = s; - m->full_name = makefullname(ctx, s->full_name, name); - m->index = i; - m->client_streaming = - google_protobuf_MethodDescriptorProto_client_streaming(method_proto); - m->server_streaming = - google_protobuf_MethodDescriptorProto_server_streaming(method_proto); - m->input_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_input_type(method_proto), - UPB_DEFTYPE_MSG); - m->output_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_output_type(method_proto), - UPB_DEFTYPE_MSG); + /* Create services. */ + services = google_protobuf_FileDescriptorProto_service(file_proto, &n); + file->service_count = n; + file->services = symtab_alloc(ctx, sizeof(*file->services) * n); + for (i = 0; i < n; i++) { + create_service(ctx, services[i], &file->services[i]); + ((upb_ServiceDef*)&file->services[i])->index = i; + } - SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, method_proto); + /* Now that all names are in the table, build layouts and resolve refs. */ + for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) { + resolve_fielddef(ctx, file->package, (upb_FieldDef*)&file->top_lvl_exts[i]); } -} -static int count_bits_debug(uint64_t x) { - // For assertions only, speed does not matter. - int n = 0; - while (x) { - if (x & 1) n++; - x >>= 1; + for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) { + resolve_msgdef(ctx, (upb_MessageDef*)&file->top_lvl_msgs[i]); } - return n; -} -static int compare_int32(const void* a_ptr, const void* b_ptr) { - int32_t a = *(int32_t*)a_ptr; - int32_t b = *(int32_t*)b_ptr; - return a < b ? -1 : (a == b ? 0 : 1); + if (file->ext_count) { + CHK_OOM(_upb_extreg_add(ctx->symtab->extreg, file->ext_layouts, + file->ext_count)); + } } -upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, - const upb_EnumDef* e) { - int n = 0; - uint64_t mask = 0; - - for (int i = 0; i < e->value_count; i++) { - uint32_t val = (uint32_t)e->values[i].number; - if (val < 64) { - mask |= 1ULL << val; - } else { - n++; +static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { + intptr_t iter = UPB_INTTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { + const upb_FileDef* f; + switch (deftype(val)) { + case UPB_DEFTYPE_EXT: + f = upb_FieldDef_File(unpack_def(val, UPB_DEFTYPE_EXT)); + break; + case UPB_DEFTYPE_MSG: + f = upb_MessageDef_File(unpack_def(val, UPB_DEFTYPE_MSG)); + break; + case UPB_DEFTYPE_ENUM: + f = upb_EnumDef_File(unpack_def(val, UPB_DEFTYPE_ENUM)); + break; + case UPB_DEFTYPE_ENUMVAL: + f = upb_EnumDef_File( + upb_EnumValueDef_Enum(unpack_def(val, UPB_DEFTYPE_ENUMVAL))); + break; + case UPB_DEFTYPE_SERVICE: + f = upb_ServiceDef_File(unpack_def(val, UPB_DEFTYPE_SERVICE)); + break; + default: + UPB_UNREACHABLE(); } - } - int32_t* values = symtab_alloc(ctx, sizeof(*values) * n); + if (f == file) upb_strtable_removeiter(&s->syms, &iter); + } +} - if (n) { - int32_t* p = values; +static const upb_FileDef* _upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + const upb_MiniTable_File* layout, upb_Status* status) { + symtab_addctx ctx; + upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); + upb_value v; - // Add values outside the bitmask range to the list, as described in the - // comments for upb_MiniTable_Enum. - for (int i = 0; i < e->value_count; i++) { - int32_t val = e->values[i].number; - if ((uint32_t)val >= 64) { - *p++ = val; - } + if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { + if (unpack_def(v, UPB_DEFTYPE_FILE)) { + upb_Status_SetErrorFormat(status, "duplicate file name (%.*s)", + UPB_STRINGVIEW_ARGS(name)); + return NULL; } - UPB_ASSERT(p == values + n); + const upb_MiniTable_File* registered = unpack_def(v, UPB_DEFTYPE_LAYOUT); + UPB_ASSERT(registered); + if (layout && layout != registered) { + upb_Status_SetErrorFormat( + status, "tried to build with a different layout (filename=%.*s)", + UPB_STRINGVIEW_ARGS(name)); + return NULL; + } + layout = registered; } - // Enums can have duplicate values; we must sort+uniq them. - if (values) qsort(values, n, sizeof(*values), &compare_int32); + ctx.symtab = s; + ctx.layout = layout; + ctx.msg_count = 0; + ctx.enum_count = 0; + ctx.ext_count = 0; + ctx.status = status; + ctx.file = NULL; + ctx.arena = upb_Arena_New(); + ctx.tmp_arena = upb_Arena_New(); - int dst = 0; - for (int i = 0; i < n; dst++) { - int32_t val = values[i]; - while (i < n && values[i] == val) i++; // Skip duplicates. - values[dst] = val; + if (!ctx.arena || !ctx.tmp_arena) { + if (ctx.arena) upb_Arena_Free(ctx.arena); + if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); + upb_Status_setoom(status); + return NULL; } - n = dst; - UPB_ASSERT(upb_inttable_count(&e->iton) == n + count_bits_debug(mask)); + if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) { + UPB_ASSERT(!upb_Status_IsOk(status)); + if (ctx.file) { + remove_filedef(s, ctx.file); + ctx.file = NULL; + } + } else { + ctx.file = symtab_alloc(&ctx, sizeof(*ctx.file)); + build_filedef(&ctx, ctx.file, file_proto); + upb_strtable_insert(&s->files, name.data, name.size, + pack_def(ctx.file, UPB_DEFTYPE_FILE), ctx.arena); + UPB_ASSERT(upb_Status_IsOk(status)); + upb_Arena_Fuse(s->arena, ctx.arena); + } - upb_MiniTable_Enum* layout = symtab_alloc(ctx, sizeof(*layout)); - layout->value_count = n; - layout->mask = mask; - layout->values = values; + upb_Arena_Free(ctx.arena); + upb_Arena_Free(ctx.tmp_arena); + return ctx.file; +} - return layout; +const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status) { + return _upb_DefPool_AddFile(s, file_proto, NULL, status); } -static void create_enumvaldef( - symtab_addctx* ctx, const char* prefix, - const google_protobuf_EnumValueDescriptorProto* val_proto, upb_EnumDef* e, - int i) { - upb_EnumValueDef* val = (upb_EnumValueDef*)&e->values[i]; - upb_StringView name = - google_protobuf_EnumValueDescriptorProto_name(val_proto); - upb_value v = upb_value_constptr(val); +/* Include here since we want most of this file to be stdio-free. */ +#include - val->parent = e; /* Must happen prior to symtab_add(). */ - val->full_name = makefullname(ctx, prefix, name); - val->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); - symtab_add(ctx, val->full_name, pack_def(val, UPB_DEFTYPE_ENUMVAL)); +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable) { + /* Since this function should never fail (it would indicate a bug in upb) we + * print errors to stderr instead of returning error status to the user. */ + _upb_DefPool_Init** deps = init->deps; + google_protobuf_FileDescriptorProto* file; + upb_Arena* arena; + upb_Status status; - SET_OPTIONS(val->opts, EnumValueDescriptorProto, EnumValueOptions, val_proto); + upb_Status_Clear(&status); - if (i == 0 && e->file->syntax == kUpb_Syntax_Proto3 && val->number != 0) { - symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)", - e->full_name); + if (upb_DefPool_FindFileByName(s, init->filename)) { + return true; } - CHK_OOM(upb_strtable_insert(&e->ntoi, name.data, name.size, v, ctx->arena)); + arena = upb_Arena_New(); - // Multiple enumerators can have the same number, first one wins. - if (!upb_inttable_lookup(&e->iton, val->number, NULL)) { - CHK_OOM(upb_inttable_insert(&e->iton, val->number, v, ctx->arena)); + for (; *deps; deps++) { + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; } -} - -static void create_enumdef( - symtab_addctx* ctx, const char* prefix, - const google_protobuf_EnumDescriptorProto* enum_proto, - const upb_MessageDef* containing_type, const upb_EnumDef* _e) { - upb_EnumDef* e = (upb_EnumDef*)_e; - ; - const google_protobuf_EnumValueDescriptorProto* const* values; - upb_StringView name; - size_t i, n; - - e->file = ctx->file; /* Must happen prior to symtab_add() */ - e->containing_type = containing_type; - - name = google_protobuf_EnumDescriptorProto_name(enum_proto); - check_ident(ctx, name, false); - - e->full_name = makefullname(ctx, prefix, name); - symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); - - values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); - CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena)); - CHK_OOM(upb_inttable_init(&e->iton, ctx->arena)); - e->defaultval = 0; - e->value_count = n; - e->values = symtab_alloc(ctx, sizeof(*e->values) * n); + file = google_protobuf_FileDescriptorProto_parse_ex( + init->descriptor.data, init->descriptor.size, NULL, + kUpb_DecodeOption_AliasString, arena); + s->bytes_loaded += init->descriptor.size; - if (n == 0) { - symtab_errf(ctx, "enums must contain at least one value (%s)", - e->full_name); + if (!file) { + upb_Status_SetErrorFormat( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; } - SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); - - for (i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, values[i], e, i); + const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { + goto err; } - upb_inttable_compact(&e->iton, ctx->arena); + upb_Arena_Free(arena); + return true; - if (e->file->syntax == kUpb_Syntax_Proto2) { - if (ctx->layout) { - UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); - e->layout = ctx->layout->enums[ctx->enum_count++]; - UPB_ASSERT(upb_inttable_count(&e->iton) == - e->layout->value_count + count_bits_debug(e->layout->mask)); - } else { - e->layout = create_enumlayout(ctx, e); - } - } else { - e->layout = NULL; - } +err: + fprintf(stderr, + "Error loading compiled-in descriptor for file '%s' (this should " + "never happen): %s\n", + init->filename, upb_Status_ErrorMessage(&status)); + upb_Arena_Free(arena); + return false; } -static void msgdef_create_nested( - symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m); - -static void create_msgdef(symtab_addctx* ctx, const char* prefix, - const google_protobuf_DescriptorProto* msg_proto, - const upb_MessageDef* containing_type, - const upb_MessageDef* _m) { - upb_MessageDef* m = (upb_MessageDef*)_m; - const google_protobuf_OneofDescriptorProto* const* oneofs; - const google_protobuf_FieldDescriptorProto* const* fields; - const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; - size_t i, n_oneof, n_field, n_ext_range; - upb_StringView name; - - m->file = ctx->file; /* Must happen prior to symtab_add(). */ - m->containing_type = containing_type; - - name = google_protobuf_DescriptorProto_name(msg_proto); - check_ident(ctx, name, false); +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { + return s->bytes_loaded; +} - m->full_name = makefullname(ctx, prefix, name); - symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG)); +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } - oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); - fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); - ext_ranges = - google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); +const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTable_Extension* ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} - CHK_OOM(upb_inttable_init(&m->itof, ctx->arena)); - CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena)); +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum) { + const upb_MiniTable* l = upb_MessageDef_MiniTable(m); + const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); + return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +} - if (ctx->layout) { - /* create_fielddef() below depends on this being set. */ - UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count); - m->layout = ctx->layout->msgs[ctx->msg_count++]; - UPB_ASSERT(n_field == m->layout->field_count); - } else { - /* Allocate now (to allow cross-linking), populate later. */ - m->layout = - symtab_alloc(ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); - } +bool _upb_DefPool_registerlayout(upb_DefPool* s, const char* filename, + const upb_MiniTable_File* file) { + if (upb_DefPool_FindFileByName(s, filename)) return false; + upb_value v = pack_def(file, UPB_DEFTYPE_LAYOUT); + return upb_strtable_insert(&s->files, filename, strlen(filename), v, + s->arena); +} - SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s) { + return s->extreg; +} - m->oneof_count = n_oneof; - m->oneofs = symtab_alloc(ctx, sizeof(*m->oneofs) * n_oneof); - for (i = 0; i < n_oneof; i++) { - create_oneofdef(ctx, m, oneofs[i], &m->oneofs[i]); +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count) { + size_t n = 0; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + // This is O(all exts) instead of O(exts for m). If we need this to be + // efficient we may need to make extreg into a two-level table, or have a + // second per-message index. + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) n++; } - - m->field_count = n_field; - m->fields = symtab_alloc(ctx, sizeof(*m->fields) * n_field); - for (i = 0; i < n_field; i++) { - create_fielddef(ctx, m->full_name, m, fields[i], &m->fields[i], - /* is_extension= */ false); + const upb_FieldDef** exts = malloc(n * sizeof(*exts)); + iter = UPB_INTTABLE_BEGIN; + size_t i = 0; + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; } + *count = n; + return exts; +} - m->ext_range_count = n_ext_range; - m->ext_ranges = symtab_alloc(ctx, sizeof(*m->ext_ranges) * n_ext_range); - for (i = 0; i < n_ext_range; i++) { - const google_protobuf_DescriptorProto_ExtensionRange* r = ext_ranges[i]; - upb_ExtensionRange* r_def = (upb_ExtensionRange*)&m->ext_ranges[i]; - int32_t start = google_protobuf_DescriptorProto_ExtensionRange_start(r); - int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(r); - int32_t max = - google_protobuf_MessageOptions_message_set_wire_format(m->opts) - ? INT32_MAX - : kUpb_MaxFieldNumber + 1; +#undef CHK_OOM - // A full validation would also check that each range is disjoint, and that - // none of the fields overlap with the extension ranges, but we are just - // sanity checking here. - if (start < 1 || end <= start || end > max) { - symtab_errf(ctx, "Extension range (%d, %d) is invalid, message=%s\n", - (int)start, (int)end, m->full_name); - } +/** upb/reflection.c ************************************************************/ - r_def->start = start; - r_def->end = end; - SET_OPTIONS(r_def->opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, r); - } +#include - finalize_oneofs(ctx, m); - assign_msg_wellknowntype(m); - upb_inttable_compact(&m->itof, ctx->arena); - msgdef_create_nested(ctx, msg_proto, m); + +static size_t get_field_size(const upb_MiniTable_Field* f) { + static unsigned char sizes[] = { + 0, /* 0 */ + 8, /* kUpb_FieldType_Double */ + 4, /* kUpb_FieldType_Float */ + 8, /* kUpb_FieldType_Int64 */ + 8, /* kUpb_FieldType_UInt64 */ + 4, /* kUpb_FieldType_Int32 */ + 8, /* kUpb_FieldType_Fixed64 */ + 4, /* kUpb_FieldType_Fixed32 */ + 1, /* kUpb_FieldType_Bool */ + sizeof(upb_StringView), /* kUpb_FieldType_String */ + sizeof(void*), /* kUpb_FieldType_Group */ + sizeof(void*), /* kUpb_FieldType_Message */ + sizeof(upb_StringView), /* kUpb_FieldType_Bytes */ + 4, /* kUpb_FieldType_UInt32 */ + 4, /* kUpb_FieldType_Enum */ + 4, /* kUpb_FieldType_SFixed32 */ + 8, /* kUpb_FieldType_SFixed64 */ + 4, /* kUpb_FieldType_SInt32 */ + 8, /* kUpb_FieldType_SInt64 */ + }; + return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; } -static void msgdef_create_nested( - symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m) { - size_t n; +/** upb_Message + * *******************************************************************/ - const google_protobuf_EnumDescriptorProto* const* enums = - google_protobuf_DescriptorProto_enum_type(msg_proto, &n); - m->nested_enum_count = n; - m->nested_enums = symtab_alloc(ctx, sizeof(*m->nested_enums) * n); - for (size_t i = 0; i < n; i++) { - m->nested_enum_count = i + 1; - create_enumdef(ctx, m->full_name, enums[i], m, &m->nested_enums[i]); - } +upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) { + return _upb_Message_New(upb_MessageDef_MiniTable(m), a); +} - const google_protobuf_FieldDescriptorProto* const* exts = - google_protobuf_DescriptorProto_extension(msg_proto, &n); - m->nested_ext_count = n; - m->nested_exts = symtab_alloc(ctx, sizeof(*m->nested_exts) * n); - for (size_t i = 0; i < n; i++) { - create_fielddef(ctx, m->full_name, m, exts[i], &m->nested_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&m->nested_exts[i])->index_ = i; - } +static bool in_oneof(const upb_MiniTable_Field* field) { + return field->presence < 0; +} - const google_protobuf_DescriptorProto* const* msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - m->nested_msg_count = n; - m->nested_msgs = symtab_alloc(ctx, sizeof(*m->nested_msgs) * n); - for (size_t i = 0; i < n; i++) { - create_msgdef(ctx, m->full_name, msgs[i], m, &m->nested_msgs[i]); - } +static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, + const upb_FieldDef* f) { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + const char* mem = UPB_PTR_AT(msg, field->offset, char); + upb_MessageValue val = {0}; + memcpy(&val, mem, get_field_size(field)); + return val; } -static void resolve_subdef(symtab_addctx* ctx, const char* prefix, - upb_FieldDef* f) { - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; - upb_StringView name = - google_protobuf_FieldDescriptorProto_type_name(field_proto); - bool has_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); - switch ((int)f->type_) { - case FIELD_TYPE_UNSPECIFIED: { - // Type was not specified and must be inferred. - UPB_ASSERT(has_name); - upb_deftype_t type; - const void* def = - symtab_resolveany(ctx, f->full_name, prefix, name, &type); - switch (type) { - case UPB_DEFTYPE_ENUM: - f->sub.enumdef = def; - f->type_ = kUpb_FieldType_Enum; - break; - case UPB_DEFTYPE_MSG: - f->sub.msgdef = def; - f->type_ = kUpb_FieldType_Message; // It appears there is no way of - // this being a group. - break; - default: - symtab_errf(ctx, "Couldn't resolve type name for field %s", - f->full_name); - } +bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { + assert(upb_FieldDef_HasPresence(f)); + if (upb_FieldDef_IsExtension(f)) { + const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); + return _upb_Message_Getext(msg, ext) != NULL; + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + if (in_oneof(field)) { + return _upb_getoneofcase_field(msg, field) == field->number; + } else if (field->presence > 0) { + return _upb_hasbit_field(msg, field); + } else { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + return _upb_Message_Getraw(msg, f).msg_val != NULL; } - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - UPB_ASSERT(has_name); - f->sub.msgdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - break; - case kUpb_FieldType_Enum: - UPB_ASSERT(has_name); - f->sub.enumdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_ENUM); - break; - default: - // No resolution necessary. - break; } } -static void resolve_extension( - symtab_addctx* ctx, const char* prefix, upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { - symtab_errf(ctx, "extension for field '%s' had no extendee", f->full_name); +const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, + const upb_OneofDef* o) { + const upb_FieldDef* f = upb_OneofDef_Field(o, 0); + if (upb_OneofDef_IsSynthetic(o)) { + UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); + return upb_Message_Has(msg, f) ? f : NULL; + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + uint32_t oneof_case = _upb_getoneofcase_field(msg, field); + f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; + UPB_ASSERT((f != NULL) == (oneof_case != 0)); + return f; } +} - upb_StringView name = - google_protobuf_FieldDescriptorProto_extendee(field_proto); - const upb_MessageDef* m = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - f->msgdef = m; - - bool found = false; - - for (int i = 0, n = m->ext_range_count; i < n; i++) { - const upb_ExtensionRange* r = &m->ext_ranges[i]; - if (r->start <= f->number_ && f->number_ < r->end) { - found = true; - break; +upb_MessageValue upb_Message_Get(const upb_Message* msg, + const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + const upb_Message_Extension* ext = + _upb_Message_Getext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + if (ext) { + upb_MessageValue val; + memcpy(&val, &ext->data, sizeof(val)); + return val; + } else if (upb_FieldDef_IsRepeated(f)) { + return (upb_MessageValue){.array_val = NULL}; } + } else if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { + return _upb_Message_Getraw(msg, f); } + return upb_FieldDef_Default(f); +} - if (!found) { - symtab_errf(ctx, - "field number %u in extension %s has no extension range in " - "message %s", - (unsigned)f->number_, f->full_name, f->msgdef->full_name); +upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a) { + UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); + if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) { + // We need to skip the upb_Message_Get() call in this case. + goto make; + } + + upb_MessageValue val = upb_Message_Get(msg, f); + if (val.array_val) { + return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; } - const upb_MiniTable_Extension* ext = ctx->file->ext_layouts[f->layout_index]; - if (ctx->layout) { - UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); + upb_MutableMessageValue ret; +make: + if (!a) return (upb_MutableMessageValue){.array = NULL}; + if (upb_FieldDef_IsMap(f)) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); + const upb_FieldDef* value = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); + ret.map = + upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); + } else if (upb_FieldDef_IsRepeated(f)) { + ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); } else { - upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; - fill_fieldlayout(&mut_ext->field, f); - mut_ext->field.presence = 0; - mut_ext->field.offset = 0; - mut_ext->field.submsg_index = 0; - mut_ext->extendee = f->msgdef->layout; - mut_ext->sub.submsg = f->sub.msgdef->layout; + UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); + ret.msg = upb_Message_New(upb_FieldDef_MessageSubDef(f), a); } - CHK_OOM(upb_inttable_insert(&ctx->symtab->exts, (uintptr_t)ext, - upb_value_constptr(f), ctx->arena)); -} + val.array_val = ret.array; + upb_Message_Set(msg, f, val, a); -static void resolve_default( - symtab_addctx* ctx, upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - // Have to delay resolving of the default value until now because of the enum - // case, since enum defaults are specified with a label. - if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { - upb_StringView defaultval = - google_protobuf_FieldDescriptorProto_default_value(field_proto); + return ret; +} - if (f->file->syntax == kUpb_Syntax_Proto3) { - symtab_errf(ctx, "proto3 fields cannot have explicit defaults (%s)", - f->full_name); +bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a) { + if (upb_FieldDef_IsExtension(f)) { + upb_Message_Extension* ext = _upb_Message_GetOrCreateExtension( + msg, _upb_FieldDef_ExtensionMiniTable(f), a); + if (!ext) return false; + memcpy(&ext->data, &val, sizeof(val)); + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + char* mem = UPB_PTR_AT(msg, field->offset, char); + memcpy(mem, &val, get_field_size(field)); + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (in_oneof(field)) { + *_upb_oneofcase_field(msg, field) = field->number; } + } + return true; +} - if (upb_FieldDef_IsSubMessage(f)) { - symtab_errf(ctx, "message fields cannot have explicit defaults (%s)", - f->full_name); +void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + char* mem = UPB_PTR_AT(msg, field->offset, char); + + if (field->presence > 0) { + _upb_clearhas_field(msg, field); + } else if (in_oneof(field)) { + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (*oneof_case != field->number) return; + *oneof_case = 0; } - parse_default(ctx, defaultval.data, defaultval.size, f); - f->has_default = true; - } else { - set_default_default(ctx, f); - f->has_default = false; + memset(mem, 0, get_field_size(field)); } } -static void resolve_fielddef(symtab_addctx* ctx, const char* prefix, - upb_FieldDef* f) { - // We have to stash this away since resolve_subdef() may overwrite it. - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; +void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { + _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +} - resolve_subdef(ctx, prefix, f); - resolve_default(ctx, f, field_proto); +bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, const upb_FieldDef** out_f, + upb_MessageValue* out_val, size_t* iter) { + size_t i = *iter; + size_t n = upb_MessageDef_FieldCount(m); + const upb_MessageValue zero = {0}; + UPB_UNUSED(ext_pool); - if (f->is_extension_) { - resolve_extension(ctx, prefix, f, field_proto); - } -} + /* Iterate over normal fields, returning the first one that is set. */ + while (++i < n) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_MessageValue val = _upb_Message_Getraw(msg, f); -static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { - for (int i = 0; i < m->field_count; i++) { - resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]); - } + /* Skip field if unset or empty. */ + if (upb_FieldDef_HasPresence(f)) { + if (!upb_Message_Has(msg, f)) continue; + } else { + upb_MessageValue test = val; + if (upb_FieldDef_IsString(f) && !upb_FieldDef_IsRepeated(f)) { + /* Clear string pointer, only size matters (ptr could be non-NULL). */ + test.str_val.data = NULL; + } + /* Continue if NULL or 0. */ + if (memcmp(&test, &zero, sizeof(test)) == 0) continue; - m->in_message_set = false; - for (int i = 0; i < m->nested_ext_count; i++) { - upb_FieldDef* ext = (upb_FieldDef*)&m->nested_exts[i]; - resolve_fielddef(ctx, m->full_name, ext); - if (ext->type_ == kUpb_FieldType_Message && - ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m && - google_protobuf_MessageOptions_message_set_wire_format( - ext->msgdef->opts)) { - m->in_message_set = true; + /* Continue on empty array or map. */ + if (upb_FieldDef_IsMap(f)) { + if (upb_Map_Size(test.map_val) == 0) continue; + } else if (upb_FieldDef_IsRepeated(f)) { + if (upb_Array_Size(test.array_val) == 0) continue; + } } - } - - if (!ctx->layout) make_layout(ctx, m); - for (int i = 0; i < m->nested_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]); + *out_val = val; + *out_f = f; + *iter = i; + return true; } -} - -static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { - size_t n; - google_protobuf_DescriptorProto_extension(msg_proto, &n); - int ext_count = n; - const google_protobuf_DescriptorProto* const* nested_msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - for (size_t i = 0; i < n; i++) { - ext_count += count_exts_in_msg(nested_msgs[i]); + if (ext_pool) { + /* Return any extensions that are set. */ + size_t count; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &count); + if (i - n < count) { + ext += count - 1 - (i - n); + memcpy(out_val, &ext->data, sizeof(*out_val)); + *out_f = _upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); + *iter = i; + return true; + } } - return ext_count; + *iter = i; + return false; } -static void build_filedef( - symtab_addctx* ctx, upb_FileDef* file, - const google_protobuf_FileDescriptorProto* file_proto) { - const google_protobuf_DescriptorProto* const* msgs; - const google_protobuf_EnumDescriptorProto* const* enums; - const google_protobuf_FieldDescriptorProto* const* exts; - const google_protobuf_ServiceDescriptorProto* const* services; - const upb_StringView* strs; - const int32_t* public_deps; - const int32_t* weak_deps; - size_t i, n; +bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int depth) { + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + bool ret = true; - file->symtab = ctx->symtab; + if (--depth == 0) return false; - /* Count all extensions in the file, to build a flat array of layouts. */ - google_protobuf_FileDescriptorProto_extension(file_proto, &n); - int ext_count = n; - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - for (int i = 0; i < n; i++) { - ext_count += count_exts_in_msg(msgs[i]); - } - file->ext_count = ext_count; + _upb_Message_DiscardUnknown_shallow(msg); - if (ctx->layout) { - /* We are using the ext layouts that were passed in. */ - file->ext_layouts = ctx->layout->exts; - if (ctx->layout->ext_count != file->ext_count) { - symtab_errf(ctx, "Extension count did not match layout (%d vs %d)", - ctx->layout->ext_count, file->ext_count); - } - } else { - /* We are building ext layouts from scratch. */ - file->ext_layouts = - symtab_alloc(ctx, sizeof(*file->ext_layouts) * file->ext_count); - upb_MiniTable_Extension* ext = - symtab_alloc(ctx, sizeof(*ext) * file->ext_count); - for (int i = 0; i < file->ext_count; i++) { - file->ext_layouts[i] = &ext[i]; + while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + if (!subm) continue; + if (upb_FieldDef_IsMap(f)) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); + const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); + upb_Map* map = (upb_Map*)val.map_val; + size_t iter = kUpb_Map_Begin; + + if (!val_m) continue; + + while (upb_MapIterator_Next(map, &iter)) { + upb_MessageValue map_val = upb_MapIterator_Value(map, iter); + if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, + depth)) { + ret = false; + } + } + } else if (upb_FieldDef_IsRepeated(f)) { + const upb_Array* arr = val.array_val; + size_t i, n = upb_Array_Size(arr); + for (i = 0; i < n; i++) { + upb_MessageValue elem = upb_Array_Get(arr, i); + if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, + depth)) { + ret = false; + } + } + } else { + if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, + depth)) { + ret = false; + } } } - if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { - symtab_errf(ctx, "File has no name"); - } + return ret; +} + +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth) { + return _upb_Message_DiscardUnknown(msg, m, maxdepth); +} - file->name = - strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); +/** upb/decode.c ************************************************************/ - if (google_protobuf_FileDescriptorProto_has_package(file_proto)) { - upb_StringView package = - google_protobuf_FileDescriptorProto_package(file_proto); - check_ident(ctx, package, true); - file->package = strviewdup(ctx, package); - } else { - file->package = NULL; - } +#include +#include - if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { - upb_StringView syntax = - google_protobuf_FileDescriptorProto_syntax(file_proto); - if (streql_view(syntax, "proto2")) { - file->syntax = kUpb_Syntax_Proto2; - } else if (streql_view(syntax, "proto3")) { - file->syntax = kUpb_Syntax_Proto3; - } else { - symtab_errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(syntax)); - } - } else { - file->syntax = kUpb_Syntax_Proto2; - } +/* Must be last. */ - /* Read options. */ - SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); +/* Maps descriptor type -> elem_size_lg2. */ +static const uint8_t desctype_to_elem_size_lg2[] = { + -1, /* invalid descriptor type */ + 3, /* DOUBLE */ + 2, /* FLOAT */ + 3, /* INT64 */ + 3, /* UINT64 */ + 2, /* INT32 */ + 3, /* FIXED64 */ + 2, /* FIXED32 */ + 0, /* BOOL */ + UPB_SIZE(3, 4), /* STRING */ + UPB_SIZE(2, 3), /* GROUP */ + UPB_SIZE(2, 3), /* MESSAGE */ + UPB_SIZE(3, 4), /* BYTES */ + 2, /* UINT32 */ + 2, /* ENUM */ + 2, /* SFIXED32 */ + 3, /* SFIXED64 */ + 2, /* SINT32 */ + 3, /* SINT64 */ +}; - /* Verify dependencies. */ - strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); - file->dep_count = n; - file->deps = symtab_alloc(ctx, sizeof(*file->deps) * n); +/* Maps descriptor type -> upb map size. */ +static const uint8_t desctype_to_mapsize[] = { + -1, /* invalid descriptor type */ + 8, /* DOUBLE */ + 4, /* FLOAT */ + 8, /* INT64 */ + 8, /* UINT64 */ + 4, /* INT32 */ + 8, /* FIXED64 */ + 4, /* FIXED32 */ + 1, /* BOOL */ + UPB_MAPTYPE_STRING, /* STRING */ + sizeof(void*), /* GROUP */ + sizeof(void*), /* MESSAGE */ + UPB_MAPTYPE_STRING, /* BYTES */ + 4, /* UINT32 */ + 4, /* ENUM */ + 4, /* SFIXED32 */ + 8, /* SFIXED64 */ + 4, /* SINT32 */ + 8, /* SINT64 */ +}; - for (i = 0; i < n; i++) { - upb_StringView str = strs[i]; - file->deps[i] = - upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); - if (!file->deps[i]) { - symtab_errf(ctx, - "Depends on file '" UPB_STRINGVIEW_FORMAT - "', but it has not been loaded", - UPB_STRINGVIEW_ARGS(str)); - } - } +static const unsigned FIXED32_OK_MASK = (1 << kUpb_FieldType_Float) | + (1 << kUpb_FieldType_Fixed32) | + (1 << kUpb_FieldType_SFixed32); - public_deps = - google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); - file->public_dep_count = n; - file->public_deps = symtab_alloc(ctx, sizeof(*file->public_deps) * n); - int32_t* mutable_public_deps = (int32_t*)file->public_deps; - for (i = 0; i < n; i++) { - if (public_deps[i] >= file->dep_count) { - symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]); - } - mutable_public_deps[i] = public_deps[i]; - } +static const unsigned FIXED64_OK_MASK = (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Fixed64) | + (1 << kUpb_FieldType_SFixed64); - weak_deps = - google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); - file->weak_dep_count = n; - file->weak_deps = symtab_alloc(ctx, sizeof(*file->weak_deps) * n); - int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; - for (i = 0; i < n; i++) { - if (weak_deps[i] >= file->dep_count) { - symtab_errf(ctx, "weak_dep %d is out of range", (int)weak_deps[i]); - } - mutable_weak_deps[i] = weak_deps[i]; - } +/* Three fake field types for MessageSet. */ +#define TYPE_MSGSET_ITEM 19 +#define TYPE_COUNT 19 - /* Create enums. */ - enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); - file->top_lvl_enum_count = n; - file->top_lvl_enums = symtab_alloc(ctx, sizeof(*file->top_lvl_enums) * n); - for (i = 0; i < n; i++) { - create_enumdef(ctx, file->package, enums[i], NULL, &file->top_lvl_enums[i]); - } +/* Op: an action to be performed for a wire-type/field-type combination. */ +#define OP_UNKNOWN -1 /* Unknown field. */ +#define OP_MSGSET_ITEM -2 +#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */ +#define OP_ENUM 1 +#define OP_STRING 4 +#define OP_BYTES 5 +#define OP_SUBMSG 6 +/* Scalar fields use only ops above. Repeated fields can use any op. */ +#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ +#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ +#define OP_PACKED_ENUM 13 - /* Create extensions. */ - exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); - file->top_lvl_ext_count = n; - file->top_lvl_exts = symtab_alloc(ctx, sizeof(*file->top_lvl_exts) * n); - for (i = 0; i < n; i++) { - create_fielddef(ctx, file->package, NULL, exts[i], &file->top_lvl_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&file->top_lvl_exts[i])->index_ = i; - } +static const int8_t varint_ops[] = { + OP_UNKNOWN, /* field not found */ + OP_UNKNOWN, /* DOUBLE */ + OP_UNKNOWN, /* FLOAT */ + OP_SCALAR_LG2(3), /* INT64 */ + OP_SCALAR_LG2(3), /* UINT64 */ + OP_SCALAR_LG2(2), /* INT32 */ + OP_UNKNOWN, /* FIXED64 */ + OP_UNKNOWN, /* FIXED32 */ + OP_SCALAR_LG2(0), /* BOOL */ + OP_UNKNOWN, /* STRING */ + OP_UNKNOWN, /* GROUP */ + OP_UNKNOWN, /* MESSAGE */ + OP_UNKNOWN, /* BYTES */ + OP_SCALAR_LG2(2), /* UINT32 */ + OP_ENUM, /* ENUM */ + OP_UNKNOWN, /* SFIXED32 */ + OP_UNKNOWN, /* SFIXED64 */ + OP_SCALAR_LG2(2), /* SINT32 */ + OP_SCALAR_LG2(3), /* SINT64 */ + OP_UNKNOWN, /* MSGSET_ITEM */ +}; - /* Create messages. */ - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - file->top_lvl_msg_count = n; - file->top_lvl_msgs = symtab_alloc(ctx, sizeof(*file->top_lvl_msgs) * n); - for (i = 0; i < n; i++) { - create_msgdef(ctx, file->package, msgs[i], NULL, &file->top_lvl_msgs[i]); - } +static const int8_t delim_ops[] = { + /* For non-repeated field type. */ + OP_UNKNOWN, /* field not found */ + OP_UNKNOWN, /* DOUBLE */ + OP_UNKNOWN, /* FLOAT */ + OP_UNKNOWN, /* INT64 */ + OP_UNKNOWN, /* UINT64 */ + OP_UNKNOWN, /* INT32 */ + OP_UNKNOWN, /* FIXED64 */ + OP_UNKNOWN, /* FIXED32 */ + OP_UNKNOWN, /* BOOL */ + OP_STRING, /* STRING */ + OP_UNKNOWN, /* GROUP */ + OP_SUBMSG, /* MESSAGE */ + OP_BYTES, /* BYTES */ + OP_UNKNOWN, /* UINT32 */ + OP_UNKNOWN, /* ENUM */ + OP_UNKNOWN, /* SFIXED32 */ + OP_UNKNOWN, /* SFIXED64 */ + OP_UNKNOWN, /* SINT32 */ + OP_UNKNOWN, /* SINT64 */ + OP_UNKNOWN, /* MSGSET_ITEM */ + /* For repeated field type. */ + OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */ + OP_FIXPCK_LG2(2), /* REPEATED FLOAT */ + OP_VARPCK_LG2(3), /* REPEATED INT64 */ + OP_VARPCK_LG2(3), /* REPEATED UINT64 */ + OP_VARPCK_LG2(2), /* REPEATED INT32 */ + OP_FIXPCK_LG2(3), /* REPEATED FIXED64 */ + OP_FIXPCK_LG2(2), /* REPEATED FIXED32 */ + OP_VARPCK_LG2(0), /* REPEATED BOOL */ + OP_STRING, /* REPEATED STRING */ + OP_SUBMSG, /* REPEATED GROUP */ + OP_SUBMSG, /* REPEATED MESSAGE */ + OP_BYTES, /* REPEATED BYTES */ + OP_VARPCK_LG2(2), /* REPEATED UINT32 */ + OP_PACKED_ENUM, /* REPEATED ENUM */ + OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */ + OP_FIXPCK_LG2(3), /* REPEATED SFIXED64 */ + OP_VARPCK_LG2(2), /* REPEATED SINT32 */ + OP_VARPCK_LG2(3), /* REPEATED SINT64 */ + /* Omitting MSGSET_*, because we never emit a repeated msgset type */ +}; - /* Create services. */ - services = google_protobuf_FileDescriptorProto_service(file_proto, &n); - file->service_count = n; - file->services = symtab_alloc(ctx, sizeof(*file->services) * n); - for (i = 0; i < n; i++) { - create_service(ctx, services[i], &file->services[i]); - ((upb_ServiceDef*)&file->services[i])->index = i; - } +typedef union { + bool bool_val; + uint32_t uint32_val; + uint64_t uint64_val; + uint32_t size; +} wireval; - /* Now that all names are in the table, build layouts and resolve refs. */ - for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) { - resolve_fielddef(ctx, file->package, (upb_FieldDef*)&file->top_lvl_exts[i]); - } +static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout); - for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&file->top_lvl_msgs[i]); - } +UPB_NORETURN static void* decode_err(upb_Decoder* d, upb_DecodeStatus status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); +} - if (file->ext_count) { - CHK_OOM(_upb_extreg_add(ctx->symtab->extreg, file->ext_layouts, - file->ext_count)); - } +const char* fastdecode_err(upb_Decoder* d, int status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); + return NULL; +} +static void decode_verifyutf8(upb_Decoder* d, const char* buf, int len) { + if (!decode_verifyutf8_inl(buf, len)) + decode_err(d, kUpb_DecodeStatus_BadUtf8); } -static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { - intptr_t iter = UPB_INTTABLE_BEGIN; - upb_StringView key; - upb_value val; - while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { - const upb_FileDef* f; - switch (deftype(val)) { - case UPB_DEFTYPE_EXT: - f = upb_FieldDef_File(unpack_def(val, UPB_DEFTYPE_EXT)); - break; - case UPB_DEFTYPE_MSG: - f = upb_MessageDef_File(unpack_def(val, UPB_DEFTYPE_MSG)); - break; - case UPB_DEFTYPE_ENUM: - f = upb_EnumDef_File(unpack_def(val, UPB_DEFTYPE_ENUM)); - break; - case UPB_DEFTYPE_ENUMVAL: - f = upb_EnumDef_File( - upb_EnumValueDef_Enum(unpack_def(val, UPB_DEFTYPE_ENUMVAL))); - break; - case UPB_DEFTYPE_SERVICE: - f = upb_ServiceDef_File(unpack_def(val, UPB_DEFTYPE_SERVICE)); - break; - default: - UPB_UNREACHABLE(); - } - - if (f == file) upb_strtable_removeiter(&s->syms, &iter); +static bool decode_reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { + bool need_realloc = arr->size - arr->len < elem; + if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); } + return need_realloc; } -static const upb_FileDef* _upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - const upb_MiniTable_File* layout, upb_Status* status) { - symtab_addctx ctx; - upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); - upb_value v; +typedef struct { + const char* ptr; + uint64_t val; +} decode_vret; - if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { - if (unpack_def(v, UPB_DEFTYPE_FILE)) { - upb_Status_SetErrorFormat(status, "duplicate file name (%.*s)", - UPB_STRINGVIEW_ARGS(name)); - return NULL; - } - const upb_MiniTable_File* registered = unpack_def(v, UPB_DEFTYPE_LAYOUT); - UPB_ASSERT(registered); - if (layout && layout != registered) { - upb_Status_SetErrorFormat( - status, "tried to build with a different layout (filename=%.*s)", - UPB_STRINGVIEW_ARGS(name)); - return NULL; +UPB_NOINLINE +static decode_vret decode_longvarint64(const char* ptr, uint64_t val) { + decode_vret ret = {NULL, 0}; + uint64_t byte; + int i; + for (i = 1; i < 10; i++) { + byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + ret.ptr = ptr + i + 1; + ret.val = val; + return ret; } - layout = registered; } + return ret; +} - ctx.symtab = s; - ctx.layout = layout; - ctx.msg_count = 0; - ctx.enum_count = 0; - ctx.ext_count = 0; - ctx.status = status; - ctx.file = NULL; - ctx.arena = upb_Arena_New(); - ctx.tmp_arena = upb_Arena_New(); - - if (!ctx.arena || !ctx.tmp_arena) { - if (ctx.arena) upb_Arena_Free(ctx.arena); - if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); - upb_Status_setoom(status); - return NULL; +UPB_FORCEINLINE +static const char* decode_varint64(upb_Decoder* d, const char* ptr, + uint64_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + decode_vret res = decode_longvarint64(ptr, byte); + if (!res.ptr) return decode_err(d, kUpb_DecodeStatus_Malformed); + *val = res.val; + return res.ptr; } +} - if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) { - UPB_ASSERT(!upb_Status_IsOk(status)); - if (ctx.file) { - remove_filedef(s, ctx.file); - ctx.file = NULL; - } +UPB_FORCEINLINE +static const char* decode_tag(upb_Decoder* d, const char* ptr, uint32_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; } else { - ctx.file = symtab_alloc(&ctx, sizeof(*ctx.file)); - build_filedef(&ctx, ctx.file, file_proto); - upb_strtable_insert(&s->files, name.data, name.size, - pack_def(ctx.file, UPB_DEFTYPE_FILE), ctx.arena); - UPB_ASSERT(upb_Status_IsOk(status)); - upb_Arena_Fuse(s->arena, ctx.arena); + const char* start = ptr; + decode_vret res = decode_longvarint64(ptr, byte); + if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { + return decode_err(d, kUpb_DecodeStatus_Malformed); + } + *val = res.val; + return res.ptr; } - - upb_Arena_Free(ctx.arena); - upb_Arena_Free(ctx.tmp_arena); - return ctx.file; } -const upb_FileDef* upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - upb_Status* status) { - return _upb_DefPool_AddFile(s, file_proto, NULL, status); +UPB_FORCEINLINE +static const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, + uint32_t* size) { + uint64_t size64; + ptr = decode_varint64(d, ptr, &size64); + if (size64 >= INT32_MAX || ptr - d->end + (int)size64 > d->limit) { + decode_err(d, kUpb_DecodeStatus_Malformed); + } + *size = size64; + return ptr; } -/* Include here since we want most of this file to be stdio-free. */ -#include - -bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, - bool rebuild_minitable) { - /* Since this function should never fail (it would indicate a bug in upb) we - * print errors to stderr instead of returning error status to the user. */ - _upb_DefPool_Init** deps = init->deps; - google_protobuf_FileDescriptorProto* file; - upb_Arena* arena; - upb_Status status; - - upb_Status_Clear(&status); - - if (upb_DefPool_FindFileByName(s, init->filename)) { - return true; +static void decode_munge_int32(wireval* val) { + if (!_upb_IsLittleEndian()) { + /* The next stage will memcpy(dst, &val, 4) */ + val->uint32_val = val->uint64_val; } +} - arena = upb_Arena_New(); - - for (; *deps; deps++) { - if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; +static void decode_munge(int type, wireval* val) { + switch (type) { + case kUpb_FieldType_Bool: + val->bool_val = val->uint64_val != 0; + break; + case kUpb_FieldType_SInt32: { + uint32_t n = val->uint64_val; + val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); + break; + } + case kUpb_FieldType_SInt64: { + uint64_t n = val->uint64_val; + val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); + break; + } + case kUpb_FieldType_Int32: + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Enum: + decode_munge_int32(val); + break; } +} - file = google_protobuf_FileDescriptorProto_parse_ex( - init->descriptor.data, init->descriptor.size, NULL, - kUpb_DecodeOption_AliasString, arena); - s->bytes_loaded += init->descriptor.size; +static upb_Message* decode_newsubmsg(upb_Decoder* d, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + upb_Message* msg = _upb_Message_New_inl(subl, &d->arena); + if (!msg) decode_err(d, kUpb_DecodeStatus_OutOfMemory); + return msg; +} - if (!file) { - upb_Status_SetErrorFormat( - &status, - "Failed to parse compiled-in descriptor for file '%s'. This should " - "never happen.", - init->filename); - goto err; +UPB_NOINLINE +const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, + int overrun) { + int status; + ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); + if (ptr == NULL) { + return decode_err(d, status); } + return ptr; +} - const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; - if (!_upb_DefPool_AddFile(s, file, mt, &status)) { - goto err; +static const char* decode_readstr(upb_Decoder* d, const char* ptr, int size, + upb_StringView* str) { + if (d->options & kUpb_DecodeOption_AliasString) { + str->data = ptr; + } else { + char* data = upb_Arena_Malloc(&d->arena, size); + if (!data) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); + memcpy(data, ptr, size); + str->data = data; } - - upb_Arena_Free(arena); - return true; - -err: - fprintf(stderr, - "Error loading compiled-in descriptor for file '%s' (this should " - "never happen): %s\n", - init->filename, upb_Status_ErrorMessage(&status)); - upb_Arena_Free(arena); - return false; + str->size = size; + return ptr + size; } -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { - return s->bytes_loaded; +UPB_FORCEINLINE +static const char* decode_tosubmsg2(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, int size) { + int saved_delta = decode_pushlimit(d, ptr, size); + if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); + ptr = decode_msg(d, ptr, submsg, subl); + if (d->end_group != DECODE_NOGROUP) + return decode_err(d, kUpb_DecodeStatus_Malformed); + decode_poplimit(d, ptr, saved_delta); + d->depth++; + return ptr; } -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } - -const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext) { - upb_value v; - bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); - UPB_ASSERT(ok); - return upb_value_getconstptr(v); +UPB_FORCEINLINE +static const char* decode_tosubmsg(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, int size) { + return decode_tosubmsg2(d, ptr, submsg, subs[field->submsg_index].submsg, + size); } -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum) { - const upb_MiniTable* l = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); - return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +UPB_FORCEINLINE +static const char* decode_group(upb_Decoder* d, const char* ptr, + upb_Message* submsg, const upb_MiniTable* subl, + uint32_t number) { + if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); + if (decode_isdone(d, &ptr)) { + return decode_err(d, kUpb_DecodeStatus_Malformed); + } + ptr = decode_msg(d, ptr, submsg, subl); + if (d->end_group != number) return decode_err(d, kUpb_DecodeStatus_Malformed); + d->end_group = DECODE_NOGROUP; + d->depth++; + return ptr; } -bool _upb_DefPool_registerlayout(upb_DefPool* s, const char* filename, - const upb_MiniTable_File* file) { - if (upb_DefPool_FindFileByName(s, filename)) return false; - upb_value v = pack_def(file, UPB_DEFTYPE_LAYOUT); - return upb_strtable_insert(&s->files, filename, strlen(filename), v, - s->arena); +UPB_FORCEINLINE +static const char* decode_togroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + return decode_group(d, ptr, submsg, subl, field->number); } -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s) { - return s->extreg; +static char* upb_Decoder_EncodeVarint32(uint32_t val, char* ptr) { + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + *(ptr++) = byte; + } while (val); + return ptr; } -const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, - const upb_MessageDef* m, - size_t* count) { - size_t n = 0; - intptr_t iter = UPB_INTTABLE_BEGIN; - uintptr_t key; - upb_value val; - // This is O(all exts) instead of O(exts for m). If we need this to be - // efficient we may need to make extreg into a two-level table, or have a - // second per-message index. - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) n++; - } - const upb_FieldDef** exts = malloc(n * sizeof(*exts)); - iter = UPB_INTTABLE_BEGIN; - size_t i = 0; - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; +static void upb_Decode_AddUnknownVarints(upb_Decoder* d, upb_Message* msg, + uint32_t val1, uint32_t val2) { + char buf[20]; + char* end = buf; + end = upb_Decoder_EncodeVarint32(val1, end); + end = upb_Decoder_EncodeVarint32(val2, end); + + if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); } - *count = n; - return exts; } -#undef CHK_OOM +UPB_NOINLINE +static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTable_Enum* e, + const upb_MiniTable_Field* field, + uint32_t v) { + // OPT: binary search long lists? + int n = e->value_count; + for (int i = 0; i < n; i++) { + if ((uint32_t)e->values[i] == v) return true; + } -/** upb/reflection.c ************************************************************/ + // Unrecognized enum goes into unknown fields. + // For packed fields the tag could be arbitrarily far in the past, so we + // just re-encode the tag and value here. + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; + upb_Message* unknown_msg = + field->mode & kUpb_LabelFlags_IsExtension ? d->unknown_msg : msg; + upb_Decode_AddUnknownVarints(d, unknown_msg, tag, v); + return false; +} -#include +UPB_FORCEINLINE +static bool decode_checkenum(upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable_Enum* e, + const upb_MiniTable_Field* field, wireval* val) { + uint32_t v = val->uint32_val; + if (UPB_LIKELY(v < 64) && UPB_LIKELY(((1ULL << v) & e->mask))) return true; -static size_t get_field_size(const upb_MiniTable_Field* f) { - static unsigned char sizes[] = { - 0, /* 0 */ - 8, /* kUpb_FieldType_Double */ - 4, /* kUpb_FieldType_Float */ - 8, /* kUpb_FieldType_Int64 */ - 8, /* kUpb_FieldType_UInt64 */ - 4, /* kUpb_FieldType_Int32 */ - 8, /* kUpb_FieldType_Fixed64 */ - 4, /* kUpb_FieldType_Fixed32 */ - 1, /* kUpb_FieldType_Bool */ - sizeof(upb_StringView), /* kUpb_FieldType_String */ - sizeof(void*), /* kUpb_FieldType_Group */ - sizeof(void*), /* kUpb_FieldType_Message */ - sizeof(upb_StringView), /* kUpb_FieldType_Bytes */ - 4, /* kUpb_FieldType_UInt32 */ - 4, /* kUpb_FieldType_Enum */ - 4, /* kUpb_FieldType_SFixed32 */ - 8, /* kUpb_FieldType_SFixed64 */ - 4, /* kUpb_FieldType_SInt32 */ - 8, /* kUpb_FieldType_SInt64 */ - }; - return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; + return decode_checkenum_slow(d, ptr, msg, e, field, v); } -/* Strings/bytes are special-cased in maps. */ -static char _upb_CTypeo_mapsize[12] = { - 0, - 1, /* kUpb_CType_Bool */ - 4, /* kUpb_CType_Float */ - 4, /* kUpb_CType_Int32 */ - 4, /* kUpb_CType_UInt32 */ - 4, /* kUpb_CType_Enum */ - sizeof(void*), /* kUpb_CType_Message */ - 8, /* kUpb_CType_Double */ - 8, /* kUpb_CType_Int64 */ - 8, /* kUpb_CType_UInt64 */ - 0, /* kUpb_CType_String */ - 0, /* kUpb_CType_Bytes */ -}; +UPB_NOINLINE +static const char* decode_enum_toarray(upb_Decoder* d, const char* ptr, + upb_Message* msg, upb_Array* arr, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val) { + const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; + if (!decode_checkenum(d, ptr, msg, e, field, val)) return ptr; + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); + arr->len++; + memcpy(mem, val, 4); + return ptr; +} -static const char _upb_CTypeo_sizelg2[12] = { - 0, - 0, /* kUpb_CType_Bool */ - 2, /* kUpb_CType_Float */ - 2, /* kUpb_CType_Int32 */ - 2, /* kUpb_CType_UInt32 */ - 2, /* kUpb_CType_Enum */ - UPB_SIZE(2, 3), /* kUpb_CType_Message */ - 3, /* kUpb_CType_Double */ - 3, /* kUpb_CType_Int64 */ - 3, /* kUpb_CType_UInt64 */ - UPB_SIZE(3, 4), /* kUpb_CType_String */ - UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ -}; +UPB_FORCEINLINE +static const char* decode_fixed_packed(upb_Decoder* d, const char* ptr, + upb_Array* arr, wireval* val, + const upb_MiniTable_Field* field, + int lg2) { + int mask = (1 << lg2) - 1; + size_t count = val->size >> lg2; + if ((val->size & mask) != 0) { + // Length isn't a round multiple of elem size. + return decode_err(d, kUpb_DecodeStatus_Malformed); + } + decode_reserve(d, arr, count); + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); + arr->len += count; + // Note: if/when the decoder supports multi-buffer input, we will need to + // handle buffer seams here. + if (_upb_IsLittleEndian()) { + memcpy(mem, ptr, val->size); + ptr += val->size; + } else { + const char* end = ptr + val->size; + char* dst = mem; + while (ptr < end) { + if (lg2 == 2) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap32(val); + memcpy(dst, &val, sizeof(val)); + } else { + UPB_ASSERT(lg2 == 3); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap64(val); + memcpy(dst, &val, sizeof(val)); + } + ptr += 1 << lg2; + dst += 1 << lg2; + } + } -/** upb_Message - * *******************************************************************/ + return ptr; +} -upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) { - return _upb_Message_New(upb_MessageDef_MiniTable(m), a); +UPB_FORCEINLINE +static const char* decode_varint_packed(upb_Decoder* d, const char* ptr, + upb_Array* arr, wireval* val, + const upb_MiniTable_Field* field, + int lg2) { + int scale = 1 << lg2; + int saved_limit = decode_pushlimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); + while (!decode_isdone(d, &ptr)) { + wireval elem; + ptr = decode_varint64(d, ptr, &elem.uint64_val); + decode_munge(field->descriptortype, &elem); + if (decode_reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); + } + arr->len++; + memcpy(out, &elem, scale); + out += scale; + } + decode_poplimit(d, ptr, saved_limit); + return ptr; } -static bool in_oneof(const upb_MiniTable_Field* field) { - return field->presence < 0; +UPB_NOINLINE +static const char* decode_enum_packed(upb_Decoder* d, const char* ptr, + upb_Message* msg, upb_Array* arr, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val) { + const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; + int saved_limit = decode_pushlimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); + while (!decode_isdone(d, &ptr)) { + wireval elem; + ptr = decode_varint64(d, ptr, &elem.uint64_val); + decode_munge_int32(&elem); + if (!decode_checkenum(d, ptr, msg, e, field, &elem)) { + continue; + } + if (decode_reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); + } + arr->len++; + memcpy(out, &elem, 4); + out += 4; + } + decode_poplimit(d, ptr, saved_limit); + return ptr; } -static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, - const upb_FieldDef* f) { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - const char* mem = UPB_PTR_AT(msg, field->offset, char); - upb_MessageValue val = {0}; - memcpy(&val, mem, get_field_size(field)); - return val; -} +static const char* decode_toarray(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val, int op) { + upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); + upb_Array* arr = *arrp; + void* mem; -bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { - assert(upb_FieldDef_HasPresence(f)); - if (upb_FieldDef_IsExtension(f)) { - const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); - return _upb_Message_Getext(msg, ext) != NULL; + if (arr) { + decode_reserve(d, arr, 1); } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - if (in_oneof(field)) { - return _upb_getoneofcase_field(msg, field) == field->number; - } else if (field->presence > 0) { - return _upb_hasbit_field(msg, field); - } else { - UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || - field->descriptortype == kUpb_FieldType_Group); - return _upb_Message_Getraw(msg, f).msg_val != NULL; + size_t lg2 = desctype_to_elem_size_lg2[field->descriptortype]; + arr = _upb_Array_New(&d->arena, 4, lg2); + if (!arr) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); + *arrp = arr; + } + + switch (op) { + case OP_SCALAR_LG2(0): + case OP_SCALAR_LG2(2): + case OP_SCALAR_LG2(3): + /* Append scalar value. */ + mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << op, void); + arr->len++; + memcpy(mem, val, 1 << op); + return ptr; + case OP_STRING: + decode_verifyutf8(d, ptr, val->size); + /* Fallthrough. */ + case OP_BYTES: { + /* Append bytes. */ + upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->len; + arr->len++; + return decode_readstr(d, ptr, val->size, str); + } + case OP_SUBMSG: { + /* Append submessage / group. */ + upb_Message* submsg = decode_newsubmsg(d, subs, field); + *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void*), upb_Message*) = + submsg; + arr->len++; + if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { + return decode_togroup(d, ptr, submsg, subs, field); + } else { + return decode_tosubmsg(d, ptr, submsg, subs, field, val->size); + } } + case OP_FIXPCK_LG2(2): + case OP_FIXPCK_LG2(3): + return decode_fixed_packed(d, ptr, arr, val, field, + op - OP_FIXPCK_LG2(0)); + case OP_VARPCK_LG2(0): + case OP_VARPCK_LG2(2): + case OP_VARPCK_LG2(3): + return decode_varint_packed(d, ptr, arr, val, field, + op - OP_VARPCK_LG2(0)); + case OP_ENUM: + return decode_enum_toarray(d, ptr, msg, arr, subs, field, val); + case OP_PACKED_ENUM: + return decode_enum_packed(d, ptr, msg, arr, subs, field, val); + default: + UPB_UNREACHABLE(); } } -const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, - const upb_OneofDef* o) { - const upb_FieldDef* f = upb_OneofDef_Field(o, 0); - if (upb_OneofDef_IsSynthetic(o)) { - UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); - return upb_Message_Has(msg, f) ? f : NULL; - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - uint32_t oneof_case = _upb_getoneofcase_field(msg, field); - f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; - UPB_ASSERT((f != NULL) == (oneof_case != 0)); - return f; +static const char* decode_tomap(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val) { + upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*); + upb_Map* map = *map_p; + upb_MapEntry ent; + const upb_MiniTable* entry = subs[field->submsg_index].submsg; + + if (!map) { + /* Lazily create map. */ + const upb_MiniTable_Field* key_field = &entry->fields[0]; + const upb_MiniTable_Field* val_field = &entry->fields[1]; + char key_size = desctype_to_mapsize[key_field->descriptortype]; + char val_size = desctype_to_mapsize[val_field->descriptortype]; + UPB_ASSERT(key_field->offset == 0); + UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); + map = _upb_Map_New(&d->arena, key_size, val_size); + *map_p = map; } -} -upb_MessageValue upb_Message_Get(const upb_Message* msg, - const upb_FieldDef* f) { - if (upb_FieldDef_IsExtension(f)) { - const upb_Message_Extension* ext = - _upb_Message_Getext(msg, _upb_FieldDef_ExtensionMiniTable(f)); - if (ext) { - upb_MessageValue val; - memcpy(&val, &ext->data, sizeof(val)); - return val; - } else if (upb_FieldDef_IsRepeated(f)) { - return (upb_MessageValue){.array_val = NULL}; + /* Parse map entry. */ + memset(&ent, 0, sizeof(ent)); + + if (entry->fields[1].descriptortype == kUpb_FieldType_Message || + entry->fields[1].descriptortype == kUpb_FieldType_Group) { + /* Create proactively to handle the case where it doesn't appear. */ + ent.v.val = + upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); + } + + const char* start = ptr; + ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size); + // check if ent had any unknown fields + size_t size; + upb_Message_GetUnknown(&ent.k, &size); + if (size != 0) { + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Delimited; + upb_Decode_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } + } else { + if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, + &d->arena) == _kUpb_MapInsertStatus_OutOfMemory) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); } - } else if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { - return _upb_Message_Getraw(msg, f); } - return upb_FieldDef_Default(f); + return ptr; } -upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, - const upb_FieldDef* f, - upb_Arena* a) { - UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); - if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) { - // We need to skip the upb_Message_Get() call in this case. - goto make; +static const char* decode_tomsg(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, wireval* val, + int op) { + void* mem = UPB_PTR_AT(msg, field->offset, void); + int type = field->descriptortype; + + if (UPB_UNLIKELY(op == OP_ENUM) && + !decode_checkenum(d, ptr, msg, subs[field->submsg_index].subenum, field, + val)) { + return ptr; } - upb_MessageValue val = upb_Message_Get(msg, f); - if (val.array_val) { - return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; + /* Set presence if necessary. */ + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (field->presence < 0) { + /* Oneof case */ + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (op == OP_SUBMSG && *oneof_case != field->number) { + memset(mem, 0, sizeof(void*)); + } + *oneof_case = field->number; } - upb_MutableMessageValue ret; -make: - if (!a) return (upb_MutableMessageValue){.array = NULL}; - if (upb_FieldDef_IsMap(f)) { - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key = - upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); - const upb_FieldDef* value = - upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); - ret.map = - upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); - } else if (upb_FieldDef_IsRepeated(f)) { - ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); - } else { - UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); - ret.msg = upb_Message_New(upb_FieldDef_MessageSubDef(f), a); + /* Store into message. */ + switch (op) { + case OP_SUBMSG: { + upb_Message** submsgp = mem; + upb_Message* submsg = *submsgp; + if (!submsg) { + submsg = decode_newsubmsg(d, subs, field); + *submsgp = submsg; + } + if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { + ptr = decode_togroup(d, ptr, submsg, subs, field); + } else { + ptr = decode_tosubmsg(d, ptr, submsg, subs, field, val->size); + } + break; + } + case OP_STRING: + decode_verifyutf8(d, ptr, val->size); + /* Fallthrough. */ + case OP_BYTES: + return decode_readstr(d, ptr, val->size, mem); + case OP_SCALAR_LG2(3): + memcpy(mem, val, 8); + break; + case OP_ENUM: + case OP_SCALAR_LG2(2): + memcpy(mem, val, 4); + break; + case OP_SCALAR_LG2(0): + memcpy(mem, val, 1); + break; + default: + UPB_UNREACHABLE(); } - val.array_val = ret.array; - upb_Message_Set(msg, f, val, a); + return ptr; +} - return ret; +UPB_NOINLINE +const char* decode_checkrequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* l) { + assert(l->required_count); + if (UPB_LIKELY((d->options & kUpb_DecodeOption_CheckRequired) == 0)) { + return ptr; + } + uint64_t msg_head; + memcpy(&msg_head, msg, 8); + msg_head = _upb_BigEndian_Swap64(msg_head); + if (upb_MiniTable_requiredmask(l) & ~msg_head) { + d->missing_required = true; + } + return ptr; +} + +UPB_FORCEINLINE +static bool decode_tryfastdispatch(upb_Decoder* d, const char** ptr, + upb_Message* msg, + const upb_MiniTable* layout) { +#if UPB_FASTTABLE + if (layout && layout->table_mask != (unsigned char)-1) { + uint16_t tag = fastdecode_loadtag(*ptr); + intptr_t table = decode_totable(layout); + *ptr = fastdecode_tagdispatch(d, *ptr, msg, table, 0, tag); + return true; + } +#endif + return false; } -bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, - upb_MessageValue val, upb_Arena* a) { - if (upb_FieldDef_IsExtension(f)) { - upb_Message_Extension* ext = _upb_Message_Getorcreateext( - msg, _upb_FieldDef_ExtensionMiniTable(f), a); - if (!ext) return false; - memcpy(&ext->data, &val, sizeof(val)); - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - char* mem = UPB_PTR_AT(msg, field->offset, char); - memcpy(mem, &val, get_field_size(field)); - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (in_oneof(field)) { - *_upb_oneofcase_field(msg, field) = field->number; +static const char* upb_Decoder_SkipField(upb_Decoder* d, const char* ptr, + uint32_t tag) { + int field_number = tag >> 3; + int wire_type = tag & 7; + switch (wire_type) { + case kUpb_WireType_Varint: { + uint64_t val; + return decode_varint64(d, ptr, &val); + } + case kUpb_WireType_64Bit: + return ptr + 8; + case kUpb_WireType_32Bit: + return ptr + 4; + case kUpb_WireType_Delimited: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + return ptr + size; } + case kUpb_WireType_StartGroup: + return decode_group(d, ptr, NULL, NULL, field_number); + default: + decode_err(d, kUpb_DecodeStatus_Malformed); } - return true; } -void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { - if (upb_FieldDef_IsExtension(f)) { - _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - char* mem = UPB_PTR_AT(msg, field->offset, char); +enum { + kStartItemTag = ((1 << 3) | kUpb_WireType_StartGroup), + kEndItemTag = ((1 << 3) | kUpb_WireType_EndGroup), + kTypeIdTag = ((2 << 3) | kUpb_WireType_Varint), + kMessageTag = ((3 << 3) | kUpb_WireType_Delimited), +}; - if (field->presence > 0) { - _upb_clearhas_field(msg, field); - } else if (in_oneof(field)) { - uint32_t* oneof_case = _upb_oneofcase_field(msg, field); - if (*oneof_case != field->number) return; - *oneof_case = 0; - } +static void upb_Decoder_AddKnownMessageSetItem( + upb_Decoder* d, upb_Message* msg, const upb_MiniTable_Extension* item_mt, + const char* data, uint32_t size) { + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, item_mt, &d->arena); + if (UPB_UNLIKELY(!ext)) decode_err(d, kUpb_DecodeStatus_OutOfMemory); + upb_Message* submsg = decode_newsubmsg(d, &ext->ext->sub, &ext->ext->field); + upb_DecodeStatus status = upb_Decode(data, size, submsg, item_mt->sub.submsg, + d->extreg, d->options, &d->arena); + memcpy(&ext->data, &submsg, sizeof(submsg)); + if (status != kUpb_DecodeStatus_Ok) decode_err(d, status); +} + +static void upb_Decoder_AddUnknownMessageSetItem(upb_Decoder* d, + upb_Message* msg, + uint32_t type_id, + const char* message_data, + uint32_t message_size) { + char buf[60]; + char* ptr = buf; + ptr = upb_Decoder_EncodeVarint32(kStartItemTag, ptr); + ptr = upb_Decoder_EncodeVarint32(kTypeIdTag, ptr); + ptr = upb_Decoder_EncodeVarint32(type_id, ptr); + ptr = upb_Decoder_EncodeVarint32(kMessageTag, ptr); + ptr = upb_Decoder_EncodeVarint32(message_size, ptr); + char* split = ptr; + + ptr = upb_Decoder_EncodeVarint32(kEndItemTag, ptr); + char* end = ptr; + + if (!_upb_Message_AddUnknown(msg, buf, split - buf, &d->arena) || + !_upb_Message_AddUnknown(msg, message_data, message_size, &d->arena) || + !_upb_Message_AddUnknown(msg, split, end - split, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } +} - memset(mem, 0, get_field_size(field)); +static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, + const upb_MiniTable* layout, + uint32_t type_id, const char* data, + uint32_t size) { + const upb_MiniTable_Extension* item_mt = + _upb_extreg_get(d->extreg, layout, type_id); + if (item_mt) { + upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); + } else { + upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); } } -void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { - _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +static const char* upb_Decoder_DecodeMessageSetItem( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout) { + uint32_t type_id = 0; + upb_StringView preserved = {NULL, 0}; + typedef enum { + kUpb_HaveId = 1 << 0, + kUpb_HavePayload = 1 << 1, + } StateMask; + StateMask state_mask = 0; + while (!decode_isdone(d, &ptr)) { + uint32_t tag; + ptr = decode_tag(d, ptr, &tag); + switch (tag) { + case kEndItemTag: + return ptr; + case kTypeIdTag: { + uint64_t tmp; + ptr = decode_varint64(d, ptr, &tmp); + if (state_mask & kUpb_HaveId) break; // Ignore dup. + state_mask |= kUpb_HaveId; + type_id = tmp; + if (state_mask & kUpb_HavePayload) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, preserved.data, + preserved.size); + } + break; + } + case kMessageTag: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + const char* data = ptr; + ptr += size; + if (state_mask & kUpb_HavePayload) break; // Ignore dup. + state_mask |= kUpb_HavePayload; + if (state_mask & kUpb_HaveId) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, data, size); + } else { + // Out of order, we must preserve the payload. + preserved.data = data; + preserved.size = size; + } + break; + } + default: + // We do not preserve unexpected fields inside a message set item. + ptr = upb_Decoder_SkipField(d, ptr, tag); + break; + } + } + decode_err(d, kUpb_DecodeStatus_Malformed); } -bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, const upb_FieldDef** out_f, - upb_MessageValue* out_val, size_t* iter) { - size_t i = *iter; - size_t n = upb_MessageDef_FieldCount(m); - const upb_MessageValue zero = {0}; - UPB_UNUSED(ext_pool); +static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d, + const upb_MiniTable* l, + uint32_t field_number, + int* last_field_index) { + static upb_MiniTable_Field none = {0, 0, 0, 0, 0, 0}; + if (l == NULL) return &none; - /* Iterate over normal fields, returning the first one that is set. */ - while (++i < n) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - upb_MessageValue val = _upb_Message_Getraw(msg, f); + size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX + if (idx < l->dense_below) { + /* Fastest case: index into dense fields. */ + goto found; + } - /* Skip field if unset or empty. */ - if (upb_FieldDef_HasPresence(f)) { - if (!upb_Message_Has(msg, f)) continue; - } else { - upb_MessageValue test = val; - if (upb_FieldDef_IsString(f) && !upb_FieldDef_IsRepeated(f)) { - /* Clear string pointer, only size matters (ptr could be non-NULL). */ - test.str_val.data = NULL; + if (l->dense_below < l->field_count) { + /* Linear search non-dense fields. Resume scanning from last_field_index + * since fields are usually in order. */ + int last = *last_field_index; + for (idx = last; idx < l->field_count; idx++) { + if (l->fields[idx].number == field_number) { + goto found; } - /* Continue if NULL or 0. */ - if (memcmp(&test, &zero, sizeof(test)) == 0) continue; + } - /* Continue on empty array or map. */ - if (upb_FieldDef_IsMap(f)) { - if (upb_Map_Size(test.map_val) == 0) continue; - } else if (upb_FieldDef_IsRepeated(f)) { - if (upb_Array_Size(test.array_val) == 0) continue; + for (idx = l->dense_below; idx < last; idx++) { + if (l->fields[idx].number == field_number) { + goto found; } } - - *out_val = val; - *out_f = f; - *iter = i; - return true; } - if (ext_pool) { - /* Return any extensions that are set. */ - size_t count; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &count); - if (i - n < count) { - ext += count - 1 - (i - n); - memcpy(out_val, &ext->data, sizeof(*out_val)); - *out_f = _upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); - *iter = i; - return true; + if (d->extreg) { + switch (l->ext) { + case kUpb_ExtMode_Extendable: { + const upb_MiniTable_Extension* ext = + _upb_extreg_get(d->extreg, l, field_number); + if (ext) return &ext->field; + break; + } + case kUpb_ExtMode_IsMessageSet: + if (field_number == _UPB_MSGSET_ITEM) { + static upb_MiniTable_Field item = {0, 0, 0, 0, TYPE_MSGSET_ITEM, 0}; + return &item; + } + break; } } - *iter = i; - return false; -} - -bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int depth) { - size_t iter = kUpb_Message_Begin; - const upb_FieldDef* f; - upb_MessageValue val; - bool ret = true; - - if (--depth == 0) return false; - - _upb_Message_DiscardUnknown_shallow(msg); - - while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { - const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); - if (!subm) continue; - if (upb_FieldDef_IsMap(f)) { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); - const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); - upb_Map* map = (upb_Map*)val.map_val; - size_t iter = kUpb_Map_Begin; + return &none; /* Unknown field. */ - if (!val_m) continue; +found: + UPB_ASSERT(l->fields[idx].number == field_number); + *last_field_index = idx; + return &l->fields[idx]; +} - while (upb_MapIterator_Next(map, &iter)) { - upb_MessageValue map_val = upb_MapIterator_Value(map, iter); - if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, - depth)) { - ret = false; - } - } - } else if (upb_FieldDef_IsRepeated(f)) { - const upb_Array* arr = val.array_val; - size_t i, n = upb_Array_Size(arr); - for (i = 0; i < n; i++) { - upb_MessageValue elem = upb_Array_Get(arr, i); - if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, - depth)) { - ret = false; - } +UPB_FORCEINLINE +static const char* decode_wireval(upb_Decoder* d, const char* ptr, + const upb_MiniTable_Field* field, + int wire_type, wireval* val, int* op) { + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = decode_varint64(d, ptr, &val->uint64_val); + *op = varint_ops[field->descriptortype]; + decode_munge(field->descriptortype, val); + return ptr; + case kUpb_WireType_32Bit: + memcpy(&val->uint32_val, ptr, 4); + val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val); + *op = OP_SCALAR_LG2(2); + if (((1 << field->descriptortype) & FIXED32_OK_MASK) == 0) { + *op = OP_UNKNOWN; } - } else { - if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, - depth)) { - ret = false; + return ptr + 4; + case kUpb_WireType_64Bit: + memcpy(&val->uint64_val, ptr, 8); + val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); + *op = OP_SCALAR_LG2(3); + if (((1 << field->descriptortype) & FIXED64_OK_MASK) == 0) { + *op = OP_UNKNOWN; } + return ptr + 8; + case kUpb_WireType_Delimited: { + int ndx = field->descriptortype; + if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += TYPE_COUNT; + ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); + *op = delim_ops[ndx]; + return ptr; } + case kUpb_WireType_StartGroup: + val->uint32_val = field->number; + if (field->descriptortype == kUpb_FieldType_Group) { + *op = OP_SUBMSG; + } else if (field->descriptortype == TYPE_MSGSET_ITEM) { + *op = OP_MSGSET_ITEM; + } else { + *op = OP_UNKNOWN; + } + return ptr; + default: + break; + } + return decode_err(d, kUpb_DecodeStatus_Malformed); +} + +UPB_FORCEINLINE +static const char* decode_known(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTable* layout, + const upb_MiniTable_Field* field, int op, + wireval* val) { + const upb_MiniTable_Sub* subs = layout->subs; + uint8_t mode = field->mode; + + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTable_Extension* ext_layout = + (const upb_MiniTable_Extension*)field; + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, ext_layout, &d->arena); + if (UPB_UNLIKELY(!ext)) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); + d->unknown_msg = msg; + msg = &ext->data; + subs = &ext->ext->sub; + } + + switch (mode & kUpb_FieldMode_Mask) { + case kUpb_FieldMode_Array: + return decode_toarray(d, ptr, msg, subs, field, val, op); + case kUpb_FieldMode_Map: + return decode_tomap(d, ptr, msg, subs, field, val); + case kUpb_FieldMode_Scalar: + return decode_tomsg(d, ptr, msg, subs, field, val, op); + default: + UPB_UNREACHABLE(); } - - return ret; } -bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int maxdepth) { - return _upb_Message_DiscardUnknown(msg, m, maxdepth); +static const char* decode_reverse_skip_varint(const char* ptr, uint32_t val) { + uint32_t seen = 0; + do { + ptr--; + seen <<= 7; + seen |= *ptr & 0x7f; + } while (seen != val); + return ptr; } -/** upb_Array *****************************************************************/ - -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { - return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); -} +static const char* decode_unknown(upb_Decoder* d, const char* ptr, + upb_Message* msg, int field_number, + int wire_type, wireval val) { + if (field_number == 0) return decode_err(d, kUpb_DecodeStatus_Malformed); -size_t upb_Array_Size(const upb_Array* arr) { return arr->len; } + // Since unknown fields are the uncommon case, we do a little extra work here + // to walk backwards through the buffer to find the field start. This frees + // up a register in the fast paths (when the field is known), which leads to + // significant speedups in benchmarks. + const char* start = ptr; -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { - upb_MessageValue ret; - const char* data = _upb_array_constptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(&ret, data + (i << lg2), 1 << lg2); - return ret; -} + if (wire_type == kUpb_WireType_Delimited) ptr += val.size; + if (msg) { + switch (wire_type) { + case kUpb_WireType_Varint: + case kUpb_WireType_Delimited: + start--; + while (start[-1] & 0x80) start--; + break; + case kUpb_WireType_32Bit: + start -= 4; + break; + case kUpb_WireType_64Bit: + start -= 8; + break; + default: + break; + } -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(data + (i << lg2), &val, 1 << lg2); -} + assert(start == d->debug_valstart); + uint32_t tag = ((uint32_t)field_number << 3) | wire_type; + start = decode_reverse_skip_varint(start, tag); + assert(start == d->debug_tagstart); -bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { - if (!upb_Array_Resize(arr, arr->len + 1, arena)) { - return false; + if (wire_type == kUpb_WireType_StartGroup) { + d->unknown = start; + d->unknown_msg = msg; + ptr = decode_group(d, ptr, NULL, NULL, field_number); + start = d->unknown; + d->unknown = NULL; + } + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + return decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } + } else if (wire_type == kUpb_WireType_StartGroup) { + ptr = decode_group(d, ptr, NULL, NULL, field_number); } - upb_Array_Set(arr, arr->len - 1, val); - return true; + return ptr; } -void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, - size_t count) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); -} +UPB_NOINLINE +static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout) { + int last_field_index = 0; -bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, - upb_Arena* arena) { - UPB_ASSERT(i <= arr->len); - UPB_ASSERT(count + arr->len >= count); - size_t oldsize = arr->len; - if (!upb_Array_Resize(arr, arr->len + count, arena)) { - return false; - } - upb_Array_Move(arr, i + count, i, oldsize - i); - return true; -} +#if UPB_FASTTABLE + // The first time we want to skip fast dispatch, because we may have just been + // invoked by the fast parser to handle a case that it bailed on. + if (!decode_isdone(d, &ptr)) goto nofast; +#endif -/* - * i end arr->len - * |------------|XXXXXXXX|--------| - */ -void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { - size_t end = i + count; - UPB_ASSERT(i <= end); - UPB_ASSERT(end <= arr->len); - upb_Array_Move(arr, i, end, arr->len - end); - arr->len -= count; -} + while (!decode_isdone(d, &ptr)) { + uint32_t tag; + const upb_MiniTable_Field* field; + int field_number; + int wire_type; + wireval val; + int op; -bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { - return _upb_Array_Resize(arr, size, arena); -} + if (decode_tryfastdispatch(d, &ptr, msg, layout)) break; -/** upb_Map *******************************************************************/ +#if UPB_FASTTABLE + nofast: +#endif -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { - return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], - _upb_CTypeo_mapsize[value_type]); -} +#ifndef NDEBUG + d->debug_tagstart = ptr; +#endif -size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } + UPB_ASSERT(ptr < d->limit_ptr); + ptr = decode_tag(d, ptr, &tag); + field_number = tag >> 3; + wire_type = tag & 7; -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val) { - return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); -} +#ifndef NDEBUG + d->debug_valstart = ptr; +#endif -void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } + if (wire_type == kUpb_WireType_EndGroup) { + d->end_group = field_number; + return ptr; + } -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena) { - return _upb_Map_Set(map, &key, map->key_size, &val, map->val_size, arena); -} + field = decode_findfield(d, layout, field_number, &last_field_index); + ptr = decode_wireval(d, ptr, field, wire_type, &val, &op); -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { - return _upb_Map_Delete(map, &key, map->key_size); -} + if (op >= 0) { + ptr = decode_known(d, ptr, msg, layout, field, op, &val); + } else { + switch (op) { + case OP_UNKNOWN: + ptr = decode_unknown(d, ptr, msg, field_number, wire_type, val); + break; + case OP_MSGSET_ITEM: + ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); + break; + } + } + } -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { - return _upb_map_next(map, iter); + return UPB_UNLIKELY(layout && layout->required_count) + ? decode_checkrequired(d, ptr, msg, layout) + : ptr; } -bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - UPB_ASSERT(iter != kUpb_Map_Begin); - i.t = &map->table; - i.index = iter; - return upb_strtable_done(&i); +const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + (void)data; + *(uint32_t*)msg |= hasbits; + return decode_msg(d, ptr, msg, decode_totablep(table)); } -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); - return ret; +static upb_DecodeStatus decode_top(struct upb_Decoder* d, const char* buf, + void* msg, const upb_MiniTable* l) { + if (!decode_tryfastdispatch(d, &buf, msg, l)) { + decode_msg(d, buf, msg, l); + } + if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; + if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; + return kUpb_DecodeStatus_Ok; } -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); - return ret; +upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg, + const upb_MiniTable* l, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena) { + upb_Decoder state; + unsigned depth = (unsigned)options >> 16; + + if (size <= 16) { + memset(&state.patch, 0, 32); + if (size) memcpy(&state.patch, buf, size); + buf = state.patch; + state.end = buf + size; + state.limit = 0; + options &= ~kUpb_DecodeOption_AliasString; // Can't alias patch buf. + } else { + state.end = buf + size - 16; + state.limit = 16; + } + + state.extreg = extreg; + state.limit_ptr = state.end; + state.unknown = NULL; + state.depth = depth ? depth : 64; + state.end_group = DECODE_NOGROUP; + state.options = (uint16_t)options; + state.missing_required = false; + state.arena.head = arena->head; + state.arena.last_size = arena->last_size; + state.arena.cleanup_metadata = arena->cleanup_metadata; + state.arena.parent = arena; + + upb_DecodeStatus status = UPB_SETJMP(state.err); + if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { + status = decode_top(&state, buf, msg, l); + } + + arena->head.ptr = state.arena.head.ptr; + arena->head.end = state.arena.head.end; + arena->cleanup_metadata = state.arena.cleanup_metadata; + return status; } -/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue - * value); */ +#undef OP_UNKNOWN +#undef OP_SKIP +#undef OP_SCALAR_LG2 +#undef OP_FIXPCK_LG2 +#undef OP_VARPCK_LG2 +#undef OP_STRING +#undef OP_BYTES +#undef OP_SUBMSG + +/** upb/encode.c ************************************************************/ +/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ -/** upb/json_decode.c ************************************************************/ -#include -#include -#include -#include -#include #include -#include #include -/* Special header, must be included last. */ - -typedef struct { - const char *ptr, *end; - upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ - const upb_DefPool* symtab; - int depth; - upb_Status* status; - jmp_buf err; - int line; - const char* line_begin; - bool is_first; - int options; - const upb_FieldDef* debug_field; -} jsondec; - -enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; - -/* Forward declarations of mutually-recursive functions. */ -static void jsondec_wellknown(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); -static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); -static void jsondec_object(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); - -static bool jsondec_streql(upb_StringView str, const char* lit) { - return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; -} - -static bool jsondec_isnullvalue(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum && - strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), - "google.protobuf.NullValue") == 0; -} +/* Must be last. */ -static bool jsondec_isvalue(const upb_FieldDef* f) { - return (upb_FieldDef_CType(f) == kUpb_CType_Message && - upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == - kUpb_WellKnown_Value) || - jsondec_isnullvalue(f); -} +#define UPB_PB_VARINT_MAX_LEN 10 -UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { - upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, - (int)(d->ptr - d->line_begin), msg); - UPB_LONGJMP(d->err, 1); +UPB_NOINLINE +static size_t encode_varint64(uint64_t val, char* buf) { + size_t i = 0; + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + buf[i++] = byte; + } while (val); + return i; } -UPB_PRINTF(2, 3) -UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { - va_list argp; - upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, - (int)(d->ptr - d->line_begin)); - va_start(argp, fmt); - upb_Status_VAppendErrorFormat(d->status, fmt, argp); - va_end(argp); - UPB_LONGJMP(d->err, 1); +static uint32_t encode_zz32(int32_t n) { + return ((uint32_t)n << 1) ^ (n >> 31); } - -static void jsondec_skipws(jsondec* d) { - while (d->ptr != d->end) { - switch (*d->ptr) { - case '\n': - d->line++; - d->line_begin = d->ptr; - /* Fallthrough. */ - case '\r': - case '\t': - case ' ': - d->ptr++; - break; - default: - return; - } - } - jsondec_err(d, "Unexpected EOF"); +static uint64_t encode_zz64(int64_t n) { + return ((uint64_t)n << 1) ^ (n >> 63); } -static bool jsondec_tryparsech(jsondec* d, char ch) { - if (d->ptr == d->end || *d->ptr != ch) return false; - d->ptr++; - return true; -} +typedef struct { + jmp_buf err; + upb_alloc* alloc; + char *buf, *ptr, *limit; + int options; + int depth; + _upb_mapsorter sorter; +} upb_encstate; -static void jsondec_parselit(jsondec* d, const char* lit) { - size_t avail = d->end - d->ptr; - size_t len = strlen(lit); - if (avail < len || memcmp(d->ptr, lit, len) != 0) { - jsondec_errf(d, "Expected: '%s'", lit); +static size_t upb_roundup_pow2(size_t bytes) { + size_t ret = 128; + while (ret < bytes) { + ret *= 2; } - d->ptr += len; + return ret; } -static void jsondec_wsch(jsondec* d, char ch) { - jsondec_skipws(d); - if (!jsondec_tryparsech(d, ch)) { - jsondec_errf(d, "Expected: '%c'", ch); - } -} +UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); } -static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } -static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } -static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } +UPB_NOINLINE +static void encode_growbuffer(upb_encstate* e, size_t bytes) { + size_t old_size = e->limit - e->buf; + size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); + char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); -static void jsondec_entrysep(jsondec* d) { - jsondec_skipws(d); - jsondec_parselit(d, ":"); -} + if (!new_buf) encode_err(e); -static int jsondec_rawpeek(jsondec* d) { - switch (*d->ptr) { - case '{': - return JD_OBJECT; - case '[': - return JD_ARRAY; - case '"': - return JD_STRING; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return JD_NUMBER; - case 't': - return JD_TRUE; - case 'f': - return JD_FALSE; - case 'n': - return JD_NULL; - default: - jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); + /* We want previous data at the end, realloc() put it at the beginning. */ + if (old_size > 0) { + memmove(new_buf + new_size - old_size, e->buf, old_size); } -} - -/* JSON object/array **********************************************************/ -/* These are used like so: - * - * jsondec_objstart(d); - * while (jsondec_objnext(d)) { - * ... - * } - * jsondec_objend(d) */ + e->ptr = new_buf + new_size - (e->limit - e->ptr); + e->limit = new_buf + new_size; + e->buf = new_buf; -static int jsondec_peek(jsondec* d) { - jsondec_skipws(d); - return jsondec_rawpeek(d); + e->ptr -= bytes; } -static void jsondec_push(jsondec* d) { - if (--d->depth < 0) { - jsondec_err(d, "Recursion limit exceeded"); +/* Call to ensure that at least "bytes" bytes are available for writing at + * e->ptr. Returns false if the bytes could not be allocated. */ +UPB_FORCEINLINE +static void encode_reserve(upb_encstate* e, size_t bytes) { + if ((size_t)(e->ptr - e->buf) < bytes) { + encode_growbuffer(e, bytes); + return; } - d->is_first = true; -} - -static bool jsondec_seqnext(jsondec* d, char end_ch) { - bool is_first = d->is_first; - d->is_first = false; - jsondec_skipws(d); - if (*d->ptr == end_ch) return false; - if (!is_first) jsondec_parselit(d, ","); - return true; -} -static void jsondec_arrstart(jsondec* d) { - jsondec_push(d); - jsondec_wsch(d, '['); -} - -static void jsondec_arrend(jsondec* d) { - d->depth++; - jsondec_wsch(d, ']'); + e->ptr -= bytes; } -static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } - -static void jsondec_objstart(jsondec* d) { - jsondec_push(d); - jsondec_wsch(d, '{'); +/* Writes the given bytes to the buffer, handling reserve/advance. */ +static void encode_bytes(upb_encstate* e, const void* data, size_t len) { + if (len == 0) return; /* memcpy() with zero size is UB */ + encode_reserve(e, len); + memcpy(e->ptr, data, len); } -static void jsondec_objend(jsondec* d) { - d->depth++; - jsondec_wsch(d, '}'); +static void encode_fixed64(upb_encstate* e, uint64_t val) { + val = _upb_BigEndian_Swap64(val); + encode_bytes(e, &val, sizeof(uint64_t)); } - -static bool jsondec_objnext(jsondec* d) { - if (!jsondec_seqnext(d, '}')) return false; - if (jsondec_peek(d) != JD_STRING) { - jsondec_err(d, "Object must start with string"); - } - return true; + +static void encode_fixed32(upb_encstate* e, uint32_t val) { + val = _upb_BigEndian_Swap32(val); + encode_bytes(e, &val, sizeof(uint32_t)); } -/* JSON number ****************************************************************/ +UPB_NOINLINE +static void encode_longvarint(upb_encstate* e, uint64_t val) { + size_t len; + char* start; -static bool jsondec_tryskipdigits(jsondec* d) { - const char* start = d->ptr; + encode_reserve(e, UPB_PB_VARINT_MAX_LEN); + len = encode_varint64(val, e->ptr); + start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; + memmove(start, e->ptr, len); + e->ptr = start; +} - while (d->ptr < d->end) { - if (*d->ptr < '0' || *d->ptr > '9') { - break; - } - d->ptr++; +UPB_FORCEINLINE +static void encode_varint(upb_encstate* e, uint64_t val) { + if (val < 128 && e->ptr != e->buf) { + --e->ptr; + *e->ptr = val; + } else { + encode_longvarint(e, val); } +} - return d->ptr != start; +static void encode_double(upb_encstate* e, double d) { + uint64_t u64; + UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); + memcpy(&u64, &d, sizeof(uint64_t)); + encode_fixed64(e, u64); } -static void jsondec_skipdigits(jsondec* d) { - if (!jsondec_tryskipdigits(d)) { - jsondec_err(d, "Expected one or more digits"); - } +static void encode_float(upb_encstate* e, float d) { + uint32_t u32; + UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); + memcpy(&u32, &d, sizeof(uint32_t)); + encode_fixed32(e, u32); } -static double jsondec_number(jsondec* d) { - const char* start = d->ptr; +static void encode_tag(upb_encstate* e, uint32_t field_number, + uint8_t wire_type) { + encode_varint(e, (field_number << 3) | wire_type); +} - assert(jsondec_rawpeek(d) == JD_NUMBER); +static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, + size_t elem_size, uint32_t tag) { + size_t bytes = arr->len * elem_size; + const char* data = _upb_array_constptr(arr); + const char* ptr = data + bytes - elem_size; - /* Skip over the syntax of a number, as specified by JSON. */ - if (*d->ptr == '-') d->ptr++; + if (tag || !_upb_IsLittleEndian()) { + while (true) { + if (elem_size == 4) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap32(val); + encode_bytes(e, &val, elem_size); + } else { + UPB_ASSERT(elem_size == 8); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap64(val); + encode_bytes(e, &val, elem_size); + } - if (jsondec_tryparsech(d, '0')) { - if (jsondec_tryskipdigits(d)) { - jsondec_err(d, "number cannot have leading zero"); + if (tag) encode_varint(e, tag); + if (ptr == data) break; + ptr -= elem_size; } } else { - jsondec_skipdigits(d); + encode_bytes(e, data, bytes); } +} - if (d->ptr == d->end) goto parse; - if (jsondec_tryparsech(d, '.')) { - jsondec_skipdigits(d); - } - if (d->ptr == d->end) goto parse; +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size); - if (*d->ptr == 'e' || *d->ptr == 'E') { - d->ptr++; - if (d->ptr == d->end) { - jsondec_err(d, "Unexpected EOF in number"); - } - if (*d->ptr == '+' || *d->ptr == '-') { - d->ptr++; - } - jsondec_skipdigits(d); - } +static void encode_scalar(upb_encstate* e, const void* _field_mem, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const char* field_mem = _field_mem; + int wire_type; -parse: - /* Having verified the syntax of a JSON number, use strtod() to parse - * (strtod() accepts a superset of JSON syntax). */ - errno = 0; - { - char* end; - double val = strtod(start, &end); - assert(end == d->ptr); +#define CASE(ctype, type, wtype, encodeval) \ + { \ + ctype val = *(ctype*)field_mem; \ + encode_##type(e, encodeval); \ + wire_type = wtype; \ + break; \ + } - /* Currently the min/max-val conformance tests fail if we check this. Does - * this mean the conformance tests are wrong or strtod() is wrong, or - * something else? Investigate further. */ - /* - if (errno == ERANGE) { - jsondec_err(d, "Number out of range"); + switch (f->descriptortype) { + case kUpb_FieldType_Double: + CASE(double, double, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Float: + CASE(float, float, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + CASE(uint64_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_UInt32: + CASE(uint32_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Bool: + CASE(bool, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_SInt32: + CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); + case kUpb_FieldType_SInt64: + CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + upb_StringView view = *(upb_StringView*)field_mem; + encode_bytes(e, view.data, view.size); + encode_varint(e, view.size); + wire_type = kUpb_WireType_Delimited; + break; } - */ - - if (val > DBL_MAX || val < -DBL_MAX) { - jsondec_err(d, "Number out of range"); + case kUpb_FieldType_Group: { + size_t size; + void* submsg = *(void**)field_mem; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (submsg == NULL) { + return; + } + if (--e->depth == 0) encode_err(e); + encode_tag(e, f->number, kUpb_WireType_EndGroup); + encode_message(e, submsg, subm, &size); + wire_type = kUpb_WireType_StartGroup; + e->depth++; + break; + } + case kUpb_FieldType_Message: { + size_t size; + void* submsg = *(void**)field_mem; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (submsg == NULL) { + return; + } + if (--e->depth == 0) encode_err(e); + encode_message(e, submsg, subm, &size); + encode_varint(e, size); + wire_type = kUpb_WireType_Delimited; + e->depth++; + break; } - - return val; - } -} - -/* JSON string ****************************************************************/ - -static char jsondec_escape(jsondec* d) { - switch (*d->ptr++) { - case '"': - return '\"'; - case '\\': - return '\\'; - case '/': - return '/'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; default: - jsondec_err(d, "Invalid escape char"); + UPB_UNREACHABLE(); } +#undef CASE + + encode_tag(e, f->number, wire_type); } -static uint32_t jsondec_codepoint(jsondec* d) { - uint32_t cp = 0; - const char* end; +static void encode_array(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); + bool packed = f->mode & kUpb_LabelFlags_IsPacked; + size_t pre_len = e->limit - e->ptr; - if (d->end - d->ptr < 4) { - jsondec_err(d, "EOF inside string"); + if (arr == NULL || arr->len == 0) { + return; } - end = d->ptr + 4; - while (d->ptr < end) { - char ch = *d->ptr++; - if (ch >= '0' && ch <= '9') { - ch -= '0'; - } else if (ch >= 'a' && ch <= 'f') { - ch = ch - 'a' + 10; - } else if (ch >= 'A' && ch <= 'F') { - ch = ch - 'A' + 10; - } else { - jsondec_err(d, "Invalid hex digit"); - } - cp = (cp << 4) | ch; - } +#define VARINT_CASE(ctype, encode) \ + { \ + const ctype* start = _upb_array_constptr(arr); \ + const ctype* ptr = start + arr->len; \ + uint32_t tag = packed ? 0 : (f->number << 3) | kUpb_WireType_Varint; \ + do { \ + ptr--; \ + encode_varint(e, encode); \ + if (tag) encode_varint(e, tag); \ + } while (ptr != start); \ + } \ + break; - return cp; -} +#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) -/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ -static size_t jsondec_unicode(jsondec* d, char* out) { - uint32_t cp = jsondec_codepoint(d); - if (cp >= 0xd800 && cp <= 0xdbff) { - /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ - uint32_t high = cp; - uint32_t low; - jsondec_parselit(d, "\\u"); - low = jsondec_codepoint(d); - if (low < 0xdc00 || low > 0xdfff) { - jsondec_err(d, "Invalid low surrogate"); + switch (f->descriptortype) { + case kUpb_FieldType_Double: + encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Float: + encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + VARINT_CASE(uint64_t, *ptr); + case kUpb_FieldType_UInt32: + VARINT_CASE(uint32_t, *ptr); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + VARINT_CASE(int32_t, (int64_t)*ptr); + case kUpb_FieldType_Bool: + VARINT_CASE(bool, *ptr); + case kUpb_FieldType_SInt32: + VARINT_CASE(int32_t, encode_zz32(*ptr)); + case kUpb_FieldType_SInt64: + VARINT_CASE(int64_t, encode_zz64(*ptr)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + const upb_StringView* start = _upb_array_constptr(arr); + const upb_StringView* ptr = start + arr->len; + do { + ptr--; + encode_bytes(e, ptr->data, ptr->size); + encode_varint(e, ptr->size); + encode_tag(e, f->number, kUpb_WireType_Delimited); + } while (ptr != start); + return; + } + case kUpb_FieldType_Group: { + const void* const* start = _upb_array_constptr(arr); + const void* const* ptr = start + arr->len; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (--e->depth == 0) encode_err(e); + do { + size_t size; + ptr--; + encode_tag(e, f->number, kUpb_WireType_EndGroup); + encode_message(e, *ptr, subm, &size); + encode_tag(e, f->number, kUpb_WireType_StartGroup); + } while (ptr != start); + e->depth++; + return; + } + case kUpb_FieldType_Message: { + const void* const* start = _upb_array_constptr(arr); + const void* const* ptr = start + arr->len; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (--e->depth == 0) encode_err(e); + do { + size_t size; + ptr--; + encode_message(e, *ptr, subm, &size); + encode_varint(e, size); + encode_tag(e, f->number, kUpb_WireType_Delimited); + } while (ptr != start); + e->depth++; + return; } - cp = (high & 0x3ff) << 10; - cp |= (low & 0x3ff); - cp += 0x10000; - } else if (cp >= 0xdc00 && cp <= 0xdfff) { - jsondec_err(d, "Unpaired low surrogate"); } +#undef VARINT_CASE - /* Write to UTF-8 */ - if (cp <= 0x7f) { - out[0] = cp; - return 1; - } else if (cp <= 0x07FF) { - out[0] = ((cp >> 6) & 0x1F) | 0xC0; - out[1] = ((cp >> 0) & 0x3F) | 0x80; - return 2; - } else if (cp <= 0xFFFF) { - out[0] = ((cp >> 12) & 0x0F) | 0xE0; - out[1] = ((cp >> 6) & 0x3F) | 0x80; - out[2] = ((cp >> 0) & 0x3F) | 0x80; - return 3; - } else if (cp < 0x10FFFF) { - out[0] = ((cp >> 18) & 0x07) | 0xF0; - out[1] = ((cp >> 12) & 0x3f) | 0x80; - out[2] = ((cp >> 6) & 0x3f) | 0x80; - out[3] = ((cp >> 0) & 0x3f) | 0x80; - return 4; - } else { - jsondec_err(d, "Invalid codepoint"); + if (packed) { + encode_varint(e, e->limit - e->ptr - pre_len); + encode_tag(e, f->number, kUpb_WireType_Delimited); } } -static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { - size_t oldsize = *buf_end - *buf; - size_t len = *end - *buf; - size_t size = UPB_MAX(8, 2 * oldsize); - - *buf = upb_Arena_Realloc(d->arena, *buf, len, size); - if (!*buf) jsondec_err(d, "Out of memory"); - - *end = *buf + len; - *buf_end = *buf + size; +static void encode_mapentry(upb_encstate* e, uint32_t number, + const upb_MiniTable* layout, + const upb_MapEntry* ent) { + const upb_MiniTable_Field* key_field = &layout->fields[0]; + const upb_MiniTable_Field* val_field = &layout->fields[1]; + size_t pre_len = e->limit - e->ptr; + size_t size; + encode_scalar(e, &ent->v, layout->subs, val_field); + encode_scalar(e, &ent->k, layout->subs, key_field); + size = (e->limit - e->ptr) - pre_len; + encode_varint(e, size); + encode_tag(e, number, kUpb_WireType_Delimited); } -static upb_StringView jsondec_string(jsondec* d) { - char* buf = NULL; - char* end = NULL; - char* buf_end = NULL; - - jsondec_skipws(d); - - if (*d->ptr++ != '"') { - jsondec_err(d, "Expected string"); - } +static void encode_map(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const upb_Map* map = *UPB_PTR_AT(msg, f->offset, const upb_Map*); + const upb_MiniTable* layout = subs[f->submsg_index].submsg; + UPB_ASSERT(layout->field_count == 2); - while (d->ptr < d->end) { - char ch = *d->ptr++; + if (map == NULL) return; - if (end == buf_end) { - jsondec_resize(d, &buf, &end, &buf_end); + if (e->options & kUpb_Encode_Deterministic) { + _upb_sortedmap sorted; + _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, + &sorted); + upb_MapEntry ent; + while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { + encode_mapentry(e, f->number, layout, &ent); } - - switch (ch) { - case '"': { - upb_StringView ret; - ret.data = buf; - ret.size = end - buf; - *end = '\0'; /* Needed for possible strtod(). */ - return ret; - } - case '\\': - if (d->ptr == d->end) goto eof; - if (*d->ptr == 'u') { - d->ptr++; - if (buf_end - end < 4) { - /* Allow space for maximum-sized code point (4 bytes). */ - jsondec_resize(d, &buf, &end, &buf_end); - } - end += jsondec_unicode(d, end); - } else { - *end++ = jsondec_escape(d); - } - break; - default: - if ((unsigned char)*d->ptr < 0x20) { - jsondec_err(d, "Invalid char in JSON string"); - } - *end++ = ch; - break; + _upb_mapsorter_popmap(&e->sorter, &sorted); + } else { + upb_strtable_iter i; + upb_strtable_begin(&i, &map->table); + for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_StringView key = upb_strtable_iter_key(&i); + const upb_value val = upb_strtable_iter_value(&i); + upb_MapEntry ent; + _upb_map_fromkey(key, &ent.k, map->key_size); + _upb_map_fromvalue(val, &ent.v, map->val_size); + encode_mapentry(e, f->number, layout, &ent); } } - -eof: - jsondec_err(d, "EOF inside string"); } -static void jsondec_skipval(jsondec* d) { - switch (jsondec_peek(d)) { - case JD_OBJECT: - jsondec_objstart(d); - while (jsondec_objnext(d)) { - jsondec_string(d); - jsondec_entrysep(d); - jsondec_skipval(d); +static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + if (f->presence == 0) { + /* Proto3 presence or map/array. */ + const void* mem = UPB_PTR_AT(msg, f->offset, void); + switch (f->mode >> kUpb_FieldRep_Shift) { + case kUpb_FieldRep_1Byte: { + char ch; + memcpy(&ch, mem, 1); + return ch != 0; } - jsondec_objend(d); - break; - case JD_ARRAY: - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - jsondec_skipval(d); +#if UINTPTR_MAX == 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_4Byte: { + uint32_t u32; + memcpy(&u32, mem, 4); + return u32 != 0; } - jsondec_arrend(d); - break; - case JD_TRUE: - jsondec_true(d); - break; - case JD_FALSE: - jsondec_false(d); - break; - case JD_NULL: - jsondec_null(d); +#if UINTPTR_MAX != 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_8Byte: { + uint64_t u64; + memcpy(&u64, mem, 8); + return u64 != 0; + } + case kUpb_FieldRep_StringView: { + const upb_StringView* str = (const upb_StringView*)mem; + return str->size != 0; + } + default: + UPB_UNREACHABLE(); + } + } else if (f->presence > 0) { + /* Proto2 presence: hasbit. */ + return _upb_hasbit_field(msg, f); + } else { + /* Field is in a oneof. */ + return _upb_getoneofcase_field(msg, f) == f->number; + } +} + +static void encode_field(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + switch (upb_FieldMode_Get(field)) { + case kUpb_FieldMode_Array: + encode_array(e, msg, subs, field); break; - case JD_STRING: - jsondec_string(d); + case kUpb_FieldMode_Map: + encode_map(e, msg, subs, field); break; - case JD_NUMBER: - jsondec_number(d); + case kUpb_FieldMode_Scalar: + encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field); break; + default: + UPB_UNREACHABLE(); } } -/* Base64 decoding for bytes fields. ******************************************/ - -static unsigned int jsondec_base64_tablelookup(const char ch) { - /* Table includes the normal base64 chars plus the URL-safe variant. */ - const signed char table[256] = { - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, - 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, - 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, - -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, - 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, - 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, - 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, - -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, - 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, - 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, - 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, - 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1}; - - /* Sign-extend return value so high bit will be set on any unexpected char. */ - return table[(unsigned)ch]; +/* message MessageSet { + * repeated group Item = 1 { + * required int32 type_id = 2; + * required string message = 3; + * } + * } */ +static void encode_msgset_item(upb_encstate* e, + const upb_Message_Extension* ext) { + size_t size; + encode_tag(e, 1, kUpb_WireType_EndGroup); + encode_message(e, ext->data.ptr, ext->ext->sub.submsg, &size); + encode_varint(e, size); + encode_tag(e, 3, kUpb_WireType_Delimited); + encode_varint(e, ext->ext->field.number); + encode_tag(e, 2, kUpb_WireType_Varint); + encode_tag(e, 1, kUpb_WireType_StartGroup); } -static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, - char* out) { - int32_t val = -1; - - switch (end - ptr) { - case 2: - val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12; - out[0] = val >> 16; - out += 1; - break; - case 3: - val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12 | - jsondec_base64_tablelookup(ptr[2]) << 6; - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out += 2; - break; - } +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size) { + size_t pre_len = e->limit - e->ptr; - if (val < 0) { - jsondec_err(d, "Corrupt base64"); + if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) { + uint64_t msg_head; + memcpy(&msg_head, msg, 8); + msg_head = _upb_BigEndian_Swap64(msg_head); + if (upb_MiniTable_requiredmask(m) & ~msg_head) { + encode_err(e); + } } - return out; -} - -static size_t jsondec_base64(jsondec* d, upb_StringView str) { - /* We decode in place. This is safe because this is a new buffer (not - * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ - char* out = (char*)str.data; - const char* ptr = str.data; - const char* end = ptr + str.size; - const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ + if ((e->options & kUpb_Encode_SkipUnknown) == 0) { + size_t unknown_size; + const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); - for (; ptr < end4; ptr += 4, out += 3) { - int val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12 | - jsondec_base64_tablelookup(ptr[2]) << 6 | - jsondec_base64_tablelookup(ptr[3]) << 0; + if (unknown) { + encode_bytes(e, unknown, unknown_size); + } + } - if (val < 0) { - /* Junk chars or padding. Remove trailing padding, if any. */ - if (end - ptr == 4 && ptr[3] == '=') { - if (ptr[2] == '=') { - end -= 2; + if (m->ext != kUpb_ExtMode_NonExtendable) { + /* Encode all extensions together. Unlike C++, we do not attempt to keep + * these in field number order relative to normal fields or even to each + * other. */ + size_t ext_count; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count); + if (ext_count) { + const upb_Message_Extension* end = ext + ext_count; + for (; ext != end; ext++) { + if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) { + encode_msgset_item(e, ext); } else { - end -= 1; + encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); } } - break; } + } - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out[2] = val & 0xff; + if (m->field_count) { + const upb_MiniTable_Field* f = &m->fields[m->field_count]; + const upb_MiniTable_Field* first = &m->fields[0]; + while (f != first) { + f--; + if (encode_shouldencode(e, msg, m->subs, f)) { + encode_field(e, msg, m->subs, f); + } + } } - if (ptr < end) { - /* Process remaining chars. We do not require padding. */ - out = jsondec_partialbase64(d, ptr, end, out); + *size = (e->limit - e->ptr) - pre_len; +} + +char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, + upb_Arena* arena, size_t* size) { + upb_encstate e; + unsigned depth = (unsigned)options >> 16; + + e.alloc = upb_Arena_Alloc(arena); + e.buf = NULL; + e.limit = NULL; + e.ptr = NULL; + e.depth = depth ? depth : 64; + e.options = options; + _upb_mapsorter_init(&e.sorter); + char* ret = NULL; + + if (UPB_SETJMP(e.err)) { + *size = 0; + ret = NULL; + } else { + encode_message(&e, msg, l, size); + *size = e.limit - e.ptr; + if (*size == 0) { + static char ch; + ret = &ch; + } else { + UPB_ASSERT(e.ptr); + ret = e.ptr; + } } - return out - str.data; + _upb_mapsorter_destroy(&e.sorter); + return ret; } -/* Low-level integer parsing **************************************************/ +/** upb/msg.c ************************************************************/ -/* We use these hand-written routines instead of strto[u]l() because the "long - * long" variants aren't in c89. Also our version allows setting a ptr limit. */ -static const char* jsondec_buftouint64(jsondec* d, const char* ptr, - const char* end, uint64_t* val) { - uint64_t u64 = 0; - while (ptr < end) { - unsigned ch = *ptr - '0'; - if (ch >= 10) break; - if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { - jsondec_err(d, "Integer overflow"); +/** upb_Message ***************************************************************/ + +static const size_t overhead = sizeof(upb_Message_InternalData); + +static const upb_Message_Internal* upb_Message_Getinternal_const( + const upb_Message* msg) { + ptrdiff_t size = sizeof(upb_Message_Internal); + return (upb_Message_Internal*)((char*)msg - size); +} + +upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a) { + return _upb_Message_New_inl(l, a); +} + +void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { + void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char); + memset(mem, 0, upb_msg_sizeof(l)); +} + +static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (!in->internal) { + /* No internal data, allocate from scratch. */ + size_t size = UPB_MAX(128, _upb_Log2CeilingSize(need + overhead)); + upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); + if (!internal) return false; + internal->size = size; + internal->unknown_end = overhead; + internal->ext_begin = size; + in->internal = internal; + } else if (in->internal->ext_begin - in->internal->unknown_end < need) { + /* Internal data is too small, reallocate. */ + size_t new_size = _upb_Log2CeilingSize(in->internal->size + need); + size_t ext_bytes = in->internal->size - in->internal->ext_begin; + size_t new_ext_begin = new_size - ext_bytes; + upb_Message_InternalData* internal = + upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size); + if (!internal) return false; + if (ext_bytes) { + /* Need to move extension data to the end. */ + char* ptr = (char*)internal; + memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes); } - u64 *= 10; - u64 += ch; - ptr++; + internal->ext_begin = new_ext_begin; + internal->size = new_size; + in->internal = internal; } - - *val = u64; - return ptr; + UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); + return true; } -static const char* jsondec_buftoint64(jsondec* d, const char* ptr, - const char* end, int64_t* val) { - bool neg = false; - uint64_t u64; - - if (ptr != end && *ptr == '-') { - ptr++; - neg = true; - } +bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, + upb_Arena* arena) { + if (!realloc_internal(msg, len, arena)) return false; + upb_Message_Internal* in = upb_Message_Getinternal(msg); + memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len); + in->internal->unknown_end += len; + return true; +} - ptr = jsondec_buftouint64(d, ptr, end, &u64); - if (u64 > (uint64_t)INT64_MAX + neg) { - jsondec_err(d, "Integer overflow"); +void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (in->internal) { + in->internal->unknown_end = overhead; } - - *val = neg ? -u64 : u64; - return ptr; } -static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { - const char* end = str.data + str.size; - uint64_t ret; - if (jsondec_buftouint64(d, str.data, end, &ret) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { + const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); + if (in->internal) { + *len = in->internal->unknown_end - overhead; + return (char*)(in->internal + 1); + } else { + *len = 0; + return NULL; } - return ret; } -static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { - const char* end = str.data + str.size; - int64_t ret; - if (jsondec_buftoint64(d, str.data, end, &ret) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count) { + const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); + if (in->internal) { + *count = (in->internal->size - in->internal->ext_begin) / + sizeof(upb_Message_Extension); + return UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + } else { + *count = 0; + return NULL; } - return ret; } -/* Primitive value types ******************************************************/ - -/* Parse INT32 or INT64 value. */ -static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; - - switch (jsondec_peek(d)) { - case JD_NUMBER: { - double dbl = jsondec_number(d); - if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { - jsondec_err(d, "JSON number is out of range."); - } - val.int64_val = dbl; /* must be guarded, overflow here is UB */ - if (val.int64_val != dbl) { - jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, - val.int64_val); - } - break; - } - case JD_STRING: { - upb_StringView str = jsondec_string(d); - val.int64_val = jsondec_strtoint64(d, str); - break; - } - default: - jsondec_err(d, "Expected number or string"); - } +const upb_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTable_Extension* e) { + size_t n; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); - if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || - upb_FieldDef_CType(f) == kUpb_CType_Enum) { - if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { - jsondec_err(d, "Integer out of range."); + /* For now we use linear search exclusively to find extensions. If this + * becomes an issue due to messages with lots of extensions, we can introduce + * a table of some sort. */ + for (size_t i = 0; i < n; i++) { + if (ext[i].ext == e) { + return &ext[i]; } - val.int32_val = (int32_t)val.int64_val; } - return val; + return NULL; } -/* Parse UINT32 or UINT64 value. */ -static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val = {0}; - - switch (jsondec_peek(d)) { - case JD_NUMBER: { - double dbl = jsondec_number(d); - if (dbl > 18446744073709549568.0 || dbl < 0) { - jsondec_err(d, "JSON number is out of range."); - } - val.uint64_val = dbl; /* must be guarded, overflow here is UB */ - if (val.uint64_val != dbl) { - jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, - val.uint64_val); - } - break; - } - case JD_STRING: { - upb_StringView str = jsondec_string(d); - val.uint64_val = jsondec_strtouint64(d, str); - break; - } - default: - jsondec_err(d, "Expected number or string"); - } - - if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { - if (val.uint64_val > UINT32_MAX) { - jsondec_err(d, "Integer out of range."); - } - val.uint32_val = (uint32_t)val.uint64_val; +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTable_Extension* ext_l) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (!in->internal) return; + const upb_Message_Extension* base = + UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + upb_Message_Extension* ext = + (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); + if (ext) { + *ext = *base; + in->internal->ext_begin += sizeof(upb_Message_Extension); } +} - return val; +upb_Message_Extension* _upb_Message_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) { + upb_Message_Extension* ext = + (upb_Message_Extension*)_upb_Message_Getext(msg, e); + if (ext) return ext; + if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL; + upb_Message_Internal* in = upb_Message_Getinternal(msg); + in->internal->ext_begin -= sizeof(upb_Message_Extension); + ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + memset(ext, 0, sizeof(upb_Message_Extension)); + ext->ext = e; + return ext; } -/* Parse DOUBLE or FLOAT value. */ -static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { - upb_StringView str; - upb_MessageValue val = {0}; +size_t upb_Message_ExtensionCount(const upb_Message* msg) { + size_t count; + _upb_Message_Getexts(msg, &count); + return count; +} - switch (jsondec_peek(d)) { - case JD_NUMBER: - val.double_val = jsondec_number(d); - break; - case JD_STRING: - str = jsondec_string(d); - if (jsondec_streql(str, "NaN")) { - val.double_val = NAN; - } else if (jsondec_streql(str, "Infinity")) { - val.double_val = INFINITY; - } else if (jsondec_streql(str, "-Infinity")) { - val.double_val = -INFINITY; - } else { - val.double_val = strtod(str.data, NULL); - } - break; - default: - jsondec_err(d, "Expected number or string"); - } +/** upb_Array *****************************************************************/ - if (upb_FieldDef_CType(f) == kUpb_CType_Float) { - if (val.double_val != INFINITY && val.double_val != -INFINITY && - (val.double_val > FLT_MAX || val.double_val < -FLT_MAX)) { - jsondec_err(d, "Float out of range"); - } - val.float_val = val.double_val; - } +bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena) { + size_t new_size = UPB_MAX(arr->size, 4); + int elem_size_lg2 = arr->data & 7; + size_t old_bytes = arr->size << elem_size_lg2; + size_t new_bytes; + void* ptr = _upb_array_ptr(arr); - return val; -} + /* Log2 ceiling of size. */ + while (new_size < min_size) new_size *= 2; -/* Parse STRING or BYTES value. */ -static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; - val.str_val = jsondec_string(d); - if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { - val.str_val.size = jsondec_base64(d, val.str_val); - } - return val; -} + new_bytes = new_size << elem_size_lg2; + ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); -static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { - switch (jsondec_peek(d)) { - case JD_STRING: { - upb_StringView str = jsondec_string(d); - const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); - const upb_EnumValueDef* ev = - upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); - upb_MessageValue val; - if (ev) { - val.int32_val = upb_EnumValueDef_Number(ev); - } else { - if (d->options & upb_JsonDecode_IgnoreUnknown) { - val.int32_val = 0; - } else { - jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(str)); - } - } - return val; - } - case JD_NULL: { - if (jsondec_isnullvalue(f)) { - upb_MessageValue val; - jsondec_null(d); - val.int32_val = 0; - return val; - } - } - /* Fallthrough. */ - default: - return jsondec_int(d, f); + if (!ptr) { + return false; } -} -static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { - bool is_map_key = upb_FieldDef_Number(f) == 1 && - upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); - upb_MessageValue val; + arr->data = _upb_tag_arrptr(ptr, elem_size_lg2); + arr->size = new_size; + return true; +} - if (is_map_key) { - upb_StringView str = jsondec_string(d); - if (jsondec_streql(str, "true")) { - val.bool_val = true; - } else if (jsondec_streql(str, "false")) { - val.bool_val = false; - } else { - jsondec_err(d, "Invalid boolean map key"); - } - } else { - switch (jsondec_peek(d)) { - case JD_TRUE: - val.bool_val = true; - jsondec_true(d); - break; - case JD_FALSE: - val.bool_val = false; - jsondec_false(d); - break; - default: - jsondec_err(d, "Expected true or false"); - } +static upb_Array* getorcreate_array(upb_Array** arr_ptr, int elem_size_lg2, + upb_Arena* arena) { + upb_Array* arr = *arr_ptr; + if (!arr) { + arr = _upb_Array_New(arena, 4, elem_size_lg2); + if (!arr) return NULL; + *arr_ptr = arr; } + return arr; +} - return val; +void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, + int elem_size_lg2, upb_Arena* arena) { + upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + return arr && _upb_Array_Resize(arr, size, arena) ? _upb_array_ptr(arr) + : NULL; } -/* Composite types (array/message/map) ****************************************/ +bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, + int elem_size_lg2, upb_Arena* arena) { + upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + if (!arr) return false; -static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { - upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; + size_t elems = arr->len; - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_MessageValue elem = jsondec_value(d, f); - upb_Array_Append(arr, elem, d->arena); + if (!_upb_Array_Resize(arr, elems + 1, arena)) { + return false; } - jsondec_arrend(d); + + char* data = _upb_array_ptr(arr); + memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2); + return true; } -static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { - upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); +/** upb_Map *******************************************************************/ - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, val; - key = jsondec_value(d, key_f); - jsondec_entrysep(d); - val = jsondec_value(d, val_f); - upb_Map_Set(map, key, val, d->arena); +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { + upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); + + if (!map) { + return NULL; } - jsondec_objend(d); + + upb_strtable_init(&map->table, 4, a); + map->key_size = key_size; + map->val_size = value_size; + + return map; } -static void jsondec_tomsg(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { - jsondec_object(d, msg, m); - } else { - jsondec_wellknown(d, msg, m); - } +static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, + void* b_key, size_t size) { + const upb_tabent* const* a = _a; + const upb_tabent* const* b = _b; + upb_StringView a_tabkey = upb_tabstrview((*a)->key); + upb_StringView b_tabkey = upb_tabstrview((*b)->key); + _upb_map_fromkey(a_tabkey, a_key, size); + _upb_map_fromkey(b_tabkey, b_key, size); } -static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { - const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); - upb_Message* msg = upb_Message_New(m, d->arena); - upb_MessageValue val; +#define UPB_COMPARE_INTEGERS(a, b) ((a) < (b) ? -1 : ((a) == (b) ? 0 : 1)) - jsondec_tomsg(d, msg, m); - val.msg_val = msg; - return val; +static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { + int64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return UPB_COMPARE_INTEGERS(a, b); } -static void jsondec_field(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_StringView name; - const upb_FieldDef* f; - const upb_FieldDef* preserved; +static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { + uint64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return UPB_COMPARE_INTEGERS(a, b); +} - name = jsondec_string(d); - jsondec_entrysep(d); +static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { + int32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return UPB_COMPARE_INTEGERS(a, b); +} - if (name.size >= 2 && name.data[0] == '[' && - name.data[name.size - 1] == ']') { - f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, - name.size - 2); - if (f && upb_FieldDef_ContainingType(f) != m) { - jsondec_errf( - d, "Extension %s extends message %s, but was seen in message %s", - upb_FieldDef_FullName(f), - upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), - upb_MessageDef_FullName(m)); - } - } else { - f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); +static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { + uint32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return UPB_COMPARE_INTEGERS(a, b); +} + +static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { + bool a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); + return UPB_COMPARE_INTEGERS(a, b); +} + +static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { + upb_StringView a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); + size_t common_size = UPB_MIN(a.size, b.size); + int cmp = memcmp(a.data, b.data, common_size); + if (cmp) return -cmp; + return UPB_COMPARE_INTEGERS(a.size, b.size); +} + +#undef UPB_COMPARE_INTEGERS + +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted) { + int map_size = _upb_Map_Size(map); + sorted->start = s->size; + sorted->pos = sorted->start; + sorted->end = sorted->start + map_size; + + /* Grow s->entries if necessary. */ + if (sorted->end > s->cap) { + s->cap = _upb_Log2CeilingSize(sorted->end); + s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); + if (!s->entries) return false; } - if (!f) { - if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { - jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(name)); + s->size = sorted->end; + + /* Copy non-empty entries from the table to s->entries. */ + upb_tabent const** dst = &s->entries[sorted->start]; + const upb_tabent* src = map->table.t.entries; + const upb_tabent* end = src + upb_table_size(&map->table.t); + for (; src < end; src++) { + if (!upb_tabent_isempty(src)) { + *dst = src; + dst++; } - jsondec_skipval(d); - return; } + UPB_ASSERT(dst == &s->entries[sorted->end]); - if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { - /* JSON "null" indicates a default value, so no need to set anything. */ - jsondec_null(d); - return; - } + /* Sort entries according to the key type. */ - if (upb_FieldDef_RealContainingOneof(f) && - upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { - jsondec_err(d, "More than one field for this oneof."); + int (*compar)(const void*, const void*); + + switch (key_type) { + case kUpb_FieldType_Int64: + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_SInt64: + compar = _upb_mapsorter_cmpi64; + break; + case kUpb_FieldType_UInt64: + case kUpb_FieldType_Fixed64: + compar = _upb_mapsorter_cmpu64; + break; + case kUpb_FieldType_Int32: + case kUpb_FieldType_SInt32: + case kUpb_FieldType_SFixed32: + case kUpb_FieldType_Enum: + compar = _upb_mapsorter_cmpi32; + break; + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Fixed32: + compar = _upb_mapsorter_cmpu32; + break; + case kUpb_FieldType_Bool: + compar = _upb_mapsorter_cmpbool; + break; + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: + compar = _upb_mapsorter_cmpstr; + break; + default: + UPB_UNREACHABLE(); } - preserved = d->debug_field; - d->debug_field = f; + qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); + return true; +} + +/** upb_ExtensionRegistry *****************************************************/ + +struct upb_ExtensionRegistry { + upb_Arena* arena; + upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ +}; + +#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) + +static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { + memcpy(buf, &l, sizeof(l)); + memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); +} + +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { + upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); + if (!r) return NULL; + r->arena = arena; + if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; + return r; +} - if (upb_FieldDef_IsMap(f)) { - jsondec_map(d, msg, f); - } else if (upb_FieldDef_IsRepeated(f)) { - jsondec_array(d, msg, f); - } else if (upb_FieldDef_IsSubMessage(f)) { - upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; - const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); - jsondec_tomsg(d, submsg, subm); - } else { - upb_MessageValue val = jsondec_value(d, f); - upb_Message_Set(msg, f, val, d->arena); +bool _upb_extreg_add(upb_ExtensionRegistry* r, + const upb_MiniTable_Extension** e, size_t count) { + char buf[EXTREG_KEY_SIZE]; + const upb_MiniTable_Extension** start = e; + const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); + for (; e < end; e++) { + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + upb_value v; + if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { + goto failure; + } + if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, + upb_value_constptr(ext), r->arena)) { + goto failure; + } } + return true; - d->debug_field = preserved; -} - -static void jsondec_object(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - jsondec_objstart(d); - while (jsondec_objnext(d)) { - jsondec_field(d, msg, m); +failure: + /* Back out the entries previously added. */ + for (end = e, e = start; e < end; e++) { + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); } - jsondec_objend(d); + return false; } -static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - return jsondec_bool(d, f); - case kUpb_CType_Float: - case kUpb_CType_Double: - return jsondec_double(d, f); - case kUpb_CType_UInt32: - case kUpb_CType_UInt64: - return jsondec_uint(d, f); - case kUpb_CType_Int32: - case kUpb_CType_Int64: - return jsondec_int(d, f); - case kUpb_CType_String: - case kUpb_CType_Bytes: - return jsondec_strfield(d, f); - case kUpb_CType_Enum: - return jsondec_enum(d, f); - case kUpb_CType_Message: - return jsondec_msg(d, f); - default: - UPB_UNREACHABLE(); +const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, + const upb_MiniTable* l, + uint32_t num) { + char buf[EXTREG_KEY_SIZE]; + upb_value v; + extreg_key(buf, l, num); + if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { + return upb_value_getconstptr(v); + } else { + return NULL; } } -/* Well-known types ***********************************************************/ - -static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, - const char* after) { - uint64_t val; - const char* p = *ptr; - const char* end = p + digits; - size_t after_len = after ? strlen(after) : 0; +/** upb/table.c ************************************************************/ +/* + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ - UPB_ASSERT(digits <= 9); /* int can't overflow. */ +#include - if (jsondec_buftouint64(d, p, end, &val) != end || - (after_len && memcmp(end, after, after_len) != 0)) { - jsondec_err(d, "Malformed timestamp"); - } - UPB_ASSERT(val < INT_MAX); +/* Must be last. */ - *ptr = end + after_len; - return (int)val; -} +#define UPB_MAXARRSIZE 16 /* 64k. */ -static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { - uint64_t nanos = 0; - const char* p = *ptr; +/* From Chromium. */ +#define ARRAY_SIZE(x) \ + ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) - if (p != end && *p == '.') { - const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); - int digits = (int)(nano_end - p - 1); - int exp_lg10 = 9 - digits; - if (digits > 9) { - jsondec_err(d, "Too many digits for partial seconds"); - } - while (exp_lg10--) nanos *= 10; - *ptr = nano_end; - } +static const double MAX_LOAD = 0.85; - UPB_ASSERT(nanos < INT_MAX); +/* The minimum utilization of the array part of a mixed hash/array table. This + * is a speed/memory-usage tradeoff (though it's not straightforward because of + * cache effects). The lower this is, the more memory we'll use. */ +static const double MIN_DENSITY = 0.1; - return (int)nanos; -} +static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } -/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ -int jsondec_epochdays(int y, int m, int d) { - const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ - const uint32_t m_adj = m - 3; /* March-based month. */ - const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; - const uint32_t adjust = carry ? 12 : 0; - const uint32_t y_adj = y + year_base - carry; - const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; - const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; - return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +static upb_value _upb_value_val(uint64_t val) { + upb_value ret; + _upb_value_setval(&ret, val); + return ret; } -static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { - return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; +static int log2ceil(uint64_t v) { + int ret = 0; + bool pow2 = is_pow2(v); + while (v >>= 1) ret++; + ret = pow2 ? ret : ret + 1; /* Ceiling. */ + return UPB_MIN(UPB_MAXARRSIZE, ret); } -static void jsondec_timestamp(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue seconds; - upb_MessageValue nanos; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - - if (str.size < 20) goto malformed; - - { - /* 1972-01-01T01:00:00 */ - int year = jsondec_tsdigits(d, &ptr, 4, "-"); - int mon = jsondec_tsdigits(d, &ptr, 2, "-"); - int day = jsondec_tsdigits(d, &ptr, 2, "T"); - int hour = jsondec_tsdigits(d, &ptr, 2, ":"); - int min = jsondec_tsdigits(d, &ptr, 2, ":"); - int sec = jsondec_tsdigits(d, &ptr, 2, NULL); +char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { + size_t n; + char* p; - seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); + /* Prevent overflow errors. */ + if (len == SIZE_MAX) return NULL; + /* Always null-terminate, even if binary data; but don't rely on the input to + * have a null-terminating byte since it may be a raw binary buffer. */ + n = len + 1; + p = upb_Arena_Malloc(a, n); + if (p) { + memcpy(p, s, len); + p[len] = 0; } + return p; +} - nanos.int32_val = jsondec_nanos(d, &ptr, end); +/* A type to represent the lookup key of either a strtable or an inttable. */ +typedef union { + uintptr_t num; + struct { + const char* str; + size_t len; + } str; +} lookupkey_t; - { - /* [+-]08:00 or Z */ - int ofs_hour = 0; - int ofs_min = 0; - bool neg = false; +static lookupkey_t strkey2(const char* str, size_t len) { + lookupkey_t k; + k.str.str = str; + k.str.len = len; + return k; +} - if (ptr == end) goto malformed; +static lookupkey_t intkey(uintptr_t key) { + lookupkey_t k; + k.num = key; + return k; +} - switch (*ptr++) { - case '-': - neg = true; - /* fallthrough */ - case '+': - if ((end - ptr) != 5) goto malformed; - ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); - ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); - ofs_min = ((ofs_hour * 60) + ofs_min) * 60; - seconds.int64_val += (neg ? ofs_min : -ofs_min); - break; - case 'Z': - if (ptr != end) goto malformed; - break; - default: - goto malformed; - } - } +typedef uint32_t hashfunc_t(upb_tabkey key); +typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); - if (seconds.int64_val < -62135596800) { - jsondec_err(d, "Timestamp out of range"); - } +/* Base table (shared code) ***************************************************/ - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); - return; +static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } -malformed: - jsondec_err(d, "Malformed timestamp"); +static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { + return t->entries + (hash & t->mask); } -static void jsondec_duration(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue seconds; - upb_MessageValue nanos; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - const int64_t max = (uint64_t)3652500 * 86400; +static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } - /* "3.000000001s", "3s", etc. */ - ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val); - nanos.int32_val = jsondec_nanos(d, &ptr, end); +static bool isfull(upb_table* t) { return t->count == t->max_count; } - if (end - ptr != 1 || *ptr != 's') { - jsondec_err(d, "Malformed duration"); - } +static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { + size_t bytes; - if (seconds.int64_val < -max || seconds.int64_val > max) { - jsondec_err(d, "Duration out of range"); + t->count = 0; + t->size_lg2 = size_lg2; + t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; + t->max_count = upb_table_size(t) * MAX_LOAD; + bytes = upb_table_size(t) * sizeof(upb_tabent); + if (bytes > 0) { + t->entries = upb_Arena_Malloc(a, bytes); + if (!t->entries) return false; + memset(t->entries, 0, bytes); + } else { + t->entries = NULL; } + return true; +} - if (seconds.int64_val < 0) { - nanos.int32_val = -nanos.int32_val; +static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { + upb_tabent* begin = t->entries; + upb_tabent* end = begin + upb_table_size(t); + for (e = e + 1; e < end; e++) { + if (upb_tabent_isempty(e)) return e; } - - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); + for (e = begin; e < end; e++) { + if (upb_tabent_isempty(e)) return e; + } + UPB_ASSERT(false); + return NULL; } -static void jsondec_listvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); - upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; - - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_Message* value_msg = upb_Message_New(value_m, d->arena); - upb_MessageValue value; - value.msg_val = value_msg; - upb_Array_Append(values, value, d->arena); - jsondec_wellknownvalue(d, value_msg, value_m); - } - jsondec_arrend(d); +static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { + return (upb_tabent*)upb_getentry(t, hash); } -static void jsondec_struct(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); - upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; +static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e; - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, value; - upb_Message* value_msg = upb_Message_New(value_m, d->arena); - key.str_val = jsondec_string(d); - value.msg_val = value_msg; - upb_Map_Set(fields, key, value, d->arena); - jsondec_entrysep(d); - jsondec_wellknownvalue(d, value_msg, value_m); + if (t->size_lg2 == 0) return NULL; + e = upb_getentry(t, hash); + if (upb_tabent_isempty(e)) return NULL; + while (1) { + if (eql(e->key, key)) return e; + if ((e = e->next) == NULL) return NULL; } - jsondec_objend(d); } -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue val; - const upb_FieldDef* f; - upb_Message* submsg; +static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + return (upb_tabent*)findentry(t, key, hash, eql); +} - switch (jsondec_peek(d)) { - case JD_NUMBER: - /* double number_value = 2; */ - f = upb_MessageDef_FindFieldByNumber(m, 2); - val.double_val = jsondec_number(d); - break; - case JD_STRING: - /* string string_value = 3; */ - f = upb_MessageDef_FindFieldByNumber(m, 3); - val.str_val = jsondec_string(d); - break; - case JD_FALSE: - /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumber(m, 4); - val.bool_val = false; - jsondec_false(d); - break; - case JD_TRUE: - /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumber(m, 4); - val.bool_val = true; - jsondec_true(d); - break; - case JD_NULL: - /* NullValue null_value = 1; */ - f = upb_MessageDef_FindFieldByNumber(m, 1); - val.int32_val = 0; - jsondec_null(d); - break; - /* Note: these cases return, because upb_Message_Mutable() is enough. */ - case JD_OBJECT: - /* Struct struct_value = 5; */ - f = upb_MessageDef_FindFieldByNumber(m, 5); - submsg = upb_Message_Mutable(msg, f, d->arena).msg; - jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); - return; - case JD_ARRAY: - /* ListValue list_value = 6; */ - f = upb_MessageDef_FindFieldByNumber(m, 6); - submsg = upb_Message_Mutable(msg, f, d->arena).msg; - jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); - return; - default: - UPB_UNREACHABLE(); +static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e = findentry(t, key, hash, eql); + if (e) { + if (v) { + _upb_value_setval(v, e->val.val); + } + return true; + } else { + return false; } - - upb_Message_Set(msg, f, val, d->arena); } -static upb_StringView jsondec_mask(jsondec* d, const char* buf, - const char* end) { - /* FieldMask fields grow due to inserted '_' characters, so we can't do the - * transform in place. */ - const char* ptr = buf; - upb_StringView ret; - char* out; +/* The given key must not already exist in the table. */ +static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey, + upb_value val, uint32_t hash, hashfunc_t* hashfunc, + eqlfunc_t* eql) { + upb_tabent* mainpos_e; + upb_tabent* our_e; - ret.size = end - ptr; - while (ptr < end) { - ret.size += (*ptr >= 'A' && *ptr <= 'Z'); - ptr++; - } + UPB_ASSERT(findentry(t, key, hash, eql) == NULL); - out = upb_Arena_Malloc(d->arena, ret.size); - ptr = buf; - ret.data = out; + t->count++; + mainpos_e = getentry_mutable(t, hash); + our_e = mainpos_e; - while (ptr < end) { - char ch = *ptr++; - if (ch >= 'A' && ch <= 'Z') { - *out++ = '_'; - *out++ = ch + 32; - } else if (ch == '_') { - jsondec_err(d, "field mask may not contain '_'"); + if (upb_tabent_isempty(mainpos_e)) { + /* Our main position is empty; use it. */ + our_e->next = NULL; + } else { + /* Collision. */ + upb_tabent* new_e = emptyent(t, mainpos_e); + /* Head of collider's chain. */ + upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key)); + if (chain == mainpos_e) { + /* Existing ent is in its main position (it has the same hash as us, and + * is the head of our chain). Insert to new ent and append to this chain. + */ + new_e->next = mainpos_e->next; + mainpos_e->next = new_e; + our_e = new_e; } else { - *out++ = ch; + /* Existing ent is not in its main position (it is a node in some other + * chain). This implies that no existing ent in the table has our hash. + * Evict it (updating its chain) and use its ent for head of our chain. */ + *new_e = *mainpos_e; /* copies next. */ + while (chain->next != mainpos_e) { + chain = (upb_tabent*)chain->next; + UPB_ASSERT(chain); + } + chain->next = new_e; + our_e = mainpos_e; + our_e->next = NULL; } } - - return ret; + our_e->key = tabkey; + our_e->val.val = val.val; + UPB_ASSERT(findentry(t, key, hash, eql) == our_e); } -static void jsondec_fieldmask(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - /* repeated string paths = 1; */ - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - upb_MessageValue val; - - while (ptr < end) { - const char* elem_end = memchr(ptr, ',', end - ptr); - if (elem_end) { - val.str_val = jsondec_mask(d, ptr, elem_end); - ptr = elem_end + 1; +static bool rm(upb_table* t, lookupkey_t key, upb_value* val, + upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) { + upb_tabent* chain = getentry_mutable(t, hash); + if (upb_tabent_isempty(chain)) return false; + if (eql(chain->key, key)) { + /* Element to remove is at the head of its chain. */ + t->count--; + if (val) _upb_value_setval(val, chain->val.val); + if (removed) *removed = chain->key; + if (chain->next) { + upb_tabent* move = (upb_tabent*)chain->next; + *chain = *move; + move->key = 0; /* Make the slot empty. */ + } else { + chain->key = 0; /* Make the slot empty. */ + } + return true; + } else { + /* Element to remove is either in a non-head position or not in the + * table. */ + while (chain->next && !eql(chain->next->key, key)) { + chain = (upb_tabent*)chain->next; + } + if (chain->next) { + /* Found element to remove. */ + upb_tabent* rm = (upb_tabent*)chain->next; + t->count--; + if (val) _upb_value_setval(val, chain->next->val.val); + if (removed) *removed = rm->key; + rm->key = 0; /* Make the slot empty. */ + chain->next = rm->next; + return true; } else { - val.str_val = jsondec_mask(d, ptr, end); - ptr = end; + /* Element to remove is not in the table. */ + return false; } - upb_Array_Append(arr, val, d->arena); } } -static void jsondec_anyfield(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { - /* For regular types: {"@type": "[user type]", "f1": , "f2": } - * where f1, f2, etc. are the normal fields of this type. */ - jsondec_field(d, msg, m); - } else { - /* For well-known types: {"@type": "[well-known type]", "value": } - * where is whatever encoding the WKT normally uses. */ - upb_StringView str = jsondec_string(d); - jsondec_entrysep(d); - if (!jsondec_streql(str, "value")) { - jsondec_err(d, "Key for well-known type must be 'value'"); - } - jsondec_wellknown(d, msg, m); - } +static size_t next(const upb_table* t, size_t i) { + do { + if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ + } while (upb_tabent_isempty(&t->entries[i])); + + return i; } -static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* type_m; - upb_StringView type_url = jsondec_string(d); - const char* end = type_url.data + type_url.size; - const char* ptr = end; - upb_MessageValue val; +static size_t begin(const upb_table* t) { return next(t, -1); } - val.str_val = type_url; - upb_Message_Set(msg, type_url_f, val, d->arena); +/* upb_strtable ***************************************************************/ - /* Find message name after the last '/' */ - while (ptr > type_url.data && *--ptr != '/') { - } +/* A simple "subclass" of upb_table that only adds a hash function for strings. + */ - if (ptr == type_url.data || ptr == end) { - jsondec_err(d, "Type url must have at least one '/' and non-empty host"); - } +static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) { + uint32_t len = (uint32_t)k2.str.len; + char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1); + if (str == NULL) return 0; + memcpy(str, &len, sizeof(uint32_t)); + if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); + str[sizeof(uint32_t) + k2.str.len] = '\0'; + return (uintptr_t)str; +} - ptr++; - type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); +/* Adapted from ABSL's wyhash. */ - if (!type_m) { - jsondec_err(d, "Type was not found"); - } +static uint64_t UnalignedLoad64(const void* p) { + uint64_t val; + memcpy(&val, p, 8); + return val; +} - return type_m; +static uint32_t UnalignedLoad32(const void* p) { + uint32_t val; + memcpy(&val, p, 4); + return val; } -static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { - /* string type_url = 1; - * bytes value = 2; */ - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); - upb_Message* any_msg; - const upb_MessageDef* any_m = NULL; - const char* pre_type_data = NULL; - const char* pre_type_end = NULL; - upb_MessageValue encoded; +#if defined(_MSC_VER) && defined(_M_X64) +#include +#endif - jsondec_objstart(d); +/* Computes a * b, returning the low 64 bits of the result and storing the high + * 64 bits in |*high|. */ +static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { +#ifdef __SIZEOF_INT128__ + __uint128_t p = v0; + p *= v1; + *out_high = (uint64_t)(p >> 64); + return (uint64_t)p; +#elif defined(_MSC_VER) && defined(_M_X64) + return _umul128(v0, v1, out_high); +#else + uint64_t a32 = v0 >> 32; + uint64_t a00 = v0 & 0xffffffff; + uint64_t b32 = v1 >> 32; + uint64_t b00 = v1 & 0xffffffff; + uint64_t high = a32 * b32; + uint64_t low = a00 * b00; + uint64_t mid1 = a32 * b00; + uint64_t mid2 = a00 * b32; + low += (mid1 << 32) + (mid2 << 32); + // Omit carry bit, for mixing we do not care about exact numerical precision. + high += (mid1 >> 32) + (mid2 >> 32); + *out_high = high; + return low; +#endif +} - /* Scan looking for "@type", which is not necessarily first. */ - while (!any_m && jsondec_objnext(d)) { - const char* start = d->ptr; - upb_StringView name = jsondec_string(d); - jsondec_entrysep(d); - if (jsondec_streql(name, "@type")) { - any_m = jsondec_typeurl(d, msg, m); - if (pre_type_data) { - pre_type_end = start; - while (*pre_type_end != ',') pre_type_end--; - } - } else { - if (!pre_type_data) pre_type_data = start; - jsondec_skipval(d); - } - } +static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { + uint64_t high; + uint64_t low = upb_umul128(v0, v1, &high); + return low ^ high; +} - if (!any_m) { - jsondec_err(d, "Any object didn't contain a '@type' field"); - } +static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, + const uint64_t salt[]) { + const uint8_t* ptr = (const uint8_t*)data; + uint64_t starting_length = (uint64_t)len; + uint64_t current_state = seed ^ salt[0]; - any_msg = upb_Message_New(any_m, d->arena); + if (len > 64) { + // If we have more than 64 bytes, we're going to handle chunks of 64 + // bytes at a time. We're going to build up two separate hash states + // which we will then hash together. + uint64_t duplicated_state = current_state; - if (pre_type_data) { - size_t len = pre_type_end - pre_type_data + 1; - char* tmp = upb_Arena_Malloc(d->arena, len); - const char* saved_ptr = d->ptr; - const char* saved_end = d->end; - memcpy(tmp, pre_type_data, len - 1); - tmp[len - 1] = '}'; - d->ptr = tmp; - d->end = tmp + len; - d->is_first = true; - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); - } - d->ptr = saved_ptr; - d->end = saved_end; - } + do { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); + uint64_t c = UnalignedLoad64(ptr + 16); + uint64_t d = UnalignedLoad64(ptr + 24); + uint64_t e = UnalignedLoad64(ptr + 32); + uint64_t f = UnalignedLoad64(ptr + 40); + uint64_t g = UnalignedLoad64(ptr + 48); + uint64_t h = UnalignedLoad64(ptr + 56); - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); + uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); + current_state = (cs0 ^ cs1); + + uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); + uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); + duplicated_state = (ds0 ^ ds1); + + ptr += 64; + len -= 64; + } while (len > 64); + + current_state = current_state ^ duplicated_state; } - jsondec_objend(d); + // We now have a data `ptr` with at most 64 bytes and the current state + // of the hashing state machine stored in current_state. + while (len > 16) { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); - encoded.str_val.data = upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, - d->arena, &encoded.str_val.size); - upb_Message_Set(msg, value_f, encoded, d->arena); -} + current_state = WyhashMix(a ^ salt[1], b ^ current_state); -static void jsondec_wrapper(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_MessageValue val = jsondec_value(d, value_f); - upb_Message_Set(msg, value_f, val, d->arena); -} + ptr += 16; + len -= 16; + } -static void jsondec_wellknown(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - switch (upb_MessageDef_WellKnownType(m)) { - case kUpb_WellKnown_Any: - jsondec_any(d, msg, m); - break; - case kUpb_WellKnown_FieldMask: - jsondec_fieldmask(d, msg, m); - break; - case kUpb_WellKnown_Duration: - jsondec_duration(d, msg, m); - break; - case kUpb_WellKnown_Timestamp: - jsondec_timestamp(d, msg, m); - break; - case kUpb_WellKnown_Value: - jsondec_wellknownvalue(d, msg, m); - break; - case kUpb_WellKnown_ListValue: - jsondec_listvalue(d, msg, m); - break; - case kUpb_WellKnown_Struct: - jsondec_struct(d, msg, m); - break; - case kUpb_WellKnown_DoubleValue: - case kUpb_WellKnown_FloatValue: - case kUpb_WellKnown_Int64Value: - case kUpb_WellKnown_UInt64Value: - case kUpb_WellKnown_Int32Value: - case kUpb_WellKnown_UInt32Value: - case kUpb_WellKnown_StringValue: - case kUpb_WellKnown_BytesValue: - case kUpb_WellKnown_BoolValue: - jsondec_wrapper(d, msg, m); - break; - default: - UPB_UNREACHABLE(); + // We now have a data `ptr` with at most 16 bytes. + uint64_t a = 0; + uint64_t b = 0; + if (len > 8) { + // When we have at least 9 and at most 16 bytes, set A to the first 64 + // bits of the input and B to the last 64 bits of the input. Yes, they will + // overlap in the middle if we are working with less than the full 16 + // bytes. + a = UnalignedLoad64(ptr); + b = UnalignedLoad64(ptr + len - 8); + } else if (len > 3) { + // If we have at least 4 and at most 8 bytes, set A to the first 32 + // bits and B to the last 32 bits. + a = UnalignedLoad32(ptr); + b = UnalignedLoad32(ptr + len - 4); + } else if (len > 0) { + // If we have at least 1 and at most 3 bytes, read all of the provided + // bits into A, with some adjustments. + a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); + b = 0; + } else { + a = 0; + b = 0; } + + uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t z = salt[1] ^ starting_length; + return WyhashMix(w, z); } -bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, - const upb_MessageDef* m, const upb_DefPool* symtab, - int options, upb_Arena* arena, upb_Status* status) { - jsondec d; +const uint64_t kWyhashSalt[5] = { + 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, + 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, +}; - if (size == 0) return true; +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); +} - d.ptr = buf; - d.end = buf + size; - d.arena = arena; - d.symtab = symtab; - d.status = status; - d.options = options; - d.depth = 64; - d.line = 1; - d.line_begin = d.ptr; - d.debug_field = NULL; - d.is_first = false; +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, 0); +} - if (UPB_SETJMP(d.err)) return false; +static uint32_t strhash(upb_tabkey key) { + uint32_t len; + char* str = upb_tabstr(key, &len); + return _upb_Hash_NoSeed(str, len); +} - jsondec_tomsg(&d, msg, m); - return true; +static bool streql(upb_tabkey k1, lookupkey_t k2) { + uint32_t len; + char* str = upb_tabstr(k1, &len); + return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); } -/** upb/json_encode.c ************************************************************/ +bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { + // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 + // denominator. + size_t need_entries = (expected_size + 1) * 1204 / 1024; + UPB_ASSERT(need_entries >= expected_size * 0.85); + int size_lg2 = _upb_Log2Ceiling(need_entries); + return init(&t->t, size_lg2, a); +} -#include -#include -#include -#include -#include -#include -#include -#include +void upb_strtable_clear(upb_strtable* t) { + size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); + t->t.count = 0; + memset((char*)t->t.entries, 0, bytes); +} +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { + upb_strtable new_table; + upb_strtable_iter i; -/* Must be last. */ + if (!init(&new_table.t, size_lg2, a)) return false; + upb_strtable_begin(&i, t); + for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_StringView key = upb_strtable_iter_key(&i); + upb_strtable_insert(&new_table, key.data, key.size, + upb_strtable_iter_value(&i), a); + } + *t = new_table; + return true; +} -typedef struct { - char *buf, *ptr, *end; - size_t overflow; - int indent_depth; - int options; - const upb_DefPool* ext_pool; - jmp_buf err; - upb_Status* status; - upb_Arena* arena; -} jsonenc; +bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, + upb_value v, upb_Arena* a) { + lookupkey_t key; + upb_tabkey tabkey; + uint32_t hash; -static void jsonenc_msg(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); -static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f); -static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first); -static void jsonenc_value(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); + if (isfull(&t->t)) { + /* Need to resize. New table of double the size, add old elements to it. */ + if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { + return false; + } + } -UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { - upb_Status_SetErrorMessage(e->status, msg); - longjmp(e->err, 1); -} + key = strkey2(k, len); + tabkey = strcopy(key, a); + if (tabkey == 0) return false; -UPB_PRINTF(2, 3) -UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(e->status, fmt, argp); - va_end(argp); - longjmp(e->err, 1); + hash = _upb_Hash_NoSeed(key.str.str, key.str.len); + insert(&t->t, key, tabkey, v, hash, &strhash, &streql); + return true; } -static upb_Arena* jsonenc_arena(jsonenc* e) { - /* Create lazily, since it's only needed for Any */ - if (!e->arena) { - e->arena = upb_Arena_New(); - } - return e->arena; +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + return lookup(&t->t, strkey2(key, len), v, hash, &streql); } -static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { - size_t have = e->end - e->ptr; - if (UPB_LIKELY(have >= len)) { - memcpy(e->ptr, data, len); - e->ptr += len; - } else { - if (have) { - memcpy(e->ptr, data, have); - e->ptr += have; - } - e->overflow += (len - have); - } +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + upb_tabkey tabkey; + return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); } -static void jsonenc_putstr(jsonenc* e, const char* str) { - jsonenc_putbytes(e, str, strlen(str)); -} +/* Iteration */ -UPB_PRINTF(2, 3) -static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { - size_t n; - size_t have = e->end - e->ptr; - va_list args; +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { + i->t = t; + i->index = begin(&t->t); +} - va_start(args, fmt); - n = vsnprintf(e->ptr, have, fmt, args); - va_end(args); +void upb_strtable_next(upb_strtable_iter* i) { + i->index = next(&i->t->t, i->index); +} - if (UPB_LIKELY(have > n)) { - e->ptr += n; - } else { - e->ptr = UPB_PTRADD(e->ptr, have); - e->overflow += (n - have); - } +bool upb_strtable_done(const upb_strtable_iter* i) { + if (!i->t) return true; + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(str_tabent(i)); } -static void jsonenc_nanos(jsonenc* e, int32_t nanos) { - int digits = 9; +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { + upb_StringView key; + uint32_t len; + UPB_ASSERT(!upb_strtable_done(i)); + key.data = upb_tabstr(str_tabent(i)->key, &len); + key.size = len; + return key; +} - if (nanos == 0) return; - if (nanos < 0 || nanos >= 1000000000) { - jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); - } +upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { + UPB_ASSERT(!upb_strtable_done(i)); + return _upb_value_val(str_tabent(i)->val.val); +} - while (nanos % 1000 == 0) { - nanos /= 1000; - digits -= 3; - } +void upb_strtable_iter_setdone(upb_strtable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; +} - jsonenc_printf(e, ".%.*" PRId32, digits, nanos); +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2) { + if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index; } -static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); - int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; - int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; - int L, N, I, J, K, hour, min, sec; +/* upb_inttable ***************************************************************/ - if (seconds < -62135596800) { - jsonenc_err(e, - "error formatting timestamp as JSON: minimum acceptable value " - "is 0001-01-01T00:00:00Z"); - } else if (seconds > 253402300799) { - jsonenc_err(e, - "error formatting timestamp as JSON: maximum acceptable value " - "is 9999-12-31T23:59:59Z"); - } +/* For inttables we use a hybrid structure where small keys are kept in an + * array and large keys are put in the hash table. */ - /* Julian Day -> Y/M/D, Algorithm from: - * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for - * Processing Calendar Dates," Communications of the Association of - * Computing Machines, vol. 11 (1968), p. 657. */ - seconds += 62135596800; // Ensure seconds is positive. - L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; - N = 4 * L / 146097; - L = L - (146097 * N + 3) / 4; - I = 4000 * (L + 1) / 1461001; - L = L - 1461 * I / 4 + 31; - J = 80 * L / 2447; - K = L - 2447 * J / 80; - L = J / 11; - J = J + 2 - 12 * L; - I = 100 * (N - 49) + I + L; +static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } - sec = seconds % 60; - min = (seconds / 60) % 60; - hour = (seconds / 3600) % 24; +static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } - jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "Z\""); +static upb_tabval* mutable_array(upb_inttable* t) { + return (upb_tabval*)t->array; } -static void jsonenc_duration(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); - int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; - int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; - - if (seconds > 315576000000 || seconds < -315576000000 || - (seconds < 0) != (nanos < 0)) { - jsonenc_err(e, "bad duration"); +static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) { + if (key < t->array_size) { + return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; + } else { + upb_tabent* e = + findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); + return e ? &e->val : NULL; } +} - if (nanos < 0) { - nanos = -nanos; - } +static const upb_tabval* inttable_val_const(const upb_inttable* t, + uintptr_t key) { + return inttable_val((upb_inttable*)t, key); +} - jsonenc_printf(e, "\"%" PRId64, seconds); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "s\""); +size_t upb_inttable_count(const upb_inttable* t) { + return t->t.count + t->array_count; } -static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { - const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); +static void check(upb_inttable* t) { + UPB_UNUSED(t); +#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) + { + /* This check is very expensive (makes inserts/deletes O(N)). */ + size_t count = 0; + upb_inttable_iter i; + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { + UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); + } + UPB_ASSERT(count == upb_inttable_count(t)); + } +#endif +} - if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { - jsonenc_putstr(e, "null"); - } else { - const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e_def, val); +bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, + upb_Arena* a) { + size_t array_bytes; - if (ev) { - jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); - } else { - jsonenc_printf(e, "%" PRId32, val); - } + if (!init(&t->t, hsize_lg2, a)) return false; + /* Always make the array part at least 1 long, so that we know key 0 + * won't be in the hash part, which simplifies things. */ + t->array_size = UPB_MAX(1, asize); + t->array_count = 0; + array_bytes = t->array_size * sizeof(upb_value); + t->array = upb_Arena_Malloc(a, array_bytes); + if (!t->array) { + return false; } + memset(mutable_array(t), 0xff, array_bytes); + check(t); + return true; } -static void jsonenc_bytes(jsonenc* e, upb_StringView str) { - /* This is the regular base64, not the "web-safe" version. */ - static const char base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - const unsigned char* ptr = (unsigned char*)str.data; - const unsigned char* end = UPB_PTRADD(ptr, str.size); - char buf[4]; +bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { + return upb_inttable_sizedinit(t, 0, 4, a); +} - jsonenc_putstr(e, "\""); +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a) { + upb_tabval tabval; + tabval.val = val.val; + UPB_ASSERT( + upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ - while (end - ptr >= 3) { - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; - buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; - buf[3] = base64[ptr[2] & 0x3f]; - jsonenc_putbytes(e, buf, 4); - ptr += 3; - } + if (key < t->array_size) { + UPB_ASSERT(!upb_arrhas(t->array[key])); + t->array_count++; + mutable_array(t)[key].val = val.val; + } else { + if (isfull(&t->t)) { + /* Need to resize the hash part, but we re-use the array part. */ + size_t i; + upb_table new_table; - switch (end - ptr) { - case 2: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; - buf[2] = base64[(ptr[1] & 0xf) << 2]; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); - break; - case 1: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4)]; - buf[2] = '='; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); - break; - } + if (!init(&new_table, t->t.size_lg2 + 1, a)) { + return false; + } - jsonenc_putstr(e, "\""); -} + for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { + const upb_tabent* e = &t->t.entries[i]; + uint32_t hash; + upb_value v; -static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { - const char* ptr = str.data; - const char* end = UPB_PTRADD(ptr, str.size); + _upb_value_setval(&v, e->val.val); + hash = upb_inthash(e->key); + insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); + } - while (ptr < end) { - switch (*ptr) { - case '\n': - jsonenc_putstr(e, "\\n"); - break; - case '\r': - jsonenc_putstr(e, "\\r"); - break; - case '\t': - jsonenc_putstr(e, "\\t"); - break; - case '\"': - jsonenc_putstr(e, "\\\""); - break; - case '\f': - jsonenc_putstr(e, "\\f"); - break; - case '\b': - jsonenc_putstr(e, "\\b"); - break; - case '\\': - jsonenc_putstr(e, "\\\\"); - break; - default: - if ((uint8_t)*ptr < 0x20) { - jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); - } else { - /* This could be a non-ASCII byte. We rely on the string being valid - * UTF-8. */ - jsonenc_putbytes(e, ptr, 1); - } - break; + UPB_ASSERT(t->t.count == new_table.count); + + t->t = new_table; } - ptr++; + insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); } + check(t); + return true; } -static void jsonenc_string(jsonenc* e, upb_StringView str) { - jsonenc_putstr(e, "\""); - jsonenc_stringbody(e, str); - jsonenc_putstr(e, "\""); +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { + const upb_tabval* table_v = inttable_val_const(t, key); + if (!table_v) return false; + if (v) _upb_value_setval(v, table_v->val); + return true; } -static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { - if (val == INFINITY) { - jsonenc_putstr(e, "\"Infinity\""); - } else if (val == -INFINITY) { - jsonenc_putstr(e, "\"-Infinity\""); - } else if (val != val) { - jsonenc_putstr(e, "\"NaN\""); - } else { - return false; - } +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { + upb_tabval* table_v = inttable_val(t, key); + if (!table_v) return false; + table_v->val = val.val; return true; } -static void upb_JsonEncode_Double(jsonenc* e, double val) { - if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; - char buf[32]; - _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); - jsonenc_putstr(e, buf); +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { + bool success; + if (key < t->array_size) { + if (upb_arrhas(t->array[key])) { + upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; + t->array_count--; + if (val) { + _upb_value_setval(val, t->array[key].val); + } + mutable_array(t)[key] = empty; + success = true; + } else { + success = false; + } + } else { + success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); + } + check(t); + return success; } -static void upb_JsonEncode_Float(jsonenc* e, float val) { - if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; - char buf[32]; - _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); - jsonenc_putstr(e, buf); -} +void upb_inttable_compact(upb_inttable* t, upb_Arena* a) { + /* A power-of-two histogram of the table keys. */ + size_t counts[UPB_MAXARRSIZE + 1] = {0}; -static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_MessageValue val = upb_Message_Get(msg, val_f); - jsonenc_scalar(e, val, val_f); -} + /* The max key in each bucket. */ + uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; -static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, - upb_StringView type_url) { - /* Find last '/', if any. */ - const char* end = type_url.data + type_url.size; - const char* ptr = end; - const upb_MessageDef* ret; + upb_inttable_iter i; + size_t arr_count; + int size_lg2; + upb_inttable new_t; - if (!e->ext_pool) { - jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t key = upb_inttable_iter_key(&i); + int bucket = log2ceil(key); + max[bucket] = UPB_MAX(max[bucket], key); + counts[bucket]++; } - if (type_url.size == 0) goto badurl; + /* Find the largest power of two that satisfies the MIN_DENSITY + * definition (while actually having some keys). */ + arr_count = upb_inttable_count(t); - while (true) { - if (--ptr == type_url.data) { - /* Type URL must contain at least one '/', with host before. */ - goto badurl; - } - if (*ptr == '/') { - ptr++; + for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { + if (counts[size_lg2] == 0) { + /* We can halve again without losing any entries. */ + continue; + } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { break; } + + arr_count -= counts[size_lg2]; } - ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); + UPB_ASSERT(arr_count <= upb_inttable_count(t)); - if (!ret) { - jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + { + /* Insert all elements into new, perfectly-sized table. */ + size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ + size_t hash_count = upb_inttable_count(t) - arr_count; + size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; + int hashsize_lg2 = log2ceil(hash_size); + + upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t k = upb_inttable_iter_key(&i); + upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); + } + UPB_ASSERT(new_t.array_size == arr_size); + UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); } + *t = new_t; +} - return ret; +/* Iteration. */ -badurl: - jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(type_url)); +static const upb_tabent* int_tabent(const upb_inttable_iter* i) { + UPB_ASSERT(!i->array_part); + return &i->t->t.entries[i->index]; } -static void jsonenc_any(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); - upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; - upb_StringView value = upb_Message_Get(msg, value_f).str_val; - const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); - const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); - upb_Arena* arena = jsonenc_arena(e); - upb_Message* any = upb_Message_New(any_m, arena); +static upb_tabval int_arrent(const upb_inttable_iter* i) { + UPB_ASSERT(i->array_part); + return i->t->array[i->index]; +} - if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != - kUpb_DecodeStatus_Ok) { - jsonenc_err(e, "Error decoding message in Any"); +void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) { + i->t = t; + i->index = -1; + i->array_part = true; + upb_inttable_next(i); +} + +void upb_inttable_next(upb_inttable_iter* iter) { + const upb_inttable* t = iter->t; + if (iter->array_part) { + while (++iter->index < t->array_size) { + if (upb_arrhas(int_arrent(iter))) { + return; + } + } + iter->array_part = false; + iter->index = begin(&t->t); + } else { + iter->index = next(&t->t, iter->index); } +} - jsonenc_putstr(e, "{\"@type\":"); - jsonenc_string(e, type_url); +bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter) { + intptr_t i = *iter; + if (i < t->array_size) { + while (++i < t->array_size) { + upb_tabval ent = t->array[i]; + if (upb_arrhas(ent)) { + *key = i; + *val = _upb_value_val(ent.val); + *iter = i; + return true; + } + } + } - if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { - /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ - jsonenc_msgfields(e, any, any_m, false); - } else { - /* Well-known type: {"@type": "...","value": } */ - jsonenc_putstr(e, ",\"value\":"); - jsonenc_msgfield(e, any, any_m); + size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + *key = ent->key; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx + t->array_size; + return true; } - jsonenc_putstr(e, "}"); + return false; } -static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { - if (*first) { - *first = false; +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { + intptr_t i = *iter; + if (i < t->array_size) { + t->array_count--; + mutable_array(t)[i].val = -1; } else { - jsonenc_putstr(e, str); + upb_tabent* ent = &t->t.entries[i - t->array_size]; + upb_tabent* prev = NULL; + + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; + } + } + + if (prev) { + prev->next = ent->next; + } + + t->t.count--; + ent->key = 0; + ent->next = NULL; } } -static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { - const char* ptr = path.data; - const char* end = ptr + path.size; +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter) { + size_t tab_idx = next(&t->t, *iter); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + uint32_t len; + key->data = upb_tabstr(ent->key, &len); + key->size = len; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx; + return true; + } - while (ptr < end) { - char ch = *ptr; + return false; +} - if (ch >= 'A' && ch <= 'Z') { - jsonenc_err(e, "Field mask element may not have upper-case letter."); - } else if (ch == '_') { - if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { - jsonenc_err(e, "Underscore must be followed by a lowercase letter."); - } - ch = *++ptr - 32; +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { + intptr_t i = *iter; + upb_tabent* ent = &t->t.entries[i]; + upb_tabent* prev = NULL; + + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; } + } - jsonenc_putbytes(e, &ch, 1); - ptr++; + if (prev) { + prev->next = ent->next; } + + t->t.count--; + ent->key = 0; + ent->next = NULL; } -static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; - bool first = true; - size_t i, n = 0; +bool upb_inttable_done(const upb_inttable_iter* i) { + if (!i->t) return true; + if (i->array_part) { + return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i)); + } else { + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(int_tabent(i)); + } +} - if (paths) n = upb_Array_Size(paths); +uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) { + UPB_ASSERT(!upb_inttable_done(i)); + return i->array_part ? i->index : int_tabent(i)->key; +} - jsonenc_putstr(e, "\""); +upb_value upb_inttable_iter_value(const upb_inttable_iter* i) { + UPB_ASSERT(!upb_inttable_done(i)); + return _upb_value_val(i->array_part ? i->t->array[i->index].val + : int_tabent(i)->val.val); +} - for (i = 0; i < n; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); - } +void upb_inttable_iter_setdone(upb_inttable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; + i->array_part = false; +} - jsonenc_putstr(e, "\""); +bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, + const upb_inttable_iter* i2) { + if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index && + i1->array_part == i2->array_part; } -static void jsonenc_struct(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; - const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - size_t iter = kUpb_Map_Begin; - bool first = true; +/** upb/upb.c ************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include - jsonenc_putstr(e, "{"); - if (fields) { - while (upb_MapIterator_Next(fields, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(fields, iter); - upb_MessageValue val = upb_MapIterator_Value(fields, iter); +// Must be last. - jsonenc_putsep(e, ",", &first); - jsonenc_string(e, key.str_val); - jsonenc_putstr(e, ":"); - jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); - } - } +/* upb_Status *****************************************************************/ - jsonenc_putstr(e, "}"); +void upb_Status_Clear(upb_Status* status) { + if (!status) return; + status->ok = true; + status->msg[0] = '\0'; } -static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); - const upb_Array* values = upb_Message_Get(msg, values_f).array_val; - size_t i; - bool first = true; +bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } - jsonenc_putstr(e, "["); +const char* upb_Status_ErrorMessage(const upb_Status* status) { + return status->msg; +} - if (values) { - const size_t size = upb_Array_Size(values); - for (i = 0; i < size; i++) { - upb_MessageValue elem = upb_Array_Get(values, i); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { + if (!status) return; + status->ok = false; + strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} - jsonenc_putsep(e, ",", &first); - jsonenc_value(e, elem.msg_val, values_m); - } - } +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_Status_VSetErrorFormat(status, fmt, args); + va_end(args); +} - jsonenc_putstr(e, "]"); +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + if (!status) return; + status->ok = false; + vsnprintf(status->msg, sizeof(status->msg), fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; } -static void jsonenc_value(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - /* TODO(haberman): do we want a reflection method to get oneof case? */ - size_t iter = kUpb_Message_Begin; - const upb_FieldDef* f; - upb_MessageValue val; +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + size_t len; + if (!status) return; + status->ok = false; + len = strlen(status->msg); + vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} - if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { - jsonenc_err(e, "No value set in Value proto"); - } +/* upb_alloc ******************************************************************/ - switch (upb_FieldDef_Number(f)) { - case 1: - jsonenc_putstr(e, "null"); - break; - case 2: - upb_JsonEncode_Double(e, val.double_val); - break; - case 3: - jsonenc_string(e, val.str_val); - break; - case 4: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case 5: - jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; - case 6: - jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; +static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + UPB_UNUSED(alloc); + UPB_UNUSED(oldsize); + if (size == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, size); } } -static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - switch (upb_MessageDef_WellKnownType(m)) { - case kUpb_WellKnown_Unspecified: - jsonenc_msg(e, msg, m); - break; - case kUpb_WellKnown_Any: - jsonenc_any(e, msg, m); - break; - case kUpb_WellKnown_FieldMask: - jsonenc_fieldmask(e, msg, m); - break; - case kUpb_WellKnown_Duration: - jsonenc_duration(e, msg, m); - break; - case kUpb_WellKnown_Timestamp: - jsonenc_timestamp(e, msg, m); - break; - case kUpb_WellKnown_DoubleValue: - case kUpb_WellKnown_FloatValue: - case kUpb_WellKnown_Int64Value: - case kUpb_WellKnown_UInt64Value: - case kUpb_WellKnown_Int32Value: - case kUpb_WellKnown_UInt32Value: - case kUpb_WellKnown_StringValue: - case kUpb_WellKnown_BytesValue: - case kUpb_WellKnown_BoolValue: - jsonenc_wrapper(e, msg, m); - break; - case kUpb_WellKnown_Value: - jsonenc_value(e, msg, m); - break; - case kUpb_WellKnown_ListValue: - jsonenc_listvalue(e, msg, m); - break; - case kUpb_WellKnown_Struct: - jsonenc_struct(e, msg, m); - break; - } +static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { + return (uint32_t*)(cleanup_metadata & ~0x1); } -static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case kUpb_CType_Float: - upb_JsonEncode_Float(e, val.float_val); - break; - case kUpb_CType_Double: - upb_JsonEncode_Double(e, val.double_val); - break; - case kUpb_CType_Int32: - jsonenc_printf(e, "%" PRId32, val.int32_val); - break; - case kUpb_CType_UInt32: - jsonenc_printf(e, "%" PRIu32, val.uint32_val); - break; - case kUpb_CType_Int64: - jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); - break; - case kUpb_CType_UInt64: - jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); - break; - case kUpb_CType_String: - jsonenc_string(e, val.str_val); - break; - case kUpb_CType_Bytes: - jsonenc_bytes(e, val.str_val); - break; - case kUpb_CType_Enum: - jsonenc_enum(val.int32_val, f, e); - break; - case kUpb_CType_Message: - jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; - } +static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { + return cleanup_metadata & 0x1; } -static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - jsonenc_putstr(e, "\""); +static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, + bool has_initial_block) { + return (uintptr_t)cleanup | has_initial_block; +} - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case kUpb_CType_Int32: - jsonenc_printf(e, "%" PRId32, val.int32_val); - break; - case kUpb_CType_UInt32: - jsonenc_printf(e, "%" PRIu32, val.uint32_val); - break; - case kUpb_CType_Int64: - jsonenc_printf(e, "%" PRId64, val.int64_val); - break; - case kUpb_CType_UInt64: - jsonenc_printf(e, "%" PRIu64, val.uint64_val); - break; - case kUpb_CType_String: - jsonenc_stringbody(e, val.str_val); - break; - default: - UPB_UNREACHABLE(); +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; + +/* upb_Arena ******************************************************************/ + +struct mem_block { + struct mem_block* next; + uint32_t size; + uint32_t cleanups; + /* Data follows. */ +}; + +typedef struct cleanup_ent { + upb_CleanupFunc* cleanup; + void* ud; +} cleanup_ent; + +static const size_t memblock_reserve = + UPB_ALIGN_UP(sizeof(mem_block), UPB_MALLOC_ALIGN); + +static upb_Arena* arena_findroot(upb_Arena* a) { + /* Path splitting keeps time complexity down, see: + * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ + while (a->parent != a) { + upb_Arena* next = a->parent; + a->parent = next->parent; + a = next; } + return a; +} - jsonenc_putstr(e, "\":"); +static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, + size_t size) { + mem_block* block = ptr; + + /* The block is for arena |a|, but should appear in the freelist of |root|. */ + block->next = root->freelist; + block->size = (uint32_t)size; + block->cleanups = 0; + root->freelist = block; + a->last_size = block->size; + if (!root->freelist_tail) root->freelist_tail = block; + + a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); + a->head.end = UPB_PTR_AT(block, size, char); + a->cleanup_metadata = upb_cleanup_metadata( + &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); + + UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); } -static void jsonenc_array(jsonenc* e, const upb_Array* arr, - const upb_FieldDef* f) { - size_t i; - size_t size = arr ? upb_Array_Size(arr) : 0; - bool first = true; +static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { + upb_Arena* root = arena_findroot(a); + size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; + mem_block* block = upb_malloc(root->block_alloc, block_size); - jsonenc_putstr(e, "["); + if (!block) return false; + upb_Arena_addblock(a, root, block, block_size); + return true; +} - for (i = 0; i < size; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_scalar(e, upb_Array_Get(arr, i), f); - } +void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { + if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= size); + return upb_Arena_Malloc(a, size); +} - jsonenc_putstr(e, "]"); +static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ + return upb_Arena_Realloc(a, ptr, oldsize, size); } -static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); - size_t iter = kUpb_Map_Begin; - bool first = true; +/* Public Arena API ***********************************************************/ - jsonenc_putstr(e, "{"); +upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { + const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; + upb_Arena* a; - if (map) { - while (upb_MapIterator_Next(map, &iter)) { - jsonenc_putsep(e, ",", &first); - jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); - jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); - } + /* We need to malloc the initial block. */ + n = first_block_overhead + 256; + if (!alloc || !(mem = upb_malloc(alloc, n))) { + return NULL; } - jsonenc_putstr(e, "}"); -} + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + n -= sizeof(*a); -static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, - upb_MessageValue val, bool* first) { - const char* name; + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->freelist = NULL; + a->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, false); - jsonenc_putsep(e, ",", first); + upb_Arena_addblock(a, a, mem, n); - if (upb_FieldDef_IsExtension(f)) { - // TODO: For MessageSet, I would have expected this to print the message - // name here, but Python doesn't appear to do this. We should do more - // research here about what various implementations do. - jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); - } else { - if (e->options & upb_JsonEncode_UseProtoNames) { - name = upb_FieldDef_Name(f); - } else { - name = upb_FieldDef_JsonName(f); - } - jsonenc_printf(e, "\"%s\":", name); + return a; +} + +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { + upb_Arena* a; + + if (n) { + /* Align initial pointer up so that we return properly-aligned pointers. */ + void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, UPB_MALLOC_ALIGN); + size_t delta = (uintptr_t)aligned - (uintptr_t)mem; + n = delta <= n ? n - delta : 0; + mem = aligned; } - if (upb_FieldDef_IsMap(f)) { - jsonenc_map(e, val.map_val, f); - } else if (upb_FieldDef_IsRepeated(f)) { - jsonenc_array(e, val.array_val, f); - } else { - jsonenc_scalar(e, val, f); + /* Round block size down to alignof(*a) since we will allocate the arena + * itself at the end. */ + n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); + + if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { + return arena_initslow(mem, n, alloc); } + + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->last_size = UPB_MAX(128, n); + a->head.ptr = mem; + a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); + a->freelist = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, true); + + return a; } -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first) { - upb_MessageValue val; - const upb_FieldDef* f; +static void arena_dofree(upb_Arena* a) { + mem_block* block = a->freelist; + UPB_ASSERT(a->parent == a); + UPB_ASSERT(a->refcount == 0); - if (e->options & upb_JsonEncode_EmitDefaults) { - /* Iterate over all fields. */ - int i = 0; - int n = upb_MessageDef_FieldCount(m); - for (i = 0; i < n; i++) { - f = upb_MessageDef_Field(m, i); - if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { - jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first); + while (block) { + /* Load first since we are deleting block. */ + mem_block* next = block->next; + + if (block->cleanups > 0) { + cleanup_ent* end = UPB_PTR_AT(block, block->size, void); + cleanup_ent* ptr = end - block->cleanups; + + for (; ptr < end; ptr++) { + ptr->cleanup(ptr->ud); } } - } else { - /* Iterate over non-empty fields. */ - size_t iter = kUpb_Message_Begin; - while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { - jsonenc_fieldval(e, f, val, &first); - } + + upb_free(a->block_alloc, block); + block = next; } } -static void jsonenc_msg(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - jsonenc_putstr(e, "{"); - jsonenc_msgfields(e, msg, m, true); - jsonenc_putstr(e, "}"); +void upb_Arena_Free(upb_Arena* a) { + a = arena_findroot(a); + if (--a->refcount == 0) arena_dofree(a); } -static size_t jsonenc_nullz(jsonenc* e, size_t size) { - size_t ret = e->ptr - e->buf + e->overflow; +bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { + cleanup_ent* ent; + uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); - if (size > 0) { - if (e->ptr == e->end) e->ptr--; - *e->ptr = '\0'; + if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { + if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); + cleanups = upb_cleanup_pointer(a->cleanup_metadata); } - return ret; + a->head.end -= sizeof(cleanup_ent); + ent = (cleanup_ent*)a->head.end; + (*cleanups)++; + UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); + + ent->cleanup = func; + ent->ud = ud; + + return true; } -size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, int options, char* buf, - size_t size, upb_Status* status) { - jsonenc e; +bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { + upb_Arena* r1 = arena_findroot(a1); + upb_Arena* r2 = arena_findroot(a2); - e.buf = buf; - e.ptr = buf; - e.end = UPB_PTRADD(buf, size); - e.overflow = 0; - e.options = options; - e.ext_pool = ext_pool; - e.status = status; - e.arena = NULL; + if (r1 == r2) return true; /* Already fused. */ - if (setjmp(e.err)) return -1; + /* Do not fuse initial blocks since we cannot lifetime extend them. */ + if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; + if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; - jsonenc_msgfield(&e, msg, m); - if (e.arena) upb_Arena_Free(e.arena); - return jsonenc_nullz(&e, size); + /* Only allow fuse with a common allocator */ + if (r1->block_alloc != r2->block_alloc) return false; + + /* We want to join the smaller tree to the larger tree. + * So swap first if they are backwards. */ + if (r1->refcount < r2->refcount) { + upb_Arena* tmp = r1; + r1 = r2; + r2 = tmp; + } + + /* r1 takes over r2's freelist and refcount. */ + r1->refcount += r2->refcount; + if (r2->freelist_tail) { + UPB_ASSERT(r2->freelist_tail->next == NULL); + r2->freelist_tail->next = r1->freelist; + r1->freelist = r2->freelist; + } + r2->parent = r1; + return true; +} + +/* Miscellaneous utilities ****************************************************/ + +static void upb_FixLocale(char* p) { + /* printf() is dependent on locales; sadly there is no easy and portable way + * to avoid this. This little post-processing step will translate 1,2 -> 1.2 + * since JSON needs the latter. Arguably a hack, but it is simple and the + * alternatives are far more complicated, platform-dependent, and/or larger + * in code size. */ + for (; *p; p++) { + if (*p == ',') *p = '.'; + } +} + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + snprintf(buf, size, "%.*g", DBL_DIG, val); + if (strtod(buf, NULL) != val) { + snprintf(buf, size, "%.*g", DBL_DIG + 2, val); + assert(strtod(buf, NULL) == val); + } + upb_FixLocale(buf); +} + +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + snprintf(buf, size, "%.*g", FLT_DIG, val); + if (strtof(buf, NULL) != val) { + snprintf(buf, size, "%.*g", FLT_DIG + 3, val); + assert(strtof(buf, NULL) == val); + } + upb_FixLocale(buf); } /** upb/port_undef.inc ************************************************************/ @@ -11380,6 +12833,7 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_MALLOC_ALIGN #undef UPB_LIKELY #undef UPB_UNLIKELY #undef UPB_FORCEINLINE @@ -11402,3 +12856,4 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN +#undef UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h index 5af4e27dfc..8291daa8cf 100644 --- a/php/ext/google/protobuf/php-upb.h +++ b/php/ext/google/protobuf/php-upb.h @@ -89,21 +89,22 @@ #define UPB_INLINE static #endif +#define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) -/* Hints to the compiler about likely/unlikely branches. */ +// Hints to the compiler about likely/unlikely branches. #if defined (__GNUC__) || defined(__clang__) -#define UPB_LIKELY(x) __builtin_expect((x),1) -#define UPB_UNLIKELY(x) __builtin_expect((x),0) +#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) +#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) #else #define UPB_LIKELY(x) (x) #define UPB_UNLIKELY(x) (x) #endif -/* Macros for function attributes on compilers that support them. */ +// Macros for function attributes on compilers that support them. #ifdef __GNUC__ #define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) #define UPB_NOINLINE __attribute__((noinline)) @@ -126,8 +127,7 @@ #define UPB_UNUSED(var) (void)var -/* UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. - */ +// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. #ifdef NDEBUG #ifdef __GNUC__ #define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() @@ -253,13 +253,45 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #endif -/** upb/decode.h ************************************************************/ +/* Disable proto2 arena behavior (TEMPORARY) **********************************/ + +#ifdef UPB_DISABLE_PROTO2_ENUM_CHECKING +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 1 +#else +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 +#endif + +/** upb/collections.h ************************************************************/ +#ifndef UPB_COLLECTIONS_H_ +#define UPB_COLLECTIONS_H_ + + +/** google/protobuf/descriptor.upb.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ + + +/** upb/msg_internal.h ************************************************************/ /* - * upb_decode: parsing into a upb_Message using a upb_MiniTable. - */ +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ -#ifndef UPB_DECODE_H_ -#define UPB_DECODE_H_ +#ifndef UPB_MSG_INT_H_ +#define UPB_MSG_INT_H_ + +#include +#include +#include /** upb/msg.h ************************************************************/ @@ -448,18 +480,14 @@ UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) { return (size_t)(h->end - h->ptr); } -UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { +UPB_INLINE void* _upb_Arena_FastMalloc(upb_Arena* a, size_t size) { _upb_ArenaHead* h = (_upb_ArenaHead*)a; - void* ret; - size = UPB_ALIGN_MALLOC(size); - - if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { - return _upb_Arena_SlowMalloc(a, size); - } + void* ret = h->ptr; + UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret); + UPB_ASSERT(UPB_ALIGN_MALLOC(size) == size); + UPB_UNPOISON_MEMORY_REGION(ret, size); - ret = h->ptr; h->ptr += size; - UPB_UNPOISON_MEMORY_REGION(ret, size); #if UPB_ASAN { @@ -475,12 +503,51 @@ UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { return ret; } +UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { + size = UPB_ALIGN_MALLOC(size); + + if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { + return _upb_Arena_SlowMalloc(a, size); + } + + return _upb_Arena_FastMalloc(a, size); +} + +// Shrinks the last alloc from arena. +// REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena. +// We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if +// this was not the last alloc. +UPB_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, size_t oldsize, + size_t size) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + UPB_ASSERT((char*)ptr + oldsize == h->ptr); // Must be the last alloc. + UPB_ASSERT(size <= oldsize); + h->ptr = (char*)ptr + size; +} + UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize, size_t size) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + bool is_most_recent_alloc = (uintptr_t)ptr + oldsize == (uintptr_t)h->ptr; + + if (is_most_recent_alloc) { + ptrdiff_t diff = size - oldsize; + if ((ptrdiff_t)_upb_ArenaHas(a) >= diff) { + h->ptr += diff; + return ptr; + } + } else if (size <= oldsize) { + return ptr; + } + void* ret = upb_Arena_Malloc(a, size); if (ret && oldsize > 0) { - memcpy(ret, ptr, oldsize); + memcpy(ret, ptr, UPB_MIN(oldsize, size)); } return ret; @@ -568,8 +635,8 @@ UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { if (_upb_IsLittleEndian()) { return val; } else { - return ((uint64_t)_upb_BigEndian_Swap32(val) << 32) | - _upb_BigEndian_Swap32(val >> 32); + return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | + _upb_BigEndian_Swap32((uint32_t)(val >> 32)); } } @@ -584,7 +651,7 @@ UPB_INLINE int _upb_Log2Ceiling(int x) { #endif } -UPB_INLINE int _upb_Log2Ceilingsize(int x) { return 1 << _upb_Log2Ceiling(x); } +UPB_INLINE int _upb_Log2CeilingSize(int x) { return 1 << _upb_Log2Ceiling(x); } #ifdef __cplusplus @@ -597,8 +664,7 @@ UPB_INLINE int _upb_Log2Ceilingsize(int x) { return 1 << _upb_Log2Ceiling(x); } extern "C" { #endif -/** upb_Message - * *******************************************************************/ +/** upb_Message ***************************************************************/ typedef void upb_Message; @@ -667,92 +733,6 @@ upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); #endif /* UPB_MSG_INT_H_ */ -/* Must be last. */ - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* If set, strings will alias the input buffer instead of copying into the - * arena. */ - kUpb_DecodeOption_AliasString = 1, - - /* If set, the parse will return failure if any message is missing any - * required fields when the message data ends. The parse will still continue, - * and the failure will only be reported at the end. - * - * IMPORTANT CAVEATS: - * - * 1. This can throw a false positive failure if an incomplete message is seen - * on the wire but is later completed when the sub-message occurs again. - * For this reason, a second pass is required to verify a failure, to be - * truly robust. - * - * 2. This can return a false success if you are decoding into a message that - * already has some sub-message fields present. If the sub-message does - * not occur in the binary payload, we will never visit it and discover the - * incomplete sub-message. For this reason, this check is only useful for - * implemting ParseFromString() semantics. For MergeFromString(), a - * post-parse validation step will always be necessary. */ - kUpb_DecodeOption_CheckRequired = 2, -}; - -#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) - -typedef enum { - kUpb_DecodeStatus_Ok = 0, - kUpb_DecodeStatus_Malformed = 1, // Wire format was corrupt - kUpb_DecodeStatus_OutOfMemory = 2, // Arena alloc failed - kUpb_DecodeStatus_BadUtf8 = 3, // String field had bad UTF-8 - kUpb_DecodeStatus_MaxDepthExceeded = 4, // Exceeded UPB_DECODE_MAXDEPTH - - // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise - // succeeded. - kUpb_DecodeStatus_MissingRequired = 5, -} upb_DecodeStatus; - -upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, - const upb_MiniTable* l, - const upb_ExtensionRegistry* extreg, int options, - upb_Arena* arena); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_DECODE_H_ */ - -/** upb/decode_internal.h ************************************************************/ -/* - * Internal implementation details of the decoder that are shared between - * decode.c and decode_fast.c. - */ - -#ifndef UPB_DECODE_INT_H_ -#define UPB_DECODE_INT_H_ - -#include - -#include "third_party/utf8_range/utf8_range.h" - -/** upb/msg_internal.h ************************************************************/ -/* -** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possibly reflection. -** -** The definitions in this file are internal to upb. -**/ - -#ifndef UPB_MSG_INT_H_ -#define UPB_MSG_INT_H_ - -#include -#include -#include - - /** upb/table_internal.h ************************************************************/ /* * upb_table @@ -1101,6 +1081,8 @@ void upb_inttable_iter_setdone(upb_inttable_iter* i); bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, const upb_inttable_iter* i2); +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); + #ifdef __cplusplus } /* extern "C" */ #endif @@ -1136,43 +1118,40 @@ typedef struct { uint32_t number; uint16_t offset; int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index - uint16_t submsg_index; // undefined if descriptortype != MESSAGE/GROUP/ENUM + uint16_t submsg_index; // kUpb_NoSub if descriptortype != MESSAGE/GROUP/ENUM uint8_t descriptortype; uint8_t mode; /* upb_FieldMode | upb_LabelFlags | - (upb_FieldRep << upb_FieldRep_Shift) */ + (upb_FieldRep << kUpb_FieldRep_Shift) */ } upb_MiniTable_Field; +#define kUpb_NoSub ((uint16_t)-1) + typedef enum { kUpb_FieldMode_Map = 0, kUpb_FieldMode_Array = 1, kUpb_FieldMode_Scalar = 2, - - kUpb_FieldMode_Mask = 3, /* Mask to isolate the mode from upb_FieldRep. */ } upb_FieldMode; -/* Extra flags on the mode field. */ -enum upb_LabelFlags { - upb_LabelFlags_IsPacked = 4, - upb_LabelFlags_IsExtension = 8, -}; +// Mask to isolate the upb_FieldMode from field.mode. +#define kUpb_FieldMode_Mask 3 -/* Representation in the message. Derivable from descriptortype and mode, but - * fast access helps the serializer. */ -enum upb_FieldRep { - upb_FieldRep_1Byte = 0, - upb_FieldRep_4Byte = 1, - upb_FieldRep_8Byte = 2, - upb_FieldRep_StringView = 3, +/* Extra flags on the mode field. */ +typedef enum { + kUpb_LabelFlags_IsPacked = 4, + kUpb_LabelFlags_IsExtension = 8, +} upb_LabelFlags; -#if UINTPTR_MAX == 0xffffffff - upb_FieldRep_Pointer = upb_FieldRep_4Byte, -#else - upb_FieldRep_Pointer = upb_FieldRep_8Byte, -#endif +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_FieldRep_1Byte = 0, + kUpb_FieldRep_4Byte = 1, + kUpb_FieldRep_StringView = 2, + kUpb_FieldRep_Pointer = 3, + kUpb_FieldRep_8Byte = 4, - upb_FieldRep_Shift = - 6, /* Bit offset of the rep in upb_MiniTable_Field.mode */ -}; + kUpb_FieldRep_Shift = 5, // Bit offset of the rep in upb_MiniTable_Field.mode + kUpb_FieldRep_Max = kUpb_FieldRep_8Byte, +} upb_FieldRep; UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTable_Field* field) { return (upb_FieldMode)(field->mode & 3); @@ -1206,36 +1185,28 @@ typedef struct { int value_count; } upb_MiniTable_Enum; -UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, - int32_t val) { - uint32_t uval = (uint32_t)val; - if (uval < 64) return e->mask & (1 << uval); - // OPT: binary search long lists? - int n = e->value_count; - for (int i = 0; i < n; i++) { - if (e->values[i] == val) return true; - } - return false; -} - typedef union { const struct upb_MiniTable* submsg; const upb_MiniTable_Enum* subenum; } upb_MiniTable_Sub; typedef enum { - upb_ExtMode_NonExtendable = 0, // Non-extendable message. - upb_ExtMode_Extendable = 1, // Normal extendable message. - upb_ExtMode_IsMessageSet = 2, // MessageSet message. - upb_ExtMode_IsMessageSet_ITEM = + kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. + kUpb_ExtMode_Extendable = 1, // Normal extendable message. + kUpb_ExtMode_IsMessageSet = 2, // MessageSet message. + kUpb_ExtMode_IsMessageSet_ITEM = 3, // MessageSet item (temporary only, see decode.c) + + // During table building we steal a bit to indicate that the message is a map + // entry. *Only* used during table building! + kUpb_ExtMode_IsMapEntry = 4, } upb_ExtMode; /* MessageSet wire format is: * message MessageSet { * repeated group Item = 1 { * required int32 type_id = 2; - * required string message = 3; + * required bytes message = 3; * } * } */ @@ -1289,8 +1260,7 @@ UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) { return ((1ULL << n) - 1) << 1; } -/** upb_ExtensionRegistry - * ****************************************************************/ +/** upb_ExtensionRegistry *****************************************************/ /* Adds the given extension info for message type |l| and field number |num| * into the registry. Returns false if this message type and field number were @@ -1305,8 +1275,7 @@ const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, const upb_MiniTable* l, uint32_t num); -/** upb_Message - * *******************************************************************/ +/** upb_Message ***************************************************************/ /* Internal members of a upb_Message that track unknown fields and/or * extensions. We can change this without breaking binary compatibility. We put @@ -1352,7 +1321,7 @@ UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) { UPB_INLINE upb_Message* _upb_Message_New_inl(const upb_MiniTable* l, upb_Arena* a) { size_t size = upb_msg_sizeof(l); - void* mem = upb_Arena_Malloc(a, size); + void* mem = upb_Arena_Malloc(a, size + sizeof(upb_Message_Internal)); upb_Message* msg; if (UPB_UNLIKELY(!mem)) return NULL; msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message); @@ -1379,8 +1348,7 @@ void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, upb_Arena* arena); -/** upb_Message_Extension - * ***************************************************************/ +/** upb_Message_Extension *****************************************************/ /* The internal representation of an extension is self-describing: it contains * enough information that we can serialize it to binary format without needing @@ -1402,7 +1370,7 @@ typedef struct { /* Adds the given extension data to the given message. |ext| is copied into the * message instance. This logically replaces any previously-added extension with * this number */ -upb_Message_Extension* _upb_Message_Getorcreateext( +upb_Message_Extension* _upb_Message_GetOrCreateExtension( upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena); /* Returns an array of extensions for this message. Note: the array is @@ -1516,8 +1484,8 @@ UPB_INLINE uintptr_t _upb_tag_arrptr(void* ptr, int elem_size_lg2) { UPB_INLINE upb_Array* _upb_Array_New(upb_Arena* a, size_t init_size, int elem_size_lg2) { - const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_Array), 8); - const size_t bytes = sizeof(upb_Array) + (init_size << elem_size_lg2); + const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_Array), UPB_MALLOC_ALIGN); + const size_t bytes = arr_size + (init_size << elem_size_lg2); upb_Array* arr = (upb_Array*)upb_Arena_Malloc(a, bytes); if (!arr) return NULL; arr->data = _upb_tag_arrptr(UPB_PTR_AT(arr, arr_size, void), elem_size_lg2); @@ -1548,6 +1516,10 @@ UPB_INLINE bool _upb_Array_Resize(upb_Array* arr, size_t size, return true; } +UPB_INLINE void _upb_array_detach(const void* msg, size_t ofs) { + *UPB_PTR_AT(msg, ofs, upb_Array*) = NULL; +} + UPB_INLINE const void* _upb_array_accessor(const void* msg, size_t ofs, size_t* size) { const upb_Array* arr = *UPB_PTR_AT(msg, ofs, const upb_Array*); @@ -1741,15 +1713,31 @@ UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { return (void*)str_tabent(&it); } -UPB_INLINE bool _upb_Map_Set(upb_Map* map, const void* key, size_t key_size, - void* val, size_t val_size, upb_Arena* a) { +typedef enum { + // LINT.IfChange + _kUpb_MapInsertStatus_Inserted = 0, + _kUpb_MapInsertStatus_Replaced = 1, + _kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/collections.h) +} _upb_MapInsertStatus; + +UPB_INLINE _upb_MapInsertStatus _upb_Map_Insert(upb_Map* map, const void* key, + size_t key_size, void* val, + size_t val_size, upb_Arena* a) { upb_StringView strkey = _upb_map_tokey(key, key_size); upb_value tabval = {0}; - if (!_upb_map_tovalue(val, val_size, &tabval, a)) return false; + if (!_upb_map_tovalue(val, val_size, &tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); - return upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a); + bool removed = + upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); + if (!upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } + return removed ? _kUpb_MapInsertStatus_Replaced + : _kUpb_MapInsertStatus_Inserted; } UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, @@ -1791,7 +1779,8 @@ UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, if (!*map) { *map = _upb_Map_New(arena, key_size, val_size); } - return _upb_Map_Set(*map, key, key_size, val, val_size, arena); + return _upb_Map_Insert(*map, key, key_size, val, val_size, arena) != + _kUpb_MapInsertStatus_OutOfMemory; } UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs, @@ -1837,8 +1826,7 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, } } -/** _upb_mapsorter - * *************************************************************/ +/** _upb_mapsorter ************************************************************/ /* _upb_mapsorter sorts maps and provides ordered iteration over the entries. * Since maps can be recursive (map values can be messages which contain other @@ -1892,258 +1880,71 @@ UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, #endif /* UPB_MSG_INT_H_ */ -/** upb/upb_internal.h ************************************************************/ -#ifndef UPB_INT_H_ -#define UPB_INT_H_ +/** upb/decode.h ************************************************************/ +/* + * upb_decode: parsing into a upb_Message using a upb_MiniTable. + */ +#ifndef UPB_DECODE_H_ +#define UPB_DECODE_H_ -struct mem_block; -typedef struct mem_block mem_block; -struct upb_Arena { - _upb_ArenaHead head; - /* Stores cleanup metadata for this arena. - * - a pointer to the current cleanup counter. - * - a boolean indicating if there is an unowned initial block. */ - uintptr_t cleanup_metadata; +/* Must be last. */ - /* Allocator to allocate arena blocks. We are responsible for freeing these - * when we are destroyed. */ - upb_alloc* block_alloc; - uint32_t last_size; +#ifdef __cplusplus +extern "C" { +#endif - /* When multiple arenas are fused together, each arena points to a parent - * arena (root points to itself). The root tracks how many live arenas - * reference it. */ - uint32_t refcount; /* Only used when a->parent == a */ - struct upb_Arena* parent; +enum { + /* If set, strings will alias the input buffer instead of copying into the + * arena. */ + kUpb_DecodeOption_AliasString = 1, - /* Linked list of blocks to free/cleanup. */ - mem_block *freelist, *freelist_tail; + /* If set, the parse will return failure if any message is missing any + * required fields when the message data ends. The parse will still continue, + * and the failure will only be reported at the end. + * + * IMPORTANT CAVEATS: + * + * 1. This can throw a false positive failure if an incomplete message is seen + * on the wire but is later completed when the sub-message occurs again. + * For this reason, a second pass is required to verify a failure, to be + * truly robust. + * + * 2. This can return a false success if you are decoding into a message that + * already has some sub-message fields present. If the sub-message does + * not occur in the binary payload, we will never visit it and discover the + * incomplete sub-message. For this reason, this check is only useful for + * implemting ParseFromString() semantics. For MergeFromString(), a + * post-parse validation step will always be necessary. */ + kUpb_DecodeOption_CheckRequired = 2, }; -// Encodes a float or double that is round-trippable, but as short as possible. -// These routines are not fully optimal (not guaranteed to be shortest), but are -// short-ish and match the implementation that has been used in protobuf since -// the beginning. -// -// The given buffer size must be at least kUpb_RoundTripBufferSize. -enum { kUpb_RoundTripBufferSize = 32 }; -void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); -void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); +#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) -#endif /* UPB_INT_H_ */ +typedef enum { + kUpb_DecodeStatus_Ok = 0, + kUpb_DecodeStatus_Malformed = 1, // Wire format was corrupt + kUpb_DecodeStatus_OutOfMemory = 2, // Arena alloc failed + kUpb_DecodeStatus_BadUtf8 = 3, // String field had bad UTF-8 + kUpb_DecodeStatus_MaxDepthExceeded = 4, // Exceeded UPB_DECODE_MAXDEPTH -/* Must be last. */ - -#define DECODE_NOGROUP (uint32_t) - 1 - -typedef struct upb_Decoder { - const char* end; /* Can read up to 16 bytes slop beyond this. */ - const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */ - upb_Message* unknown_msg; /* If non-NULL, add unknown data at buffer flip. */ - const char* unknown; /* Start of unknown data. */ - const upb_ExtensionRegistry* - extreg; /* For looking up extensions during the parse. */ - int limit; /* Submessage limit relative to end. */ - int depth; /* Tracks recursion depth to bound stack usage. */ - uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ - uint16_t options; - bool missing_required; - char patch[32]; - upb_Arena arena; - jmp_buf err; - -#ifndef NDEBUG - const char* debug_tagstart; - const char* debug_valstart; -#endif -} upb_Decoder; - -/* Error function that will abort decoding with longjmp(). We can't declare this - * UPB_NORETURN, even though it is appropriate, because if we do then compilers - * will "helpfully" refuse to tailcall to it - * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal - * of our optimizations. That is also why we must declare it in a separate file, - * otherwise the compiler will see that it calls longjmp() and deduce that it is - * noreturn. */ -const char* fastdecode_err(upb_Decoder* d, int status); - -extern const uint8_t upb_utf8_offsets[]; - -UPB_INLINE -bool decode_verifyutf8_inl(const char* ptr, int len) { - const char* end = ptr + len; - - // Check 8 bytes at a time for any non-ASCII char. - while (end - ptr >= 8) { - uint64_t data; - memcpy(&data, ptr, 8); - if (data & 0x8080808080808080) goto non_ascii; - ptr += 8; - } - - // Check one byte at a time for non-ASCII. - while (ptr < end) { - if (*ptr & 0x80) goto non_ascii; - ptr++; - } - - return true; - -non_ascii: - return utf8_range2((const unsigned char*)ptr, end - ptr) == 0; -} - -const char* decode_checkrequired(upb_Decoder* d, const char* ptr, - const upb_Message* msg, - const upb_MiniTable* l); - -/* x86-64 pointers always have the high 16 bits matching. So we can shift - * left 8 and right 8 without loss of information. */ -UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) { - return ((intptr_t)tablep << 8) | tablep->table_mask; -} - -UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) { - return (const upb_MiniTable*)(table >> 8); -} - -UPB_INLINE -const char* decode_isdonefallback_inl(upb_Decoder* d, const char* ptr, - int overrun, int* status) { - if (overrun < d->limit) { - /* Need to copy remaining data into patch buffer. */ - UPB_ASSERT(overrun < 16); - if (d->unknown_msg) { - if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown, - &d->arena)) { - *status = kUpb_DecodeStatus_OutOfMemory; - return NULL; - } - d->unknown = &d->patch[0] + overrun; - } - memset(d->patch + 16, 0, 16); - memcpy(d->patch, d->end, 16); - ptr = &d->patch[0] + overrun; - d->end = &d->patch[16]; - d->limit -= 16; - d->limit_ptr = d->end + d->limit; - d->options &= ~kUpb_DecodeOption_AliasString; - UPB_ASSERT(ptr < d->limit_ptr); - return ptr; - } else { - *status = kUpb_DecodeStatus_Malformed; - return NULL; - } -} - -const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, int overrun); - -UPB_INLINE -bool decode_isdone(upb_Decoder* d, const char** ptr) { - int overrun = *ptr - d->end; - if (UPB_LIKELY(*ptr < d->limit_ptr)) { - return false; - } else if (UPB_LIKELY(overrun == d->limit)) { - return true; - } else { - *ptr = decode_isdonefallback(d, *ptr, overrun); - return false; - } -} - -#if UPB_FASTTABLE -UPB_INLINE -const char* fastdecode_tagdispatch(upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t tag) { - const upb_MiniTable* table_p = decode_totablep(table); - uint8_t mask = table; - uint64_t data; - size_t idx = tag & mask; - UPB_ASSUME((idx & 7) == 0); - idx >>= 3; - data = table_p->fasttable[idx].field_data ^ tag; - UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, - hasbits, data); -} -#endif - -UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) { - uint16_t tag; - memcpy(&tag, ptr, 2); - return tag; -} - -UPB_INLINE void decode_checklimit(upb_Decoder* d) { - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); -} - -UPB_INLINE int decode_pushlimit(upb_Decoder* d, const char* ptr, int size) { - int limit = size + (int)(ptr - d->end); - int delta = d->limit - limit; - decode_checklimit(d); - d->limit = limit; - d->limit_ptr = d->end + UPB_MIN(0, limit); - decode_checklimit(d); - return delta; -} - -UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr, - int saved_delta) { - UPB_ASSERT(ptr - d->end == d->limit); - decode_checklimit(d); - d->limit += saved_delta; - d->limit_ptr = d->end + UPB_MIN(0, d->limit); - decode_checklimit(d); -} - - -#endif /* UPB_DECODE_INT_H_ */ - -/** upb/encode.h ************************************************************/ -/* - * upb_Encode: parsing into a upb_Message using a upb_MiniTable. - */ - -#ifndef UPB_ENCODE_H_ -#define UPB_ENCODE_H_ - - -/* Must be last. */ - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* If set, the results of serializing will be deterministic across all - * instances of this binary. There are no guarantees across different - * binary builds. - * - * If your proto contains maps, the encoder will need to malloc()/free() - * memory during encode. */ - kUpb_Encode_Deterministic = 1, - - /* When set, unknown fields are not printed. */ - kUpb_Encode_SkipUnknown = 2, - - /* When set, the encode will fail if any required fields are missing. */ - kUpb_Encode_CheckRequired = 4, -}; - -#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) - -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size); + // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise + // succeeded. + kUpb_DecodeStatus_MissingRequired = 5, +} upb_DecodeStatus; +upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, + const upb_MiniTable* l, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_ENCODE_H_ */ + +#endif /* UPB_DECODE_H_ */ /** upb/decode_fast.h ************************************************************/ // These are the specialized field parser functions for the fast parser. @@ -2272,53 +2073,84 @@ TAGBYTES(r) #endif /* UPB_DECODE_FAST_H_ */ -/** google/protobuf/descriptor.upb.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ +/** upb/encode.h ************************************************************/ +/* + * upb_Encode: parsing into a upb_Message using a upb_MiniTable. + */ -#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ -#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ +#ifndef UPB_ENCODE_H_ +#define UPB_ENCODE_H_ +/* Must be last. */ #ifdef __cplusplus extern "C" { #endif -struct google_protobuf_FileDescriptorSet; -struct google_protobuf_FileDescriptorProto; -struct google_protobuf_DescriptorProto; -struct google_protobuf_DescriptorProto_ExtensionRange; -struct google_protobuf_DescriptorProto_ReservedRange; -struct google_protobuf_ExtensionRangeOptions; -struct google_protobuf_FieldDescriptorProto; -struct google_protobuf_OneofDescriptorProto; -struct google_protobuf_EnumDescriptorProto; -struct google_protobuf_EnumDescriptorProto_EnumReservedRange; -struct google_protobuf_EnumValueDescriptorProto; -struct google_protobuf_ServiceDescriptorProto; -struct google_protobuf_MethodDescriptorProto; -struct google_protobuf_FileOptions; -struct google_protobuf_MessageOptions; -struct google_protobuf_FieldOptions; -struct google_protobuf_OneofOptions; -struct google_protobuf_EnumOptions; -struct google_protobuf_EnumValueOptions; -struct google_protobuf_ServiceOptions; -struct google_protobuf_MethodOptions; -struct google_protobuf_UninterpretedOption; -struct google_protobuf_UninterpretedOption_NamePart; -struct google_protobuf_SourceCodeInfo; -struct google_protobuf_SourceCodeInfo_Location; -struct google_protobuf_GeneratedCodeInfo; -struct google_protobuf_GeneratedCodeInfo_Annotation; -typedef struct google_protobuf_FileDescriptorSet google_protobuf_FileDescriptorSet; -typedef struct google_protobuf_FileDescriptorProto google_protobuf_FileDescriptorProto; -typedef struct google_protobuf_DescriptorProto google_protobuf_DescriptorProto; +enum { + /* If set, the results of serializing will be deterministic across all + * instances of this binary. There are no guarantees across different + * binary builds. + * + * If your proto contains maps, the encoder will need to malloc()/free() + * memory during encode. */ + kUpb_Encode_Deterministic = 1, + + /* When set, unknown fields are not printed. */ + kUpb_Encode_SkipUnknown = 2, + + /* When set, the encode will fail if any required fields are missing. */ + kUpb_Encode_CheckRequired = 4, +}; + +#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) + +char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, + upb_Arena* arena, size_t* size); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_ENCODE_H_ */ + + +#ifdef __cplusplus +extern "C" { +#endif + +struct google_protobuf_FileDescriptorSet; +struct google_protobuf_FileDescriptorProto; +struct google_protobuf_DescriptorProto; +struct google_protobuf_DescriptorProto_ExtensionRange; +struct google_protobuf_DescriptorProto_ReservedRange; +struct google_protobuf_ExtensionRangeOptions; +struct google_protobuf_FieldDescriptorProto; +struct google_protobuf_OneofDescriptorProto; +struct google_protobuf_EnumDescriptorProto; +struct google_protobuf_EnumDescriptorProto_EnumReservedRange; +struct google_protobuf_EnumValueDescriptorProto; +struct google_protobuf_ServiceDescriptorProto; +struct google_protobuf_MethodDescriptorProto; +struct google_protobuf_FileOptions; +struct google_protobuf_MessageOptions; +struct google_protobuf_FieldOptions; +struct google_protobuf_OneofOptions; +struct google_protobuf_EnumOptions; +struct google_protobuf_EnumValueOptions; +struct google_protobuf_ServiceOptions; +struct google_protobuf_MethodOptions; +struct google_protobuf_UninterpretedOption; +struct google_protobuf_UninterpretedOption_NamePart; +struct google_protobuf_SourceCodeInfo; +struct google_protobuf_SourceCodeInfo_Location; +struct google_protobuf_GeneratedCodeInfo; +struct google_protobuf_GeneratedCodeInfo_Annotation; +typedef struct google_protobuf_FileDescriptorSet google_protobuf_FileDescriptorSet; +typedef struct google_protobuf_FileDescriptorProto google_protobuf_FileDescriptorProto; +typedef struct google_protobuf_DescriptorProto google_protobuf_DescriptorProto; typedef struct google_protobuf_DescriptorProto_ExtensionRange google_protobuf_DescriptorProto_ExtensionRange; typedef struct google_protobuf_DescriptorProto_ReservedRange google_protobuf_DescriptorProto_ReservedRange; typedef struct google_protobuf_ExtensionRangeOptions google_protobuf_ExtensionRangeOptions; @@ -2461,19 +2293,25 @@ UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_pro upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FileDescriptorSet_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet *msg, size_t *len) { return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_FileDescriptorSet_clear_file(const google_protobuf_FileDescriptorSet* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet* msg, size_t* len) { + return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet *msg, size_t *len) { +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet* msg, size_t* len) { return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet* msg, size_t len, upb_Arena* arena) { return (google_protobuf_FileDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet* msg, upb_Arena* arena) { struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -2509,36 +2347,107 @@ UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize_ex(const google_p upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FileDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_name(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_package(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } -UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } -UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(44, 88)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(48, 96)); } -UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 104)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_message_type(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_enum_type(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_service(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(32, 64)); +} +UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_extension(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_options(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 80), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_FileOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(40, 80), const google_protobuf_FileOptions*); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(44, 88), const upb_Message*) = NULL; } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 4); } UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_SourceCodeInfo*); + return *UPB_PTR_AT(msg, UPB_SIZE(44, 88), const google_protobuf_SourceCodeInfo*); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_public_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(48, 96)); +} +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_weak_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(52, 104)); +} +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_syntax(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); } -UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(56, 112), len); } -UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(60, 120), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 5); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { @@ -2549,73 +2458,68 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_ _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; } -UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena); +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(3, 4), &val, arena); } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(44, 88), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); } -UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(48, 96), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(52, 104), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto *msg, google_protobuf_FileOptions* value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_FileOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(40, 80), google_protobuf_FileOptions*) = value; } -UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msginit, arena); @@ -2626,9 +2530,9 @@ UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorPro } UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto *msg, google_protobuf_SourceCodeInfo* value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_SourceCodeInfo*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(44, 88), google_protobuf_SourceCodeInfo*) = value; } -UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg); if (sub == NULL) { sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msginit, arena); @@ -2637,29 +2541,27 @@ UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptor } return sub; } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 112), len); +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 112), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, 2, arena); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 112), 2, &val, - arena); +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(48, 96), 2, &val, arena); } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(60, 120), len); +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(60, 120), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, 2, arena); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(60, 120), 2, &val, - arena); +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(52, 104), 2, &val, arena); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView) = value; } /* google.protobuf.DescriptorProto */ @@ -2693,104 +2595,164 @@ UPB_INLINE char* google_protobuf_DescriptorProto_serialize_ex(const google_proto upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_DescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_name(const google_protobuf_DescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } -UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_enum_type(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); } -UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_field(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_nested_type(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(16, 32)); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_enum_type(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_enum_type(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension_range(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_options(const google_protobuf_DescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_MessageOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_MessageOptions*); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_oneof_decl(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_range(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(40, 80)); +} +UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_name(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(44, 88)); +} +UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); } -UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } -UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto* msg, size_t* len) { + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_DescriptorProto_set_options(google_protobuf_DescriptorProto *msg, google_protobuf_MessageOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_MessageOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_MessageOptions*) = value; } -UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msginit, arena); @@ -2799,41 +2761,38 @@ UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProt } return sub; } -UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_OneofDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_OneofDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_DescriptorProto_ReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val, arena); } /* google.protobuf.DescriptorProto.ExtensionRange */ @@ -2867,15 +2826,32 @@ UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize_ex(con upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const google_protobuf_ExtensionRangeOptions*); } @@ -2892,7 +2868,7 @@ UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(googl _upb_sethas(msg, 3); *UPB_PTR_AT(msg, UPB_SIZE(12, 16), google_protobuf_ExtensionRangeOptions*) = value; } -UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena) { struct google_protobuf_ExtensionRangeOptions* sub = (struct google_protobuf_ExtensionRangeOptions*)google_protobuf_DescriptorProto_ExtensionRange_options(msg); if (sub == NULL) { sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msginit, arena); @@ -2933,11 +2909,23 @@ UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize_ex(cons upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -2982,19 +2970,25 @@ UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3030,47 +3024,112 @@ UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize_ex(const google_ upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_extendee(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_number(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); + return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_label(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 4); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 4); } UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto* msg) { - return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; + return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 5); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 5); } UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto* msg) { - return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1; + return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) : 1; +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 6); } UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 7); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_default_value(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 7); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 8); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_options(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(56, 88), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(64, 104), const google_protobuf_FieldOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), const google_protobuf_FieldOptions*); +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 9); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = 0; + _upb_clearhas(msg, 9); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 9); } UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 10); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_json_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 10); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView); +} +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 11); +} +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool) = 0; + _upb_clearhas(msg, 11); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 11); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool); } @@ -3085,15 +3144,15 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobu } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 6); @@ -3105,9 +3164,9 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_pr } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) { _upb_sethas(msg, 8); - *UPB_PTR_AT(msg, UPB_SIZE(64, 104), google_protobuf_FieldOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(56, 88), google_protobuf_FieldOptions*) = value; } -UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msginit, arena); @@ -3122,7 +3181,7 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_prot } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 10); - *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { _upb_sethas(msg, 11); @@ -3160,11 +3219,22 @@ UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize_ex(const google_ upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_name(const google_protobuf_OneofDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_options(const google_protobuf_OneofDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_OneofOptions*); } @@ -3177,7 +3247,7 @@ UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_OneofOptions*) = value; } -UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_OneofOptions* sub = (struct google_protobuf_OneofOptions*)google_protobuf_OneofDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msginit, arena); @@ -3218,42 +3288,71 @@ UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize_ex(const google_p upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_name(const google_protobuf_EnumDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_value(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_options(const google_protobuf_EnumDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_EnumOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const google_protobuf_EnumOptions*); +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_name(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_EnumDescriptorProto *msg, google_protobuf_EnumOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_EnumOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), google_protobuf_EnumOptions*) = value; } -UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msginit, arena); @@ -3262,28 +3361,26 @@ UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorPro } return sub; } -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val, arena); } /* google.protobuf.EnumDescriptorProto.EnumReservedRange */ @@ -3317,11 +3414,23 @@ UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -3366,15 +3475,32 @@ UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize_ex(const goo upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_name(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_number(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_options(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const google_protobuf_EnumValueOptions*); } @@ -3391,7 +3517,7 @@ UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_prot _upb_sethas(msg, 3); *UPB_PTR_AT(msg, UPB_SIZE(16, 24), google_protobuf_EnumValueOptions*) = value; } -UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumValueOptions* sub = (struct google_protobuf_EnumValueOptions*)google_protobuf_EnumValueDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msginit, arena); @@ -3432,39 +3558,56 @@ UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize_ex(const googl upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_name(const google_protobuf_ServiceDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto *msg, size_t *len) { return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_method(const google_protobuf_ServiceDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto* msg, size_t* len) { + return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); +} +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_options(const google_protobuf_ServiceDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_ServiceOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const google_protobuf_ServiceOptions*); } UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto *msg, size_t *len) { - return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto* msg, size_t* len) { + return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options(google_protobuf_ServiceDescriptorProto *msg, google_protobuf_ServiceOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_ServiceOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), google_protobuf_ServiceOptions*) = value; } -UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msginit, arena); @@ -3505,27 +3648,62 @@ UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize_ex(const google upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_name(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_input_type(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_output_type(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 3); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_options(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_MethodOptions*); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 5); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } @@ -3546,7 +3724,7 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobu _upb_sethas(msg, 4); *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_MethodOptions*) = value; } -UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MethodOptions* sub = (struct google_protobuf_MethodOptions*)google_protobuf_MethodDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msginit, arena); @@ -3595,88 +3773,215 @@ UPB_INLINE char* google_protobuf_FileOptions_serialize_ex(const google_protobuf_ upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FileOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_outer_classname(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_FileOptions_clear_optimize_for(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_optimize_for(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; } -UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_multiple_files(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_FileOptions_clear_go_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_FileOptions_clear_cc_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 7); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = 0; + _upb_clearhas(msg, 7); +} UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 8); +} +UPB_INLINE void google_protobuf_FileOptions_clear_py_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool) = 0; + _upb_clearhas(msg, 8); +} UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 9); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 9); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = 0; + _upb_clearhas(msg, 9); +} UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 10); +} +UPB_INLINE void google_protobuf_FileOptions_clear_deprecated(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = 0; + _upb_clearhas(msg, 10); +} UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 11); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 11); +} +UPB_INLINE void google_protobuf_FileOptions_clear_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = 0; + _upb_clearhas(msg, 11); +} UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 12); } +UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 12); +} +UPB_INLINE void google_protobuf_FileOptions_clear_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = 0; + _upb_clearhas(msg, 12); +} UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_cc_enable_arenas(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) : true; } -UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 13); } +UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 13); +} +UPB_INLINE void google_protobuf_FileOptions_clear_objc_class_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 13); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 14); } +UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 14); +} +UPB_INLINE void google_protobuf_FileOptions_clear_csharp_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 14); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 15); } +UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 15); +} +UPB_INLINE void google_protobuf_FileOptions_clear_swift_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 15); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 16); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 16); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_class_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 16); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 17); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 17); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 17); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 18); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 18); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = 0; + _upb_clearhas(msg, 18); +} UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 19); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 19); +} +UPB_INLINE void google_protobuf_FileOptions_clear_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 19); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 20); } +UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 20); +} +UPB_INLINE void google_protobuf_FileOptions_clear_ruby_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 20); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); } +UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); +} +UPB_INLINE void google_protobuf_FileOptions_clear_uninterpreted_option(const google_protobuf_FileOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(100, 184)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); +} UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_StringView value) { _upb_sethas(msg, 1); @@ -3758,16 +4063,15 @@ UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_Fil _upb_sethas(msg, 20); *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(100, 184), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(100, 184), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3803,24 +4107,55 @@ UPB_INLINE char* google_protobuf_MessageOptions_serialize_ex(const google_protob upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_MessageOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_deprecated(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_map_entry(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); } +UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE void google_protobuf_MessageOptions_clear_uninterpreted_option(const google_protobuf_MessageOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); +} UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions *msg, bool value) { _upb_sethas(msg, 1); @@ -3838,16 +4173,15 @@ UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_Mes _upb_sethas(msg, 4); *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3883,36 +4217,85 @@ UPB_INLINE char* google_protobuf_FieldOptions_serialize_ex(const google_protobuf upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FieldOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_ctype(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_packed(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_deprecated(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = 0; + _upb_clearhas(msg, 3); } -UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 3); } UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_lazy(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = 0; + _upb_clearhas(msg, 4); } -UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 4); } UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_jstype(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 5); } -UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 5); } UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); + return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_weak(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = 0; + _upb_clearhas(msg, 6); } -UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 6); } UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_unverified_lazy(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 7); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_unverified_lazy(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = 0; + _upb_clearhas(msg, 7); } -UPB_INLINE bool google_protobuf_FieldOptions_has_unverified_lazy(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 7); } UPB_INLINE bool google_protobuf_FieldOptions_unverified_lazy(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); +} +UPB_INLINE void google_protobuf_FieldOptions_clear_uninterpreted_option(const google_protobuf_FieldOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 24)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(20, 24), len); } -UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(20, 24), len); } UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, int32_t value) { _upb_sethas(msg, 1); @@ -3920,38 +4303,37 @@ UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOpti } UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, int32_t value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_unverified_lazy(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 24), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 24), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(20, 24), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3987,19 +4369,25 @@ UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_OneofOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_OneofOptions_clear_uninterpreted_option(const google_protobuf_OneofOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4035,16 +4423,35 @@ UPB_INLINE char* google_protobuf_EnumOptions_serialize_ex(const google_protobuf_ upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_allow_alias(const google_protobuf_EnumOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_deprecated(const google_protobuf_EnumOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } -UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } +UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_EnumOptions_clear_uninterpreted_option(const google_protobuf_EnumOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value) { _upb_sethas(msg, 1); @@ -4054,16 +4461,15 @@ UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumO _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4099,27 +4505,39 @@ UPB_INLINE char* google_protobuf_EnumValueOptions_serialize_ex(const google_prot upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumValueOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_deprecated(const google_protobuf_EnumValueOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } +UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_EnumValueOptions_clear_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} UPB_INLINE void google_protobuf_EnumValueOptions_set_deprecated(google_protobuf_EnumValueOptions *msg, bool value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4155,27 +4573,39 @@ UPB_INLINE char* google_protobuf_ServiceOptions_serialize_ex(const google_protob upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_ServiceOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_deprecated(const google_protobuf_ServiceOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } +UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_ServiceOptions_clear_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} UPB_INLINE void google_protobuf_ServiceOptions_set_deprecated(google_protobuf_ServiceOptions *msg, bool value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4211,35 +4641,53 @@ UPB_INLINE char* google_protobuf_MethodOptions_serialize_ex(const google_protobu upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_MethodOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_deprecated(const google_protobuf_MethodOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); +} +UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_idempotency_level(const google_protobuf_MethodOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); } -UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 2); } UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 16)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); } +UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_uninterpreted_option(const google_protobuf_MethodOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); +} UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, int32_t value) { _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len); +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t* len) { + return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(12, 16), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4275,69 +4723,111 @@ UPB_INLINE char* google_protobuf_UninterpretedOption_serialize_ex(const google_p upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_UninterpretedOption_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(56, 80)); } -UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption *msg, size_t *len) { return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(56, 80), len); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_name(const google_protobuf_UninterpretedOption* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_identifier_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t) = 0; + _upb_clearhas(msg, 2); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 2); } UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t); + return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t) = 0; + _upb_clearhas(msg, 3); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 3); } UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t); + return *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 4); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_double_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double) = 0; + _upb_clearhas(msg, 4); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 4); } UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double); + return *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 5); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_string_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 5); } UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 6); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 6); } UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView); } -UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption *msg, size_t *len) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 80), len); +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption* msg, size_t* len) { + return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 80), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(56, 80), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double) = value; + *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView) = value; } /* google.protobuf.UninterpretedOption.NamePart */ @@ -4371,11 +4861,23 @@ UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize_ex(const upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } @@ -4420,19 +4922,25 @@ UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protob upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_SourceCodeInfo_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo *msg, size_t *len) { return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_clear_location(const google_protobuf_SourceCodeInfo* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo* msg, size_t* len) { + return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo *msg, size_t *len) { +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo* msg, size_t* len) { return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo* msg, size_t len, upb_Arena* arena) { return (google_protobuf_SourceCodeInfo_Location**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo* msg, upb_Arena* arena) { struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4468,55 +4976,79 @@ UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize_ex(const goog upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, options, arena, len); } -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_path(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_span(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 16)); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 2); } UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, 2, arena); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), 2, &val, - arena); +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), 2, &val, arena); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 16), len, 2, arena); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), 2, &val, - arena); +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 16), 2, &val, arena); } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value; } -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val, arena); } /* google.protobuf.GeneratedCodeInfo */ @@ -4550,19 +5082,25 @@ UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_pro upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo *msg, size_t *len) { return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_clear_annotation(const google_protobuf_GeneratedCodeInfo* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo* msg, size_t* len) { + return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t *len) { +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t* len) { return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t len, upb_Arena* arena) { return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena) { struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4598,33 +5136,55 @@ UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize_ex(const upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, options, arena, len); } -UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 32), len); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 16)); +} +UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 1); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_StringView); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 2); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 2); } UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 3); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 32), len); +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len); } -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t len, upb_Arena *arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 32), len, 2, arena); +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t len, upb_Arena* arena) { + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 16), len, 2, arena); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 32), 2, &val, - arena); +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 16), 2, &val, arena); } UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_StringView) = value; } UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { _upb_sethas(msg, 2); @@ -4648,6 +5208,147 @@ extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout #endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { + bool bool_val; + float float_val; + double double_val; + int32_t int32_val; + int64_t int64_val; + uint32_t uint32_val; + uint64_t uint64_val; + const upb_Map* map_val; + const upb_Message* msg_val; + const upb_Array* array_val; + upb_StringView str_val; +} upb_MessageValue; + +typedef union { + upb_Map* map; + upb_Message* msg; + upb_Array* array; +} upb_MutableMessageValue; + +/** upb_Array *****************************************************************/ + +/* Creates a new array on the given arena that holds elements of this type. */ +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); + +/* Returns the size of the array. */ +size_t upb_Array_Size(const upb_Array* arr); + +/* Returns the given element, which must be within the array's current size. */ +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); + +/* Sets the given element, which must be within the array's current size. */ +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); + +/* Appends an element to the array. Returns false on allocation failure. */ +bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); + +/* Moves elements within the array using memmove(). Like memmove(), the source + * and destination elements may be overlapping. */ +void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, + size_t count); + +/* Inserts one or more empty elements into the array. Existing elements are + * shifted right. The new elements have undefined state and must be set with + * `upb_Array_Set()`. + * REQUIRES: `i <= upb_Array_Size(arr)` */ +bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, + upb_Arena* arena); + +/* Deletes one or more elements from the array. Existing elements are shifted + * left. + * REQUIRES: `i + count <= upb_Array_Size(arr)` */ +void upb_Array_Delete(upb_Array* array, size_t i, size_t count); + +/* Changes the size of a vector. New elements are initialized to empty/0. + * Returns false on allocation failure. */ +bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); + +/** upb_Map *******************************************************************/ + +/* Creates a new map on the given arena with the given key/value size. */ +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); + +/* Returns the number of entries in the map. */ +size_t upb_Map_Size(const upb_Map* map); + +/* Stores a value for the given key into |*val| (or the zero value if the key is + * not present). Returns whether the key was present. The |val| pointer may be + * NULL, in which case the function tests whether the given key is present. */ +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val); + +/* Removes all entries in the map. */ +void upb_Map_Clear(upb_Map* map); + +typedef enum { + // LINT.IfChange + kUpb_MapInsertStatus_Inserted = 0, + kUpb_MapInsertStatus_Replaced = 1, + kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/msg_internal.h) +} upb_MapInsertStatus; + +/* Sets the given key to the given value, returning whether the key was inserted + * or replaced. If the key was inserted, then any existing iterators will be + * invalidated. */ +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena); + +/* Sets the given key to the given value. Returns false if memory allocation + * failed. If the key is newly inserted, then any existing iterators will be + * invalidated. */ +UPB_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return upb_Map_Insert(map, key, val, arena) != + kUpb_MapInsertStatus_OutOfMemory; +} + +/* Deletes this key from the table. Returns true if the key was present. */ +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); + +/* Map iteration: + * + * size_t iter = kUpb_Map_Begin; + * while (upb_MapIterator_Next(map, &iter)) { + * upb_MessageValue key = upb_MapIterator_Key(map, iter); + * upb_MessageValue val = upb_MapIterator_Value(map, iter); + * + * // If mutating is desired. + * upb_MapIterator_SetValue(map, iter, value2); + * } + */ + +/* Advances to the next entry. Returns false if no more entries are present. */ +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); + +/* Returns true if the iterator still points to a valid entry, or false if the + * iterator is past the last element. It is an error to call this function with + * kUpb_Map_Begin (you must call next() at least once first). */ +bool upb_MapIterator_Done(const upb_Map* map, size_t iter); + +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); + +/* Sets the value for this entry. The iterator must not be done, and the + * iterator must not have been initialized const. */ +void upb_MapIterator_SetValue(upb_Map* map, size_t iter, + upb_MessageValue value); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_COLLECTIONS_H_ */ + /** upb/def.h ************************************************************/ #ifndef UPB_DEF_H_ #define UPB_DEF_H_ @@ -4681,6 +5382,9 @@ struct upb_streamdef; typedef struct upb_streamdef upb_streamdef; struct upb_DefPool; typedef struct upb_DefPool upb_DefPool; +typedef struct upb_EnumReservedRange upb_EnumReservedRange; +typedef struct upb_MessageReservedRange upb_MessageReservedRange; +typedef struct symtab_addctx symtab_addctx; typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; @@ -4784,11 +5488,11 @@ const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, #define kUpb_Any_TypeFieldNumber 1 #define kUpb_Any_ValueFieldNumber 2 -/* Well-known field tag numbers for timestamp messages. */ +/* Well-known field tag numbers for duration messages. */ #define kUpb_Duration_SecondsFieldNumber 1 #define kUpb_Duration_NanosFieldNumber 2 -/* Well-known field tag numbers for duration messages. */ +/* Well-known field tag numbers for timestamp messages. */ #define kUpb_Timestamp_SecondsFieldNumber 1 #define kUpb_Timestamp_NanosFieldNumber 2 @@ -4830,7 +5534,12 @@ UPB_INLINE bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m)); } -/* Nested entities. */ +UPB_INLINE bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(m)); +} + +/* Nested entities. */ int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m); @@ -4863,6 +5572,16 @@ UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); } +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m); + +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m); + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r); +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r); + /* upb_ExtensionRange *********************************************************/ const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( @@ -4895,6 +5614,16 @@ UPB_INLINE const upb_EnumValueDef* upb_EnumDef_FindValueByName( return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); } +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i); +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e); + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i); +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e); + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r); +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r); + /* upb_EnumValueDef ***********************************************************/ const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( @@ -5188,6 +5917,250 @@ UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_Annotation_ge #endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ */ +/** upb/decode_internal.h ************************************************************/ +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_DECODE_INT_H_ +#define UPB_DECODE_INT_H_ + +#include + +#include "third_party/utf8_range/utf8_range.h" + +/** upb/upb_internal.h ************************************************************/ +#ifndef UPB_INT_H_ +#define UPB_INT_H_ + + +struct mem_block; +typedef struct mem_block mem_block; + +struct upb_Arena { + _upb_ArenaHead head; + /* Stores cleanup metadata for this arena. + * - a pointer to the current cleanup counter. + * - a boolean indicating if there is an unowned initial block. */ + uintptr_t cleanup_metadata; + + /* Allocator to allocate arena blocks. We are responsible for freeing these + * when we are destroyed. */ + upb_alloc* block_alloc; + uint32_t last_size; + + /* When multiple arenas are fused together, each arena points to a parent + * arena (root points to itself). The root tracks how many live arenas + * reference it. */ + uint32_t refcount; /* Only used when a->parent == a */ + struct upb_Arena* parent; + + /* Linked list of blocks to free/cleanup. */ + mem_block *freelist, *freelist_tail; +}; + +// Encodes a float or double that is round-trippable, but as short as possible. +// These routines are not fully optimal (not guaranteed to be shortest), but are +// short-ish and match the implementation that has been used in protobuf since +// the beginning. +// +// The given buffer size must be at least kUpb_RoundTripBufferSize. +enum { kUpb_RoundTripBufferSize = 32 }; +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); + +#endif /* UPB_INT_H_ */ + +/* Must be last. */ + +#define DECODE_NOGROUP (uint32_t) - 1 + +typedef struct upb_Decoder { + const char* end; /* Can read up to 16 bytes slop beyond this. */ + const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */ + upb_Message* unknown_msg; /* Used for preserving unknown data. */ + const char* unknown; /* Start of unknown data, preserve at buffer flip. */ + const upb_ExtensionRegistry* + extreg; /* For looking up extensions during the parse. */ + int limit; /* Submessage limit relative to end. */ + int depth; /* Tracks recursion depth to bound stack usage. */ + uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ + uint16_t options; + bool missing_required; + char patch[32]; + upb_Arena arena; + jmp_buf err; + +#ifndef NDEBUG + const char* debug_tagstart; + const char* debug_valstart; +#endif +} upb_Decoder; + +/* Error function that will abort decoding with longjmp(). We can't declare this + * UPB_NORETURN, even though it is appropriate, because if we do then compilers + * will "helpfully" refuse to tailcall to it + * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal + * of our optimizations. That is also why we must declare it in a separate file, + * otherwise the compiler will see that it calls longjmp() and deduce that it is + * noreturn. */ +const char* fastdecode_err(upb_Decoder* d, int status); + +extern const uint8_t upb_utf8_offsets[]; + +UPB_INLINE +bool decode_verifyutf8_inl(const char* ptr, int len) { + const char* end = ptr + len; + + // Check 8 bytes at a time for any non-ASCII char. + while (end - ptr >= 8) { + uint64_t data; + memcpy(&data, ptr, 8); + if (data & 0x8080808080808080) goto non_ascii; + ptr += 8; + } + + // Check one byte at a time for non-ASCII. + while (ptr < end) { + if (*ptr & 0x80) goto non_ascii; + ptr++; + } + + return true; + +non_ascii: + return utf8_range2((const unsigned char*)ptr, end - ptr) == 0; +} + +const char* decode_checkrequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* l); + +/* x86-64 pointers always have the high 16 bits matching. So we can shift + * left 8 and right 8 without loss of information. */ +UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) { + return ((intptr_t)tablep << 8) | tablep->table_mask; +} + +UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) { + return (const upb_MiniTable*)(table >> 8); +} + +UPB_INLINE +const char* decode_isdonefallback_inl(upb_Decoder* d, const char* ptr, + int overrun, int* status) { + if (overrun < d->limit) { + /* Need to copy remaining data into patch buffer. */ + UPB_ASSERT(overrun < 16); + if (d->unknown) { + if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown, + &d->arena)) { + *status = kUpb_DecodeStatus_OutOfMemory; + return NULL; + } + d->unknown = &d->patch[0] + overrun; + } + memset(d->patch + 16, 0, 16); + memcpy(d->patch, d->end, 16); + ptr = &d->patch[0] + overrun; + d->end = &d->patch[16]; + d->limit -= 16; + d->limit_ptr = d->end + d->limit; + d->options &= ~kUpb_DecodeOption_AliasString; + UPB_ASSERT(ptr < d->limit_ptr); + return ptr; + } else { + *status = kUpb_DecodeStatus_Malformed; + return NULL; + } +} + +const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, int overrun); + +UPB_INLINE +bool decode_isdone(upb_Decoder* d, const char** ptr) { + int overrun = *ptr - d->end; + if (UPB_LIKELY(*ptr < d->limit_ptr)) { + return false; + } else if (UPB_LIKELY(overrun == d->limit)) { + return true; + } else { + *ptr = decode_isdonefallback(d, *ptr, overrun); + return false; + } +} + +#if UPB_FASTTABLE +UPB_INLINE +const char* fastdecode_tagdispatch(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t tag) { + const upb_MiniTable* table_p = decode_totablep(table); + uint8_t mask = table; + uint64_t data; + size_t idx = tag & mask; + UPB_ASSUME((idx & 7) == 0); + idx >>= 3; + data = table_p->fasttable[idx].field_data ^ tag; + UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, + hasbits, data); +} +#endif + +UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) { + uint16_t tag; + memcpy(&tag, ptr, 2); + return tag; +} + +UPB_INLINE void decode_checklimit(upb_Decoder* d) { + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +} + +UPB_INLINE int decode_pushlimit(upb_Decoder* d, const char* ptr, int size) { + int limit = size + (int)(ptr - d->end); + int delta = d->limit - limit; + decode_checklimit(d); + d->limit = limit; + d->limit_ptr = d->end + UPB_MIN(0, limit); + decode_checklimit(d); + return delta; +} + +UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr, + int saved_delta) { + UPB_ASSERT(ptr - d->end == d->limit); + decode_checklimit(d); + d->limit += saved_delta; + d->limit_ptr = d->end + UPB_MIN(0, d->limit); + decode_checklimit(d); +} + + +#endif /* UPB_DECODE_INT_H_ */ + +/** upb/json_decode.h ************************************************************/ +#ifndef UPB_JSONDECODE_H_ +#define UPB_JSONDECODE_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +enum { upb_JsonDecode_IgnoreUnknown = 1 }; + +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_JSONDECODE_H_ */ + /** upb/reflection.h ************************************************************/ #ifndef UPB_REFLECTION_H_ #define UPB_REFLECTION_H_ @@ -5197,26 +6170,6 @@ UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_Annotation_ge extern "C" { #endif -typedef union { - bool bool_val; - float float_val; - double double_val; - int32_t int32_val; - int64_t int64_val; - uint32_t uint32_val; - uint64_t uint64_val; - const upb_Map* map_val; - const upb_Message* msg_val; - const upb_Array* array_val; - upb_StringView str_val; -} upb_MessageValue; - -typedef union { - upb_Map* map; - upb_Message* msg; - upb_Array* array; -} upb_MutableMessageValue; - upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); /** upb_Message @@ -5279,98 +6232,6 @@ bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, int maxdepth); -/** upb_Array *****************************************************************/ - -/* Creates a new array on the given arena that holds elements of this type. */ -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); - -/* Returns the size of the array. */ -size_t upb_Array_Size(const upb_Array* arr); - -/* Returns the given element, which must be within the array's current size. */ -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); - -/* Sets the given element, which must be within the array's current size. */ -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); - -/* Appends an element to the array. Returns false on allocation failure. */ -bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); - -/* Moves elements within the array using memmove(). Like memmove(), the source - * and destination elements may be overlapping. */ -void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, - size_t count); - -/* Inserts one or more empty elements into the array. Existing elements are - * shifted right. The new elements have undefined state and must be set with - * `upb_Array_Set()`. - * REQUIRES: `i <= upb_Array_Size(arr)` */ -bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, - upb_Arena* arena); - -/* Deletes one or more elements from the array. Existing elements are shifted - * left. - * REQUIRES: `i + count <= upb_Array_Size(arr)` */ -void upb_Array_Delete(upb_Array* array, size_t i, size_t count); - -/* Changes the size of a vector. New elements are initialized to empty/0. - * Returns false on allocation failure. */ -bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); - -/** upb_Map *******************************************************************/ - -/* Creates a new map on the given arena with the given key/value size. */ -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); - -/* Returns the number of entries in the map. */ -size_t upb_Map_Size(const upb_Map* map); - -/* Stores a value for the given key into |*val| (or the zero value if the key is - * not present). Returns whether the key was present. The |val| pointer may be - * NULL, in which case the function tests whether the given key is present. */ -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val); - -/* Removes all entries in the map. */ -void upb_Map_Clear(upb_Map* map); - -/* Sets the given key to the given value. Returns true if this was a new key in - * the map, or false if an existing key was replaced. */ -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena); - -/* Deletes this key from the table. Returns true if the key was present. */ -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); - -/* Map iteration: - * - * size_t iter = kUpb_Map_Begin; - * while (upb_MapIterator_Next(map, &iter)) { - * upb_MessageValue key = upb_MapIterator_Key(map, iter); - * upb_MessageValue val = upb_MapIterator_Value(map, iter); - * - * // If mutating is desired. - * upb_MapIterator_SetValue(map, iter, value2); - * } - */ - -/* Advances to the next entry. Returns false if no more entries are present. */ -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); - -/* Returns true if the iterator still points to a valid entry, or false if the - * iterator is past the last element. It is an error to call this function with - * kUpb_Map_Begin (you must call next() at least once first). */ -bool upb_MapIterator_Done(const upb_Map* map, size_t iter); - -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); - -/* Sets the value for this entry. The iterator must not be done, and the - * iterator must not have been initialized const. */ -void upb_MapIterator_SetValue(upb_Map* map, size_t iter, - upb_MessageValue value); - #ifdef __cplusplus } /* extern "C" */ #endif @@ -5378,27 +6239,6 @@ void upb_MapIterator_SetValue(upb_Map* map, size_t iter, #endif /* UPB_REFLECTION_H_ */ -/** upb/json_decode.h ************************************************************/ -#ifndef UPB_JSONDECODE_H_ -#define UPB_JSONDECODE_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - -enum { upb_JsonDecode_IgnoreUnknown = 1 }; - -bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, - const upb_MessageDef* m, const upb_DefPool* symtab, - int options, upb_Arena* arena, upb_Status* status); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_JSONDECODE_H_ */ - /** upb/json_encode.h ************************************************************/ #ifndef UPB_JSONENCODE_H_ #define UPB_JSONENCODE_H_ @@ -5435,6 +6275,192 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #endif /* UPB_JSONENCODE_H_ */ +/** upb/internal/vsnprintf_compat.h ************************************************************/ +#ifndef UPB_INTERNAL_VSNPRINTF_COMPAT_H_ +#define UPB_INTERNAL_VSNPRINTF_COMPAT_H_ + +#include + +// Must be last. + +UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, + va_list ap) { +#if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) + // The msvc runtime has a non-conforming vsnprintf() that requires the + // following compatibility code to become conformant. + int n = -1; + if (size != 0) n = _vsnprintf_s(buf, size, _TRUNCATE, fmt, ap); + if (n == -1) n = _vscprintf(fmt, ap); + return n; +#else + return vsnprintf(buf, size, fmt, ap); +#endif +} + + +#endif // UPB_INTERNAL_VSNPRINTF_COMPAT_H_ + +/** upb/mini_table.h ************************************************************/ +#ifndef UPB_MINI_TABLE_H_ +#define UPB_MINI_TABLE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number); + +UPB_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { + return mini_table->subs[field->submsg_index].submsg; +} + +UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, + int32_t val) { + uint32_t uval = (uint32_t)val; + if (uval < 64) return e->mask & (1ULL << uval); + // OPT: binary search long lists? + int n = e->value_count; + for (int i = 0; i < n; i++) { + if (e->values[i] == val) return true; + } + return false; +} + +/** upb_MtDataEncoder *********************************************************/ + +// Functions to encode a string in a format that can be loaded by +// upb_MiniTable_Build(). + +typedef enum { + kUpb_MessageModifier_ValidateUtf8 = 1 << 0, + kUpb_MessageModifier_DefaultIsPacked = 1 << 1, + kUpb_MessageModifier_IsExtendable = 1 << 2, +} kUpb_MessageModifier; + +typedef enum { + kUpb_FieldModifier_IsRepeated = 1 << 0, + kUpb_FieldModifier_IsPacked = 1 << 1, + kUpb_FieldModifier_IsClosedEnum = 1 << 2, + kUpb_FieldModifier_IsProto3Singular = 1 << 3, + kUpb_FieldModifier_IsRequired = 1 << 4, +} kUpb_FieldModifier; + +typedef struct { + char* end; // Limit of the buffer passed as a parameter. + // Aliased to internal-only members in .cc. + char internal[32]; +} upb_MtDataEncoder; + +// If the input buffer has at least this many bytes available, the encoder call +// is guaranteed to succeed (as long as field number order is maintained). +#define kUpb_MtDataEncoder_MinSize 16 + +// Encodes field/oneof information for a given message. The sequence of calls +// should look like: +// +// upb_MtDataEncoder e; +// char buf[256]; +// char* ptr = buf; +// e.end = ptr + sizeof(buf); +// ptr = upb_MtDataEncoder_StartMessage(&e, ptr); +// // Fields *must* be in field number order. +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// +// // If oneofs are present. Oneofs must be encoded after regular fields. +// ptr = upb_MiniTable_StartOneof(&e, ptr) +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// ptr = upb_MiniTable_StartOneof(&e, ptr); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// Oneofs must be encoded after all regular fields. +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod); +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod); +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr); +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num); + +// Encodes the set of values for a given enum. The values must be given in +// order (after casting to uint32_t), and repeats are not allowed. +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e); +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val); +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr); + +/** upb_MiniTable *************************************************************/ + +typedef enum { + kUpb_MiniTablePlatform_32Bit, + kUpb_MiniTablePlatform_64Bit, + kUpb_MiniTablePlatform_Native = + UPB_SIZE(kUpb_MiniTablePlatform_32Bit, kUpb_MiniTablePlatform_64Bit), +} upb_MiniTablePlatform; + +// Builds a mini table from the data encoded in the buffer [data, len]. If any +// errors occur, returns NULL and sets a status message. In the success case, +// the caller must call upb_MiniTable_SetSub*() for all message or proto2 enum +// fields to link the table to the appropriate sub-tables. +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status); +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub); +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub); + +bool upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + upb_MiniTable_Sub sub, upb_Status* status); + +// Special-case functions for MessageSet layout and map entries. +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena); +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena); + +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status); + +// Like upb_MiniTable_Build(), but the user provides a buffer of layout data so +// it can be reused from call to call, avoiding repeated realloc()/free(). +// +// The caller owns `*buf` both before and after the call, and must free() it +// when it is no longer in use. The function will realloc() `*buf` as +// necessary, updating `*size` accordingly. +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, upb_Status* status); + +// For testing only. +char upb_ToBase92(int8_t ch); +char upb_FromBase92(uint8_t ch); +bool upb_IsTypePackable(upb_FieldType type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_H_ */ + /** upb/port_undef.inc ************************************************************/ /* See port_def.inc. This should #undef all macros #defined there. */ @@ -5448,6 +6474,7 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_MALLOC_ALIGN #undef UPB_LIKELY #undef UPB_UNLIKELY #undef UPB_FORCEINLINE @@ -5470,3 +6497,4 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN +#undef UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl index f635031519..6aee8b76dd 100644 --- a/protobuf_deps.bzl +++ b/protobuf_deps.bzl @@ -117,6 +117,6 @@ def protobuf_deps(): _github_archive( name = "upb", repo = "https://github.com/protocolbuffers/upb", - commit = "79462f8a654ef782e149f59cb07d930269af951a", - sha256 = "1613eae24fdd0cd7b570860123502f336939094de9af5777815f63ac86ef8d0c", + commit = "969f6fdb88e94ced87953e53716893c68ec7b1ce", + sha256 = "6754b7f95c92f69a832a82931aea40d066cc689dbc1eb3348b84c1ed95285296", ) diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index d50bd99f9c..85b1d0f2ff 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -90,21 +90,22 @@ #define UPB_INLINE static #endif +#define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) -/* Hints to the compiler about likely/unlikely branches. */ +// Hints to the compiler about likely/unlikely branches. #if defined (__GNUC__) || defined(__clang__) -#define UPB_LIKELY(x) __builtin_expect((x),1) -#define UPB_UNLIKELY(x) __builtin_expect((x),0) +#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) +#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) #else #define UPB_LIKELY(x) (x) #define UPB_UNLIKELY(x) (x) #endif -/* Macros for function attributes on compilers that support them. */ +// Macros for function attributes on compilers that support them. #ifdef __GNUC__ #define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) #define UPB_NOINLINE __attribute__((noinline)) @@ -127,8 +128,7 @@ #define UPB_UNUSED(var) (void)var -/* UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. - */ +// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. #ifdef NDEBUG #ifdef __GNUC__ #define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() @@ -262,4911 +262,5111 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 #endif -/** upb/decode.c ************************************************************/ +/** upb/collections.c ************************************************************/ -#include #include -/* Must be last. */ - -/* Maps descriptor type -> elem_size_lg2. */ -static const uint8_t desctype_to_elem_size_lg2[] = { - -1, /* invalid descriptor type */ - 3, /* DOUBLE */ - 2, /* FLOAT */ - 3, /* INT64 */ - 3, /* UINT64 */ - 2, /* INT32 */ - 3, /* FIXED64 */ - 2, /* FIXED32 */ - 0, /* BOOL */ - UPB_SIZE(3, 4), /* STRING */ - UPB_SIZE(2, 3), /* GROUP */ - UPB_SIZE(2, 3), /* MESSAGE */ - UPB_SIZE(3, 4), /* BYTES */ - 2, /* UINT32 */ - 2, /* ENUM */ - 2, /* SFIXED32 */ - 3, /* SFIXED64 */ - 2, /* SINT32 */ - 3, /* SINT64 */ +/* Strings/bytes are special-cased in maps. */ +static char _upb_CTypeo_mapsize[12] = { + 0, + 1, /* kUpb_CType_Bool */ + 4, /* kUpb_CType_Float */ + 4, /* kUpb_CType_Int32 */ + 4, /* kUpb_CType_UInt32 */ + 4, /* kUpb_CType_Enum */ + sizeof(void*), /* kUpb_CType_Message */ + 8, /* kUpb_CType_Double */ + 8, /* kUpb_CType_Int64 */ + 8, /* kUpb_CType_UInt64 */ + 0, /* kUpb_CType_String */ + 0, /* kUpb_CType_Bytes */ }; -/* Maps descriptor type -> upb map size. */ -static const uint8_t desctype_to_mapsize[] = { - -1, /* invalid descriptor type */ - 8, /* DOUBLE */ - 4, /* FLOAT */ - 8, /* INT64 */ - 8, /* UINT64 */ - 4, /* INT32 */ - 8, /* FIXED64 */ - 4, /* FIXED32 */ - 1, /* BOOL */ - UPB_MAPTYPE_STRING, /* STRING */ - sizeof(void*), /* GROUP */ - sizeof(void*), /* MESSAGE */ - UPB_MAPTYPE_STRING, /* BYTES */ - 4, /* UINT32 */ - 4, /* ENUM */ - 4, /* SFIXED32 */ - 8, /* SFIXED64 */ - 4, /* SINT32 */ - 8, /* SINT64 */ +static const char _upb_CTypeo_sizelg2[12] = { + 0, + 0, /* kUpb_CType_Bool */ + 2, /* kUpb_CType_Float */ + 2, /* kUpb_CType_Int32 */ + 2, /* kUpb_CType_UInt32 */ + 2, /* kUpb_CType_Enum */ + UPB_SIZE(2, 3), /* kUpb_CType_Message */ + 3, /* kUpb_CType_Double */ + 3, /* kUpb_CType_Int64 */ + 3, /* kUpb_CType_UInt64 */ + UPB_SIZE(3, 4), /* kUpb_CType_String */ + UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ }; -static const unsigned FIXED32_OK_MASK = (1 << kUpb_FieldType_Float) | - (1 << kUpb_FieldType_Fixed32) | - (1 << kUpb_FieldType_SFixed32); +/** upb_Array *****************************************************************/ -static const unsigned FIXED64_OK_MASK = (1 << kUpb_FieldType_Double) | - (1 << kUpb_FieldType_Fixed64) | - (1 << kUpb_FieldType_SFixed64); +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { + return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); +} -/* Three fake field types for MessageSet. */ -#define TYPE_MSGSET_ITEM 19 -#define TYPE_MSGSET_TYPE_ID 20 -#define TYPE_COUNT 20 +size_t upb_Array_Size(const upb_Array* arr) { return arr->len; } -/* Op: an action to be performed for a wire-type/field-type combination. */ -#define OP_UNKNOWN -1 /* Unknown field. */ -#define OP_MSGSET_ITEM -2 -#define OP_MSGSET_TYPEID -3 -#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */ -#define OP_ENUM 1 -#define OP_STRING 4 -#define OP_BYTES 5 -#define OP_SUBMSG 6 -/* Scalar fields use only ops above. Repeated fields can use any op. */ -#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ -#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ -#define OP_PACKED_ENUM 13 +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { + upb_MessageValue ret; + const char* data = _upb_array_constptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); + memcpy(&ret, data + (i << lg2), 1 << lg2); + return ret; +} -static const int8_t varint_ops[] = { - OP_UNKNOWN, /* field not found */ - OP_UNKNOWN, /* DOUBLE */ - OP_UNKNOWN, /* FLOAT */ - OP_SCALAR_LG2(3), /* INT64 */ - OP_SCALAR_LG2(3), /* UINT64 */ - OP_SCALAR_LG2(2), /* INT32 */ - OP_UNKNOWN, /* FIXED64 */ - OP_UNKNOWN, /* FIXED32 */ - OP_SCALAR_LG2(0), /* BOOL */ - OP_UNKNOWN, /* STRING */ - OP_UNKNOWN, /* GROUP */ - OP_UNKNOWN, /* MESSAGE */ - OP_UNKNOWN, /* BYTES */ - OP_SCALAR_LG2(2), /* UINT32 */ - OP_ENUM, /* ENUM */ - OP_UNKNOWN, /* SFIXED32 */ - OP_UNKNOWN, /* SFIXED64 */ - OP_SCALAR_LG2(2), /* SINT32 */ - OP_SCALAR_LG2(3), /* SINT64 */ - OP_UNKNOWN, /* MSGSET_ITEM */ - OP_MSGSET_TYPEID, /* MSGSET TYPEID */ -}; +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); + memcpy(data + (i << lg2), &val, 1 << lg2); +} -static const int8_t delim_ops[] = { - /* For non-repeated field type. */ - OP_UNKNOWN, /* field not found */ - OP_UNKNOWN, /* DOUBLE */ - OP_UNKNOWN, /* FLOAT */ - OP_UNKNOWN, /* INT64 */ - OP_UNKNOWN, /* UINT64 */ - OP_UNKNOWN, /* INT32 */ - OP_UNKNOWN, /* FIXED64 */ - OP_UNKNOWN, /* FIXED32 */ - OP_UNKNOWN, /* BOOL */ - OP_STRING, /* STRING */ - OP_UNKNOWN, /* GROUP */ - OP_SUBMSG, /* MESSAGE */ - OP_BYTES, /* BYTES */ - OP_UNKNOWN, /* UINT32 */ - OP_UNKNOWN, /* ENUM */ - OP_UNKNOWN, /* SFIXED32 */ - OP_UNKNOWN, /* SFIXED64 */ - OP_UNKNOWN, /* SINT32 */ - OP_UNKNOWN, /* SINT64 */ - OP_UNKNOWN, /* MSGSET_ITEM */ - OP_UNKNOWN, /* MSGSET TYPEID */ - /* For repeated field type. */ - OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */ - OP_FIXPCK_LG2(2), /* REPEATED FLOAT */ - OP_VARPCK_LG2(3), /* REPEATED INT64 */ - OP_VARPCK_LG2(3), /* REPEATED UINT64 */ - OP_VARPCK_LG2(2), /* REPEATED INT32 */ - OP_FIXPCK_LG2(3), /* REPEATED FIXED64 */ - OP_FIXPCK_LG2(2), /* REPEATED FIXED32 */ - OP_VARPCK_LG2(0), /* REPEATED BOOL */ - OP_STRING, /* REPEATED STRING */ - OP_SUBMSG, /* REPEATED GROUP */ - OP_SUBMSG, /* REPEATED MESSAGE */ - OP_BYTES, /* REPEATED BYTES */ - OP_VARPCK_LG2(2), /* REPEATED UINT32 */ - OP_PACKED_ENUM, /* REPEATED ENUM */ - OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */ - OP_FIXPCK_LG2(3), /* REPEATED SFIXED64 */ - OP_VARPCK_LG2(2), /* REPEATED SINT32 */ - OP_VARPCK_LG2(3), /* REPEATED SINT64 */ - /* Omitting MSGSET_*, because we never emit a repeated msgset type */ -}; +bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + if (!upb_Array_Resize(arr, arr->len + 1, arena)) { + return false; + } + upb_Array_Set(arr, arr->len - 1, val); + return true; +} -typedef union { - bool bool_val; - uint32_t uint32_val; - uint64_t uint64_val; - uint32_t size; -} wireval; +void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, + size_t count) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); +} -static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable* layout); +bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, + upb_Arena* arena) { + UPB_ASSERT(i <= arr->len); + UPB_ASSERT(count + arr->len >= count); + size_t oldsize = arr->len; + if (!upb_Array_Resize(arr, arr->len + count, arena)) { + return false; + } + upb_Array_Move(arr, i + count, i, oldsize - i); + return true; +} -UPB_NORETURN static void* decode_err(upb_Decoder* d, upb_DecodeStatus status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); +/* + * i end arr->len + * |------------|XXXXXXXX|--------| + */ +void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { + size_t end = i + count; + UPB_ASSERT(i <= end); + UPB_ASSERT(end <= arr->len); + upb_Array_Move(arr, i, end, arr->len - end); + arr->len -= count; } -const char* fastdecode_err(upb_Decoder* d, int status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); - return NULL; +bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { + return _upb_Array_Resize(arr, size, arena); } -static void decode_verifyutf8(upb_Decoder* d, const char* buf, int len) { - if (!decode_verifyutf8_inl(buf, len)) - decode_err(d, kUpb_DecodeStatus_BadUtf8); + +/** upb_Map *******************************************************************/ + +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { + return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], + _upb_CTypeo_mapsize[value_type]); } -static bool decode_reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { - bool need_realloc = arr->size - arr->len < elem; - if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - return need_realloc; +size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } + +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val) { + return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); } -typedef struct { - const char* ptr; - uint64_t val; -} decode_vret; +void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } -UPB_NOINLINE -static decode_vret decode_longvarint64(const char* ptr, uint64_t val) { - decode_vret ret = {NULL, 0}; - uint64_t byte; - int i; - for (i = 1; i < 10; i++) { - byte = (uint8_t)ptr[i]; - val += (byte - 1) << (i * 7); - if (!(byte & 0x80)) { - ret.ptr = ptr + i + 1; - ret.val = val; - return ret; - } - } - return ret; +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val, + map->val_size, arena); } -UPB_FORCEINLINE -static const char* decode_varint64(upb_Decoder* d, const char* ptr, - uint64_t* val) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = byte; - return ptr + 1; - } else { - decode_vret res = decode_longvarint64(ptr, byte); - if (!res.ptr) return decode_err(d, kUpb_DecodeStatus_Malformed); - *val = res.val; - return res.ptr; - } +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { + return _upb_Map_Delete(map, &key, map->key_size); } -UPB_FORCEINLINE -static const char* decode_tag(upb_Decoder* d, const char* ptr, uint32_t* val) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = byte; - return ptr + 1; - } else { - const char* start = ptr; - decode_vret res = decode_longvarint64(ptr, byte); - if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - *val = res.val; - return res.ptr; - } +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { + return _upb_map_next(map, iter); } -static void decode_munge_int32(wireval* val) { - if (!_upb_IsLittleEndian()) { - /* The next stage will memcpy(dst, &val, 4) */ - val->uint32_val = val->uint64_val; - } +bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + UPB_ASSERT(iter != kUpb_Map_Begin); + i.t = &map->table; + i.index = iter; + return upb_strtable_done(&i); } -static void decode_munge(int type, wireval* val) { - switch (type) { - case kUpb_FieldType_Bool: - val->bool_val = val->uint64_val != 0; - break; - case kUpb_FieldType_SInt32: { - uint32_t n = val->uint64_val; - val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); - break; - } - case kUpb_FieldType_SInt64: { - uint64_t n = val->uint64_val; - val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); - break; - } - case kUpb_FieldType_Int32: - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Enum: - decode_munge_int32(val); - break; - } +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); + return ret; } -static upb_Message* decode_newsubmsg(upb_Decoder* d, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - return _upb_Message_New_inl(subl, &d->arena); +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); + return ret; } -UPB_NOINLINE -const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, - int overrun) { - int status; - ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); - if (ptr == NULL) { - return decode_err(d, status); - } - return ptr; -} +/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue + * value); */ -static const char* decode_readstr(upb_Decoder* d, const char* ptr, int size, - upb_StringView* str) { - if (d->options & kUpb_DecodeOption_AliasString) { - str->data = ptr; - } else { - char* data = upb_Arena_Malloc(&d->arena, size); - if (!data) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - memcpy(data, ptr, size); - str->data = data; - } - str->size = size; - return ptr + size; -} +/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upb.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ -UPB_FORCEINLINE -static const char* decode_tosubmsg2(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable* subl, int size) { - int saved_delta = decode_pushlimit(d, ptr, size); - if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); - ptr = decode_msg(d, ptr, submsg, subl); - if (d->end_group != DECODE_NOGROUP) - return decode_err(d, kUpb_DecodeStatus_Malformed); - decode_poplimit(d, ptr, saved_delta); - d->depth++; - return ptr; -} +#include -UPB_FORCEINLINE -static const char* decode_tosubmsg(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, int size) { - return decode_tosubmsg2(d, ptr, submsg, subs[field->submsg_index].submsg, - size); -} -UPB_FORCEINLINE -static const char* decode_group(upb_Decoder* d, const char* ptr, - upb_Message* submsg, const upb_MiniTable* subl, - uint32_t number) { - if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); - if (decode_isdone(d, &ptr)) { - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - ptr = decode_msg(d, ptr, submsg, subl); - if (d->end_group != number) return decode_err(d, kUpb_DecodeStatus_Malformed); - d->end_group = DECODE_NOGROUP; - d->depth++; - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { + {.submsg = &google_protobuf_FileDescriptorProto_msginit}, +}; -UPB_FORCEINLINE -static const char* decode_togroup(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - return decode_group(d, ptr, submsg, subl, field->number); -} +static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static char* encode_varint32(uint32_t val, char* ptr) { - do { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - *(ptr++) = byte; - } while (val); - return ptr; -} +const upb_MiniTable google_protobuf_FileDescriptorSet_msginit = { + &google_protobuf_FileDescriptorSet_submsgs[0], + &google_protobuf_FileDescriptorSet__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; -static void upb_Decode_AddUnknownVarints(upb_Decoder* d, upb_Message* msg, - uint32_t val1, uint32_t val2) { - char buf[20]; - char* end = buf; - end = encode_varint32(val1, end); - end = encode_varint32(val2, end); +static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { + {.submsg = &google_protobuf_DescriptorProto_msginit}, + {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, + {.submsg = &google_protobuf_ServiceDescriptorProto_msginit}, + {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, + {.submsg = &google_protobuf_FileOptions_msginit}, + {.submsg = &google_protobuf_SourceCodeInfo_msginit}, +}; - if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } -} +static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[12] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(24, 48), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(28, 56), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(32, 64), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(36, 72), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(40, 80), UPB_SIZE(3, 3), 4, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(44, 88), UPB_SIZE(4, 4), 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(48, 96), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(52, 104), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {12, UPB_SIZE(56, 112), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}; -UPB_NOINLINE -static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, - uint32_t v) { - // OPT: binary search long lists? - int n = e->value_count; - for (int i = 0; i < n; i++) { - if ((uint32_t)e->values[i] == v) return true; - } +const upb_MiniTable google_protobuf_FileDescriptorProto_msginit = { + &google_protobuf_FileDescriptorProto_submsgs[0], + &google_protobuf_FileDescriptorProto__fields[0], + UPB_SIZE(64, 128), 12, kUpb_ExtMode_NonExtendable, 12, 255, 0, +}; - // Unrecognized enum goes into unknown fields. - // For packed fields the tag could be arbitrarily far in the past, so we - // just re-encode the tag and value here. - uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; - upb_Decode_AddUnknownVarints(d, msg, tag, v); - return false; -} +static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[8] = { + {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, + {.submsg = &google_protobuf_DescriptorProto_msginit}, + {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, + {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msginit}, + {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, + {.submsg = &google_protobuf_MessageOptions_msginit}, + {.submsg = &google_protobuf_OneofDescriptorProto_msginit}, + {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msginit}, +}; -UPB_FORCEINLINE -static bool decode_checkenum(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, wireval* val) { - uint32_t v = val->uint32_val; +static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 48), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 56), UPB_SIZE(0, 0), 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(32, 64), UPB_SIZE(2, 2), 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(36, 72), UPB_SIZE(0, 0), 6, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(40, 80), UPB_SIZE(0, 0), 7, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(44, 88), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (UPB_LIKELY(v < 64) && UPB_LIKELY(((1ULL << v) & e->mask))) return true; +const upb_MiniTable google_protobuf_DescriptorProto_msginit = { + &google_protobuf_DescriptorProto_submsgs[0], + &google_protobuf_DescriptorProto__fields[0], + UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, 255, 0, +}; - return decode_checkenum_slow(d, ptr, msg, e, field, v); -} +static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { + {.submsg = &google_protobuf_ExtensionRangeOptions_msginit}, +}; -UPB_NOINLINE -static const char* decode_enum_toarray(upb_Decoder* d, const char* ptr, - upb_Message* msg, upb_Array* arr, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; - if (!decode_checkenum(d, ptr, msg, e, field, val)) return ptr; - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - arr->len++; - memcpy(mem, val, 4); - return ptr; -} +static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 16), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -UPB_FORCEINLINE -static const char* decode_fixed_packed(upb_Decoder* d, const char* ptr, - upb_Array* arr, wireval* val, - const upb_MiniTable_Field* field, - int lg2) { - int mask = (1 << lg2) - 1; - size_t count = val->size >> lg2; - if ((val->size & mask) != 0) { - // Length isn't a round multiple of elem size. - return decode_err(d, kUpb_DecodeStatus_Malformed); - } - decode_reserve(d, arr, count); - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - arr->len += count; - // Note: if/when the decoder supports multi-buffer input, we will need to - // handle buffer seams here. - if (_upb_IsLittleEndian()) { - memcpy(mem, ptr, val->size); - ptr += val->size; - } else { - const char* end = ptr + val->size; - char* dst = mem; - while (ptr < end) { - if (lg2 == 2) { - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap32(val); - memcpy(dst, &val, sizeof(val)); - } else { - UPB_ASSERT(lg2 == 3); - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap64(val); - memcpy(dst, &val, sizeof(val)); - } - ptr += 1 << lg2; - dst += 1 << lg2; - } - } +const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit = { + &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], + &google_protobuf_DescriptorProto_ExtensionRange__fields[0], + UPB_SIZE(16, 24), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; - return ptr; -} +static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; -UPB_FORCEINLINE -static const char* decode_varint_packed(upb_Decoder* d, const char* ptr, - upb_Array* arr, wireval* val, - const upb_MiniTable_Field* field, - int lg2) { - int scale = 1 << lg2; - int saved_limit = decode_pushlimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - while (!decode_isdone(d, &ptr)) { - wireval elem; - ptr = decode_varint64(d, ptr, &elem.uint64_val); - decode_munge(field->descriptortype, &elem); - if (decode_reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - } - arr->len++; - memcpy(out, &elem, scale); - out += scale; - } - decode_poplimit(d, ptr, saved_limit); - return ptr; -} +const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit = { + NULL, + &google_protobuf_DescriptorProto_ReservedRange__fields[0], + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; -UPB_NOINLINE -static const char* decode_enum_packed(upb_Decoder* d, const char* ptr, - upb_Message* msg, upb_Array* arr, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; - int saved_limit = decode_pushlimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - while (!decode_isdone(d, &ptr)) { - wireval elem; - ptr = decode_varint64(d, ptr, &elem.uint64_val); - decode_munge_int32(&elem); - if (!decode_checkenum(d, ptr, msg, e, field, &elem)) { - continue; - } - if (decode_reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); - } - arr->len++; - memcpy(out, &elem, 4); - out += 4; - } - decode_poplimit(d, ptr, saved_limit); - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; -static const char* decode_toarray(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val, int op) { - upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); - upb_Array* arr = *arrp; - void* mem; +static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { + {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (arr) { - decode_reserve(d, arr, 1); - } else { - size_t lg2 = desctype_to_elem_size_lg2[field->descriptortype]; - arr = _upb_Array_New(&d->arena, 4, lg2); - if (!arr) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - *arrp = arr; - } +const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit = { + &google_protobuf_ExtensionRangeOptions_submsgs[0], + &google_protobuf_ExtensionRangeOptions__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - switch (op) { - case OP_SCALAR_LG2(0): - case OP_SCALAR_LG2(2): - case OP_SCALAR_LG2(3): - /* Append scalar value. */ - mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << op, void); - arr->len++; - memcpy(mem, val, 1 << op); - return ptr; - case OP_STRING: - decode_verifyutf8(d, ptr, val->size); - /* Fallthrough. */ - case OP_BYTES: { - /* Append bytes. */ - upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->len; - arr->len++; - return decode_readstr(d, ptr, val->size, str); - } - case OP_SUBMSG: { - /* Append submessage / group. */ - upb_Message* submsg = decode_newsubmsg(d, subs, field); - *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void*), upb_Message*) = - submsg; - arr->len++; - if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { - return decode_togroup(d, ptr, submsg, subs, field); - } else { - return decode_tosubmsg(d, ptr, submsg, subs, field, val->size); - } - } - case OP_FIXPCK_LG2(2): - case OP_FIXPCK_LG2(3): - return decode_fixed_packed(d, ptr, arr, val, field, - op - OP_FIXPCK_LG2(0)); - case OP_VARPCK_LG2(0): - case OP_VARPCK_LG2(2): - case OP_VARPCK_LG2(3): - return decode_varint_packed(d, ptr, arr, val, field, - op - OP_VARPCK_LG2(0)); - case OP_ENUM: - return decode_enum_toarray(d, ptr, msg, arr, subs, field, val); - case OP_PACKED_ENUM: - return decode_enum_packed(d, ptr, msg, arr, subs, field, val); - default: - UPB_UNREACHABLE(); - } -} +static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { + {.subenum = &google_protobuf_FieldDescriptorProto_Label_enuminit}, + {.subenum = &google_protobuf_FieldDescriptorProto_Type_enuminit}, + {.submsg = &google_protobuf_FieldOptions_msginit}, +}; -static const char* decode_tomap(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, - wireval* val) { - upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*); - upb_Map* map = *map_p; - upb_MapEntry ent; - const upb_MiniTable* entry = subs[field->submsg_index].submsg; +static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { + {1, UPB_SIZE(24, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(32, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 4), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), UPB_SIZE(4, 4), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(12, 12), UPB_SIZE(5, 5), 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(40, 56), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(48, 72), UPB_SIZE(7, 7), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(56, 88), UPB_SIZE(8, 8), 2, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(16, 16), UPB_SIZE(9, 9), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(60, 96), UPB_SIZE(10, 10), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(20, 20), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; - if (!map) { - /* Lazily create map. */ - const upb_MiniTable_Field* key_field = &entry->fields[0]; - const upb_MiniTable_Field* val_field = &entry->fields[1]; - char key_size = desctype_to_mapsize[key_field->descriptortype]; - char val_size = desctype_to_mapsize[val_field->descriptortype]; - UPB_ASSERT(key_field->offset == 0); - UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); - map = _upb_Map_New(&d->arena, key_size, val_size); - *map_p = map; - } +const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit = { + &google_protobuf_FieldDescriptorProto_submsgs[0], + &google_protobuf_FieldDescriptorProto__fields[0], + UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, 255, 0, +}; - /* Parse map entry. */ - memset(&ent, 0, sizeof(ent)); +static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_OneofOptions_msginit}, +}; - if (entry->fields[1].descriptortype == kUpb_FieldType_Message || - entry->fields[1].descriptortype == kUpb_FieldType_Group) { - /* Create proactively to handle the case where it doesn't appear. */ - ent.v.val = - upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); - } +static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - const char* start = ptr; - ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size); - // check if ent had any unknown fields - size_t size; - upb_Message_GetUnknown(&ent.k, &size); - if (size != 0) { - uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Delimited; - upb_Decode_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); - if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - } else { - _upb_Map_Set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena); - } - return ptr; -} +const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit = { + &google_protobuf_OneofDescriptorProto_submsgs[0], + &google_protobuf_OneofDescriptorProto__fields[0], + UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; -static const char* decode_tomsg(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field, wireval* val, - int op) { - void* mem = UPB_PTR_AT(msg, field->offset, void); - int type = field->descriptortype; +static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { + {.submsg = &google_protobuf_EnumValueDescriptorProto_msginit}, + {.submsg = &google_protobuf_EnumOptions_msginit}, + {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit}, +}; - if (UPB_UNLIKELY(op == OP_ENUM) && - !decode_checkenum(d, ptr, msg, subs[field->submsg_index].subenum, field, - val)) { - return ptr; - } +static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 48), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - /* Set presence if necessary. */ - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (field->presence < 0) { - /* Oneof case */ - uint32_t* oneof_case = _upb_oneofcase_field(msg, field); - if (op == OP_SUBMSG && *oneof_case != field->number) { - memset(mem, 0, sizeof(void*)); - } - *oneof_case = field->number; - } +const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit = { + &google_protobuf_EnumDescriptorProto_submsgs[0], + &google_protobuf_EnumDescriptorProto__fields[0], + UPB_SIZE(32, 56), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, +}; - /* Store into message. */ - switch (op) { - case OP_SUBMSG: { - upb_Message** submsgp = mem; - upb_Message* submsg = *submsgp; - if (!submsg) { - submsg = decode_newsubmsg(d, subs, field); - *submsgp = submsg; - } - if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { - ptr = decode_togroup(d, ptr, submsg, subs, field); - } else { - ptr = decode_tosubmsg(d, ptr, submsg, subs, field, val->size); - } - break; - } - case OP_STRING: - decode_verifyutf8(d, ptr, val->size); - /* Fallthrough. */ - case OP_BYTES: - return decode_readstr(d, ptr, val->size, mem); - case OP_SCALAR_LG2(3): - memcpy(mem, val, 8); - break; - case OP_ENUM: - case OP_SCALAR_LG2(2): - memcpy(mem, val, 4); - break; - case OP_SCALAR_LG2(0): - memcpy(mem, val, 1); - break; - default: - UPB_UNREACHABLE(); - } +static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; - return ptr; -} +const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { + NULL, + &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +}; -UPB_NOINLINE -const char* decode_checkrequired(upb_Decoder* d, const char* ptr, - const upb_Message* msg, - const upb_MiniTable* l) { - assert(l->required_count); - if (UPB_LIKELY((d->options & kUpb_DecodeOption_CheckRequired) == 0)) { - return ptr; - } - uint64_t msg_head; - memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); - if (upb_MiniTable_requiredmask(l) & ~msg_head) { - d->missing_required = true; - } - return ptr; -} +static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_EnumValueOptions_msginit}, +}; -UPB_FORCEINLINE -static bool decode_tryfastdispatch(upb_Decoder* d, const char** ptr, - upb_Message* msg, - const upb_MiniTable* layout) { -#if UPB_FASTTABLE - if (layout && layout->table_mask != (unsigned char)-1) { - uint16_t tag = fastdecode_loadtag(*ptr); - intptr_t table = decode_totable(layout); - *ptr = fastdecode_tagdispatch(d, *ptr, msg, table, 0, tag); - return true; - } -#endif - return false; -} +static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { + {1, UPB_SIZE(8, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 24), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static const char* decode_msgset(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable* layout) { - // We create a temporary upb_MiniTable here and abuse its fields as temporary - // storage, to avoid creating lots of MessageSet-specific parsing code-paths: - // 1. We store 'layout' in item_layout.subs. We will need this later as - // a key to look up extensions for this MessageSet. - // 2. We use item_layout.fields as temporary storage to store the extension - // we - // found when parsing the type id. - upb_MiniTable item_layout = { - .subs = (const upb_MiniTable_Sub[]){{.submsg = layout}}, - .fields = NULL, - .size = 0, - .field_count = 0, - .ext = kUpb_ExtMode_IsMessageSet_ITEM, - .dense_below = 0, - .table_mask = -1}; - return decode_group(d, ptr, msg, &item_layout, 1); -} +const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit = { + &google_protobuf_EnumValueDescriptorProto_submsgs[0], + &google_protobuf_EnumValueDescriptorProto__fields[0], + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; -static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d, - const upb_MiniTable* l, - uint32_t field_number, - int* last_field_index) { - static upb_MiniTable_Field none = {0, 0, 0, 0, 0, 0}; - if (l == NULL) return &none; +static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { + {.submsg = &google_protobuf_MethodDescriptorProto_msginit}, + {.submsg = &google_protobuf_ServiceOptions_msginit}, +}; - size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX - if (idx < l->dense_below) { - /* Fastest case: index into dense fields. */ - goto found; - } +static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (l->dense_below < l->field_count) { - /* Linear search non-dense fields. Resume scanning from last_field_index - * since fields are usually in order. */ - int last = *last_field_index; - for (idx = last; idx < l->field_count; idx++) { - if (l->fields[idx].number == field_number) { - goto found; - } - } +const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit = { + &google_protobuf_ServiceDescriptorProto_submsgs[0], + &google_protobuf_ServiceDescriptorProto__fields[0], + UPB_SIZE(24, 40), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, +}; - for (idx = l->dense_below; idx < last; idx++) { - if (l->fields[idx].number == field_number) { - goto found; - } - } - } +static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_MethodOptions_msginit}, +}; - if (d->extreg) { - switch (l->ext) { - case kUpb_ExtMode_Extendable: { - const upb_MiniTable_Extension* ext = - _upb_extreg_get(d->extreg, l, field_number); - if (ext) return &ext->field; - break; - } - case kUpb_ExtMode_IsMessageSet: - if (field_number == _UPB_MSGSET_ITEM) { - static upb_MiniTable_Field item = {0, 0, 0, 0, TYPE_MSGSET_ITEM, 0}; - return &item; - } - break; - case kUpb_ExtMode_IsMessageSet_ITEM: - switch (field_number) { - case _UPB_MSGSET_TYPEID: { - static upb_MiniTable_Field type_id = { - 0, 0, 0, 0, TYPE_MSGSET_TYPE_ID, 0}; - return &type_id; - } - case _UPB_MSGSET_MESSAGE: - if (l->fields) { - // We saw type_id previously and succeeded in looking up msg. - return l->fields; - } else { - // TODO: out of order MessageSet. - // This is a very rare case: all serializers will emit in-order - // MessageSets. To hit this case there has to be some kind of - // re-ordering proxy. We should eventually handle this case, but - // not today. - } - break; - } - } - } +static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), UPB_SIZE(3, 3), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(28, 56), UPB_SIZE(4, 4), 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(1, 1), UPB_SIZE(5, 5), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(2, 2), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; - return &none; /* Unknown field. */ +const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit = { + &google_protobuf_MethodDescriptorProto_submsgs[0], + &google_protobuf_MethodDescriptorProto__fields[0], + UPB_SIZE(32, 64), 6, kUpb_ExtMode_NonExtendable, 6, 255, 0, +}; -found: - UPB_ASSERT(l->fields[idx].number == field_number); - *last_field_index = idx; - return &l->fields[idx]; -} +static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { + {.subenum = &google_protobuf_FileOptions_OptimizeMode_enuminit}, + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; -UPB_FORCEINLINE -static const char* decode_wireval(upb_Decoder* d, const char* ptr, - const upb_MiniTable_Field* field, - int wire_type, wireval* val, int* op) { - switch (wire_type) { - case kUpb_WireType_Varint: - ptr = decode_varint64(d, ptr, &val->uint64_val); - *op = varint_ops[field->descriptortype]; - decode_munge(field->descriptortype, val); - return ptr; - case kUpb_WireType_32Bit: - memcpy(&val->uint32_val, ptr, 4); - val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val); - *op = OP_SCALAR_LG2(2); - if (((1 << field->descriptortype) & FIXED32_OK_MASK) == 0) { - *op = OP_UNKNOWN; - } - return ptr + 4; - case kUpb_WireType_64Bit: - memcpy(&val->uint64_val, ptr, 8); - val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); - *op = OP_SCALAR_LG2(3); - if (((1 << field->descriptortype) & FIXED64_OK_MASK) == 0) { - *op = OP_UNKNOWN; - } - return ptr + 8; - case kUpb_WireType_Delimited: { - int ndx = field->descriptortype; - uint64_t size; - if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += TYPE_COUNT; - ptr = decode_varint64(d, ptr, &size); - if (size >= INT32_MAX || ptr - d->end + (int32_t)size > d->limit) { - break; /* Length overflow. */ - } - *op = delim_ops[ndx]; - val->size = size; - return ptr; - } - case kUpb_WireType_StartGroup: - val->uint32_val = field->number; - if (field->descriptortype == kUpb_FieldType_Group) { - *op = OP_SUBMSG; - } else if (field->descriptortype == TYPE_MSGSET_ITEM) { - *op = OP_MSGSET_ITEM; - } else { - *op = OP_UNKNOWN; - } - return ptr; - default: - break; - } - return decode_err(d, kUpb_DecodeStatus_Malformed); -} +static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { + {1, UPB_SIZE(20, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(28, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(4, 4), UPB_SIZE(3, 3), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(8, 8), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(36, 56), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {16, UPB_SIZE(9, 9), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(10, 10), UPB_SIZE(7, 7), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {18, UPB_SIZE(11, 11), UPB_SIZE(8, 8), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {20, UPB_SIZE(12, 12), UPB_SIZE(9, 9), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {23, UPB_SIZE(13, 13), UPB_SIZE(10, 10), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {27, UPB_SIZE(14, 14), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {31, UPB_SIZE(15, 15), UPB_SIZE(12, 12), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {36, UPB_SIZE(44, 72), UPB_SIZE(13, 13), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {37, UPB_SIZE(52, 88), UPB_SIZE(14, 14), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {39, UPB_SIZE(60, 104), UPB_SIZE(15, 15), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {40, UPB_SIZE(68, 120), UPB_SIZE(16, 16), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {41, UPB_SIZE(76, 136), UPB_SIZE(17, 17), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {42, UPB_SIZE(16, 16), UPB_SIZE(18, 18), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {44, UPB_SIZE(84, 152), UPB_SIZE(19, 19), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {45, UPB_SIZE(92, 168), UPB_SIZE(20, 20), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(100, 184), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -UPB_FORCEINLINE -static const char* decode_known(upb_Decoder* d, const char* ptr, - upb_Message* msg, const upb_MiniTable* layout, - const upb_MiniTable_Field* field, int op, - wireval* val) { - const upb_MiniTable_Sub* subs = layout->subs; - uint8_t mode = field->mode; +const upb_MiniTable google_protobuf_FileOptions_msginit = { + &google_protobuf_FileOptions_submsgs[0], + &google_protobuf_FileOptions__fields[0], + UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, 255, 0, +}; - if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { - const upb_MiniTable_Extension* ext_layout = - (const upb_MiniTable_Extension*)field; - upb_Message_Extension* ext = - _upb_Message_Getorcreateext(msg, ext_layout, &d->arena); - if (UPB_UNLIKELY(!ext)) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - msg = &ext->data; - subs = &ext->ext->sub; - } +static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - switch (mode & kUpb_FieldMode_Mask) { - case kUpb_FieldMode_Array: - return decode_toarray(d, ptr, msg, subs, field, val, op); - case kUpb_FieldMode_Map: - return decode_tomap(d, ptr, msg, subs, field, val); - case kUpb_FieldMode_Scalar: - return decode_tomsg(d, ptr, msg, subs, field, val, op); - default: - UPB_UNREACHABLE(); - } -} +static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = { + {1, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(2, 2), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(3, 3), UPB_SIZE(3, 3), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(4, 4), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(8, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -static const char* decode_reverse_skip_varint(const char* ptr, uint32_t val) { - uint32_t seen = 0; - do { - ptr--; - seen <<= 7; - seen |= *ptr & 0x7f; - } while (seen != val); - return ptr; -} +const upb_MiniTable google_protobuf_MessageOptions_msginit = { + &google_protobuf_MessageOptions_submsgs[0], + &google_protobuf_MessageOptions__fields[0], + UPB_SIZE(16, 16), 5, kUpb_ExtMode_Extendable, 3, 255, 0, +}; -static const char* decode_unknown(upb_Decoder* d, const char* ptr, - upb_Message* msg, int field_number, - int wire_type, wireval val) { - if (field_number == 0) return decode_err(d, kUpb_DecodeStatus_Malformed); +static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { + {.subenum = &google_protobuf_FieldOptions_CType_enuminit}, + {.subenum = &google_protobuf_FieldOptions_JSType_enuminit}, + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - // Since unknown fields are the uncommon case, we do a little extra work here - // to walk backwards through the buffer to find the field start. This frees - // up a register in the fast paths (when the field is known), which leads to - // significant speedups in benchmarks. - const char* start = ptr; +static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[8] = { + {1, UPB_SIZE(4, 4), UPB_SIZE(1, 1), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(9, 9), UPB_SIZE(3, 3), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(10, 10), UPB_SIZE(4, 4), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(12, 12), UPB_SIZE(5, 5), 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(16, 16), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {15, UPB_SIZE(17, 17), UPB_SIZE(7, 7), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (wire_type == kUpb_WireType_Delimited) ptr += val.size; - if (msg) { - switch (wire_type) { - case kUpb_WireType_Varint: - case kUpb_WireType_Delimited: - start--; - while (start[-1] & 0x80) start--; - break; - case kUpb_WireType_32Bit: - start -= 4; - break; - case kUpb_WireType_64Bit: - start -= 8; - break; - default: - break; - } +const upb_MiniTable google_protobuf_FieldOptions_msginit = { + &google_protobuf_FieldOptions_submsgs[0], + &google_protobuf_FieldOptions__fields[0], + UPB_SIZE(24, 32), 8, kUpb_ExtMode_Extendable, 3, 255, 0, +}; - assert(start == d->debug_valstart); - uint32_t tag = ((uint32_t)field_number << 3) | wire_type; - start = decode_reverse_skip_varint(start, tag); - assert(start == d->debug_tagstart); +static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - if (wire_type == kUpb_WireType_StartGroup) { - d->unknown = start; - d->unknown_msg = msg; - ptr = decode_group(d, ptr, NULL, NULL, field_number); - start = d->unknown; - d->unknown_msg = NULL; - d->unknown = NULL; - } - if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { - return decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - } else if (wire_type == kUpb_WireType_StartGroup) { - ptr = decode_group(d, ptr, NULL, NULL, field_number); - } - return ptr; -} +static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { + {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -UPB_NOINLINE -static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, - const upb_MiniTable* layout) { - int last_field_index = 0; +const upb_MiniTable google_protobuf_OneofOptions_msginit = { + &google_protobuf_OneofOptions_submsgs[0], + &google_protobuf_OneofOptions__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, +}; -#if UPB_FASTTABLE - // The first time we want to skip fast dispatch, because we may have just been - // invoked by the fast parser to handle a case that it bailed on. - if (!decode_isdone(d, &ptr)) goto nofast; -#endif +static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - while (!decode_isdone(d, &ptr)) { - uint32_t tag; - const upb_MiniTable_Field* field; - int field_number; - int wire_type; - wireval val; - int op; +static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = { + {2, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(2, 2), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - if (decode_tryfastdispatch(d, &ptr, msg, layout)) break; +const upb_MiniTable google_protobuf_EnumOptions_msginit = { + &google_protobuf_EnumOptions_submsgs[0], + &google_protobuf_EnumOptions__fields[0], + UPB_SIZE(8, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, +}; -#if UPB_FASTTABLE - nofast: -#endif +static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; -#ifndef NDEBUG - d->debug_tagstart = ptr; -#endif +static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = { + {1, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - UPB_ASSERT(ptr < d->limit_ptr); - ptr = decode_tag(d, ptr, &tag); - field_number = tag >> 3; - wire_type = tag & 7; +const upb_MiniTable google_protobuf_EnumValueOptions_msginit = { + &google_protobuf_EnumValueOptions_submsgs[0], + &google_protobuf_EnumValueOptions__fields[0], + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 1, 255, 0, +}; -#ifndef NDEBUG - d->debug_valstart = ptr; -#endif +static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - if (wire_type == kUpb_WireType_EndGroup) { - d->end_group = field_number; - return ptr; - } +static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = { + {33, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; - field = decode_findfield(d, layout, field_number, &last_field_index); - ptr = decode_wireval(d, ptr, field, wire_type, &val, &op); +const upb_MiniTable google_protobuf_ServiceOptions_msginit = { + &google_protobuf_ServiceOptions_submsgs[0], + &google_protobuf_ServiceOptions__fields[0], + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 0, 255, 0, +}; - if (op >= 0) { - ptr = decode_known(d, ptr, msg, layout, field, op, &val); - } else { - switch (op) { - case OP_UNKNOWN: - ptr = decode_unknown(d, ptr, msg, field_number, wire_type, val); - break; - case OP_MSGSET_ITEM: - ptr = decode_msgset(d, ptr, msg, layout); - break; - case OP_MSGSET_TYPEID: { - const upb_MiniTable_Extension* ext = _upb_extreg_get( - d->extreg, layout->subs[0].submsg, val.uint64_val); - if (ext) ((upb_MiniTable*)layout)->fields = &ext->field; - break; - } - } - } - } +static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { + {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enuminit}, + {.submsg = &google_protobuf_UninterpretedOption_msginit}, +}; - return UPB_UNLIKELY(layout && layout->required_count) - ? decode_checkrequired(d, ptr, msg, layout) - : ptr; -} +static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = { + {33, UPB_SIZE(1, 1), UPB_SIZE(1, 1), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, UPB_SIZE(4, 4), UPB_SIZE(2, 2), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(8, 8), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - (void)data; - *(uint32_t*)msg |= hasbits; - return decode_msg(d, ptr, msg, decode_totablep(table)); -} +const upb_MiniTable google_protobuf_MethodOptions_msginit = { + &google_protobuf_MethodOptions_submsgs[0], + &google_protobuf_MethodOptions__fields[0], + UPB_SIZE(16, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, +}; -static upb_DecodeStatus decode_top(struct upb_Decoder* d, const char* buf, - void* msg, const upb_MiniTable* l) { - if (!decode_tryfastdispatch(d, &buf, msg, l)) { - decode_msg(d, buf, msg, l); - } - if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; - if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; - return kUpb_DecodeStatus_Ok; -} +static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_NamePart_msginit}, +}; -upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg, - const upb_MiniTable* l, - const upb_ExtensionRegistry* extreg, int options, - upb_Arena* arena) { - upb_Decoder state; - unsigned depth = (unsigned)options >> 16; +static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { + {2, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 16), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(32, 64), UPB_SIZE(2, 2), kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(40, 72), UPB_SIZE(3, 3), kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(48, 80), UPB_SIZE(4, 4), kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(16, 32), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(24, 48), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +}; - if (size <= 16) { - memset(&state.patch, 0, 32); - if (size) memcpy(&state.patch, buf, size); - buf = state.patch; - state.end = buf + size; - state.limit = 0; - options &= ~kUpb_DecodeOption_AliasString; // Can't alias patch buf. - } else { - state.end = buf + size - 16; - state.limit = 16; - } +const upb_MiniTable google_protobuf_UninterpretedOption_msginit = { + &google_protobuf_UninterpretedOption_submsgs[0], + &google_protobuf_UninterpretedOption__fields[0], + UPB_SIZE(56, 88), 7, kUpb_ExtMode_NonExtendable, 0, 255, 0, +}; - state.extreg = extreg; - state.limit_ptr = state.end; - state.unknown_msg = NULL; - state.depth = depth ? depth : 64; - state.end_group = DECODE_NOGROUP; - state.options = (uint16_t)options; - state.missing_required = false; - state.arena.head = arena->head; - state.arena.last_size = arena->last_size; - state.arena.cleanup_metadata = arena->cleanup_metadata; - state.arena.parent = arena; +static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(1, 1), UPB_SIZE(2, 2), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +}; - upb_DecodeStatus status = UPB_SETJMP(state.err); - if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { - status = decode_top(&state, buf, msg, l); - } +const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit = { + NULL, + &google_protobuf_UninterpretedOption_NamePart__fields[0], + UPB_SIZE(16, 24), 2, kUpb_ExtMode_NonExtendable, 2, 255, 2, +}; - arena->head.ptr = state.arena.head.ptr; - arena->head.end = state.arena.head.end; - arena->cleanup_metadata = state.arena.cleanup_metadata; - return status; -} +static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_SourceCodeInfo_Location_msginit}, +}; -#undef OP_UNKNOWN -#undef OP_SKIP -#undef OP_SCALAR_LG2 -#undef OP_FIXPCK_LG2 -#undef OP_VARPCK_LG2 -#undef OP_STRING -#undef OP_BYTES -#undef OP_SUBMSG +static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -/** upb/encode.c ************************************************************/ -/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ +const upb_MiniTable google_protobuf_SourceCodeInfo_msginit = { + &google_protobuf_SourceCodeInfo_submsgs[0], + &google_protobuf_SourceCodeInfo__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; +static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = { + {1, UPB_SIZE(4, 8), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 56), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#include -#include +const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit = { + NULL, + &google_protobuf_SourceCodeInfo_Location__fields[0], + UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 4, 255, 0, +}; +static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msginit}, +}; -/* Must be last. */ +static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { + {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, +}; -#define UPB_PB_VARINT_MAX_LEN 10 +const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit = { + &google_protobuf_GeneratedCodeInfo_submsgs[0], + &google_protobuf_GeneratedCodeInfo__fields[0], + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, +}; -UPB_NOINLINE -static size_t encode_varint64(uint64_t val, char* buf) { - size_t i = 0; - do { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - buf[i++] = byte; - } while (val); - return i; -} +static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { + {1, UPB_SIZE(12, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(16, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +}; -static uint32_t encode_zz32(int32_t n) { - return ((uint32_t)n << 1) ^ (n >> 31); -} -static uint64_t encode_zz64(int64_t n) { - return ((uint64_t)n << 1) ^ (n >> 63); -} +const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit = { + NULL, + &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], + UPB_SIZE(24, 40), 4, kUpb_ExtMode_NonExtendable, 4, 255, 0, +}; -typedef struct { - jmp_buf err; - upb_alloc* alloc; - char *buf, *ptr, *limit; - int options; - int depth; - _upb_mapsorter sorter; -} upb_encstate; +static const upb_MiniTable *messages_layout[27] = { + &google_protobuf_FileDescriptorSet_msginit, + &google_protobuf_FileDescriptorProto_msginit, + &google_protobuf_DescriptorProto_msginit, + &google_protobuf_DescriptorProto_ExtensionRange_msginit, + &google_protobuf_DescriptorProto_ReservedRange_msginit, + &google_protobuf_ExtensionRangeOptions_msginit, + &google_protobuf_FieldDescriptorProto_msginit, + &google_protobuf_OneofDescriptorProto_msginit, + &google_protobuf_EnumDescriptorProto_msginit, + &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, + &google_protobuf_EnumValueDescriptorProto_msginit, + &google_protobuf_ServiceDescriptorProto_msginit, + &google_protobuf_MethodDescriptorProto_msginit, + &google_protobuf_FileOptions_msginit, + &google_protobuf_MessageOptions_msginit, + &google_protobuf_FieldOptions_msginit, + &google_protobuf_OneofOptions_msginit, + &google_protobuf_EnumOptions_msginit, + &google_protobuf_EnumValueOptions_msginit, + &google_protobuf_ServiceOptions_msginit, + &google_protobuf_MethodOptions_msginit, + &google_protobuf_UninterpretedOption_msginit, + &google_protobuf_UninterpretedOption_NamePart_msginit, + &google_protobuf_SourceCodeInfo_msginit, + &google_protobuf_SourceCodeInfo_Location_msginit, + &google_protobuf_GeneratedCodeInfo_msginit, + &google_protobuf_GeneratedCodeInfo_Annotation_msginit, +}; -static size_t upb_roundup_pow2(size_t bytes) { - size_t ret = 128; - while (ret < bytes) { - ret *= 2; - } - return ret; -} +const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit = { + NULL, + 0x7fffeULL, + 0, +}; -UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); } +const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit = { + NULL, + 0xeULL, + 0, +}; -UPB_NOINLINE -static void encode_growbuffer(upb_encstate* e, size_t bytes) { - size_t old_size = e->limit - e->buf; - size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); - char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); +const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit = { + NULL, + 0xeULL, + 0, +}; - if (!new_buf) encode_err(e); +const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit = { + NULL, + 0x7ULL, + 0, +}; - /* We want previous data at the end, realloc() put it at the beginning. */ - if (old_size > 0) { - memmove(new_buf + new_size - old_size, e->buf, old_size); - } +const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit = { + NULL, + 0x7ULL, + 0, +}; - e->ptr = new_buf + new_size - (e->limit - e->ptr); - e->limit = new_buf + new_size; - e->buf = new_buf; +const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit = { + NULL, + 0x7ULL, + 0, +}; - e->ptr -= bytes; -} +static const upb_MiniTable_Enum *enums_layout[6] = { + &google_protobuf_FieldDescriptorProto_Type_enuminit, + &google_protobuf_FieldDescriptorProto_Label_enuminit, + &google_protobuf_FileOptions_OptimizeMode_enuminit, + &google_protobuf_FieldOptions_CType_enuminit, + &google_protobuf_FieldOptions_JSType_enuminit, + &google_protobuf_MethodOptions_IdempotencyLevel_enuminit, +}; -/* Call to ensure that at least "bytes" bytes are available for writing at - * e->ptr. Returns false if the bytes could not be allocated. */ -UPB_FORCEINLINE -static void encode_reserve(upb_encstate* e, size_t bytes) { - if ((size_t)(e->ptr - e->buf) < bytes) { - encode_growbuffer(e, bytes); - return; - } +const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { + messages_layout, + enums_layout, + NULL, + 27, + 6, + 0, +}; - e->ptr -= bytes; -} -/* Writes the given bytes to the buffer, handling reserve/advance. */ -static void encode_bytes(upb_encstate* e, const void* data, size_t len) { - if (len == 0) return; /* memcpy() with zero size is UB */ - encode_reserve(e, len); - memcpy(e->ptr, data, len); -} -static void encode_fixed64(upb_encstate* e, uint64_t val) { - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, sizeof(uint64_t)); -} +/** upb/decode_fast.c ************************************************************/ +// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. +// Also the table size grows by 2x. +// +// Could potentially be ported to other 64-bit archs that pass at least six +// arguments in registers and have 8 unused high bits in pointers. +// +// The overall design is to create specialized functions for every possible +// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch +// to the specialized function as quickly as possible. -static void encode_fixed32(upb_encstate* e, uint32_t val) { - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, sizeof(uint32_t)); -} -UPB_NOINLINE -static void encode_longvarint(upb_encstate* e, uint64_t val) { - size_t len; - char* start; - encode_reserve(e, UPB_PB_VARINT_MAX_LEN); - len = encode_varint64(val, e->ptr); - start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; - memmove(start, e->ptr, len); - e->ptr = start; -} +/* Must be last. */ -UPB_FORCEINLINE -static void encode_varint(upb_encstate* e, uint64_t val) { - if (val < 128 && e->ptr != e->buf) { - --e->ptr; - *e->ptr = val; - } else { - encode_longvarint(e, val); - } -} +#if UPB_FASTTABLE -static void encode_double(upb_encstate* e, double d) { - uint64_t u64; - UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); - memcpy(&u64, &d, sizeof(uint64_t)); - encode_fixed64(e, u64); -} +// The standard set of arguments passed to each parsing function. +// Thanks to x86-64 calling conventions, these will stay in registers. +#define UPB_PARSE_PARAMS \ + upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data -static void encode_float(upb_encstate* e, float d) { - uint32_t u32; - UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); - memcpy(&u32, &d, sizeof(uint32_t)); - encode_fixed32(e, u32); -} +#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data -static void encode_tag(upb_encstate* e, uint32_t field_number, - uint8_t wire_type) { - encode_varint(e, (field_number << 3) | wire_type); -} +#define RETURN_GENERIC(m) \ + /* Uncomment either of these for debugging purposes. */ \ + /* fprintf(stderr, m); */ \ + /*__builtin_trap(); */ \ + return fastdecode_generic(d, ptr, msg, table, hasbits, 0); -static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, - size_t elem_size, uint32_t tag) { - size_t bytes = arr->len * elem_size; - const char* data = _upb_array_constptr(arr); - const char* ptr = data + bytes - elem_size; +typedef enum { + CARD_s = 0, /* Singular (optional, non-repeated) */ + CARD_o = 1, /* Oneof */ + CARD_r = 2, /* Repeated */ + CARD_p = 3 /* Packed Repeated */ +} upb_card; - if (tag || !_upb_IsLittleEndian()) { - while (true) { - if (elem_size == 4) { - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, elem_size); - } else { - UPB_ASSERT(elem_size == 8); - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, elem_size); - } +UPB_NOINLINE +static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { + int overrun = data; + int status; + ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); + if (ptr == NULL) { + return fastdecode_err(d, status); + } + data = fastdecode_loadtag(ptr); + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); +} - if (tag) encode_varint(e, tag); - if (ptr == data) break; - ptr -= elem_size; +UPB_FORCEINLINE +static const char* fastdecode_dispatch(UPB_PARSE_PARAMS) { + if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { + int overrun = ptr - d->end; + if (UPB_LIKELY(overrun == d->limit)) { + // Parse is finished. + *(uint32_t*)msg |= hasbits; // Sync hasbits. + const upb_MiniTable* l = decode_totablep(table); + return UPB_UNLIKELY(l->required_count) + ? decode_checkrequired(d, ptr, msg, l) + : ptr; + } else { + data = overrun; + UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); } + } + + // Read two bytes of tag data (for a one-byte tag, the high byte is junk). + data = fastdecode_loadtag(ptr); + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); +} + +UPB_FORCEINLINE +static bool fastdecode_checktag(uint16_t data, int tagbytes) { + if (tagbytes == 1) { + return (data & 0xff) == 0; } else { - encode_bytes(e, data, bytes); + return data == 0; } } -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size); +UPB_FORCEINLINE +static const char* fastdecode_longsize(const char* ptr, int* size) { + int i; + UPB_ASSERT(*size & 0x80); + *size &= 0xff; + for (i = 0; i < 3; i++) { + ptr++; + size_t byte = (uint8_t)ptr[-1]; + *size += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; + } + ptr++; + size_t byte = (uint8_t)ptr[-1]; + // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected + // for a 32 bit varint. + if (UPB_UNLIKELY(byte >= 8)) return NULL; + *size += (byte - 1) << 28; + return ptr; +} -static void encode_scalar(upb_encstate* e, const void* _field_mem, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const char* field_mem = _field_mem; - int wire_type; +UPB_FORCEINLINE +static bool fastdecode_boundscheck(const char* ptr, size_t len, + const char* end) { + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end + 16; + uintptr_t res = uptr + len; + return res < uptr || res > uend; +} -#define CASE(ctype, type, wtype, encodeval) \ - { \ - ctype val = *(ctype*)field_mem; \ - encode_##type(e, encodeval); \ - wire_type = wtype; \ - break; \ - } +UPB_FORCEINLINE +static bool fastdecode_boundscheck2(const char* ptr, size_t len, + const char* end) { + // This is one extra branch compared to the more normal: + // return (size_t)(end - ptr) < size; + // However it is one less computation if we are just about to use "ptr + len": + // https://godbolt.org/z/35YGPz + // In microbenchmarks this shows an overall 4% improvement. + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end; + uintptr_t res = uptr + len; + return res < uptr || res > uend; +} - switch (f->descriptortype) { - case kUpb_FieldType_Double: - CASE(double, double, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Float: - CASE(float, float, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - CASE(uint64_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_UInt32: - CASE(uint32_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Bool: - CASE(bool, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_SInt32: - CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); - case kUpb_FieldType_SInt64: - CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - upb_StringView view = *(upb_StringView*)field_mem; - encode_bytes(e, view.data, view.size); - encode_varint(e, view.size); - wire_type = kUpb_WireType_Delimited; - break; - } - case kUpb_FieldType_Group: { - size_t size; - void* submsg = *(void**)field_mem; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (submsg == NULL) { - return; +typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, + void* ctx); + +UPB_FORCEINLINE +static const char* fastdecode_delimited(upb_Decoder* d, const char* ptr, + fastdecode_delimfunc* func, void* ctx) { + ptr++; + int len = (int8_t)ptr[-1]; + if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) { + // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. + // If it exceeds the buffer limit, limit/limit_ptr will change during + // sub-message parsing, so we need to preserve delta, not limit. + if (UPB_UNLIKELY(len & 0x80)) { + // Size varint >1 byte (length >= 128). + ptr = fastdecode_longsize(ptr, &len); + if (!ptr) { + // Corrupt wire format: size exceeded INT_MAX. + return NULL; } - if (--e->depth == 0) encode_err(e); - encode_tag(e, f->number, kUpb_WireType_EndGroup); - encode_message(e, submsg, subm, &size); - wire_type = kUpb_WireType_StartGroup; - e->depth++; - break; } - case kUpb_FieldType_Message: { - size_t size; - void* submsg = *(void**)field_mem; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (submsg == NULL) { - return; - } - if (--e->depth == 0) encode_err(e); - encode_message(e, submsg, subm, &size); - encode_varint(e, size); - wire_type = kUpb_WireType_Delimited; - e->depth++; - break; + if (ptr - d->end + (int)len > d->limit) { + // Corrupt wire format: invalid limit. + return NULL; } - default: - UPB_UNREACHABLE(); + int delta = decode_pushlimit(d, ptr, len); + ptr = func(d, ptr, ctx); + decode_poplimit(d, ptr, delta); + } else { + // Fast case: Sub-message is <128 bytes and fits in the current buffer. + // This means we can preserve limit/limit_ptr verbatim. + const char* saved_limit_ptr = d->limit_ptr; + int saved_limit = d->limit; + d->limit_ptr = ptr + len; + d->limit = d->limit_ptr - d->end; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); + ptr = func(d, ptr, ctx); + d->limit_ptr = saved_limit_ptr; + d->limit = saved_limit; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); } -#undef CASE - - encode_tag(e, f->number, wire_type); + return ptr; } -static void encode_array(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); - bool packed = f->mode & kUpb_LabelFlags_IsPacked; - size_t pre_len = e->limit - e->ptr; +/* singular, oneof, repeated field handling ***********************************/ - if (arr == NULL || arr->len == 0) { - return; - } +typedef struct { + upb_Array* arr; + void* end; +} fastdecode_arr; -#define VARINT_CASE(ctype, encode) \ - { \ - const ctype* start = _upb_array_constptr(arr); \ - const ctype* ptr = start + arr->len; \ - uint32_t tag = packed ? 0 : (f->number << 3) | kUpb_WireType_Varint; \ - do { \ - ptr--; \ - encode_varint(e, encode); \ - if (tag) encode_varint(e, tag); \ - } while (ptr != start); \ - } \ - break; +typedef enum { + FD_NEXT_ATLIMIT, + FD_NEXT_SAMEFIELD, + FD_NEXT_OTHERFIELD +} fastdecode_next; -#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) +typedef struct { + void* dst; + fastdecode_next next; + uint32_t tag; +} fastdecode_nextret; - switch (f->descriptortype) { - case kUpb_FieldType_Double: - encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Float: - encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - VARINT_CASE(uint64_t, *ptr); - case kUpb_FieldType_UInt32: - VARINT_CASE(uint32_t, *ptr); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - VARINT_CASE(int32_t, (int64_t)*ptr); - case kUpb_FieldType_Bool: - VARINT_CASE(bool, *ptr); - case kUpb_FieldType_SInt32: - VARINT_CASE(int32_t, encode_zz32(*ptr)); - case kUpb_FieldType_SInt64: - VARINT_CASE(int64_t, encode_zz64(*ptr)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - const upb_StringView* start = _upb_array_constptr(arr); - const upb_StringView* ptr = start + arr->len; - do { - ptr--; - encode_bytes(e, ptr->data, ptr->size); - encode_varint(e, ptr->size); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } while (ptr != start); - return; - } - case kUpb_FieldType_Group: { - const void* const* start = _upb_array_constptr(arr); - const void* const* ptr = start + arr->len; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); - do { - size_t size; - ptr--; - encode_tag(e, f->number, kUpb_WireType_EndGroup); - encode_message(e, *ptr, subm, &size); - encode_tag(e, f->number, kUpb_WireType_StartGroup); - } while (ptr != start); - e->depth++; - return; - } - case kUpb_FieldType_Message: { - const void* const* start = _upb_array_constptr(arr); - const void* const* ptr = start + arr->len; - const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); - do { - size_t size; - ptr--; - encode_message(e, *ptr, subm, &size); - encode_varint(e, size); - encode_tag(e, f->number, kUpb_WireType_Delimited); - } while (ptr != start); - e->depth++; - return; - } +UPB_FORCEINLINE +static void* fastdecode_resizearr(upb_Decoder* d, void* dst, + fastdecode_arr* farr, int valbytes) { + if (UPB_UNLIKELY(dst == farr->end)) { + size_t old_size = farr->arr->size; + size_t old_bytes = old_size * valbytes; + size_t new_size = old_size * 2; + size_t new_bytes = new_size * valbytes; + char* old_ptr = _upb_array_ptr(farr->arr); + char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes); + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + farr->arr->size = new_size; + farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2); + dst = (void*)(new_ptr + (old_size * valbytes)); + farr->end = (void*)(new_ptr + (new_size * valbytes)); } -#undef VARINT_CASE + return dst; +} - if (packed) { - encode_varint(e, e->limit - e->ptr - pre_len); - encode_tag(e, f->number, kUpb_WireType_Delimited); +UPB_FORCEINLINE +static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { + if (tagbytes == 1) { + return (uint8_t)tag == (uint8_t)data; + } else { + return (uint16_t)tag == (uint16_t)data; } } -static void encode_mapentry(upb_encstate* e, uint32_t number, - const upb_MiniTable* layout, - const upb_MapEntry* ent) { - const upb_MiniTable_Field* key_field = &layout->fields[0]; - const upb_MiniTable_Field* val_field = &layout->fields[1]; - size_t pre_len = e->limit - e->ptr; - size_t size; - encode_scalar(e, &ent->v, layout->subs, val_field); - encode_scalar(e, &ent->k, layout->subs, key_field); - size = (e->limit - e->ptr) - pre_len; - encode_varint(e, size); - encode_tag(e, number, kUpb_WireType_Delimited); +UPB_FORCEINLINE +static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, + int valbytes) { + farr->arr->len = + (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; } -static void encode_map(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - const upb_Map* map = *UPB_PTR_AT(msg, f->offset, const upb_Map*); - const upb_MiniTable* layout = subs[f->submsg_index].submsg; - UPB_ASSERT(layout->field_count == 2); - - if (map == NULL) return; +UPB_FORCEINLINE +static fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst, + const char** ptr, + fastdecode_arr* farr, + uint64_t data, int tagbytes, + int valbytes) { + fastdecode_nextret ret; + dst = (char*)dst + valbytes; - if (e->options & kUpb_Encode_Deterministic) { - _upb_sortedmap sorted; - _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, - &sorted); - upb_MapEntry ent; - while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { - encode_mapentry(e, f->number, layout, &ent); + if (UPB_LIKELY(!decode_isdone(d, ptr))) { + ret.tag = fastdecode_loadtag(*ptr); + if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { + ret.next = FD_NEXT_SAMEFIELD; + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_OTHERFIELD; } - _upb_mapsorter_popmap(&e->sorter, &sorted); } else { - upb_strtable_iter i; - upb_strtable_begin(&i, &map->table); - for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_StringView key = upb_strtable_iter_key(&i); - const upb_value val = upb_strtable_iter_value(&i); - upb_MapEntry ent; - _upb_map_fromkey(key, &ent.k, map->key_size); - _upb_map_fromvalue(val, &ent.v, map->val_size); - encode_mapentry(e, f->number, layout, &ent); - } + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_ATLIMIT; } + + ret.dst = dst; + return ret; } -static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { - if (f->presence == 0) { - /* Proto3 presence or map/array. */ - const void* mem = UPB_PTR_AT(msg, f->offset, void); - switch (f->mode >> kUpb_FieldRep_Shift) { - case kUpb_FieldRep_1Byte: { - char ch; - memcpy(&ch, mem, 1); - return ch != 0; - } -#if UINTPTR_MAX == 0xffffffff - case kUpb_FieldRep_Pointer: -#endif - case kUpb_FieldRep_4Byte: { - uint32_t u32; - memcpy(&u32, mem, 4); - return u32 != 0; - } -#if UINTPTR_MAX != 0xffffffff - case kUpb_FieldRep_Pointer: -#endif - case kUpb_FieldRep_8Byte: { - uint64_t u64; - memcpy(&u64, mem, 8); - return u64 != 0; - } - case kUpb_FieldRep_StringView: { - const upb_StringView* str = (const upb_StringView*)mem; - return str->size != 0; - } - default: - UPB_UNREACHABLE(); - } - } else if (f->presence > 0) { - /* Proto2 presence: hasbit. */ - return _upb_hasbit_field(msg, f); - } else { - /* Field is in a oneof. */ - return _upb_getoneofcase_field(msg, f) == f->number; - } +UPB_FORCEINLINE +static void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) { + size_t ofs = data >> 48; + return (char*)msg + ofs; } -static void encode_field(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - switch (upb_FieldMode_Get(field)) { - case kUpb_FieldMode_Array: - encode_array(e, msg, subs, field); - break; - case kUpb_FieldMode_Map: - encode_map(e, msg, subs, field); - break; - case kUpb_FieldMode_Scalar: - encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field); - break; +UPB_FORCEINLINE +static void* fastdecode_getfield(upb_Decoder* d, const char* ptr, + upb_Message* msg, uint64_t* data, + uint64_t* hasbits, fastdecode_arr* farr, + int valbytes, upb_card card) { + switch (card) { + case CARD_s: { + uint8_t hasbit_index = *data >> 24; + // Set hasbit and return pointer to scalar field. + *hasbits |= 1ull << hasbit_index; + return fastdecode_fieldmem(msg, *data); + } + case CARD_o: { + uint16_t case_ofs = *data >> 32; + uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); + uint8_t field_number = *data >> 24; + *oneof_case = field_number; + return fastdecode_fieldmem(msg, *data); + } + case CARD_r: { + // Get pointer to upb_Array and allocate/expand if necessary. + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + upb_Array** arr_p = fastdecode_fieldmem(msg, *data); + char* begin; + *(uint32_t*)msg |= *hasbits; + *hasbits = 0; + if (UPB_LIKELY(!*arr_p)) { + farr->arr = _upb_Array_New(&d->arena, 8, elem_size_lg2); + *arr_p = farr->arr; + } else { + farr->arr = *arr_p; + } + begin = _upb_array_ptr(farr->arr); + farr->end = begin + (farr->arr->size * valbytes); + *data = fastdecode_loadtag(ptr); + return begin + (farr->arr->len * valbytes); + } default: UPB_UNREACHABLE(); } } -/* message MessageSet { - * repeated group Item = 1 { - * required int32 type_id = 2; - * required string message = 3; - * } - * } */ -static void encode_msgset_item(upb_encstate* e, - const upb_Message_Extension* ext) { - size_t size; - encode_tag(e, 1, kUpb_WireType_EndGroup); - encode_message(e, ext->data.ptr, ext->ext->sub.submsg, &size); - encode_varint(e, size); - encode_tag(e, 3, kUpb_WireType_Delimited); - encode_varint(e, ext->ext->field.number); - encode_tag(e, 2, kUpb_WireType_Varint); - encode_tag(e, 1, kUpb_WireType_StartGroup); +UPB_FORCEINLINE +static bool fastdecode_flippacked(uint64_t* data, int tagbytes) { + *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. + return fastdecode_checktag(*data, tagbytes); } -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size) { - size_t pre_len = e->limit - e->ptr; - - if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) { - uint64_t msg_head; - memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); - if (upb_MiniTable_requiredmask(m) & ~msg_head) { - encode_err(e); - } +#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ + UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ + } \ + RETURN_GENERIC("packed check tag mismatch\n"); \ } - if ((e->options & kUpb_Encode_SkipUnknown) == 0) { - size_t unknown_size; - const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); +/* varint fields **************************************************************/ - if (unknown) { - encode_bytes(e, unknown, unknown_size); +UPB_FORCEINLINE +static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { + if (valbytes == 1) { + return val != 0; + } else if (zigzag) { + if (valbytes == 4) { + uint32_t n = val; + return (n >> 1) ^ -(int32_t)(n & 1); + } else if (valbytes == 8) { + return (val >> 1) ^ -(int64_t)(val & 1); } + UPB_UNREACHABLE(); } + return val; +} - if (m->ext != kUpb_ExtMode_NonExtendable) { - /* Encode all extensions together. Unlike C++, we do not attempt to keep - * these in field number order relative to normal fields or even to each - * other. */ - size_t ext_count; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count); - if (ext_count) { - const upb_Message_Extension* end = ext + ext_count; - for (; ext != end; ext++) { - if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) { - encode_msgset_item(e, ext); - } else { - encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); - } - } +UPB_FORCEINLINE +static const char* fastdecode_varint64(const char* ptr, uint64_t* val) { + ptr++; + *val = (uint8_t)ptr[-1]; + if (UPB_UNLIKELY(*val & 0x80)) { + int i; + for (i = 0; i < 8; i++) { + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + *val += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) goto done; } - } - - if (m->field_count) { - const upb_MiniTable_Field* f = &m->fields[m->field_count]; - const upb_MiniTable_Field* first = &m->fields[0]; - while (f != first) { - f--; - if (encode_shouldencode(e, msg, m->subs, f)) { - encode_field(e, msg, m->subs, f); - } + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + if (byte > 1) { + return NULL; } + *val += (byte - 1) << 63; } - - *size = (e->limit - e->ptr) - pre_len; +done: + UPB_ASSUME(ptr != NULL); + return ptr; } -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size) { - upb_encstate e; - unsigned depth = (unsigned)options >> 16; +#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed) \ + uint64_t val; \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_varint64(ptr, &val); \ + if (ptr == NULL) return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + val = fastdecode_munge(val, valbytes, zigzag); \ + memcpy(dst, &val, valbytes); \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - e.alloc = upb_Arena_Alloc(arena); - e.buf = NULL; - e.limit = NULL; - e.ptr = NULL; - e.depth = depth ? depth : 64; - e.options = options; - _upb_mapsorter_init(&e.sorter); - char* ret = NULL; +typedef struct { + uint8_t valbytes; + bool zigzag; + void* dst; + fastdecode_arr farr; +} fastdecode_varintdata; - if (UPB_SETJMP(e.err)) { - *size = 0; - ret = NULL; - } else { - encode_message(&e, msg, l, size); - *size = e.limit - e.ptr; - if (*size == 0) { - static char ch; - ret = &ch; - } else { - UPB_ASSERT(e.ptr); - ret = e.ptr; - } +UPB_FORCEINLINE +static const char* fastdecode_topackedvarint(upb_Decoder* d, const char* ptr, + void* ctx) { + fastdecode_varintdata* data = ctx; + void* dst = data->dst; + uint64_t val; + + while (!decode_isdone(d, &ptr)) { + dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); + ptr = fastdecode_varint64(ptr, &val); + if (ptr == NULL) return NULL; + val = fastdecode_munge(val, data->valbytes, data->zigzag); + memcpy(dst, &val, data->valbytes); + dst = (char*)dst + data->valbytes; } - _upb_mapsorter_destroy(&e.sorter); - return ret; + fastdecode_commitarr(dst, &data->farr, data->valbytes); + return ptr; } -/** upb/msg.c ************************************************************/ +#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked) \ + fastdecode_varintdata ctx = {valbytes, zigzag}; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ + \ + ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ + valbytes, CARD_r); \ + if (UPB_UNLIKELY(!ctx.dst)) { \ + RETURN_GENERIC("need array resize\n"); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ + \ + if (UPB_UNLIKELY(ptr == NULL)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); +#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, zigzag, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, zigzag, packed); \ + } -/** upb_Message - * *******************************************************************/ +#define z_ZZ true +#define b_ZZ false +#define v_ZZ false -static const size_t overhead = sizeof(upb_Message_InternalData); +/* Generate all combinations: + * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ -static const upb_Message_Internal* upb_Message_Getinternal_const( - const upb_Message* msg) { - ptrdiff_t size = sizeof(upb_Message_Internal); - return (upb_Message_Internal*)((char*)msg - size); -} +#define F(card, type, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, type##_ZZ, \ + upb_pr##type##valbytes##_##tagbytes##bt, \ + upb_pp##type##valbytes##_##tagbytes##bt); \ + } -upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a) { - return _upb_Message_New_inl(l, a); -} +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) -void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { - void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char); - memset(mem, 0, upb_msg_sizeof(l)); -} +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) -static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (!in->internal) { - /* No internal data, allocate from scratch. */ - size_t size = UPB_MAX(128, _upb_Log2CeilingSize(need + overhead)); - upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); - if (!internal) return false; - internal->size = size; - internal->unknown_end = overhead; - internal->ext_begin = size; - in->internal = internal; - } else if (in->internal->ext_begin - in->internal->unknown_end < need) { - /* Internal data is too small, reallocate. */ - size_t new_size = _upb_Log2CeilingSize(in->internal->size + need); - size_t ext_bytes = in->internal->size - in->internal->ext_begin; - size_t new_ext_begin = new_size - ext_bytes; - upb_Message_InternalData* internal = - upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size); - if (!internal) return false; - if (ext_bytes) { - /* Need to move extension data to the end. */ - char* ptr = (char*)internal; - memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes); - } - internal->ext_begin = new_ext_begin; - internal->size = new_size; - in->internal = internal; - } - UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); - return true; -} - -bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, - upb_Arena* arena) { - if (!realloc_internal(msg, len, arena)) return false; - upb_Message_Internal* in = upb_Message_Getinternal(msg); - memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len); - in->internal->unknown_end += len; - return true; -} +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) -void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (in->internal) { - in->internal->unknown_end = overhead; - } -} +#undef z_ZZ +#undef b_ZZ +#undef v_ZZ +#undef o_ONEOF +#undef s_ONEOF +#undef r_ONEOF +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDVARINT +#undef FASTDECODE_PACKEDVARINT +#undef FASTDECODE_VARINT -const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { - const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); - if (in->internal) { - *len = in->internal->unknown_end - overhead; - return (char*)(in->internal + 1); - } else { - *len = 0; - return NULL; - } -} +/* fixed fields ***************************************************************/ -const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, - size_t* count) { - const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); - if (in->internal) { - *count = (in->internal->size - in->internal->ext_begin) / - sizeof(upb_Message_Extension); - return UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - } else { - *count = 0; - return NULL; - } -} +#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed) \ + void* dst; \ + fastdecode_arr farr; \ + \ + FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ + card); \ + if (card == CARD_r) { \ + if (UPB_UNLIKELY(!dst)) { \ + RETURN_GENERIC("couldn't allocate array in arena\n"); \ + } \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ + } \ + \ + ptr += tagbytes; \ + memcpy(dst, ptr, valbytes); \ + ptr += valbytes; \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, valbytes); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); -const upb_Message_Extension* _upb_Message_Getext( - const upb_Message* msg, const upb_MiniTable_Extension* e) { - size_t n; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); +#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked) \ + FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ + \ + ptr += tagbytes; \ + int size = (uint8_t)ptr[0]; \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ + (size % valbytes) != 0)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + upb_Array** arr_p = fastdecode_fieldmem(msg, data); \ + upb_Array* arr = *arr_p; \ + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ + int elems = size / valbytes; \ + \ + if (UPB_LIKELY(!arr)) { \ + *arr_p = arr = _upb_Array_New(&d->arena, elems, elem_size_lg2); \ + if (!arr) { \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + } else { \ + _upb_Array_Resize(arr, elems, &d->arena); \ + } \ + \ + char* dst = _upb_array_ptr(arr); \ + memcpy(dst, ptr, size); \ + arr->len = elems; \ + \ + ptr += size; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - /* For now we use linear search exclusively to find extensions. If this - * becomes an issue due to messages with lots of extensions, we can introduce - * a table of some sort. */ - for (size_t i = 0; i < n; i++) { - if (ext[i].ext == e) { - return &ext[i]; - } +#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, unpacked, packed) \ + if (card == CARD_p) { \ + FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, unpacked); \ + } else { \ + FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ + valbytes, card, packed); \ } - return NULL; -} +/* Generate all combinations: + * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext_l) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (!in->internal) return; - const upb_Message_Extension* base = - UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - upb_Message_Extension* ext = - (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); - if (ext) { - *ext = *base; - in->internal->ext_begin += sizeof(upb_Message_Extension); +#define F(card, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ + CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ + upb_prf##valbytes##_##tagbytes##bt); \ } -} -upb_Message_Extension* _upb_Message_Getorcreateext( - upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) { - upb_Message_Extension* ext = - (upb_Message_Extension*)_upb_Message_Getext(msg, e); - if (ext) return ext; - if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL; - upb_Message_Internal* in = upb_Message_Getinternal(msg); - in->internal->ext_begin -= sizeof(upb_Message_Extension); - ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void); - memset(ext, 0, sizeof(upb_Message_Extension)); - ext->ext = e; - return ext; -} +#define TYPES(card, tagbytes) \ + F(card, 4, tagbytes) \ + F(card, 8, tagbytes) -size_t upb_Message_ExtensionCount(const upb_Message* msg) { - size_t count; - _upb_Message_Getexts(msg, &count); - return count; -} +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) -/** upb_Array *****************************************************************/ +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) -bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena) { - size_t new_size = UPB_MAX(arr->size, 4); - int elem_size_lg2 = arr->data & 7; - size_t old_bytes = arr->size << elem_size_lg2; - size_t new_bytes; - void* ptr = _upb_array_ptr(arr); +#undef F +#undef TYPES +#undef TAGBYTES +#undef FASTDECODE_UNPACKEDFIXED +#undef FASTDECODE_PACKEDFIXED - /* Log2 ceiling of size. */ - while (new_size < min_size) new_size *= 2; +/* string fields **************************************************************/ - new_bytes = new_size << elem_size_lg2; - ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); +typedef const char* fastdecode_copystr_func(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + const upb_MiniTable* table, + uint64_t hasbits, + upb_StringView* dst); - if (!ptr) { - return false; +UPB_NOINLINE +static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + if (!decode_verifyutf8_inl(dst->data, dst->size)) { + return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); } - - arr->data = _upb_tag_arrptr(ptr, elem_size_lg2); - arr->size = new_size; - return true; + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); } -static upb_Array* getorcreate_array(upb_Array** arr_ptr, int elem_size_lg2, - upb_Arena* arena) { - upb_Array* arr = *arr_ptr; - if (!arr) { - arr = _upb_Array_New(arena, 4, elem_size_lg2); - if (!arr) return NULL; - *arr_ptr = arr; +#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ + int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ + ptr++; \ + if (size & 0x80) { \ + ptr = fastdecode_longsize(ptr, &size); \ + } \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ + dst->size = 0; \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + if (d->options & kUpb_DecodeOption_AliasString) { \ + dst->data = ptr; \ + dst->size = size; \ + } else { \ + char* data = upb_Arena_Malloc(&d->arena, size); \ + if (!data) { \ + return fastdecode_err(d, kUpb_DecodeStatus_OutOfMemory); \ + } \ + memcpy(data, ptr, size); \ + dst->data = data; \ + dst->size = size; \ + } \ + \ + ptr += size; \ + if (validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } else { \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ } - return arr; -} -void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, - int elem_size_lg2, upb_Arena* arena) { - upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); - return arr && _upb_Array_Resize(arr, size, arena) ? _upb_array_ptr(arr) - : NULL; +UPB_NOINLINE +static const char* fastdecode_longstring_utf8(struct upb_Decoder* d, + const char* ptr, upb_Message* msg, + intptr_t table, uint64_t hasbits, + uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); } -bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, - int elem_size_lg2, upb_Arena* arena) { - upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); - if (!arr) return false; - - size_t elems = arr->len; - - if (!_upb_Array_Resize(arr, elems + 1, arena)) { - return false; - } - - char* data = _upb_array_ptr(arr); - memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2); - return true; +UPB_NOINLINE +static const char* fastdecode_longstring_noutf8( + struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + upb_StringView* dst = (upb_StringView*)data; + FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); } -/** upb_Map *******************************************************************/ - -upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { - upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); +UPB_FORCEINLINE +static void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size, + int copy, char* data, upb_StringView* dst) { + d->arena.head.ptr += copy; + dst->data = data; + UPB_UNPOISON_MEMORY_REGION(data, copy); + memcpy(data, ptr, copy); + UPB_POISON_MEMORY_REGION(data + size, copy - size); +} - if (!map) { - return NULL; +#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + card, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + size_t arena_has; \ + size_t common_has; \ + char* buf; \ + \ + UPB_ASSERT((d->options & kUpb_DecodeOption_AliasString) == 0); \ + UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (uint8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->size = size; \ + \ + buf = d->arena.head.ptr; \ + arena_has = _upb_ArenaHas(&d->arena); \ + common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ + \ + if (UPB_LIKELY(size <= 15 - tagbytes)) { \ + if (arena_has < 16) goto longstr; \ + d->arena.head.ptr += 16; \ + memcpy(buf, ptr - tagbytes - 1, 16); \ + dst->data = buf + tagbytes + 1; \ + } else if (UPB_LIKELY(size <= 32)) { \ + if (UPB_UNLIKELY(common_has < 32)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 32, buf, dst); \ + } else if (UPB_LIKELY(size <= 64)) { \ + if (UPB_UNLIKELY(common_has < 64)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 64, buf, dst); \ + } else if (UPB_LIKELY(size < 128)) { \ + if (UPB_UNLIKELY(common_has < 128)) goto longstr; \ + fastdecode_docopy(d, ptr, size, 128, buf, dst); \ + } else { \ + goto longstr; \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ + \ + longstr: \ + if (card == CARD_r) { \ + fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView)); \ + } \ + ptr--; \ + if (validate_utf8) { \ + UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ + } else { \ + UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ + hasbits, (uint64_t)dst); \ } - upb_strtable_init(&map->table, 4, a); - map->key_size = key_size; - map->val_size = value_size; +#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ + copyfunc, validate_utf8) \ + upb_StringView* dst; \ + fastdecode_arr farr; \ + int64_t size; \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("string field tag mismatch\n"); \ + } \ + \ + if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ + UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_StringView), card); \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ + } \ + \ + size = (int8_t)ptr[tagbytes]; \ + ptr += tagbytes + 1; \ + dst->data = ptr; \ + dst->size = size; \ + \ + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ + ptr--; \ + if (validate_utf8) { \ + return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } else { \ + return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ + (uint64_t)dst); \ + } \ + } \ + \ + ptr += size; \ + \ + if (card == CARD_r) { \ + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ + } \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ + /* Buffer flipped and we can't alias any more. Bounce to */ \ + /* copyfunc(), but via dispatch since we need to reload table */ \ + /* data also. */ \ + fastdecode_commitarr(dst, &farr, sizeof(upb_StringView)); \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + } \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + return ptr; \ + } \ + } \ + \ + if (card != CARD_r && validate_utf8) { \ + data = (uint64_t)dst; \ + UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ + } \ + \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - return map; -} +/* Generate all combinations: + * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ -static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, - void* b_key, size_t size) { - const upb_tabent* const* a = _a; - const upb_tabent* const* b = _b; - upb_StringView a_tabkey = upb_tabstrview((*a)->key); - upb_StringView b_tabkey = upb_tabstrview((*b)->key); - _upb_map_fromkey(a_tabkey, a_key, size); - _upb_map_fromkey(b_tabkey, b_key, size); -} +#define s_VALIDATE true +#define b_VALIDATE false -#define UPB_COMPARE_INTEGERS(a, b) ((a) < (b) ? -1 : ((a) == (b) ? 0 : 1)) +#define F(card, tagbytes, type) \ + UPB_NOINLINE \ + const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, type##_VALIDATE); \ + } \ + const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ + CARD_##card, upb_c##card##type##_##tagbytes##bt, \ + type##_VALIDATE); \ + } -static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { - int64_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); - return UPB_COMPARE_INTEGERS(a, b); -} +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) -static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { - uint64_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); - return UPB_COMPARE_INTEGERS(a, b); -} +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) -static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { - int32_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); - return UPB_COMPARE_INTEGERS(a, b); -} +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) -static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { - uint32_t a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); - return UPB_COMPARE_INTEGERS(a, b); -} +#undef s_VALIDATE +#undef b_VALIDATE +#undef F +#undef TAGBYTES +#undef FASTDECODE_LONGSTRING +#undef FASTDECODE_COPYSTRING +#undef FASTDECODE_STRING -static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { - bool a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); - return UPB_COMPARE_INTEGERS(a, b); -} +/* message fields *************************************************************/ -static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { - upb_StringView a, b; - _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); - size_t common_size = UPB_MIN(a.size, b.size); - int cmp = memcmp(a.data, b.data, common_size); - if (cmp) return -cmp; - return UPB_COMPARE_INTEGERS(a.size, b.size); +UPB_INLINE +upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* l, + int msg_ceil_bytes) { + size_t size = l->size + sizeof(upb_Message_Internal); + char* msg_data; + if (UPB_LIKELY(msg_ceil_bytes > 0 && + _upb_ArenaHas(&d->arena) >= msg_ceil_bytes)) { + UPB_ASSERT(size <= (size_t)msg_ceil_bytes); + msg_data = d->arena.head.ptr; + d->arena.head.ptr += size; + UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); + memset(msg_data, 0, msg_ceil_bytes); + UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); + } else { + msg_data = (char*)upb_Arena_Malloc(&d->arena, size); + memset(msg_data, 0, size); + } + return msg_data + sizeof(upb_Message_Internal); } -#undef UPB_COMPARE_INTEGERS - -bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, - const upb_Map* map, _upb_sortedmap* sorted) { - int map_size = _upb_Map_Size(map); - sorted->start = s->size; - sorted->pos = sorted->start; - sorted->end = sorted->start + map_size; +typedef struct { + intptr_t table; + upb_Message* msg; +} fastdecode_submsgdata; - /* Grow s->entries if necessary. */ - if (sorted->end > s->cap) { - s->cap = _upb_Log2CeilingSize(sorted->end); - s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); - if (!s->entries) return false; - } +UPB_FORCEINLINE +static const char* fastdecode_tosubmsg(upb_Decoder* d, const char* ptr, + void* ctx) { + fastdecode_submsgdata* submsg = ctx; + ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); + UPB_ASSUME(ptr != NULL); + return ptr; +} - s->size = sorted->end; +#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ + msg_ceil_bytes, card) \ + \ + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ + RETURN_GENERIC("submessage field tag mismatch\n"); \ + } \ + \ + if (--d->depth == 0) { \ + return fastdecode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); \ + } \ + \ + upb_Message** dst; \ + uint32_t submsg_idx = (data >> 16) & 0xff; \ + const upb_MiniTable* tablep = decode_totablep(table); \ + const upb_MiniTable* subtablep = tablep->subs[submsg_idx].submsg; \ + fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ + fastdecode_arr farr; \ + \ + if (subtablep->table_mask == (uint8_t)-1) { \ + RETURN_GENERIC("submessage doesn't have fast tables."); \ + } \ + \ + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ + sizeof(upb_Message*), card); \ + \ + if (card == CARD_s) { \ + *(uint32_t*)msg |= hasbits; \ + hasbits = 0; \ + } \ + \ + again: \ + if (card == CARD_r) { \ + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ + } \ + \ + submsg.msg = *dst; \ + \ + if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ + *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ + } \ + \ + ptr += tagbytes; \ + ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ + \ + if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ + return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ + } \ + \ + if (card == CARD_r) { \ + fastdecode_nextret ret = fastdecode_nextrepeated( \ + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ + switch (ret.next) { \ + case FD_NEXT_SAMEFIELD: \ + dst = ret.dst; \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + d->depth++; \ + data = ret.tag; \ + UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + d->depth++; \ + return ptr; \ + } \ + } \ + \ + d->depth++; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - /* Copy non-empty entries from the table to s->entries. */ - upb_tabent const** dst = &s->entries[sorted->start]; - const upb_tabent* src = map->table.t.entries; - const upb_tabent* end = src + upb_table_size(&map->table.t); - for (; src < end; src++) { - if (!upb_tabent_isempty(src)) { - *dst = src; - dst++; - } +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ + UPB_PARSE_PARAMS) { \ + FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ + CARD_##card); \ } - UPB_ASSERT(dst == &s->entries[sorted->end]); - - /* Sort entries according to the key type. */ - int (*compar)(const void*, const void*); +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) - switch (key_type) { - case kUpb_FieldType_Int64: - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_SInt64: - compar = _upb_mapsorter_cmpi64; - break; - case kUpb_FieldType_UInt64: - case kUpb_FieldType_Fixed64: - compar = _upb_mapsorter_cmpu64; - break; - case kUpb_FieldType_Int32: - case kUpb_FieldType_SInt32: - case kUpb_FieldType_SFixed32: - case kUpb_FieldType_Enum: - compar = _upb_mapsorter_cmpi32; - break; - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Fixed32: - compar = _upb_mapsorter_cmpu32; - break; - case kUpb_FieldType_Bool: - compar = _upb_mapsorter_cmpbool; - break; - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: - compar = _upb_mapsorter_cmpstr; - break; - default: - UPB_UNREACHABLE(); - } +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) - qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); - return true; -} +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) -/** upb_ExtensionRegistry - * ****************************************************************/ +#undef TAGBYTES +#undef SIZES +#undef F +#undef FASTDECODE_SUBMSG -struct upb_ExtensionRegistry { - upb_Arena* arena; - upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ -}; +#endif /* UPB_FASTTABLE */ -#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) - -static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { - memcpy(buf, &l, sizeof(l)); - memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); -} - -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { - upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); - if (!r) return NULL; - r->arena = arena; - if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; - return r; -} - -bool _upb_extreg_add(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, size_t count) { - char buf[EXTREG_KEY_SIZE]; - const upb_MiniTable_Extension** start = e; - const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); - for (; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, - upb_value_constptr(ext), r->arena)) { - goto failure; - } - } - return true; - -failure: - /* Back out the entries previously added. */ - for (end = e, e = start; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); - } - return false; -} - -const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, - const upb_MiniTable* l, - uint32_t num) { - char buf[EXTREG_KEY_SIZE]; - upb_value v; - extreg_key(buf, l, num); - if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { - return upb_value_getconstptr(v); - } else { - return NULL; - } -} - -/** upb/table.c ************************************************************/ -/* - * upb_table Implementation - * - * Implementation is heavily inspired by Lua's ltable.c. - */ +/** upb/json_decode.c ************************************************************/ +#include +#include +#include +#include +#include +#include +#include #include -/* Must be last. */ - -#define UPB_MAXARRSIZE 16 /* 64k. */ - -/* From Chromium. */ -#define ARRAY_SIZE(x) \ - ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) +/* Special header, must be included last. */ -static const double MAX_LOAD = 0.85; +typedef struct { + const char *ptr, *end; + upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ + const upb_DefPool* symtab; + int depth; + upb_Status* status; + jmp_buf err; + int line; + const char* line_begin; + bool is_first; + int options; + const upb_FieldDef* debug_field; +} jsondec; -/* The minimum utilization of the array part of a mixed hash/array table. This - * is a speed/memory-usage tradeoff (though it's not straightforward because of - * cache effects). The lower this is, the more memory we'll use. */ -static const double MIN_DENSITY = 0.1; +enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; -static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } +/* Forward declarations of mutually-recursive functions. */ +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); -static upb_value _upb_value_val(uint64_t val) { - upb_value ret; - _upb_value_setval(&ret, val); - return ret; +static bool jsondec_streql(upb_StringView str, const char* lit) { + return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; } -static int log2ceil(uint64_t v) { - int ret = 0; - bool pow2 = is_pow2(v); - while (v >>= 1) ret++; - ret = pow2 ? ret : ret + 1; /* Ceiling. */ - return UPB_MIN(UPB_MAXARRSIZE, ret); +static bool jsondec_isnullvalue(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum && + strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), + "google.protobuf.NullValue") == 0; } -char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { - size_t n; - char* p; - - /* Prevent overflow errors. */ - if (len == SIZE_MAX) return NULL; - /* Always null-terminate, even if binary data; but don't rely on the input to - * have a null-terminating byte since it may be a raw binary buffer. */ - n = len + 1; - p = upb_Arena_Malloc(a, n); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; +static bool jsondec_isvalue(const upb_FieldDef* f) { + return (upb_FieldDef_CType(f) == kUpb_CType_Message && + upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == + kUpb_WellKnown_Value) || + jsondec_isnullvalue(f); } -/* A type to represent the lookup key of either a strtable or an inttable. */ -typedef union { - uintptr_t num; - struct { - const char* str; - size_t len; - } str; -} lookupkey_t; - -static lookupkey_t strkey2(const char* str, size_t len) { - lookupkey_t k; - k.str.str = str; - k.str.len = len; - return k; +UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, + (int)(d->ptr - d->line_begin), msg); + UPB_LONGJMP(d->err, 1); } -static lookupkey_t intkey(uintptr_t key) { - lookupkey_t k; - k.num = key; - return k; +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, + (int)(d->ptr - d->line_begin)); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); } -typedef uint32_t hashfunc_t(upb_tabkey key); -typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); - -/* Base table (shared code) ***************************************************/ - -static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } - -static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { - return t->entries + (hash & t->mask); +static void jsondec_skipws(jsondec* d) { + while (d->ptr != d->end) { + switch (*d->ptr) { + case '\n': + d->line++; + d->line_begin = d->ptr; + /* Fallthrough. */ + case '\r': + case '\t': + case ' ': + d->ptr++; + break; + default: + return; + } + } + jsondec_err(d, "Unexpected EOF"); } -static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } - -static bool isfull(upb_table* t) { return t->count == t->max_count; } - -static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { - size_t bytes; - - t->count = 0; - t->size_lg2 = size_lg2; - t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; - t->max_count = upb_table_size(t) * MAX_LOAD; - bytes = upb_table_size(t) * sizeof(upb_tabent); - if (bytes > 0) { - t->entries = upb_Arena_Malloc(a, bytes); - if (!t->entries) return false; - memset(t->entries, 0, bytes); - } else { - t->entries = NULL; - } +static bool jsondec_tryparsech(jsondec* d, char ch) { + if (d->ptr == d->end || *d->ptr != ch) return false; + d->ptr++; return true; } -static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { - upb_tabent* begin = t->entries; - upb_tabent* end = begin + upb_table_size(t); - for (e = e + 1; e < end; e++) { - if (upb_tabent_isempty(e)) return e; - } - for (e = begin; e < end; e++) { - if (upb_tabent_isempty(e)) return e; +static void jsondec_parselit(jsondec* d, const char* lit) { + size_t avail = d->end - d->ptr; + size_t len = strlen(lit); + if (avail < len || memcmp(d->ptr, lit, len) != 0) { + jsondec_errf(d, "Expected: '%s'", lit); } - UPB_ASSERT(false); - return NULL; + d->ptr += len; } -static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { - return (upb_tabent*)upb_getentry(t, hash); +static void jsondec_wsch(jsondec* d, char ch) { + jsondec_skipws(d); + if (!jsondec_tryparsech(d, ch)) { + jsondec_errf(d, "Expected: '%c'", ch); + } } -static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e; +static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } +static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } +static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } - if (t->size_lg2 == 0) return NULL; - e = upb_getentry(t, hash); - if (upb_tabent_isempty(e)) return NULL; - while (1) { - if (eql(e->key, key)) return e; - if ((e = e->next) == NULL) return NULL; - } +static void jsondec_entrysep(jsondec* d) { + jsondec_skipws(d); + jsondec_parselit(d, ":"); } -static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - return (upb_tabent*)findentry(t, key, hash, eql); -} - -static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e = findentry(t, key, hash, eql); - if (e) { - if (v) { - _upb_value_setval(v, e->val.val); - } - return true; - } else { - return false; +static int jsondec_rawpeek(jsondec* d) { + switch (*d->ptr) { + case '{': + return JD_OBJECT; + case '[': + return JD_ARRAY; + case '"': + return JD_STRING; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return JD_NUMBER; + case 't': + return JD_TRUE; + case 'f': + return JD_FALSE; + case 'n': + return JD_NULL; + default: + jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); } } -/* The given key must not already exist in the table. */ -static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey, - upb_value val, uint32_t hash, hashfunc_t* hashfunc, - eqlfunc_t* eql) { - upb_tabent* mainpos_e; - upb_tabent* our_e; - - UPB_ASSERT(findentry(t, key, hash, eql) == NULL); +/* JSON object/array **********************************************************/ - t->count++; - mainpos_e = getentry_mutable(t, hash); - our_e = mainpos_e; +/* These are used like so: + * + * jsondec_objstart(d); + * while (jsondec_objnext(d)) { + * ... + * } + * jsondec_objend(d) */ - if (upb_tabent_isempty(mainpos_e)) { - /* Our main position is empty; use it. */ - our_e->next = NULL; - } else { - /* Collision. */ - upb_tabent* new_e = emptyent(t, mainpos_e); - /* Head of collider's chain. */ - upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key)); - if (chain == mainpos_e) { - /* Existing ent is in its main position (it has the same hash as us, and - * is the head of our chain). Insert to new ent and append to this chain. - */ - new_e->next = mainpos_e->next; - mainpos_e->next = new_e; - our_e = new_e; - } else { - /* Existing ent is not in its main position (it is a node in some other - * chain). This implies that no existing ent in the table has our hash. - * Evict it (updating its chain) and use its ent for head of our chain. */ - *new_e = *mainpos_e; /* copies next. */ - while (chain->next != mainpos_e) { - chain = (upb_tabent*)chain->next; - UPB_ASSERT(chain); - } - chain->next = new_e; - our_e = mainpos_e; - our_e->next = NULL; - } - } - our_e->key = tabkey; - our_e->val.val = val.val; - UPB_ASSERT(findentry(t, key, hash, eql) == our_e); +static int jsondec_peek(jsondec* d) { + jsondec_skipws(d); + return jsondec_rawpeek(d); } -static bool rm(upb_table* t, lookupkey_t key, upb_value* val, - upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) { - upb_tabent* chain = getentry_mutable(t, hash); - if (upb_tabent_isempty(chain)) return false; - if (eql(chain->key, key)) { - /* Element to remove is at the head of its chain. */ - t->count--; - if (val) _upb_value_setval(val, chain->val.val); - if (removed) *removed = chain->key; - if (chain->next) { - upb_tabent* move = (upb_tabent*)chain->next; - *chain = *move; - move->key = 0; /* Make the slot empty. */ - } else { - chain->key = 0; /* Make the slot empty. */ - } - return true; - } else { - /* Element to remove is either in a non-head position or not in the - * table. */ - while (chain->next && !eql(chain->next->key, key)) { - chain = (upb_tabent*)chain->next; - } - if (chain->next) { - /* Found element to remove. */ - upb_tabent* rm = (upb_tabent*)chain->next; - t->count--; - if (val) _upb_value_setval(val, chain->next->val.val); - if (removed) *removed = rm->key; - rm->key = 0; /* Make the slot empty. */ - chain->next = rm->next; - return true; - } else { - /* Element to remove is not in the table. */ - return false; - } +static void jsondec_push(jsondec* d) { + if (--d->depth < 0) { + jsondec_err(d, "Recursion limit exceeded"); } + d->is_first = true; } -static size_t next(const upb_table* t, size_t i) { - do { - if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ - } while (upb_tabent_isempty(&t->entries[i])); - - return i; +static bool jsondec_seqnext(jsondec* d, char end_ch) { + bool is_first = d->is_first; + d->is_first = false; + jsondec_skipws(d); + if (*d->ptr == end_ch) return false; + if (!is_first) jsondec_parselit(d, ","); + return true; } -static size_t begin(const upb_table* t) { return next(t, -1); } +static void jsondec_arrstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '['); +} -/* upb_strtable ***************************************************************/ +static void jsondec_arrend(jsondec* d) { + d->depth++; + jsondec_wsch(d, ']'); +} -/* A simple "subclass" of upb_table that only adds a hash function for strings. - */ +static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } -static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) { - uint32_t len = (uint32_t)k2.str.len; - char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1); - if (str == NULL) return 0; - memcpy(str, &len, sizeof(uint32_t)); - if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); - str[sizeof(uint32_t) + k2.str.len] = '\0'; - return (uintptr_t)str; +static void jsondec_objstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '{'); } -/* Adapted from ABSL's wyhash. */ - -static uint64_t UnalignedLoad64(const void* p) { - uint64_t val; - memcpy(&val, p, 8); - return val; +static void jsondec_objend(jsondec* d) { + d->depth++; + jsondec_wsch(d, '}'); } -static uint32_t UnalignedLoad32(const void* p) { - uint32_t val; - memcpy(&val, p, 4); - return val; +static bool jsondec_objnext(jsondec* d) { + if (!jsondec_seqnext(d, '}')) return false; + if (jsondec_peek(d) != JD_STRING) { + jsondec_err(d, "Object must start with string"); + } + return true; } -#if defined(_MSC_VER) && defined(_M_X64) -#include -#endif +/* JSON number ****************************************************************/ -/* Computes a * b, returning the low 64 bits of the result and storing the high - * 64 bits in |*high|. */ -static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { -#ifdef __SIZEOF_INT128__ - __uint128_t p = v0; - p *= v1; - *out_high = (uint64_t)(p >> 64); - return (uint64_t)p; -#elif defined(_MSC_VER) && defined(_M_X64) - return _umul128(v0, v1, out_high); -#else - uint64_t a32 = v0 >> 32; - uint64_t a00 = v0 & 0xffffffff; - uint64_t b32 = v1 >> 32; - uint64_t b00 = v1 & 0xffffffff; - uint64_t high = a32 * b32; - uint64_t low = a00 * b00; - uint64_t mid1 = a32 * b00; - uint64_t mid2 = a00 * b32; - low += (mid1 << 32) + (mid2 << 32); - // Omit carry bit, for mixing we do not care about exact numerical precision. - high += (mid1 >> 32) + (mid2 >> 32); - *out_high = high; - return low; -#endif +static bool jsondec_tryskipdigits(jsondec* d) { + const char* start = d->ptr; + + while (d->ptr < d->end) { + if (*d->ptr < '0' || *d->ptr > '9') { + break; + } + d->ptr++; + } + + return d->ptr != start; } -static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { - uint64_t high; - uint64_t low = upb_umul128(v0, v1, &high); - return low ^ high; +static void jsondec_skipdigits(jsondec* d) { + if (!jsondec_tryskipdigits(d)) { + jsondec_err(d, "Expected one or more digits"); + } } -static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, - const uint64_t salt[]) { - const uint8_t* ptr = (const uint8_t*)data; - uint64_t starting_length = (uint64_t)len; - uint64_t current_state = seed ^ salt[0]; +static double jsondec_number(jsondec* d) { + const char* start = d->ptr; - if (len > 64) { - // If we have more than 64 bytes, we're going to handle chunks of 64 - // bytes at a time. We're going to build up two separate hash states - // which we will then hash together. - uint64_t duplicated_state = current_state; + assert(jsondec_rawpeek(d) == JD_NUMBER); - do { - uint64_t a = UnalignedLoad64(ptr); - uint64_t b = UnalignedLoad64(ptr + 8); - uint64_t c = UnalignedLoad64(ptr + 16); - uint64_t d = UnalignedLoad64(ptr + 24); - uint64_t e = UnalignedLoad64(ptr + 32); - uint64_t f = UnalignedLoad64(ptr + 40); - uint64_t g = UnalignedLoad64(ptr + 48); - uint64_t h = UnalignedLoad64(ptr + 56); - - uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); - current_state = (cs0 ^ cs1); + /* Skip over the syntax of a number, as specified by JSON. */ + if (*d->ptr == '-') d->ptr++; - uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); - uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); - duplicated_state = (ds0 ^ ds1); + if (jsondec_tryparsech(d, '0')) { + if (jsondec_tryskipdigits(d)) { + jsondec_err(d, "number cannot have leading zero"); + } + } else { + jsondec_skipdigits(d); + } - ptr += 64; - len -= 64; - } while (len > 64); + if (d->ptr == d->end) goto parse; + if (jsondec_tryparsech(d, '.')) { + jsondec_skipdigits(d); + } + if (d->ptr == d->end) goto parse; - current_state = current_state ^ duplicated_state; + if (*d->ptr == 'e' || *d->ptr == 'E') { + d->ptr++; + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF in number"); + } + if (*d->ptr == '+' || *d->ptr == '-') { + d->ptr++; + } + jsondec_skipdigits(d); } - // We now have a data `ptr` with at most 64 bytes and the current state - // of the hashing state machine stored in current_state. - while (len > 16) { - uint64_t a = UnalignedLoad64(ptr); - uint64_t b = UnalignedLoad64(ptr + 8); +parse: + /* Having verified the syntax of a JSON number, use strtod() to parse + * (strtod() accepts a superset of JSON syntax). */ + errno = 0; + { + char* end; + double val = strtod(start, &end); + assert(end == d->ptr); - current_state = WyhashMix(a ^ salt[1], b ^ current_state); + /* Currently the min/max-val conformance tests fail if we check this. Does + * this mean the conformance tests are wrong or strtod() is wrong, or + * something else? Investigate further. */ + /* + if (errno == ERANGE) { + jsondec_err(d, "Number out of range"); + } + */ - ptr += 16; - len -= 16; - } + if (val > DBL_MAX || val < -DBL_MAX) { + jsondec_err(d, "Number out of range"); + } - // We now have a data `ptr` with at most 16 bytes. - uint64_t a = 0; - uint64_t b = 0; - if (len > 8) { - // When we have at least 9 and at most 16 bytes, set A to the first 64 - // bits of the input and B to the last 64 bits of the input. Yes, they will - // overlap in the middle if we are working with less than the full 16 - // bytes. - a = UnalignedLoad64(ptr); - b = UnalignedLoad64(ptr + len - 8); - } else if (len > 3) { - // If we have at least 4 and at most 8 bytes, set A to the first 32 - // bits and B to the last 32 bits. - a = UnalignedLoad32(ptr); - b = UnalignedLoad32(ptr + len - 4); - } else if (len > 0) { - // If we have at least 1 and at most 3 bytes, read all of the provided - // bits into A, with some adjustments. - a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); - b = 0; - } else { - a = 0; - b = 0; + return val; } - - uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t z = salt[1] ^ starting_length; - return WyhashMix(w, z); } -const uint64_t kWyhashSalt[5] = { - 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, - 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, -}; - -uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { - return Wyhash(p, n, seed, kWyhashSalt); -} +/* JSON string ****************************************************************/ -static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { - return _upb_Hash(p, n, 0); +static char jsondec_escape(jsondec* d) { + switch (*d->ptr++) { + case '"': + return '\"'; + case '\\': + return '\\'; + case '/': + return '/'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + default: + jsondec_err(d, "Invalid escape char"); + } } -static uint32_t strhash(upb_tabkey key) { - uint32_t len; - char* str = upb_tabstr(key, &len); - return _upb_Hash_NoSeed(str, len); -} +static uint32_t jsondec_codepoint(jsondec* d) { + uint32_t cp = 0; + const char* end; -static bool streql(upb_tabkey k1, lookupkey_t k2) { - uint32_t len; - char* str = upb_tabstr(k1, &len); - return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); -} + if (d->end - d->ptr < 4) { + jsondec_err(d, "EOF inside string"); + } -bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { - // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 - // denominator. - size_t need_entries = (expected_size + 1) * 1204 / 1024; - UPB_ASSERT(need_entries >= expected_size * 0.85); - int size_lg2 = _upb_Log2Ceiling(need_entries); - return init(&t->t, size_lg2, a); -} + end = d->ptr + 4; + while (d->ptr < end) { + char ch = *d->ptr++; + if (ch >= '0' && ch <= '9') { + ch -= '0'; + } else if (ch >= 'a' && ch <= 'f') { + ch = ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + ch = ch - 'A' + 10; + } else { + jsondec_err(d, "Invalid hex digit"); + } + cp = (cp << 4) | ch; + } -void upb_strtable_clear(upb_strtable* t) { - size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); - t->t.count = 0; - memset((char*)t->t.entries, 0, bytes); + return cp; } -bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { - upb_strtable new_table; - upb_strtable_iter i; +/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ +static size_t jsondec_unicode(jsondec* d, char* out) { + uint32_t cp = jsondec_codepoint(d); + if (cp >= 0xd800 && cp <= 0xdbff) { + /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ + uint32_t high = cp; + uint32_t low; + jsondec_parselit(d, "\\u"); + low = jsondec_codepoint(d); + if (low < 0xdc00 || low > 0xdfff) { + jsondec_err(d, "Invalid low surrogate"); + } + cp = (high & 0x3ff) << 10; + cp |= (low & 0x3ff); + cp += 0x10000; + } else if (cp >= 0xdc00 && cp <= 0xdfff) { + jsondec_err(d, "Unpaired low surrogate"); + } - if (!init(&new_table.t, size_lg2, a)) return false; - upb_strtable_begin(&i, t); - for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_StringView key = upb_strtable_iter_key(&i); - upb_strtable_insert(&new_table, key.data, key.size, - upb_strtable_iter_value(&i), a); + /* Write to UTF-8 */ + if (cp <= 0x7f) { + out[0] = cp; + return 1; + } else if (cp <= 0x07FF) { + out[0] = ((cp >> 6) & 0x1F) | 0xC0; + out[1] = ((cp >> 0) & 0x3F) | 0x80; + return 2; + } else if (cp <= 0xFFFF) { + out[0] = ((cp >> 12) & 0x0F) | 0xE0; + out[1] = ((cp >> 6) & 0x3F) | 0x80; + out[2] = ((cp >> 0) & 0x3F) | 0x80; + return 3; + } else if (cp < 0x10FFFF) { + out[0] = ((cp >> 18) & 0x07) | 0xF0; + out[1] = ((cp >> 12) & 0x3f) | 0x80; + out[2] = ((cp >> 6) & 0x3f) | 0x80; + out[3] = ((cp >> 0) & 0x3f) | 0x80; + return 4; + } else { + jsondec_err(d, "Invalid codepoint"); } - *t = new_table; - return true; } -bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, - upb_value v, upb_Arena* a) { - lookupkey_t key; - upb_tabkey tabkey; - uint32_t hash; - - if (isfull(&t->t)) { - /* Need to resize. New table of double the size, add old elements to it. */ - if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { - return false; - } - } +static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { + size_t oldsize = *buf_end - *buf; + size_t len = *end - *buf; + size_t size = UPB_MAX(8, 2 * oldsize); - key = strkey2(k, len); - tabkey = strcopy(key, a); - if (tabkey == 0) return false; + *buf = upb_Arena_Realloc(d->arena, *buf, len, size); + if (!*buf) jsondec_err(d, "Out of memory"); - hash = _upb_Hash_NoSeed(key.str.str, key.str.len); - insert(&t->t, key, tabkey, v, hash, &strhash, &streql); - return true; + *end = *buf + len; + *buf_end = *buf + size; } -bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, - upb_value* v) { - uint32_t hash = _upb_Hash_NoSeed(key, len); - return lookup(&t->t, strkey2(key, len), v, hash, &streql); -} +static upb_StringView jsondec_string(jsondec* d) { + char* buf = NULL; + char* end = NULL; + char* buf_end = NULL; -bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, - upb_value* val) { - uint32_t hash = _upb_Hash_NoSeed(key, len); - upb_tabkey tabkey; - return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); -} - -/* Iteration */ - -void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { - i->t = t; - i->index = begin(&t->t); -} + jsondec_skipws(d); -void upb_strtable_next(upb_strtable_iter* i) { - i->index = next(&i->t->t, i->index); -} + if (*d->ptr++ != '"') { + jsondec_err(d, "Expected string"); + } -bool upb_strtable_done(const upb_strtable_iter* i) { - if (!i->t) return true; - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(str_tabent(i)); -} + while (d->ptr < d->end) { + char ch = *d->ptr++; -upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { - upb_StringView key; - uint32_t len; - UPB_ASSERT(!upb_strtable_done(i)); - key.data = upb_tabstr(str_tabent(i)->key, &len); - key.size = len; - return key; -} + if (end == buf_end) { + jsondec_resize(d, &buf, &end, &buf_end); + } -upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { - UPB_ASSERT(!upb_strtable_done(i)); - return _upb_value_val(str_tabent(i)->val.val); -} + switch (ch) { + case '"': { + upb_StringView ret; + ret.data = buf; + ret.size = end - buf; + *end = '\0'; /* Needed for possible strtod(). */ + return ret; + } + case '\\': + if (d->ptr == d->end) goto eof; + if (*d->ptr == 'u') { + d->ptr++; + if (buf_end - end < 4) { + /* Allow space for maximum-sized code point (4 bytes). */ + jsondec_resize(d, &buf, &end, &buf_end); + } + end += jsondec_unicode(d, end); + } else { + *end++ = jsondec_escape(d); + } + break; + default: + if ((unsigned char)*d->ptr < 0x20) { + jsondec_err(d, "Invalid char in JSON string"); + } + *end++ = ch; + break; + } + } -void upb_strtable_iter_setdone(upb_strtable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; +eof: + jsondec_err(d, "EOF inside string"); } -bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, - const upb_strtable_iter* i2) { - if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; - return i1->t == i2->t && i1->index == i2->index; +static void jsondec_skipval(jsondec* d) { + switch (jsondec_peek(d)) { + case JD_OBJECT: + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_string(d); + jsondec_entrysep(d); + jsondec_skipval(d); + } + jsondec_objend(d); + break; + case JD_ARRAY: + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + jsondec_skipval(d); + } + jsondec_arrend(d); + break; + case JD_TRUE: + jsondec_true(d); + break; + case JD_FALSE: + jsondec_false(d); + break; + case JD_NULL: + jsondec_null(d); + break; + case JD_STRING: + jsondec_string(d); + break; + case JD_NUMBER: + jsondec_number(d); + break; + } } -/* upb_inttable ***************************************************************/ +/* Base64 decoding for bytes fields. ******************************************/ -/* For inttables we use a hybrid structure where small keys are kept in an - * array and large keys are put in the hash table. */ +static unsigned int jsondec_base64_tablelookup(const char ch) { + /* Table includes the normal base64 chars plus the URL-safe variant. */ + const signed char table[256] = { + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, + 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, + 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, + -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, + 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, + 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, + 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, + -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, + 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, + 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, + 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, + 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; -static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } + /* Sign-extend return value so high bit will be set on any unexpected char. */ + return table[(unsigned)ch]; +} -static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } +static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, + char* out) { + int32_t val = -1; -static upb_tabval* mutable_array(upb_inttable* t) { - return (upb_tabval*)t->array; -} + switch (end - ptr) { + case 2: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12; + out[0] = val >> 16; + out += 1; + break; + case 3: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6; + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out += 2; + break; + } -static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) { - if (key < t->array_size) { - return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; - } else { - upb_tabent* e = - findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); - return e ? &e->val : NULL; + if (val < 0) { + jsondec_err(d, "Corrupt base64"); } -} -static const upb_tabval* inttable_val_const(const upb_inttable* t, - uintptr_t key) { - return inttable_val((upb_inttable*)t, key); + return out; } -size_t upb_inttable_count(const upb_inttable* t) { - return t->t.count + t->array_count; -} +static size_t jsondec_base64(jsondec* d, upb_StringView str) { + /* We decode in place. This is safe because this is a new buffer (not + * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ + char* out = (char*)str.data; + const char* ptr = str.data; + const char* end = ptr + str.size; + const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ -static void check(upb_inttable* t) { - UPB_UNUSED(t); -#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) - { - /* This check is very expensive (makes inserts/deletes O(N)). */ - size_t count = 0; - upb_inttable_iter i; - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { - UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); + for (; ptr < end4; ptr += 4, out += 3) { + int val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6 | + jsondec_base64_tablelookup(ptr[3]) << 0; + + if (val < 0) { + /* Junk chars or padding. Remove trailing padding, if any. */ + if (end - ptr == 4 && ptr[3] == '=') { + if (ptr[2] == '=') { + end -= 2; + } else { + end -= 1; + } + } + break; } - UPB_ASSERT(count == upb_inttable_count(t)); + + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; } -#endif + + if (ptr < end) { + /* Process remaining chars. We do not require padding. */ + out = jsondec_partialbase64(d, ptr, end, out); + } + + return out - str.data; } -bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, - upb_Arena* a) { - size_t array_bytes; +/* Low-level integer parsing **************************************************/ - if (!init(&t->t, hsize_lg2, a)) return false; - /* Always make the array part at least 1 long, so that we know key 0 - * won't be in the hash part, which simplifies things. */ - t->array_size = UPB_MAX(1, asize); - t->array_count = 0; - array_bytes = t->array_size * sizeof(upb_value); - t->array = upb_Arena_Malloc(a, array_bytes); - if (!t->array) { - return false; +/* We use these hand-written routines instead of strto[u]l() because the "long + * long" variants aren't in c89. Also our version allows setting a ptr limit. */ + +static const char* jsondec_buftouint64(jsondec* d, const char* ptr, + const char* end, uint64_t* val) { + uint64_t u64 = 0; + while (ptr < end) { + unsigned ch = *ptr - '0'; + if (ch >= 10) break; + if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { + jsondec_err(d, "Integer overflow"); + } + u64 *= 10; + u64 += ch; + ptr++; } - memset(mutable_array(t), 0xff, array_bytes); - check(t); - return true; -} -bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { - return upb_inttable_sizedinit(t, 0, 4, a); + *val = u64; + return ptr; } -bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, - upb_Arena* a) { - upb_tabval tabval; - tabval.val = val.val; - UPB_ASSERT( - upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ - - if (key < t->array_size) { - UPB_ASSERT(!upb_arrhas(t->array[key])); - t->array_count++; - mutable_array(t)[key].val = val.val; - } else { - if (isfull(&t->t)) { - /* Need to resize the hash part, but we re-use the array part. */ - size_t i; - upb_table new_table; - - if (!init(&new_table, t->t.size_lg2 + 1, a)) { - return false; - } - - for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { - const upb_tabent* e = &t->t.entries[i]; - uint32_t hash; - upb_value v; - - _upb_value_setval(&v, e->val.val); - hash = upb_inthash(e->key); - insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); - } +static const char* jsondec_buftoint64(jsondec* d, const char* ptr, + const char* end, int64_t* val) { + bool neg = false; + uint64_t u64; - UPB_ASSERT(t->t.count == new_table.count); + if (ptr != end && *ptr == '-') { + ptr++; + neg = true; + } - t->t = new_table; - } - insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); + ptr = jsondec_buftouint64(d, ptr, end, &u64); + if (u64 > (uint64_t)INT64_MAX + neg) { + jsondec_err(d, "Integer overflow"); } - check(t); - return true; -} -bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { - const upb_tabval* table_v = inttable_val_const(t, key); - if (!table_v) return false; - if (v) _upb_value_setval(v, table_v->val); - return true; + *val = neg ? -u64 : u64; + return ptr; } -bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { - upb_tabval* table_v = inttable_val(t, key); - if (!table_v) return false; - table_v->val = val.val; - return true; +static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + uint64_t ret; + if (jsondec_buftouint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; } -bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { - bool success; - if (key < t->array_size) { - if (upb_arrhas(t->array[key])) { - upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; - t->array_count--; - if (val) { - _upb_value_setval(val, t->array[key].val); - } - mutable_array(t)[key] = empty; - success = true; - } else { - success = false; - } - } else { - success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); +static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + int64_t ret; + if (jsondec_buftoint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); } - check(t); - return success; + return ret; } -void upb_inttable_compact(upb_inttable* t, upb_Arena* a) { - /* A power-of-two histogram of the table keys. */ - size_t counts[UPB_MAXARRSIZE + 1] = {0}; - - /* The max key in each bucket. */ - uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; - - upb_inttable_iter i; - size_t arr_count; - int size_lg2; - upb_inttable new_t; - - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t key = upb_inttable_iter_key(&i); - int bucket = log2ceil(key); - max[bucket] = UPB_MAX(max[bucket], key); - counts[bucket]++; - } +/* Primitive value types ******************************************************/ - /* Find the largest power of two that satisfies the MIN_DENSITY - * definition (while actually having some keys). */ - arr_count = upb_inttable_count(t); +/* Parse INT32 or INT64 value. */ +static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; - for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { - if (counts[size_lg2] == 0) { - /* We can halve again without losing any entries. */ - continue; - } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { + jsondec_err(d, "JSON number is out of range."); + } + val.int64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.int64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, + val.int64_val); + } break; } - - arr_count -= counts[size_lg2]; + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.int64_val = jsondec_strtoint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); } - UPB_ASSERT(arr_count <= upb_inttable_count(t)); - - { - /* Insert all elements into new, perfectly-sized table. */ - size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ - size_t hash_count = upb_inttable_count(t) - arr_count; - size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; - int hashsize_lg2 = log2ceil(hash_size); - - upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t k = upb_inttable_iter_key(&i); - upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); + if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || + upb_FieldDef_CType(f) == kUpb_CType_Enum) { + if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { + jsondec_err(d, "Integer out of range."); } - UPB_ASSERT(new_t.array_size == arr_size); - UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); + val.int32_val = (int32_t)val.int64_val; } - *t = new_t; -} - -/* Iteration. */ - -static const upb_tabent* int_tabent(const upb_inttable_iter* i) { - UPB_ASSERT(!i->array_part); - return &i->t->t.entries[i->index]; -} -static upb_tabval int_arrent(const upb_inttable_iter* i) { - UPB_ASSERT(i->array_part); - return i->t->array[i->index]; + return val; } -void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) { - i->t = t; - i->index = -1; - i->array_part = true; - upb_inttable_next(i); -} +/* Parse UINT32 or UINT64 value. */ +static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val = {0}; -void upb_inttable_next(upb_inttable_iter* iter) { - const upb_inttable* t = iter->t; - if (iter->array_part) { - while (++iter->index < t->array_size) { - if (upb_arrhas(int_arrent(iter))) { - return; + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 18446744073709549568.0 || dbl < 0) { + jsondec_err(d, "JSON number is out of range."); } - } - iter->array_part = false; - iter->index = begin(&t->t); - } else { - iter->index = next(&t->t, iter->index); - } -} - -bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, - intptr_t* iter) { - intptr_t i = *iter; - if (i < t->array_size) { - while (++i < t->array_size) { - upb_tabval ent = t->array[i]; - if (upb_arrhas(ent)) { - *key = i; - *val = _upb_value_val(ent.val); - *iter = i; - return true; + val.uint64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.uint64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, + val.uint64_val); } + break; } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.uint64_val = jsondec_strtouint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); } - size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size); - if (tab_idx < upb_table_size(&t->t)) { - upb_tabent* ent = &t->t.entries[tab_idx]; - *key = ent->key; - *val = _upb_value_val(ent->val.val); - *iter = tab_idx + t->array_size; - return true; + if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { + if (val.uint64_val > UINT32_MAX) { + jsondec_err(d, "Integer out of range."); + } + val.uint32_val = (uint32_t)val.uint64_val; } - return false; + return val; } -void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { - intptr_t i = *iter; - if (i < t->array_size) { - t->array_count--; - mutable_array(t)[i].val = -1; - } else { - upb_tabent* ent = &t->t.entries[i - t->array_size]; - upb_tabent* prev = NULL; +/* Parse DOUBLE or FLOAT value. */ +static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { + upb_StringView str; + upb_MessageValue val = {0}; - // Linear search, not great. - upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; - for (upb_tabent* e = t->t.entries; e != end; e++) { - if (e->next == ent) { - prev = e; - break; + switch (jsondec_peek(d)) { + case JD_NUMBER: + val.double_val = jsondec_number(d); + break; + case JD_STRING: + str = jsondec_string(d); + if (jsondec_streql(str, "NaN")) { + val.double_val = NAN; + } else if (jsondec_streql(str, "Infinity")) { + val.double_val = INFINITY; + } else if (jsondec_streql(str, "-Infinity")) { + val.double_val = -INFINITY; + } else { + val.double_val = strtod(str.data, NULL); } - } + break; + default: + jsondec_err(d, "Expected number or string"); + } - if (prev) { - prev->next = ent->next; + if (upb_FieldDef_CType(f) == kUpb_CType_Float) { + if (val.double_val != INFINITY && val.double_val != -INFINITY && + (val.double_val > FLT_MAX || val.double_val < -FLT_MAX)) { + jsondec_err(d, "Float out of range"); } - - t->t.count--; - ent->key = 0; - ent->next = NULL; + val.float_val = val.double_val; } + + return val; } -bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, - upb_value* val, intptr_t* iter) { - size_t tab_idx = next(&t->t, *iter); - if (tab_idx < upb_table_size(&t->t)) { - upb_tabent* ent = &t->t.entries[tab_idx]; - uint32_t len; - key->data = upb_tabstr(ent->key, &len); - key->size = len; - *val = _upb_value_val(ent->val.val); - *iter = tab_idx; - return true; +/* Parse STRING or BYTES value. */ +static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + val.str_val = jsondec_string(d); + if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { + val.str_val.size = jsondec_base64(d, val.str_val); } - - return false; + return val; } -void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { - intptr_t i = *iter; - upb_tabent* ent = &t->t.entries[i]; - upb_tabent* prev = NULL; - - // Linear search, not great. - upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; - for (upb_tabent* e = t->t.entries; e != end; e++) { - if (e->next == ent) { - prev = e; - break; +static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { + switch (jsondec_peek(d)) { + case JD_STRING: { + upb_StringView str = jsondec_string(d); + const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); + upb_MessageValue val; + if (ev) { + val.int32_val = upb_EnumValueDef_Number(ev); + } else { + if (d->options & upb_JsonDecode_IgnoreUnknown) { + val.int32_val = 0; + } else { + jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(str)); + } + } + return val; } + case JD_NULL: { + if (jsondec_isnullvalue(f)) { + upb_MessageValue val; + jsondec_null(d); + val.int32_val = 0; + return val; + } + } + /* Fallthrough. */ + default: + return jsondec_int(d, f); } - - if (prev) { - prev->next = ent->next; - } - - t->t.count--; - ent->key = 0; - ent->next = NULL; } -bool upb_inttable_done(const upb_inttable_iter* i) { - if (!i->t) return true; - if (i->array_part) { - return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i)); +static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { + bool is_map_key = upb_FieldDef_Number(f) == 1 && + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); + upb_MessageValue val; + + if (is_map_key) { + upb_StringView str = jsondec_string(d); + if (jsondec_streql(str, "true")) { + val.bool_val = true; + } else if (jsondec_streql(str, "false")) { + val.bool_val = false; + } else { + jsondec_err(d, "Invalid boolean map key"); + } } else { - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(int_tabent(i)); + switch (jsondec_peek(d)) { + case JD_TRUE: + val.bool_val = true; + jsondec_true(d); + break; + case JD_FALSE: + val.bool_val = false; + jsondec_false(d); + break; + default: + jsondec_err(d, "Expected true or false"); + } } -} -uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) { - UPB_ASSERT(!upb_inttable_done(i)); - return i->array_part ? i->index : int_tabent(i)->key; + return val; } -upb_value upb_inttable_iter_value(const upb_inttable_iter* i) { - UPB_ASSERT(!upb_inttable_done(i)); - return _upb_value_val(i->array_part ? i->t->array[i->index].val - : int_tabent(i)->val.val); -} +/* Composite types (array/message/map) ****************************************/ -void upb_inttable_iter_setdone(upb_inttable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; - i->array_part = false; -} +static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; -bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, - const upb_inttable_iter* i2) { - if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true; - return i1->t == i2->t && i1->index == i2->index && - i1->array_part == i2->array_part; + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_MessageValue elem = jsondec_value(d, f); + upb_Array_Append(arr, elem, d->arena); + } + jsondec_arrend(d); } -/** upb/upb.c ************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include - - -// Must be last. - -/* upb_Status *****************************************************************/ +static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); -void upb_Status_Clear(upb_Status* status) { - if (!status) return; - status->ok = true; - status->msg[0] = '\0'; + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, val; + key = jsondec_value(d, key_f); + jsondec_entrysep(d); + val = jsondec_value(d, val_f); + upb_Map_Set(map, key, val, d->arena); + } + jsondec_objend(d); } -bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } - -const char* upb_Status_ErrorMessage(const upb_Status* status) { - return status->msg; +static void jsondec_tomsg(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + jsondec_object(d, msg, m); + } else { + jsondec_wellknown(d, msg, m); + } } -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { - if (!status) return; - status->ok = false; - strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} +static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + upb_Message* msg = upb_Message_New(m, d->arena); + upb_MessageValue val; -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - upb_Status_VSetErrorFormat(status, fmt, args); - va_end(args); + jsondec_tomsg(d, msg, m); + val.msg_val = msg; + return val; } -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - if (!status) return; - status->ok = false; - vsnprintf(status->msg, sizeof(status->msg), fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} +static void jsondec_field(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_StringView name; + const upb_FieldDef* f; + const upb_FieldDef* preserved; -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - size_t len; - if (!status) return; - status->ok = false; - len = strlen(status->msg); - vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} + name = jsondec_string(d); + jsondec_entrysep(d); -/* upb_alloc ******************************************************************/ + if (name.size >= 2 && name.data[0] == '[' && + name.data[name.size - 1] == ']') { + f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, + name.size - 2); + if (f && upb_FieldDef_ContainingType(f) != m) { + jsondec_errf( + d, "Extension %s extends message %s, but was seen in message %s", + upb_FieldDef_FullName(f), + upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), + upb_MessageDef_FullName(m)); + } + } else { + f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); + } -static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - UPB_UNUSED(alloc); - UPB_UNUSED(oldsize); - if (size == 0) { - free(ptr); - return NULL; + if (!f) { + if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { + jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + } + jsondec_skipval(d); + return; + } + + if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { + /* JSON "null" indicates a default value, so no need to set anything. */ + jsondec_null(d); + return; + } + + if (upb_FieldDef_RealContainingOneof(f) && + upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { + jsondec_err(d, "More than one field for this oneof."); + } + + preserved = d->debug_field; + d->debug_field = f; + + if (upb_FieldDef_IsMap(f)) { + jsondec_map(d, msg, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsondec_array(d, msg, f); + } else if (upb_FieldDef_IsSubMessage(f)) { + upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + jsondec_tomsg(d, submsg, subm); } else { - return realloc(ptr, size); + upb_MessageValue val = jsondec_value(d, f); + upb_Message_Set(msg, f, val, d->arena); } -} -static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { - return (uint32_t*)(cleanup_metadata & ~0x1); + d->debug_field = preserved; } -static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { - return cleanup_metadata & 0x1; +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_field(d, msg, m); + } + jsondec_objend(d); } -static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, - bool has_initial_block) { - return (uintptr_t)cleanup | has_initial_block; +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return jsondec_bool(d, f); + case kUpb_CType_Float: + case kUpb_CType_Double: + return jsondec_double(d, f); + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + return jsondec_uint(d, f); + case kUpb_CType_Int32: + case kUpb_CType_Int64: + return jsondec_int(d, f); + case kUpb_CType_String: + case kUpb_CType_Bytes: + return jsondec_strfield(d, f); + case kUpb_CType_Enum: + return jsondec_enum(d, f); + case kUpb_CType_Message: + return jsondec_msg(d, f); + default: + UPB_UNREACHABLE(); + } } -upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - -/* upb_Arena ******************************************************************/ +/* Well-known types ***********************************************************/ -/* Be conservative and choose 16 in case anyone is using SSE. */ +static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, + const char* after) { + uint64_t val; + const char* p = *ptr; + const char* end = p + digits; + size_t after_len = after ? strlen(after) : 0; -struct mem_block { - struct mem_block* next; - uint32_t size; - uint32_t cleanups; - /* Data follows. */ -}; + UPB_ASSERT(digits <= 9); /* int can't overflow. */ -typedef struct cleanup_ent { - upb_CleanupFunc* cleanup; - void* ud; -} cleanup_ent; + if (jsondec_buftouint64(d, p, end, &val) != end || + (after_len && memcmp(end, after, after_len) != 0)) { + jsondec_err(d, "Malformed timestamp"); + } -static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16); + UPB_ASSERT(val < INT_MAX); -static upb_Arena* arena_findroot(upb_Arena* a) { - /* Path splitting keeps time complexity down, see: - * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ - while (a->parent != a) { - upb_Arena* next = a->parent; - a->parent = next->parent; - a = next; - } - return a; + *ptr = end + after_len; + return (int)val; } -static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, - size_t size) { - mem_block* block = ptr; +static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { + uint64_t nanos = 0; + const char* p = *ptr; - /* The block is for arena |a|, but should appear in the freelist of |root|. */ - block->next = root->freelist; - block->size = (uint32_t)size; - block->cleanups = 0; - root->freelist = block; - a->last_size = block->size; - if (!root->freelist_tail) root->freelist_tail = block; + if (p != end && *p == '.') { + const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); + int digits = (int)(nano_end - p - 1); + int exp_lg10 = 9 - digits; + if (digits > 9) { + jsondec_err(d, "Too many digits for partial seconds"); + } + while (exp_lg10--) nanos *= 10; + *ptr = nano_end; + } - a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); - a->head.end = UPB_PTR_AT(block, size, char); - a->cleanup_metadata = upb_cleanup_metadata( - &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); + UPB_ASSERT(nanos < INT_MAX); - UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); + return (int)nanos; } -static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { - upb_Arena* root = arena_findroot(a); - size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; - mem_block* block = upb_malloc(root->block_alloc, block_size); - - if (!block) return false; - upb_Arena_addblock(a, root, block, block_size); - return true; +/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ +int jsondec_epochdays(int y, int m, int d) { + const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ + const uint32_t m_adj = m - 3; /* March-based month. */ + const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; + const uint32_t adjust = carry ? 12 : 0; + const uint32_t y_adj = y + year_base - carry; + const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; + const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; + return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; } -void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { - if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= size); - return upb_Arena_Malloc(a, size); +static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { + return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; } -static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ - return upb_Arena_Realloc(a, ptr, oldsize, size); -} +static void jsondec_timestamp(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; -/* Public Arena API ***********************************************************/ + if (str.size < 20) goto malformed; -upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { - const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; - upb_Arena* a; + { + /* 1972-01-01T01:00:00 */ + int year = jsondec_tsdigits(d, &ptr, 4, "-"); + int mon = jsondec_tsdigits(d, &ptr, 2, "-"); + int day = jsondec_tsdigits(d, &ptr, 2, "T"); + int hour = jsondec_tsdigits(d, &ptr, 2, ":"); + int min = jsondec_tsdigits(d, &ptr, 2, ":"); + int sec = jsondec_tsdigits(d, &ptr, 2, NULL); - /* We need to malloc the initial block. */ - n = first_block_overhead + 256; - if (!alloc || !(mem = upb_malloc(alloc, n))) { - return NULL; + seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); } - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - n -= sizeof(*a); + nanos.int32_val = jsondec_nanos(d, &ptr, end); - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->freelist = NULL; - a->freelist_tail = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, false); + { + /* [+-]08:00 or Z */ + int ofs_hour = 0; + int ofs_min = 0; + bool neg = false; - upb_Arena_addblock(a, a, mem, n); + if (ptr == end) goto malformed; - return a; -} - -upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { - upb_Arena* a; - - if (n) { - /* Align initial pointer up so that we return properly-aligned pointers. */ - void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, 16); - size_t delta = (uintptr_t)aligned - (uintptr_t)mem; - n = delta <= n ? n - delta : 0; - mem = aligned; + switch (*ptr++) { + case '-': + neg = true; + /* fallthrough */ + case '+': + if ((end - ptr) != 5) goto malformed; + ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); + ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); + ofs_min = ((ofs_hour * 60) + ofs_min) * 60; + seconds.int64_val += (neg ? ofs_min : -ofs_min); + break; + case 'Z': + if (ptr != end) goto malformed; + break; + default: + goto malformed; + } } - /* Round block size down to alignof(*a) since we will allocate the arena - * itself at the end. */ - n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); - - if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { - return arena_initslow(mem, n, alloc); + if (seconds.int64_val < -62135596800) { + jsondec_err(d, "Timestamp out of range"); } - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->last_size = UPB_MAX(128, n); - a->head.ptr = mem; - a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); - a->freelist = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, true); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); + return; - return a; +malformed: + jsondec_err(d, "Malformed timestamp"); } -static void arena_dofree(upb_Arena* a) { - mem_block* block = a->freelist; - UPB_ASSERT(a->parent == a); - UPB_ASSERT(a->refcount == 0); +static void jsondec_duration(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + const int64_t max = (uint64_t)3652500 * 86400; - while (block) { - /* Load first since we are deleting block. */ - mem_block* next = block->next; + /* "3.000000001s", "3s", etc. */ + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val); + nanos.int32_val = jsondec_nanos(d, &ptr, end); - if (block->cleanups > 0) { - cleanup_ent* end = UPB_PTR_AT(block, block->size, void); - cleanup_ent* ptr = end - block->cleanups; + if (end - ptr != 1 || *ptr != 's') { + jsondec_err(d, "Malformed duration"); + } - for (; ptr < end; ptr++) { - ptr->cleanup(ptr->ud); - } - } + if (seconds.int64_val < -max || seconds.int64_val > max) { + jsondec_err(d, "Duration out of range"); + } - upb_free(a->block_alloc, block); - block = next; + if (seconds.int64_val < 0) { + nanos.int32_val = -nanos.int32_val; } -} -void upb_Arena_Free(upb_Arena* a) { - a = arena_findroot(a); - if (--a->refcount == 0) arena_dofree(a); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); } -bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { - cleanup_ent* ent; - uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); +static void jsondec_listvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); + upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; - if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { - if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); - cleanups = upb_cleanup_pointer(a->cleanup_metadata); + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + upb_MessageValue value; + value.msg_val = value_msg; + upb_Array_Append(values, value, d->arena); + jsondec_wellknownvalue(d, value_msg, value_m); } + jsondec_arrend(d); +} - a->head.end -= sizeof(cleanup_ent); - ent = (cleanup_ent*)a->head.end; - (*cleanups)++; - UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); - - ent->cleanup = func; - ent->ud = ud; +static void jsondec_struct(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); + upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; - return true; + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, value; + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + key.str_val = jsondec_string(d); + value.msg_val = value_msg; + upb_Map_Set(fields, key, value, d->arena); + jsondec_entrysep(d); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_objend(d); } -bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { - upb_Arena* r1 = arena_findroot(a1); - upb_Arena* r2 = arena_findroot(a2); - - if (r1 == r2) return true; /* Already fused. */ +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue val; + const upb_FieldDef* f; + upb_Message* submsg; - /* Do not fuse initial blocks since we cannot lifetime extend them. */ - if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; - if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; + switch (jsondec_peek(d)) { + case JD_NUMBER: + /* double number_value = 2; */ + f = upb_MessageDef_FindFieldByNumber(m, 2); + val.double_val = jsondec_number(d); + break; + case JD_STRING: + /* string string_value = 3; */ + f = upb_MessageDef_FindFieldByNumber(m, 3); + val.str_val = jsondec_string(d); + break; + case JD_FALSE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = false; + jsondec_false(d); + break; + case JD_TRUE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = true; + jsondec_true(d); + break; + case JD_NULL: + /* NullValue null_value = 1; */ + f = upb_MessageDef_FindFieldByNumber(m, 1); + val.int32_val = 0; + jsondec_null(d); + break; + /* Note: these cases return, because upb_Message_Mutable() is enough. */ + case JD_OBJECT: + /* Struct struct_value = 5; */ + f = upb_MessageDef_FindFieldByNumber(m, 5); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + case JD_ARRAY: + /* ListValue list_value = 6; */ + f = upb_MessageDef_FindFieldByNumber(m, 6); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + default: + UPB_UNREACHABLE(); + } - /* Only allow fuse with a common allocator */ - if (r1->block_alloc != r2->block_alloc) return false; + upb_Message_Set(msg, f, val, d->arena); +} - /* We want to join the smaller tree to the larger tree. - * So swap first if they are backwards. */ - if (r1->refcount < r2->refcount) { - upb_Arena* tmp = r1; - r1 = r2; - r2 = tmp; - } +static upb_StringView jsondec_mask(jsondec* d, const char* buf, + const char* end) { + /* FieldMask fields grow due to inserted '_' characters, so we can't do the + * transform in place. */ + const char* ptr = buf; + upb_StringView ret; + char* out; - /* r1 takes over r2's freelist and refcount. */ - r1->refcount += r2->refcount; - if (r2->freelist_tail) { - UPB_ASSERT(r2->freelist_tail->next == NULL); - r2->freelist_tail->next = r1->freelist; - r1->freelist = r2->freelist; + ret.size = end - ptr; + while (ptr < end) { + ret.size += (*ptr >= 'A' && *ptr <= 'Z'); + ptr++; } - r2->parent = r1; - return true; -} -/* Miscellaneous utilities ****************************************************/ + out = upb_Arena_Malloc(d->arena, ret.size); + ptr = buf; + ret.data = out; -static void upb_FixLocale(char* p) { - /* printf() is dependent on locales; sadly there is no easy and portable way - * to avoid this. This little post-processing step will translate 1,2 -> 1.2 - * since JSON needs the latter. Arguably a hack, but it is simple and the - * alternatives are far more complicated, platform-dependent, and/or larger - * in code size. */ - for (; *p; p++) { - if (*p == ',') *p = '.'; + while (ptr < end) { + char ch = *ptr++; + if (ch >= 'A' && ch <= 'Z') { + *out++ = '_'; + *out++ = ch + 32; + } else if (ch == '_') { + jsondec_err(d, "field mask may not contain '_'"); + } else { + *out++ = ch; + } } + + return ret; } -void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { - assert(size >= kUpb_RoundTripBufferSize); - snprintf(buf, size, "%.*g", DBL_DIG, val); - if (strtod(buf, NULL) != val) { - snprintf(buf, size, "%.*g", DBL_DIG + 2, val); - assert(strtod(buf, NULL) == val); +static void jsondec_fieldmask(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + /* repeated string paths = 1; */ + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + upb_MessageValue val; + + while (ptr < end) { + const char* elem_end = memchr(ptr, ',', end - ptr); + if (elem_end) { + val.str_val = jsondec_mask(d, ptr, elem_end); + ptr = elem_end + 1; + } else { + val.str_val = jsondec_mask(d, ptr, end); + ptr = end; + } + upb_Array_Append(arr, val, d->arena); } - upb_FixLocale(buf); } -void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { - assert(size >= kUpb_RoundTripBufferSize); - snprintf(buf, size, "%.*g", FLT_DIG, val); - if (strtof(buf, NULL) != val) { - snprintf(buf, size, "%.*g", FLT_DIG + 3, val); - assert(strtof(buf, NULL) == val); +static void jsondec_anyfield(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + /* For regular types: {"@type": "[user type]", "f1": , "f2": } + * where f1, f2, etc. are the normal fields of this type. */ + jsondec_field(d, msg, m); + } else { + /* For well-known types: {"@type": "[well-known type]", "value": } + * where is whatever encoding the WKT normally uses. */ + upb_StringView str = jsondec_string(d); + jsondec_entrysep(d); + if (!jsondec_streql(str, "value")) { + jsondec_err(d, "Key for well-known type must be 'value'"); + } + jsondec_wellknown(d, msg, m); } - upb_FixLocale(buf); } -/** upb/decode_fast.c ************************************************************/ -// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. -// Also the table size grows by 2x. -// -// Could potentially be ported to other 64-bit archs that pass at least six -// arguments in registers and have 8 unused high bits in pointers. -// -// The overall design is to create specialized functions for every possible -// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch -// to the specialized function as quickly as possible. - +static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* type_m; + upb_StringView type_url = jsondec_string(d); + const char* end = type_url.data + type_url.size; + const char* ptr = end; + upb_MessageValue val; + val.str_val = type_url; + upb_Message_Set(msg, type_url_f, val, d->arena); -/* Must be last. */ + /* Find message name after the last '/' */ + while (ptr > type_url.data && *--ptr != '/') { + } -#if UPB_FASTTABLE + if (ptr == type_url.data || ptr == end) { + jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + } -// The standard set of arguments passed to each parsing function. -// Thanks to x86-64 calling conventions, these will stay in registers. -#define UPB_PARSE_PARAMS \ - upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \ - uint64_t hasbits, uint64_t data + ptr++; + type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); -#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data + if (!type_m) { + jsondec_err(d, "Type was not found"); + } -#define RETURN_GENERIC(m) \ - /* Uncomment either of these for debugging purposes. */ \ - /* fprintf(stderr, m); */ \ - /*__builtin_trap(); */ \ - return fastdecode_generic(d, ptr, msg, table, hasbits, 0); + return type_m; +} -typedef enum { - CARD_s = 0, /* Singular (optional, non-repeated) */ - CARD_o = 1, /* Oneof */ - CARD_r = 2, /* Repeated */ - CARD_p = 3 /* Packed Repeated */ -} upb_card; +static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { + /* string type_url = 1; + * bytes value = 2; */ + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_Message* any_msg; + const upb_MessageDef* any_m = NULL; + const char* pre_type_data = NULL; + const char* pre_type_end = NULL; + upb_MessageValue encoded; -UPB_NOINLINE -static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { - int overrun = data; - int status; - ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); - if (ptr == NULL) { - return fastdecode_err(d, status); - } - data = fastdecode_loadtag(ptr); - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); -} + jsondec_objstart(d); -UPB_FORCEINLINE -static const char* fastdecode_dispatch(UPB_PARSE_PARAMS) { - if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { - int overrun = ptr - d->end; - if (UPB_LIKELY(overrun == d->limit)) { - // Parse is finished. - *(uint32_t*)msg |= hasbits; // Sync hasbits. - const upb_MiniTable* l = decode_totablep(table); - return UPB_UNLIKELY(l->required_count) - ? decode_checkrequired(d, ptr, msg, l) - : ptr; + /* Scan looking for "@type", which is not necessarily first. */ + while (!any_m && jsondec_objnext(d)) { + const char* start = d->ptr; + upb_StringView name = jsondec_string(d); + jsondec_entrysep(d); + if (jsondec_streql(name, "@type")) { + any_m = jsondec_typeurl(d, msg, m); + if (pre_type_data) { + pre_type_end = start; + while (*pre_type_end != ',') pre_type_end--; + } } else { - data = overrun; - UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS); + if (!pre_type_data) pre_type_data = start; + jsondec_skipval(d); } } - // Read two bytes of tag data (for a one-byte tag, the high byte is junk). - data = fastdecode_loadtag(ptr); - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); -} + if (!any_m) { + jsondec_err(d, "Any object didn't contain a '@type' field"); + } -UPB_FORCEINLINE -static bool fastdecode_checktag(uint16_t data, int tagbytes) { - if (tagbytes == 1) { - return (data & 0xff) == 0; - } else { - return data == 0; + any_msg = upb_Message_New(any_m, d->arena); + + if (pre_type_data) { + size_t len = pre_type_end - pre_type_data + 1; + char* tmp = upb_Arena_Malloc(d->arena, len); + const char* saved_ptr = d->ptr; + const char* saved_end = d->end; + memcpy(tmp, pre_type_data, len - 1); + tmp[len - 1] = '}'; + d->ptr = tmp; + d->end = tmp + len; + d->is_first = true; + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); + } + d->ptr = saved_ptr; + d->end = saved_end; } -} -UPB_FORCEINLINE -static const char* fastdecode_longsize(const char* ptr, int* size) { - int i; - UPB_ASSERT(*size & 0x80); - *size &= 0xff; - for (i = 0; i < 3; i++) { - ptr++; - size_t byte = (uint8_t)ptr[-1]; - *size += (byte - 1) << (7 + 7 * i); - if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); } - ptr++; - size_t byte = (uint8_t)ptr[-1]; - // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected - // for a 32 bit varint. - if (UPB_UNLIKELY(byte >= 8)) return NULL; - *size += (byte - 1) << 28; - return ptr; -} -UPB_FORCEINLINE -static bool fastdecode_boundscheck(const char* ptr, size_t len, - const char* end) { - uintptr_t uptr = (uintptr_t)ptr; - uintptr_t uend = (uintptr_t)end + 16; - uintptr_t res = uptr + len; - return res < uptr || res > uend; -} + jsondec_objend(d); -UPB_FORCEINLINE -static bool fastdecode_boundscheck2(const char* ptr, size_t len, - const char* end) { - // This is one extra branch compared to the more normal: - // return (size_t)(end - ptr) < size; - // However it is one less computation if we are just about to use "ptr + len": - // https://godbolt.org/z/35YGPz - // In microbenchmarks this shows an overall 4% improvement. - uintptr_t uptr = (uintptr_t)ptr; - uintptr_t uend = (uintptr_t)end; - uintptr_t res = uptr + len; - return res < uptr || res > uend; + encoded.str_val.data = upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, + d->arena, &encoded.str_val.size); + upb_Message_Set(msg, value_f, encoded, d->arena); } -typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, - void* ctx); +static void jsondec_wrapper(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = jsondec_value(d, value_f); + upb_Message_Set(msg, value_f, val, d->arena); +} -UPB_FORCEINLINE -static const char* fastdecode_delimited(upb_Decoder* d, const char* ptr, - fastdecode_delimfunc* func, void* ctx) { - ptr++; - int len = (int8_t)ptr[-1]; - if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) { - // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. - // If it exceeds the buffer limit, limit/limit_ptr will change during - // sub-message parsing, so we need to preserve delta, not limit. - if (UPB_UNLIKELY(len & 0x80)) { - // Size varint >1 byte (length >= 128). - ptr = fastdecode_longsize(ptr, &len); - if (!ptr) { - // Corrupt wire format: size exceeded INT_MAX. - return NULL; - } - } - if (ptr - d->end + (int)len > d->limit) { - // Corrupt wire format: invalid limit. - return NULL; - } - int delta = decode_pushlimit(d, ptr, len); - ptr = func(d, ptr, ctx); - decode_poplimit(d, ptr, delta); - } else { - // Fast case: Sub-message is <128 bytes and fits in the current buffer. - // This means we can preserve limit/limit_ptr verbatim. - const char* saved_limit_ptr = d->limit_ptr; - int saved_limit = d->limit; - d->limit_ptr = ptr + len; - d->limit = d->limit_ptr - d->end; - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); - ptr = func(d, ptr, ctx); - d->limit_ptr = saved_limit_ptr; - d->limit = saved_limit; - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Any: + jsondec_any(d, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsondec_fieldmask(d, msg, m); + break; + case kUpb_WellKnown_Duration: + jsondec_duration(d, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsondec_timestamp(d, msg, m); + break; + case kUpb_WellKnown_Value: + jsondec_wellknownvalue(d, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsondec_listvalue(d, msg, m); + break; + case kUpb_WellKnown_Struct: + jsondec_struct(d, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsondec_wrapper(d, msg, m); + break; + default: + UPB_UNREACHABLE(); } - return ptr; } -/* singular, oneof, repeated field handling ***********************************/ +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status) { + jsondec d; -typedef struct { - upb_Array* arr; - void* end; -} fastdecode_arr; + if (size == 0) return true; -typedef enum { - FD_NEXT_ATLIMIT, - FD_NEXT_SAMEFIELD, - FD_NEXT_OTHERFIELD -} fastdecode_next; + d.ptr = buf; + d.end = buf + size; + d.arena = arena; + d.symtab = symtab; + d.status = status; + d.options = options; + d.depth = 64; + d.line = 1; + d.line_begin = d.ptr; + d.debug_field = NULL; + d.is_first = false; -typedef struct { - void* dst; - fastdecode_next next; - uint32_t tag; -} fastdecode_nextret; + if (UPB_SETJMP(d.err)) return false; -UPB_FORCEINLINE -static void* fastdecode_resizearr(upb_Decoder* d, void* dst, - fastdecode_arr* farr, int valbytes) { - if (UPB_UNLIKELY(dst == farr->end)) { - size_t old_size = farr->arr->size; - size_t old_bytes = old_size * valbytes; - size_t new_size = old_size * 2; - size_t new_bytes = new_size * valbytes; - char* old_ptr = _upb_array_ptr(farr->arr); - char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes); - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - farr->arr->size = new_size; - farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2); - dst = (void*)(new_ptr + (old_size * valbytes)); - farr->end = (void*)(new_ptr + (new_size * valbytes)); - } - return dst; + jsondec_tomsg(&d, msg, m); + return true; } -UPB_FORCEINLINE -static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { - if (tagbytes == 1) { - return (uint8_t)tag == (uint8_t)data; - } else { - return (uint16_t)tag == (uint16_t)data; - } -} +/** upb/json_encode.c ************************************************************/ -UPB_FORCEINLINE -static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, - int valbytes) { - farr->arr->len = - (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; -} +#include +#include +#include +#include +#include +#include +#include +#include -UPB_FORCEINLINE -static fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst, - const char** ptr, - fastdecode_arr* farr, - uint64_t data, int tagbytes, - int valbytes) { - fastdecode_nextret ret; - dst = (char*)dst + valbytes; - if (UPB_LIKELY(!decode_isdone(d, ptr))) { - ret.tag = fastdecode_loadtag(*ptr); - if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { - ret.next = FD_NEXT_SAMEFIELD; - } else { - fastdecode_commitarr(dst, farr, valbytes); - ret.next = FD_NEXT_OTHERFIELD; - } - } else { - fastdecode_commitarr(dst, farr, valbytes); - ret.next = FD_NEXT_ATLIMIT; - } +/* Must be last. */ - ret.dst = dst; - return ret; +typedef struct { + char *buf, *ptr, *end; + size_t overflow; + int indent_depth; + int options; + const upb_DefPool* ext_pool; + jmp_buf err; + upb_Status* status; + upb_Arena* arena; +} jsonenc; + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f); +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first); +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); + +UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { + upb_Status_SetErrorMessage(e->status, msg); + longjmp(e->err, 1); } -UPB_FORCEINLINE -static void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) { - size_t ofs = data >> 48; - return (char*)msg + ofs; +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(e->status, fmt, argp); + va_end(argp); + longjmp(e->err, 1); } -UPB_FORCEINLINE -static void* fastdecode_getfield(upb_Decoder* d, const char* ptr, - upb_Message* msg, uint64_t* data, - uint64_t* hasbits, fastdecode_arr* farr, - int valbytes, upb_card card) { - switch (card) { - case CARD_s: { - uint8_t hasbit_index = *data >> 24; - // Set hasbit and return pointer to scalar field. - *hasbits |= 1ull << hasbit_index; - return fastdecode_fieldmem(msg, *data); - } - case CARD_o: { - uint16_t case_ofs = *data >> 32; - uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); - uint8_t field_number = *data >> 24; - *oneof_case = field_number; - return fastdecode_fieldmem(msg, *data); - } - case CARD_r: { - // Get pointer to upb_Array and allocate/expand if necessary. - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); - upb_Array** arr_p = fastdecode_fieldmem(msg, *data); - char* begin; - *(uint32_t*)msg |= *hasbits; - *hasbits = 0; - if (UPB_LIKELY(!*arr_p)) { - farr->arr = _upb_Array_New(&d->arena, 8, elem_size_lg2); - *arr_p = farr->arr; - } else { - farr->arr = *arr_p; - } - begin = _upb_array_ptr(farr->arr); - farr->end = begin + (farr->arr->size * valbytes); - *data = fastdecode_loadtag(ptr); - return begin + (farr->arr->len * valbytes); +static upb_Arena* jsonenc_arena(jsonenc* e) { + /* Create lazily, since it's only needed for Any */ + if (!e->arena) { + e->arena = upb_Arena_New(); + } + return e->arena; +} + +static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { + size_t have = e->end - e->ptr; + if (UPB_LIKELY(have >= len)) { + memcpy(e->ptr, data, len); + e->ptr += len; + } else { + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; } - default: - UPB_UNREACHABLE(); + e->overflow += (len - have); } } -UPB_FORCEINLINE -static bool fastdecode_flippacked(uint64_t* data, int tagbytes) { - *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. - return fastdecode_checktag(*data, tagbytes); +static void jsonenc_putstr(jsonenc* e, const char* str) { + jsonenc_putbytes(e, str, strlen(str)); } -#define FASTDECODE_CHECKPACKED(tagbytes, card, func) \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \ - UPB_MUSTTAIL return func(UPB_PARSE_ARGS); \ - } \ - RETURN_GENERIC("packed check tag mismatch\n"); \ - } +UPB_PRINTF(2, 3) +static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { + size_t n; + size_t have = e->end - e->ptr; + va_list args; -/* varint fields **************************************************************/ + va_start(args, fmt); + n = _upb_vsnprintf(e->ptr, have, fmt, args); + va_end(args); -UPB_FORCEINLINE -static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { - if (valbytes == 1) { - return val != 0; - } else if (zigzag) { - if (valbytes == 4) { - uint32_t n = val; - return (n >> 1) ^ -(int32_t)(n & 1); - } else if (valbytes == 8) { - return (val >> 1) ^ -(int64_t)(val & 1); - } - UPB_UNREACHABLE(); + if (UPB_LIKELY(have > n)) { + e->ptr += n; + } else { + e->ptr = UPB_PTRADD(e->ptr, have); + e->overflow += (n - have); } - return val; } -UPB_FORCEINLINE -static const char* fastdecode_varint64(const char* ptr, uint64_t* val) { - ptr++; - *val = (uint8_t)ptr[-1]; - if (UPB_UNLIKELY(*val & 0x80)) { - int i; - for (i = 0; i < 8; i++) { - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - *val += (byte - 1) << (7 + 7 * i); - if (UPB_LIKELY((byte & 0x80) == 0)) goto done; - } - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - if (byte > 1) { - return NULL; - } - *val += (byte - 1) << 63; +static void jsonenc_nanos(jsonenc* e, int32_t nanos) { + int digits = 9; + + if (nanos == 0) return; + if (nanos < 0 || nanos >= 1000000000) { + jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); } -done: - UPB_ASSUME(ptr != NULL); - return ptr; -} -#define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, packed) \ - uint64_t val; \ - void* dst; \ - fastdecode_arr farr; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, card, packed); \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ - card); \ - if (card == CARD_r) { \ - if (UPB_UNLIKELY(!dst)) { \ - RETURN_GENERIC("need array resize\n"); \ - } \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_varint64(ptr, &val); \ - if (ptr == NULL) return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - val = fastdecode_munge(val, valbytes, zigzag); \ - memcpy(dst, &val, valbytes); \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, valbytes); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + while (nanos % 1000 == 0) { + nanos /= 1000; + digits -= 3; + } -typedef struct { - uint8_t valbytes; - bool zigzag; - void* dst; - fastdecode_arr farr; -} fastdecode_varintdata; + jsonenc_printf(e, ".%.*" PRId32, digits, nanos); +} -UPB_FORCEINLINE -static const char* fastdecode_topackedvarint(upb_Decoder* d, const char* ptr, - void* ctx) { - fastdecode_varintdata* data = ctx; - void* dst = data->dst; - uint64_t val; +static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + int L, N, I, J, K, hour, min, sec; - while (!decode_isdone(d, &ptr)) { - dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); - ptr = fastdecode_varint64(ptr, &val); - if (ptr == NULL) return NULL; - val = fastdecode_munge(val, data->valbytes, data->zigzag); - memcpy(dst, &val, data->valbytes); - dst = (char*)dst + data->valbytes; + if (seconds < -62135596800) { + jsonenc_err(e, + "error formatting timestamp as JSON: minimum acceptable value " + "is 0001-01-01T00:00:00Z"); + } else if (seconds > 253402300799) { + jsonenc_err(e, + "error formatting timestamp as JSON: maximum acceptable value " + "is 9999-12-31T23:59:59Z"); } - fastdecode_commitarr(dst, &data->farr, data->valbytes); - return ptr; + /* Julian Day -> Y/M/D, Algorithm from: + * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for + * Processing Calendar Dates," Communications of the Association of + * Computing Machines, vol. 11 (1968), p. 657. */ + seconds += 62135596800; // Ensure seconds is positive. + L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; + N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + I = 4000 * (L + 1) / 1461001; + L = L - 1461 * I / 4 + 31; + J = 80 * L / 2447; + K = L - 2447 * J / 80; + L = J / 11; + J = J + 2 - 12 * L; + I = 100 * (N - 49) + I + L; + + sec = seconds % 60; + min = (seconds / 60) % 60; + hour = (seconds / 3600) % 24; + + jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "Z\""); } -#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, zigzag, unpacked) \ - fastdecode_varintdata ctx = {valbytes, zigzag}; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked); \ - \ - ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, \ - valbytes, CARD_r); \ - if (UPB_UNLIKELY(!ctx.dst)) { \ - RETURN_GENERIC("need array resize\n"); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); \ - \ - if (UPB_UNLIKELY(ptr == NULL)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); +static void jsonenc_duration(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; -#define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, unpacked, packed) \ - if (card == CARD_p) { \ - FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, zigzag, unpacked); \ - } else { \ - FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, zigzag, packed); \ + if (seconds > 315576000000 || seconds < -315576000000 || + (seconds < 0) != (nanos < 0)) { + jsonenc_err(e, "bad duration"); } -#define z_ZZ true -#define b_ZZ false -#define v_ZZ false + if (nanos < 0) { + nanos = -nanos; + } -/* Generate all combinations: - * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ + jsonenc_printf(e, "\"%" PRId64, seconds); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "s\""); +} -#define F(card, type, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ - CARD_##card, type##_ZZ, \ - upb_pr##type##valbytes##_##tagbytes##bt, \ - upb_pp##type##valbytes##_##tagbytes##bt); \ +static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { + const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); + + if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { + jsonenc_putstr(e, "null"); + } else { + const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e_def, val); + + if (ev) { + jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); + } else { + jsonenc_printf(e, "%" PRId32, val); + } } +} -#define TYPES(card, tagbytes) \ - F(card, b, 1, tagbytes) \ - F(card, v, 4, tagbytes) \ - F(card, v, 8, tagbytes) \ - F(card, z, 4, tagbytes) \ - F(card, z, 8, tagbytes) +static void jsonenc_bytes(jsonenc* e, upb_StringView str) { + /* This is the regular base64, not the "web-safe" version. */ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const unsigned char* ptr = (unsigned char*)str.data; + const unsigned char* end = UPB_PTRADD(ptr, str.size); + char buf[4]; -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) + jsonenc_putstr(e, "\""); -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) + while (end - ptr >= 3) { + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; + buf[3] = base64[ptr[2] & 0x3f]; + jsonenc_putbytes(e, buf, 4); + ptr += 3; + } -#undef z_ZZ -#undef b_ZZ -#undef v_ZZ -#undef o_ONEOF -#undef s_ONEOF -#undef r_ONEOF -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDVARINT -#undef FASTDECODE_PACKEDVARINT -#undef FASTDECODE_VARINT - -/* fixed fields ***************************************************************/ + switch (end - ptr) { + case 2: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[(ptr[1] & 0xf) << 2]; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + case 1: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4)]; + buf[2] = '='; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + } -#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, packed) \ - void* dst; \ - fastdecode_arr farr; \ - \ - FASTDECODE_CHECKPACKED(tagbytes, card, packed) \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, \ - card); \ - if (card == CARD_r) { \ - if (UPB_UNLIKELY(!dst)) { \ - RETURN_GENERIC("couldn't allocate array in arena\n"); \ - } \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, valbytes); \ - } \ - \ - ptr += tagbytes; \ - memcpy(dst, ptr, valbytes); \ - ptr += valbytes; \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, valbytes); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + jsonenc_putstr(e, "\""); +} -#define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, unpacked) \ - FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked) \ - \ - ptr += tagbytes; \ - int size = (uint8_t)ptr[0]; \ - ptr++; \ - if (size & 0x80) { \ - ptr = fastdecode_longsize(ptr, &size); \ - } \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) || \ - (size % valbytes) != 0)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - upb_Array** arr_p = fastdecode_fieldmem(msg, data); \ - upb_Array* arr = *arr_p; \ - uint8_t elem_size_lg2 = __builtin_ctz(valbytes); \ - int elems = size / valbytes; \ - \ - if (UPB_LIKELY(!arr)) { \ - *arr_p = arr = _upb_Array_New(&d->arena, elems, elem_size_lg2); \ - if (!arr) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - } else { \ - _upb_Array_Resize(arr, elems, &d->arena); \ - } \ - \ - char* dst = _upb_array_ptr(arr); \ - memcpy(dst, ptr, size); \ - arr->len = elems; \ - \ - ptr += size; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { + const char* ptr = str.data; + const char* end = UPB_PTRADD(ptr, str.size); -#define FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, unpacked, packed) \ - if (card == CARD_p) { \ - FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, unpacked); \ - } else { \ - FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \ - valbytes, card, packed); \ + while (ptr < end) { + switch (*ptr) { + case '\n': + jsonenc_putstr(e, "\\n"); + break; + case '\r': + jsonenc_putstr(e, "\\r"); + break; + case '\t': + jsonenc_putstr(e, "\\t"); + break; + case '\"': + jsonenc_putstr(e, "\\\""); + break; + case '\f': + jsonenc_putstr(e, "\\f"); + break; + case '\b': + jsonenc_putstr(e, "\\b"); + break; + case '\\': + jsonenc_putstr(e, "\\\\"); + break; + default: + if ((uint8_t)*ptr < 0x20) { + jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); + } else { + /* This could be a non-ASCII byte. We rely on the string being valid + * UTF-8. */ + jsonenc_putbytes(e, ptr, 1); + } + break; + } + ptr++; } +} -/* Generate all combinations: - * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ +static void jsonenc_string(jsonenc* e, upb_StringView str) { + jsonenc_putstr(e, "\""); + jsonenc_stringbody(e, str); + jsonenc_putstr(e, "\""); +} -#define F(card, valbytes, tagbytes) \ - UPB_NOINLINE \ - const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \ - CARD_##card, upb_ppf##valbytes##_##tagbytes##bt, \ - upb_prf##valbytes##_##tagbytes##bt); \ +static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { + if (val == INFINITY) { + jsonenc_putstr(e, "\"Infinity\""); + } else if (val == -INFINITY) { + jsonenc_putstr(e, "\"-Infinity\""); + } else if (val != val) { + jsonenc_putstr(e, "\"NaN\""); + } else { + return false; } + return true; +} -#define TYPES(card, tagbytes) \ - F(card, 4, tagbytes) \ - F(card, 8, tagbytes) +static void upb_JsonEncode_Double(jsonenc* e, double val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) +static void upb_JsonEncode_Float(jsonenc* e, float val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) +static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = upb_Message_Get(msg, val_f); + jsonenc_scalar(e, val, val_f); +} -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDFIXED -#undef FASTDECODE_PACKEDFIXED +static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, + upb_StringView type_url) { + /* Find last '/', if any. */ + const char* end = type_url.data + type_url.size; + const char* ptr = end; + const upb_MessageDef* ret; -/* string fields **************************************************************/ + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + } -typedef const char* fastdecode_copystr_func(struct upb_Decoder* d, - const char* ptr, upb_Message* msg, - const upb_MiniTable* table, - uint64_t hasbits, - upb_StringView* dst); + if (type_url.size == 0) goto badurl; -UPB_NOINLINE -static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - if (!decode_verifyutf8_inl(dst->data, dst->size)) { - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); + while (true) { + if (--ptr == type_url.data) { + /* Type URL must contain at least one '/', with host before. */ + goto badurl; + } + if (*ptr == '/') { + ptr++; + break; + } } - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + + ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); + + if (!ret) { + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + } + + return ret; + +badurl: + jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(type_url)); } -#define FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, validate_utf8) \ - int size = (uint8_t)ptr[0]; /* Could plumb through hasbits. */ \ - ptr++; \ - if (size & 0x80) { \ - ptr = fastdecode_longsize(ptr, &size); \ - } \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { \ - dst->size = 0; \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - if (d->options & kUpb_DecodeOption_AliasString) { \ - dst->data = ptr; \ - dst->size = size; \ - } else { \ - char* data = upb_Arena_Malloc(&d->arena, size); \ - if (!data) { \ - return fastdecode_err(d, kUpb_DecodeStatus_OutOfMemory); \ - } \ - memcpy(data, ptr, size); \ - dst->data = data; \ - dst->size = size; \ - } \ - \ - ptr += size; \ - if (validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } else { \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ +static void jsonenc_any(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; + upb_StringView value = upb_Message_Get(msg, value_f).str_val; + const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + upb_Arena* arena = jsonenc_arena(e); + upb_Message* any = upb_Message_New(any_m, arena); + + if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + jsonenc_err(e, "Error decoding message in Any"); + } + + jsonenc_putstr(e, "{\"@type\":"); + jsonenc_string(e, type_url); + + if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { + /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ + jsonenc_msgfields(e, any, any_m, false); + } else { + /* Well-known type: {"@type": "...","value": } */ + jsonenc_putstr(e, ",\"value\":"); + jsonenc_msgfield(e, any, any_m); + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { + if (*first) { + *first = false; + } else { + jsonenc_putstr(e, str); + } +} + +static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { + const char* ptr = path.data; + const char* end = ptr + path.size; + + while (ptr < end) { + char ch = *ptr; + + if (ch >= 'A' && ch <= 'Z') { + jsonenc_err(e, "Field mask element may not have upper-case letter."); + } else if (ch == '_') { + if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { + jsonenc_err(e, "Underscore must be followed by a lowercase letter."); + } + ch = *++ptr - 32; + } + + jsonenc_putbytes(e, &ch, 1); + ptr++; + } +} + +static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; + bool first = true; + size_t i, n = 0; + + if (paths) n = upb_Array_Size(paths); + + jsonenc_putstr(e, "\""); + + for (i = 0; i < n; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_struct(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; + + jsonenc_putstr(e, "{"); + + if (fields) { + while (upb_MapIterator_Next(fields, &iter)) { + upb_MessageValue key = upb_MapIterator_Key(fields, iter); + upb_MessageValue val = upb_MapIterator_Value(fields, iter); + + jsonenc_putsep(e, ",", &first); + jsonenc_string(e, key.str_val); + jsonenc_putstr(e, ":"); + jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); + const upb_Array* values = upb_Message_Get(msg, values_f).array_val; + size_t i; + bool first = true; + + jsonenc_putstr(e, "["); + + if (values) { + const size_t size = upb_Array_Size(values); + for (i = 0; i < size; i++) { + upb_MessageValue elem = upb_Array_Get(values, i); + + jsonenc_putsep(e, ",", &first); + jsonenc_value(e, elem.msg_val, values_m); + } + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + /* TODO(haberman): do we want a reflection method to get oneof case? */ + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + + if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { + jsonenc_err(e, "No value set in Value proto"); + } + + switch (upb_FieldDef_Number(f)) { + case 1: + jsonenc_putstr(e, "null"); + break; + case 2: + upb_JsonEncode_Double(e, val.double_val); + break; + case 3: + jsonenc_string(e, val.str_val); + break; + case 4: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case 5: + jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + case 6: + jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Unspecified: + jsonenc_msg(e, msg, m); + break; + case kUpb_WellKnown_Any: + jsonenc_any(e, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsonenc_fieldmask(e, msg, m); + break; + case kUpb_WellKnown_Duration: + jsonenc_duration(e, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsonenc_timestamp(e, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsonenc_wrapper(e, msg, m); + break; + case kUpb_WellKnown_Value: + jsonenc_value(e, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsonenc_listvalue(e, msg, m); + break; + case kUpb_WellKnown_Struct: + jsonenc_struct(e, msg, m); + break; + } +} + +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Float: + upb_JsonEncode_Float(e, val.float_val); + break; + case kUpb_CType_Double: + upb_JsonEncode_Double(e, val.double_val); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_string(e, val.str_val); + break; + case kUpb_CType_Bytes: + jsonenc_bytes(e, val.str_val); + break; + case kUpb_CType_Enum: + jsonenc_enum(val.int32_val, f, e); + break; + case kUpb_CType_Message: + jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + jsonenc_putstr(e, "\""); + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "%" PRId64, val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "%" PRIu64, val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_stringbody(e, val.str_val); + break; + default: + UPB_UNREACHABLE(); + } + + jsonenc_putstr(e, "\":"); +} + +static void jsonenc_array(jsonenc* e, const upb_Array* arr, + const upb_FieldDef* f) { + size_t i; + size_t size = arr ? upb_Array_Size(arr) : 0; + bool first = true; + + jsonenc_putstr(e, "["); + + for (i = 0; i < size; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_scalar(e, upb_Array_Get(arr, i), f); + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; + + jsonenc_putstr(e, "{"); + + if (map) { + while (upb_MapIterator_Next(map, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); + jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); + } } -UPB_NOINLINE -static const char* fastdecode_longstring_utf8(struct upb_Decoder* d, - const char* ptr, upb_Message* msg, - intptr_t table, uint64_t hasbits, - uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true); + jsonenc_putstr(e, "}"); } -UPB_NOINLINE -static const char* fastdecode_longstring_noutf8( - struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data) { - upb_StringView* dst = (upb_StringView*)data; - FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false); -} +static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, + upb_MessageValue val, bool* first) { + const char* name; -UPB_FORCEINLINE -static void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size, - int copy, char* data, upb_StringView* dst) { - d->arena.head.ptr += copy; - dst->data = data; - UPB_UNPOISON_MEMORY_REGION(data, copy); - memcpy(data, ptr, copy); - UPB_POISON_MEMORY_REGION(data + size, copy - size); -} + jsonenc_putsep(e, ",", first); -#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - card, validate_utf8) \ - upb_StringView* dst; \ - fastdecode_arr farr; \ - int64_t size; \ - size_t arena_has; \ - size_t common_has; \ - char* buf; \ - \ - UPB_ASSERT((d->options & kUpb_DecodeOption_AliasString) == 0); \ - UPB_ASSERT(fastdecode_checktag(data, tagbytes)); \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_StringView), card); \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ - } \ - \ - size = (uint8_t)ptr[tagbytes]; \ - ptr += tagbytes + 1; \ - dst->size = size; \ - \ - buf = d->arena.head.ptr; \ - arena_has = _upb_ArenaHas(&d->arena); \ - common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); \ - \ - if (UPB_LIKELY(size <= 15 - tagbytes)) { \ - if (arena_has < 16) goto longstr; \ - d->arena.head.ptr += 16; \ - memcpy(buf, ptr - tagbytes - 1, 16); \ - dst->data = buf + tagbytes + 1; \ - } else if (UPB_LIKELY(size <= 32)) { \ - if (UPB_UNLIKELY(common_has < 32)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 32, buf, dst); \ - } else if (UPB_LIKELY(size <= 64)) { \ - if (UPB_UNLIKELY(common_has < 64)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 64, buf, dst); \ - } else if (UPB_LIKELY(size < 128)) { \ - if (UPB_UNLIKELY(common_has < 128)) goto longstr; \ - fastdecode_docopy(d, ptr, size, 128, buf, dst); \ - } else { \ - goto longstr; \ - } \ - \ - ptr += size; \ - \ - if (card == CARD_r) { \ - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ - } \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - if (card != CARD_r && validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); \ - \ - longstr: \ - if (card == CARD_r) { \ - fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView)); \ - } \ - ptr--; \ - if (validate_utf8) { \ - UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table, \ - hasbits, (uint64_t)dst); \ - } else { \ - UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table, \ - hasbits, (uint64_t)dst); \ + if (upb_FieldDef_IsExtension(f)) { + // TODO: For MessageSet, I would have expected this to print the message + // name here, but Python doesn't appear to do this. We should do more + // research here about what various implementations do. + jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); + } else { + if (e->options & upb_JsonEncode_UseProtoNames) { + name = upb_FieldDef_Name(f); + } else { + name = upb_FieldDef_JsonName(f); + } + jsonenc_printf(e, "\"%s\":", name); } -#define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card, \ - copyfunc, validate_utf8) \ - upb_StringView* dst; \ - fastdecode_arr farr; \ - int64_t size; \ - \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - RETURN_GENERIC("string field tag mismatch\n"); \ - } \ - \ - if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ - UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS); \ - } \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_StringView), card); \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView)); \ - } \ - \ - size = (int8_t)ptr[tagbytes]; \ - ptr += tagbytes + 1; \ - dst->data = ptr; \ - dst->size = size; \ - \ - if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { \ - ptr--; \ - if (validate_utf8) { \ - return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, \ - (uint64_t)dst); \ - } else { \ - return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, \ - (uint64_t)dst); \ - } \ - } \ - \ - ptr += size; \ - \ - if (card == CARD_r) { \ - if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8); \ - } \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \ - /* Buffer flipped and we can't alias any more. Bounce to */ \ - /* copyfunc(), but via dispatch since we need to reload table */ \ - /* data also. */ \ - fastdecode_commitarr(dst, &farr, sizeof(upb_StringView)); \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - } \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - if (card != CARD_r && validate_utf8) { \ - data = (uint64_t)dst; \ - UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + if (upb_FieldDef_IsMap(f)) { + jsonenc_map(e, val.map_val, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsonenc_array(e, val.array_val, f); + } else { + jsonenc_scalar(e, val, f); + } +} -/* Generate all combinations: - * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first) { + upb_MessageValue val; + const upb_FieldDef* f; -#define s_VALIDATE true -#define b_VALIDATE false + if (e->options & upb_JsonEncode_EmitDefaults) { + /* Iterate over all fields. */ + int i = 0; + int n = upb_MessageDef_FieldCount(m); + for (i = 0; i < n; i++) { + f = upb_MessageDef_Field(m, i); + if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { + jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first); + } + } + } else { + /* Iterate over non-empty fields. */ + size_t iter = kUpb_Message_Begin; + while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { + jsonenc_fieldval(e, f, val, &first); + } + } +} -#define F(card, tagbytes, type) \ - UPB_NOINLINE \ - const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - CARD_##card, type##_VALIDATE); \ - } \ - const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ - FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, \ - CARD_##card, upb_c##card##type##_##tagbytes##bt, \ - type##_VALIDATE); \ +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); + jsonenc_msgfields(e, msg, m, true); + jsonenc_putstr(e, "}"); +} + +static size_t jsonenc_nullz(jsonenc* e, size_t size) { + size_t ret = e->ptr - e->buf + e->overflow; + + if (size > 0) { + if (e->ptr == e->end) e->ptr--; + *e->ptr = '\0'; } -#define UTF8(card, tagbytes) \ - F(card, tagbytes, s) \ - F(card, tagbytes, b) - -#define TAGBYTES(card) \ - UTF8(card, 1) \ - UTF8(card, 2) + return ret; +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status) { + jsonenc e; -#undef s_VALIDATE -#undef b_VALIDATE -#undef F -#undef TAGBYTES -#undef FASTDECODE_LONGSTRING -#undef FASTDECODE_COPYSTRING -#undef FASTDECODE_STRING + e.buf = buf; + e.ptr = buf; + e.end = UPB_PTRADD(buf, size); + e.overflow = 0; + e.options = options; + e.ext_pool = ext_pool; + e.status = status; + e.arena = NULL; -/* message fields *************************************************************/ + if (setjmp(e.err)) return -1; -UPB_INLINE -upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* l, - int msg_ceil_bytes) { - size_t size = l->size + sizeof(upb_Message_Internal); - char* msg_data; - if (UPB_LIKELY(msg_ceil_bytes > 0 && - _upb_ArenaHas(&d->arena) >= msg_ceil_bytes)) { - UPB_ASSERT(size <= (size_t)msg_ceil_bytes); - msg_data = d->arena.head.ptr; - d->arena.head.ptr += size; - UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); - memset(msg_data, 0, msg_ceil_bytes); - UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); - } else { - msg_data = (char*)upb_Arena_Malloc(&d->arena, size); - memset(msg_data, 0, size); - } - return msg_data + sizeof(upb_Message_Internal); + jsonenc_msgfield(&e, msg, m); + if (e.arena) upb_Arena_Free(e.arena); + return jsonenc_nullz(&e, size); } -typedef struct { - intptr_t table; - upb_Message* msg; -} fastdecode_submsgdata; +/** upb/mini_table.c ************************************************************/ -UPB_FORCEINLINE -static const char* fastdecode_tosubmsg(upb_Decoder* d, const char* ptr, - void* ctx) { - fastdecode_submsgdata* submsg = ctx; - ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); - UPB_ASSUME(ptr != NULL); - return ptr; -} +#include +#include -#define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, \ - msg_ceil_bytes, card) \ - \ - if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ - RETURN_GENERIC("submessage field tag mismatch\n"); \ - } \ - \ - if (--d->depth == 0) { \ - return fastdecode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); \ - } \ - \ - upb_Message** dst; \ - uint32_t submsg_idx = (data >> 16) & 0xff; \ - const upb_MiniTable* tablep = decode_totablep(table); \ - const upb_MiniTable* subtablep = tablep->subs[submsg_idx].submsg; \ - fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ - fastdecode_arr farr; \ - \ - if (subtablep->table_mask == (uint8_t)-1) { \ - RETURN_GENERIC("submessage doesn't have fast tables."); \ - } \ - \ - dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ - sizeof(upb_Message*), card); \ - \ - if (card == CARD_s) { \ - *(uint32_t*)msg |= hasbits; \ - hasbits = 0; \ - } \ - \ - again: \ - if (card == CARD_r) { \ - dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ - } \ - \ - submsg.msg = *dst; \ - \ - if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { \ - *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); \ - } \ - \ - ptr += tagbytes; \ - ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ - \ - if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ - return fastdecode_err(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - if (card == CARD_r) { \ - fastdecode_nextret ret = fastdecode_nextrepeated( \ - d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ - switch (ret.next) { \ - case FD_NEXT_SAMEFIELD: \ - dst = ret.dst; \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - d->depth++; \ - data = ret.tag; \ - UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - d->depth++; \ - return ptr; \ - } \ - } \ - \ - d->depth++; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); -#define F(card, tagbytes, size_ceil, ceil_arg) \ - const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ - UPB_PARSE_PARAMS) { \ - FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \ - CARD_##card); \ - } +// Must be last. -#define SIZES(card, tagbytes) \ - F(card, tagbytes, 64, 64) \ - F(card, tagbytes, 128, 128) \ - F(card, tagbytes, 192, 192) \ - F(card, tagbytes, 256, 256) \ - F(card, tagbytes, max, -1) +typedef enum { + kUpb_EncodedType_Double = 0, + kUpb_EncodedType_Float = 1, + kUpb_EncodedType_Fixed32 = 2, + kUpb_EncodedType_Fixed64 = 3, + kUpb_EncodedType_SFixed32 = 4, + kUpb_EncodedType_SFixed64 = 5, + kUpb_EncodedType_Int32 = 6, + kUpb_EncodedType_UInt32 = 7, + kUpb_EncodedType_SInt32 = 8, + kUpb_EncodedType_Int64 = 9, + kUpb_EncodedType_UInt64 = 10, + kUpb_EncodedType_SInt64 = 11, + kUpb_EncodedType_Enum = 12, + kUpb_EncodedType_Bool = 13, + kUpb_EncodedType_Bytes = 14, + kUpb_EncodedType_String = 15, + kUpb_EncodedType_Group = 16, + kUpb_EncodedType_Message = 17, + + kUpb_EncodedType_RepeatedBase = 20, +} upb_EncodedType; -#define TAGBYTES(card) \ - SIZES(card, 1) \ - SIZES(card, 2) +typedef enum { + kUpb_EncodedFieldModifier_FlipPacked = 1 << 0, + kUpb_EncodedFieldModifier_IsClosedEnum = 1 << 1, + // upb only. + kUpb_EncodedFieldModifier_IsProto3Singular = 1 << 2, + kUpb_EncodedFieldModifier_IsRequired = 1 << 3, +} upb_EncodedFieldModifier; + +enum { + kUpb_EncodedValue_MinField = ' ', + kUpb_EncodedValue_MaxField = 'K', + kUpb_EncodedValue_MinModifier = 'L', + kUpb_EncodedValue_MaxModifier = '[', + kUpb_EncodedValue_End = '^', + kUpb_EncodedValue_MinSkip = '_', + kUpb_EncodedValue_MaxSkip = '~', + kUpb_EncodedValue_OneofSeparator = '~', + kUpb_EncodedValue_FieldSeparator = '|', + kUpb_EncodedValue_MinOneofField = ' ', + kUpb_EncodedValue_MaxOneofField = 'b', + kUpb_EncodedValue_MaxEnumMask = 'A', +}; -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +char upb_ToBase92(int8_t ch) { + static const char kUpb_ToBase92[] = { + ' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', + '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '[', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '{', '|', '}', '~', + }; -#undef TAGBYTES -#undef SIZES -#undef F -#undef FASTDECODE_SUBMSG + UPB_ASSERT(0 <= ch && ch < 92); + return kUpb_ToBase92[ch]; +} -#endif /* UPB_FASTTABLE */ +char upb_FromBase92(uint8_t ch) { + static const int8_t kUpb_FromBase92[] = { + 0, 1, -1, 2, 3, 4, 5, -1, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + }; -/** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upb.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ + if (' ' > ch || ch > '~') return -1; + return kUpb_FromBase92[ch - ' ']; +} -#include +bool upb_IsTypePackable(upb_FieldType type) { + // clang-format off + static const unsigned kUnpackableTypes = + (1 << kUpb_FieldType_String) | + (1 << kUpb_FieldType_Bytes) | + (1 << kUpb_FieldType_Message) | + (1 << kUpb_FieldType_Group); + // clang-format on + return (1 << type) & ~kUnpackableTypes; +} +/** upb_MtDataEncoder *********************************************************/ -static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { - {.submsg = &google_protobuf_FileDescriptorProto_msginit}, -}; +typedef struct { + uint64_t present_values_mask; + uint32_t last_written_value; +} upb_MtDataEncoderInternal_EnumState; -static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +typedef struct { + uint64_t msg_modifiers; + uint32_t last_field_num; + enum { + kUpb_OneofState_NotStarted, + kUpb_OneofState_StartedOneof, + kUpb_OneofState_EmittedOneofField, + } oneof_state; +} upb_MtDataEncoderInternal_MsgState; -const upb_MiniTable google_protobuf_FileDescriptorSet_msginit = { - &google_protobuf_FileDescriptorSet_submsgs[0], - &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, -}; +typedef struct { + char* buf_start; // Only for checking kUpb_MtDataEncoder_MinSize. + union { + upb_MtDataEncoderInternal_EnumState enum_state; + upb_MtDataEncoderInternal_MsgState msg_state; + } state; +} upb_MtDataEncoderInternal; + +static upb_MtDataEncoderInternal* upb_MtDataEncoder_GetInternal( + upb_MtDataEncoder* e, char* buf_start) { + UPB_ASSERT(sizeof(upb_MtDataEncoderInternal) <= sizeof(e->internal)); + upb_MtDataEncoderInternal* ret = (upb_MtDataEncoderInternal*)e->internal; + ret->buf_start = buf_start; + return ret; +} -static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { - {.submsg = &google_protobuf_DescriptorProto_msginit}, - {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, - {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, - {.submsg = &google_protobuf_FileOptions_msginit}, - {.submsg = &google_protobuf_ServiceDescriptorProto_msginit}, - {.submsg = &google_protobuf_SourceCodeInfo_msginit}, -}; +static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + UPB_ASSERT(ptr - in->buf_start < kUpb_MtDataEncoder_MinSize); + if (ptr == e->end) return NULL; + *ptr++ = upb_ToBase92(ch); + return ptr; +} -static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(36, 72), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(40, 80), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(44, 88), 0, 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(48, 96), 0, 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(52, 104), 0, 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 56), 3, 3, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(32, 64), 4, 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 112), 0, 0, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {11, UPB_SIZE(60, 120), 0, 0, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {12, UPB_SIZE(20, 40), 5, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, -}; +static char* upb_MtDataEncoder_PutBase92Varint(upb_MtDataEncoder* e, char* ptr, + uint32_t val, int min, int max) { + int shift = _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min) + 1); + UPB_ASSERT(shift <= 6); + uint32_t mask = (1 << shift) - 1; + do { + uint32_t bits = val & mask; + ptr = upb_MtDataEncoder_Put(e, ptr, bits + upb_FromBase92(min)); + if (!ptr) return NULL; + val >>= shift; + } while (val); + return ptr; +} -const upb_MiniTable google_protobuf_FileDescriptorProto_msginit = { - &google_protobuf_FileDescriptorProto_submsgs[0], - &google_protobuf_FileDescriptorProto__fields[0], - UPB_SIZE(64, 128), 12, kUpb_ExtMode_NonExtendable, 12, 255, 0, -}; +char* upb_MtDataEncoder_PutModifier(upb_MtDataEncoder* e, char* ptr, + uint64_t mod) { + if (mod) { + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, mod, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier); + } + return ptr; +} -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[7] = { - {.submsg = &google_protobuf_DescriptorProto_msginit}, - {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msginit}, - {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msginit}, - {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, - {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, - {.submsg = &google_protobuf_MessageOptions_msginit}, - {.submsg = &google_protobuf_OneofDescriptorProto_msginit}, -}; +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = msg_mod; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); +} + +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + static const char kUpb_TypeToEncoded[] = { + [kUpb_FieldType_Double] = kUpb_EncodedType_Double, + [kUpb_FieldType_Float] = kUpb_EncodedType_Float, + [kUpb_FieldType_Int64] = kUpb_EncodedType_Int64, + [kUpb_FieldType_UInt64] = kUpb_EncodedType_UInt64, + [kUpb_FieldType_Int32] = kUpb_EncodedType_Int32, + [kUpb_FieldType_Fixed64] = kUpb_EncodedType_Fixed64, + [kUpb_FieldType_Fixed32] = kUpb_EncodedType_Fixed32, + [kUpb_FieldType_Bool] = kUpb_EncodedType_Bool, + [kUpb_FieldType_String] = kUpb_EncodedType_String, + [kUpb_FieldType_Group] = kUpb_EncodedType_Group, + [kUpb_FieldType_Message] = kUpb_EncodedType_Message, + [kUpb_FieldType_Bytes] = kUpb_EncodedType_Bytes, + [kUpb_FieldType_UInt32] = kUpb_EncodedType_UInt32, + [kUpb_FieldType_Enum] = kUpb_EncodedType_Enum, + [kUpb_FieldType_SFixed32] = kUpb_EncodedType_SFixed32, + [kUpb_FieldType_SFixed64] = kUpb_EncodedType_SFixed64, + [kUpb_FieldType_SInt32] = kUpb_EncodedType_SInt32, + [kUpb_FieldType_SInt64] = kUpb_EncodedType_SInt64, + }; -static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(24, 48), 0, 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(28, 56), 0, 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(32, 64), 0, 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(12, 24), 2, 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(36, 72), 0, 6, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(40, 80), 0, 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(44, 88), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (field_num <= in->state.msg_state.last_field_num) return NULL; + if (in->state.msg_state.last_field_num + 1 != field_num) { + // Put skip. + UPB_ASSERT(field_num > in->state.msg_state.last_field_num); + uint32_t skip = field_num - in->state.msg_state.last_field_num; + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, skip, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + if (!ptr) return NULL; + } + in->state.msg_state.last_field_num = field_num; + + uint32_t encoded_modifiers = 0; + + // Put field type. + if (type == kUpb_FieldType_Enum && + !(field_mod & kUpb_FieldModifier_IsClosedEnum)) { + type = kUpb_FieldType_Int32; + } + + int encoded_type = kUpb_TypeToEncoded[type]; + if (field_mod & kUpb_FieldModifier_IsRepeated) { + // Repeated fields shift the type number up (unlike other modifiers which + // are bit flags). + encoded_type += kUpb_EncodedType_RepeatedBase; + + if (upb_IsTypePackable(type)) { + bool field_is_packed = field_mod & kUpb_FieldModifier_IsPacked; + bool default_is_packed = in->state.msg_state.msg_modifiers & + kUpb_MessageModifier_DefaultIsPacked; + if (field_is_packed != default_is_packed) { + encoded_modifiers |= kUpb_EncodedFieldModifier_FlipPacked; + } + } + } + ptr = upb_MtDataEncoder_Put(e, ptr, encoded_type); + if (!ptr) return NULL; -const upb_MiniTable google_protobuf_DescriptorProto_msginit = { - &google_protobuf_DescriptorProto_submsgs[0], - &google_protobuf_DescriptorProto__fields[0], - UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, 255, 0, -}; + if (field_mod & kUpb_FieldModifier_IsProto3Singular) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; + } + if (field_mod & kUpb_FieldModifier_IsRequired) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; + } + return upb_MtDataEncoder_PutModifier(e, ptr, encoded_modifiers); +} -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { - {.submsg = &google_protobuf_ExtensionRangeOptions_msginit}, -}; +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_NotStarted) { + ptr = upb_MtDataEncoder_Put(e, ptr, upb_FromBase92(kUpb_EncodedValue_End)); + } else { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); + } + in->state.msg_state.oneof_state = kUpb_OneofState_StartedOneof; + return ptr; +} -static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_EmittedOneofField) { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_FieldSeparator)); + if (!ptr) return NULL; + } + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, field_num, upb_ToBase92(0), + upb_ToBase92(63)); + in->state.msg_state.oneof_state = kUpb_OneofState_EmittedOneofField; + return ptr; +} -const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit = { - &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], - &google_protobuf_DescriptorProto_ExtensionRange__fields[0], - UPB_SIZE(16, 24), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, -}; +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, NULL); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value = 0; +} -static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, -}; +static char* upb_MtDataEncoder_FlushDenseEnumMask(upb_MtDataEncoder* e, + char* ptr) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + ptr = upb_MtDataEncoder_Put(e, ptr, in->state.enum_state.present_values_mask); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value += 5; + return ptr; +} -const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit = { - NULL, - &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, -}; +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val) { + // TODO(b/229641772): optimize this encoding. + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + UPB_ASSERT(val >= in->state.enum_state.last_written_value); + uint32_t delta = val - in->state.enum_state.last_written_value; + if (delta >= 5 && in->state.enum_state.present_values_mask) { + ptr = upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); + delta -= 5; + } -static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; + if (delta >= 5) { + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, delta, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + in->state.enum_state.last_written_value += delta; + delta = 0; + } -static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + UPB_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); + in->state.enum_state.present_values_mask |= 1ULL << delta; + return ptr; +} -const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit = { - &google_protobuf_ExtensionRangeOptions_submsgs[0], - &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, -}; +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (!in->state.enum_state.present_values_mask) return ptr; + return upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); +} -static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { - {.submsg = &google_protobuf_FieldOptions_msginit}, - {.subenum = &google_protobuf_FieldDescriptorProto_Label_enuminit}, - {.subenum = &google_protobuf_FieldDescriptorProto_Type_enuminit}, -}; +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number) { + int n = table->field_count; + for (int i = 0; i < n; i++) { + if (table->fields[i].number == number) { + return &table->fields[i]; + } + } + return NULL; +} -static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(24, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(32, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 12), 3, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(4, 4), 4, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(40, 56), 6, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(48, 72), 7, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(64, 104), 8, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(16, 16), 9, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 88), 10, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {17, UPB_SIZE(20, 20), 11, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, -}; +/** Data decoder **************************************************************/ -const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit = { - &google_protobuf_FieldDescriptorProto_submsgs[0], - &google_protobuf_FieldDescriptorProto__fields[0], - UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, 255, 0, -}; +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_LayoutItemType_OneofCase, // Oneof case. + kUpb_LayoutItemType_OneofField, // Oneof field data. + kUpb_LayoutItemType_Field, // Non-oneof field data. -static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_OneofOptions_msginit}, -}; + kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, +} upb_LayoutItemType; -static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +#define kUpb_LayoutItem_IndexSentinel ((uint16_t)-1) -const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit = { - &google_protobuf_OneofDescriptorProto_submsgs[0], - &google_protobuf_OneofDescriptorProto__fields[0], - UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, -}; +typedef struct { + // Index of the corresponding field. When this is a oneof field, the field's + // offset will be the index of the next field in a linked list. + uint16_t field_index; + uint16_t offset; + upb_FieldRep rep; + upb_LayoutItemType type; +} upb_LayoutItem; -static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { - {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit}, - {.submsg = &google_protobuf_EnumOptions_msginit}, - {.submsg = &google_protobuf_EnumValueDescriptorProto_msginit}, -}; +typedef struct { + upb_LayoutItem* data; + size_t size; + size_t capacity; +} upb_LayoutItemVector; -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(24, 48), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +typedef struct { + const char* end; + upb_MiniTable* table; + upb_MiniTable_Field* fields; + upb_MiniTablePlatform platform; + upb_LayoutItemVector vec; + upb_Arena* arena; + upb_Status* status; + jmp_buf err; +} upb_MtDecoder; -const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit = { - &google_protobuf_EnumDescriptorProto_submsgs[0], - &google_protobuf_EnumDescriptorProto__fields[0], - UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, -}; +UPB_PRINTF(2, 3) +UPB_NORETURN static void upb_MtDecoder_ErrorFormat(upb_MtDecoder* d, + const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorMessage(d->status, "Error building mini table: "); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); +} -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, -}; +static void upb_MtDecoder_CheckOutOfMemory(upb_MtDecoder* d, const void* ptr) { + if (!ptr) upb_MtDecoder_ErrorFormat(d, "Out of memory"); +} -const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { - NULL, - &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, +// In each field's offset, we temporarily store a presence classifier: +enum PresenceClass { + kNoPresence = 0, + kHasbitPresence = 1, + kRequiredPresence = 2, + kOneofBase = 3, + // Negative values refer to a specific oneof with that number. Positive + // values >= kOneofBase indicate that this field is in a oneof, and specify + // the next field in this oneof's linked list. }; -static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_EnumValueOptions_msginit}, -}; +static const char* upb_MiniTable_DecodeBase92Varint(upb_MtDecoder* d, + const char* ptr, + char first_ch, uint8_t min, + uint8_t max, + uint32_t* out_val) { + uint32_t val = 0; + uint32_t shift = 0; + const int bits_per_char = + _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min)); + char ch = first_ch; + while (1) { + uint32_t bits = upb_FromBase92(ch) - upb_FromBase92(min); + UPB_ASSERT(shift < 32); + val |= bits << shift; + if (ptr == d->end || *ptr < min || max < *ptr) { + *out_val = val; + return ptr; + } + ch = *ptr++; + shift += bits_per_char; + } +} -static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(16, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +static bool upb_MiniTable_HasSub(upb_MiniTable_Field* field, + uint64_t msg_modifiers) { + switch (field->descriptortype) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + return true; + case kUpb_FieldType_String: + if (!(msg_modifiers & kUpb_MessageModifier_ValidateUtf8)) { + field->descriptortype = kUpb_FieldType_Bytes; + } + return false; + default: + return false; + } +} -const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit = { - &google_protobuf_EnumValueDescriptorProto_submsgs[0], - &google_protobuf_EnumValueDescriptorProto__fields[0], - UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, -}; +static bool upb_MtDecoder_FieldIsPackable(upb_MiniTable_Field* field) { + return (field->mode & kUpb_FieldMode_Array) && + upb_IsTypePackable(field->descriptortype); +} -static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { - {.submsg = &google_protobuf_MethodDescriptorProto_msginit}, - {.submsg = &google_protobuf_ServiceOptions_msginit}, -}; +static void upb_MiniTable_SetTypeAndSub(upb_MiniTable_Field* field, + upb_FieldType type, uint32_t* sub_count, + uint64_t msg_modifiers) { + field->descriptortype = type; + if (upb_MiniTable_HasSub(field, msg_modifiers)) { + field->submsg_index = sub_count ? (*sub_count)++ : 0; + } else { + field->submsg_index = kUpb_NoSub; + } -static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + if (upb_MtDecoder_FieldIsPackable(field) && + (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { + field->mode |= kUpb_LabelFlags_IsPacked; + } +} -const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit = { - &google_protobuf_ServiceDescriptorProto_submsgs[0], - &google_protobuf_ServiceDescriptorProto__fields[0], - UPB_SIZE(24, 48), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, -}; +static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, + upb_MiniTable_Field* field, + uint64_t msg_modifiers, + uint32_t* sub_count) { + static const char kUpb_EncodedToFieldRep[] = { + [kUpb_EncodedType_Double] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Float] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Int64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_UInt64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Int32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Fixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Fixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Bool] = kUpb_FieldRep_1Byte, + [kUpb_EncodedType_String] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_Group] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Message] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Bytes] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Enum] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_SInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SInt64] = kUpb_FieldRep_8Byte, + }; -static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { - {.submsg = &google_protobuf_MethodOptions_msginit}, -}; + static const char kUpb_EncodedToType[] = { + [kUpb_EncodedType_Double] = kUpb_FieldType_Double, + [kUpb_EncodedType_Float] = kUpb_FieldType_Float, + [kUpb_EncodedType_Int64] = kUpb_FieldType_Int64, + [kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64, + [kUpb_EncodedType_Int32] = kUpb_FieldType_Int32, + [kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64, + [kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32, + [kUpb_EncodedType_Bool] = kUpb_FieldType_Bool, + [kUpb_EncodedType_String] = kUpb_FieldType_String, + [kUpb_EncodedType_Group] = kUpb_FieldType_Group, + [kUpb_EncodedType_Message] = kUpb_FieldType_Message, + [kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes, + [kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32, + [kUpb_EncodedType_Enum] = kUpb_FieldType_Enum, + [kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32, + [kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64, + [kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32, + [kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64, + }; -static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 3, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(28, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(1, 1), 5, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(2, 2), 6, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, -}; + int8_t type = upb_FromBase92(ch); + if (ch >= upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { + type -= kUpb_EncodedType_RepeatedBase; + field->mode = kUpb_FieldMode_Array; + field->mode |= kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift; + field->offset = kNoPresence; + } else { + field->mode = kUpb_FieldMode_Scalar; + field->mode |= kUpb_EncodedToFieldRep[type] << kUpb_FieldRep_Shift; + field->offset = kHasbitPresence; + } + if (type >= 18) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); + } + upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_count, + msg_modifiers); +} -const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit = { - &google_protobuf_MethodDescriptorProto_submsgs[0], - &google_protobuf_MethodDescriptorProto__fields[0], - UPB_SIZE(32, 64), 6, kUpb_ExtMode_NonExtendable, 6, 255, 0, -}; +static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, + uint32_t message_modifiers, + uint32_t field_modifiers, + upb_MiniTable_Field* field) { + if (field_modifiers & kUpb_EncodedFieldModifier_FlipPacked) { + if (!upb_MtDecoder_FieldIsPackable(field)) { + upb_MtDecoder_ErrorFormat( + d, "Cannot flip packed on unpackable field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + field->mode ^= kUpb_LabelFlags_IsPacked; + } -static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_FileOptions_OptimizeMode_enuminit}, -}; + bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; + bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; -static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(20, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(4, 4), 3, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(8, 8), 4, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {11, UPB_SIZE(36, 56), 5, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {16, UPB_SIZE(9, 9), 6, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {17, UPB_SIZE(10, 10), 7, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {18, UPB_SIZE(11, 11), 8, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {20, UPB_SIZE(12, 12), 9, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {23, UPB_SIZE(13, 13), 10, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {27, UPB_SIZE(14, 14), 11, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {31, UPB_SIZE(15, 15), 12, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {36, UPB_SIZE(44, 72), 13, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {37, UPB_SIZE(52, 88), 14, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {39, UPB_SIZE(60, 104), 15, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {40, UPB_SIZE(68, 120), 16, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {41, UPB_SIZE(76, 136), 17, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {42, UPB_SIZE(16, 16), 18, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {44, UPB_SIZE(84, 152), 19, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {45, UPB_SIZE(92, 168), 20, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(100, 184), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + // Validate. + if ((singular || required) && field->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, "Invalid modifier(s) for repeated field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + if (singular && required) { + upb_MtDecoder_ErrorFormat( + d, "Field %" PRIu32 " cannot be both singular and required", + field->number); + UPB_UNREACHABLE(); + } -const upb_MiniTable google_protobuf_FileOptions_msginit = { - &google_protobuf_FileOptions_submsgs[0], - &google_protobuf_FileOptions__fields[0], - UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, 255, 0, -}; + if (singular) field->offset = kNoPresence; + if (required) { + field->offset = kRequiredPresence; + } +} -static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +static void upb_MtDecoder_PushItem(upb_MtDecoder* d, upb_LayoutItem item) { + if (d->vec.size == d->vec.capacity) { + size_t new_cap = UPB_MAX(8, d->vec.size * 2); + d->vec.data = realloc(d->vec.data, new_cap * sizeof(*d->vec.data)); + upb_MtDecoder_CheckOutOfMemory(d, d->vec.data); + d->vec.capacity = new_cap; + } + d->vec.data[d->vec.size++] = item; +} -static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(3, 3), 3, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(4, 4), 4, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(8, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +static void upb_MtDecoder_PushOneof(upb_MtDecoder* d, upb_LayoutItem item) { + if (item.field_index == kUpb_LayoutItem_IndexSentinel) { + upb_MtDecoder_ErrorFormat(d, "Empty oneof"); + UPB_UNREACHABLE(); + } + item.field_index -= kOneofBase; -const upb_MiniTable google_protobuf_MessageOptions_msginit = { - &google_protobuf_MessageOptions_submsgs[0], - &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(16, 16), 5, kUpb_ExtMode_Extendable, 3, 255, 0, -}; + // Push oneof data. + item.type = kUpb_LayoutItemType_OneofField; + upb_MtDecoder_PushItem(d, item); -static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_FieldOptions_CType_enuminit}, - {.subenum = &google_protobuf_FieldOptions_JSType_enuminit}, -}; + // Push oneof case. + item.rep = kUpb_FieldRep_4Byte; // Field Number. + item.type = kUpb_LayoutItemType_OneofCase; + upb_MtDecoder_PushItem(d, item); +} -static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[8] = { - {1, UPB_SIZE(4, 4), 1, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 12), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(13, 13), 3, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(14, 14), 4, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(15, 15), 6, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {15, UPB_SIZE(16, 16), 7, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(20, 24), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +size_t upb_MtDecoder_SizeOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToSize32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToSize64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 16, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(sizeof(upb_StringView) == + UPB_SIZE(kRepToSize32, kRepToSize64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToSize32[rep] + : kRepToSize64[rep]; +} + +size_t upb_MtDecoder_AlignOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToAlign32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 4, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToAlign64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(UPB_ALIGN_OF(upb_StringView) == + UPB_SIZE(kRepToAlign32, kRepToAlign64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToAlign32[rep] + : kRepToAlign64[rep]; +} + +static const char* upb_MtDecoder_DecodeOneofField(upb_MtDecoder* d, + const char* ptr, + char first_ch, + upb_LayoutItem* item) { + uint32_t field_num; + ptr = upb_MiniTable_DecodeBase92Varint( + d, ptr, first_ch, kUpb_EncodedValue_MinOneofField, + kUpb_EncodedValue_MaxOneofField, &field_num); + upb_MiniTable_Field* f = + (void*)upb_MiniTable_FindFieldByNumber(d->table, field_num); -const upb_MiniTable google_protobuf_FieldOptions_msginit = { - &google_protobuf_FieldOptions_submsgs[0], - &google_protobuf_FieldOptions__fields[0], - UPB_SIZE(24, 32), 8, kUpb_ExtMode_Extendable, 3, 255, 0, -}; + if (!f) { + upb_MtDecoder_ErrorFormat(d, + "Couldn't add field number %" PRIu32 + " to oneof, no such field number.", + field_num); + UPB_UNREACHABLE(); + } + if (f->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, + "Cannot add repeated, required, or singular field %" PRIu32 + " to oneof.", + field_num); + UPB_UNREACHABLE(); + } -static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; + // Oneof storage must be large enough to accommodate the largest member. + int rep = f->mode >> kUpb_FieldRep_Shift; + if (upb_MtDecoder_SizeOfRep(rep, d->platform) > + upb_MtDecoder_SizeOfRep(item->rep, d->platform)) { + item->rep = rep; + } + // Prepend this field to the linked list. + f->offset = item->field_index; + item->field_index = (f - d->fields) + kOneofBase; + return ptr; +} -static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +static const char* upb_MtDecoder_DecodeOneofs(upb_MtDecoder* d, + const char* ptr) { + upb_LayoutItem item = {.rep = 0, + .field_index = kUpb_LayoutItem_IndexSentinel}; + while (ptr < d->end) { + char ch = *ptr++; + if (ch == kUpb_EncodedValue_FieldSeparator) { + // Field separator, no action needed. + } else if (ch == kUpb_EncodedValue_OneofSeparator) { + // End of oneof. + upb_MtDecoder_PushOneof(d, item); + item.field_index = kUpb_LayoutItem_IndexSentinel; // Move to next oneof. + } else { + ptr = upb_MtDecoder_DecodeOneofField(d, ptr, ch, &item); + } + } -const upb_MiniTable google_protobuf_OneofOptions_msginit = { - &google_protobuf_OneofOptions_submsgs[0], - &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, -}; + // Push final oneof. + upb_MtDecoder_PushOneof(d, item); + return ptr; +} -static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, + const char* ptr, char first_ch, + upb_MiniTable_Field* last_field, + uint64_t* msg_modifiers) { + uint32_t mod; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, first_ch, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier, &mod); + if (last_field) { + upb_MtDecoder_ModifyField(d, *msg_modifiers, mod, last_field); + } else { + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have message modifiers"); + UPB_UNREACHABLE(); + } + *msg_modifiers = mod; + } -static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = { - {2, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + return ptr; +} -const upb_MiniTable google_protobuf_EnumOptions_msginit = { - &google_protobuf_EnumOptions_submsgs[0], - &google_protobuf_EnumOptions__fields[0], - UPB_SIZE(8, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, -}; +static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, uint32_t sub_count) { + size_t subs_bytes = sizeof(*d->table->subs) * sub_count; + d->table->subs = upb_Arena_Malloc(d->arena, subs_bytes); + upb_MtDecoder_CheckOutOfMemory(d, d->table->subs); +} -static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; +static void upb_MtDecoder_Parse(upb_MtDecoder* d, const char* ptr, size_t len, + void* fields, size_t field_size, + uint16_t* field_count, uint32_t* sub_count) { + uint64_t msg_modifiers = 0; + uint32_t last_field_number = 0; + upb_MiniTable_Field* last_field = NULL; + bool need_dense_below = d->table != NULL; -static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + d->end = UPB_PTRADD(ptr, len); -const upb_MiniTable google_protobuf_EnumValueOptions_msginit = { - &google_protobuf_EnumValueOptions_submsgs[0], - &google_protobuf_EnumValueOptions__fields[0], - UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 1, 255, 0, -}; + while (ptr < d->end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxField) { + upb_MiniTable_Field* field = fields; + *field_count += 1; + fields = (char*)fields + field_size; + field->number = ++last_field_number; + last_field = field; + upb_MiniTable_SetField(d, ch, field, msg_modifiers, sub_count); + } else if (kUpb_EncodedValue_MinModifier <= ch && + ch <= kUpb_EncodedValue_MaxModifier) { + ptr = upb_MtDecoder_ParseModifier(d, ptr, ch, last_field, &msg_modifiers); + if (msg_modifiers & kUpb_MessageModifier_IsExtendable) { + d->table->ext |= kUpb_ExtMode_Extendable; + } + } else if (ch == kUpb_EncodedValue_End) { + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have oneofs."); + UPB_UNREACHABLE(); + } + ptr = upb_MtDecoder_DecodeOneofs(d, ptr); + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + need_dense_below = false; + } + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + last_field_number += skip; + last_field_number--; // Next field seen will increment. + } + } + + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + } +} + +static void upb_MtDecoder_ParseMessage(upb_MtDecoder* d, const char* data, + size_t len) { + // Buffer length is an upper bound on the number of fields. We will return + // what we don't use. + d->fields = upb_Arena_Malloc(d->arena, sizeof(*d->fields) * len); + upb_MtDecoder_CheckOutOfMemory(d, d->fields); + + uint32_t sub_count = 0; + d->table->field_count = 0; + d->table->fields = d->fields; + upb_MtDecoder_Parse(d, data, len, d->fields, sizeof(*d->fields), + &d->table->field_count, &sub_count); + + upb_Arena_ShrinkLast(d->arena, d->fields, sizeof(*d->fields) * len, + sizeof(*d->fields) * d->table->field_count); + d->table->fields = d->fields; + upb_MtDecoder_AllocateSubs(d, sub_count); +} + +int upb_MtDecoder_CompareFields(const void* _a, const void* _b) { + const upb_LayoutItem* a = _a; + const upb_LayoutItem* b = _b; + // Currently we just sort by: + // 1. rep (smallest fields first) + // 2. type (oneof cases first) + // 2. field_index (smallest numbers first) + // The main goal of this is to reduce space lost to padding. + // Later we may have more subtle reasons to prefer a different ordering. + const int rep_bits = _upb_Log2Ceiling(kUpb_FieldRep_Max); + const int type_bits = _upb_Log2Ceiling(kUpb_LayoutItemType_Max); + const int idx_bits = (sizeof(a->field_index) * 8); + UPB_ASSERT(idx_bits + rep_bits + type_bits < 32); +#define UPB_COMBINE(rep, ty, idx) (((rep << type_bits) | ty) << idx_bits) | idx + uint32_t a_packed = UPB_COMBINE(a->rep, a->type, a->field_index); + uint32_t b_packed = UPB_COMBINE(b->rep, b->type, b->field_index); + assert(a_packed != b_packed); +#undef UPB_COMBINE + return a_packed < b_packed ? -1 : 1; +} + +static bool upb_MtDecoder_SortLayoutItems(upb_MtDecoder* d) { + // Add items for all non-oneof fields (oneofs were already added). + int n = d->table->field_count; + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* f = &d->fields[i]; + if (f->offset >= kOneofBase) continue; + upb_LayoutItem item = {.field_index = i, + .rep = f->mode >> kUpb_FieldRep_Shift, + .type = kUpb_LayoutItemType_Field}; + upb_MtDecoder_PushItem(d, item); + } + + if (d->vec.size) { + qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), + upb_MtDecoder_CompareFields); + } -static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, -}; + return true; +} -static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = { - {33, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { + return (n + d - 1) / d; +} -const upb_MiniTable google_protobuf_ServiceOptions_msginit = { - &google_protobuf_ServiceOptions_submsgs[0], - &google_protobuf_ServiceOptions__fields[0], - UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 0, 255, 0, -}; +static void upb_MtDecoder_AssignHasbits(upb_MiniTable* ret) { + int n = ret->field_count; + int last_hasbit = 0; // 0 cannot be used. -static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { - {.submsg = &google_protobuf_UninterpretedOption_msginit}, - {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enuminit}, -}; + // First assign required fields, which must have the lowest hasbits. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kRequiredPresence) { + field->presence = ++last_hasbit; + } else if (field->offset == kNoPresence) { + field->presence = 0; + } + } + ret->required_count = last_hasbit; -static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = { - {33, UPB_SIZE(8, 8), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {34, UPB_SIZE(4, 4), 2, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(12, 16), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + // Next assign non-required hasbit fields. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kHasbitPresence) { + field->presence = ++last_hasbit; + } + } -const upb_MiniTable google_protobuf_MethodOptions_msginit = { - &google_protobuf_MethodOptions_submsgs[0], - &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(16, 24), 3, kUpb_ExtMode_Extendable, 0, 255, 0, -}; + ret->size = last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; +} -static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { - {.submsg = &google_protobuf_UninterpretedOption_NamePart_msginit}, -}; +size_t upb_MtDecoder_Place(upb_MtDecoder* d, upb_FieldRep rep) { + size_t size = upb_MtDecoder_SizeOfRep(rep, d->platform); + size_t align = upb_MtDecoder_AlignOfRep(rep, d->platform); + size_t ret = UPB_ALIGN_UP(d->table->size, align); + d->table->size = ret + size; + return ret; +} -static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { - {2, UPB_SIZE(56, 80), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(32, 32), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 2, 0, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 16), 3, 0, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(24, 24), 4, 0, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(40, 48), 5, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(48, 64), 6, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, -}; +static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { + upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); -const upb_MiniTable google_protobuf_UninterpretedOption_msginit = { - &google_protobuf_UninterpretedOption_submsgs[0], - &google_protobuf_UninterpretedOption__fields[0], - UPB_SIZE(64, 96), 7, kUpb_ExtMode_NonExtendable, 0, 255, 0, -}; + // Compute offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + item->offset = upb_MtDecoder_Place(d, item->rep); + } -static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(1, 1), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, -}; + // Assign oneof case offsets. We must do these first, since assigning + // actual offsets will overwrite the links of the linked list. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + if (item->type != kUpb_LayoutItemType_OneofCase) continue; + upb_MiniTable_Field* f = &d->fields[item->field_index]; + while (true) { + f->presence = ~item->offset; + if (f->offset == kUpb_LayoutItem_IndexSentinel) break; + UPB_ASSERT(f->offset - kOneofBase < d->table->field_count); + f = &d->fields[f->offset - kOneofBase]; + } + } + + // Assign offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + upb_MiniTable_Field* f = &d->fields[item->field_index]; + switch (item->type) { + case kUpb_LayoutItemType_OneofField: + while (true) { + uint16_t next_offset = f->offset; + f->offset = item->offset; + if (next_offset == kUpb_LayoutItem_IndexSentinel) break; + f = &d->fields[next_offset - kOneofBase]; + } + break; + case kUpb_LayoutItemType_Field: + f->offset = item->offset; + break; + default: + break; + } + } -const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit = { - NULL, - &google_protobuf_UninterpretedOption_NamePart__fields[0], - UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 2, -}; + // The fasttable parser (supported on 64-bit only) depends on this being a + // multiple of 8 in order to satisfy UPB_MALLOC_ALIGN, which is also 8. + // + // On 32-bit we could potentially make this smaller, but there is no + // compelling reason to optimize this right now. + d->table->size = UPB_ALIGN_UP(d->table->size, 8); +} + +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, + upb_Status* status) { + upb_MtDecoder decoder = { + .platform = platform, + .vec = + { + .data = *buf, + .capacity = *buf_size / sizeof(*decoder.vec.data), + .size = 0, + }, + .arena = arena, + .status = status, + .table = upb_Arena_Malloc(arena, sizeof(*decoder.table)), + }; -static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { - {.submsg = &google_protobuf_SourceCodeInfo_Location_msginit}, -}; + if (UPB_SETJMP(decoder.err)) { + decoder.table = NULL; + goto done; + } -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table); -const upb_MiniTable google_protobuf_SourceCodeInfo_msginit = { - &google_protobuf_SourceCodeInfo_submsgs[0], - &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, -}; + decoder.table->size = 0; + decoder.table->field_count = 0; + decoder.table->ext = kUpb_ExtMode_NonExtendable; + decoder.table->dense_below = 0; + decoder.table->table_mask = -1; + decoder.table->required_count = 0; -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = { - {1, UPB_SIZE(20, 40), 0, 0, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(24, 48), 0, 0, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(28, 56), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; + upb_MtDecoder_ParseMessage(&decoder, data, len); + upb_MtDecoder_AssignHasbits(decoder.table); + upb_MtDecoder_SortLayoutItems(&decoder); + upb_MtDecoder_AssignOffsets(&decoder); -const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit = { - NULL, - &google_protobuf_SourceCodeInfo_Location__fields[0], - UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 4, 255, 0, -}; +done: + *buf = decoder.vec.data; + *buf_size = decoder.vec.capacity / sizeof(*decoder.vec.data); + return decoder.table; +} + +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + if (!ret) return NULL; + + ret->size = 0; + ret->field_count = 0; + ret->ext = kUpb_ExtMode_IsMessageSet; + ret->dense_below = 0; + ret->table_mask = -1; + ret->required_count = 0; + return ret; +} -static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { - {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msginit}, -}; +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + upb_MiniTable_Field* fields = upb_Arena_Malloc(arena, sizeof(*fields) * 2); + if (!ret || !fields) return NULL; + + upb_MiniTable_Sub* subs = NULL; + if (value_is_proto3_enum) value_type = kUpb_FieldType_Int32; + if (value_type == kUpb_FieldType_Message || + value_type == kUpb_FieldType_Group || value_type == kUpb_FieldType_Enum) { + subs = upb_Arena_Malloc(arena, sizeof(*subs)); + if (!subs) return NULL; + } + + size_t field_size = + upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, platform); + + fields[0].number = 1; + fields[1].number = 2; + fields[0].mode = kUpb_FieldMode_Scalar; + fields[1].mode = kUpb_FieldMode_Scalar; + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].offset = 0; + fields[1].offset = field_size; + + upb_MiniTable_SetTypeAndSub(&fields[0], key_type, NULL, 0); + upb_MiniTable_SetTypeAndSub(&fields[1], value_type, NULL, 0); + + ret->size = UPB_ALIGN_UP(2 * field_size, 8); + ret->field_count = 2; + ret->ext = kUpb_ExtMode_NonExtendable | kUpb_ExtMode_IsMapEntry; + ret->dense_below = 2; + ret->table_mask = -1; + ret->required_count = 0; + ret->subs = subs; + ret->fields = fields; + return ret; +} -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, -}; +static bool upb_MiniTable_BuildEnumValue(upb_MtDecoder* d, + upb_MiniTable_Enum* table, + uint32_t val, upb_Arena* arena) { + if (val < 64) { + table->mask |= 1ULL << val; + return true; + } -const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit = { - &google_protobuf_GeneratedCodeInfo_submsgs[0], - &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, -}; + int32_t* values = (void*)table->values; + values = upb_Arena_Realloc(arena, values, table->value_count * 4, + (table->value_count + 1) * 4); + upb_MtDecoder_CheckOutOfMemory(d, values); + values[table->value_count++] = (int32_t)val; + table->values = values; + return true; +} -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { - {1, UPB_SIZE(20, 32), 0, 0, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 16), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 3, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, -}; +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + upb_MtDecoder d = { + .status = status, + .end = UPB_PTRADD(data, len), + }; -const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit = { - NULL, - &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], - UPB_SIZE(24, 48), 4, kUpb_ExtMode_NonExtendable, 4, 255, 0, -}; + if (UPB_SETJMP(d.err)) { + return NULL; + } -static const upb_MiniTable *messages_layout[27] = { - &google_protobuf_FileDescriptorSet_msginit, - &google_protobuf_FileDescriptorProto_msginit, - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_DescriptorProto_ExtensionRange_msginit, - &google_protobuf_DescriptorProto_ReservedRange_msginit, - &google_protobuf_ExtensionRangeOptions_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_OneofDescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, - &google_protobuf_EnumValueDescriptorProto_msginit, - &google_protobuf_ServiceDescriptorProto_msginit, - &google_protobuf_MethodDescriptorProto_msginit, - &google_protobuf_FileOptions_msginit, - &google_protobuf_MessageOptions_msginit, - &google_protobuf_FieldOptions_msginit, - &google_protobuf_OneofOptions_msginit, - &google_protobuf_EnumOptions_msginit, - &google_protobuf_EnumValueOptions_msginit, - &google_protobuf_ServiceOptions_msginit, - &google_protobuf_MethodOptions_msginit, - &google_protobuf_UninterpretedOption_msginit, - &google_protobuf_UninterpretedOption_NamePart_msginit, - &google_protobuf_SourceCodeInfo_msginit, - &google_protobuf_SourceCodeInfo_Location_msginit, - &google_protobuf_GeneratedCodeInfo_msginit, - &google_protobuf_GeneratedCodeInfo_Annotation_msginit, -}; + upb_MiniTable_Enum* table = upb_Arena_Malloc(arena, sizeof(*table)); + upb_MtDecoder_CheckOutOfMemory(&d, table); -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit = { - NULL, - 0x7fffeULL, - 0, -}; + table->mask = 0; + table->value_count = 0; + table->values = NULL; -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit = { - NULL, - 0xeULL, - 0, -}; + const char* ptr = data; + uint32_t base = 0; -const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit = { - NULL, - 0xeULL, - 0, -}; + while (ptr < d.end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxEnumMask) { + uint32_t mask = upb_FromBase92(ch); + for (int i = 0; i < 5; i++, base++, mask >>= 1) { + if (mask & 1) { + if (!upb_MiniTable_BuildEnumValue(&d, table, base, arena)) { + return NULL; + } + } + } + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(&d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + base += skip; + } else { + upb_Status_SetErrorFormat(status, "Unexpected character: %c", ch); + return NULL; + } + } -const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit = { - NULL, - 0x7ULL, - 0, -}; + return table; +} -const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit = { - NULL, - 0x7ULL, - 0, -}; +bool upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + upb_MiniTable_Sub sub, upb_Status* status) { + upb_MtDecoder decoder = { + .arena = NULL, + .status = status, + .table = NULL, + }; -const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit = { - NULL, - 0x7ULL, - 0, -}; + if (UPB_SETJMP(decoder.err)) { + return false; + } -static const upb_MiniTable_Enum *enums_layout[6] = { - &google_protobuf_FieldDescriptorProto_Type_enuminit, - &google_protobuf_FieldDescriptorProto_Label_enuminit, - &google_protobuf_FileOptions_OptimizeMode_enuminit, - &google_protobuf_FieldOptions_CType_enuminit, - &google_protobuf_FieldOptions_JSType_enuminit, - &google_protobuf_MethodOptions_IdempotencyLevel_enuminit, -}; + uint16_t count = 0; + upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); + ext->field.mode |= kUpb_LabelFlags_IsExtension; + ext->field.offset = 0; + return true; +} -const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { - messages_layout, - enums_layout, - NULL, - 27, - 6, - 0, -}; +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status) { + void* buf = NULL; + size_t size = 0; + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf(data, len, platform, arena, + &buf, &size, status); + free(buf); + return ret; +} +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + if (sub->ext & kUpb_ExtMode_IsMapEntry) { + field->mode = + (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift) | kUpb_FieldMode_Map; + } + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->submsg = sub; +} +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->subenum = sub; +} /** upb/def.c ************************************************************/ @@ -5254,13 +5454,17 @@ struct upb_MessageDef { const upb_FieldDef* fields; const upb_OneofDef* oneofs; const upb_ExtensionRange* ext_ranges; + const upb_StringView* res_names; const upb_MessageDef* nested_msgs; + const upb_MessageReservedRange* res_ranges; const upb_EnumDef* nested_enums; const upb_FieldDef* nested_exts; int field_count; int real_oneof_count; int oneof_count; int ext_range_count; + int res_range_count; + int res_name_count; int nested_msg_count; int nested_enum_count; int nested_ext_count; @@ -5280,7 +5484,11 @@ struct upb_EnumDef { upb_strtable ntoi; upb_inttable iton; const upb_EnumValueDef* values; + const upb_EnumReservedRange* res_ranges; + const upb_StringView* res_names; int value_count; + int res_range_count; + int res_name_count; int32_t defaultval; #if UINTPTR_MAX == 0xffffffff uint32_t padding; // Increase size to a multiple of 8. @@ -5386,6 +5594,24 @@ typedef enum { #define FIELD_TYPE_UNSPECIFIED 0 +struct upb_MessageReservedRange { + int32_t start; + int32_t end; +}; + +struct symtab_addctx { + upb_DefPool* symtab; + upb_FileDef* file; /* File we are building. */ + upb_Arena* arena; /* Allocate defs here. */ + upb_Arena* tmp_arena; /* For temporary allocations. */ + const upb_MiniTable_File* layout; /* NULL if we should build layouts. */ + int enum_count; /* Count of enums built so far. */ + int msg_count; /* Count of messages built so far. */ + int ext_count; /* Count of extensions built so far. */ + upb_Status* status; /* Record errors here. */ + jmp_buf err; /* longjmp() on error. */ +}; + static upb_deftype_t deftype(upb_value v) { uintptr_t num = (uintptr_t)upb_value_getconstptr(v); return num & UPB_DEFTYPE_MASK; @@ -5533,15 +5759,94 @@ const char* upb_EnumDef_Name(const upb_EnumDef* e) { return shortdefname(e->full_name); } -const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } + +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { + return e->containing_type; +} + +int32_t upb_EnumDef_Default(const upb_EnumDef* e) { + UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); + return e->defaultval; +} + +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e) { + return e->res_range_count; +} + +/* upb_EnumReservedRange ******************************************************/ + +struct upb_EnumReservedRange { + int32_t start; + int32_t end; +}; + +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i) { + return (upb_EnumReservedRange*)&r[i]; +} + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r) { + return r->start; +} +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r) { + return r->end; +} + +UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3) static void symtab_errf( + symtab_addctx* ctx, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(ctx->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(ctx->err, 1); +} + +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + symtab_addctx* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e) { + upb_EnumReservedRange* r = + upb_Arena_Malloc(ctx->arena, sizeof(upb_EnumReservedRange) * n); + + for (int i = 0; i < n; i++) { + const int32_t start = + google_protobuf_EnumDescriptorProto_EnumReservedRange_start(protos[i]); + const int32_t end = + google_protobuf_EnumDescriptorProto_EnumReservedRange_end(protos[i]); + const int32_t max = kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + + // Note: Not a typo! Unlike extension ranges and message reserved ranges, + // the end value of an enum reserved range is *inclusive*! + if (start < 1 || end < start || end > max) { + symtab_errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", + (int)start, (int)end, upb_EnumDef_FullName(e)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i) { + UPB_ASSERT(0 <= i && i < e->res_range_count); + return _upb_EnumReservedRange_At(e->res_ranges, i); +} -const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { - return e->containing_type; +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e) { + return e->res_name_count; } -int32_t upb_EnumDef_Default(const upb_EnumDef* e) { - UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); - return e->defaultval; +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->res_name_count); + return e->res_names[i]; } int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } @@ -5884,5197 +6189,6306 @@ const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( return NULL; } - return unpack_def(val, UPB_DEFTYPE_ONEOF); + return unpack_def(val, UPB_DEFTYPE_ONEOF); +} + +bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, + const char* name, size_t len, + const upb_FieldDef** out_f, + const upb_OneofDef** out_o) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; + } + + const upb_FieldDef* f = unpack_def(val, UPB_DEFTYPE_FIELD); + const upb_OneofDef* o = unpack_def(val, UPB_DEFTYPE_ONEOF); + if (out_f) *out_f = f; + if (out_o) *out_o = o; + return f || o; /* False if this was a JSON name. */ +} + +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t len) { + upb_value val; + const upb_FieldDef* f; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return NULL; + } + + f = unpack_def(val, UPB_DEFTYPE_FIELD); + if (!f) f = unpack_def(val, UPB_DEFTYPE_FIELD_JSONNAME); + + return f; +} + +int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; } + +int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; } + +int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) { + return m->real_oneof_count; +} + +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { + return m->ext_range_count; +} + +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m) { + return m->res_range_count; +} + +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m) { + return m->res_name_count; +} + +int upb_MessageDef_FieldCount(const upb_MessageDef* m) { + return m->field_count; +} + +int upb_MessageDef_OneofCount(const upb_MessageDef* m) { + return m->oneof_count; +} + +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { + return m->nested_msg_count; +} + +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { + return m->nested_enum_count; +} + +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { + return m->nested_ext_count; +} + +int upb_MessageDef_realoneofcount(const upb_MessageDef* m) { + return m->real_oneof_count; +} + +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { + return m->layout; +} + +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->ext_range_count); + return &m->ext_ranges[i]; +} + +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i) { + return (upb_MessageReservedRange*)&r[i]; +} + +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_range_count); + return _upb_MessageReservedRange_At(m->res_ranges, i); +} + +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_name_count); + return m->res_names[i]; +} + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r) { + return r->start; +} +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r) { + return r->end; +} + +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + symtab_addctx* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m) { + upb_MessageReservedRange* r = + upb_Arena_Malloc(ctx->arena, sizeof(upb_MessageReservedRange) * n); + + for (int i = 0; i < n; i++) { + const int32_t start = google_protobuf_DescriptorProto_ReservedRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ReservedRange_end(protos[i]); + const int32_t max = kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + symtab_errf(ctx, + "Reserved range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} + +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->field_count); + return &m->fields[i]; +} + +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->oneof_count); + return &m->oneofs[i]; +} + +const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_msg_count); + return &m->nested_msgs[i]; +} + +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->nested_enum_count); + return &m->nested_enums[i]; +} + +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_ext_count); + return &m->nested_exts[i]; +} + +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { + return m->well_known_type; +} + +/* upb_OneofDef ***************************************************************/ + +const google_protobuf_OneofOptions* upb_OneofDef_Options( + const upb_OneofDef* o) { + return o->opts; +} + +bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { + return o->opts != (void*)opt_default; +} + +const char* upb_OneofDef_Name(const upb_OneofDef* o) { + return shortdefname(o->full_name); +} + +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { + return o->parent; +} + +int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } + +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; +} + +int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } + +uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { + // Compute index in our parent's array. + return o - o->parent->oneofs; +} + +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } + +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t length) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, length, &val) + ? upb_value_getptr(val) + : NULL; +} + +const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, + uint32_t num) { + upb_value val; + return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) + : NULL; +} + +/* upb_FileDef ****************************************************************/ + +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { + return f->opts; +} + +bool upb_FileDef_HasOptions(const upb_FileDef* f) { + return f->opts != (void*)opt_default; +} + +const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } + +const char* upb_FileDef_Package(const upb_FileDef* f) { + return f->package ? f->package : ""; +} + +upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } + +int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { + return f->top_lvl_msg_count; +} + +int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } + +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { + return f->public_dep_count; +} + +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { + return f->weak_dep_count; +} + +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { + return f->public_deps; +} + +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { + return f->weak_deps; +} + +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { + return f->top_lvl_enum_count; +} + +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { + return f->top_lvl_ext_count; +} + +int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } + +const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->dep_count); + return f->deps[i]; +} + +const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->public_deps[i]]; +} + +const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->public_dep_count); + return f->deps[f->weak_deps[i]]; } -bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, - const char* name, size_t len, - const upb_FieldDef** out_f, - const upb_OneofDef** out_o) { - upb_value val; +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); + return &f->top_lvl_msgs[i]; +} - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return false; - } +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); + return &f->top_lvl_enums[i]; +} - const upb_FieldDef* f = unpack_def(val, UPB_DEFTYPE_FIELD); - const upb_OneofDef* o = unpack_def(val, UPB_DEFTYPE_ONEOF); - if (out_f) *out_f = f; - if (out_o) *out_o = o; - return f || o; /* False if this was a JSON name. */ +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); + return &f->top_lvl_exts[i]; } -const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( - const upb_MessageDef* m, const char* name, size_t len) { - upb_value val; - const upb_FieldDef* f; +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->service_count); + return &f->services[i]; +} - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; - } +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } - f = unpack_def(val, UPB_DEFTYPE_FIELD); - if (!f) f = unpack_def(val, UPB_DEFTYPE_FIELD_JSONNAME); +/* upb_MethodDef **************************************************************/ - return f; +const google_protobuf_MethodOptions* upb_MethodDef_Options( + const upb_MethodDef* m) { + return m->opts; } -int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; } - -int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; } - -int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) { - return m->real_oneof_count; +bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { + return m->opts != (void*)opt_default; } -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { - return m->ext_range_count; +const char* upb_MethodDef_FullName(const upb_MethodDef* m) { + return m->full_name; } -int upb_MessageDef_FieldCount(const upb_MessageDef* m) { - return m->field_count; +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } + +const char* upb_MethodDef_Name(const upb_MethodDef* m) { + return shortdefname(m->full_name); } -int upb_MessageDef_OneofCount(const upb_MessageDef* m) { - return m->oneof_count; +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { + return m->service; } -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { - return m->nested_msg_count; +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { + return m->input_type; } -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { - return m->nested_enum_count; +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { + return m->output_type; } -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { - return m->nested_ext_count; +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { + return m->client_streaming; } -int upb_MessageDef_realoneofcount(const upb_MessageDef* m) { - return m->real_oneof_count; +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { + return m->server_streaming; } -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { - return m->layout; +/* upb_ServiceDef *************************************************************/ + +const google_protobuf_ServiceOptions* upb_ServiceDef_Options( + const upb_ServiceDef* s) { + return s->opts; } -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->ext_range_count); - return &m->ext_ranges[i]; +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { + return s->opts != (void*)opt_default; } -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->field_count); - return &m->fields[i]; +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { + return s->full_name; } -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->oneof_count); - return &m->oneofs[i]; +const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { + return shortdefname(s->full_name); } -const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_msg_count); - return &m->nested_msgs[i]; +int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } + +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { + return s->file; } -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->nested_enum_count); - return &m->nested_enums[i]; +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { + return s->method_count; } -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_ext_count); - return &m->nested_exts[i]; +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { + return i < 0 || i >= s->method_count ? NULL : &s->methods[i]; } -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { - return m->well_known_type; +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name) { + for (int i = 0; i < s->method_count; i++) { + if (strcmp(name, upb_MethodDef_Name(&s->methods[i])) == 0) { + return &s->methods[i]; + } + } + return NULL; } -/* upb_OneofDef ***************************************************************/ +/* upb_DefPool ****************************************************************/ -const google_protobuf_OneofOptions* upb_OneofDef_Options( - const upb_OneofDef* o) { - return o->opts; +void upb_DefPool_Free(upb_DefPool* s) { + upb_Arena_Free(s->arena); + upb_gfree(s); } -bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { - return o->opts != (void*)opt_default; -} +upb_DefPool* upb_DefPool_New(void) { + upb_DefPool* s = upb_gmalloc(sizeof(*s)); -const char* upb_OneofDef_Name(const upb_OneofDef* o) { - return shortdefname(o->full_name); + if (!s) { + return NULL; + } + + s->arena = upb_Arena_New(); + s->bytes_loaded = 0; + + if (!upb_strtable_init(&s->syms, 32, s->arena) || + !upb_strtable_init(&s->files, 4, s->arena) || + !upb_inttable_init(&s->exts, s->arena)) { + goto err; + } + + s->extreg = upb_ExtensionRegistry_New(s->arena); + if (!s->extreg) goto err; + return s; + +err: + upb_Arena_Free(s->arena); + upb_gfree(s); + return NULL; } -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { - return o->parent; +static const void* symtab_lookup(const upb_DefPool* s, const char* sym, + upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup(&s->syms, sym, &v) ? unpack_def(v, type) : NULL; } -int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } +static const void* symtab_lookup2(const upb_DefPool* s, const char* sym, + size_t size, upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup2(&s->syms, sym, size, &v) ? unpack_def(v, type) + : NULL; +} -const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { - UPB_ASSERT(i < o->field_count); - return o->fields[i]; +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym) { + return symtab_lookup(s, sym, UPB_DEFTYPE_MSG); } -int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return symtab_lookup2(s, sym, len, UPB_DEFTYPE_MSG); +} -uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { - // Compute index in our parent's array. - return o - o->parent->oneofs; +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym) { + return symtab_lookup(s, sym, UPB_DEFTYPE_ENUM); } -bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym) { + return symtab_lookup(s, sym, UPB_DEFTYPE_ENUMVAL); +} -const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, - const char* name, - size_t length) { - upb_value val; - return upb_strtable_lookup2(&o->ntof, name, length, &val) - ? upb_value_getptr(val) +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) + ? unpack_def(v, UPB_DEFTYPE_FILE) : NULL; } -const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, - uint32_t num) { - upb_value val; - return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) - : NULL; +const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, + const char* name, + size_t len) { + upb_value v; + return upb_strtable_lookup2(&s->files, name, len, &v) + ? unpack_def(v, UPB_DEFTYPE_FILE) + : NULL; } -/* upb_FileDef ****************************************************************/ +const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + upb_value v; + if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; -const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { - return f->opts; + switch (deftype(v)) { + case UPB_DEFTYPE_FIELD: + return unpack_def(v, UPB_DEFTYPE_FIELD); + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); + return m->in_message_set ? &m->nested_exts[0] : NULL; + } + default: + break; + } + + return NULL; +} + +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); } -bool upb_FileDef_HasOptions(const upb_FileDef* f) { - return f->opts != (void*)opt_default; +const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name) { + return symtab_lookup(s, name, UPB_DEFTYPE_SERVICE); } -const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + return symtab_lookup2(s, name, size, UPB_DEFTYPE_SERVICE); +} -const char* upb_FileDef_Package(const upb_FileDef* f) { return f->package; } +const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, + const char* name) { + upb_value v; + // TODO(haberman): non-extension fields and oneofs. + if (upb_strtable_lookup(&s->syms, name, &v)) { + switch (deftype(v)) { + case UPB_DEFTYPE_EXT: { + const upb_FieldDef* f = unpack_def(v, UPB_DEFTYPE_EXT); + return upb_FieldDef_File(f); + } + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); + return upb_MessageDef_File(m); + } + case UPB_DEFTYPE_ENUM: { + const upb_EnumDef* e = unpack_def(v, UPB_DEFTYPE_ENUM); + return upb_EnumDef_File(e); + } + case UPB_DEFTYPE_ENUMVAL: { + const upb_EnumValueDef* ev = unpack_def(v, UPB_DEFTYPE_ENUMVAL); + return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); + } + case UPB_DEFTYPE_SERVICE: { + const upb_ServiceDef* service = unpack_def(v, UPB_DEFTYPE_SERVICE); + return upb_ServiceDef_File(service); + } + default: + UPB_UNREACHABLE(); + } + } -upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } + const char* last_dot = strrchr(name, '.'); + if (last_dot) { + const upb_MessageDef* parent = + upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); + if (parent) { + const char* shortname = last_dot + 1; + if (upb_MessageDef_FindByNameWithSize(parent, shortname, + strlen(shortname), NULL, NULL)) { + return upb_MessageDef_File(parent); + } + } + } -int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { - return f->top_lvl_msg_count; + return NULL; } -int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } +/* Code to build defs from descriptor protos. *********************************/ -int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { - return f->public_dep_count; -} +/* There is a question of how much validation to do here. It will be difficult + * to perfectly match the amount of validation performed by proto2. But since + * this code is used to directly build defs from Ruby (for example) we do need + * to validate important constraints like uniqueness of names and numbers. */ -int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { - return f->weak_dep_count; -} +#define CHK_OOM(x) \ + if (!(x)) { \ + symtab_oomerr(ctx); \ + } -const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { - return f->public_deps; +UPB_NORETURN UPB_NOINLINE static void symtab_oomerr(symtab_addctx* ctx) { + upb_Status_setoom(ctx->status); + UPB_LONGJMP(ctx->err, 1); } -const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { - return f->weak_deps; +void* symtab_alloc(symtab_addctx* ctx, size_t bytes) { + if (bytes == 0) return NULL; + void* ret = upb_Arena_Malloc(ctx->arena, bytes); + if (!ret) symtab_oomerr(ctx); + return ret; } -int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { - return f->top_lvl_enum_count; -} +// We want to copy the options verbatim into the destination options proto. +// We use serialize+parse as our deep copy. +#define SET_OPTIONS(target, desc_type, options_type, proto) \ + if (google_protobuf_##desc_type##_has_options(proto)) { \ + size_t size; \ + char* pb = google_protobuf_##options_type##_serialize( \ + google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ + CHK_OOM(pb); \ + target = google_protobuf_##options_type##_parse(pb, size, ctx->arena); \ + CHK_OOM(target); \ + } else { \ + target = (const google_protobuf_##options_type*)opt_default; \ + } -int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { - return f->top_lvl_ext_count; +static void check_ident(symtab_addctx* ctx, upb_StringView name, bool full) { + const char* str = name.data; + size_t len = name.size; + bool start = true; + size_t i; + for (i = 0; i < len; i++) { + char c = str[i]; + if (c == '.') { + if (start || !full) { + symtab_errf(ctx, "invalid name: unexpected '.' (%.*s)", (int)len, str); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + symtab_errf( + ctx, + "invalid name: path components must start with a letter (%.*s)", + (int)len, str); + } + start = false; + } else { + if (!upb_isalphanum(c)) { + symtab_errf(ctx, "invalid name: non-alphanumeric character (%.*s)", + (int)len, str); + } + } + } + if (start) { + symtab_errf(ctx, "invalid name: empty part (%.*s)", (int)len, str); + } } -int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } +static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } -const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->dep_count); - return f->deps[i]; +static size_t upb_MessageValue_sizeof(upb_CType type) { + switch (type) { + case kUpb_CType_Double: + case kUpb_CType_Int64: + case kUpb_CType_UInt64: + return 8; + case kUpb_CType_Enum: + case kUpb_CType_Int32: + case kUpb_CType_UInt32: + case kUpb_CType_Float: + return 4; + case kUpb_CType_Bool: + return 1; + case kUpb_CType_Message: + return sizeof(void*); + case kUpb_CType_Bytes: + case kUpb_CType_String: + return sizeof(upb_StringView); + } + UPB_UNREACHABLE(); } -const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->public_dep_count); - return f->deps[f->public_deps[i]]; +static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) { + if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { + upb_MapEntry ent; + UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); + return sizeof(ent.k); + } else if (upb_FieldDef_IsRepeated(f)) { + return sizeof(void*); + } else { + return upb_MessageValue_sizeof(upb_FieldDef_CType(f)); + } } -const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->public_dep_count); - return f->deps[f->weak_deps[i]]; -} +static uint32_t upb_MiniTable_place(symtab_addctx* ctx, upb_MiniTable* l, + size_t size, const upb_MessageDef* m) { + size_t ofs = UPB_ALIGN_UP(l->size, size); + size_t next = ofs + size; -const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); - return &f->top_lvl_msgs[i]; + if (next > UINT16_MAX) { + symtab_errf(ctx, "size of message %s exceeded max size of %zu bytes", + upb_MessageDef_FullName(m), (size_t)UINT16_MAX); + } + + l->size = next; + return ofs; } -const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); - return &f->top_lvl_enums[i]; +static int field_number_cmp(const void* p1, const void* p2) { + const upb_MiniTable_Field* f1 = p1; + const upb_MiniTable_Field* f2 = p2; + return f1->number - f2->number; } -const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); - return &f->top_lvl_exts[i]; +static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l, + upb_MiniTable_Field* fields) { + int i; + int n = upb_MessageDef_numfields(m); + int dense_below = 0; + for (i = 0; i < n; i++) { + upb_FieldDef* f = + (upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number); + UPB_ASSERT(f); + f->layout_index = i; + if (i < UINT8_MAX && fields[i].number == i + 1 && + (i == 0 || fields[i - 1].number == i)) { + dense_below = i + 1; + } + } + l->dense_below = dense_below; } -const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->service_count); - return &f->services[i]; +static uint8_t map_descriptortype(const upb_FieldDef* f) { + uint8_t type = upb_FieldDef_Type(f); + /* See TableDescriptorType() in upbc/generator.cc for details and + * rationale of these exceptions. */ + if (type == kUpb_FieldType_String && f->file->syntax == kUpb_Syntax_Proto2) { + return kUpb_FieldType_Bytes; + } else if (type == kUpb_FieldType_Enum && + (f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3 || + UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 || + // TODO(https://github.com/protocolbuffers/upb/issues/541): + // fix map enum values to check for unknown enum values and put + // them in the unknown field set. + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)))) { + return kUpb_FieldType_Int32; + } + return type; } -const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } +static void fill_fieldlayout(upb_MiniTable_Field* field, + const upb_FieldDef* f) { + field->number = upb_FieldDef_Number(f); + field->descriptortype = map_descriptortype(f); -/* upb_MethodDef **************************************************************/ + if (upb_FieldDef_IsMap(f)) { + field->mode = + kUpb_FieldMode_Map | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); + } else if (upb_FieldDef_IsRepeated(f)) { + field->mode = + kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); + } else { + /* Maps descriptor type -> elem_size_lg2. */ + static const uint8_t sizes[] = { + -1, /* invalid descriptor type */ + kUpb_FieldRep_8Byte, /* DOUBLE */ + kUpb_FieldRep_4Byte, /* FLOAT */ + kUpb_FieldRep_8Byte, /* INT64 */ + kUpb_FieldRep_8Byte, /* UINT64 */ + kUpb_FieldRep_4Byte, /* INT32 */ + kUpb_FieldRep_8Byte, /* FIXED64 */ + kUpb_FieldRep_4Byte, /* FIXED32 */ + kUpb_FieldRep_1Byte, /* BOOL */ + kUpb_FieldRep_StringView, /* STRING */ + kUpb_FieldRep_Pointer, /* GROUP */ + kUpb_FieldRep_Pointer, /* MESSAGE */ + kUpb_FieldRep_StringView, /* BYTES */ + kUpb_FieldRep_4Byte, /* UINT32 */ + kUpb_FieldRep_4Byte, /* ENUM */ + kUpb_FieldRep_4Byte, /* SFIXED32 */ + kUpb_FieldRep_8Byte, /* SFIXED64 */ + kUpb_FieldRep_4Byte, /* SINT32 */ + kUpb_FieldRep_8Byte, /* SINT64 */ + }; + field->mode = kUpb_FieldMode_Scalar | + (sizes[field->descriptortype] << kUpb_FieldRep_Shift); + } -const google_protobuf_MethodOptions* upb_MethodDef_Options( - const upb_MethodDef* m) { - return m->opts; -} + if (upb_FieldDef_IsPacked(f)) { + field->mode |= kUpb_LabelFlags_IsPacked; + } -bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { - return m->opts != (void*)opt_default; + if (upb_FieldDef_IsExtension(f)) { + field->mode |= kUpb_LabelFlags_IsExtension; + } } -const char* upb_MethodDef_FullName(const upb_MethodDef* m) { - return m->full_name; -} +/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. + * It computes a dynamic layout for all of the fields in |m|. */ +static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { + upb_MiniTable* l = (upb_MiniTable*)m->layout; + size_t field_count = upb_MessageDef_numfields(m); + size_t sublayout_count = 0; + upb_MiniTable_Sub* subs; + upb_MiniTable_Field* fields; -int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } + memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry)); -const char* upb_MethodDef_Name(const upb_MethodDef* m) { - return shortdefname(m->full_name); -} + /* Count sub-messages. */ + for (size_t i = 0; i < field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + if (upb_FieldDef_IsSubMessage(f)) { + sublayout_count++; + } + if (upb_FieldDef_CType(f) == kUpb_CType_Enum && + f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2) { + sublayout_count++; + } + } -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { - return m->service; -} + fields = symtab_alloc(ctx, field_count * sizeof(*fields)); + subs = symtab_alloc(ctx, sublayout_count * sizeof(*subs)); -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { - return m->input_type; -} + l->field_count = upb_MessageDef_numfields(m); + l->fields = fields; + l->subs = subs; + l->table_mask = 0; + l->required_count = 0; -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { - return m->output_type; -} + if (upb_MessageDef_ExtensionRangeCount(m) > 0) { + if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { + l->ext = kUpb_ExtMode_IsMessageSet; + } else { + l->ext = kUpb_ExtMode_Extendable; + } + } else { + l->ext = kUpb_ExtMode_NonExtendable; + } -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { - return m->client_streaming; -} + /* TODO(haberman): initialize fast tables so that reflection-based parsing + * can get the same speeds as linked-in types. */ + l->fasttable[0].field_parser = &fastdecode_generic; + l->fasttable[0].field_data = 0; -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { - return m->server_streaming; -} + if (upb_MessageDef_IsMapEntry(m)) { + /* TODO(haberman): refactor this method so this special case is more + * elegant. */ + const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2); + if (key == NULL || val == NULL) { + symtab_errf(ctx, "Malformed map entry from message: %s", + upb_MessageDef_FullName(m)); + } + fields[0].number = 1; + fields[1].number = 2; + fields[0].mode = kUpb_FieldMode_Scalar; + fields[1].mode = kUpb_FieldMode_Scalar; + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].descriptortype = map_descriptortype(key); + fields[1].descriptortype = map_descriptortype(val); + fields[0].offset = 0; + fields[1].offset = sizeof(upb_StringView); + fields[1].submsg_index = 0; -/* upb_ServiceDef *************************************************************/ + if (upb_FieldDef_CType(val) == kUpb_CType_Message) { + subs[0].submsg = upb_FieldDef_MessageSubDef(val)->layout; + } -const google_protobuf_ServiceOptions* upb_ServiceDef_Options( - const upb_ServiceDef* s) { - return s->opts; -} + upb_FieldDef* fielddefs = (upb_FieldDef*)&m->fields[0]; + UPB_ASSERT(fielddefs[0].number_ == 1); + UPB_ASSERT(fielddefs[1].number_ == 2); + fielddefs[0].layout_index = 0; + fielddefs[1].layout_index = 1; -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { - return s->opts != (void*)opt_default; -} + l->field_count = 2; + l->size = 2 * sizeof(upb_StringView); + l->size = UPB_ALIGN_UP(l->size, 8); + l->dense_below = 2; + return; + } -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { - return s->full_name; -} + /* 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. + */ -const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { - return shortdefname(s->full_name); -} + /* Assign hasbits for required fields first. */ + size_t hasbit = 0; -int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; + if (upb_FieldDef_Label(f) == kUpb_Label_Required) { + field->presence = ++hasbit; + if (hasbit >= 63) { + symtab_errf(ctx, "Message with >=63 required fields: %s", + upb_MessageDef_FullName(m)); + } + l->required_count++; + } + } -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { - return s->file; -} + /* Allocate hasbits and set basic field attributes. */ + sublayout_count = 0; + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { - return s->method_count; -} + fill_fieldlayout(field, f); -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { - return i < 0 || i >= s->method_count ? NULL : &s->methods[i]; -} + if (field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group) { + field->submsg_index = sublayout_count++; + subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout; + } else if (field->descriptortype == kUpb_FieldType_Enum) { + field->submsg_index = sublayout_count++; + subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout; + UPB_ASSERT(subs[field->submsg_index].subenum); + } -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name) { - for (int i = 0; i < s->method_count; i++) { - if (strcmp(name, upb_MethodDef_Name(&s->methods[i])) == 0) { - return &s->methods[i]; + if (upb_FieldDef_Label(f) == kUpb_Label_Required) { + /* Hasbit was already assigned. */ + } else if (upb_FieldDef_HasPresence(f) && + !upb_FieldDef_RealContainingOneof(f)) { + /* We don't use hasbit 0, so that 0 can indicate "no presence" in the + * table. This wastes one hasbit, but we don't worry about it for now. */ + field->presence = ++hasbit; + } else { + field->presence = 0; } } - return NULL; -} -/* upb_DefPool ****************************************************************/ + /* Account for space used by hasbits. */ + l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0; -void upb_DefPool_Free(upb_DefPool* s) { - upb_Arena_Free(s->arena); - upb_gfree(s); -} + /* Allocate non-oneof fields. */ + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + size_t field_size = upb_msg_fielddefsize(f); + size_t index = upb_FieldDef_Index(f); -upb_DefPool* upb_DefPool_New(void) { - upb_DefPool* s = upb_gmalloc(sizeof(*s)); + if (upb_FieldDef_RealContainingOneof(f)) { + /* Oneofs are handled separately below. */ + continue; + } - if (!s) { - return NULL; + fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m); } - s->arena = upb_Arena_New(); - s->bytes_loaded = 0; - - if (!upb_strtable_init(&s->syms, 32, s->arena) || - !upb_strtable_init(&s->files, 4, s->arena) || - !upb_inttable_init(&s->exts, s->arena)) { - goto err; - } + /* Allocate oneof fields. Each oneof field consists of a uint32 for the case + * and space for the actual data. */ + for (int i = 0; i < m->oneof_count; i++) { + const upb_OneofDef* o = &m->oneofs[i]; + size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ + size_t field_size = 0; + uint32_t case_offset; + uint32_t data_offset; - s->extreg = upb_ExtensionRegistry_New(s->arena); - if (!s->extreg) goto err; - return s; + if (upb_OneofDef_IsSynthetic(o)) continue; -err: - upb_Arena_Free(s->arena); - upb_gfree(s); - return NULL; -} + if (o->field_count == 0) { + symtab_errf(ctx, "Oneof must have at least one field (%s)", o->full_name); + } -static const void* symtab_lookup(const upb_DefPool* s, const char* sym, - upb_deftype_t type) { - upb_value v; - return upb_strtable_lookup(&s->syms, sym, &v) ? unpack_def(v, type) : NULL; -} + /* Calculate field size: the max of all field sizes. */ + for (int j = 0; j < o->field_count; j++) { + const upb_FieldDef* f = o->fields[j]; + field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); + } -static const void* symtab_lookup2(const upb_DefPool* s, const char* sym, - size_t size, upb_deftype_t type) { - upb_value v; - return upb_strtable_lookup2(&s->syms, sym, size, &v) ? unpack_def(v, type) - : NULL; -} + /* Align and allocate case offset. */ + case_offset = upb_MiniTable_place(ctx, l, case_size, m); + data_offset = upb_MiniTable_place(ctx, l, field_size, m); -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_MSG); -} + for (int i = 0; i < o->field_count; i++) { + const upb_FieldDef* f = o->fields[i]; + fields[upb_FieldDef_Index(f)].offset = data_offset; + fields[upb_FieldDef_Index(f)].presence = ~case_offset; + } + } -const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len) { - return symtab_lookup2(s, sym, len, UPB_DEFTYPE_MSG); -} + /* Size of the entire structure should be a multiple of its greatest + * alignment. TODO: track overall alignment for real? */ + l->size = UPB_ALIGN_UP(l->size, 8); -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUM); + /* Sort fields by number. */ + if (fields) { + qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), + field_number_cmp); + } + assign_layout_indices(m, l, fields); } -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym) { - return symtab_lookup(s, sym, UPB_DEFTYPE_ENUMVAL); +static char* strviewdup(symtab_addctx* ctx, upb_StringView view) { + char* ret = upb_strdup2(view.data, view.size, ctx->arena); + CHK_OOM(ret); + return ret; } -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name) { - upb_value v; - return upb_strtable_lookup(&s->files, name, &v) - ? unpack_def(v, UPB_DEFTYPE_FILE) - : NULL; +static bool streql2(const char* a, size_t n, const char* b) { + return n == strlen(b) && memcmp(a, b, n) == 0; } -const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, - const char* name, - size_t len) { - upb_value v; - return upb_strtable_lookup2(&s->files, name, len, &v) - ? unpack_def(v, UPB_DEFTYPE_FILE) - : NULL; +static bool streql_view(upb_StringView view, const char* b) { + return streql2(view.data, view.size, b); } -const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - upb_value v; - if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; - - switch (deftype(v)) { - case UPB_DEFTYPE_FIELD: - return unpack_def(v, UPB_DEFTYPE_FIELD); - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); - return m->in_message_set ? &m->nested_exts[0] : NULL; - } - default: - break; +static const char* makefullname(symtab_addctx* ctx, const char* prefix, + upb_StringView name) { + if (prefix) { + /* ret = prefix + '.' + name; */ + size_t n = strlen(prefix); + char* ret = symtab_alloc(ctx, n + name.size + 2); + strcpy(ret, prefix); + ret[n] = '.'; + memcpy(&ret[n + 1], name.data, name.size); + ret[n + 1 + name.size] = '\0'; + return ret; + } else { + return strviewdup(ctx, name); } - - return NULL; } -const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, - const char* sym) { - return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); -} +static void finalize_oneofs(symtab_addctx* ctx, upb_MessageDef* m) { + int i; + int synthetic_count = 0; + upb_OneofDef* mutable_oneofs = (upb_OneofDef*)m->oneofs; -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name) { - return symtab_lookup(s, name, UPB_DEFTYPE_SERVICE); -} + for (i = 0; i < m->oneof_count; i++) { + upb_OneofDef* o = &mutable_oneofs[i]; -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - return symtab_lookup2(s, name, size, UPB_DEFTYPE_SERVICE); -} + if (o->synthetic && o->field_count != 1) { + symtab_errf(ctx, "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_OneofDef_Name(o)); + } -const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, - const char* name) { - upb_value v; - // TODO(haberman): non-extension fields and oneofs. - if (upb_strtable_lookup(&s->syms, name, &v)) { - switch (deftype(v)) { - case UPB_DEFTYPE_EXT: { - const upb_FieldDef* f = unpack_def(v, UPB_DEFTYPE_EXT); - return upb_FieldDef_File(f); - } - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG); - return upb_MessageDef_File(m); - } - case UPB_DEFTYPE_ENUM: { - const upb_EnumDef* e = unpack_def(v, UPB_DEFTYPE_ENUM); - return upb_EnumDef_File(e); - } - case UPB_DEFTYPE_ENUMVAL: { - const upb_EnumValueDef* ev = unpack_def(v, UPB_DEFTYPE_ENUMVAL); - return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); - } - case UPB_DEFTYPE_SERVICE: { - const upb_ServiceDef* service = unpack_def(v, UPB_DEFTYPE_SERVICE); - return upb_ServiceDef_File(service); - } - default: - UPB_UNREACHABLE(); + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + symtab_errf(ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_OneofDef_Name(o)); } + + o->fields = symtab_alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); + o->field_count = 0; } - const char* last_dot = strrchr(name, '.'); - if (last_dot) { - const upb_MessageDef* parent = - upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); - if (parent) { - const char* shortname = last_dot + 1; - if (upb_MessageDef_FindByNameWithSize(parent, shortname, - strlen(shortname), NULL, NULL)) { - return upb_MessageDef_File(parent); - } + for (i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = &m->fields[i]; + upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); + if (o) { + o->fields[o->field_count++] = f; } } - return NULL; + m->real_oneof_count = m->oneof_count - synthetic_count; } -/* Code to build defs from descriptor protos. *********************************/ +size_t getjsonname(const char* name, char* buf, size_t len) { + size_t src, dst = 0; + bool ucase_next = false; -/* There is a question of how much validation to do here. It will be difficult - * to perfectly match the amount of validation performed by proto2. But since - * this code is used to directly build defs from Ruby (for example) we do need - * to validate important constraints like uniqueness of names and numbers. */ +#define WRITE(byte) \ + ++dst; \ + if (dst < len) \ + buf[dst - 1] = byte; \ + else if (dst == len) \ + buf[dst - 1] = '\0' -#define CHK_OOM(x) \ - if (!(x)) { \ - symtab_oomerr(ctx); \ + if (!name) { + WRITE('\0'); + return 0; } -typedef struct { - upb_DefPool* symtab; - upb_FileDef* file; /* File we are building. */ - upb_Arena* arena; /* Allocate defs here. */ - upb_Arena* tmp_arena; /* For temporary allocations. */ - const upb_MiniTable_File* layout; /* NULL if we should build layouts. */ - int enum_count; /* Count of enums built so far. */ - int msg_count; /* Count of messages built so far. */ - int ext_count; /* Count of extensions built so far. */ - upb_Status* status; /* Record errors here. */ - jmp_buf err; /* longjmp() on error. */ -} symtab_addctx; + /* Implement the transformation as described in the spec: + * 1. upper case all letters after an underscore. + * 2. remove all underscores. + */ + for (src = 0; name[src]; src++) { + if (name[src] == '_') { + ucase_next = true; + continue; + } -UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3) static void symtab_errf( - symtab_addctx* ctx, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(ctx->status, fmt, argp); - va_end(argp); - UPB_LONGJMP(ctx->err, 1); -} + if (ucase_next) { + WRITE(toupper(name[src])); + ucase_next = false; + } else { + WRITE(name[src]); + } + } -UPB_NORETURN UPB_NOINLINE static void symtab_oomerr(symtab_addctx* ctx) { - upb_Status_setoom(ctx->status); - UPB_LONGJMP(ctx->err, 1); + WRITE('\0'); + return dst; + +#undef WRITE } -void* symtab_alloc(symtab_addctx* ctx, size_t bytes) { - if (bytes == 0) return NULL; - void* ret = upb_Arena_Malloc(ctx->arena, bytes); - if (!ret) symtab_oomerr(ctx); - return ret; +static char* makejsonname(symtab_addctx* ctx, const char* name) { + size_t size = getjsonname(name, NULL, 0); + char* json_name = symtab_alloc(ctx, size); + getjsonname(name, json_name, size); + return json_name; } -// We want to copy the options verbatim into the destination options proto. -// We use serialize+parse as our deep copy. -#define SET_OPTIONS(target, desc_type, options_type, proto) \ - if (google_protobuf_##desc_type##_has_options(proto)) { \ - size_t size; \ - char* pb = google_protobuf_##options_type##_serialize( \ - google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \ - CHK_OOM(pb); \ - target = google_protobuf_##options_type##_parse(pb, size, ctx->arena); \ - CHK_OOM(target); \ - } else { \ - target = (const google_protobuf_##options_type*)opt_default; \ +/* Adds a symbol |v| to the symtab, which must be a def pointer previously + * packed with pack_def(). The def's pointer to upb_FileDef* must be set before + * adding, so we know which entries to remove if building this file fails. */ +static void symtab_add(symtab_addctx* ctx, const char* name, upb_value v) { + // TODO: table should support an operation "tryinsert" to avoid the double + // lookup. + if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { + symtab_errf(ctx, "duplicate symbol '%s'", name); + } + size_t len = strlen(name); + CHK_OOM(upb_strtable_insert(&ctx->symtab->syms, name, len, v, + ctx->symtab->arena)); +} + +static bool remove_component(char* base, size_t* len) { + if (*len == 0) return false; + + for (size_t i = *len - 1; i > 0; i--) { + if (base[i] == '.') { + *len = i; + return true; + } } -static void check_ident(symtab_addctx* ctx, upb_StringView name, bool full) { - const char* str = name.data; - size_t len = name.size; - bool start = true; - size_t i; - for (i = 0; i < len; i++) { - char c = str[i]; - if (c == '.') { - if (start || !full) { - symtab_errf(ctx, "invalid name: unexpected '.' (%.*s)", (int)len, str); + *len = 0; + return true; +} + +/* Given a symbol and the base symbol inside which it is defined, find the + * symbol's definition in t. */ +static const void* symtab_resolveany(symtab_addctx* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type) { + const upb_strtable* t = &ctx->symtab->syms; + if (sym.size == 0) goto notfound; + upb_value v; + if (sym.data[0] == '.') { + /* Symbols starting with '.' are absolute, so we do a single lookup. + * Slice to omit the leading '.' */ + if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) { + goto notfound; + } + } else { + /* Remove components from base until we find an entry or run out. */ + size_t baselen = base ? strlen(base) : 0; + char* tmp = malloc(sym.size + baselen + 1); + while (1) { + char* p = tmp; + if (baselen) { + memcpy(p, base, baselen); + p[baselen] = '.'; + p += baselen + 1; } - start = true; - } else if (start) { - if (!upb_isletter(c)) { - symtab_errf( - ctx, - "invalid name: path components must start with a letter (%.*s)", - (int)len, str); + memcpy(p, sym.data, sym.size); + p += sym.size; + if (upb_strtable_lookup2(t, tmp, p - tmp, &v)) { + break; } - start = false; - } else { - if (!upb_isalphanum(c)) { - symtab_errf(ctx, "invalid name: non-alphanumeric character (%.*s)", - (int)len, str); + if (!remove_component(tmp, &baselen)) { + free(tmp); + goto notfound; } } + free(tmp); } - if (start) { - symtab_errf(ctx, "invalid name: empty part (%.*s)", (int)len, str); - } -} -static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; } + *type = deftype(v); + return unpack_def(v, *type); -static size_t upb_MessageValue_sizeof(upb_CType type) { - switch (type) { - case kUpb_CType_Double: - case kUpb_CType_Int64: - case kUpb_CType_UInt64: - return 8; - case kUpb_CType_Enum: - case kUpb_CType_Int32: - case kUpb_CType_UInt32: - case kUpb_CType_Float: - return 4; - case kUpb_CType_Bool: - return 1; - case kUpb_CType_Message: - return sizeof(void*); - case kUpb_CType_Bytes: - case kUpb_CType_String: - return sizeof(upb_StringView); - } - UPB_UNREACHABLE(); +notfound: + symtab_errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(sym)); } -static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) { - if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) { - upb_MapEntry ent; - UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); - return sizeof(ent.k); - } else if (upb_FieldDef_IsRepeated(f)) { - return sizeof(void*); - } else { - return upb_MessageValue_sizeof(upb_FieldDef_CType(f)); +static const void* symtab_resolve(symtab_addctx* ctx, const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t type) { + upb_deftype_t found_type; + const void* ret = + symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type); + if (ret && found_type != type) { + symtab_errf(ctx, + "type mismatch when resolving %s: couldn't find " + "name " UPB_STRINGVIEW_FORMAT " with type=%d", + from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); } + return ret; } -static uint32_t upb_MiniTable_place(symtab_addctx* ctx, upb_MiniTable* l, - size_t size, const upb_MessageDef* m) { - size_t ofs = UPB_ALIGN_UP(l->size, size); - size_t next = ofs + size; +static void create_oneofdef( + symtab_addctx* ctx, upb_MessageDef* m, + const google_protobuf_OneofDescriptorProto* oneof_proto, + const upb_OneofDef* _o) { + upb_OneofDef* o = (upb_OneofDef*)_o; + upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); + upb_value v; - if (next > UINT16_MAX) { - symtab_errf(ctx, "size of message %s exceeded max size of %zu bytes", - upb_MessageDef_FullName(m), (size_t)UINT16_MAX); + o->parent = m; + o->full_name = makefullname(ctx, m->full_name, name); + o->field_count = 0; + o->synthetic = false; + + SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + + upb_value existing_v; + if (upb_strtable_lookup2(&m->ntof, name.data, name.size, &existing_v)) { + symtab_errf(ctx, "duplicate oneof name (%s)", o->full_name); } - l->size = next; - return ofs; + v = pack_def(o, UPB_DEFTYPE_ONEOF); + CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); + + CHK_OOM(upb_inttable_init(&o->itof, ctx->arena)); + CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena)); } -static int field_number_cmp(const void* p1, const void* p2) { - const upb_MiniTable_Field* f1 = p1; - const upb_MiniTable_Field* f2 = p2; - return f1->number - f2->number; +static str_t* newstr(symtab_addctx* ctx, const char* data, size_t len) { + str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); + CHK_OOM(ret); + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; } -static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l, - upb_MiniTable_Field* fields) { - int i; - int n = upb_MessageDef_numfields(m); - int dense_below = 0; - for (i = 0; i < n; i++) { - upb_FieldDef* f = - (upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number); - UPB_ASSERT(f); - f->layout_index = i; - if (i < UINT8_MAX && fields[i].number == i + 1 && - (i == 0 || fields[i - 1].number == i)) { - dense_below = i + 1; - } - } - l->dense_below = dense_below; +static bool upb_DefPool_TryGetChar(const char** src, const char* end, + char* ch) { + if (*src == end) return false; + *ch = **src; + *src += 1; + return true; } -static uint8_t map_descriptortype(const upb_FieldDef* f) { - uint8_t type = upb_FieldDef_Type(f); - /* See TableDescriptorType() in upbc/generator.cc for details and - * rationale of these exceptions. */ - if (type == kUpb_FieldType_String && f->file->syntax == kUpb_Syntax_Proto2) { - return kUpb_FieldType_Bytes; - } else if (type == kUpb_FieldType_Enum && - (f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3 || - UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 || - // TODO(https://github.com/protocolbuffers/upb/issues/541): - // fix map enum values to check for unknown enum values and put - // them in the unknown field set. - upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)))) { - return kUpb_FieldType_Int32; +static char upb_DefPool_TryGetHexDigit(symtab_addctx* ctx, + const upb_FieldDef* f, const char** src, + const char* end) { + char ch; + if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '9') { + return ch - '0'; } - return type; + ch = upb_ascii_lower(ch); + if ('a' <= ch && ch <= 'f') { + return ch - 'a' + 0xa; + } + *src -= 1; // Char wasn't actually a hex digit. + return -1; } -static void fill_fieldlayout(upb_MiniTable_Field* field, - const upb_FieldDef* f) { - field->number = upb_FieldDef_Number(f); - field->descriptortype = map_descriptortype(f); - - if (upb_FieldDef_IsMap(f)) { - field->mode = - kUpb_FieldMode_Map | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); - } else if (upb_FieldDef_IsRepeated(f)) { - field->mode = - kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); - } else { - /* Maps descriptor type -> elem_size_lg2. */ - static const uint8_t sizes[] = { - -1, /* invalid descriptor type */ - kUpb_FieldRep_8Byte, /* DOUBLE */ - kUpb_FieldRep_4Byte, /* FLOAT */ - kUpb_FieldRep_8Byte, /* INT64 */ - kUpb_FieldRep_8Byte, /* UINT64 */ - kUpb_FieldRep_4Byte, /* INT32 */ - kUpb_FieldRep_8Byte, /* FIXED64 */ - kUpb_FieldRep_4Byte, /* FIXED32 */ - kUpb_FieldRep_1Byte, /* BOOL */ - kUpb_FieldRep_StringView, /* STRING */ - kUpb_FieldRep_Pointer, /* GROUP */ - kUpb_FieldRep_Pointer, /* MESSAGE */ - kUpb_FieldRep_StringView, /* BYTES */ - kUpb_FieldRep_4Byte, /* UINT32 */ - kUpb_FieldRep_4Byte, /* ENUM */ - kUpb_FieldRep_4Byte, /* SFIXED32 */ - kUpb_FieldRep_8Byte, /* SFIXED64 */ - kUpb_FieldRep_4Byte, /* SINT32 */ - kUpb_FieldRep_8Byte, /* SINT64 */ - }; - field->mode = kUpb_FieldMode_Scalar | - (sizes[field->descriptortype] << kUpb_FieldRep_Shift); +static char upb_DefPool_ParseHexEscape(symtab_addctx* ctx, + const upb_FieldDef* f, const char** src, + const char* end) { + char hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end); + if (hex_digit < 0) { + symtab_errf(ctx, + "\\x cannot be followed by non-hex digit in field '%s' default", + upb_FieldDef_FullName(f)); + return 0; } - - if (upb_FieldDef_IsPacked(f)) { - field->mode |= kUpb_LabelFlags_IsPacked; + unsigned int ret = hex_digit; + while ((hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end)) >= 0) { + ret = (ret << 4) | hex_digit; } - - if (upb_FieldDef_IsExtension(f)) { - field->mode |= kUpb_LabelFlags_IsExtension; + if (ret > 0xff) { + symtab_errf(ctx, "Value of hex escape in field %s exceeds 8 bits", + upb_FieldDef_FullName(f)); + return 0; } + return ret; } -/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. - * It computes a dynamic layout for all of the fields in |m|. */ -static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { - upb_MiniTable* l = (upb_MiniTable*)m->layout; - size_t field_count = upb_MessageDef_numfields(m); - size_t sublayout_count = 0; - upb_MiniTable_Sub* subs; - upb_MiniTable_Field* fields; - - memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry)); +char upb_DefPool_TryGetOctalDigit(const char** src, const char* end) { + char ch; + if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '7') { + return ch - '0'; + } + *src -= 1; // Char wasn't actually an octal digit. + return -1; +} - /* Count sub-messages. */ - for (size_t i = 0; i < field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - if (upb_FieldDef_IsSubMessage(f)) { - sublayout_count++; - } - if (upb_FieldDef_CType(f) == kUpb_CType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2) { - sublayout_count++; +static char upb_DefPool_ParseOctalEscape(symtab_addctx* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char ch = 0; + for (int i = 0; i < 3; i++) { + char digit; + if ((digit = upb_DefPool_TryGetOctalDigit(src, end)) >= 0) { + ch = (ch << 3) | digit; } } + return ch; +} - fields = symtab_alloc(ctx, field_count * sizeof(*fields)); - subs = symtab_alloc(ctx, sublayout_count * sizeof(*subs)); +static char upb_DefPool_ParseEscape(symtab_addctx* ctx, const upb_FieldDef* f, + const char** src, const char* end) { + char ch; + if (!upb_DefPool_TryGetChar(src, end, &ch)) { + symtab_errf(ctx, "unterminated escape sequence in field %s", + upb_FieldDef_FullName(f)); + return 0; + } + switch (ch) { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '\"': + return '\"'; + case '?': + return '\?'; + case 'x': + case 'X': + return upb_DefPool_ParseHexEscape(ctx, f, src, end); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + *src -= 1; + return upb_DefPool_ParseOctalEscape(ctx, f, src, end); + } + symtab_errf(ctx, "Unknown escape sequence: \\%c", ch); +} - l->field_count = upb_MessageDef_numfields(m); - l->fields = fields; - l->subs = subs; - l->table_mask = 0; - l->required_count = 0; +static str_t* unescape(symtab_addctx* ctx, const upb_FieldDef* f, + const char* data, size_t len) { + // Size here is an upper bound; escape sequences could ultimately shrink it. + str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); + char* dst = &ret->str[0]; + const char* src = data; + const char* end = data + len; - if (upb_MessageDef_ExtensionRangeCount(m) > 0) { - if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { - l->ext = kUpb_ExtMode_IsMessageSet; + while (src < end) { + if (*src == '\\') { + src++; + *dst++ = upb_DefPool_ParseEscape(ctx, f, &src, end); } else { - l->ext = kUpb_ExtMode_Extendable; + *dst++ = *src++; } - } else { - l->ext = kUpb_ExtMode_NonExtendable; } - /* TODO(haberman): initialize fast tables so that reflection-based parsing - * can get the same speeds as linked-in types. */ - l->fasttable[0].field_parser = &fastdecode_generic; - l->fasttable[0].field_data = 0; + ret->len = dst - &ret->str[0]; + return ret; +} - if (upb_MessageDef_IsMapEntry(m)) { - /* TODO(haberman): refactor this method so this special case is more - * elegant. */ - const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2); - fields[0].number = 1; - fields[1].number = 2; - fields[0].mode = kUpb_FieldMode_Scalar; - fields[1].mode = kUpb_FieldMode_Scalar; - fields[0].presence = 0; - fields[1].presence = 0; - fields[0].descriptortype = map_descriptortype(key); - fields[1].descriptortype = map_descriptortype(val); - fields[0].offset = 0; - fields[1].offset = sizeof(upb_StringView); - fields[1].submsg_index = 0; +static void parse_default(symtab_addctx* ctx, const char* str, size_t len, + upb_FieldDef* f) { + char* end; + char nullz[64]; + errno = 0; + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + case kUpb_CType_Double: + case kUpb_CType_Float: + /* Standard C number parsing functions expect null-terminated strings. */ + if (len >= sizeof(nullz) - 1) { + symtab_errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; + } + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_Enum: { + const upb_EnumDef* e = f->sub.enumdef; + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str, len); + if (!ev) { + goto invalid; + } + f->defaultval.sint = ev->number; + break; + } + case kUpb_CType_Int64: { + long long val = strtoll(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case kUpb_CType_UInt32: { + unsigned long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_UInt64: { + unsigned long long val = strtoull(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case kUpb_CType_Double: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.dbl = val; + break; + } + case kUpb_CType_Float: { + float val = strtof(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.flt = val; + break; + } + case kUpb_CType_Bool: { + if (streql2(str, len, "false")) { + f->defaultval.boolean = false; + } else if (streql2(str, len, "true")) { + f->defaultval.boolean = true; + } else { + goto invalid; + } + break; + } + case kUpb_CType_String: + f->defaultval.str = newstr(ctx, str, len); + break; + case kUpb_CType_Bytes: + f->defaultval.str = unescape(ctx, f, str, len); + break; + case kUpb_CType_Message: + /* Should not have a default value. */ + symtab_errf(ctx, "Message should not have a default (%s)", + upb_FieldDef_FullName(f)); + } - if (upb_FieldDef_CType(val) == kUpb_CType_Message) { - subs[0].submsg = upb_FieldDef_MessageSubDef(val)->layout; - } + return; - upb_FieldDef* fielddefs = (upb_FieldDef*)&m->fields[0]; - UPB_ASSERT(fielddefs[0].number_ == 1); - UPB_ASSERT(fielddefs[1].number_ == 2); - fielddefs[0].layout_index = 0; - fielddefs[1].layout_index = 1; +invalid: + symtab_errf(ctx, "Invalid default '%.*s' for field %s of type %d", (int)len, + str, upb_FieldDef_FullName(f), (int)upb_FieldDef_Type(f)); +} - l->field_count = 2; - l->size = 2 * sizeof(upb_StringView); - l->size = UPB_ALIGN_UP(l->size, 8); - l->dense_below = 2; - return; +static void set_default_default(symtab_addctx* ctx, upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Int32: + case kUpb_CType_Int64: + f->defaultval.sint = 0; + break; + case kUpb_CType_UInt64: + case kUpb_CType_UInt32: + f->defaultval.uint = 0; + break; + case kUpb_CType_Double: + case kUpb_CType_Float: + f->defaultval.dbl = 0; + break; + case kUpb_CType_String: + case kUpb_CType_Bytes: + f->defaultval.str = newstr(ctx, NULL, 0); + break; + case kUpb_CType_Bool: + f->defaultval.boolean = false; + break; + case kUpb_CType_Enum: + f->defaultval.sint = f->sub.enumdef->values[0].number; + case kUpb_CType_Message: + break; } +} - /* 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. - */ +static void create_fielddef( + symtab_addctx* ctx, const char* prefix, upb_MessageDef* m, + const google_protobuf_FieldDescriptorProto* field_proto, + const upb_FieldDef* _f, bool is_extension) { + upb_FieldDef* f = (upb_FieldDef*)_f; + upb_StringView name; + const char* full_name; + const char* json_name; + const char* shortname; + int32_t field_number; - /* Assign hasbits for required fields first. */ - size_t hasbit = 0; + f->file = ctx->file; /* Must happen prior to symtab_add(). */ - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - field->presence = ++hasbit; - if (hasbit >= 63) { - symtab_errf(ctx, "Message with >=63 required fields: %s", - upb_MessageDef_FullName(m)); - } - l->required_count++; - } + if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { + symtab_errf(ctx, "field has no name"); } - /* Allocate hasbits and set basic field attributes. */ - sublayout_count = 0; - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)]; + name = google_protobuf_FieldDescriptorProto_name(field_proto); + check_ident(ctx, name, false); + full_name = makefullname(ctx, prefix, name); + shortname = shortdefname(full_name); - fill_fieldlayout(field, f); + if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { + json_name = strviewdup( + ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto)); + f->has_json_name_ = true; + } else { + json_name = makejsonname(ctx, shortname); + f->has_json_name_ = false; + } - if (field->descriptortype == kUpb_FieldType_Message || - field->descriptortype == kUpb_FieldType_Group) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout; - } else if (field->descriptortype == kUpb_FieldType_Enum) { - field->submsg_index = sublayout_count++; - subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout; - UPB_ASSERT(subs[field->submsg_index].subenum); - } + field_number = google_protobuf_FieldDescriptorProto_number(field_proto); - if (upb_FieldDef_Label(f) == kUpb_Label_Required) { - /* Hasbit was already assigned. */ - } else if (upb_FieldDef_HasPresence(f) && - !upb_FieldDef_RealContainingOneof(f)) { - /* We don't use hasbit 0, so that 0 can indicate "no presence" in the - * table. This wastes one hasbit, but we don't worry about it for now. */ - field->presence = ++hasbit; - } else { - field->presence = 0; - } - } + f->full_name = full_name; + f->json_name = json_name; + f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); + f->number_ = field_number; + f->scope.oneof = NULL; + f->proto3_optional_ = + google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); - /* Account for space used by hasbits. */ - l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0; + bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); + bool has_type_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); - /* Allocate non-oneof fields. */ - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - size_t field_size = upb_msg_fielddefsize(f); - size_t index = upb_FieldDef_Index(f); + f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); - if (upb_FieldDef_RealContainingOneof(f)) { - /* Oneofs are handled separately below. */ - continue; + if (has_type) { + switch (f->type_) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + if (!has_type_name) { + symtab_errf(ctx, "field of type %d requires type name (%s)", + (int)f->type_, full_name); + } + break; + default: + if (has_type_name) { + symtab_errf(ctx, "invalid type for field with type_name set (%s, %d)", + full_name, (int)f->type_); + } } - - fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m); + } else if (has_type_name) { + f->type_ = + FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef(). } - /* Allocate oneof fields. Each oneof field consists of a uint32 for the case - * and space for the actual data. */ - for (int i = 0; i < m->oneof_count; i++) { - const upb_OneofDef* o = &m->oneofs[i]; - size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ - size_t field_size = 0; - uint32_t case_offset; - uint32_t data_offset; - - if (upb_OneofDef_IsSynthetic(o)) continue; + if (!is_extension) { + /* direct message field. */ + upb_value v, field_v, json_v, existing_v; + size_t json_size; - if (o->field_count == 0) { - symtab_errf(ctx, "Oneof must have at least one field (%s)", o->full_name); + if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { + symtab_errf(ctx, "invalid field number (%u)", field_number); } - /* Calculate field size: the max of all field sizes. */ - for (int j = 0; j < o->field_count; j++) { - const upb_FieldDef* f = o->fields[j]; - field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); + f->index_ = f - m->fields; + f->msgdef = m; + f->is_extension_ = false; + + field_v = pack_def(f, UPB_DEFTYPE_FIELD); + json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME); + v = upb_value_constptr(f); + json_size = strlen(json_name); + + if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { + symtab_errf(ctx, "duplicate field name (%s)", shortname); } - /* Align and allocate case offset. */ - case_offset = upb_MiniTable_place(ctx, l, case_size, m); - data_offset = upb_MiniTable_place(ctx, l, field_size, m); + CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v, + ctx->arena)); - for (int i = 0; i < o->field_count; i++) { - const upb_FieldDef* f = o->fields[i]; - fields[upb_FieldDef_Index(f)].offset = data_offset; - fields[upb_FieldDef_Index(f)].presence = ~case_offset; + if (strcmp(shortname, json_name) != 0) { + if (upb_strtable_lookup(&m->ntof, json_name, &v)) { + symtab_errf(ctx, "duplicate json_name (%s)", json_name); + } else { + CHK_OOM(upb_strtable_insert(&m->ntof, json_name, json_size, json_v, + ctx->arena)); + } } - } - /* Size of the entire structure should be a multiple of its greatest - * alignment. TODO: track overall alignment for real? */ - l->size = UPB_ALIGN_UP(l->size, 8); + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + symtab_errf(ctx, "duplicate field number (%u)", field_number); + } - /* Sort fields by number. */ - if (fields) { - qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), - field_number_cmp); - } - assign_layout_indices(m, l, fields); -} + CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena)); -static char* strviewdup(symtab_addctx* ctx, upb_StringView view) { - char* ret = upb_strdup2(view.data, view.size, ctx->arena); - CHK_OOM(ret); - return ret; -} + if (ctx->layout) { + const upb_MiniTable_Field* fields = m->layout->fields; + int count = m->layout->field_count; + bool found = false; + for (int i = 0; i < count; i++) { + if (fields[i].number == field_number) { + f->layout_index = i; + found = true; + break; + } + } + UPB_ASSERT(found); + } + } else { + /* extension field. */ + f->is_extension_ = true; + f->scope.extension_scope = m; + symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_EXT)); + f->layout_index = ctx->ext_count++; + if (ctx->layout) { + UPB_ASSERT(ctx->file->ext_layouts[f->layout_index]->field.number == + field_number); + } + } -static bool streql2(const char* a, size_t n, const char* b) { - return n == strlen(b) && memcmp(a, b, n) == 0; -} + if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { + symtab_errf(ctx, "invalid type for field %s (%d)", f->full_name, f->type_); + } -static bool streql_view(upb_StringView view, const char* b) { - return streql2(view.data, view.size, b); -} + if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { + symtab_errf(ctx, "invalid label for field %s (%d)", f->full_name, + f->label_); + } -static const char* makefullname(symtab_addctx* ctx, const char* prefix, - upb_StringView name) { - if (prefix) { - /* ret = prefix + '.' + name; */ - size_t n = strlen(prefix); - char* ret = symtab_alloc(ctx, n + name.size + 2); - strcpy(ret, prefix); - ret[n] = '.'; - memcpy(&ret[n + 1], name.data, name.size); - ret[n + 1 + name.size] = '\0'; - return ret; - } else { - return strviewdup(ctx, name); + /* We can't resolve the subdef or (in the case of extensions) the containing + * message yet, because it may not have been defined yet. We stash a pointer + * to the field_proto until later when we can properly resolve it. */ + f->sub.unresolved = field_proto; + + if (f->label_ == kUpb_Label_Required && + f->file->syntax == kUpb_Syntax_Proto3) { + symtab_errf(ctx, "proto3 fields cannot be required (%s)", f->full_name); } -} -static void finalize_oneofs(symtab_addctx* ctx, upb_MessageDef* m) { - int i; - int synthetic_count = 0; - upb_OneofDef* mutable_oneofs = (upb_OneofDef*)m->oneofs; + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); + upb_OneofDef* oneof; + upb_value v = upb_value_constptr(f); - for (i = 0; i < m->oneof_count; i++) { - upb_OneofDef* o = &mutable_oneofs[i]; + if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { + symtab_errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } - if (o->synthetic && o->field_count != 1) { - symtab_errf(ctx, "Synthetic oneofs must have one field, not %d: %s", - o->field_count, upb_OneofDef_Name(o)); + if (!m) { + symtab_errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); } - if (o->synthetic) { - synthetic_count++; - } else if (synthetic_count != 0) { - symtab_errf(ctx, "Synthetic oneofs must be after all other oneofs: %s", - upb_OneofDef_Name(o)); + if (oneof_index >= m->oneof_count) { + symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name); } - o->fields = symtab_alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); - o->field_count = 0; - } + oneof = (upb_OneofDef*)&m->oneofs[oneof_index]; + f->scope.oneof = oneof; - for (i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = &m->fields[i]; - upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); - if (o) { - o->fields[o->field_count++] = f; + oneof->field_count++; + if (f->proto3_optional_) { + oneof->synthetic = true; + } + CHK_OOM(upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena)); + CHK_OOM( + upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); + } else { + if (f->proto3_optional_) { + symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)", + f->full_name); } } - m->real_oneof_count = m->oneof_count - synthetic_count; + SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + + if (google_protobuf_FieldOptions_has_packed(f->opts)) { + f->packed_ = google_protobuf_FieldOptions_packed(f->opts); + } else { + /* Repeated fields default to packed for proto3 only. */ + f->packed_ = upb_FieldDef_IsPrimitive(f) && + f->label_ == kUpb_Label_Repeated && + f->file->syntax == kUpb_Syntax_Proto3; + } } -size_t getjsonname(const char* name, char* buf, size_t len) { - size_t src, dst = 0; - bool ucase_next = false; +static void create_service( + symtab_addctx* ctx, const google_protobuf_ServiceDescriptorProto* svc_proto, + const upb_ServiceDef* _s) { + upb_ServiceDef* s = (upb_ServiceDef*)_s; + upb_StringView name; + const google_protobuf_MethodDescriptorProto* const* methods; + size_t i, n; -#define WRITE(byte) \ - ++dst; \ - if (dst < len) \ - buf[dst - 1] = byte; \ - else if (dst == len) \ - buf[dst - 1] = '\0' + s->file = ctx->file; /* Must happen prior to symtab_add. */ - if (!name) { - WRITE('\0'); - return 0; - } + name = google_protobuf_ServiceDescriptorProto_name(svc_proto); + check_ident(ctx, name, false); + s->full_name = makefullname(ctx, ctx->file->package, name); + symtab_add(ctx, s->full_name, pack_def(s, UPB_DEFTYPE_SERVICE)); - /* Implement the transformation as described in the spec: - * 1. upper case all letters after an underscore. - * 2. remove all underscores. - */ - for (src = 0; name[src]; src++) { - if (name[src] == '_') { - ucase_next = true; - continue; - } + methods = google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); - if (ucase_next) { - WRITE(toupper(name[src])); - ucase_next = false; - } else { - WRITE(name[src]); - } - } + s->method_count = n; + s->methods = symtab_alloc(ctx, sizeof(*s->methods) * n); - WRITE('\0'); - return dst; + SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, svc_proto); -#undef WRITE -} + for (i = 0; i < n; i++) { + const google_protobuf_MethodDescriptorProto* method_proto = methods[i]; + upb_MethodDef* m = (upb_MethodDef*)&s->methods[i]; + upb_StringView name = + google_protobuf_MethodDescriptorProto_name(method_proto); -static char* makejsonname(symtab_addctx* ctx, const char* name) { - size_t size = getjsonname(name, NULL, 0); - char* json_name = symtab_alloc(ctx, size); - getjsonname(name, json_name, size); - return json_name; + m->service = s; + m->full_name = makefullname(ctx, s->full_name, name); + m->index = i; + m->client_streaming = + google_protobuf_MethodDescriptorProto_client_streaming(method_proto); + m->server_streaming = + google_protobuf_MethodDescriptorProto_server_streaming(method_proto); + m->input_type = symtab_resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_input_type(method_proto), + UPB_DEFTYPE_MSG); + m->output_type = symtab_resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_output_type(method_proto), + UPB_DEFTYPE_MSG); + + SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, method_proto); + } } -/* Adds a symbol |v| to the symtab, which must be a def pointer previously - * packed with pack_def(). The def's pointer to upb_FileDef* must be set before - * adding, so we know which entries to remove if building this file fails. */ -static void symtab_add(symtab_addctx* ctx, const char* name, upb_value v) { - // TODO: table should support an operation "tryinsert" to avoid the double - // lookup. - if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { - symtab_errf(ctx, "duplicate symbol '%s'", name); +static int count_bits_debug(uint64_t x) { + // For assertions only, speed does not matter. + int n = 0; + while (x) { + if (x & 1) n++; + x >>= 1; } - size_t len = strlen(name); - CHK_OOM(upb_strtable_insert(&ctx->symtab->syms, name, len, v, - ctx->symtab->arena)); + return n; } -static bool remove_component(char* base, size_t* len) { - if (*len == 0) return false; +static int compare_int32(const void* a_ptr, const void* b_ptr) { + int32_t a = *(int32_t*)a_ptr; + int32_t b = *(int32_t*)b_ptr; + return a < b ? -1 : (a == b ? 0 : 1); +} - for (size_t i = *len - 1; i > 0; i--) { - if (base[i] == '.') { - *len = i; - return true; +upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, + const upb_EnumDef* e) { + int n = 0; + uint64_t mask = 0; + + for (int i = 0; i < e->value_count; i++) { + uint32_t val = (uint32_t)e->values[i].number; + if (val < 64) { + mask |= 1ULL << val; + } else { + n++; } } - *len = 0; - return true; -} + int32_t* values = symtab_alloc(ctx, sizeof(*values) * n); -/* Given a symbol and the base symbol inside which it is defined, find the - * symbol's definition in t. */ -static const void* symtab_resolveany(symtab_addctx* ctx, - const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t* type) { - const upb_strtable* t = &ctx->symtab->syms; - if (sym.size == 0) goto notfound; - upb_value v; - if (sym.data[0] == '.') { - /* Symbols starting with '.' are absolute, so we do a single lookup. - * Slice to omit the leading '.' */ - if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) { - goto notfound; - } - } else { - /* Remove components from base until we find an entry or run out. */ - size_t baselen = base ? strlen(base) : 0; - char* tmp = malloc(sym.size + baselen + 1); - while (1) { - char* p = tmp; - if (baselen) { - memcpy(p, base, baselen); - p[baselen] = '.'; - p += baselen + 1; - } - memcpy(p, sym.data, sym.size); - p += sym.size; - if (upb_strtable_lookup2(t, tmp, p - tmp, &v)) { - break; - } - if (!remove_component(tmp, &baselen)) { - free(tmp); - goto notfound; + if (n) { + int32_t* p = values; + + // Add values outside the bitmask range to the list, as described in the + // comments for upb_MiniTable_Enum. + for (int i = 0; i < e->value_count; i++) { + int32_t val = e->values[i].number; + if ((uint32_t)val >= 64) { + *p++ = val; } } - free(tmp); + UPB_ASSERT(p == values + n); + } + + // Enums can have duplicate values; we must sort+uniq them. + if (values) qsort(values, n, sizeof(*values), &compare_int32); + + int dst = 0; + for (int i = 0; i < n; dst++) { + int32_t val = values[i]; + while (i < n && values[i] == val) i++; // Skip duplicates. + values[dst] = val; } + n = dst; - *type = deftype(v); - return unpack_def(v, *type); + UPB_ASSERT(upb_inttable_count(&e->iton) == n + count_bits_debug(mask)); -notfound: - symtab_errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(sym)); -} + upb_MiniTable_Enum* layout = symtab_alloc(ctx, sizeof(*layout)); + layout->value_count = n; + layout->mask = mask; + layout->values = values; -static const void* symtab_resolve(symtab_addctx* ctx, const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t type) { - upb_deftype_t found_type; - const void* ret = - symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type); - if (ret && found_type != type) { - symtab_errf(ctx, - "type mismatch when resolving %s: couldn't find " - "name " UPB_STRINGVIEW_FORMAT " with type=%d", - from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); - } - return ret; + return layout; } -static void create_oneofdef( - symtab_addctx* ctx, upb_MessageDef* m, - const google_protobuf_OneofDescriptorProto* oneof_proto, - const upb_OneofDef* _o) { - upb_OneofDef* o = (upb_OneofDef*)_o; - upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); - upb_value v; +static void create_enumvaldef( + symtab_addctx* ctx, const char* prefix, + const google_protobuf_EnumValueDescriptorProto* val_proto, upb_EnumDef* e, + int i) { + upb_EnumValueDef* val = (upb_EnumValueDef*)&e->values[i]; + upb_StringView name = + google_protobuf_EnumValueDescriptorProto_name(val_proto); + upb_value v = upb_value_constptr(val); - o->parent = m; - o->full_name = makefullname(ctx, m->full_name, name); - o->field_count = 0; - o->synthetic = false; + val->parent = e; /* Must happen prior to symtab_add(). */ + val->full_name = makefullname(ctx, prefix, name); + val->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); + symtab_add(ctx, val->full_name, pack_def(val, UPB_DEFTYPE_ENUMVAL)); - SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + SET_OPTIONS(val->opts, EnumValueDescriptorProto, EnumValueOptions, val_proto); - upb_value existing_v; - if (upb_strtable_lookup2(&m->ntof, name.data, name.size, &existing_v)) { - symtab_errf(ctx, "duplicate oneof name (%s)", o->full_name); + if (i == 0 && e->file->syntax == kUpb_Syntax_Proto3 && val->number != 0) { + symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)", + e->full_name); } - v = pack_def(o, UPB_DEFTYPE_ONEOF); - CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); + CHK_OOM(upb_strtable_insert(&e->ntoi, name.data, name.size, v, ctx->arena)); - CHK_OOM(upb_inttable_init(&o->itof, ctx->arena)); - CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena)); + // Multiple enumerators can have the same number, first one wins. + if (!upb_inttable_lookup(&e->iton, val->number, NULL)) { + CHK_OOM(upb_inttable_insert(&e->iton, val->number, v, ctx->arena)); + } } -static str_t* newstr(symtab_addctx* ctx, const char* data, size_t len) { - str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); - CHK_OOM(ret); - ret->len = len; - if (len) memcpy(ret->str, data, len); - ret->str[len] = '\0'; - return ret; +static upb_StringView* _upb_EnumReservedNames_New( + symtab_addctx* ctx, int n, const upb_StringView* protos) { + upb_StringView* sv = + upb_Arena_Malloc(ctx->arena, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, ctx->arena); + sv[i].size = protos[i].size; + } + return sv; } -static bool upb_DefPool_TryGetChar(const char** src, const char* end, - char* ch) { - if (*src == end) return false; - *ch = **src; - *src += 1; - return true; -} +static void create_enumdef( + symtab_addctx* ctx, const char* prefix, + const google_protobuf_EnumDescriptorProto* enum_proto, + const upb_MessageDef* containing_type, const upb_EnumDef* _e) { + upb_EnumDef* e = (upb_EnumDef*)_e; + ; + const google_protobuf_EnumValueDescriptorProto* const* values; + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* res_ranges; + const upb_StringView* res_names; + upb_StringView name; + size_t i, n, n_res_range, n_res_name; -static char upb_DefPool_TryGetHexDigit(symtab_addctx* ctx, - const upb_FieldDef* f, const char** src, - const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '9') { - return ch - '0'; - } - ch = upb_ascii_lower(ch); - if ('a' <= ch && ch <= 'f') { - return ch - 'a' + 0xa; - } - *src -= 1; // Char wasn't actually a hex digit. - return -1; -} + e->file = ctx->file; /* Must happen prior to symtab_add() */ + e->containing_type = containing_type; -static char upb_DefPool_ParseHexEscape(symtab_addctx* ctx, - const upb_FieldDef* f, const char** src, - const char* end) { - char hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end); - if (hex_digit < 0) { - symtab_errf(ctx, - "\\x cannot be followed by non-hex digit in field '%s' default", - upb_FieldDef_FullName(f)); - return 0; - } - unsigned int ret = hex_digit; - while ((hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end)) >= 0) { - ret = (ret << 4) | hex_digit; - } - if (ret > 0xff) { - symtab_errf(ctx, "Value of hex escape in field %s exceeds 8 bits", - upb_FieldDef_FullName(f)); - return 0; + name = google_protobuf_EnumDescriptorProto_name(enum_proto); + check_ident(ctx, name, false); + + e->full_name = makefullname(ctx, prefix, name); + symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); + + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); + CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena)); + CHK_OOM(upb_inttable_init(&e->iton, ctx->arena)); + + e->defaultval = 0; + e->value_count = n; + e->values = symtab_alloc(ctx, sizeof(*e->values) * n); + + if (n == 0) { + symtab_errf(ctx, "enums must contain at least one value (%s)", + e->full_name); } - return ret; -} -char upb_DefPool_TryGetOctalDigit(const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1; - if ('0' <= ch && ch <= '7') { - return ch - '0'; + res_ranges = + google_protobuf_EnumDescriptorProto_reserved_range(enum_proto, &n_res_range); + e->res_range_count = n_res_range; + e->res_ranges = _upb_EnumReservedRanges_New(ctx, n_res_range, res_ranges, e); + + res_names = google_protobuf_EnumDescriptorProto_reserved_name(enum_proto, &n_res_name); + e->res_name_count = n_res_name; + e->res_names = _upb_EnumReservedNames_New(ctx, n_res_name, res_names); + + SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); + + for (i = 0; i < n; i++) { + create_enumvaldef(ctx, prefix, values[i], e, i); } - *src -= 1; // Char wasn't actually an octal digit. - return -1; -} -static char upb_DefPool_ParseOctalEscape(symtab_addctx* ctx, - const upb_FieldDef* f, - const char** src, const char* end) { - char ch = 0; - for (int i = 0; i < 3; i++) { - char digit; - if ((digit = upb_DefPool_TryGetOctalDigit(src, end)) >= 0) { - ch = (ch << 3) | digit; + upb_inttable_compact(&e->iton, ctx->arena); + + if (e->file->syntax == kUpb_Syntax_Proto2) { + if (ctx->layout) { + UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); + e->layout = ctx->layout->enums[ctx->enum_count++]; + UPB_ASSERT(upb_inttable_count(&e->iton) == + e->layout->value_count + count_bits_debug(e->layout->mask)); + } else { + e->layout = create_enumlayout(ctx, e); } + } else { + e->layout = NULL; } - return ch; } -static char upb_DefPool_ParseEscape(symtab_addctx* ctx, const upb_FieldDef* f, - const char** src, const char* end) { - char ch; - if (!upb_DefPool_TryGetChar(src, end, &ch)) { - symtab_errf(ctx, "unterminated escape sequence in field %s", - upb_FieldDef_FullName(f)); - return 0; +static void msgdef_create_nested( + symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, + upb_MessageDef* m); + +static upb_StringView* _upb_ReservedNames_New(symtab_addctx* ctx, int n, + const upb_StringView* protos) { + upb_StringView* sv = upb_Arena_Malloc(ctx->arena, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, ctx->arena); + sv[i].size = protos[i].size; } - switch (ch) { - case 'a': - return '\a'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - case 'v': - return '\v'; - case '\\': - return '\\'; - case '\'': - return '\''; - case '\"': - return '\"'; - case '?': - return '\?'; - case 'x': - case 'X': - return upb_DefPool_ParseHexEscape(ctx, f, src, end); - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - *src -= 1; - return upb_DefPool_ParseOctalEscape(ctx, f, src, end); + return sv; +} + +static void create_msgdef(symtab_addctx* ctx, const char* prefix, + const google_protobuf_DescriptorProto* msg_proto, + const upb_MessageDef* containing_type, + const upb_MessageDef* _m) { + upb_MessageDef* m = (upb_MessageDef*)_m; + const google_protobuf_OneofDescriptorProto* const* oneofs; + const google_protobuf_FieldDescriptorProto* const* fields; + const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; + + const google_protobuf_DescriptorProto_ReservedRange* const* res_ranges; + const upb_StringView* res_names; + size_t i, n_oneof, n_field, n_ext_range; + size_t n_res_range, n_res_name; + upb_StringView name; + + m->file = ctx->file; /* Must happen prior to symtab_add(). */ + m->containing_type = containing_type; + + name = google_protobuf_DescriptorProto_name(msg_proto); + check_ident(ctx, name, false); + + m->full_name = makefullname(ctx, prefix, name); + symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG)); + + oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); + fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); + ext_ranges = + google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); + res_ranges = google_protobuf_DescriptorProto_reserved_range(msg_proto, &n_res_range); + res_names = google_protobuf_DescriptorProto_reserved_name(msg_proto, &n_res_name); + + CHK_OOM(upb_inttable_init(&m->itof, ctx->arena)); + CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena)); + + if (ctx->layout) { + /* create_fielddef() below depends on this being set. */ + UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count); + m->layout = ctx->layout->msgs[ctx->msg_count++]; + UPB_ASSERT(n_field == m->layout->field_count); + } else { + /* Allocate now (to allow cross-linking), populate later. */ + m->layout = + symtab_alloc(ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); } - symtab_errf(ctx, "Unknown escape sequence: \\%c", ch); -} -static str_t* unescape(symtab_addctx* ctx, const upb_FieldDef* f, - const char* data, size_t len) { - // Size here is an upper bound; escape sequences could ultimately shrink it. - str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len); - char* dst = &ret->str[0]; - const char* src = data; - const char* end = data + len; + SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); - while (src < end) { - if (*src == '\\') { - src++; - *dst++ = upb_DefPool_ParseEscape(ctx, f, &src, end); - } else { - *dst++ = *src++; + m->oneof_count = n_oneof; + m->oneofs = symtab_alloc(ctx, sizeof(*m->oneofs) * n_oneof); + for (i = 0; i < n_oneof; i++) { + create_oneofdef(ctx, m, oneofs[i], &m->oneofs[i]); + } + + m->field_count = n_field; + m->fields = symtab_alloc(ctx, sizeof(*m->fields) * n_field); + for (i = 0; i < n_field; i++) { + create_fielddef(ctx, m->full_name, m, fields[i], &m->fields[i], + /* is_extension= */ false); + } + + m->ext_range_count = n_ext_range; + m->ext_ranges = symtab_alloc(ctx, sizeof(*m->ext_ranges) * n_ext_range); + for (i = 0; i < n_ext_range; i++) { + const google_protobuf_DescriptorProto_ExtensionRange* r = ext_ranges[i]; + upb_ExtensionRange* r_def = (upb_ExtensionRange*)&m->ext_ranges[i]; + int32_t start = google_protobuf_DescriptorProto_ExtensionRange_start(r); + int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(r); + int32_t max = + google_protobuf_MessageOptions_message_set_wire_format(m->opts) + ? INT32_MAX + : kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + symtab_errf(ctx, "Extension range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, m->full_name); } + + r_def->start = start; + r_def->end = end; + SET_OPTIONS(r_def->opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, r); } - ret->len = dst - &ret->str[0]; - return ret; + m->res_range_count = n_res_range; + m->res_ranges = + _upb_MessageReservedRanges_New(ctx, n_res_range, res_ranges, m); + + m->res_name_count = n_res_name; + m->res_names = _upb_ReservedNames_New(ctx, n_res_name, res_names); + + finalize_oneofs(ctx, m); + assign_msg_wellknowntype(m); + upb_inttable_compact(&m->itof, ctx->arena); + msgdef_create_nested(ctx, msg_proto, m); } -static void parse_default(symtab_addctx* ctx, const char* str, size_t len, - upb_FieldDef* f) { - char* end; - char nullz[64]; - errno = 0; +static void msgdef_create_nested( + symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, + upb_MessageDef* m) { + size_t n; - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - case kUpb_CType_UInt32: - case kUpb_CType_UInt64: - case kUpb_CType_Double: - case kUpb_CType_Float: - /* Standard C number parsing functions expect null-terminated strings. */ - if (len >= sizeof(nullz) - 1) { - symtab_errf(ctx, "Default too long: %.*s", (int)len, str); - } - memcpy(nullz, str, len); - nullz[len] = '\0'; - str = nullz; - break; - default: - break; + const google_protobuf_EnumDescriptorProto* const* enums = + google_protobuf_DescriptorProto_enum_type(msg_proto, &n); + m->nested_enum_count = n; + m->nested_enums = symtab_alloc(ctx, sizeof(*m->nested_enums) * n); + for (size_t i = 0; i < n; i++) { + m->nested_enum_count = i + 1; + create_enumdef(ctx, m->full_name, enums[i], m, &m->nested_enums[i]); } - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: { - long val = strtol(str, &end, 0); - if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.sint = val; - break; - } - case kUpb_CType_Enum: { - const upb_EnumDef* e = f->sub.enumdef; - const upb_EnumValueDef* ev = - upb_EnumDef_FindValueByNameWithSize(e, str, len); - if (!ev) { - goto invalid; - } - f->defaultval.sint = ev->number; - break; - } - case kUpb_CType_Int64: { - long long val = strtoll(str, &end, 0); - if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.sint = val; - break; - } - case kUpb_CType_UInt32: { - unsigned long val = strtoul(str, &end, 0); - if (val > UINT32_MAX || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.uint = val; - break; - } - case kUpb_CType_UInt64: { - unsigned long long val = strtoull(str, &end, 0); - if (val > UINT64_MAX || errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.uint = val; - break; - } - case kUpb_CType_Double: { - double val = strtod(str, &end); - if (errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.dbl = val; - break; - } - case kUpb_CType_Float: { - float val = strtof(str, &end); - if (errno == ERANGE || *end) { - goto invalid; - } - f->defaultval.flt = val; - break; - } - case kUpb_CType_Bool: { - if (streql2(str, len, "false")) { - f->defaultval.boolean = false; - } else if (streql2(str, len, "true")) { - f->defaultval.boolean = true; - } else { - goto invalid; - } - break; - } - case kUpb_CType_String: - f->defaultval.str = newstr(ctx, str, len); - break; - case kUpb_CType_Bytes: - f->defaultval.str = unescape(ctx, f, str, len); - break; - case kUpb_CType_Message: - /* Should not have a default value. */ - symtab_errf(ctx, "Message should not have a default (%s)", - upb_FieldDef_FullName(f)); + const google_protobuf_FieldDescriptorProto* const* exts = + google_protobuf_DescriptorProto_extension(msg_proto, &n); + m->nested_ext_count = n; + m->nested_exts = symtab_alloc(ctx, sizeof(*m->nested_exts) * n); + for (size_t i = 0; i < n; i++) { + create_fielddef(ctx, m->full_name, m, exts[i], &m->nested_exts[i], + /* is_extension= */ true); + ((upb_FieldDef*)&m->nested_exts[i])->index_ = i; } - return; - -invalid: - symtab_errf(ctx, "Invalid default '%.*s' for field %s of type %d", (int)len, - str, upb_FieldDef_FullName(f), (int)upb_FieldDef_Type(f)); + const google_protobuf_DescriptorProto* const* msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + m->nested_msg_count = n; + m->nested_msgs = symtab_alloc(ctx, sizeof(*m->nested_msgs) * n); + for (size_t i = 0; i < n; i++) { + create_msgdef(ctx, m->full_name, msgs[i], m, &m->nested_msgs[i]); + } } -static void set_default_default(symtab_addctx* ctx, upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Int32: - case kUpb_CType_Int64: - f->defaultval.sint = 0; - break; - case kUpb_CType_UInt64: - case kUpb_CType_UInt32: - f->defaultval.uint = 0; - break; - case kUpb_CType_Double: - case kUpb_CType_Float: - f->defaultval.dbl = 0; - break; - case kUpb_CType_String: - case kUpb_CType_Bytes: - f->defaultval.str = newstr(ctx, NULL, 0); +static void resolve_subdef(symtab_addctx* ctx, const char* prefix, + upb_FieldDef* f) { + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; + upb_StringView name = + google_protobuf_FieldDescriptorProto_type_name(field_proto); + bool has_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); + switch ((int)f->type_) { + case FIELD_TYPE_UNSPECIFIED: { + // Type was not specified and must be inferred. + UPB_ASSERT(has_name); + upb_deftype_t type; + const void* def = + symtab_resolveany(ctx, f->full_name, prefix, name, &type); + switch (type) { + case UPB_DEFTYPE_ENUM: + f->sub.enumdef = def; + f->type_ = kUpb_FieldType_Enum; + break; + case UPB_DEFTYPE_MSG: + f->sub.msgdef = def; + f->type_ = kUpb_FieldType_Message; // It appears there is no way of + // this being a group. + break; + default: + symtab_errf(ctx, "Couldn't resolve type name for field %s", + f->full_name); + } + } + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + UPB_ASSERT(has_name); + f->sub.msgdef = + symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); break; - case kUpb_CType_Bool: - f->defaultval.boolean = false; + case kUpb_FieldType_Enum: + UPB_ASSERT(has_name); + f->sub.enumdef = + symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_ENUM); break; - case kUpb_CType_Enum: - f->defaultval.sint = f->sub.enumdef->values[0].number; - case kUpb_CType_Message: + default: + // No resolution necessary. break; } } -static void create_fielddef( - symtab_addctx* ctx, const char* prefix, upb_MessageDef* m, - const google_protobuf_FieldDescriptorProto* field_proto, - const upb_FieldDef* _f, bool is_extension) { - upb_FieldDef* f = (upb_FieldDef*)_f; - upb_StringView name; - const char* full_name; - const char* json_name; - const char* shortname; - int32_t field_number; +static void resolve_extension( + symtab_addctx* ctx, const char* prefix, upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { + symtab_errf(ctx, "extension for field '%s' had no extendee", f->full_name); + } - f->file = ctx->file; /* Must happen prior to symtab_add(). */ + upb_StringView name = + google_protobuf_FieldDescriptorProto_extendee(field_proto); + const upb_MessageDef* m = + symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); + f->msgdef = m; - if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - symtab_errf(ctx, "field has no name"); + bool found = false; + + for (int i = 0, n = m->ext_range_count; i < n; i++) { + const upb_ExtensionRange* r = &m->ext_ranges[i]; + if (r->start <= f->number_ && f->number_ < r->end) { + found = true; + break; + } } - name = google_protobuf_FieldDescriptorProto_name(field_proto); - check_ident(ctx, name, false); - full_name = makefullname(ctx, prefix, name); - shortname = shortdefname(full_name); + if (!found) { + symtab_errf(ctx, + "field number %u in extension %s has no extension range in " + "message %s", + (unsigned)f->number_, f->full_name, f->msgdef->full_name); + } - if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { - json_name = strviewdup( - ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto)); - f->has_json_name_ = true; + const upb_MiniTable_Extension* ext = ctx->file->ext_layouts[f->layout_index]; + if (ctx->layout) { + UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); } else { - json_name = makejsonname(ctx, shortname); - f->has_json_name_ = false; + upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; + fill_fieldlayout(&mut_ext->field, f); + mut_ext->field.presence = 0; + mut_ext->field.offset = 0; + mut_ext->field.submsg_index = 0; + mut_ext->extendee = f->msgdef->layout; + mut_ext->sub.submsg = f->sub.msgdef->layout; } - field_number = google_protobuf_FieldDescriptorProto_number(field_proto); - - f->full_name = full_name; - f->json_name = json_name; - f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); - f->number_ = field_number; - f->scope.oneof = NULL; - f->proto3_optional_ = - google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + CHK_OOM(upb_inttable_insert(&ctx->symtab->exts, (uintptr_t)ext, + upb_value_constptr(f), ctx->arena)); +} - bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); - bool has_type_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); +static void resolve_default( + symtab_addctx* ctx, upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + // Have to delay resolving of the default value until now because of the enum + // case, since enum defaults are specified with a label. + if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { + upb_StringView defaultval = + google_protobuf_FieldDescriptorProto_default_value(field_proto); - f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); + if (f->file->syntax == kUpb_Syntax_Proto3) { + symtab_errf(ctx, "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } - if (has_type) { - switch (f->type_) { - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - case kUpb_FieldType_Enum: - if (!has_type_name) { - symtab_errf(ctx, "field of type %d requires type name (%s)", - (int)f->type_, full_name); - } - break; - default: - if (has_type_name) { - symtab_errf(ctx, "invalid type for field with type_name set (%s, %d)", - full_name, (int)f->type_); - } + if (upb_FieldDef_IsSubMessage(f)) { + symtab_errf(ctx, "message fields cannot have explicit defaults (%s)", + f->full_name); } - } else if (has_type_name) { - f->type_ = - FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef(). + + parse_default(ctx, defaultval.data, defaultval.size, f); + f->has_default = true; + } else { + set_default_default(ctx, f); + f->has_default = false; } +} - if (!is_extension) { - /* direct message field. */ - upb_value v, field_v, json_v, existing_v; - size_t json_size; +static void resolve_fielddef(symtab_addctx* ctx, const char* prefix, + upb_FieldDef* f) { + // We have to stash this away since resolve_subdef() may overwrite it. + const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; - if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { - symtab_errf(ctx, "invalid field number (%u)", field_number); - } + resolve_subdef(ctx, prefix, f); + resolve_default(ctx, f, field_proto); - f->index_ = f - m->fields; - f->msgdef = m; - f->is_extension_ = false; + if (f->is_extension_) { + resolve_extension(ctx, prefix, f, field_proto); + } +} - field_v = pack_def(f, UPB_DEFTYPE_FIELD); - json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME); - v = upb_value_constptr(f); - json_size = strlen(json_name); +static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]); + } - if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { - symtab_errf(ctx, "duplicate field name (%s)", shortname); + m->in_message_set = false; + for (int i = 0; i < m->nested_ext_count; i++) { + upb_FieldDef* ext = (upb_FieldDef*)&m->nested_exts[i]; + resolve_fielddef(ctx, m->full_name, ext); + if (ext->type_ == kUpb_FieldType_Message && + ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m && + google_protobuf_MessageOptions_message_set_wire_format( + ext->msgdef->opts)) { + m->in_message_set = true; } + } - CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v, - ctx->arena)); + if (!ctx->layout) make_layout(ctx, m); - if (strcmp(shortname, json_name) != 0) { - if (upb_strtable_lookup(&m->ntof, json_name, &v)) { - symtab_errf(ctx, "duplicate json_name (%s)", json_name); - } else { - CHK_OOM(upb_strtable_insert(&m->ntof, json_name, json_size, json_v, - ctx->arena)); - } - } + for (int i = 0; i < m->nested_msg_count; i++) { + resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]); + } +} - if (upb_inttable_lookup(&m->itof, field_number, NULL)) { - symtab_errf(ctx, "duplicate field number (%u)", field_number); - } +static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { + size_t n; + google_protobuf_DescriptorProto_extension(msg_proto, &n); + int ext_count = n; - CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena)); + const google_protobuf_DescriptorProto* const* nested_msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + for (size_t i = 0; i < n; i++) { + ext_count += count_exts_in_msg(nested_msgs[i]); + } - if (ctx->layout) { - const upb_MiniTable_Field* fields = m->layout->fields; - int count = m->layout->field_count; - bool found = false; - for (int i = 0; i < count; i++) { - if (fields[i].number == field_number) { - f->layout_index = i; - found = true; - break; - } - } - UPB_ASSERT(found); + return ext_count; +} + +static void build_filedef( + symtab_addctx* ctx, upb_FileDef* file, + const google_protobuf_FileDescriptorProto* file_proto) { + const google_protobuf_DescriptorProto* const* msgs; + const google_protobuf_EnumDescriptorProto* const* enums; + const google_protobuf_FieldDescriptorProto* const* exts; + const google_protobuf_ServiceDescriptorProto* const* services; + const upb_StringView* strs; + const int32_t* public_deps; + const int32_t* weak_deps; + size_t i, n; + + file->symtab = ctx->symtab; + + /* Count all extensions in the file, to build a flat array of layouts. */ + google_protobuf_FileDescriptorProto_extension(file_proto, &n); + int ext_count = n; + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + for (int i = 0; i < n; i++) { + ext_count += count_exts_in_msg(msgs[i]); + } + file->ext_count = ext_count; + + if (ctx->layout) { + /* We are using the ext layouts that were passed in. */ + file->ext_layouts = ctx->layout->exts; + if (ctx->layout->ext_count != file->ext_count) { + symtab_errf(ctx, "Extension count did not match layout (%d vs %d)", + ctx->layout->ext_count, file->ext_count); } } else { - /* extension field. */ - f->is_extension_ = true; - f->scope.extension_scope = m; - symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_EXT)); - f->layout_index = ctx->ext_count++; - if (ctx->layout) { - UPB_ASSERT(ctx->file->ext_layouts[f->layout_index]->field.number == - field_number); + /* We are building ext layouts from scratch. */ + file->ext_layouts = + symtab_alloc(ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_MiniTable_Extension* ext = + symtab_alloc(ctx, sizeof(*ext) * file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; } } - if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { - symtab_errf(ctx, "invalid type for field %s (%d)", f->full_name, f->type_); + if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { + symtab_errf(ctx, "File has no name"); } - if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { - symtab_errf(ctx, "invalid label for field %s (%d)", f->full_name, - f->label_); + file->name = + strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); + + upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); + if (package.size) { + check_ident(ctx, package, true); + file->package = strviewdup(ctx, package); + } else { + file->package = NULL; } - /* We can't resolve the subdef or (in the case of extensions) the containing - * message yet, because it may not have been defined yet. We stash a pointer - * to the field_proto until later when we can properly resolve it. */ - f->sub.unresolved = field_proto; + if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { + upb_StringView syntax = + google_protobuf_FileDescriptorProto_syntax(file_proto); - if (f->label_ == kUpb_Label_Required && - f->file->syntax == kUpb_Syntax_Proto3) { - symtab_errf(ctx, "proto3 fields cannot be required (%s)", f->full_name); + if (streql_view(syntax, "proto2")) { + file->syntax = kUpb_Syntax_Proto2; + } else if (streql_view(syntax, "proto3")) { + file->syntax = kUpb_Syntax_Proto3; + } else { + symtab_errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(syntax)); + } + } else { + file->syntax = kUpb_Syntax_Proto2; } - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - int oneof_index = - google_protobuf_FieldDescriptorProto_oneof_index(field_proto); - upb_OneofDef* oneof; - upb_value v = upb_value_constptr(f); + /* Read options. */ + SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); - if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { - symtab_errf(ctx, "fields in oneof must have OPTIONAL label (%s)", - f->full_name); - } + /* Verify dependencies. */ + strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); + file->dep_count = n; + file->deps = symtab_alloc(ctx, sizeof(*file->deps) * n); - if (!m) { - symtab_errf(ctx, "oneof_index provided for extension field (%s)", - f->full_name); + for (i = 0; i < n; i++) { + upb_StringView str = strs[i]; + file->deps[i] = + upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); + if (!file->deps[i]) { + symtab_errf(ctx, + "Depends on file '" UPB_STRINGVIEW_FORMAT + "', but it has not been loaded", + UPB_STRINGVIEW_ARGS(str)); } + } - if (oneof_index >= m->oneof_count) { - symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name); + public_deps = + google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); + file->public_dep_count = n; + file->public_deps = symtab_alloc(ctx, sizeof(*file->public_deps) * n); + int32_t* mutable_public_deps = (int32_t*)file->public_deps; + for (i = 0; i < n; i++) { + if (public_deps[i] >= file->dep_count) { + symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]); } + mutable_public_deps[i] = public_deps[i]; + } - oneof = (upb_OneofDef*)&m->oneofs[oneof_index]; - f->scope.oneof = oneof; - - oneof->field_count++; - if (f->proto3_optional_) { - oneof->synthetic = true; - } - CHK_OOM(upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena)); - CHK_OOM( - upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); - } else { - if (f->proto3_optional_) { - symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)", - f->full_name); + weak_deps = + google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); + file->weak_dep_count = n; + file->weak_deps = symtab_alloc(ctx, sizeof(*file->weak_deps) * n); + int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; + for (i = 0; i < n; i++) { + if (weak_deps[i] >= file->dep_count) { + symtab_errf(ctx, "weak_dep %d is out of range", (int)weak_deps[i]); } + mutable_weak_deps[i] = weak_deps[i]; } - SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); - - if (google_protobuf_FieldOptions_has_packed(f->opts)) { - f->packed_ = google_protobuf_FieldOptions_packed(f->opts); - } else { - /* Repeated fields default to packed for proto3 only. */ - f->packed_ = upb_FieldDef_IsPrimitive(f) && - f->label_ == kUpb_Label_Repeated && - f->file->syntax == kUpb_Syntax_Proto3; + /* Create enums. */ + enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + file->top_lvl_enum_count = n; + file->top_lvl_enums = symtab_alloc(ctx, sizeof(*file->top_lvl_enums) * n); + for (i = 0; i < n; i++) { + create_enumdef(ctx, file->package, enums[i], NULL, &file->top_lvl_enums[i]); } -} - -static void create_service( - symtab_addctx* ctx, const google_protobuf_ServiceDescriptorProto* svc_proto, - const upb_ServiceDef* _s) { - upb_ServiceDef* s = (upb_ServiceDef*)_s; - upb_StringView name; - const google_protobuf_MethodDescriptorProto* const* methods; - size_t i, n; - - s->file = ctx->file; /* Must happen prior to symtab_add. */ - - name = google_protobuf_ServiceDescriptorProto_name(svc_proto); - check_ident(ctx, name, false); - s->full_name = makefullname(ctx, ctx->file->package, name); - symtab_add(ctx, s->full_name, pack_def(s, UPB_DEFTYPE_SERVICE)); - methods = google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); - - s->method_count = n; - s->methods = symtab_alloc(ctx, sizeof(*s->methods) * n); - - SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, svc_proto); + /* Create extensions. */ + exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->top_lvl_ext_count = n; + file->top_lvl_exts = symtab_alloc(ctx, sizeof(*file->top_lvl_exts) * n); + for (i = 0; i < n; i++) { + create_fielddef(ctx, file->package, NULL, exts[i], &file->top_lvl_exts[i], + /* is_extension= */ true); + ((upb_FieldDef*)&file->top_lvl_exts[i])->index_ = i; + } + /* Create messages. */ + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + file->top_lvl_msg_count = n; + file->top_lvl_msgs = symtab_alloc(ctx, sizeof(*file->top_lvl_msgs) * n); for (i = 0; i < n; i++) { - const google_protobuf_MethodDescriptorProto* method_proto = methods[i]; - upb_MethodDef* m = (upb_MethodDef*)&s->methods[i]; - upb_StringView name = - google_protobuf_MethodDescriptorProto_name(method_proto); + create_msgdef(ctx, file->package, msgs[i], NULL, &file->top_lvl_msgs[i]); + } - m->service = s; - m->full_name = makefullname(ctx, s->full_name, name); - m->index = i; - m->client_streaming = - google_protobuf_MethodDescriptorProto_client_streaming(method_proto); - m->server_streaming = - google_protobuf_MethodDescriptorProto_server_streaming(method_proto); - m->input_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_input_type(method_proto), - UPB_DEFTYPE_MSG); - m->output_type = symtab_resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_output_type(method_proto), - UPB_DEFTYPE_MSG); + /* Create services. */ + services = google_protobuf_FileDescriptorProto_service(file_proto, &n); + file->service_count = n; + file->services = symtab_alloc(ctx, sizeof(*file->services) * n); + for (i = 0; i < n; i++) { + create_service(ctx, services[i], &file->services[i]); + ((upb_ServiceDef*)&file->services[i])->index = i; + } - SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, method_proto); + /* Now that all names are in the table, build layouts and resolve refs. */ + for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) { + resolve_fielddef(ctx, file->package, (upb_FieldDef*)&file->top_lvl_exts[i]); } -} -static int count_bits_debug(uint64_t x) { - // For assertions only, speed does not matter. - int n = 0; - while (x) { - if (x & 1) n++; - x >>= 1; + for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) { + resolve_msgdef(ctx, (upb_MessageDef*)&file->top_lvl_msgs[i]); } - return n; -} -static int compare_int32(const void* a_ptr, const void* b_ptr) { - int32_t a = *(int32_t*)a_ptr; - int32_t b = *(int32_t*)b_ptr; - return a < b ? -1 : (a == b ? 0 : 1); + if (file->ext_count) { + CHK_OOM(_upb_extreg_add(ctx->symtab->extreg, file->ext_layouts, + file->ext_count)); + } } -upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, - const upb_EnumDef* e) { - int n = 0; - uint64_t mask = 0; - - for (int i = 0; i < e->value_count; i++) { - uint32_t val = (uint32_t)e->values[i].number; - if (val < 64) { - mask |= 1ULL << val; - } else { - n++; +static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { + intptr_t iter = UPB_INTTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { + const upb_FileDef* f; + switch (deftype(val)) { + case UPB_DEFTYPE_EXT: + f = upb_FieldDef_File(unpack_def(val, UPB_DEFTYPE_EXT)); + break; + case UPB_DEFTYPE_MSG: + f = upb_MessageDef_File(unpack_def(val, UPB_DEFTYPE_MSG)); + break; + case UPB_DEFTYPE_ENUM: + f = upb_EnumDef_File(unpack_def(val, UPB_DEFTYPE_ENUM)); + break; + case UPB_DEFTYPE_ENUMVAL: + f = upb_EnumDef_File( + upb_EnumValueDef_Enum(unpack_def(val, UPB_DEFTYPE_ENUMVAL))); + break; + case UPB_DEFTYPE_SERVICE: + f = upb_ServiceDef_File(unpack_def(val, UPB_DEFTYPE_SERVICE)); + break; + default: + UPB_UNREACHABLE(); } - } - int32_t* values = symtab_alloc(ctx, sizeof(*values) * n); + if (f == file) upb_strtable_removeiter(&s->syms, &iter); + } +} - if (n) { - int32_t* p = values; +static const upb_FileDef* _upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + const upb_MiniTable_File* layout, upb_Status* status) { + symtab_addctx ctx; + upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); + upb_value v; - // Add values outside the bitmask range to the list, as described in the - // comments for upb_MiniTable_Enum. - for (int i = 0; i < e->value_count; i++) { - int32_t val = e->values[i].number; - if ((uint32_t)val >= 64) { - *p++ = val; - } + if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { + if (unpack_def(v, UPB_DEFTYPE_FILE)) { + upb_Status_SetErrorFormat(status, "duplicate file name (%.*s)", + UPB_STRINGVIEW_ARGS(name)); + return NULL; } - UPB_ASSERT(p == values + n); + const upb_MiniTable_File* registered = unpack_def(v, UPB_DEFTYPE_LAYOUT); + UPB_ASSERT(registered); + if (layout && layout != registered) { + upb_Status_SetErrorFormat( + status, "tried to build with a different layout (filename=%.*s)", + UPB_STRINGVIEW_ARGS(name)); + return NULL; + } + layout = registered; } - // Enums can have duplicate values; we must sort+uniq them. - if (values) qsort(values, n, sizeof(*values), &compare_int32); + ctx.symtab = s; + ctx.layout = layout; + ctx.msg_count = 0; + ctx.enum_count = 0; + ctx.ext_count = 0; + ctx.status = status; + ctx.file = NULL; + ctx.arena = upb_Arena_New(); + ctx.tmp_arena = upb_Arena_New(); - int dst = 0; - for (int i = 0; i < n; dst++) { - int32_t val = values[i]; - while (i < n && values[i] == val) i++; // Skip duplicates. - values[dst] = val; + if (!ctx.arena || !ctx.tmp_arena) { + if (ctx.arena) upb_Arena_Free(ctx.arena); + if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); + upb_Status_setoom(status); + return NULL; } - n = dst; - UPB_ASSERT(upb_inttable_count(&e->iton) == n + count_bits_debug(mask)); + if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) { + UPB_ASSERT(!upb_Status_IsOk(status)); + if (ctx.file) { + remove_filedef(s, ctx.file); + ctx.file = NULL; + } + } else { + ctx.file = symtab_alloc(&ctx, sizeof(*ctx.file)); + build_filedef(&ctx, ctx.file, file_proto); + upb_strtable_insert(&s->files, name.data, name.size, + pack_def(ctx.file, UPB_DEFTYPE_FILE), ctx.arena); + UPB_ASSERT(upb_Status_IsOk(status)); + upb_Arena_Fuse(s->arena, ctx.arena); + } - upb_MiniTable_Enum* layout = symtab_alloc(ctx, sizeof(*layout)); - layout->value_count = n; - layout->mask = mask; - layout->values = values; + upb_Arena_Free(ctx.arena); + upb_Arena_Free(ctx.tmp_arena); + return ctx.file; +} - return layout; +const upb_FileDef* upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + upb_Status* status) { + return _upb_DefPool_AddFile(s, file_proto, NULL, status); } -static void create_enumvaldef( - symtab_addctx* ctx, const char* prefix, - const google_protobuf_EnumValueDescriptorProto* val_proto, upb_EnumDef* e, - int i) { - upb_EnumValueDef* val = (upb_EnumValueDef*)&e->values[i]; - upb_StringView name = - google_protobuf_EnumValueDescriptorProto_name(val_proto); - upb_value v = upb_value_constptr(val); +/* Include here since we want most of this file to be stdio-free. */ +#include - val->parent = e; /* Must happen prior to symtab_add(). */ - val->full_name = makefullname(ctx, prefix, name); - val->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); - symtab_add(ctx, val->full_name, pack_def(val, UPB_DEFTYPE_ENUMVAL)); +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable) { + /* Since this function should never fail (it would indicate a bug in upb) we + * print errors to stderr instead of returning error status to the user. */ + _upb_DefPool_Init** deps = init->deps; + google_protobuf_FileDescriptorProto* file; + upb_Arena* arena; + upb_Status status; - SET_OPTIONS(val->opts, EnumValueDescriptorProto, EnumValueOptions, val_proto); + upb_Status_Clear(&status); - if (i == 0 && e->file->syntax == kUpb_Syntax_Proto3 && val->number != 0) { - symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)", - e->full_name); + if (upb_DefPool_FindFileByName(s, init->filename)) { + return true; } - CHK_OOM(upb_strtable_insert(&e->ntoi, name.data, name.size, v, ctx->arena)); + arena = upb_Arena_New(); - // Multiple enumerators can have the same number, first one wins. - if (!upb_inttable_lookup(&e->iton, val->number, NULL)) { - CHK_OOM(upb_inttable_insert(&e->iton, val->number, v, ctx->arena)); + for (; *deps; deps++) { + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; } -} - -static void create_enumdef( - symtab_addctx* ctx, const char* prefix, - const google_protobuf_EnumDescriptorProto* enum_proto, - const upb_MessageDef* containing_type, const upb_EnumDef* _e) { - upb_EnumDef* e = (upb_EnumDef*)_e; - ; - const google_protobuf_EnumValueDescriptorProto* const* values; - upb_StringView name; - size_t i, n; - - e->file = ctx->file; /* Must happen prior to symtab_add() */ - e->containing_type = containing_type; - - name = google_protobuf_EnumDescriptorProto_name(enum_proto); - check_ident(ctx, name, false); - - e->full_name = makefullname(ctx, prefix, name); - symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); - values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); - CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena)); - CHK_OOM(upb_inttable_init(&e->iton, ctx->arena)); - - e->defaultval = 0; - e->value_count = n; - e->values = symtab_alloc(ctx, sizeof(*e->values) * n); + file = google_protobuf_FileDescriptorProto_parse_ex( + init->descriptor.data, init->descriptor.size, NULL, + kUpb_DecodeOption_AliasString, arena); + s->bytes_loaded += init->descriptor.size; - if (n == 0) { - symtab_errf(ctx, "enums must contain at least one value (%s)", - e->full_name); + if (!file) { + upb_Status_SetErrorFormat( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; } - SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); - - for (i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, values[i], e, i); + const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { + goto err; } - upb_inttable_compact(&e->iton, ctx->arena); + upb_Arena_Free(arena); + return true; - if (e->file->syntax == kUpb_Syntax_Proto2) { - if (ctx->layout) { - UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); - e->layout = ctx->layout->enums[ctx->enum_count++]; - UPB_ASSERT(upb_inttable_count(&e->iton) == - e->layout->value_count + count_bits_debug(e->layout->mask)); - } else { - e->layout = create_enumlayout(ctx, e); - } - } else { - e->layout = NULL; - } +err: + fprintf(stderr, + "Error loading compiled-in descriptor for file '%s' (this should " + "never happen): %s\n", + init->filename, upb_Status_ErrorMessage(&status)); + upb_Arena_Free(arena); + return false; } -static void msgdef_create_nested( - symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m); - -static void create_msgdef(symtab_addctx* ctx, const char* prefix, - const google_protobuf_DescriptorProto* msg_proto, - const upb_MessageDef* containing_type, - const upb_MessageDef* _m) { - upb_MessageDef* m = (upb_MessageDef*)_m; - const google_protobuf_OneofDescriptorProto* const* oneofs; - const google_protobuf_FieldDescriptorProto* const* fields; - const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; - size_t i, n_oneof, n_field, n_ext_range; - upb_StringView name; +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { + return s->bytes_loaded; +} - m->file = ctx->file; /* Must happen prior to symtab_add(). */ - m->containing_type = containing_type; +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } - name = google_protobuf_DescriptorProto_name(msg_proto); - check_ident(ctx, name, false); +const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTable_Extension* ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} - m->full_name = makefullname(ctx, prefix, name); - symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG)); +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum) { + const upb_MiniTable* l = upb_MessageDef_MiniTable(m); + const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); + return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +} - oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); - fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); - ext_ranges = - google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); +bool _upb_DefPool_registerlayout(upb_DefPool* s, const char* filename, + const upb_MiniTable_File* file) { + if (upb_DefPool_FindFileByName(s, filename)) return false; + upb_value v = pack_def(file, UPB_DEFTYPE_LAYOUT); + return upb_strtable_insert(&s->files, filename, strlen(filename), v, + s->arena); +} - CHK_OOM(upb_inttable_init(&m->itof, ctx->arena)); - CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena)); +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s) { + return s->extreg; +} - if (ctx->layout) { - /* create_fielddef() below depends on this being set. */ - UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count); - m->layout = ctx->layout->msgs[ctx->msg_count++]; - UPB_ASSERT(n_field == m->layout->field_count); - } else { - /* Allocate now (to allow cross-linking), populate later. */ - m->layout = - symtab_alloc(ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); +const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, + const upb_MessageDef* m, + size_t* count) { + size_t n = 0; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + // This is O(all exts) instead of O(exts for m). If we need this to be + // efficient we may need to make extreg into a two-level table, or have a + // second per-message index. + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) n++; } - - SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); - - m->oneof_count = n_oneof; - m->oneofs = symtab_alloc(ctx, sizeof(*m->oneofs) * n_oneof); - for (i = 0; i < n_oneof; i++) { - create_oneofdef(ctx, m, oneofs[i], &m->oneofs[i]); + const upb_FieldDef** exts = malloc(n * sizeof(*exts)); + iter = UPB_INTTABLE_BEGIN; + size_t i = 0; + while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; } + *count = n; + return exts; +} - m->field_count = n_field; - m->fields = symtab_alloc(ctx, sizeof(*m->fields) * n_field); - for (i = 0; i < n_field; i++) { - create_fielddef(ctx, m->full_name, m, fields[i], &m->fields[i], - /* is_extension= */ false); - } +#undef CHK_OOM - m->ext_range_count = n_ext_range; - m->ext_ranges = symtab_alloc(ctx, sizeof(*m->ext_ranges) * n_ext_range); - for (i = 0; i < n_ext_range; i++) { - const google_protobuf_DescriptorProto_ExtensionRange* r = ext_ranges[i]; - upb_ExtensionRange* r_def = (upb_ExtensionRange*)&m->ext_ranges[i]; - int32_t start = google_protobuf_DescriptorProto_ExtensionRange_start(r); - int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(r); - int32_t max = - google_protobuf_MessageOptions_message_set_wire_format(m->opts) - ? INT32_MAX - : kUpb_MaxFieldNumber + 1; +/** upb/reflection.c ************************************************************/ - // A full validation would also check that each range is disjoint, and that - // none of the fields overlap with the extension ranges, but we are just - // sanity checking here. - if (start < 1 || end <= start || end > max) { - symtab_errf(ctx, "Extension range (%d, %d) is invalid, message=%s\n", - (int)start, (int)end, m->full_name); - } +#include - r_def->start = start; - r_def->end = end; - SET_OPTIONS(r_def->opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, r); - } - finalize_oneofs(ctx, m); - assign_msg_wellknowntype(m); - upb_inttable_compact(&m->itof, ctx->arena); - msgdef_create_nested(ctx, msg_proto, m); +static size_t get_field_size(const upb_MiniTable_Field* f) { + static unsigned char sizes[] = { + 0, /* 0 */ + 8, /* kUpb_FieldType_Double */ + 4, /* kUpb_FieldType_Float */ + 8, /* kUpb_FieldType_Int64 */ + 8, /* kUpb_FieldType_UInt64 */ + 4, /* kUpb_FieldType_Int32 */ + 8, /* kUpb_FieldType_Fixed64 */ + 4, /* kUpb_FieldType_Fixed32 */ + 1, /* kUpb_FieldType_Bool */ + sizeof(upb_StringView), /* kUpb_FieldType_String */ + sizeof(void*), /* kUpb_FieldType_Group */ + sizeof(void*), /* kUpb_FieldType_Message */ + sizeof(upb_StringView), /* kUpb_FieldType_Bytes */ + 4, /* kUpb_FieldType_UInt32 */ + 4, /* kUpb_FieldType_Enum */ + 4, /* kUpb_FieldType_SFixed32 */ + 8, /* kUpb_FieldType_SFixed64 */ + 4, /* kUpb_FieldType_SInt32 */ + 8, /* kUpb_FieldType_SInt64 */ + }; + return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; } -static void msgdef_create_nested( - symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto, - upb_MessageDef* m) { - size_t n; +/** upb_Message + * *******************************************************************/ - const google_protobuf_EnumDescriptorProto* const* enums = - google_protobuf_DescriptorProto_enum_type(msg_proto, &n); - m->nested_enum_count = n; - m->nested_enums = symtab_alloc(ctx, sizeof(*m->nested_enums) * n); - for (size_t i = 0; i < n; i++) { - m->nested_enum_count = i + 1; - create_enumdef(ctx, m->full_name, enums[i], m, &m->nested_enums[i]); - } +upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) { + return _upb_Message_New(upb_MessageDef_MiniTable(m), a); +} - const google_protobuf_FieldDescriptorProto* const* exts = - google_protobuf_DescriptorProto_extension(msg_proto, &n); - m->nested_ext_count = n; - m->nested_exts = symtab_alloc(ctx, sizeof(*m->nested_exts) * n); - for (size_t i = 0; i < n; i++) { - create_fielddef(ctx, m->full_name, m, exts[i], &m->nested_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&m->nested_exts[i])->index_ = i; - } +static bool in_oneof(const upb_MiniTable_Field* field) { + return field->presence < 0; +} - const google_protobuf_DescriptorProto* const* msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - m->nested_msg_count = n; - m->nested_msgs = symtab_alloc(ctx, sizeof(*m->nested_msgs) * n); - for (size_t i = 0; i < n; i++) { - create_msgdef(ctx, m->full_name, msgs[i], m, &m->nested_msgs[i]); - } +static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, + const upb_FieldDef* f) { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + const char* mem = UPB_PTR_AT(msg, field->offset, char); + upb_MessageValue val = {0}; + memcpy(&val, mem, get_field_size(field)); + return val; } -static void resolve_subdef(symtab_addctx* ctx, const char* prefix, - upb_FieldDef* f) { - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; - upb_StringView name = - google_protobuf_FieldDescriptorProto_type_name(field_proto); - bool has_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); - switch ((int)f->type_) { - case FIELD_TYPE_UNSPECIFIED: { - // Type was not specified and must be inferred. - UPB_ASSERT(has_name); - upb_deftype_t type; - const void* def = - symtab_resolveany(ctx, f->full_name, prefix, name, &type); - switch (type) { - case UPB_DEFTYPE_ENUM: - f->sub.enumdef = def; - f->type_ = kUpb_FieldType_Enum; - break; - case UPB_DEFTYPE_MSG: - f->sub.msgdef = def; - f->type_ = kUpb_FieldType_Message; // It appears there is no way of - // this being a group. - break; - default: - symtab_errf(ctx, "Couldn't resolve type name for field %s", - f->full_name); - } +bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { + assert(upb_FieldDef_HasPresence(f)); + if (upb_FieldDef_IsExtension(f)) { + const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); + return _upb_Message_Getext(msg, ext) != NULL; + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + if (in_oneof(field)) { + return _upb_getoneofcase_field(msg, field) == field->number; + } else if (field->presence > 0) { + return _upb_hasbit_field(msg, field); + } else { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + return _upb_Message_Getraw(msg, f).msg_val != NULL; } - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - UPB_ASSERT(has_name); - f->sub.msgdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - break; - case kUpb_FieldType_Enum: - UPB_ASSERT(has_name); - f->sub.enumdef = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_ENUM); - break; - default: - // No resolution necessary. - break; } } -static void resolve_extension( - symtab_addctx* ctx, const char* prefix, upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { - symtab_errf(ctx, "extension for field '%s' had no extendee", f->full_name); +const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, + const upb_OneofDef* o) { + const upb_FieldDef* f = upb_OneofDef_Field(o, 0); + if (upb_OneofDef_IsSynthetic(o)) { + UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); + return upb_Message_Has(msg, f) ? f : NULL; + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + uint32_t oneof_case = _upb_getoneofcase_field(msg, field); + f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; + UPB_ASSERT((f != NULL) == (oneof_case != 0)); + return f; } +} - upb_StringView name = - google_protobuf_FieldDescriptorProto_extendee(field_proto); - const upb_MessageDef* m = - symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - f->msgdef = m; - - bool found = false; - - for (int i = 0, n = m->ext_range_count; i < n; i++) { - const upb_ExtensionRange* r = &m->ext_ranges[i]; - if (r->start <= f->number_ && f->number_ < r->end) { - found = true; - break; +upb_MessageValue upb_Message_Get(const upb_Message* msg, + const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + const upb_Message_Extension* ext = + _upb_Message_Getext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + if (ext) { + upb_MessageValue val; + memcpy(&val, &ext->data, sizeof(val)); + return val; + } else if (upb_FieldDef_IsRepeated(f)) { + return (upb_MessageValue){.array_val = NULL}; } + } else if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { + return _upb_Message_Getraw(msg, f); } + return upb_FieldDef_Default(f); +} - if (!found) { - symtab_errf(ctx, - "field number %u in extension %s has no extension range in " - "message %s", - (unsigned)f->number_, f->full_name, f->msgdef->full_name); +upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, + const upb_FieldDef* f, + upb_Arena* a) { + UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); + if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) { + // We need to skip the upb_Message_Get() call in this case. + goto make; } - const upb_MiniTable_Extension* ext = ctx->file->ext_layouts[f->layout_index]; - if (ctx->layout) { - UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); + upb_MessageValue val = upb_Message_Get(msg, f); + if (val.array_val) { + return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; + } + + upb_MutableMessageValue ret; +make: + if (!a) return (upb_MutableMessageValue){.array = NULL}; + if (upb_FieldDef_IsMap(f)) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); + const upb_FieldDef* value = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); + ret.map = + upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); + } else if (upb_FieldDef_IsRepeated(f)) { + ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); } else { - upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; - fill_fieldlayout(&mut_ext->field, f); - mut_ext->field.presence = 0; - mut_ext->field.offset = 0; - mut_ext->field.submsg_index = 0; - mut_ext->extendee = f->msgdef->layout; - mut_ext->sub.submsg = f->sub.msgdef->layout; + UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); + ret.msg = upb_Message_New(upb_FieldDef_MessageSubDef(f), a); } - CHK_OOM(upb_inttable_insert(&ctx->symtab->exts, (uintptr_t)ext, - upb_value_constptr(f), ctx->arena)); + val.array_val = ret.array; + upb_Message_Set(msg, f, val, a); + + return ret; } -static void resolve_default( - symtab_addctx* ctx, upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - // Have to delay resolving of the default value until now because of the enum - // case, since enum defaults are specified with a label. - if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { - upb_StringView defaultval = - google_protobuf_FieldDescriptorProto_default_value(field_proto); - - if (f->file->syntax == kUpb_Syntax_Proto3) { - symtab_errf(ctx, "proto3 fields cannot have explicit defaults (%s)", - f->full_name); +bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a) { + if (upb_FieldDef_IsExtension(f)) { + upb_Message_Extension* ext = _upb_Message_GetOrCreateExtension( + msg, _upb_FieldDef_ExtensionMiniTable(f), a); + if (!ext) return false; + memcpy(&ext->data, &val, sizeof(val)); + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + char* mem = UPB_PTR_AT(msg, field->offset, char); + memcpy(mem, &val, get_field_size(field)); + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (in_oneof(field)) { + *_upb_oneofcase_field(msg, field) = field->number; } + } + return true; +} - if (upb_FieldDef_IsSubMessage(f)) { - symtab_errf(ctx, "message fields cannot have explicit defaults (%s)", - f->full_name); +void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { + if (upb_FieldDef_IsExtension(f)) { + _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + } else { + const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); + char* mem = UPB_PTR_AT(msg, field->offset, char); + + if (field->presence > 0) { + _upb_clearhas_field(msg, field); + } else if (in_oneof(field)) { + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (*oneof_case != field->number) return; + *oneof_case = 0; } - parse_default(ctx, defaultval.data, defaultval.size, f); - f->has_default = true; - } else { - set_default_default(ctx, f); - f->has_default = false; + memset(mem, 0, get_field_size(field)); } } -static void resolve_fielddef(symtab_addctx* ctx, const char* prefix, - upb_FieldDef* f) { - // We have to stash this away since resolve_subdef() may overwrite it. - const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; +void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { + _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +} - resolve_subdef(ctx, prefix, f); - resolve_default(ctx, f, field_proto); +bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, const upb_FieldDef** out_f, + upb_MessageValue* out_val, size_t* iter) { + size_t i = *iter; + size_t n = upb_MessageDef_FieldCount(m); + const upb_MessageValue zero = {0}; + UPB_UNUSED(ext_pool); - if (f->is_extension_) { - resolve_extension(ctx, prefix, f, field_proto); - } -} + /* Iterate over normal fields, returning the first one that is set. */ + while (++i < n) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_MessageValue val = _upb_Message_Getraw(msg, f); -static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { - for (int i = 0; i < m->field_count; i++) { - resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]); - } + /* Skip field if unset or empty. */ + if (upb_FieldDef_HasPresence(f)) { + if (!upb_Message_Has(msg, f)) continue; + } else { + upb_MessageValue test = val; + if (upb_FieldDef_IsString(f) && !upb_FieldDef_IsRepeated(f)) { + /* Clear string pointer, only size matters (ptr could be non-NULL). */ + test.str_val.data = NULL; + } + /* Continue if NULL or 0. */ + if (memcmp(&test, &zero, sizeof(test)) == 0) continue; - m->in_message_set = false; - for (int i = 0; i < m->nested_ext_count; i++) { - upb_FieldDef* ext = (upb_FieldDef*)&m->nested_exts[i]; - resolve_fielddef(ctx, m->full_name, ext); - if (ext->type_ == kUpb_FieldType_Message && - ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m && - google_protobuf_MessageOptions_message_set_wire_format( - ext->msgdef->opts)) { - m->in_message_set = true; + /* Continue on empty array or map. */ + if (upb_FieldDef_IsMap(f)) { + if (upb_Map_Size(test.map_val) == 0) continue; + } else if (upb_FieldDef_IsRepeated(f)) { + if (upb_Array_Size(test.array_val) == 0) continue; + } } - } - if (!ctx->layout) make_layout(ctx, m); + *out_val = val; + *out_f = f; + *iter = i; + return true; + } - for (int i = 0; i < m->nested_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]); + if (ext_pool) { + /* Return any extensions that are set. */ + size_t count; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &count); + if (i - n < count) { + ext += count - 1 - (i - n); + memcpy(out_val, &ext->data, sizeof(*out_val)); + *out_f = _upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); + *iter = i; + return true; + } } + + *iter = i; + return false; } -static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { - size_t n; - google_protobuf_DescriptorProto_extension(msg_proto, &n); - int ext_count = n; +bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int depth) { + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + bool ret = true; - const google_protobuf_DescriptorProto* const* nested_msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - for (size_t i = 0; i < n; i++) { - ext_count += count_exts_in_msg(nested_msgs[i]); + if (--depth == 0) return false; + + _upb_Message_DiscardUnknown_shallow(msg); + + while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + if (!subm) continue; + if (upb_FieldDef_IsMap(f)) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); + const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); + upb_Map* map = (upb_Map*)val.map_val; + size_t iter = kUpb_Map_Begin; + + if (!val_m) continue; + + while (upb_MapIterator_Next(map, &iter)) { + upb_MessageValue map_val = upb_MapIterator_Value(map, iter); + if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, + depth)) { + ret = false; + } + } + } else if (upb_FieldDef_IsRepeated(f)) { + const upb_Array* arr = val.array_val; + size_t i, n = upb_Array_Size(arr); + for (i = 0; i < n; i++) { + upb_MessageValue elem = upb_Array_Get(arr, i); + if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, + depth)) { + ret = false; + } + } + } else { + if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, + depth)) { + ret = false; + } + } } - return ext_count; + return ret; } -static void build_filedef( - symtab_addctx* ctx, upb_FileDef* file, - const google_protobuf_FileDescriptorProto* file_proto) { - const google_protobuf_DescriptorProto* const* msgs; - const google_protobuf_EnumDescriptorProto* const* enums; - const google_protobuf_FieldDescriptorProto* const* exts; - const google_protobuf_ServiceDescriptorProto* const* services; - const upb_StringView* strs; - const int32_t* public_deps; - const int32_t* weak_deps; - size_t i, n; +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth) { + return _upb_Message_DiscardUnknown(msg, m, maxdepth); +} - file->symtab = ctx->symtab; +/** upb/decode.c ************************************************************/ - /* Count all extensions in the file, to build a flat array of layouts. */ - google_protobuf_FileDescriptorProto_extension(file_proto, &n); - int ext_count = n; - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - for (int i = 0; i < n; i++) { - ext_count += count_exts_in_msg(msgs[i]); - } - file->ext_count = ext_count; +#include +#include - if (ctx->layout) { - /* We are using the ext layouts that were passed in. */ - file->ext_layouts = ctx->layout->exts; - if (ctx->layout->ext_count != file->ext_count) { - symtab_errf(ctx, "Extension count did not match layout (%d vs %d)", - ctx->layout->ext_count, file->ext_count); - } - } else { - /* We are building ext layouts from scratch. */ - file->ext_layouts = - symtab_alloc(ctx, sizeof(*file->ext_layouts) * file->ext_count); - upb_MiniTable_Extension* ext = - symtab_alloc(ctx, sizeof(*ext) * file->ext_count); - for (int i = 0; i < file->ext_count; i++) { - file->ext_layouts[i] = &ext[i]; - } - } - if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { - symtab_errf(ctx, "File has no name"); - } +/* Must be last. */ + +/* Maps descriptor type -> elem_size_lg2. */ +static const uint8_t desctype_to_elem_size_lg2[] = { + -1, /* invalid descriptor type */ + 3, /* DOUBLE */ + 2, /* FLOAT */ + 3, /* INT64 */ + 3, /* UINT64 */ + 2, /* INT32 */ + 3, /* FIXED64 */ + 2, /* FIXED32 */ + 0, /* BOOL */ + UPB_SIZE(3, 4), /* STRING */ + UPB_SIZE(2, 3), /* GROUP */ + UPB_SIZE(2, 3), /* MESSAGE */ + UPB_SIZE(3, 4), /* BYTES */ + 2, /* UINT32 */ + 2, /* ENUM */ + 2, /* SFIXED32 */ + 3, /* SFIXED64 */ + 2, /* SINT32 */ + 3, /* SINT64 */ +}; - file->name = - strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); +/* Maps descriptor type -> upb map size. */ +static const uint8_t desctype_to_mapsize[] = { + -1, /* invalid descriptor type */ + 8, /* DOUBLE */ + 4, /* FLOAT */ + 8, /* INT64 */ + 8, /* UINT64 */ + 4, /* INT32 */ + 8, /* FIXED64 */ + 4, /* FIXED32 */ + 1, /* BOOL */ + UPB_MAPTYPE_STRING, /* STRING */ + sizeof(void*), /* GROUP */ + sizeof(void*), /* MESSAGE */ + UPB_MAPTYPE_STRING, /* BYTES */ + 4, /* UINT32 */ + 4, /* ENUM */ + 4, /* SFIXED32 */ + 8, /* SFIXED64 */ + 4, /* SINT32 */ + 8, /* SINT64 */ +}; - if (google_protobuf_FileDescriptorProto_has_package(file_proto)) { - upb_StringView package = - google_protobuf_FileDescriptorProto_package(file_proto); - check_ident(ctx, package, true); - file->package = strviewdup(ctx, package); - } else { - file->package = NULL; - } +static const unsigned FIXED32_OK_MASK = (1 << kUpb_FieldType_Float) | + (1 << kUpb_FieldType_Fixed32) | + (1 << kUpb_FieldType_SFixed32); - if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { - upb_StringView syntax = - google_protobuf_FileDescriptorProto_syntax(file_proto); +static const unsigned FIXED64_OK_MASK = (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Fixed64) | + (1 << kUpb_FieldType_SFixed64); - if (streql_view(syntax, "proto2")) { - file->syntax = kUpb_Syntax_Proto2; - } else if (streql_view(syntax, "proto3")) { - file->syntax = kUpb_Syntax_Proto3; - } else { - symtab_errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(syntax)); - } - } else { - file->syntax = kUpb_Syntax_Proto2; - } +/* Three fake field types for MessageSet. */ +#define TYPE_MSGSET_ITEM 19 +#define TYPE_COUNT 19 - /* Read options. */ - SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); +/* Op: an action to be performed for a wire-type/field-type combination. */ +#define OP_UNKNOWN -1 /* Unknown field. */ +#define OP_MSGSET_ITEM -2 +#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */ +#define OP_ENUM 1 +#define OP_STRING 4 +#define OP_BYTES 5 +#define OP_SUBMSG 6 +/* Scalar fields use only ops above. Repeated fields can use any op. */ +#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ +#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ +#define OP_PACKED_ENUM 13 - /* Verify dependencies. */ - strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); - file->dep_count = n; - file->deps = symtab_alloc(ctx, sizeof(*file->deps) * n); +static const int8_t varint_ops[] = { + OP_UNKNOWN, /* field not found */ + OP_UNKNOWN, /* DOUBLE */ + OP_UNKNOWN, /* FLOAT */ + OP_SCALAR_LG2(3), /* INT64 */ + OP_SCALAR_LG2(3), /* UINT64 */ + OP_SCALAR_LG2(2), /* INT32 */ + OP_UNKNOWN, /* FIXED64 */ + OP_UNKNOWN, /* FIXED32 */ + OP_SCALAR_LG2(0), /* BOOL */ + OP_UNKNOWN, /* STRING */ + OP_UNKNOWN, /* GROUP */ + OP_UNKNOWN, /* MESSAGE */ + OP_UNKNOWN, /* BYTES */ + OP_SCALAR_LG2(2), /* UINT32 */ + OP_ENUM, /* ENUM */ + OP_UNKNOWN, /* SFIXED32 */ + OP_UNKNOWN, /* SFIXED64 */ + OP_SCALAR_LG2(2), /* SINT32 */ + OP_SCALAR_LG2(3), /* SINT64 */ + OP_UNKNOWN, /* MSGSET_ITEM */ +}; - for (i = 0; i < n; i++) { - upb_StringView str = strs[i]; - file->deps[i] = - upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); - if (!file->deps[i]) { - symtab_errf(ctx, - "Depends on file '" UPB_STRINGVIEW_FORMAT - "', but it has not been loaded", - UPB_STRINGVIEW_ARGS(str)); - } - } +static const int8_t delim_ops[] = { + /* For non-repeated field type. */ + OP_UNKNOWN, /* field not found */ + OP_UNKNOWN, /* DOUBLE */ + OP_UNKNOWN, /* FLOAT */ + OP_UNKNOWN, /* INT64 */ + OP_UNKNOWN, /* UINT64 */ + OP_UNKNOWN, /* INT32 */ + OP_UNKNOWN, /* FIXED64 */ + OP_UNKNOWN, /* FIXED32 */ + OP_UNKNOWN, /* BOOL */ + OP_STRING, /* STRING */ + OP_UNKNOWN, /* GROUP */ + OP_SUBMSG, /* MESSAGE */ + OP_BYTES, /* BYTES */ + OP_UNKNOWN, /* UINT32 */ + OP_UNKNOWN, /* ENUM */ + OP_UNKNOWN, /* SFIXED32 */ + OP_UNKNOWN, /* SFIXED64 */ + OP_UNKNOWN, /* SINT32 */ + OP_UNKNOWN, /* SINT64 */ + OP_UNKNOWN, /* MSGSET_ITEM */ + /* For repeated field type. */ + OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */ + OP_FIXPCK_LG2(2), /* REPEATED FLOAT */ + OP_VARPCK_LG2(3), /* REPEATED INT64 */ + OP_VARPCK_LG2(3), /* REPEATED UINT64 */ + OP_VARPCK_LG2(2), /* REPEATED INT32 */ + OP_FIXPCK_LG2(3), /* REPEATED FIXED64 */ + OP_FIXPCK_LG2(2), /* REPEATED FIXED32 */ + OP_VARPCK_LG2(0), /* REPEATED BOOL */ + OP_STRING, /* REPEATED STRING */ + OP_SUBMSG, /* REPEATED GROUP */ + OP_SUBMSG, /* REPEATED MESSAGE */ + OP_BYTES, /* REPEATED BYTES */ + OP_VARPCK_LG2(2), /* REPEATED UINT32 */ + OP_PACKED_ENUM, /* REPEATED ENUM */ + OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */ + OP_FIXPCK_LG2(3), /* REPEATED SFIXED64 */ + OP_VARPCK_LG2(2), /* REPEATED SINT32 */ + OP_VARPCK_LG2(3), /* REPEATED SINT64 */ + /* Omitting MSGSET_*, because we never emit a repeated msgset type */ +}; - public_deps = - google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); - file->public_dep_count = n; - file->public_deps = symtab_alloc(ctx, sizeof(*file->public_deps) * n); - int32_t* mutable_public_deps = (int32_t*)file->public_deps; - for (i = 0; i < n; i++) { - if (public_deps[i] >= file->dep_count) { - symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]); - } - mutable_public_deps[i] = public_deps[i]; - } +typedef union { + bool bool_val; + uint32_t uint32_val; + uint64_t uint64_val; + uint32_t size; +} wireval; - weak_deps = - google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); - file->weak_dep_count = n; - file->weak_deps = symtab_alloc(ctx, sizeof(*file->weak_deps) * n); - int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; - for (i = 0; i < n; i++) { - if (weak_deps[i] >= file->dep_count) { - symtab_errf(ctx, "weak_dep %d is out of range", (int)weak_deps[i]); - } - mutable_weak_deps[i] = weak_deps[i]; - } +static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout); - /* Create enums. */ - enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); - file->top_lvl_enum_count = n; - file->top_lvl_enums = symtab_alloc(ctx, sizeof(*file->top_lvl_enums) * n); - for (i = 0; i < n; i++) { - create_enumdef(ctx, file->package, enums[i], NULL, &file->top_lvl_enums[i]); - } +UPB_NORETURN static void* decode_err(upb_Decoder* d, upb_DecodeStatus status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); +} - /* Create extensions. */ - exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); - file->top_lvl_ext_count = n; - file->top_lvl_exts = symtab_alloc(ctx, sizeof(*file->top_lvl_exts) * n); - for (i = 0; i < n; i++) { - create_fielddef(ctx, file->package, NULL, exts[i], &file->top_lvl_exts[i], - /* is_extension= */ true); - ((upb_FieldDef*)&file->top_lvl_exts[i])->index_ = i; - } +const char* fastdecode_err(upb_Decoder* d, int status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); + return NULL; +} +static void decode_verifyutf8(upb_Decoder* d, const char* buf, int len) { + if (!decode_verifyutf8_inl(buf, len)) + decode_err(d, kUpb_DecodeStatus_BadUtf8); +} - /* Create messages. */ - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - file->top_lvl_msg_count = n; - file->top_lvl_msgs = symtab_alloc(ctx, sizeof(*file->top_lvl_msgs) * n); - for (i = 0; i < n; i++) { - create_msgdef(ctx, file->package, msgs[i], NULL, &file->top_lvl_msgs[i]); +static bool decode_reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { + bool need_realloc = arr->size - arr->len < elem; + if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); } + return need_realloc; +} - /* Create services. */ - services = google_protobuf_FileDescriptorProto_service(file_proto, &n); - file->service_count = n; - file->services = symtab_alloc(ctx, sizeof(*file->services) * n); - for (i = 0; i < n; i++) { - create_service(ctx, services[i], &file->services[i]); - ((upb_ServiceDef*)&file->services[i])->index = i; - } +typedef struct { + const char* ptr; + uint64_t val; +} decode_vret; - /* Now that all names are in the table, build layouts and resolve refs. */ - for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) { - resolve_fielddef(ctx, file->package, (upb_FieldDef*)&file->top_lvl_exts[i]); +UPB_NOINLINE +static decode_vret decode_longvarint64(const char* ptr, uint64_t val) { + decode_vret ret = {NULL, 0}; + uint64_t byte; + int i; + for (i = 1; i < 10; i++) { + byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + ret.ptr = ptr + i + 1; + ret.val = val; + return ret; + } } + return ret; +} - for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) { - resolve_msgdef(ctx, (upb_MessageDef*)&file->top_lvl_msgs[i]); +UPB_FORCEINLINE +static const char* decode_varint64(upb_Decoder* d, const char* ptr, + uint64_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + decode_vret res = decode_longvarint64(ptr, byte); + if (!res.ptr) return decode_err(d, kUpb_DecodeStatus_Malformed); + *val = res.val; + return res.ptr; } +} - if (file->ext_count) { - CHK_OOM(_upb_extreg_add(ctx->symtab->extreg, file->ext_layouts, - file->ext_count)); +UPB_FORCEINLINE +static const char* decode_tag(upb_Decoder* d, const char* ptr, uint32_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + const char* start = ptr; + decode_vret res = decode_longvarint64(ptr, byte); + if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { + return decode_err(d, kUpb_DecodeStatus_Malformed); + } + *val = res.val; + return res.ptr; } } -static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { - intptr_t iter = UPB_INTTABLE_BEGIN; - upb_StringView key; - upb_value val; - while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { - const upb_FileDef* f; - switch (deftype(val)) { - case UPB_DEFTYPE_EXT: - f = upb_FieldDef_File(unpack_def(val, UPB_DEFTYPE_EXT)); - break; - case UPB_DEFTYPE_MSG: - f = upb_MessageDef_File(unpack_def(val, UPB_DEFTYPE_MSG)); - break; - case UPB_DEFTYPE_ENUM: - f = upb_EnumDef_File(unpack_def(val, UPB_DEFTYPE_ENUM)); - break; - case UPB_DEFTYPE_ENUMVAL: - f = upb_EnumDef_File( - upb_EnumValueDef_Enum(unpack_def(val, UPB_DEFTYPE_ENUMVAL))); - break; - case UPB_DEFTYPE_SERVICE: - f = upb_ServiceDef_File(unpack_def(val, UPB_DEFTYPE_SERVICE)); - break; - default: - UPB_UNREACHABLE(); - } +UPB_FORCEINLINE +static const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, + uint32_t* size) { + uint64_t size64; + ptr = decode_varint64(d, ptr, &size64); + if (size64 >= INT32_MAX || ptr - d->end + (int)size64 > d->limit) { + decode_err(d, kUpb_DecodeStatus_Malformed); + } + *size = size64; + return ptr; +} - if (f == file) upb_strtable_removeiter(&s->syms, &iter); +static void decode_munge_int32(wireval* val) { + if (!_upb_IsLittleEndian()) { + /* The next stage will memcpy(dst, &val, 4) */ + val->uint32_val = val->uint64_val; } } -static const upb_FileDef* _upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - const upb_MiniTable_File* layout, upb_Status* status) { - symtab_addctx ctx; - upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); - upb_value v; - - if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { - if (unpack_def(v, UPB_DEFTYPE_FILE)) { - upb_Status_SetErrorFormat(status, "duplicate file name (%.*s)", - UPB_STRINGVIEW_ARGS(name)); - return NULL; +static void decode_munge(int type, wireval* val) { + switch (type) { + case kUpb_FieldType_Bool: + val->bool_val = val->uint64_val != 0; + break; + case kUpb_FieldType_SInt32: { + uint32_t n = val->uint64_val; + val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); + break; } - const upb_MiniTable_File* registered = unpack_def(v, UPB_DEFTYPE_LAYOUT); - UPB_ASSERT(registered); - if (layout && layout != registered) { - upb_Status_SetErrorFormat( - status, "tried to build with a different layout (filename=%.*s)", - UPB_STRINGVIEW_ARGS(name)); - return NULL; + case kUpb_FieldType_SInt64: { + uint64_t n = val->uint64_val; + val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); + break; } - layout = registered; + case kUpb_FieldType_Int32: + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Enum: + decode_munge_int32(val); + break; } +} - ctx.symtab = s; - ctx.layout = layout; - ctx.msg_count = 0; - ctx.enum_count = 0; - ctx.ext_count = 0; - ctx.status = status; - ctx.file = NULL; - ctx.arena = upb_Arena_New(); - ctx.tmp_arena = upb_Arena_New(); +static upb_Message* decode_newsubmsg(upb_Decoder* d, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + upb_Message* msg = _upb_Message_New_inl(subl, &d->arena); + if (!msg) decode_err(d, kUpb_DecodeStatus_OutOfMemory); + return msg; +} - if (!ctx.arena || !ctx.tmp_arena) { - if (ctx.arena) upb_Arena_Free(ctx.arena); - if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); - upb_Status_setoom(status); - return NULL; +UPB_NOINLINE +const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, + int overrun) { + int status; + ptr = decode_isdonefallback_inl(d, ptr, overrun, &status); + if (ptr == NULL) { + return decode_err(d, status); } + return ptr; +} - if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) { - UPB_ASSERT(!upb_Status_IsOk(status)); - if (ctx.file) { - remove_filedef(s, ctx.file); - ctx.file = NULL; - } +static const char* decode_readstr(upb_Decoder* d, const char* ptr, int size, + upb_StringView* str) { + if (d->options & kUpb_DecodeOption_AliasString) { + str->data = ptr; } else { - ctx.file = symtab_alloc(&ctx, sizeof(*ctx.file)); - build_filedef(&ctx, ctx.file, file_proto); - upb_strtable_insert(&s->files, name.data, name.size, - pack_def(ctx.file, UPB_DEFTYPE_FILE), ctx.arena); - UPB_ASSERT(upb_Status_IsOk(status)); - upb_Arena_Fuse(s->arena, ctx.arena); + char* data = upb_Arena_Malloc(&d->arena, size); + if (!data) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); + memcpy(data, ptr, size); + str->data = data; } - - upb_Arena_Free(ctx.arena); - upb_Arena_Free(ctx.tmp_arena); - return ctx.file; + str->size = size; + return ptr + size; } -const upb_FileDef* upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - upb_Status* status) { - return _upb_DefPool_AddFile(s, file_proto, NULL, status); +UPB_FORCEINLINE +static const char* decode_tosubmsg2(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, int size) { + int saved_delta = decode_pushlimit(d, ptr, size); + if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); + ptr = decode_msg(d, ptr, submsg, subl); + if (d->end_group != DECODE_NOGROUP) + return decode_err(d, kUpb_DecodeStatus_Malformed); + decode_poplimit(d, ptr, saved_delta); + d->depth++; + return ptr; } -/* Include here since we want most of this file to be stdio-free. */ -#include - -bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, - bool rebuild_minitable) { - /* Since this function should never fail (it would indicate a bug in upb) we - * print errors to stderr instead of returning error status to the user. */ - _upb_DefPool_Init** deps = init->deps; - google_protobuf_FileDescriptorProto* file; - upb_Arena* arena; - upb_Status status; - - upb_Status_Clear(&status); +UPB_FORCEINLINE +static const char* decode_tosubmsg(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, int size) { + return decode_tosubmsg2(d, ptr, submsg, subs[field->submsg_index].submsg, + size); +} - if (upb_DefPool_FindFileByName(s, init->filename)) { - return true; +UPB_FORCEINLINE +static const char* decode_group(upb_Decoder* d, const char* ptr, + upb_Message* submsg, const upb_MiniTable* subl, + uint32_t number) { + if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded); + if (decode_isdone(d, &ptr)) { + return decode_err(d, kUpb_DecodeStatus_Malformed); } + ptr = decode_msg(d, ptr, submsg, subl); + if (d->end_group != number) return decode_err(d, kUpb_DecodeStatus_Malformed); + d->end_group = DECODE_NOGROUP; + d->depth++; + return ptr; +} - arena = upb_Arena_New(); - - for (; *deps; deps++) { - if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; - } +UPB_FORCEINLINE +static const char* decode_togroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + return decode_group(d, ptr, submsg, subl, field->number); +} - file = google_protobuf_FileDescriptorProto_parse_ex( - init->descriptor.data, init->descriptor.size, NULL, - kUpb_DecodeOption_AliasString, arena); - s->bytes_loaded += init->descriptor.size; +static char* upb_Decoder_EncodeVarint32(uint32_t val, char* ptr) { + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + *(ptr++) = byte; + } while (val); + return ptr; +} - if (!file) { - upb_Status_SetErrorFormat( - &status, - "Failed to parse compiled-in descriptor for file '%s'. This should " - "never happen.", - init->filename); - goto err; - } +static void upb_Decode_AddUnknownVarints(upb_Decoder* d, upb_Message* msg, + uint32_t val1, uint32_t val2) { + char buf[20]; + char* end = buf; + end = upb_Decoder_EncodeVarint32(val1, end); + end = upb_Decoder_EncodeVarint32(val2, end); - const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; - if (!_upb_DefPool_AddFile(s, file, mt, &status)) { - goto err; + if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); } +} - upb_Arena_Free(arena); - return true; +UPB_NOINLINE +static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTable_Enum* e, + const upb_MiniTable_Field* field, + uint32_t v) { + // OPT: binary search long lists? + int n = e->value_count; + for (int i = 0; i < n; i++) { + if ((uint32_t)e->values[i] == v) return true; + } -err: - fprintf(stderr, - "Error loading compiled-in descriptor for file '%s' (this should " - "never happen): %s\n", - init->filename, upb_Status_ErrorMessage(&status)); - upb_Arena_Free(arena); + // Unrecognized enum goes into unknown fields. + // For packed fields the tag could be arbitrarily far in the past, so we + // just re-encode the tag and value here. + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; + upb_Message* unknown_msg = + field->mode & kUpb_LabelFlags_IsExtension ? d->unknown_msg : msg; + upb_Decode_AddUnknownVarints(d, unknown_msg, tag, v); return false; } -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { - return s->bytes_loaded; -} +UPB_FORCEINLINE +static bool decode_checkenum(upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable_Enum* e, + const upb_MiniTable_Field* field, wireval* val) { + uint32_t v = val->uint32_val; -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } + if (UPB_LIKELY(v < 64) && UPB_LIKELY(((1ULL << v) & e->mask))) return true; -const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext) { - upb_value v; - bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); - UPB_ASSERT(ok); - return upb_value_getconstptr(v); + return decode_checkenum_slow(d, ptr, msg, e, field, v); } -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum) { - const upb_MiniTable* l = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum); - return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +UPB_NOINLINE +static const char* decode_enum_toarray(upb_Decoder* d, const char* ptr, + upb_Message* msg, upb_Array* arr, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val) { + const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; + if (!decode_checkenum(d, ptr, msg, e, field, val)) return ptr; + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); + arr->len++; + memcpy(mem, val, 4); + return ptr; } -bool _upb_DefPool_registerlayout(upb_DefPool* s, const char* filename, - const upb_MiniTable_File* file) { - if (upb_DefPool_FindFileByName(s, filename)) return false; - upb_value v = pack_def(file, UPB_DEFTYPE_LAYOUT); - return upb_strtable_insert(&s->files, filename, strlen(filename), v, - s->arena); -} +UPB_FORCEINLINE +static const char* decode_fixed_packed(upb_Decoder* d, const char* ptr, + upb_Array* arr, wireval* val, + const upb_MiniTable_Field* field, + int lg2) { + int mask = (1 << lg2) - 1; + size_t count = val->size >> lg2; + if ((val->size & mask) != 0) { + // Length isn't a round multiple of elem size. + return decode_err(d, kUpb_DecodeStatus_Malformed); + } + decode_reserve(d, arr, count); + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); + arr->len += count; + // Note: if/when the decoder supports multi-buffer input, we will need to + // handle buffer seams here. + if (_upb_IsLittleEndian()) { + memcpy(mem, ptr, val->size); + ptr += val->size; + } else { + const char* end = ptr + val->size; + char* dst = mem; + while (ptr < end) { + if (lg2 == 2) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap32(val); + memcpy(dst, &val, sizeof(val)); + } else { + UPB_ASSERT(lg2 == 3); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap64(val); + memcpy(dst, &val, sizeof(val)); + } + ptr += 1 << lg2; + dst += 1 << lg2; + } + } -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s) { - return s->extreg; + return ptr; } -const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, - const upb_MessageDef* m, - size_t* count) { - size_t n = 0; - intptr_t iter = UPB_INTTABLE_BEGIN; - uintptr_t key; - upb_value val; - // This is O(all exts) instead of O(exts for m). If we need this to be - // efficient we may need to make extreg into a two-level table, or have a - // second per-message index. - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) n++; - } - const upb_FieldDef** exts = malloc(n * sizeof(*exts)); - iter = UPB_INTTABLE_BEGIN; - size_t i = 0; - while (upb_inttable_next2(&s->exts, &key, &val, &iter)) { - const upb_FieldDef* f = upb_value_getconstptr(val); - if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; +UPB_FORCEINLINE +static const char* decode_varint_packed(upb_Decoder* d, const char* ptr, + upb_Array* arr, wireval* val, + const upb_MiniTable_Field* field, + int lg2) { + int scale = 1 << lg2; + int saved_limit = decode_pushlimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); + while (!decode_isdone(d, &ptr)) { + wireval elem; + ptr = decode_varint64(d, ptr, &elem.uint64_val); + decode_munge(field->descriptortype, &elem); + if (decode_reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); + } + arr->len++; + memcpy(out, &elem, scale); + out += scale; } - *count = n; - return exts; + decode_poplimit(d, ptr, saved_limit); + return ptr; } -#undef CHK_OOM - -/** upb/reflection.c ************************************************************/ - -#include - - -static size_t get_field_size(const upb_MiniTable_Field* f) { - static unsigned char sizes[] = { - 0, /* 0 */ - 8, /* kUpb_FieldType_Double */ - 4, /* kUpb_FieldType_Float */ - 8, /* kUpb_FieldType_Int64 */ - 8, /* kUpb_FieldType_UInt64 */ - 4, /* kUpb_FieldType_Int32 */ - 8, /* kUpb_FieldType_Fixed64 */ - 4, /* kUpb_FieldType_Fixed32 */ - 1, /* kUpb_FieldType_Bool */ - sizeof(upb_StringView), /* kUpb_FieldType_String */ - sizeof(void*), /* kUpb_FieldType_Group */ - sizeof(void*), /* kUpb_FieldType_Message */ - sizeof(upb_StringView), /* kUpb_FieldType_Bytes */ - 4, /* kUpb_FieldType_UInt32 */ - 4, /* kUpb_FieldType_Enum */ - 4, /* kUpb_FieldType_SFixed32 */ - 8, /* kUpb_FieldType_SFixed64 */ - 4, /* kUpb_FieldType_SInt32 */ - 8, /* kUpb_FieldType_SInt64 */ - }; - return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; +UPB_NOINLINE +static const char* decode_enum_packed(upb_Decoder* d, const char* ptr, + upb_Message* msg, upb_Array* arr, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val) { + const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum; + int saved_limit = decode_pushlimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); + while (!decode_isdone(d, &ptr)) { + wireval elem; + ptr = decode_varint64(d, ptr, &elem.uint64_val); + decode_munge_int32(&elem); + if (!decode_checkenum(d, ptr, msg, e, field, &elem)) { + continue; + } + if (decode_reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void); + } + arr->len++; + memcpy(out, &elem, 4); + out += 4; + } + decode_poplimit(d, ptr, saved_limit); + return ptr; } -/* Strings/bytes are special-cased in maps. */ -static char _upb_CTypeo_mapsize[12] = { - 0, - 1, /* kUpb_CType_Bool */ - 4, /* kUpb_CType_Float */ - 4, /* kUpb_CType_Int32 */ - 4, /* kUpb_CType_UInt32 */ - 4, /* kUpb_CType_Enum */ - sizeof(void*), /* kUpb_CType_Message */ - 8, /* kUpb_CType_Double */ - 8, /* kUpb_CType_Int64 */ - 8, /* kUpb_CType_UInt64 */ - 0, /* kUpb_CType_String */ - 0, /* kUpb_CType_Bytes */ -}; +static const char* decode_toarray(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val, int op) { + upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); + upb_Array* arr = *arrp; + void* mem; -static const char _upb_CTypeo_sizelg2[12] = { - 0, - 0, /* kUpb_CType_Bool */ - 2, /* kUpb_CType_Float */ - 2, /* kUpb_CType_Int32 */ - 2, /* kUpb_CType_UInt32 */ - 2, /* kUpb_CType_Enum */ - UPB_SIZE(2, 3), /* kUpb_CType_Message */ - 3, /* kUpb_CType_Double */ - 3, /* kUpb_CType_Int64 */ - 3, /* kUpb_CType_UInt64 */ - UPB_SIZE(3, 4), /* kUpb_CType_String */ - UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ -}; + if (arr) { + decode_reserve(d, arr, 1); + } else { + size_t lg2 = desctype_to_elem_size_lg2[field->descriptortype]; + arr = _upb_Array_New(&d->arena, 4, lg2); + if (!arr) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); + *arrp = arr; + } + + switch (op) { + case OP_SCALAR_LG2(0): + case OP_SCALAR_LG2(2): + case OP_SCALAR_LG2(3): + /* Append scalar value. */ + mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << op, void); + arr->len++; + memcpy(mem, val, 1 << op); + return ptr; + case OP_STRING: + decode_verifyutf8(d, ptr, val->size); + /* Fallthrough. */ + case OP_BYTES: { + /* Append bytes. */ + upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->len; + arr->len++; + return decode_readstr(d, ptr, val->size, str); + } + case OP_SUBMSG: { + /* Append submessage / group. */ + upb_Message* submsg = decode_newsubmsg(d, subs, field); + *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void*), upb_Message*) = + submsg; + arr->len++; + if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { + return decode_togroup(d, ptr, submsg, subs, field); + } else { + return decode_tosubmsg(d, ptr, submsg, subs, field, val->size); + } + } + case OP_FIXPCK_LG2(2): + case OP_FIXPCK_LG2(3): + return decode_fixed_packed(d, ptr, arr, val, field, + op - OP_FIXPCK_LG2(0)); + case OP_VARPCK_LG2(0): + case OP_VARPCK_LG2(2): + case OP_VARPCK_LG2(3): + return decode_varint_packed(d, ptr, arr, val, field, + op - OP_VARPCK_LG2(0)); + case OP_ENUM: + return decode_enum_toarray(d, ptr, msg, arr, subs, field, val); + case OP_PACKED_ENUM: + return decode_enum_packed(d, ptr, msg, arr, subs, field, val); + default: + UPB_UNREACHABLE(); + } +} -/** upb_Message - * *******************************************************************/ +static const char* decode_tomap(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, + wireval* val) { + upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*); + upb_Map* map = *map_p; + upb_MapEntry ent; + const upb_MiniTable* entry = subs[field->submsg_index].submsg; -upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) { - return _upb_Message_New(upb_MessageDef_MiniTable(m), a); -} + if (!map) { + /* Lazily create map. */ + const upb_MiniTable_Field* key_field = &entry->fields[0]; + const upb_MiniTable_Field* val_field = &entry->fields[1]; + char key_size = desctype_to_mapsize[key_field->descriptortype]; + char val_size = desctype_to_mapsize[val_field->descriptortype]; + UPB_ASSERT(key_field->offset == 0); + UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); + map = _upb_Map_New(&d->arena, key_size, val_size); + *map_p = map; + } -static bool in_oneof(const upb_MiniTable_Field* field) { - return field->presence < 0; -} + /* Parse map entry. */ + memset(&ent, 0, sizeof(ent)); -static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, - const upb_FieldDef* f) { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - const char* mem = UPB_PTR_AT(msg, field->offset, char); - upb_MessageValue val = {0}; - memcpy(&val, mem, get_field_size(field)); - return val; -} + if (entry->fields[1].descriptortype == kUpb_FieldType_Message || + entry->fields[1].descriptortype == kUpb_FieldType_Group) { + /* Create proactively to handle the case where it doesn't appear. */ + ent.v.val = + upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); + } -bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { - assert(upb_FieldDef_HasPresence(f)); - if (upb_FieldDef_IsExtension(f)) { - const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); - return _upb_Message_Getext(msg, ext) != NULL; + const char* start = ptr; + ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size); + // check if ent had any unknown fields + size_t size; + upb_Message_GetUnknown(&ent.k, &size); + if (size != 0) { + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Delimited; + upb_Decode_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - if (in_oneof(field)) { - return _upb_getoneofcase_field(msg, field) == field->number; - } else if (field->presence > 0) { - return _upb_hasbit_field(msg, field); - } else { - UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || - field->descriptortype == kUpb_FieldType_Group); - return _upb_Message_Getraw(msg, f).msg_val != NULL; + if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, + &d->arena) == _kUpb_MapInsertStatus_OutOfMemory) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); } } + return ptr; } -const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, - const upb_OneofDef* o) { - const upb_FieldDef* f = upb_OneofDef_Field(o, 0); - if (upb_OneofDef_IsSynthetic(o)) { - UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); - return upb_Message_Has(msg, f) ? f : NULL; - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - uint32_t oneof_case = _upb_getoneofcase_field(msg, field); - f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; - UPB_ASSERT((f != NULL) == (oneof_case != 0)); - return f; +static const char* decode_tomsg(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field, wireval* val, + int op) { + void* mem = UPB_PTR_AT(msg, field->offset, void); + int type = field->descriptortype; + + if (UPB_UNLIKELY(op == OP_ENUM) && + !decode_checkenum(d, ptr, msg, subs[field->submsg_index].subenum, field, + val)) { + return ptr; } -} -upb_MessageValue upb_Message_Get(const upb_Message* msg, - const upb_FieldDef* f) { - if (upb_FieldDef_IsExtension(f)) { - const upb_Message_Extension* ext = - _upb_Message_Getext(msg, _upb_FieldDef_ExtensionMiniTable(f)); - if (ext) { - upb_MessageValue val; - memcpy(&val, &ext->data, sizeof(val)); - return val; - } else if (upb_FieldDef_IsRepeated(f)) { - return (upb_MessageValue){.array_val = NULL}; + /* Set presence if necessary. */ + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (field->presence < 0) { + /* Oneof case */ + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (op == OP_SUBMSG && *oneof_case != field->number) { + memset(mem, 0, sizeof(void*)); } - } else if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { - return _upb_Message_Getraw(msg, f); + *oneof_case = field->number; } - return upb_FieldDef_Default(f); -} -upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, - const upb_FieldDef* f, - upb_Arena* a) { - UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); - if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) { - // We need to skip the upb_Message_Get() call in this case. - goto make; + /* Store into message. */ + switch (op) { + case OP_SUBMSG: { + upb_Message** submsgp = mem; + upb_Message* submsg = *submsgp; + if (!submsg) { + submsg = decode_newsubmsg(d, subs, field); + *submsgp = submsg; + } + if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { + ptr = decode_togroup(d, ptr, submsg, subs, field); + } else { + ptr = decode_tosubmsg(d, ptr, submsg, subs, field, val->size); + } + break; + } + case OP_STRING: + decode_verifyutf8(d, ptr, val->size); + /* Fallthrough. */ + case OP_BYTES: + return decode_readstr(d, ptr, val->size, mem); + case OP_SCALAR_LG2(3): + memcpy(mem, val, 8); + break; + case OP_ENUM: + case OP_SCALAR_LG2(2): + memcpy(mem, val, 4); + break; + case OP_SCALAR_LG2(0): + memcpy(mem, val, 1); + break; + default: + UPB_UNREACHABLE(); } - upb_MessageValue val = upb_Message_Get(msg, f); - if (val.array_val) { - return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; - } + return ptr; +} - upb_MutableMessageValue ret; -make: - if (!a) return (upb_MutableMessageValue){.array = NULL}; - if (upb_FieldDef_IsMap(f)) { - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key = - upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); - const upb_FieldDef* value = - upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); - ret.map = - upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); - } else if (upb_FieldDef_IsRepeated(f)) { - ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); - } else { - UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); - ret.msg = upb_Message_New(upb_FieldDef_MessageSubDef(f), a); +UPB_NOINLINE +const char* decode_checkrequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* l) { + assert(l->required_count); + if (UPB_LIKELY((d->options & kUpb_DecodeOption_CheckRequired) == 0)) { + return ptr; } - - val.array_val = ret.array; - upb_Message_Set(msg, f, val, a); - - return ret; + uint64_t msg_head; + memcpy(&msg_head, msg, 8); + msg_head = _upb_BigEndian_Swap64(msg_head); + if (upb_MiniTable_requiredmask(l) & ~msg_head) { + d->missing_required = true; + } + return ptr; } -bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, - upb_MessageValue val, upb_Arena* a) { - if (upb_FieldDef_IsExtension(f)) { - upb_Message_Extension* ext = _upb_Message_Getorcreateext( - msg, _upb_FieldDef_ExtensionMiniTable(f), a); - if (!ext) return false; - memcpy(&ext->data, &val, sizeof(val)); - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - char* mem = UPB_PTR_AT(msg, field->offset, char); - memcpy(mem, &val, get_field_size(field)); - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (in_oneof(field)) { - *_upb_oneofcase_field(msg, field) = field->number; +UPB_FORCEINLINE +static bool decode_tryfastdispatch(upb_Decoder* d, const char** ptr, + upb_Message* msg, + const upb_MiniTable* layout) { +#if UPB_FASTTABLE + if (layout && layout->table_mask != (unsigned char)-1) { + uint16_t tag = fastdecode_loadtag(*ptr); + intptr_t table = decode_totable(layout); + *ptr = fastdecode_tagdispatch(d, *ptr, msg, table, 0, tag); + return true; + } +#endif + return false; +} + +static const char* upb_Decoder_SkipField(upb_Decoder* d, const char* ptr, + uint32_t tag) { + int field_number = tag >> 3; + int wire_type = tag & 7; + switch (wire_type) { + case kUpb_WireType_Varint: { + uint64_t val; + return decode_varint64(d, ptr, &val); + } + case kUpb_WireType_64Bit: + return ptr + 8; + case kUpb_WireType_32Bit: + return ptr + 4; + case kUpb_WireType_Delimited: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + return ptr + size; } + case kUpb_WireType_StartGroup: + return decode_group(d, ptr, NULL, NULL, field_number); + default: + decode_err(d, kUpb_DecodeStatus_Malformed); } - return true; } -void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { - if (upb_FieldDef_IsExtension(f)) { - _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); - } else { - const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f); - char* mem = UPB_PTR_AT(msg, field->offset, char); +enum { + kStartItemTag = ((1 << 3) | kUpb_WireType_StartGroup), + kEndItemTag = ((1 << 3) | kUpb_WireType_EndGroup), + kTypeIdTag = ((2 << 3) | kUpb_WireType_Varint), + kMessageTag = ((3 << 3) | kUpb_WireType_Delimited), +}; - if (field->presence > 0) { - _upb_clearhas_field(msg, field); - } else if (in_oneof(field)) { - uint32_t* oneof_case = _upb_oneofcase_field(msg, field); - if (*oneof_case != field->number) return; - *oneof_case = 0; - } +static void upb_Decoder_AddKnownMessageSetItem( + upb_Decoder* d, upb_Message* msg, const upb_MiniTable_Extension* item_mt, + const char* data, uint32_t size) { + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, item_mt, &d->arena); + if (UPB_UNLIKELY(!ext)) decode_err(d, kUpb_DecodeStatus_OutOfMemory); + upb_Message* submsg = decode_newsubmsg(d, &ext->ext->sub, &ext->ext->field); + upb_DecodeStatus status = upb_Decode(data, size, submsg, item_mt->sub.submsg, + d->extreg, d->options, &d->arena); + memcpy(&ext->data, &submsg, sizeof(submsg)); + if (status != kUpb_DecodeStatus_Ok) decode_err(d, status); +} + +static void upb_Decoder_AddUnknownMessageSetItem(upb_Decoder* d, + upb_Message* msg, + uint32_t type_id, + const char* message_data, + uint32_t message_size) { + char buf[60]; + char* ptr = buf; + ptr = upb_Decoder_EncodeVarint32(kStartItemTag, ptr); + ptr = upb_Decoder_EncodeVarint32(kTypeIdTag, ptr); + ptr = upb_Decoder_EncodeVarint32(type_id, ptr); + ptr = upb_Decoder_EncodeVarint32(kMessageTag, ptr); + ptr = upb_Decoder_EncodeVarint32(message_size, ptr); + char* split = ptr; + + ptr = upb_Decoder_EncodeVarint32(kEndItemTag, ptr); + char* end = ptr; + + if (!_upb_Message_AddUnknown(msg, buf, split - buf, &d->arena) || + !_upb_Message_AddUnknown(msg, message_data, message_size, &d->arena) || + !_upb_Message_AddUnknown(msg, split, end - split, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } +} - memset(mem, 0, get_field_size(field)); +static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, + const upb_MiniTable* layout, + uint32_t type_id, const char* data, + uint32_t size) { + const upb_MiniTable_Extension* item_mt = + _upb_extreg_get(d->extreg, layout, type_id); + if (item_mt) { + upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); + } else { + upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); } } -void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { - _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +static const char* upb_Decoder_DecodeMessageSetItem( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout) { + uint32_t type_id = 0; + upb_StringView preserved = {NULL, 0}; + typedef enum { + kUpb_HaveId = 1 << 0, + kUpb_HavePayload = 1 << 1, + } StateMask; + StateMask state_mask = 0; + while (!decode_isdone(d, &ptr)) { + uint32_t tag; + ptr = decode_tag(d, ptr, &tag); + switch (tag) { + case kEndItemTag: + return ptr; + case kTypeIdTag: { + uint64_t tmp; + ptr = decode_varint64(d, ptr, &tmp); + if (state_mask & kUpb_HaveId) break; // Ignore dup. + state_mask |= kUpb_HaveId; + type_id = tmp; + if (state_mask & kUpb_HavePayload) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, preserved.data, + preserved.size); + } + break; + } + case kMessageTag: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + const char* data = ptr; + ptr += size; + if (state_mask & kUpb_HavePayload) break; // Ignore dup. + state_mask |= kUpb_HavePayload; + if (state_mask & kUpb_HaveId) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, data, size); + } else { + // Out of order, we must preserve the payload. + preserved.data = data; + preserved.size = size; + } + break; + } + default: + // We do not preserve unexpected fields inside a message set item. + ptr = upb_Decoder_SkipField(d, ptr, tag); + break; + } + } + decode_err(d, kUpb_DecodeStatus_Malformed); } -bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, const upb_FieldDef** out_f, - upb_MessageValue* out_val, size_t* iter) { - size_t i = *iter; - size_t n = upb_MessageDef_FieldCount(m); - const upb_MessageValue zero = {0}; - UPB_UNUSED(ext_pool); +static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d, + const upb_MiniTable* l, + uint32_t field_number, + int* last_field_index) { + static upb_MiniTable_Field none = {0, 0, 0, 0, 0, 0}; + if (l == NULL) return &none; - /* Iterate over normal fields, returning the first one that is set. */ - while (++i < n) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - upb_MessageValue val = _upb_Message_Getraw(msg, f); + size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX + if (idx < l->dense_below) { + /* Fastest case: index into dense fields. */ + goto found; + } - /* Skip field if unset or empty. */ - if (upb_FieldDef_HasPresence(f)) { - if (!upb_Message_Has(msg, f)) continue; - } else { - upb_MessageValue test = val; - if (upb_FieldDef_IsString(f) && !upb_FieldDef_IsRepeated(f)) { - /* Clear string pointer, only size matters (ptr could be non-NULL). */ - test.str_val.data = NULL; + if (l->dense_below < l->field_count) { + /* Linear search non-dense fields. Resume scanning from last_field_index + * since fields are usually in order. */ + int last = *last_field_index; + for (idx = last; idx < l->field_count; idx++) { + if (l->fields[idx].number == field_number) { + goto found; } - /* Continue if NULL or 0. */ - if (memcmp(&test, &zero, sizeof(test)) == 0) continue; + } - /* Continue on empty array or map. */ - if (upb_FieldDef_IsMap(f)) { - if (upb_Map_Size(test.map_val) == 0) continue; - } else if (upb_FieldDef_IsRepeated(f)) { - if (upb_Array_Size(test.array_val) == 0) continue; + for (idx = l->dense_below; idx < last; idx++) { + if (l->fields[idx].number == field_number) { + goto found; } } - - *out_val = val; - *out_f = f; - *iter = i; - return true; } - if (ext_pool) { - /* Return any extensions that are set. */ - size_t count; - const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &count); - if (i - n < count) { - ext += count - 1 - (i - n); - memcpy(out_val, &ext->data, sizeof(*out_val)); - *out_f = _upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext); - *iter = i; - return true; + if (d->extreg) { + switch (l->ext) { + case kUpb_ExtMode_Extendable: { + const upb_MiniTable_Extension* ext = + _upb_extreg_get(d->extreg, l, field_number); + if (ext) return &ext->field; + break; + } + case kUpb_ExtMode_IsMessageSet: + if (field_number == _UPB_MSGSET_ITEM) { + static upb_MiniTable_Field item = {0, 0, 0, 0, TYPE_MSGSET_ITEM, 0}; + return &item; + } + break; } } - *iter = i; - return false; -} - -bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int depth) { - size_t iter = kUpb_Message_Begin; - const upb_FieldDef* f; - upb_MessageValue val; - bool ret = true; - - if (--depth == 0) return false; - - _upb_Message_DiscardUnknown_shallow(msg); - - while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { - const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); - if (!subm) continue; - if (upb_FieldDef_IsMap(f)) { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); - const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); - upb_Map* map = (upb_Map*)val.map_val; - size_t iter = kUpb_Map_Begin; + return &none; /* Unknown field. */ - if (!val_m) continue; +found: + UPB_ASSERT(l->fields[idx].number == field_number); + *last_field_index = idx; + return &l->fields[idx]; +} - while (upb_MapIterator_Next(map, &iter)) { - upb_MessageValue map_val = upb_MapIterator_Value(map, iter); - if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, - depth)) { - ret = false; - } - } - } else if (upb_FieldDef_IsRepeated(f)) { - const upb_Array* arr = val.array_val; - size_t i, n = upb_Array_Size(arr); - for (i = 0; i < n; i++) { - upb_MessageValue elem = upb_Array_Get(arr, i); - if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, - depth)) { - ret = false; - } +UPB_FORCEINLINE +static const char* decode_wireval(upb_Decoder* d, const char* ptr, + const upb_MiniTable_Field* field, + int wire_type, wireval* val, int* op) { + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = decode_varint64(d, ptr, &val->uint64_val); + *op = varint_ops[field->descriptortype]; + decode_munge(field->descriptortype, val); + return ptr; + case kUpb_WireType_32Bit: + memcpy(&val->uint32_val, ptr, 4); + val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val); + *op = OP_SCALAR_LG2(2); + if (((1 << field->descriptortype) & FIXED32_OK_MASK) == 0) { + *op = OP_UNKNOWN; } - } else { - if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, - depth)) { - ret = false; + return ptr + 4; + case kUpb_WireType_64Bit: + memcpy(&val->uint64_val, ptr, 8); + val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); + *op = OP_SCALAR_LG2(3); + if (((1 << field->descriptortype) & FIXED64_OK_MASK) == 0) { + *op = OP_UNKNOWN; } + return ptr + 8; + case kUpb_WireType_Delimited: { + int ndx = field->descriptortype; + if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += TYPE_COUNT; + ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); + *op = delim_ops[ndx]; + return ptr; } + case kUpb_WireType_StartGroup: + val->uint32_val = field->number; + if (field->descriptortype == kUpb_FieldType_Group) { + *op = OP_SUBMSG; + } else if (field->descriptortype == TYPE_MSGSET_ITEM) { + *op = OP_MSGSET_ITEM; + } else { + *op = OP_UNKNOWN; + } + return ptr; + default: + break; } + return decode_err(d, kUpb_DecodeStatus_Malformed); +} - return ret; +UPB_FORCEINLINE +static const char* decode_known(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTable* layout, + const upb_MiniTable_Field* field, int op, + wireval* val) { + const upb_MiniTable_Sub* subs = layout->subs; + uint8_t mode = field->mode; + + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTable_Extension* ext_layout = + (const upb_MiniTable_Extension*)field; + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, ext_layout, &d->arena); + if (UPB_UNLIKELY(!ext)) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); + d->unknown_msg = msg; + msg = &ext->data; + subs = &ext->ext->sub; + } + + switch (mode & kUpb_FieldMode_Mask) { + case kUpb_FieldMode_Array: + return decode_toarray(d, ptr, msg, subs, field, val, op); + case kUpb_FieldMode_Map: + return decode_tomap(d, ptr, msg, subs, field, val); + case kUpb_FieldMode_Scalar: + return decode_tomsg(d, ptr, msg, subs, field, val, op); + default: + UPB_UNREACHABLE(); + } } -bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int maxdepth) { - return _upb_Message_DiscardUnknown(msg, m, maxdepth); +static const char* decode_reverse_skip_varint(const char* ptr, uint32_t val) { + uint32_t seen = 0; + do { + ptr--; + seen <<= 7; + seen |= *ptr & 0x7f; + } while (seen != val); + return ptr; } -/** upb_Array *****************************************************************/ - -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { - return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); -} +static const char* decode_unknown(upb_Decoder* d, const char* ptr, + upb_Message* msg, int field_number, + int wire_type, wireval val) { + if (field_number == 0) return decode_err(d, kUpb_DecodeStatus_Malformed); -size_t upb_Array_Size(const upb_Array* arr) { return arr->len; } + // Since unknown fields are the uncommon case, we do a little extra work here + // to walk backwards through the buffer to find the field start. This frees + // up a register in the fast paths (when the field is known), which leads to + // significant speedups in benchmarks. + const char* start = ptr; -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { - upb_MessageValue ret; - const char* data = _upb_array_constptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(&ret, data + (i << lg2), 1 << lg2); - return ret; -} + if (wire_type == kUpb_WireType_Delimited) ptr += val.size; + if (msg) { + switch (wire_type) { + case kUpb_WireType_Varint: + case kUpb_WireType_Delimited: + start--; + while (start[-1] & 0x80) start--; + break; + case kUpb_WireType_32Bit: + start -= 4; + break; + case kUpb_WireType_64Bit: + start -= 8; + break; + default: + break; + } -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(data + (i << lg2), &val, 1 << lg2); -} + assert(start == d->debug_valstart); + uint32_t tag = ((uint32_t)field_number << 3) | wire_type; + start = decode_reverse_skip_varint(start, tag); + assert(start == d->debug_tagstart); -bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { - if (!upb_Array_Resize(arr, arr->len + 1, arena)) { - return false; + if (wire_type == kUpb_WireType_StartGroup) { + d->unknown = start; + d->unknown_msg = msg; + ptr = decode_group(d, ptr, NULL, NULL, field_number); + start = d->unknown; + d->unknown = NULL; + } + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + return decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } + } else if (wire_type == kUpb_WireType_StartGroup) { + ptr = decode_group(d, ptr, NULL, NULL, field_number); } - upb_Array_Set(arr, arr->len - 1, val); - return true; + return ptr; } -void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, - size_t count) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); -} +UPB_NOINLINE +static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout) { + int last_field_index = 0; -bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, - upb_Arena* arena) { - UPB_ASSERT(i <= arr->len); - UPB_ASSERT(count + arr->len >= count); - size_t oldsize = arr->len; - if (!upb_Array_Resize(arr, arr->len + count, arena)) { - return false; - } - upb_Array_Move(arr, i + count, i, oldsize - i); - return true; -} +#if UPB_FASTTABLE + // The first time we want to skip fast dispatch, because we may have just been + // invoked by the fast parser to handle a case that it bailed on. + if (!decode_isdone(d, &ptr)) goto nofast; +#endif -/* - * i end arr->len - * |------------|XXXXXXXX|--------| - */ -void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { - size_t end = i + count; - UPB_ASSERT(i <= end); - UPB_ASSERT(end <= arr->len); - upb_Array_Move(arr, i, end, arr->len - end); - arr->len -= count; -} + while (!decode_isdone(d, &ptr)) { + uint32_t tag; + const upb_MiniTable_Field* field; + int field_number; + int wire_type; + wireval val; + int op; -bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { - return _upb_Array_Resize(arr, size, arena); -} + if (decode_tryfastdispatch(d, &ptr, msg, layout)) break; -/** upb_Map *******************************************************************/ +#if UPB_FASTTABLE + nofast: +#endif -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { - return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], - _upb_CTypeo_mapsize[value_type]); -} +#ifndef NDEBUG + d->debug_tagstart = ptr; +#endif -size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } + UPB_ASSERT(ptr < d->limit_ptr); + ptr = decode_tag(d, ptr, &tag); + field_number = tag >> 3; + wire_type = tag & 7; -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val) { - return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); -} +#ifndef NDEBUG + d->debug_valstart = ptr; +#endif -void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } + if (wire_type == kUpb_WireType_EndGroup) { + d->end_group = field_number; + return ptr; + } -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena) { - return _upb_Map_Set(map, &key, map->key_size, &val, map->val_size, arena); -} + field = decode_findfield(d, layout, field_number, &last_field_index); + ptr = decode_wireval(d, ptr, field, wire_type, &val, &op); -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { - return _upb_Map_Delete(map, &key, map->key_size); -} + if (op >= 0) { + ptr = decode_known(d, ptr, msg, layout, field, op, &val); + } else { + switch (op) { + case OP_UNKNOWN: + ptr = decode_unknown(d, ptr, msg, field_number, wire_type, val); + break; + case OP_MSGSET_ITEM: + ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); + break; + } + } + } -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { - return _upb_map_next(map, iter); + return UPB_UNLIKELY(layout && layout->required_count) + ? decode_checkrequired(d, ptr, msg, layout) + : ptr; } -bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - UPB_ASSERT(iter != kUpb_Map_Begin); - i.t = &map->table; - i.index = iter; - return upb_strtable_done(&i); +const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data) { + (void)data; + *(uint32_t*)msg |= hasbits; + return decode_msg(d, ptr, msg, decode_totablep(table)); } -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); - return ret; +static upb_DecodeStatus decode_top(struct upb_Decoder* d, const char* buf, + void* msg, const upb_MiniTable* l) { + if (!decode_tryfastdispatch(d, &buf, msg, l)) { + decode_msg(d, buf, msg, l); + } + if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; + if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; + return kUpb_DecodeStatus_Ok; } -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); - return ret; -} +upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg, + const upb_MiniTable* l, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena) { + upb_Decoder state; + unsigned depth = (unsigned)options >> 16; -/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue - * value); */ + if (size <= 16) { + memset(&state.patch, 0, 32); + if (size) memcpy(&state.patch, buf, size); + buf = state.patch; + state.end = buf + size; + state.limit = 0; + options &= ~kUpb_DecodeOption_AliasString; // Can't alias patch buf. + } else { + state.end = buf + size - 16; + state.limit = 16; + } -/** upb/json_decode.c ************************************************************/ + state.extreg = extreg; + state.limit_ptr = state.end; + state.unknown = NULL; + state.depth = depth ? depth : 64; + state.end_group = DECODE_NOGROUP; + state.options = (uint16_t)options; + state.missing_required = false; + state.arena.head = arena->head; + state.arena.last_size = arena->last_size; + state.arena.cleanup_metadata = arena->cleanup_metadata; + state.arena.parent = arena; -#include -#include -#include -#include -#include -#include -#include -#include + upb_DecodeStatus status = UPB_SETJMP(state.err); + if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { + status = decode_top(&state, buf, msg, l); + } + arena->head.ptr = state.arena.head.ptr; + arena->head.end = state.arena.head.end; + arena->cleanup_metadata = state.arena.cleanup_metadata; + return status; +} -/* Special header, must be included last. */ +#undef OP_UNKNOWN +#undef OP_SKIP +#undef OP_SCALAR_LG2 +#undef OP_FIXPCK_LG2 +#undef OP_VARPCK_LG2 +#undef OP_STRING +#undef OP_BYTES +#undef OP_SUBMSG -typedef struct { - const char *ptr, *end; - upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ - const upb_DefPool* symtab; - int depth; - upb_Status* status; - jmp_buf err; - int line; - const char* line_begin; - bool is_first; - int options; - const upb_FieldDef* debug_field; -} jsondec; +/** upb/encode.c ************************************************************/ +/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ -enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; -/* Forward declarations of mutually-recursive functions. */ -static void jsondec_wellknown(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); -static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); -static void jsondec_object(jsondec* d, upb_Message* msg, - const upb_MessageDef* m); +#include +#include -static bool jsondec_streql(upb_StringView str, const char* lit) { - return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; -} -static bool jsondec_isnullvalue(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum && - strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), - "google.protobuf.NullValue") == 0; -} +/* Must be last. */ -static bool jsondec_isvalue(const upb_FieldDef* f) { - return (upb_FieldDef_CType(f) == kUpb_CType_Message && - upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == - kUpb_WellKnown_Value) || - jsondec_isnullvalue(f); -} +#define UPB_PB_VARINT_MAX_LEN 10 -UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { - upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, - (int)(d->ptr - d->line_begin), msg); - UPB_LONGJMP(d->err, 1); +UPB_NOINLINE +static size_t encode_varint64(uint64_t val, char* buf) { + size_t i = 0; + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + buf[i++] = byte; + } while (val); + return i; } -UPB_PRINTF(2, 3) -UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { - va_list argp; - upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, - (int)(d->ptr - d->line_begin)); - va_start(argp, fmt); - upb_Status_VAppendErrorFormat(d->status, fmt, argp); - va_end(argp); - UPB_LONGJMP(d->err, 1); +static uint32_t encode_zz32(int32_t n) { + return ((uint32_t)n << 1) ^ (n >> 31); } - -static void jsondec_skipws(jsondec* d) { - while (d->ptr != d->end) { - switch (*d->ptr) { - case '\n': - d->line++; - d->line_begin = d->ptr; - /* Fallthrough. */ - case '\r': - case '\t': - case ' ': - d->ptr++; - break; - default: - return; - } - } - jsondec_err(d, "Unexpected EOF"); +static uint64_t encode_zz64(int64_t n) { + return ((uint64_t)n << 1) ^ (n >> 63); } -static bool jsondec_tryparsech(jsondec* d, char ch) { - if (d->ptr == d->end || *d->ptr != ch) return false; - d->ptr++; - return true; -} +typedef struct { + jmp_buf err; + upb_alloc* alloc; + char *buf, *ptr, *limit; + int options; + int depth; + _upb_mapsorter sorter; +} upb_encstate; -static void jsondec_parselit(jsondec* d, const char* lit) { - size_t avail = d->end - d->ptr; - size_t len = strlen(lit); - if (avail < len || memcmp(d->ptr, lit, len) != 0) { - jsondec_errf(d, "Expected: '%s'", lit); +static size_t upb_roundup_pow2(size_t bytes) { + size_t ret = 128; + while (ret < bytes) { + ret *= 2; } - d->ptr += len; + return ret; } -static void jsondec_wsch(jsondec* d, char ch) { - jsondec_skipws(d); - if (!jsondec_tryparsech(d, ch)) { - jsondec_errf(d, "Expected: '%c'", ch); - } -} +UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); } -static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } -static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } -static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } +UPB_NOINLINE +static void encode_growbuffer(upb_encstate* e, size_t bytes) { + size_t old_size = e->limit - e->buf; + size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); + char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); -static void jsondec_entrysep(jsondec* d) { - jsondec_skipws(d); - jsondec_parselit(d, ":"); -} + if (!new_buf) encode_err(e); -static int jsondec_rawpeek(jsondec* d) { - switch (*d->ptr) { - case '{': - return JD_OBJECT; - case '[': - return JD_ARRAY; - case '"': - return JD_STRING; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return JD_NUMBER; - case 't': - return JD_TRUE; - case 'f': - return JD_FALSE; - case 'n': - return JD_NULL; - default: - jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); + /* We want previous data at the end, realloc() put it at the beginning. */ + if (old_size > 0) { + memmove(new_buf + new_size - old_size, e->buf, old_size); } -} - -/* JSON object/array **********************************************************/ -/* These are used like so: - * - * jsondec_objstart(d); - * while (jsondec_objnext(d)) { - * ... - * } - * jsondec_objend(d) */ + e->ptr = new_buf + new_size - (e->limit - e->ptr); + e->limit = new_buf + new_size; + e->buf = new_buf; -static int jsondec_peek(jsondec* d) { - jsondec_skipws(d); - return jsondec_rawpeek(d); + e->ptr -= bytes; } -static void jsondec_push(jsondec* d) { - if (--d->depth < 0) { - jsondec_err(d, "Recursion limit exceeded"); +/* Call to ensure that at least "bytes" bytes are available for writing at + * e->ptr. Returns false if the bytes could not be allocated. */ +UPB_FORCEINLINE +static void encode_reserve(upb_encstate* e, size_t bytes) { + if ((size_t)(e->ptr - e->buf) < bytes) { + encode_growbuffer(e, bytes); + return; } - d->is_first = true; -} -static bool jsondec_seqnext(jsondec* d, char end_ch) { - bool is_first = d->is_first; - d->is_first = false; - jsondec_skipws(d); - if (*d->ptr == end_ch) return false; - if (!is_first) jsondec_parselit(d, ","); - return true; + e->ptr -= bytes; } -static void jsondec_arrstart(jsondec* d) { - jsondec_push(d); - jsondec_wsch(d, '['); +/* Writes the given bytes to the buffer, handling reserve/advance. */ +static void encode_bytes(upb_encstate* e, const void* data, size_t len) { + if (len == 0) return; /* memcpy() with zero size is UB */ + encode_reserve(e, len); + memcpy(e->ptr, data, len); } -static void jsondec_arrend(jsondec* d) { - d->depth++; - jsondec_wsch(d, ']'); +static void encode_fixed64(upb_encstate* e, uint64_t val) { + val = _upb_BigEndian_Swap64(val); + encode_bytes(e, &val, sizeof(uint64_t)); } -static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } - -static void jsondec_objstart(jsondec* d) { - jsondec_push(d); - jsondec_wsch(d, '{'); +static void encode_fixed32(upb_encstate* e, uint32_t val) { + val = _upb_BigEndian_Swap32(val); + encode_bytes(e, &val, sizeof(uint32_t)); } -static void jsondec_objend(jsondec* d) { - d->depth++; - jsondec_wsch(d, '}'); -} +UPB_NOINLINE +static void encode_longvarint(upb_encstate* e, uint64_t val) { + size_t len; + char* start; -static bool jsondec_objnext(jsondec* d) { - if (!jsondec_seqnext(d, '}')) return false; - if (jsondec_peek(d) != JD_STRING) { - jsondec_err(d, "Object must start with string"); - } - return true; + encode_reserve(e, UPB_PB_VARINT_MAX_LEN); + len = encode_varint64(val, e->ptr); + start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; + memmove(start, e->ptr, len); + e->ptr = start; } -/* JSON number ****************************************************************/ - -static bool jsondec_tryskipdigits(jsondec* d) { - const char* start = d->ptr; - - while (d->ptr < d->end) { - if (*d->ptr < '0' || *d->ptr > '9') { - break; - } - d->ptr++; +UPB_FORCEINLINE +static void encode_varint(upb_encstate* e, uint64_t val) { + if (val < 128 && e->ptr != e->buf) { + --e->ptr; + *e->ptr = val; + } else { + encode_longvarint(e, val); } +} - return d->ptr != start; +static void encode_double(upb_encstate* e, double d) { + uint64_t u64; + UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); + memcpy(&u64, &d, sizeof(uint64_t)); + encode_fixed64(e, u64); } -static void jsondec_skipdigits(jsondec* d) { - if (!jsondec_tryskipdigits(d)) { - jsondec_err(d, "Expected one or more digits"); - } +static void encode_float(upb_encstate* e, float d) { + uint32_t u32; + UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); + memcpy(&u32, &d, sizeof(uint32_t)); + encode_fixed32(e, u32); } -static double jsondec_number(jsondec* d) { - const char* start = d->ptr; +static void encode_tag(upb_encstate* e, uint32_t field_number, + uint8_t wire_type) { + encode_varint(e, (field_number << 3) | wire_type); +} - assert(jsondec_rawpeek(d) == JD_NUMBER); +static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, + size_t elem_size, uint32_t tag) { + size_t bytes = arr->len * elem_size; + const char* data = _upb_array_constptr(arr); + const char* ptr = data + bytes - elem_size; - /* Skip over the syntax of a number, as specified by JSON. */ - if (*d->ptr == '-') d->ptr++; + if (tag || !_upb_IsLittleEndian()) { + while (true) { + if (elem_size == 4) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap32(val); + encode_bytes(e, &val, elem_size); + } else { + UPB_ASSERT(elem_size == 8); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = _upb_BigEndian_Swap64(val); + encode_bytes(e, &val, elem_size); + } - if (jsondec_tryparsech(d, '0')) { - if (jsondec_tryskipdigits(d)) { - jsondec_err(d, "number cannot have leading zero"); + if (tag) encode_varint(e, tag); + if (ptr == data) break; + ptr -= elem_size; } } else { - jsondec_skipdigits(d); + encode_bytes(e, data, bytes); } +} - if (d->ptr == d->end) goto parse; - if (jsondec_tryparsech(d, '.')) { - jsondec_skipdigits(d); +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size); + +static void encode_scalar(upb_encstate* e, const void* _field_mem, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const char* field_mem = _field_mem; + int wire_type; + +#define CASE(ctype, type, wtype, encodeval) \ + { \ + ctype val = *(ctype*)field_mem; \ + encode_##type(e, encodeval); \ + wire_type = wtype; \ + break; \ } - if (d->ptr == d->end) goto parse; - if (*d->ptr == 'e' || *d->ptr == 'E') { - d->ptr++; - if (d->ptr == d->end) { - jsondec_err(d, "Unexpected EOF in number"); + switch (f->descriptortype) { + case kUpb_FieldType_Double: + CASE(double, double, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Float: + CASE(float, float, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + CASE(uint64_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_UInt32: + CASE(uint32_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Bool: + CASE(bool, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_SInt32: + CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); + case kUpb_FieldType_SInt64: + CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + upb_StringView view = *(upb_StringView*)field_mem; + encode_bytes(e, view.data, view.size); + encode_varint(e, view.size); + wire_type = kUpb_WireType_Delimited; + break; } - if (*d->ptr == '+' || *d->ptr == '-') { - d->ptr++; + case kUpb_FieldType_Group: { + size_t size; + void* submsg = *(void**)field_mem; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (submsg == NULL) { + return; + } + if (--e->depth == 0) encode_err(e); + encode_tag(e, f->number, kUpb_WireType_EndGroup); + encode_message(e, submsg, subm, &size); + wire_type = kUpb_WireType_StartGroup; + e->depth++; + break; } - jsondec_skipdigits(d); + case kUpb_FieldType_Message: { + size_t size; + void* submsg = *(void**)field_mem; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (submsg == NULL) { + return; + } + if (--e->depth == 0) encode_err(e); + encode_message(e, submsg, subm, &size); + encode_varint(e, size); + wire_type = kUpb_WireType_Delimited; + e->depth++; + break; + } + default: + UPB_UNREACHABLE(); } +#undef CASE -parse: - /* Having verified the syntax of a JSON number, use strtod() to parse - * (strtod() accepts a superset of JSON syntax). */ - errno = 0; - { - char* end; - double val = strtod(start, &end); - assert(end == d->ptr); + encode_tag(e, f->number, wire_type); +} - /* Currently the min/max-val conformance tests fail if we check this. Does - * this mean the conformance tests are wrong or strtod() is wrong, or - * something else? Investigate further. */ - /* - if (errno == ERANGE) { - jsondec_err(d, "Number out of range"); - } - */ +static void encode_array(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); + bool packed = f->mode & kUpb_LabelFlags_IsPacked; + size_t pre_len = e->limit - e->ptr; - if (val > DBL_MAX || val < -DBL_MAX) { - jsondec_err(d, "Number out of range"); + if (arr == NULL || arr->len == 0) { + return; + } + +#define VARINT_CASE(ctype, encode) \ + { \ + const ctype* start = _upb_array_constptr(arr); \ + const ctype* ptr = start + arr->len; \ + uint32_t tag = packed ? 0 : (f->number << 3) | kUpb_WireType_Varint; \ + do { \ + ptr--; \ + encode_varint(e, encode); \ + if (tag) encode_varint(e, tag); \ + } while (ptr != start); \ + } \ + break; + +#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) + + switch (f->descriptortype) { + case kUpb_FieldType_Double: + encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Float: + encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + VARINT_CASE(uint64_t, *ptr); + case kUpb_FieldType_UInt32: + VARINT_CASE(uint32_t, *ptr); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + VARINT_CASE(int32_t, (int64_t)*ptr); + case kUpb_FieldType_Bool: + VARINT_CASE(bool, *ptr); + case kUpb_FieldType_SInt32: + VARINT_CASE(int32_t, encode_zz32(*ptr)); + case kUpb_FieldType_SInt64: + VARINT_CASE(int64_t, encode_zz64(*ptr)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + const upb_StringView* start = _upb_array_constptr(arr); + const upb_StringView* ptr = start + arr->len; + do { + ptr--; + encode_bytes(e, ptr->data, ptr->size); + encode_varint(e, ptr->size); + encode_tag(e, f->number, kUpb_WireType_Delimited); + } while (ptr != start); + return; + } + case kUpb_FieldType_Group: { + const void* const* start = _upb_array_constptr(arr); + const void* const* ptr = start + arr->len; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (--e->depth == 0) encode_err(e); + do { + size_t size; + ptr--; + encode_tag(e, f->number, kUpb_WireType_EndGroup); + encode_message(e, *ptr, subm, &size); + encode_tag(e, f->number, kUpb_WireType_StartGroup); + } while (ptr != start); + e->depth++; + return; + } + case kUpb_FieldType_Message: { + const void* const* start = _upb_array_constptr(arr); + const void* const* ptr = start + arr->len; + const upb_MiniTable* subm = subs[f->submsg_index].submsg; + if (--e->depth == 0) encode_err(e); + do { + size_t size; + ptr--; + encode_message(e, *ptr, subm, &size); + encode_varint(e, size); + encode_tag(e, f->number, kUpb_WireType_Delimited); + } while (ptr != start); + e->depth++; + return; } - - return val; } -} - -/* JSON string ****************************************************************/ +#undef VARINT_CASE -static char jsondec_escape(jsondec* d) { - switch (*d->ptr++) { - case '"': - return '\"'; - case '\\': - return '\\'; - case '/': - return '/'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - default: - jsondec_err(d, "Invalid escape char"); + if (packed) { + encode_varint(e, e->limit - e->ptr - pre_len); + encode_tag(e, f->number, kUpb_WireType_Delimited); } } -static uint32_t jsondec_codepoint(jsondec* d) { - uint32_t cp = 0; - const char* end; - - if (d->end - d->ptr < 4) { - jsondec_err(d, "EOF inside string"); - } +static void encode_mapentry(upb_encstate* e, uint32_t number, + const upb_MiniTable* layout, + const upb_MapEntry* ent) { + const upb_MiniTable_Field* key_field = &layout->fields[0]; + const upb_MiniTable_Field* val_field = &layout->fields[1]; + size_t pre_len = e->limit - e->ptr; + size_t size; + encode_scalar(e, &ent->v, layout->subs, val_field); + encode_scalar(e, &ent->k, layout->subs, key_field); + size = (e->limit - e->ptr) - pre_len; + encode_varint(e, size); + encode_tag(e, number, kUpb_WireType_Delimited); +} - end = d->ptr + 4; - while (d->ptr < end) { - char ch = *d->ptr++; - if (ch >= '0' && ch <= '9') { - ch -= '0'; - } else if (ch >= 'a' && ch <= 'f') { - ch = ch - 'a' + 10; - } else if (ch >= 'A' && ch <= 'F') { - ch = ch - 'A' + 10; - } else { - jsondec_err(d, "Invalid hex digit"); - } - cp = (cp << 4) | ch; - } +static void encode_map(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + const upb_Map* map = *UPB_PTR_AT(msg, f->offset, const upb_Map*); + const upb_MiniTable* layout = subs[f->submsg_index].submsg; + UPB_ASSERT(layout->field_count == 2); - return cp; -} + if (map == NULL) return; -/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ -static size_t jsondec_unicode(jsondec* d, char* out) { - uint32_t cp = jsondec_codepoint(d); - if (cp >= 0xd800 && cp <= 0xdbff) { - /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ - uint32_t high = cp; - uint32_t low; - jsondec_parselit(d, "\\u"); - low = jsondec_codepoint(d); - if (low < 0xdc00 || low > 0xdfff) { - jsondec_err(d, "Invalid low surrogate"); + if (e->options & kUpb_Encode_Deterministic) { + _upb_sortedmap sorted; + _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, + &sorted); + upb_MapEntry ent; + while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { + encode_mapentry(e, f->number, layout, &ent); } - cp = (high & 0x3ff) << 10; - cp |= (low & 0x3ff); - cp += 0x10000; - } else if (cp >= 0xdc00 && cp <= 0xdfff) { - jsondec_err(d, "Unpaired low surrogate"); - } - - /* Write to UTF-8 */ - if (cp <= 0x7f) { - out[0] = cp; - return 1; - } else if (cp <= 0x07FF) { - out[0] = ((cp >> 6) & 0x1F) | 0xC0; - out[1] = ((cp >> 0) & 0x3F) | 0x80; - return 2; - } else if (cp <= 0xFFFF) { - out[0] = ((cp >> 12) & 0x0F) | 0xE0; - out[1] = ((cp >> 6) & 0x3F) | 0x80; - out[2] = ((cp >> 0) & 0x3F) | 0x80; - return 3; - } else if (cp < 0x10FFFF) { - out[0] = ((cp >> 18) & 0x07) | 0xF0; - out[1] = ((cp >> 12) & 0x3f) | 0x80; - out[2] = ((cp >> 6) & 0x3f) | 0x80; - out[3] = ((cp >> 0) & 0x3f) | 0x80; - return 4; + _upb_mapsorter_popmap(&e->sorter, &sorted); } else { - jsondec_err(d, "Invalid codepoint"); + upb_strtable_iter i; + upb_strtable_begin(&i, &map->table); + for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_StringView key = upb_strtable_iter_key(&i); + const upb_value val = upb_strtable_iter_value(&i); + upb_MapEntry ent; + _upb_map_fromkey(key, &ent.k, map->key_size); + _upb_map_fromvalue(val, &ent.v, map->val_size); + encode_mapentry(e, f->number, layout, &ent); + } } } -static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { - size_t oldsize = *buf_end - *buf; - size_t len = *end - *buf; - size_t size = UPB_MAX(8, 2 * oldsize); - - *buf = upb_Arena_Realloc(d->arena, *buf, len, size); - if (!*buf) jsondec_err(d, "Out of memory"); - - *end = *buf + len; - *buf_end = *buf + size; -} - -static upb_StringView jsondec_string(jsondec* d) { - char* buf = NULL; - char* end = NULL; - char* buf_end = NULL; - - jsondec_skipws(d); - - if (*d->ptr++ != '"') { - jsondec_err(d, "Expected string"); - } - - while (d->ptr < d->end) { - char ch = *d->ptr++; - - if (end == buf_end) { - jsondec_resize(d, &buf, &end, &buf_end); - } - - switch (ch) { - case '"': { - upb_StringView ret; - ret.data = buf; - ret.size = end - buf; - *end = '\0'; /* Needed for possible strtod(). */ - return ret; +static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* f) { + if (f->presence == 0) { + /* Proto3 presence or map/array. */ + const void* mem = UPB_PTR_AT(msg, f->offset, void); + switch (f->mode >> kUpb_FieldRep_Shift) { + case kUpb_FieldRep_1Byte: { + char ch; + memcpy(&ch, mem, 1); + return ch != 0; + } +#if UINTPTR_MAX == 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_4Byte: { + uint32_t u32; + memcpy(&u32, mem, 4); + return u32 != 0; + } +#if UINTPTR_MAX != 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_8Byte: { + uint64_t u64; + memcpy(&u64, mem, 8); + return u64 != 0; + } + case kUpb_FieldRep_StringView: { + const upb_StringView* str = (const upb_StringView*)mem; + return str->size != 0; } - case '\\': - if (d->ptr == d->end) goto eof; - if (*d->ptr == 'u') { - d->ptr++; - if (buf_end - end < 4) { - /* Allow space for maximum-sized code point (4 bytes). */ - jsondec_resize(d, &buf, &end, &buf_end); - } - end += jsondec_unicode(d, end); - } else { - *end++ = jsondec_escape(d); - } - break; default: - if ((unsigned char)*d->ptr < 0x20) { - jsondec_err(d, "Invalid char in JSON string"); - } - *end++ = ch; - break; + UPB_UNREACHABLE(); } + } else if (f->presence > 0) { + /* Proto2 presence: hasbit. */ + return _upb_hasbit_field(msg, f); + } else { + /* Field is in a oneof. */ + return _upb_getoneofcase_field(msg, f) == f->number; } - -eof: - jsondec_err(d, "EOF inside string"); } - -static void jsondec_skipval(jsondec* d) { - switch (jsondec_peek(d)) { - case JD_OBJECT: - jsondec_objstart(d); - while (jsondec_objnext(d)) { - jsondec_string(d); - jsondec_entrysep(d); - jsondec_skipval(d); - } - jsondec_objend(d); - break; - case JD_ARRAY: - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - jsondec_skipval(d); - } - jsondec_arrend(d); - break; - case JD_TRUE: - jsondec_true(d); - break; - case JD_FALSE: - jsondec_false(d); - break; - case JD_NULL: - jsondec_null(d); + +static void encode_field(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable_Sub* subs, + const upb_MiniTable_Field* field) { + switch (upb_FieldMode_Get(field)) { + case kUpb_FieldMode_Array: + encode_array(e, msg, subs, field); break; - case JD_STRING: - jsondec_string(d); + case kUpb_FieldMode_Map: + encode_map(e, msg, subs, field); break; - case JD_NUMBER: - jsondec_number(d); + case kUpb_FieldMode_Scalar: + encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field); break; + default: + UPB_UNREACHABLE(); } } -/* Base64 decoding for bytes fields. ******************************************/ - -static unsigned int jsondec_base64_tablelookup(const char ch) { - /* Table includes the normal base64 chars plus the URL-safe variant. */ - const signed char table[256] = { - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, - 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, - 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, - -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, - 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, - 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, - 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, - -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, - 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, - 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, - 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, - 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1}; - - /* Sign-extend return value so high bit will be set on any unexpected char. */ - return table[(unsigned)ch]; +/* message MessageSet { + * repeated group Item = 1 { + * required int32 type_id = 2; + * required string message = 3; + * } + * } */ +static void encode_msgset_item(upb_encstate* e, + const upb_Message_Extension* ext) { + size_t size; + encode_tag(e, 1, kUpb_WireType_EndGroup); + encode_message(e, ext->data.ptr, ext->ext->sub.submsg, &size); + encode_varint(e, size); + encode_tag(e, 3, kUpb_WireType_Delimited); + encode_varint(e, ext->ext->field.number); + encode_tag(e, 2, kUpb_WireType_Varint); + encode_tag(e, 1, kUpb_WireType_StartGroup); } -static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, - char* out) { - int32_t val = -1; - - switch (end - ptr) { - case 2: - val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12; - out[0] = val >> 16; - out += 1; - break; - case 3: - val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12 | - jsondec_base64_tablelookup(ptr[2]) << 6; - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out += 2; - break; - } +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size) { + size_t pre_len = e->limit - e->ptr; - if (val < 0) { - jsondec_err(d, "Corrupt base64"); + if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) { + uint64_t msg_head; + memcpy(&msg_head, msg, 8); + msg_head = _upb_BigEndian_Swap64(msg_head); + if (upb_MiniTable_requiredmask(m) & ~msg_head) { + encode_err(e); + } } - return out; -} - -static size_t jsondec_base64(jsondec* d, upb_StringView str) { - /* We decode in place. This is safe because this is a new buffer (not - * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ - char* out = (char*)str.data; - const char* ptr = str.data; - const char* end = ptr + str.size; - const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ + if ((e->options & kUpb_Encode_SkipUnknown) == 0) { + size_t unknown_size; + const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); - for (; ptr < end4; ptr += 4, out += 3) { - int val = jsondec_base64_tablelookup(ptr[0]) << 18 | - jsondec_base64_tablelookup(ptr[1]) << 12 | - jsondec_base64_tablelookup(ptr[2]) << 6 | - jsondec_base64_tablelookup(ptr[3]) << 0; + if (unknown) { + encode_bytes(e, unknown, unknown_size); + } + } - if (val < 0) { - /* Junk chars or padding. Remove trailing padding, if any. */ - if (end - ptr == 4 && ptr[3] == '=') { - if (ptr[2] == '=') { - end -= 2; + if (m->ext != kUpb_ExtMode_NonExtendable) { + /* Encode all extensions together. Unlike C++, we do not attempt to keep + * these in field number order relative to normal fields or even to each + * other. */ + size_t ext_count; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count); + if (ext_count) { + const upb_Message_Extension* end = ext + ext_count; + for (; ext != end; ext++) { + if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) { + encode_msgset_item(e, ext); } else { - end -= 1; + encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); } } - break; } + } - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out[2] = val & 0xff; + if (m->field_count) { + const upb_MiniTable_Field* f = &m->fields[m->field_count]; + const upb_MiniTable_Field* first = &m->fields[0]; + while (f != first) { + f--; + if (encode_shouldencode(e, msg, m->subs, f)) { + encode_field(e, msg, m->subs, f); + } + } } - if (ptr < end) { - /* Process remaining chars. We do not require padding. */ - out = jsondec_partialbase64(d, ptr, end, out); + *size = (e->limit - e->ptr) - pre_len; +} + +char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, + upb_Arena* arena, size_t* size) { + upb_encstate e; + unsigned depth = (unsigned)options >> 16; + + e.alloc = upb_Arena_Alloc(arena); + e.buf = NULL; + e.limit = NULL; + e.ptr = NULL; + e.depth = depth ? depth : 64; + e.options = options; + _upb_mapsorter_init(&e.sorter); + char* ret = NULL; + + if (UPB_SETJMP(e.err)) { + *size = 0; + ret = NULL; + } else { + encode_message(&e, msg, l, size); + *size = e.limit - e.ptr; + if (*size == 0) { + static char ch; + ret = &ch; + } else { + UPB_ASSERT(e.ptr); + ret = e.ptr; + } } - return out - str.data; + _upb_mapsorter_destroy(&e.sorter); + return ret; } -/* Low-level integer parsing **************************************************/ +/** upb/msg.c ************************************************************/ -/* We use these hand-written routines instead of strto[u]l() because the "long - * long" variants aren't in c89. Also our version allows setting a ptr limit. */ -static const char* jsondec_buftouint64(jsondec* d, const char* ptr, - const char* end, uint64_t* val) { - uint64_t u64 = 0; - while (ptr < end) { - unsigned ch = *ptr - '0'; - if (ch >= 10) break; - if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { - jsondec_err(d, "Integer overflow"); +/** upb_Message ***************************************************************/ + +static const size_t overhead = sizeof(upb_Message_InternalData); + +static const upb_Message_Internal* upb_Message_Getinternal_const( + const upb_Message* msg) { + ptrdiff_t size = sizeof(upb_Message_Internal); + return (upb_Message_Internal*)((char*)msg - size); +} + +upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a) { + return _upb_Message_New_inl(l, a); +} + +void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { + void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char); + memset(mem, 0, upb_msg_sizeof(l)); +} + +static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (!in->internal) { + /* No internal data, allocate from scratch. */ + size_t size = UPB_MAX(128, _upb_Log2CeilingSize(need + overhead)); + upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); + if (!internal) return false; + internal->size = size; + internal->unknown_end = overhead; + internal->ext_begin = size; + in->internal = internal; + } else if (in->internal->ext_begin - in->internal->unknown_end < need) { + /* Internal data is too small, reallocate. */ + size_t new_size = _upb_Log2CeilingSize(in->internal->size + need); + size_t ext_bytes = in->internal->size - in->internal->ext_begin; + size_t new_ext_begin = new_size - ext_bytes; + upb_Message_InternalData* internal = + upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size); + if (!internal) return false; + if (ext_bytes) { + /* Need to move extension data to the end. */ + char* ptr = (char*)internal; + memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes); } - u64 *= 10; - u64 += ch; - ptr++; + internal->ext_begin = new_ext_begin; + internal->size = new_size; + in->internal = internal; } - - *val = u64; - return ptr; + UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); + return true; } -static const char* jsondec_buftoint64(jsondec* d, const char* ptr, - const char* end, int64_t* val) { - bool neg = false; - uint64_t u64; - - if (ptr != end && *ptr == '-') { - ptr++; - neg = true; - } +bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, + upb_Arena* arena) { + if (!realloc_internal(msg, len, arena)) return false; + upb_Message_Internal* in = upb_Message_Getinternal(msg); + memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len); + in->internal->unknown_end += len; + return true; +} - ptr = jsondec_buftouint64(d, ptr, end, &u64); - if (u64 > (uint64_t)INT64_MAX + neg) { - jsondec_err(d, "Integer overflow"); +void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (in->internal) { + in->internal->unknown_end = overhead; } - - *val = neg ? -u64 : u64; - return ptr; } -static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { - const char* end = str.data + str.size; - uint64_t ret; - if (jsondec_buftouint64(d, str.data, end, &ret) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { + const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); + if (in->internal) { + *len = in->internal->unknown_end - overhead; + return (char*)(in->internal + 1); + } else { + *len = 0; + return NULL; } - return ret; } -static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { - const char* end = str.data + str.size; - int64_t ret; - if (jsondec_buftoint64(d, str.data, end, &ret) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count) { + const upb_Message_Internal* in = upb_Message_Getinternal_const(msg); + if (in->internal) { + *count = (in->internal->size - in->internal->ext_begin) / + sizeof(upb_Message_Extension); + return UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + } else { + *count = 0; + return NULL; } - return ret; } -/* Primitive value types ******************************************************/ - -/* Parse INT32 or INT64 value. */ -static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; - - switch (jsondec_peek(d)) { - case JD_NUMBER: { - double dbl = jsondec_number(d); - if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { - jsondec_err(d, "JSON number is out of range."); - } - val.int64_val = dbl; /* must be guarded, overflow here is UB */ - if (val.int64_val != dbl) { - jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, - val.int64_val); - } - break; - } - case JD_STRING: { - upb_StringView str = jsondec_string(d); - val.int64_val = jsondec_strtoint64(d, str); - break; - } - default: - jsondec_err(d, "Expected number or string"); - } +const upb_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTable_Extension* e) { + size_t n; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); - if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || - upb_FieldDef_CType(f) == kUpb_CType_Enum) { - if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { - jsondec_err(d, "Integer out of range."); + /* For now we use linear search exclusively to find extensions. If this + * becomes an issue due to messages with lots of extensions, we can introduce + * a table of some sort. */ + for (size_t i = 0; i < n; i++) { + if (ext[i].ext == e) { + return &ext[i]; } - val.int32_val = (int32_t)val.int64_val; } - return val; + return NULL; } -/* Parse UINT32 or UINT64 value. */ -static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val = {0}; - - switch (jsondec_peek(d)) { - case JD_NUMBER: { - double dbl = jsondec_number(d); - if (dbl > 18446744073709549568.0 || dbl < 0) { - jsondec_err(d, "JSON number is out of range."); - } - val.uint64_val = dbl; /* must be guarded, overflow here is UB */ - if (val.uint64_val != dbl) { - jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, - val.uint64_val); - } - break; - } - case JD_STRING: { - upb_StringView str = jsondec_string(d); - val.uint64_val = jsondec_strtouint64(d, str); - break; - } - default: - jsondec_err(d, "Expected number or string"); +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTable_Extension* ext_l) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (!in->internal) return; + const upb_Message_Extension* base = + UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + upb_Message_Extension* ext = + (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); + if (ext) { + *ext = *base; + in->internal->ext_begin += sizeof(upb_Message_Extension); } +} - if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { - if (val.uint64_val > UINT32_MAX) { - jsondec_err(d, "Integer out of range."); - } - val.uint32_val = (uint32_t)val.uint64_val; - } +upb_Message_Extension* _upb_Message_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) { + upb_Message_Extension* ext = + (upb_Message_Extension*)_upb_Message_Getext(msg, e); + if (ext) return ext; + if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL; + upb_Message_Internal* in = upb_Message_Getinternal(msg); + in->internal->ext_begin -= sizeof(upb_Message_Extension); + ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + memset(ext, 0, sizeof(upb_Message_Extension)); + ext->ext = e; + return ext; +} - return val; +size_t upb_Message_ExtensionCount(const upb_Message* msg) { + size_t count; + _upb_Message_Getexts(msg, &count); + return count; } -/* Parse DOUBLE or FLOAT value. */ -static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { - upb_StringView str; - upb_MessageValue val = {0}; +/** upb_Array *****************************************************************/ - switch (jsondec_peek(d)) { - case JD_NUMBER: - val.double_val = jsondec_number(d); - break; - case JD_STRING: - str = jsondec_string(d); - if (jsondec_streql(str, "NaN")) { - val.double_val = NAN; - } else if (jsondec_streql(str, "Infinity")) { - val.double_val = INFINITY; - } else if (jsondec_streql(str, "-Infinity")) { - val.double_val = -INFINITY; - } else { - val.double_val = strtod(str.data, NULL); - } - break; - default: - jsondec_err(d, "Expected number or string"); - } +bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena) { + size_t new_size = UPB_MAX(arr->size, 4); + int elem_size_lg2 = arr->data & 7; + size_t old_bytes = arr->size << elem_size_lg2; + size_t new_bytes; + void* ptr = _upb_array_ptr(arr); - if (upb_FieldDef_CType(f) == kUpb_CType_Float) { - if (val.double_val != INFINITY && val.double_val != -INFINITY && - (val.double_val > FLT_MAX || val.double_val < -FLT_MAX)) { - jsondec_err(d, "Float out of range"); - } - val.float_val = val.double_val; - } + /* Log2 ceiling of size. */ + while (new_size < min_size) new_size *= 2; - return val; -} + new_bytes = new_size << elem_size_lg2; + ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes); -/* Parse STRING or BYTES value. */ -static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; - val.str_val = jsondec_string(d); - if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { - val.str_val.size = jsondec_base64(d, val.str_val); + if (!ptr) { + return false; } - return val; -} -static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { - switch (jsondec_peek(d)) { - case JD_STRING: { - upb_StringView str = jsondec_string(d); - const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); - const upb_EnumValueDef* ev = - upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); - upb_MessageValue val; - if (ev) { - val.int32_val = upb_EnumValueDef_Number(ev); - } else { - if (d->options & upb_JsonDecode_IgnoreUnknown) { - val.int32_val = 0; - } else { - jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(str)); - } - } - return val; - } - case JD_NULL: { - if (jsondec_isnullvalue(f)) { - upb_MessageValue val; - jsondec_null(d); - val.int32_val = 0; - return val; - } - } - /* Fallthrough. */ - default: - return jsondec_int(d, f); + arr->data = _upb_tag_arrptr(ptr, elem_size_lg2); + arr->size = new_size; + return true; +} + +static upb_Array* getorcreate_array(upb_Array** arr_ptr, int elem_size_lg2, + upb_Arena* arena) { + upb_Array* arr = *arr_ptr; + if (!arr) { + arr = _upb_Array_New(arena, 4, elem_size_lg2); + if (!arr) return NULL; + *arr_ptr = arr; } + return arr; } -static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { - bool is_map_key = upb_FieldDef_Number(f) == 1 && - upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); - upb_MessageValue val; +void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size, + int elem_size_lg2, upb_Arena* arena) { + upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + return arr && _upb_Array_Resize(arr, size, arena) ? _upb_array_ptr(arr) + : NULL; +} - if (is_map_key) { - upb_StringView str = jsondec_string(d); - if (jsondec_streql(str, "true")) { - val.bool_val = true; - } else if (jsondec_streql(str, "false")) { - val.bool_val = false; - } else { - jsondec_err(d, "Invalid boolean map key"); - } - } else { - switch (jsondec_peek(d)) { - case JD_TRUE: - val.bool_val = true; - jsondec_true(d); - break; - case JD_FALSE: - val.bool_val = false; - jsondec_false(d); - break; - default: - jsondec_err(d, "Expected true or false"); - } +bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value, + int elem_size_lg2, upb_Arena* arena) { + upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + if (!arr) return false; + + size_t elems = arr->len; + + if (!_upb_Array_Resize(arr, elems + 1, arena)) { + return false; } - return val; + char* data = _upb_array_ptr(arr); + memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2); + return true; } -/* Composite types (array/message/map) ****************************************/ +/** upb_Map *******************************************************************/ -static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { - upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { + upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_MessageValue elem = jsondec_value(d, f); - upb_Array_Append(arr, elem, d->arena); + if (!map) { + return NULL; } - jsondec_arrend(d); + + upb_strtable_init(&map->table, 4, a); + map->key_size = key_size; + map->val_size = value_size; + + return map; } -static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { - upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); +static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, + void* b_key, size_t size) { + const upb_tabent* const* a = _a; + const upb_tabent* const* b = _b; + upb_StringView a_tabkey = upb_tabstrview((*a)->key); + upb_StringView b_tabkey = upb_tabstrview((*b)->key); + _upb_map_fromkey(a_tabkey, a_key, size); + _upb_map_fromkey(b_tabkey, b_key, size); +} - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, val; - key = jsondec_value(d, key_f); - jsondec_entrysep(d); - val = jsondec_value(d, val_f); - upb_Map_Set(map, key, val, d->arena); - } - jsondec_objend(d); +#define UPB_COMPARE_INTEGERS(a, b) ((a) < (b) ? -1 : ((a) == (b) ? 0 : 1)) + +static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { + int64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return UPB_COMPARE_INTEGERS(a, b); } -static void jsondec_tomsg(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { - jsondec_object(d, msg, m); - } else { - jsondec_wellknown(d, msg, m); - } +static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { + uint64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return UPB_COMPARE_INTEGERS(a, b); } -static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { - const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); - upb_Message* msg = upb_Message_New(m, d->arena); - upb_MessageValue val; +static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { + int32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return UPB_COMPARE_INTEGERS(a, b); +} - jsondec_tomsg(d, msg, m); - val.msg_val = msg; - return val; +static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { + uint32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return UPB_COMPARE_INTEGERS(a, b); } -static void jsondec_field(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_StringView name; - const upb_FieldDef* f; - const upb_FieldDef* preserved; +static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { + bool a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); + return UPB_COMPARE_INTEGERS(a, b); +} - name = jsondec_string(d); - jsondec_entrysep(d); +static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { + upb_StringView a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); + size_t common_size = UPB_MIN(a.size, b.size); + int cmp = memcmp(a.data, b.data, common_size); + if (cmp) return -cmp; + return UPB_COMPARE_INTEGERS(a.size, b.size); +} - if (name.size >= 2 && name.data[0] == '[' && - name.data[name.size - 1] == ']') { - f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, - name.size - 2); - if (f && upb_FieldDef_ContainingType(f) != m) { - jsondec_errf( - d, "Extension %s extends message %s, but was seen in message %s", - upb_FieldDef_FullName(f), - upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), - upb_MessageDef_FullName(m)); - } - } else { - f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); +#undef UPB_COMPARE_INTEGERS + +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted) { + int map_size = _upb_Map_Size(map); + sorted->start = s->size; + sorted->pos = sorted->start; + sorted->end = sorted->start + map_size; + + /* Grow s->entries if necessary. */ + if (sorted->end > s->cap) { + s->cap = _upb_Log2CeilingSize(sorted->end); + s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); + if (!s->entries) return false; } - if (!f) { - if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { - jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(name)); + s->size = sorted->end; + + /* Copy non-empty entries from the table to s->entries. */ + upb_tabent const** dst = &s->entries[sorted->start]; + const upb_tabent* src = map->table.t.entries; + const upb_tabent* end = src + upb_table_size(&map->table.t); + for (; src < end; src++) { + if (!upb_tabent_isempty(src)) { + *dst = src; + dst++; } - jsondec_skipval(d); - return; } + UPB_ASSERT(dst == &s->entries[sorted->end]); - if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { - /* JSON "null" indicates a default value, so no need to set anything. */ - jsondec_null(d); - return; - } + /* Sort entries according to the key type. */ - if (upb_FieldDef_RealContainingOneof(f) && - upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { - jsondec_err(d, "More than one field for this oneof."); + int (*compar)(const void*, const void*); + + switch (key_type) { + case kUpb_FieldType_Int64: + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_SInt64: + compar = _upb_mapsorter_cmpi64; + break; + case kUpb_FieldType_UInt64: + case kUpb_FieldType_Fixed64: + compar = _upb_mapsorter_cmpu64; + break; + case kUpb_FieldType_Int32: + case kUpb_FieldType_SInt32: + case kUpb_FieldType_SFixed32: + case kUpb_FieldType_Enum: + compar = _upb_mapsorter_cmpi32; + break; + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Fixed32: + compar = _upb_mapsorter_cmpu32; + break; + case kUpb_FieldType_Bool: + compar = _upb_mapsorter_cmpbool; + break; + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: + compar = _upb_mapsorter_cmpstr; + break; + default: + UPB_UNREACHABLE(); } - preserved = d->debug_field; - d->debug_field = f; + qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); + return true; +} - if (upb_FieldDef_IsMap(f)) { - jsondec_map(d, msg, f); - } else if (upb_FieldDef_IsRepeated(f)) { - jsondec_array(d, msg, f); - } else if (upb_FieldDef_IsSubMessage(f)) { - upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; - const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); - jsondec_tomsg(d, submsg, subm); - } else { - upb_MessageValue val = jsondec_value(d, f); - upb_Message_Set(msg, f, val, d->arena); - } +/** upb_ExtensionRegistry *****************************************************/ + +struct upb_ExtensionRegistry { + upb_Arena* arena; + upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ +}; + +#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) - d->debug_field = preserved; +static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { + memcpy(buf, &l, sizeof(l)); + memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); } -static void jsondec_object(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - jsondec_objstart(d); - while (jsondec_objnext(d)) { - jsondec_field(d, msg, m); - } - jsondec_objend(d); +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { + upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); + if (!r) return NULL; + r->arena = arena; + if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; + return r; } -static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - return jsondec_bool(d, f); - case kUpb_CType_Float: - case kUpb_CType_Double: - return jsondec_double(d, f); - case kUpb_CType_UInt32: - case kUpb_CType_UInt64: - return jsondec_uint(d, f); - case kUpb_CType_Int32: - case kUpb_CType_Int64: - return jsondec_int(d, f); - case kUpb_CType_String: - case kUpb_CType_Bytes: - return jsondec_strfield(d, f); - case kUpb_CType_Enum: - return jsondec_enum(d, f); - case kUpb_CType_Message: - return jsondec_msg(d, f); - default: - UPB_UNREACHABLE(); +bool _upb_extreg_add(upb_ExtensionRegistry* r, + const upb_MiniTable_Extension** e, size_t count) { + char buf[EXTREG_KEY_SIZE]; + const upb_MiniTable_Extension** start = e; + const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); + for (; e < end; e++) { + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + upb_value v; + if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { + goto failure; + } + if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, + upb_value_constptr(ext), r->arena)) { + goto failure; + } + } + return true; + +failure: + /* Back out the entries previously added. */ + for (end = e, e = start; e < end; e++) { + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); } + return false; } -/* Well-known types ***********************************************************/ +const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, + const upb_MiniTable* l, + uint32_t num) { + char buf[EXTREG_KEY_SIZE]; + upb_value v; + extreg_key(buf, l, num); + if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { + return upb_value_getconstptr(v); + } else { + return NULL; + } +} -static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, - const char* after) { - uint64_t val; - const char* p = *ptr; - const char* end = p + digits; - size_t after_len = after ? strlen(after) : 0; +/** upb/table.c ************************************************************/ +/* + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ - UPB_ASSERT(digits <= 9); /* int can't overflow. */ +#include - if (jsondec_buftouint64(d, p, end, &val) != end || - (after_len && memcmp(end, after, after_len) != 0)) { - jsondec_err(d, "Malformed timestamp"); - } - UPB_ASSERT(val < INT_MAX); +/* Must be last. */ - *ptr = end + after_len; - return (int)val; -} +#define UPB_MAXARRSIZE 16 /* 64k. */ -static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { - uint64_t nanos = 0; - const char* p = *ptr; +/* From Chromium. */ +#define ARRAY_SIZE(x) \ + ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) - if (p != end && *p == '.') { - const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); - int digits = (int)(nano_end - p - 1); - int exp_lg10 = 9 - digits; - if (digits > 9) { - jsondec_err(d, "Too many digits for partial seconds"); - } - while (exp_lg10--) nanos *= 10; - *ptr = nano_end; - } +static const double MAX_LOAD = 0.85; - UPB_ASSERT(nanos < INT_MAX); +/* The minimum utilization of the array part of a mixed hash/array table. This + * is a speed/memory-usage tradeoff (though it's not straightforward because of + * cache effects). The lower this is, the more memory we'll use. */ +static const double MIN_DENSITY = 0.1; - return (int)nanos; -} +static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } -/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ -int jsondec_epochdays(int y, int m, int d) { - const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ - const uint32_t m_adj = m - 3; /* March-based month. */ - const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; - const uint32_t adjust = carry ? 12 : 0; - const uint32_t y_adj = y + year_base - carry; - const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; - const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; - return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +static upb_value _upb_value_val(uint64_t val) { + upb_value ret; + _upb_value_setval(&ret, val); + return ret; } -static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { - return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; +static int log2ceil(uint64_t v) { + int ret = 0; + bool pow2 = is_pow2(v); + while (v >>= 1) ret++; + ret = pow2 ? ret : ret + 1; /* Ceiling. */ + return UPB_MIN(UPB_MAXARRSIZE, ret); } -static void jsondec_timestamp(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue seconds; - upb_MessageValue nanos; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - - if (str.size < 20) goto malformed; - - { - /* 1972-01-01T01:00:00 */ - int year = jsondec_tsdigits(d, &ptr, 4, "-"); - int mon = jsondec_tsdigits(d, &ptr, 2, "-"); - int day = jsondec_tsdigits(d, &ptr, 2, "T"); - int hour = jsondec_tsdigits(d, &ptr, 2, ":"); - int min = jsondec_tsdigits(d, &ptr, 2, ":"); - int sec = jsondec_tsdigits(d, &ptr, 2, NULL); +char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { + size_t n; + char* p; - seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); + /* Prevent overflow errors. */ + if (len == SIZE_MAX) return NULL; + /* Always null-terminate, even if binary data; but don't rely on the input to + * have a null-terminating byte since it may be a raw binary buffer. */ + n = len + 1; + p = upb_Arena_Malloc(a, n); + if (p) { + memcpy(p, s, len); + p[len] = 0; } + return p; +} - nanos.int32_val = jsondec_nanos(d, &ptr, end); +/* A type to represent the lookup key of either a strtable or an inttable. */ +typedef union { + uintptr_t num; + struct { + const char* str; + size_t len; + } str; +} lookupkey_t; - { - /* [+-]08:00 or Z */ - int ofs_hour = 0; - int ofs_min = 0; - bool neg = false; +static lookupkey_t strkey2(const char* str, size_t len) { + lookupkey_t k; + k.str.str = str; + k.str.len = len; + return k; +} - if (ptr == end) goto malformed; +static lookupkey_t intkey(uintptr_t key) { + lookupkey_t k; + k.num = key; + return k; +} - switch (*ptr++) { - case '-': - neg = true; - /* fallthrough */ - case '+': - if ((end - ptr) != 5) goto malformed; - ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); - ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); - ofs_min = ((ofs_hour * 60) + ofs_min) * 60; - seconds.int64_val += (neg ? ofs_min : -ofs_min); - break; - case 'Z': - if (ptr != end) goto malformed; - break; - default: - goto malformed; - } - } +typedef uint32_t hashfunc_t(upb_tabkey key); +typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); - if (seconds.int64_val < -62135596800) { - jsondec_err(d, "Timestamp out of range"); - } +/* Base table (shared code) ***************************************************/ - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); - return; +static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } -malformed: - jsondec_err(d, "Malformed timestamp"); +static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { + return t->entries + (hash & t->mask); } -static void jsondec_duration(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue seconds; - upb_MessageValue nanos; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - const int64_t max = (uint64_t)3652500 * 86400; +static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } - /* "3.000000001s", "3s", etc. */ - ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val); - nanos.int32_val = jsondec_nanos(d, &ptr, end); +static bool isfull(upb_table* t) { return t->count == t->max_count; } + +static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { + size_t bytes; - if (end - ptr != 1 || *ptr != 's') { - jsondec_err(d, "Malformed duration"); + t->count = 0; + t->size_lg2 = size_lg2; + t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; + t->max_count = upb_table_size(t) * MAX_LOAD; + bytes = upb_table_size(t) * sizeof(upb_tabent); + if (bytes > 0) { + t->entries = upb_Arena_Malloc(a, bytes); + if (!t->entries) return false; + memset(t->entries, 0, bytes); + } else { + t->entries = NULL; } + return true; +} - if (seconds.int64_val < -max || seconds.int64_val > max) { - jsondec_err(d, "Duration out of range"); +static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { + upb_tabent* begin = t->entries; + upb_tabent* end = begin + upb_table_size(t); + for (e = e + 1; e < end; e++) { + if (upb_tabent_isempty(e)) return e; } - - if (seconds.int64_val < 0) { - nanos.int32_val = -nanos.int32_val; + for (e = begin; e < end; e++) { + if (upb_tabent_isempty(e)) return e; } - - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); + UPB_ASSERT(false); + return NULL; } -static void jsondec_listvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); - upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; - - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_Message* value_msg = upb_Message_New(value_m, d->arena); - upb_MessageValue value; - value.msg_val = value_msg; - upb_Array_Append(values, value, d->arena); - jsondec_wellknownvalue(d, value_msg, value_m); - } - jsondec_arrend(d); +static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { + return (upb_tabent*)upb_getentry(t, hash); } -static void jsondec_struct(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); - upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; +static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e; - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, value; - upb_Message* value_msg = upb_Message_New(value_m, d->arena); - key.str_val = jsondec_string(d); - value.msg_val = value_msg; - upb_Map_Set(fields, key, value, d->arena); - jsondec_entrysep(d); - jsondec_wellknownvalue(d, value_msg, value_m); + if (t->size_lg2 == 0) return NULL; + e = upb_getentry(t, hash); + if (upb_tabent_isempty(e)) return NULL; + while (1) { + if (eql(e->key, key)) return e; + if ((e = e->next) == NULL) return NULL; } - jsondec_objend(d); } -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - upb_MessageValue val; - const upb_FieldDef* f; - upb_Message* submsg; +static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + return (upb_tabent*)findentry(t, key, hash, eql); +} - switch (jsondec_peek(d)) { - case JD_NUMBER: - /* double number_value = 2; */ - f = upb_MessageDef_FindFieldByNumber(m, 2); - val.double_val = jsondec_number(d); - break; - case JD_STRING: - /* string string_value = 3; */ - f = upb_MessageDef_FindFieldByNumber(m, 3); - val.str_val = jsondec_string(d); - break; - case JD_FALSE: - /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumber(m, 4); - val.bool_val = false; - jsondec_false(d); - break; - case JD_TRUE: - /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumber(m, 4); - val.bool_val = true; - jsondec_true(d); - break; - case JD_NULL: - /* NullValue null_value = 1; */ - f = upb_MessageDef_FindFieldByNumber(m, 1); - val.int32_val = 0; - jsondec_null(d); - break; - /* Note: these cases return, because upb_Message_Mutable() is enough. */ - case JD_OBJECT: - /* Struct struct_value = 5; */ - f = upb_MessageDef_FindFieldByNumber(m, 5); - submsg = upb_Message_Mutable(msg, f, d->arena).msg; - jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); - return; - case JD_ARRAY: - /* ListValue list_value = 6; */ - f = upb_MessageDef_FindFieldByNumber(m, 6); - submsg = upb_Message_Mutable(msg, f, d->arena).msg; - jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); - return; - default: - UPB_UNREACHABLE(); +static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e = findentry(t, key, hash, eql); + if (e) { + if (v) { + _upb_value_setval(v, e->val.val); + } + return true; + } else { + return false; } - - upb_Message_Set(msg, f, val, d->arena); } -static upb_StringView jsondec_mask(jsondec* d, const char* buf, - const char* end) { - /* FieldMask fields grow due to inserted '_' characters, so we can't do the - * transform in place. */ - const char* ptr = buf; - upb_StringView ret; - char* out; +/* The given key must not already exist in the table. */ +static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey, + upb_value val, uint32_t hash, hashfunc_t* hashfunc, + eqlfunc_t* eql) { + upb_tabent* mainpos_e; + upb_tabent* our_e; - ret.size = end - ptr; - while (ptr < end) { - ret.size += (*ptr >= 'A' && *ptr <= 'Z'); - ptr++; - } + UPB_ASSERT(findentry(t, key, hash, eql) == NULL); - out = upb_Arena_Malloc(d->arena, ret.size); - ptr = buf; - ret.data = out; + t->count++; + mainpos_e = getentry_mutable(t, hash); + our_e = mainpos_e; - while (ptr < end) { - char ch = *ptr++; - if (ch >= 'A' && ch <= 'Z') { - *out++ = '_'; - *out++ = ch + 32; - } else if (ch == '_') { - jsondec_err(d, "field mask may not contain '_'"); + if (upb_tabent_isempty(mainpos_e)) { + /* Our main position is empty; use it. */ + our_e->next = NULL; + } else { + /* Collision. */ + upb_tabent* new_e = emptyent(t, mainpos_e); + /* Head of collider's chain. */ + upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key)); + if (chain == mainpos_e) { + /* Existing ent is in its main position (it has the same hash as us, and + * is the head of our chain). Insert to new ent and append to this chain. + */ + new_e->next = mainpos_e->next; + mainpos_e->next = new_e; + our_e = new_e; } else { - *out++ = ch; + /* Existing ent is not in its main position (it is a node in some other + * chain). This implies that no existing ent in the table has our hash. + * Evict it (updating its chain) and use its ent for head of our chain. */ + *new_e = *mainpos_e; /* copies next. */ + while (chain->next != mainpos_e) { + chain = (upb_tabent*)chain->next; + UPB_ASSERT(chain); + } + chain->next = new_e; + our_e = mainpos_e; + our_e->next = NULL; } } - - return ret; + our_e->key = tabkey; + our_e->val.val = val.val; + UPB_ASSERT(findentry(t, key, hash, eql) == our_e); } -static void jsondec_fieldmask(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - /* repeated string paths = 1; */ - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; - upb_StringView str = jsondec_string(d); - const char* ptr = str.data; - const char* end = ptr + str.size; - upb_MessageValue val; - - while (ptr < end) { - const char* elem_end = memchr(ptr, ',', end - ptr); - if (elem_end) { - val.str_val = jsondec_mask(d, ptr, elem_end); - ptr = elem_end + 1; +static bool rm(upb_table* t, lookupkey_t key, upb_value* val, + upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) { + upb_tabent* chain = getentry_mutable(t, hash); + if (upb_tabent_isempty(chain)) return false; + if (eql(chain->key, key)) { + /* Element to remove is at the head of its chain. */ + t->count--; + if (val) _upb_value_setval(val, chain->val.val); + if (removed) *removed = chain->key; + if (chain->next) { + upb_tabent* move = (upb_tabent*)chain->next; + *chain = *move; + move->key = 0; /* Make the slot empty. */ } else { - val.str_val = jsondec_mask(d, ptr, end); - ptr = end; + chain->key = 0; /* Make the slot empty. */ + } + return true; + } else { + /* Element to remove is either in a non-head position or not in the + * table. */ + while (chain->next && !eql(chain->next->key, key)) { + chain = (upb_tabent*)chain->next; + } + if (chain->next) { + /* Found element to remove. */ + upb_tabent* rm = (upb_tabent*)chain->next; + t->count--; + if (val) _upb_value_setval(val, chain->next->val.val); + if (removed) *removed = rm->key; + rm->key = 0; /* Make the slot empty. */ + chain->next = rm->next; + return true; + } else { + /* Element to remove is not in the table. */ + return false; } - upb_Array_Append(arr, val, d->arena); } } -static void jsondec_anyfield(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { - /* For regular types: {"@type": "[user type]", "f1": , "f2": } - * where f1, f2, etc. are the normal fields of this type. */ - jsondec_field(d, msg, m); - } else { - /* For well-known types: {"@type": "[well-known type]", "value": } - * where is whatever encoding the WKT normally uses. */ - upb_StringView str = jsondec_string(d); - jsondec_entrysep(d); - if (!jsondec_streql(str, "value")) { - jsondec_err(d, "Key for well-known type must be 'value'"); - } - jsondec_wellknown(d, msg, m); - } +static size_t next(const upb_table* t, size_t i) { + do { + if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ + } while (upb_tabent_isempty(&t->entries[i])); + + return i; } -static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* type_m; - upb_StringView type_url = jsondec_string(d); - const char* end = type_url.data + type_url.size; - const char* ptr = end; - upb_MessageValue val; +static size_t begin(const upb_table* t) { return next(t, -1); } - val.str_val = type_url; - upb_Message_Set(msg, type_url_f, val, d->arena); +/* upb_strtable ***************************************************************/ - /* Find message name after the last '/' */ - while (ptr > type_url.data && *--ptr != '/') { - } +/* A simple "subclass" of upb_table that only adds a hash function for strings. + */ - if (ptr == type_url.data || ptr == end) { - jsondec_err(d, "Type url must have at least one '/' and non-empty host"); - } +static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) { + uint32_t len = (uint32_t)k2.str.len; + char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1); + if (str == NULL) return 0; + memcpy(str, &len, sizeof(uint32_t)); + if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); + str[sizeof(uint32_t) + k2.str.len] = '\0'; + return (uintptr_t)str; +} - ptr++; - type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); +/* Adapted from ABSL's wyhash. */ - if (!type_m) { - jsondec_err(d, "Type was not found"); - } +static uint64_t UnalignedLoad64(const void* p) { + uint64_t val; + memcpy(&val, p, 8); + return val; +} - return type_m; +static uint32_t UnalignedLoad32(const void* p) { + uint32_t val; + memcpy(&val, p, 4); + return val; } -static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { - /* string type_url = 1; - * bytes value = 2; */ - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); - upb_Message* any_msg; - const upb_MessageDef* any_m = NULL; - const char* pre_type_data = NULL; - const char* pre_type_end = NULL; - upb_MessageValue encoded; +#if defined(_MSC_VER) && defined(_M_X64) +#include +#endif - jsondec_objstart(d); +/* Computes a * b, returning the low 64 bits of the result and storing the high + * 64 bits in |*high|. */ +static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { +#ifdef __SIZEOF_INT128__ + __uint128_t p = v0; + p *= v1; + *out_high = (uint64_t)(p >> 64); + return (uint64_t)p; +#elif defined(_MSC_VER) && defined(_M_X64) + return _umul128(v0, v1, out_high); +#else + uint64_t a32 = v0 >> 32; + uint64_t a00 = v0 & 0xffffffff; + uint64_t b32 = v1 >> 32; + uint64_t b00 = v1 & 0xffffffff; + uint64_t high = a32 * b32; + uint64_t low = a00 * b00; + uint64_t mid1 = a32 * b00; + uint64_t mid2 = a00 * b32; + low += (mid1 << 32) + (mid2 << 32); + // Omit carry bit, for mixing we do not care about exact numerical precision. + high += (mid1 >> 32) + (mid2 >> 32); + *out_high = high; + return low; +#endif +} - /* Scan looking for "@type", which is not necessarily first. */ - while (!any_m && jsondec_objnext(d)) { - const char* start = d->ptr; - upb_StringView name = jsondec_string(d); - jsondec_entrysep(d); - if (jsondec_streql(name, "@type")) { - any_m = jsondec_typeurl(d, msg, m); - if (pre_type_data) { - pre_type_end = start; - while (*pre_type_end != ',') pre_type_end--; - } - } else { - if (!pre_type_data) pre_type_data = start; - jsondec_skipval(d); - } - } +static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { + uint64_t high; + uint64_t low = upb_umul128(v0, v1, &high); + return low ^ high; +} - if (!any_m) { - jsondec_err(d, "Any object didn't contain a '@type' field"); - } +static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, + const uint64_t salt[]) { + const uint8_t* ptr = (const uint8_t*)data; + uint64_t starting_length = (uint64_t)len; + uint64_t current_state = seed ^ salt[0]; - any_msg = upb_Message_New(any_m, d->arena); + if (len > 64) { + // If we have more than 64 bytes, we're going to handle chunks of 64 + // bytes at a time. We're going to build up two separate hash states + // which we will then hash together. + uint64_t duplicated_state = current_state; - if (pre_type_data) { - size_t len = pre_type_end - pre_type_data + 1; - char* tmp = upb_Arena_Malloc(d->arena, len); - const char* saved_ptr = d->ptr; - const char* saved_end = d->end; - memcpy(tmp, pre_type_data, len - 1); - tmp[len - 1] = '}'; - d->ptr = tmp; - d->end = tmp + len; - d->is_first = true; - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); - } - d->ptr = saved_ptr; - d->end = saved_end; - } + do { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); + uint64_t c = UnalignedLoad64(ptr + 16); + uint64_t d = UnalignedLoad64(ptr + 24); + uint64_t e = UnalignedLoad64(ptr + 32); + uint64_t f = UnalignedLoad64(ptr + 40); + uint64_t g = UnalignedLoad64(ptr + 48); + uint64_t h = UnalignedLoad64(ptr + 56); - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); + uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); + current_state = (cs0 ^ cs1); + + uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); + uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); + duplicated_state = (ds0 ^ ds1); + + ptr += 64; + len -= 64; + } while (len > 64); + + current_state = current_state ^ duplicated_state; } - jsondec_objend(d); + // We now have a data `ptr` with at most 64 bytes and the current state + // of the hashing state machine stored in current_state. + while (len > 16) { + uint64_t a = UnalignedLoad64(ptr); + uint64_t b = UnalignedLoad64(ptr + 8); - encoded.str_val.data = upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, - d->arena, &encoded.str_val.size); - upb_Message_Set(msg, value_f, encoded, d->arena); -} + current_state = WyhashMix(a ^ salt[1], b ^ current_state); -static void jsondec_wrapper(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_MessageValue val = jsondec_value(d, value_f); - upb_Message_Set(msg, value_f, val, d->arena); -} + ptr += 16; + len -= 16; + } -static void jsondec_wellknown(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { - switch (upb_MessageDef_WellKnownType(m)) { - case kUpb_WellKnown_Any: - jsondec_any(d, msg, m); - break; - case kUpb_WellKnown_FieldMask: - jsondec_fieldmask(d, msg, m); - break; - case kUpb_WellKnown_Duration: - jsondec_duration(d, msg, m); - break; - case kUpb_WellKnown_Timestamp: - jsondec_timestamp(d, msg, m); - break; - case kUpb_WellKnown_Value: - jsondec_wellknownvalue(d, msg, m); - break; - case kUpb_WellKnown_ListValue: - jsondec_listvalue(d, msg, m); - break; - case kUpb_WellKnown_Struct: - jsondec_struct(d, msg, m); - break; - case kUpb_WellKnown_DoubleValue: - case kUpb_WellKnown_FloatValue: - case kUpb_WellKnown_Int64Value: - case kUpb_WellKnown_UInt64Value: - case kUpb_WellKnown_Int32Value: - case kUpb_WellKnown_UInt32Value: - case kUpb_WellKnown_StringValue: - case kUpb_WellKnown_BytesValue: - case kUpb_WellKnown_BoolValue: - jsondec_wrapper(d, msg, m); - break; - default: - UPB_UNREACHABLE(); + // We now have a data `ptr` with at most 16 bytes. + uint64_t a = 0; + uint64_t b = 0; + if (len > 8) { + // When we have at least 9 and at most 16 bytes, set A to the first 64 + // bits of the input and B to the last 64 bits of the input. Yes, they will + // overlap in the middle if we are working with less than the full 16 + // bytes. + a = UnalignedLoad64(ptr); + b = UnalignedLoad64(ptr + len - 8); + } else if (len > 3) { + // If we have at least 4 and at most 8 bytes, set A to the first 32 + // bits and B to the last 32 bits. + a = UnalignedLoad32(ptr); + b = UnalignedLoad32(ptr + len - 4); + } else if (len > 0) { + // If we have at least 1 and at most 3 bytes, read all of the provided + // bits into A, with some adjustments. + a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); + b = 0; + } else { + a = 0; + b = 0; } + + uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t z = salt[1] ^ starting_length; + return WyhashMix(w, z); } -bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, - const upb_MessageDef* m, const upb_DefPool* symtab, - int options, upb_Arena* arena, upb_Status* status) { - jsondec d; +const uint64_t kWyhashSalt[5] = { + 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, + 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, +}; - if (size == 0) return true; +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); +} - d.ptr = buf; - d.end = buf + size; - d.arena = arena; - d.symtab = symtab; - d.status = status; - d.options = options; - d.depth = 64; - d.line = 1; - d.line_begin = d.ptr; - d.debug_field = NULL; - d.is_first = false; +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, 0); +} - if (UPB_SETJMP(d.err)) return false; +static uint32_t strhash(upb_tabkey key) { + uint32_t len; + char* str = upb_tabstr(key, &len); + return _upb_Hash_NoSeed(str, len); +} - jsondec_tomsg(&d, msg, m); - return true; +static bool streql(upb_tabkey k1, lookupkey_t k2) { + uint32_t len; + char* str = upb_tabstr(k1, &len); + return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); } -/** upb/json_encode.c ************************************************************/ +bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { + // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 + // denominator. + size_t need_entries = (expected_size + 1) * 1204 / 1024; + UPB_ASSERT(need_entries >= expected_size * 0.85); + int size_lg2 = _upb_Log2Ceiling(need_entries); + return init(&t->t, size_lg2, a); +} -#include -#include -#include -#include -#include -#include -#include -#include +void upb_strtable_clear(upb_strtable* t) { + size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); + t->t.count = 0; + memset((char*)t->t.entries, 0, bytes); +} +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { + upb_strtable new_table; + upb_strtable_iter i; -/* Must be last. */ + if (!init(&new_table.t, size_lg2, a)) return false; + upb_strtable_begin(&i, t); + for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_StringView key = upb_strtable_iter_key(&i); + upb_strtable_insert(&new_table, key.data, key.size, + upb_strtable_iter_value(&i), a); + } + *t = new_table; + return true; +} -typedef struct { - char *buf, *ptr, *end; - size_t overflow; - int indent_depth; - int options; - const upb_DefPool* ext_pool; - jmp_buf err; - upb_Status* status; - upb_Arena* arena; -} jsonenc; +bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, + upb_value v, upb_Arena* a) { + lookupkey_t key; + upb_tabkey tabkey; + uint32_t hash; -static void jsonenc_msg(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); -static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f); -static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first); -static void jsonenc_value(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m); + if (isfull(&t->t)) { + /* Need to resize. New table of double the size, add old elements to it. */ + if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { + return false; + } + } -UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { - upb_Status_SetErrorMessage(e->status, msg); - longjmp(e->err, 1); -} + key = strkey2(k, len); + tabkey = strcopy(key, a); + if (tabkey == 0) return false; -UPB_PRINTF(2, 3) -UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(e->status, fmt, argp); - va_end(argp); - longjmp(e->err, 1); + hash = _upb_Hash_NoSeed(key.str.str, key.str.len); + insert(&t->t, key, tabkey, v, hash, &strhash, &streql); + return true; } -static upb_Arena* jsonenc_arena(jsonenc* e) { - /* Create lazily, since it's only needed for Any */ - if (!e->arena) { - e->arena = upb_Arena_New(); - } - return e->arena; +bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, + upb_value* v) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + return lookup(&t->t, strkey2(key, len), v, hash, &streql); } -static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { - size_t have = e->end - e->ptr; - if (UPB_LIKELY(have >= len)) { - memcpy(e->ptr, data, len); - e->ptr += len; - } else { - if (have) { - memcpy(e->ptr, data, have); - e->ptr += have; - } - e->overflow += (len - have); - } +bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, + upb_value* val) { + uint32_t hash = _upb_Hash_NoSeed(key, len); + upb_tabkey tabkey; + return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); } -static void jsonenc_putstr(jsonenc* e, const char* str) { - jsonenc_putbytes(e, str, strlen(str)); -} +/* Iteration */ -UPB_PRINTF(2, 3) -static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { - size_t n; - size_t have = e->end - e->ptr; - va_list args; +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { + i->t = t; + i->index = begin(&t->t); +} - va_start(args, fmt); - n = vsnprintf(e->ptr, have, fmt, args); - va_end(args); +void upb_strtable_next(upb_strtable_iter* i) { + i->index = next(&i->t->t, i->index); +} - if (UPB_LIKELY(have > n)) { - e->ptr += n; - } else { - e->ptr = UPB_PTRADD(e->ptr, have); - e->overflow += (n - have); - } +bool upb_strtable_done(const upb_strtable_iter* i) { + if (!i->t) return true; + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(str_tabent(i)); } -static void jsonenc_nanos(jsonenc* e, int32_t nanos) { - int digits = 9; +upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { + upb_StringView key; + uint32_t len; + UPB_ASSERT(!upb_strtable_done(i)); + key.data = upb_tabstr(str_tabent(i)->key, &len); + key.size = len; + return key; +} - if (nanos == 0) return; - if (nanos < 0 || nanos >= 1000000000) { - jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); - } +upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { + UPB_ASSERT(!upb_strtable_done(i)); + return _upb_value_val(str_tabent(i)->val.val); +} - while (nanos % 1000 == 0) { - nanos /= 1000; - digits -= 3; - } +void upb_strtable_iter_setdone(upb_strtable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; +} - jsonenc_printf(e, ".%.*" PRId32, digits, nanos); +bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, + const upb_strtable_iter* i2) { + if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index; } -static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); - int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; - int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; - int L, N, I, J, K, hour, min, sec; +/* upb_inttable ***************************************************************/ - if (seconds < -62135596800) { - jsonenc_err(e, - "error formatting timestamp as JSON: minimum acceptable value " - "is 0001-01-01T00:00:00Z"); - } else if (seconds > 253402300799) { - jsonenc_err(e, - "error formatting timestamp as JSON: maximum acceptable value " - "is 9999-12-31T23:59:59Z"); - } +/* For inttables we use a hybrid structure where small keys are kept in an + * array and large keys are put in the hash table. */ - /* Julian Day -> Y/M/D, Algorithm from: - * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for - * Processing Calendar Dates," Communications of the Association of - * Computing Machines, vol. 11 (1968), p. 657. */ - seconds += 62135596800; // Ensure seconds is positive. - L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; - N = 4 * L / 146097; - L = L - (146097 * N + 3) / 4; - I = 4000 * (L + 1) / 1461001; - L = L - 1461 * I / 4 + 31; - J = 80 * L / 2447; - K = L - 2447 * J / 80; - L = J / 11; - J = J + 2 - 12 * L; - I = 100 * (N - 49) + I + L; +static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } - sec = seconds % 60; - min = (seconds / 60) % 60; - hour = (seconds / 3600) % 24; +static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } - jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "Z\""); +static upb_tabval* mutable_array(upb_inttable* t) { + return (upb_tabval*)t->array; } -static void jsonenc_duration(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); - int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; - int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; - - if (seconds > 315576000000 || seconds < -315576000000 || - (seconds < 0) != (nanos < 0)) { - jsonenc_err(e, "bad duration"); +static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) { + if (key < t->array_size) { + return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; + } else { + upb_tabent* e = + findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); + return e ? &e->val : NULL; } +} - if (nanos < 0) { - nanos = -nanos; - } +static const upb_tabval* inttable_val_const(const upb_inttable* t, + uintptr_t key) { + return inttable_val((upb_inttable*)t, key); +} - jsonenc_printf(e, "\"%" PRId64, seconds); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "s\""); +size_t upb_inttable_count(const upb_inttable* t) { + return t->t.count + t->array_count; } -static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { - const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); +static void check(upb_inttable* t) { + UPB_UNUSED(t); +#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) + { + /* This check is very expensive (makes inserts/deletes O(N)). */ + size_t count = 0; + upb_inttable_iter i; + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { + UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); + } + UPB_ASSERT(count == upb_inttable_count(t)); + } +#endif +} - if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { - jsonenc_putstr(e, "null"); - } else { - const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e_def, val); +bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, + upb_Arena* a) { + size_t array_bytes; - if (ev) { - jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); - } else { - jsonenc_printf(e, "%" PRId32, val); - } + if (!init(&t->t, hsize_lg2, a)) return false; + /* Always make the array part at least 1 long, so that we know key 0 + * won't be in the hash part, which simplifies things. */ + t->array_size = UPB_MAX(1, asize); + t->array_count = 0; + array_bytes = t->array_size * sizeof(upb_value); + t->array = upb_Arena_Malloc(a, array_bytes); + if (!t->array) { + return false; } + memset(mutable_array(t), 0xff, array_bytes); + check(t); + return true; } -static void jsonenc_bytes(jsonenc* e, upb_StringView str) { - /* This is the regular base64, not the "web-safe" version. */ - static const char base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - const unsigned char* ptr = (unsigned char*)str.data; - const unsigned char* end = UPB_PTRADD(ptr, str.size); - char buf[4]; +bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { + return upb_inttable_sizedinit(t, 0, 4, a); +} - jsonenc_putstr(e, "\""); +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a) { + upb_tabval tabval; + tabval.val = val.val; + UPB_ASSERT( + upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ - while (end - ptr >= 3) { - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; - buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; - buf[3] = base64[ptr[2] & 0x3f]; - jsonenc_putbytes(e, buf, 4); - ptr += 3; - } + if (key < t->array_size) { + UPB_ASSERT(!upb_arrhas(t->array[key])); + t->array_count++; + mutable_array(t)[key].val = val.val; + } else { + if (isfull(&t->t)) { + /* Need to resize the hash part, but we re-use the array part. */ + size_t i; + upb_table new_table; - switch (end - ptr) { - case 2: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; - buf[2] = base64[(ptr[1] & 0xf) << 2]; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); - break; - case 1: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4)]; - buf[2] = '='; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); - break; - } + if (!init(&new_table, t->t.size_lg2 + 1, a)) { + return false; + } - jsonenc_putstr(e, "\""); -} + for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { + const upb_tabent* e = &t->t.entries[i]; + uint32_t hash; + upb_value v; -static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { - const char* ptr = str.data; - const char* end = UPB_PTRADD(ptr, str.size); + _upb_value_setval(&v, e->val.val); + hash = upb_inthash(e->key); + insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); + } - while (ptr < end) { - switch (*ptr) { - case '\n': - jsonenc_putstr(e, "\\n"); - break; - case '\r': - jsonenc_putstr(e, "\\r"); - break; - case '\t': - jsonenc_putstr(e, "\\t"); - break; - case '\"': - jsonenc_putstr(e, "\\\""); - break; - case '\f': - jsonenc_putstr(e, "\\f"); - break; - case '\b': - jsonenc_putstr(e, "\\b"); - break; - case '\\': - jsonenc_putstr(e, "\\\\"); - break; - default: - if ((uint8_t)*ptr < 0x20) { - jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); - } else { - /* This could be a non-ASCII byte. We rely on the string being valid - * UTF-8. */ - jsonenc_putbytes(e, ptr, 1); - } - break; + UPB_ASSERT(t->t.count == new_table.count); + + t->t = new_table; } - ptr++; + insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); } + check(t); + return true; } -static void jsonenc_string(jsonenc* e, upb_StringView str) { - jsonenc_putstr(e, "\""); - jsonenc_stringbody(e, str); - jsonenc_putstr(e, "\""); +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { + const upb_tabval* table_v = inttable_val_const(t, key); + if (!table_v) return false; + if (v) _upb_value_setval(v, table_v->val); + return true; } -static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { - if (val == INFINITY) { - jsonenc_putstr(e, "\"Infinity\""); - } else if (val == -INFINITY) { - jsonenc_putstr(e, "\"-Infinity\""); - } else if (val != val) { - jsonenc_putstr(e, "\"NaN\""); - } else { - return false; - } +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { + upb_tabval* table_v = inttable_val(t, key); + if (!table_v) return false; + table_v->val = val.val; return true; } -static void upb_JsonEncode_Double(jsonenc* e, double val) { - if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; - char buf[32]; - _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); - jsonenc_putstr(e, buf); +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { + bool success; + if (key < t->array_size) { + if (upb_arrhas(t->array[key])) { + upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; + t->array_count--; + if (val) { + _upb_value_setval(val, t->array[key].val); + } + mutable_array(t)[key] = empty; + success = true; + } else { + success = false; + } + } else { + success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); + } + check(t); + return success; } -static void upb_JsonEncode_Float(jsonenc* e, float val) { - if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; - char buf[32]; - _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); - jsonenc_putstr(e, buf); -} +void upb_inttable_compact(upb_inttable* t, upb_Arena* a) { + /* A power-of-two histogram of the table keys. */ + size_t counts[UPB_MAXARRSIZE + 1] = {0}; -static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); - upb_MessageValue val = upb_Message_Get(msg, val_f); - jsonenc_scalar(e, val, val_f); -} + /* The max key in each bucket. */ + uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; -static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, - upb_StringView type_url) { - /* Find last '/', if any. */ - const char* end = type_url.data + type_url.size; - const char* ptr = end; - const upb_MessageDef* ret; + upb_inttable_iter i; + size_t arr_count; + int size_lg2; + upb_inttable new_t; - if (!e->ext_pool) { - jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t key = upb_inttable_iter_key(&i); + int bucket = log2ceil(key); + max[bucket] = UPB_MAX(max[bucket], key); + counts[bucket]++; } - if (type_url.size == 0) goto badurl; + /* Find the largest power of two that satisfies the MIN_DENSITY + * definition (while actually having some keys). */ + arr_count = upb_inttable_count(t); - while (true) { - if (--ptr == type_url.data) { - /* Type URL must contain at least one '/', with host before. */ - goto badurl; - } - if (*ptr == '/') { - ptr++; + for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { + if (counts[size_lg2] == 0) { + /* We can halve again without losing any entries. */ + continue; + } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { break; } + + arr_count -= counts[size_lg2]; } - ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); + UPB_ASSERT(arr_count <= upb_inttable_count(t)); - if (!ret) { - jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + { + /* Insert all elements into new, perfectly-sized table. */ + size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ + size_t hash_count = upb_inttable_count(t) - arr_count; + size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; + int hashsize_lg2 = log2ceil(hash_size); + + upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t k = upb_inttable_iter_key(&i); + upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a); + } + UPB_ASSERT(new_t.array_size == arr_size); + UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); } + *t = new_t; +} - return ret; +/* Iteration. */ -badurl: - jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(type_url)); +static const upb_tabent* int_tabent(const upb_inttable_iter* i) { + UPB_ASSERT(!i->array_part); + return &i->t->t.entries[i->index]; } -static void jsonenc_any(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); - upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; - upb_StringView value = upb_Message_Get(msg, value_f).str_val; - const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); - const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); - upb_Arena* arena = jsonenc_arena(e); - upb_Message* any = upb_Message_New(any_m, arena); +static upb_tabval int_arrent(const upb_inttable_iter* i) { + UPB_ASSERT(i->array_part); + return i->t->array[i->index]; +} - if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != - kUpb_DecodeStatus_Ok) { - jsonenc_err(e, "Error decoding message in Any"); +void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) { + i->t = t; + i->index = -1; + i->array_part = true; + upb_inttable_next(i); +} + +void upb_inttable_next(upb_inttable_iter* iter) { + const upb_inttable* t = iter->t; + if (iter->array_part) { + while (++iter->index < t->array_size) { + if (upb_arrhas(int_arrent(iter))) { + return; + } + } + iter->array_part = false; + iter->index = begin(&t->t); + } else { + iter->index = next(&t->t, iter->index); } +} - jsonenc_putstr(e, "{\"@type\":"); - jsonenc_string(e, type_url); +bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter) { + intptr_t i = *iter; + if (i < t->array_size) { + while (++i < t->array_size) { + upb_tabval ent = t->array[i]; + if (upb_arrhas(ent)) { + *key = i; + *val = _upb_value_val(ent.val); + *iter = i; + return true; + } + } + } - if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { - /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ - jsonenc_msgfields(e, any, any_m, false); - } else { - /* Well-known type: {"@type": "...","value": } */ - jsonenc_putstr(e, ",\"value\":"); - jsonenc_msgfield(e, any, any_m); + size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + *key = ent->key; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx + t->array_size; + return true; } - jsonenc_putstr(e, "}"); + return false; } -static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { - if (*first) { - *first = false; +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { + intptr_t i = *iter; + if (i < t->array_size) { + t->array_count--; + mutable_array(t)[i].val = -1; } else { - jsonenc_putstr(e, str); + upb_tabent* ent = &t->t.entries[i - t->array_size]; + upb_tabent* prev = NULL; + + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; + } + } + + if (prev) { + prev->next = ent->next; + } + + t->t.count--; + ent->key = 0; + ent->next = NULL; } } -static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { - const char* ptr = path.data; - const char* end = ptr + path.size; +bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, + upb_value* val, intptr_t* iter) { + size_t tab_idx = next(&t->t, *iter); + if (tab_idx < upb_table_size(&t->t)) { + upb_tabent* ent = &t->t.entries[tab_idx]; + uint32_t len; + key->data = upb_tabstr(ent->key, &len); + key->size = len; + *val = _upb_value_val(ent->val.val); + *iter = tab_idx; + return true; + } - while (ptr < end) { - char ch = *ptr; + return false; +} - if (ch >= 'A' && ch <= 'Z') { - jsonenc_err(e, "Field mask element may not have upper-case letter."); - } else if (ch == '_') { - if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { - jsonenc_err(e, "Underscore must be followed by a lowercase letter."); - } - ch = *++ptr - 32; +void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { + intptr_t i = *iter; + upb_tabent* ent = &t->t.entries[i]; + upb_tabent* prev = NULL; + + // Linear search, not great. + upb_tabent* end = &t->t.entries[upb_table_size(&t->t)]; + for (upb_tabent* e = t->t.entries; e != end; e++) { + if (e->next == ent) { + prev = e; + break; } + } - jsonenc_putbytes(e, &ch, 1); - ptr++; + if (prev) { + prev->next = ent->next; } + + t->t.count--; + ent->key = 0; + ent->next = NULL; } -static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; - bool first = true; - size_t i, n = 0; +bool upb_inttable_done(const upb_inttable_iter* i) { + if (!i->t) return true; + if (i->array_part) { + return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i)); + } else { + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(int_tabent(i)); + } +} - if (paths) n = upb_Array_Size(paths); +uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) { + UPB_ASSERT(!upb_inttable_done(i)); + return i->array_part ? i->index : int_tabent(i)->key; +} - jsonenc_putstr(e, "\""); +upb_value upb_inttable_iter_value(const upb_inttable_iter* i) { + UPB_ASSERT(!upb_inttable_done(i)); + return _upb_value_val(i->array_part ? i->t->array[i->index].val + : int_tabent(i)->val.val); +} - for (i = 0; i < n; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); - } +void upb_inttable_iter_setdone(upb_inttable_iter* i) { + i->t = NULL; + i->index = SIZE_MAX; + i->array_part = false; +} - jsonenc_putstr(e, "\""); +bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, + const upb_inttable_iter* i2) { + if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true; + return i1->t == i2->t && i1->index == i2->index && + i1->array_part == i2->array_part; } -static void jsonenc_struct(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; - const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - size_t iter = kUpb_Map_Begin; - bool first = true; +/** upb/upb.c ************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include - jsonenc_putstr(e, "{"); - if (fields) { - while (upb_MapIterator_Next(fields, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(fields, iter); - upb_MessageValue val = upb_MapIterator_Value(fields, iter); +// Must be last. - jsonenc_putsep(e, ",", &first); - jsonenc_string(e, key.str_val); - jsonenc_putstr(e, ":"); - jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); - } - } +/* upb_Status *****************************************************************/ - jsonenc_putstr(e, "}"); +void upb_Status_Clear(upb_Status* status) { + if (!status) return; + status->ok = true; + status->msg[0] = '\0'; } -static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); - const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); - const upb_Array* values = upb_Message_Get(msg, values_f).array_val; - size_t i; - bool first = true; +bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } - jsonenc_putstr(e, "["); +const char* upb_Status_ErrorMessage(const upb_Status* status) { + return status->msg; +} - if (values) { - const size_t size = upb_Array_Size(values); - for (i = 0; i < size; i++) { - upb_MessageValue elem = upb_Array_Get(values, i); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { + if (!status) return; + status->ok = false; + strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} - jsonenc_putsep(e, ",", &first); - jsonenc_value(e, elem.msg_val, values_m); - } - } +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_Status_VSetErrorFormat(status, fmt, args); + va_end(args); +} - jsonenc_putstr(e, "]"); +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + if (!status) return; + status->ok = false; + vsnprintf(status->msg, sizeof(status->msg), fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; } -static void jsonenc_value(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - /* TODO(haberman): do we want a reflection method to get oneof case? */ - size_t iter = kUpb_Message_Begin; - const upb_FieldDef* f; - upb_MessageValue val; +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + size_t len; + if (!status) return; + status->ok = false; + len = strlen(status->msg); + vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} - if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { - jsonenc_err(e, "No value set in Value proto"); - } +/* upb_alloc ******************************************************************/ - switch (upb_FieldDef_Number(f)) { - case 1: - jsonenc_putstr(e, "null"); - break; - case 2: - upb_JsonEncode_Double(e, val.double_val); - break; - case 3: - jsonenc_string(e, val.str_val); - break; - case 4: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case 5: - jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; - case 6: - jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; +static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + UPB_UNUSED(alloc); + UPB_UNUSED(oldsize); + if (size == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, size); } } -static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - switch (upb_MessageDef_WellKnownType(m)) { - case kUpb_WellKnown_Unspecified: - jsonenc_msg(e, msg, m); - break; - case kUpb_WellKnown_Any: - jsonenc_any(e, msg, m); - break; - case kUpb_WellKnown_FieldMask: - jsonenc_fieldmask(e, msg, m); - break; - case kUpb_WellKnown_Duration: - jsonenc_duration(e, msg, m); - break; - case kUpb_WellKnown_Timestamp: - jsonenc_timestamp(e, msg, m); - break; - case kUpb_WellKnown_DoubleValue: - case kUpb_WellKnown_FloatValue: - case kUpb_WellKnown_Int64Value: - case kUpb_WellKnown_UInt64Value: - case kUpb_WellKnown_Int32Value: - case kUpb_WellKnown_UInt32Value: - case kUpb_WellKnown_StringValue: - case kUpb_WellKnown_BytesValue: - case kUpb_WellKnown_BoolValue: - jsonenc_wrapper(e, msg, m); - break; - case kUpb_WellKnown_Value: - jsonenc_value(e, msg, m); - break; - case kUpb_WellKnown_ListValue: - jsonenc_listvalue(e, msg, m); - break; - case kUpb_WellKnown_Struct: - jsonenc_struct(e, msg, m); - break; - } +static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { + return (uint32_t*)(cleanup_metadata & ~0x1); } -static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case kUpb_CType_Float: - upb_JsonEncode_Float(e, val.float_val); - break; - case kUpb_CType_Double: - upb_JsonEncode_Double(e, val.double_val); - break; - case kUpb_CType_Int32: - jsonenc_printf(e, "%" PRId32, val.int32_val); - break; - case kUpb_CType_UInt32: - jsonenc_printf(e, "%" PRIu32, val.uint32_val); - break; - case kUpb_CType_Int64: - jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); - break; - case kUpb_CType_UInt64: - jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); - break; - case kUpb_CType_String: - jsonenc_string(e, val.str_val); - break; - case kUpb_CType_Bytes: - jsonenc_bytes(e, val.str_val); - break; - case kUpb_CType_Enum: - jsonenc_enum(val.int32_val, f, e); - break; - case kUpb_CType_Message: - jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); - break; - } +static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { + return cleanup_metadata & 0x1; } -static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - jsonenc_putstr(e, "\""); +static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, + bool has_initial_block) { + return (uintptr_t)cleanup | has_initial_block; +} - switch (upb_FieldDef_CType(f)) { - case kUpb_CType_Bool: - jsonenc_putstr(e, val.bool_val ? "true" : "false"); - break; - case kUpb_CType_Int32: - jsonenc_printf(e, "%" PRId32, val.int32_val); - break; - case kUpb_CType_UInt32: - jsonenc_printf(e, "%" PRIu32, val.uint32_val); - break; - case kUpb_CType_Int64: - jsonenc_printf(e, "%" PRId64, val.int64_val); - break; - case kUpb_CType_UInt64: - jsonenc_printf(e, "%" PRIu64, val.uint64_val); - break; - case kUpb_CType_String: - jsonenc_stringbody(e, val.str_val); - break; - default: - UPB_UNREACHABLE(); +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; + +/* upb_Arena ******************************************************************/ + +struct mem_block { + struct mem_block* next; + uint32_t size; + uint32_t cleanups; + /* Data follows. */ +}; + +typedef struct cleanup_ent { + upb_CleanupFunc* cleanup; + void* ud; +} cleanup_ent; + +static const size_t memblock_reserve = + UPB_ALIGN_UP(sizeof(mem_block), UPB_MALLOC_ALIGN); + +static upb_Arena* arena_findroot(upb_Arena* a) { + /* Path splitting keeps time complexity down, see: + * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ + while (a->parent != a) { + upb_Arena* next = a->parent; + a->parent = next->parent; + a = next; } + return a; +} - jsonenc_putstr(e, "\":"); +static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, + size_t size) { + mem_block* block = ptr; + + /* The block is for arena |a|, but should appear in the freelist of |root|. */ + block->next = root->freelist; + block->size = (uint32_t)size; + block->cleanups = 0; + root->freelist = block; + a->last_size = block->size; + if (!root->freelist_tail) root->freelist_tail = block; + + a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); + a->head.end = UPB_PTR_AT(block, size, char); + a->cleanup_metadata = upb_cleanup_metadata( + &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); + + UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); } -static void jsonenc_array(jsonenc* e, const upb_Array* arr, - const upb_FieldDef* f) { - size_t i; - size_t size = arr ? upb_Array_Size(arr) : 0; - bool first = true; +static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { + upb_Arena* root = arena_findroot(a); + size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; + mem_block* block = upb_malloc(root->block_alloc, block_size); - jsonenc_putstr(e, "["); + if (!block) return false; + upb_Arena_addblock(a, root, block, block_size); + return true; +} - for (i = 0; i < size; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_scalar(e, upb_Array_Get(arr, i), f); - } +void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { + if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= size); + return upb_Arena_Malloc(a, size); +} - jsonenc_putstr(e, "]"); +static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ + return upb_Arena_Realloc(a, ptr, oldsize, size); } -static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { - const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); - size_t iter = kUpb_Map_Begin; - bool first = true; +/* Public Arena API ***********************************************************/ - jsonenc_putstr(e, "{"); +upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { + const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; + upb_Arena* a; - if (map) { - while (upb_MapIterator_Next(map, &iter)) { - jsonenc_putsep(e, ",", &first); - jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); - jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); - } + /* We need to malloc the initial block. */ + n = first_block_overhead + 256; + if (!alloc || !(mem = upb_malloc(alloc, n))) { + return NULL; } - jsonenc_putstr(e, "}"); -} + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + n -= sizeof(*a); -static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, - upb_MessageValue val, bool* first) { - const char* name; + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->freelist = NULL; + a->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, false); - jsonenc_putsep(e, ",", first); + upb_Arena_addblock(a, a, mem, n); - if (upb_FieldDef_IsExtension(f)) { - // TODO: For MessageSet, I would have expected this to print the message - // name here, but Python doesn't appear to do this. We should do more - // research here about what various implementations do. - jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); - } else { - if (e->options & upb_JsonEncode_UseProtoNames) { - name = upb_FieldDef_Name(f); - } else { - name = upb_FieldDef_JsonName(f); - } - jsonenc_printf(e, "\"%s\":", name); + return a; +} + +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { + upb_Arena* a; + + if (n) { + /* Align initial pointer up so that we return properly-aligned pointers. */ + void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, UPB_MALLOC_ALIGN); + size_t delta = (uintptr_t)aligned - (uintptr_t)mem; + n = delta <= n ? n - delta : 0; + mem = aligned; } - if (upb_FieldDef_IsMap(f)) { - jsonenc_map(e, val.map_val, f); - } else if (upb_FieldDef_IsRepeated(f)) { - jsonenc_array(e, val.array_val, f); - } else { - jsonenc_scalar(e, val, f); + /* Round block size down to alignof(*a) since we will allocate the arena + * itself at the end. */ + n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); + + if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { + return arena_initslow(mem, n, alloc); } + + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->last_size = UPB_MAX(128, n); + a->head.ptr = mem; + a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); + a->freelist = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, true); + + return a; } -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first) { - upb_MessageValue val; - const upb_FieldDef* f; +static void arena_dofree(upb_Arena* a) { + mem_block* block = a->freelist; + UPB_ASSERT(a->parent == a); + UPB_ASSERT(a->refcount == 0); - if (e->options & upb_JsonEncode_EmitDefaults) { - /* Iterate over all fields. */ - int i = 0; - int n = upb_MessageDef_FieldCount(m); - for (i = 0; i < n; i++) { - f = upb_MessageDef_Field(m, i); - if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { - jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first); + while (block) { + /* Load first since we are deleting block. */ + mem_block* next = block->next; + + if (block->cleanups > 0) { + cleanup_ent* end = UPB_PTR_AT(block, block->size, void); + cleanup_ent* ptr = end - block->cleanups; + + for (; ptr < end; ptr++) { + ptr->cleanup(ptr->ud); } } - } else { - /* Iterate over non-empty fields. */ - size_t iter = kUpb_Message_Begin; - while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { - jsonenc_fieldval(e, f, val, &first); - } + + upb_free(a->block_alloc, block); + block = next; } } -static void jsonenc_msg(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { - jsonenc_putstr(e, "{"); - jsonenc_msgfields(e, msg, m, true); - jsonenc_putstr(e, "}"); +void upb_Arena_Free(upb_Arena* a) { + a = arena_findroot(a); + if (--a->refcount == 0) arena_dofree(a); } -static size_t jsonenc_nullz(jsonenc* e, size_t size) { - size_t ret = e->ptr - e->buf + e->overflow; +bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { + cleanup_ent* ent; + uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); - if (size > 0) { - if (e->ptr == e->end) e->ptr--; - *e->ptr = '\0'; + if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { + if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); + cleanups = upb_cleanup_pointer(a->cleanup_metadata); } - return ret; + a->head.end -= sizeof(cleanup_ent); + ent = (cleanup_ent*)a->head.end; + (*cleanups)++; + UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); + + ent->cleanup = func; + ent->ud = ud; + + return true; } -size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, - const upb_DefPool* ext_pool, int options, char* buf, - size_t size, upb_Status* status) { - jsonenc e; +bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { + upb_Arena* r1 = arena_findroot(a1); + upb_Arena* r2 = arena_findroot(a2); - e.buf = buf; - e.ptr = buf; - e.end = UPB_PTRADD(buf, size); - e.overflow = 0; - e.options = options; - e.ext_pool = ext_pool; - e.status = status; - e.arena = NULL; + if (r1 == r2) return true; /* Already fused. */ - if (setjmp(e.err)) return -1; + /* Do not fuse initial blocks since we cannot lifetime extend them. */ + if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; + if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; - jsonenc_msgfield(&e, msg, m); - if (e.arena) upb_Arena_Free(e.arena); - return jsonenc_nullz(&e, size); + /* Only allow fuse with a common allocator */ + if (r1->block_alloc != r2->block_alloc) return false; + + /* We want to join the smaller tree to the larger tree. + * So swap first if they are backwards. */ + if (r1->refcount < r2->refcount) { + upb_Arena* tmp = r1; + r1 = r2; + r2 = tmp; + } + + /* r1 takes over r2's freelist and refcount. */ + r1->refcount += r2->refcount; + if (r2->freelist_tail) { + UPB_ASSERT(r2->freelist_tail->next == NULL); + r2->freelist_tail->next = r1->freelist; + r1->freelist = r2->freelist; + } + r2->parent = r1; + return true; +} + +/* Miscellaneous utilities ****************************************************/ + +static void upb_FixLocale(char* p) { + /* printf() is dependent on locales; sadly there is no easy and portable way + * to avoid this. This little post-processing step will translate 1,2 -> 1.2 + * since JSON needs the latter. Arguably a hack, but it is simple and the + * alternatives are far more complicated, platform-dependent, and/or larger + * in code size. */ + for (; *p; p++) { + if (*p == ',') *p = '.'; + } +} + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + snprintf(buf, size, "%.*g", DBL_DIG, val); + if (strtod(buf, NULL) != val) { + snprintf(buf, size, "%.*g", DBL_DIG + 2, val); + assert(strtod(buf, NULL) == val); + } + upb_FixLocale(buf); +} + +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { + assert(size >= kUpb_RoundTripBufferSize); + snprintf(buf, size, "%.*g", FLT_DIG, val); + if (strtof(buf, NULL) != val) { + snprintf(buf, size, "%.*g", FLT_DIG + 3, val); + assert(strtof(buf, NULL) == val); + } + upb_FixLocale(buf); } /** upb/port_undef.inc ************************************************************/ @@ -11090,6 +12504,7 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_MALLOC_ALIGN #undef UPB_LIKELY #undef UPB_UNLIKELY #undef UPB_FORCEINLINE diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index e57eb0edad..54865a19cd 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -91,21 +91,22 @@ #define UPB_INLINE static #endif +#define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) -/* Hints to the compiler about likely/unlikely branches. */ +// Hints to the compiler about likely/unlikely branches. #if defined (__GNUC__) || defined(__clang__) -#define UPB_LIKELY(x) __builtin_expect((x),1) -#define UPB_UNLIKELY(x) __builtin_expect((x),0) +#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) +#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) #else #define UPB_LIKELY(x) (x) #define UPB_UNLIKELY(x) (x) #endif -/* Macros for function attributes on compilers that support them. */ +// Macros for function attributes on compilers that support them. #ifdef __GNUC__ #define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) #define UPB_NOINLINE __attribute__((noinline)) @@ -128,8 +129,7 @@ #define UPB_UNUSED(var) (void)var -/* UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. - */ +// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. #ifdef NDEBUG #ifdef __GNUC__ #define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() @@ -263,13 +263,37 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 #endif -/** upb/decode.h ************************************************************/ +/** upb/collections.h ************************************************************/ +#ifndef UPB_COLLECTIONS_H_ +#define UPB_COLLECTIONS_H_ + + +/** google/protobuf/descriptor.upb.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input + * file: + * + * google/protobuf/descriptor.proto + * + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ + + +/** upb/msg_internal.h ************************************************************/ /* - * upb_decode: parsing into a upb_Message using a upb_MiniTable. - */ +** Our memory representation for parsing tables and messages themselves. +** Functions in this file are used by generated code and possibly reflection. +** +** The definitions in this file are internal to upb. +**/ -#ifndef UPB_DECODE_H_ -#define UPB_DECODE_H_ +#ifndef UPB_MSG_INT_H_ +#define UPB_MSG_INT_H_ + +#include +#include +#include /** upb/msg.h ************************************************************/ @@ -458,18 +482,14 @@ UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) { return (size_t)(h->end - h->ptr); } -UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { +UPB_INLINE void* _upb_Arena_FastMalloc(upb_Arena* a, size_t size) { _upb_ArenaHead* h = (_upb_ArenaHead*)a; - void* ret; - size = UPB_ALIGN_MALLOC(size); - - if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { - return _upb_Arena_SlowMalloc(a, size); - } + void* ret = h->ptr; + UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret); + UPB_ASSERT(UPB_ALIGN_MALLOC(size) == size); + UPB_UNPOISON_MEMORY_REGION(ret, size); - ret = h->ptr; h->ptr += size; - UPB_UNPOISON_MEMORY_REGION(ret, size); #if UPB_ASAN { @@ -485,6 +505,16 @@ UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { return ret; } +UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { + size = UPB_ALIGN_MALLOC(size); + + if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { + return _upb_Arena_SlowMalloc(a, size); + } + + return _upb_Arena_FastMalloc(a, size); +} + // Shrinks the last alloc from arena. // REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena. // We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if @@ -504,17 +534,22 @@ UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize, _upb_ArenaHead* h = (_upb_ArenaHead*)a; oldsize = UPB_ALIGN_MALLOC(oldsize); size = UPB_ALIGN_MALLOC(size); - if (size <= oldsize) { - if ((char*)ptr + oldsize == h->ptr) { - upb_Arena_ShrinkLast(a, ptr, oldsize, size); + bool is_most_recent_alloc = (uintptr_t)ptr + oldsize == (uintptr_t)h->ptr; + + if (is_most_recent_alloc) { + ptrdiff_t diff = size - oldsize; + if ((ptrdiff_t)_upb_ArenaHas(a) >= diff) { + h->ptr += diff; + return ptr; } + } else if (size <= oldsize) { return ptr; } void* ret = upb_Arena_Malloc(a, size); if (ret && oldsize > 0) { - memcpy(ret, ptr, oldsize); + memcpy(ret, ptr, UPB_MIN(oldsize, size)); } return ret; @@ -602,8 +637,8 @@ UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { if (_upb_IsLittleEndian()) { return val; } else { - return ((uint64_t)_upb_BigEndian_Swap32(val) << 32) | - _upb_BigEndian_Swap32(val >> 32); + return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | + _upb_BigEndian_Swap32((uint32_t)(val >> 32)); } } @@ -631,8 +666,7 @@ UPB_INLINE int _upb_Log2CeilingSize(int x) { return 1 << _upb_Log2Ceiling(x); } extern "C" { #endif -/** upb_Message - * *******************************************************************/ +/** upb_Message ***************************************************************/ typedef void upb_Message; @@ -701,92 +735,6 @@ upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); #endif /* UPB_MSG_INT_H_ */ -/* Must be last. */ - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* If set, strings will alias the input buffer instead of copying into the - * arena. */ - kUpb_DecodeOption_AliasString = 1, - - /* If set, the parse will return failure if any message is missing any - * required fields when the message data ends. The parse will still continue, - * and the failure will only be reported at the end. - * - * IMPORTANT CAVEATS: - * - * 1. This can throw a false positive failure if an incomplete message is seen - * on the wire but is later completed when the sub-message occurs again. - * For this reason, a second pass is required to verify a failure, to be - * truly robust. - * - * 2. This can return a false success if you are decoding into a message that - * already has some sub-message fields present. If the sub-message does - * not occur in the binary payload, we will never visit it and discover the - * incomplete sub-message. For this reason, this check is only useful for - * implemting ParseFromString() semantics. For MergeFromString(), a - * post-parse validation step will always be necessary. */ - kUpb_DecodeOption_CheckRequired = 2, -}; - -#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) - -typedef enum { - kUpb_DecodeStatus_Ok = 0, - kUpb_DecodeStatus_Malformed = 1, // Wire format was corrupt - kUpb_DecodeStatus_OutOfMemory = 2, // Arena alloc failed - kUpb_DecodeStatus_BadUtf8 = 3, // String field had bad UTF-8 - kUpb_DecodeStatus_MaxDepthExceeded = 4, // Exceeded UPB_DECODE_MAXDEPTH - - // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise - // succeeded. - kUpb_DecodeStatus_MissingRequired = 5, -} upb_DecodeStatus; - -upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, - const upb_MiniTable* l, - const upb_ExtensionRegistry* extreg, int options, - upb_Arena* arena); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_DECODE_H_ */ - -/** upb/decode_internal.h ************************************************************/ -/* - * Internal implementation details of the decoder that are shared between - * decode.c and decode_fast.c. - */ - -#ifndef UPB_DECODE_INT_H_ -#define UPB_DECODE_INT_H_ - -#include - -#include "third_party/utf8_range/utf8_range.h" - -/** upb/msg_internal.h ************************************************************/ -/* -** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possibly reflection. -** -** The definitions in this file are internal to upb. -**/ - -#ifndef UPB_MSG_INT_H_ -#define UPB_MSG_INT_H_ - -#include -#include -#include - - /** upb/table_internal.h ************************************************************/ /* * upb_table @@ -1172,20 +1120,23 @@ typedef struct { uint32_t number; uint16_t offset; int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index - uint16_t submsg_index; // undefined if descriptortype != MESSAGE/GROUP/ENUM + uint16_t submsg_index; // kUpb_NoSub if descriptortype != MESSAGE/GROUP/ENUM uint8_t descriptortype; uint8_t mode; /* upb_FieldMode | upb_LabelFlags | (upb_FieldRep << kUpb_FieldRep_Shift) */ } upb_MiniTable_Field; +#define kUpb_NoSub ((uint16_t)-1) + typedef enum { kUpb_FieldMode_Map = 0, kUpb_FieldMode_Array = 1, kUpb_FieldMode_Scalar = 2, - - kUpb_FieldMode_Mask = 3, /* Mask to isolate the mode from upb_FieldRep. */ } upb_FieldMode; +// Mask to isolate the upb_FieldMode from field.mode. +#define kUpb_FieldMode_Mask 3 + /* Extra flags on the mode field. */ typedef enum { kUpb_LabelFlags_IsPacked = 4, @@ -1236,18 +1187,6 @@ typedef struct { int value_count; } upb_MiniTable_Enum; -UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, - int32_t val) { - uint32_t uval = (uint32_t)val; - if (uval < 64) return e->mask & (1 << uval); - // OPT: binary search long lists? - int n = e->value_count; - for (int i = 0; i < n; i++) { - if (e->values[i] == val) return true; - } - return false; -} - typedef union { const struct upb_MiniTable* submsg; const upb_MiniTable_Enum* subenum; @@ -1269,7 +1208,7 @@ typedef enum { * message MessageSet { * repeated group Item = 1 { * required int32 type_id = 2; - * required string message = 3; + * required bytes message = 3; * } * } */ @@ -1384,7 +1323,7 @@ UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) { UPB_INLINE upb_Message* _upb_Message_New_inl(const upb_MiniTable* l, upb_Arena* a) { size_t size = upb_msg_sizeof(l); - void* mem = upb_Arena_Malloc(a, size); + void* mem = upb_Arena_Malloc(a, size + sizeof(upb_Message_Internal)); upb_Message* msg; if (UPB_UNLIKELY(!mem)) return NULL; msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message); @@ -1433,7 +1372,7 @@ typedef struct { /* Adds the given extension data to the given message. |ext| is copied into the * message instance. This logically replaces any previously-added extension with * this number */ -upb_Message_Extension* _upb_Message_Getorcreateext( +upb_Message_Extension* _upb_Message_GetOrCreateExtension( upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena); /* Returns an array of extensions for this message. Note: the array is @@ -1547,8 +1486,8 @@ UPB_INLINE uintptr_t _upb_tag_arrptr(void* ptr, int elem_size_lg2) { UPB_INLINE upb_Array* _upb_Array_New(upb_Arena* a, size_t init_size, int elem_size_lg2) { - const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_Array), 8); - const size_t bytes = sizeof(upb_Array) + (init_size << elem_size_lg2); + const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_Array), UPB_MALLOC_ALIGN); + const size_t bytes = arr_size + (init_size << elem_size_lg2); upb_Array* arr = (upb_Array*)upb_Arena_Malloc(a, bytes); if (!arr) return NULL; arr->data = _upb_tag_arrptr(UPB_PTR_AT(arr, arr_size, void), elem_size_lg2); @@ -1579,6 +1518,10 @@ UPB_INLINE bool _upb_Array_Resize(upb_Array* arr, size_t size, return true; } +UPB_INLINE void _upb_array_detach(const void* msg, size_t ofs) { + *UPB_PTR_AT(msg, ofs, upb_Array*) = NULL; +} + UPB_INLINE const void* _upb_array_accessor(const void* msg, size_t ofs, size_t* size) { const upb_Array* arr = *UPB_PTR_AT(msg, ofs, const upb_Array*); @@ -1772,15 +1715,31 @@ UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { return (void*)str_tabent(&it); } -UPB_INLINE bool _upb_Map_Set(upb_Map* map, const void* key, size_t key_size, - void* val, size_t val_size, upb_Arena* a) { +typedef enum { + // LINT.IfChange + _kUpb_MapInsertStatus_Inserted = 0, + _kUpb_MapInsertStatus_Replaced = 1, + _kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/collections.h) +} _upb_MapInsertStatus; + +UPB_INLINE _upb_MapInsertStatus _upb_Map_Insert(upb_Map* map, const void* key, + size_t key_size, void* val, + size_t val_size, upb_Arena* a) { upb_StringView strkey = _upb_map_tokey(key, key_size); upb_value tabval = {0}; - if (!_upb_map_tovalue(val, val_size, &tabval, a)) return false; + if (!_upb_map_tovalue(val, val_size, &tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); - return upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a); + bool removed = + upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); + if (!upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } + return removed ? _kUpb_MapInsertStatus_Replaced + : _kUpb_MapInsertStatus_Inserted; } UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, @@ -1822,7 +1781,8 @@ UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, if (!*map) { *map = _upb_Map_New(arena, key_size, val_size); } - return _upb_Map_Set(*map, key, key_size, val, val_size, arena); + return _upb_Map_Insert(*map, key, key_size, val, val_size, arena) != + _kUpb_MapInsertStatus_OutOfMemory; } UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs, @@ -1922,258 +1882,71 @@ UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, #endif /* UPB_MSG_INT_H_ */ -/** upb/upb_internal.h ************************************************************/ -#ifndef UPB_INT_H_ -#define UPB_INT_H_ +/** upb/decode.h ************************************************************/ +/* + * upb_decode: parsing into a upb_Message using a upb_MiniTable. + */ +#ifndef UPB_DECODE_H_ +#define UPB_DECODE_H_ -struct mem_block; -typedef struct mem_block mem_block; -struct upb_Arena { - _upb_ArenaHead head; - /* Stores cleanup metadata for this arena. - * - a pointer to the current cleanup counter. - * - a boolean indicating if there is an unowned initial block. */ - uintptr_t cleanup_metadata; +/* Must be last. */ - /* Allocator to allocate arena blocks. We are responsible for freeing these - * when we are destroyed. */ - upb_alloc* block_alloc; - uint32_t last_size; +#ifdef __cplusplus +extern "C" { +#endif - /* When multiple arenas are fused together, each arena points to a parent - * arena (root points to itself). The root tracks how many live arenas - * reference it. */ - uint32_t refcount; /* Only used when a->parent == a */ - struct upb_Arena* parent; +enum { + /* If set, strings will alias the input buffer instead of copying into the + * arena. */ + kUpb_DecodeOption_AliasString = 1, - /* Linked list of blocks to free/cleanup. */ - mem_block *freelist, *freelist_tail; + /* If set, the parse will return failure if any message is missing any + * required fields when the message data ends. The parse will still continue, + * and the failure will only be reported at the end. + * + * IMPORTANT CAVEATS: + * + * 1. This can throw a false positive failure if an incomplete message is seen + * on the wire but is later completed when the sub-message occurs again. + * For this reason, a second pass is required to verify a failure, to be + * truly robust. + * + * 2. This can return a false success if you are decoding into a message that + * already has some sub-message fields present. If the sub-message does + * not occur in the binary payload, we will never visit it and discover the + * incomplete sub-message. For this reason, this check is only useful for + * implemting ParseFromString() semantics. For MergeFromString(), a + * post-parse validation step will always be necessary. */ + kUpb_DecodeOption_CheckRequired = 2, }; -// Encodes a float or double that is round-trippable, but as short as possible. -// These routines are not fully optimal (not guaranteed to be shortest), but are -// short-ish and match the implementation that has been used in protobuf since -// the beginning. -// -// The given buffer size must be at least kUpb_RoundTripBufferSize. -enum { kUpb_RoundTripBufferSize = 32 }; -void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); -void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); +#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) -#endif /* UPB_INT_H_ */ +typedef enum { + kUpb_DecodeStatus_Ok = 0, + kUpb_DecodeStatus_Malformed = 1, // Wire format was corrupt + kUpb_DecodeStatus_OutOfMemory = 2, // Arena alloc failed + kUpb_DecodeStatus_BadUtf8 = 3, // String field had bad UTF-8 + kUpb_DecodeStatus_MaxDepthExceeded = 4, // Exceeded UPB_DECODE_MAXDEPTH -/* Must be last. */ + // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise + // succeeded. + kUpb_DecodeStatus_MissingRequired = 5, +} upb_DecodeStatus; -#define DECODE_NOGROUP (uint32_t) - 1 +upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, + const upb_MiniTable* l, + const upb_ExtensionRegistry* extreg, int options, + upb_Arena* arena); -typedef struct upb_Decoder { - const char* end; /* Can read up to 16 bytes slop beyond this. */ - const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */ - upb_Message* unknown_msg; /* If non-NULL, add unknown data at buffer flip. */ - const char* unknown; /* Start of unknown data. */ - const upb_ExtensionRegistry* - extreg; /* For looking up extensions during the parse. */ - int limit; /* Submessage limit relative to end. */ - int depth; /* Tracks recursion depth to bound stack usage. */ - uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ - uint16_t options; - bool missing_required; - char patch[32]; - upb_Arena arena; - jmp_buf err; +#ifdef __cplusplus +} /* extern "C" */ +#endif -#ifndef NDEBUG - const char* debug_tagstart; - const char* debug_valstart; -#endif -} upb_Decoder; - -/* Error function that will abort decoding with longjmp(). We can't declare this - * UPB_NORETURN, even though it is appropriate, because if we do then compilers - * will "helpfully" refuse to tailcall to it - * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal - * of our optimizations. That is also why we must declare it in a separate file, - * otherwise the compiler will see that it calls longjmp() and deduce that it is - * noreturn. */ -const char* fastdecode_err(upb_Decoder* d, int status); - -extern const uint8_t upb_utf8_offsets[]; - -UPB_INLINE -bool decode_verifyutf8_inl(const char* ptr, int len) { - const char* end = ptr + len; - - // Check 8 bytes at a time for any non-ASCII char. - while (end - ptr >= 8) { - uint64_t data; - memcpy(&data, ptr, 8); - if (data & 0x8080808080808080) goto non_ascii; - ptr += 8; - } - - // Check one byte at a time for non-ASCII. - while (ptr < end) { - if (*ptr & 0x80) goto non_ascii; - ptr++; - } - - return true; - -non_ascii: - return utf8_range2((const unsigned char*)ptr, end - ptr) == 0; -} - -const char* decode_checkrequired(upb_Decoder* d, const char* ptr, - const upb_Message* msg, - const upb_MiniTable* l); - -/* x86-64 pointers always have the high 16 bits matching. So we can shift - * left 8 and right 8 without loss of information. */ -UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) { - return ((intptr_t)tablep << 8) | tablep->table_mask; -} - -UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) { - return (const upb_MiniTable*)(table >> 8); -} - -UPB_INLINE -const char* decode_isdonefallback_inl(upb_Decoder* d, const char* ptr, - int overrun, int* status) { - if (overrun < d->limit) { - /* Need to copy remaining data into patch buffer. */ - UPB_ASSERT(overrun < 16); - if (d->unknown_msg) { - if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown, - &d->arena)) { - *status = kUpb_DecodeStatus_OutOfMemory; - return NULL; - } - d->unknown = &d->patch[0] + overrun; - } - memset(d->patch + 16, 0, 16); - memcpy(d->patch, d->end, 16); - ptr = &d->patch[0] + overrun; - d->end = &d->patch[16]; - d->limit -= 16; - d->limit_ptr = d->end + d->limit; - d->options &= ~kUpb_DecodeOption_AliasString; - UPB_ASSERT(ptr < d->limit_ptr); - return ptr; - } else { - *status = kUpb_DecodeStatus_Malformed; - return NULL; - } -} - -const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, int overrun); - -UPB_INLINE -bool decode_isdone(upb_Decoder* d, const char** ptr) { - int overrun = *ptr - d->end; - if (UPB_LIKELY(*ptr < d->limit_ptr)) { - return false; - } else if (UPB_LIKELY(overrun == d->limit)) { - return true; - } else { - *ptr = decode_isdonefallback(d, *ptr, overrun); - return false; - } -} - -#if UPB_FASTTABLE -UPB_INLINE -const char* fastdecode_tagdispatch(upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t tag) { - const upb_MiniTable* table_p = decode_totablep(table); - uint8_t mask = table; - uint64_t data; - size_t idx = tag & mask; - UPB_ASSUME((idx & 7) == 0); - idx >>= 3; - data = table_p->fasttable[idx].field_data ^ tag; - UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, - hasbits, data); -} -#endif - -UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) { - uint16_t tag; - memcpy(&tag, ptr, 2); - return tag; -} - -UPB_INLINE void decode_checklimit(upb_Decoder* d) { - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); -} - -UPB_INLINE int decode_pushlimit(upb_Decoder* d, const char* ptr, int size) { - int limit = size + (int)(ptr - d->end); - int delta = d->limit - limit; - decode_checklimit(d); - d->limit = limit; - d->limit_ptr = d->end + UPB_MIN(0, limit); - decode_checklimit(d); - return delta; -} - -UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr, - int saved_delta) { - UPB_ASSERT(ptr - d->end == d->limit); - decode_checklimit(d); - d->limit += saved_delta; - d->limit_ptr = d->end + UPB_MIN(0, d->limit); - decode_checklimit(d); -} - - -#endif /* UPB_DECODE_INT_H_ */ - -/** upb/encode.h ************************************************************/ -/* - * upb_Encode: parsing into a upb_Message using a upb_MiniTable. - */ - -#ifndef UPB_ENCODE_H_ -#define UPB_ENCODE_H_ - - -/* Must be last. */ - -#ifdef __cplusplus -extern "C" { -#endif -enum { - /* If set, the results of serializing will be deterministic across all - * instances of this binary. There are no guarantees across different - * binary builds. - * - * If your proto contains maps, the encoder will need to malloc()/free() - * memory during encode. */ - kUpb_Encode_Deterministic = 1, - - /* When set, unknown fields are not printed. */ - kUpb_Encode_SkipUnknown = 2, - - /* When set, the encode will fail if any required fields are missing. */ - kUpb_Encode_CheckRequired = 4, -}; - -#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) - -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size); - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_ENCODE_H_ */ +#endif /* UPB_DECODE_H_ */ /** upb/decode_fast.h ************************************************************/ // These are the specialized field parser functions for the fast parser. @@ -2302,17 +2075,48 @@ TAGBYTES(r) #endif /* UPB_DECODE_FAST_H_ */ -/** google/protobuf/descriptor.upb.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ +/** upb/encode.h ************************************************************/ +/* + * upb_Encode: parsing into a upb_Message using a upb_MiniTable. + */ + +#ifndef UPB_ENCODE_H_ +#define UPB_ENCODE_H_ + + +/* Must be last. */ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* If set, the results of serializing will be deterministic across all + * instances of this binary. There are no guarantees across different + * binary builds. + * + * If your proto contains maps, the encoder will need to malloc()/free() + * memory during encode. */ + kUpb_Encode_Deterministic = 1, + + /* When set, unknown fields are not printed. */ + kUpb_Encode_SkipUnknown = 2, + + /* When set, the encode will fail if any required fields are missing. */ + kUpb_Encode_CheckRequired = 4, +}; + +#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) + +char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, + upb_Arena* arena, size_t* size); -#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ -#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_ENCODE_H_ */ #ifdef __cplusplus @@ -2494,6 +2298,9 @@ UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_pro UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } +UPB_INLINE void google_protobuf_FileDescriptorSet_clear_file(const google_protobuf_FileDescriptorSet* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet* msg, size_t* len) { return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } @@ -2545,65 +2352,104 @@ UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize_ex(const google_p UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_name(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_package(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); +} UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_message_type(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); } UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(44, 88)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_enum_type(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); } UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_protobuf_FileDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(48, 96)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_service(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(32, 64)); } UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); + return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 104)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_extension(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(36, 72)); } UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_options(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 80), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_FileOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(40, 80), const google_protobuf_FileOptions*); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(44, 88), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_SourceCodeInfo*); + return *UPB_PTR_AT(msg, UPB_SIZE(44, 88), const google_protobuf_SourceCodeInfo*); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_public_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(48, 96)); } UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(56, 112), len); + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); +} +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_weak_dependency(const google_protobuf_FileDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(52, 104)); } UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(60, 120), len); + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_FileDescriptorProto_clear_syntax(const google_protobuf_FileDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { @@ -2615,65 +2461,65 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_ *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; } UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); + return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena); + return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(3, 4), arena); } UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val, arena); + return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(3, 4), &val, arena); } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); + return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); + return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); + return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); } UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(48, 96), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(52, 104), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto *msg, google_protobuf_FileOptions* value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_FileOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(40, 80), google_protobuf_FileOptions*) = value; } UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg); @@ -2686,7 +2532,7 @@ UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorPro } UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto *msg, google_protobuf_SourceCodeInfo* value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_SourceCodeInfo*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(44, 88), google_protobuf_SourceCodeInfo*) = value; } UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg); @@ -2698,26 +2544,26 @@ UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptor return sub; } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 112), len); + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 112), len, 2, arena); + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, 2, arena); } UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 112), 2, &val, arena); + return _upb_Array_Append_accessor2(msg, UPB_SIZE(48, 96), 2, &val, arena); } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(60, 120), len); + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); } UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(60, 120), len, 2, arena); + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, 2, arena); } UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(60, 120), 2, &val, arena); + return _upb_Array_Append_accessor2(msg, UPB_SIZE(52, 104), 2, &val, arena); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView) = value; } /* google.protobuf.DescriptorProto */ @@ -2754,57 +2600,88 @@ UPB_INLINE char* google_protobuf_DescriptorProto_serialize_ex(const google_proto UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_name(const google_protobuf_DescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_field(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); } UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_nested_type(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(16, 32)); } UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_enum_type(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_enum_type(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); } UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension_range(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); } UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); + return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE void google_protobuf_DescriptorProto_clear_extension(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); } UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto* msg, size_t* len) { - return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_options(const google_protobuf_DescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_MessageOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_MessageOptions*); } UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_oneof_decl(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(36, 72)); +} UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto* msg, size_t* len) { return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_range(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(40, 80)); +} UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto* msg, size_t* len) { return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } +UPB_INLINE void google_protobuf_DescriptorProto_clear_reserved_name(const google_protobuf_DescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(44, 88)); +} UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto* msg, size_t* len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } @@ -2814,68 +2691,68 @@ UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_Descrip *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); + return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); + return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); + return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto* msg, size_t* len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); + return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_DescriptorProto_set_options(google_protobuf_DescriptorProto *msg, google_protobuf_MessageOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_MessageOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_MessageOptions*) = value; } UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg); @@ -2954,18 +2831,29 @@ UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize_ex(con UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const google_protobuf_ExtensionRangeOptions*); } @@ -3026,12 +2914,20 @@ UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize_ex(cons UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_clear_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -3079,6 +2975,9 @@ UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } +UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } @@ -3130,66 +3029,109 @@ UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize_ex(const google_ UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_extendee(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_number(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); + return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_label(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto* msg) { - return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; + return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 5); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto* msg) { - return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1; + return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) : 1; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_default_value(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 7); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_options(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(56, 88), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(64, 104), const google_protobuf_FieldOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), const google_protobuf_FieldOptions*); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 9); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = 0; + _upb_clearhas(msg, 9); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_json_name(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 10); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 11); } +UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool) = 0; + _upb_clearhas(msg, 11); +} UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool); } @@ -3204,15 +3146,15 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobu } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, int32_t value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 6); @@ -3224,7 +3166,7 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_pr } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) { _upb_sethas(msg, 8); - *UPB_PTR_AT(msg, UPB_SIZE(64, 104), google_protobuf_FieldOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(56, 88), google_protobuf_FieldOptions*) = value; } UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg); @@ -3241,7 +3183,7 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_prot } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 10); - *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_StringView) = value; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { _upb_sethas(msg, 11); @@ -3282,12 +3224,19 @@ UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize_ex(const google_ UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_name(const google_protobuf_OneofDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_options(const google_protobuf_OneofDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_OneofOptions*); } @@ -3344,27 +3293,43 @@ UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize_ex(const google_p UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_name(const google_protobuf_EnumDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_value(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); } UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { - return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); + return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_options(const google_protobuf_EnumDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_EnumOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const google_protobuf_EnumOptions*); } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 40)); +} UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_reserved_name(const google_protobuf_EnumDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(24, 48)); +} UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } @@ -3374,20 +3339,20 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_Enu *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto* msg, size_t* len) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); + return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_EnumDescriptorProto *msg, google_protobuf_EnumOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_EnumOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), google_protobuf_EnumOptions*) = value; } UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg); @@ -3454,12 +3419,20 @@ UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_clear_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -3507,18 +3480,29 @@ UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize_ex(const goo UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_name(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView); } UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_number(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_options(const google_protobuf_EnumValueDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const google_protobuf_EnumValueOptions*); } @@ -3579,20 +3563,30 @@ UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize_ex(const googl UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_name(const google_protobuf_ServiceDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 24)); +} +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_method(const google_protobuf_ServiceDescriptorProto* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 24)); } UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto* msg, size_t* len) { - return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); + return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_options(const google_protobuf_ServiceDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_ServiceOptions*); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), const google_protobuf_ServiceOptions*); } UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_StringView value) { @@ -3600,20 +3594,20 @@ UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto* msg, size_t* len) { - return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); + return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 24), len); } UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 24), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options(google_protobuf_ServiceDescriptorProto *msg, google_protobuf_ServiceOptions* value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_ServiceOptions*) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), google_protobuf_ServiceOptions*) = value; } UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg); @@ -3659,36 +3653,59 @@ UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize_ex(const google UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_name(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_input_type(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_output_type(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 3); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_options(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const upb_Message*) = NULL; +} UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_MethodOptions*); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 5); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } @@ -3761,126 +3778,209 @@ UPB_INLINE char* google_protobuf_FileOptions_serialize_ex(const google_protobuf_ UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_outer_classname(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FileOptions_clear_optimize_for(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_optimize_for(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; } UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_multiple_files(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_FileOptions_clear_go_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_FileOptions_clear_cc_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = 0; + _upb_clearhas(msg, 7); +} UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE void google_protobuf_FileOptions_clear_py_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool) = 0; + _upb_clearhas(msg, 8); +} UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 9); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = 0; + _upb_clearhas(msg, 9); +} UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE void google_protobuf_FileOptions_clear_deprecated(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = 0; + _upb_clearhas(msg, 10); +} UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 11); } +UPB_INLINE void google_protobuf_FileOptions_clear_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = 0; + _upb_clearhas(msg, 11); +} UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 12); } +UPB_INLINE void google_protobuf_FileOptions_clear_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = 0; + _upb_clearhas(msg, 12); +} UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_cc_enable_arenas(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) : true; } UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 13); } +UPB_INLINE void google_protobuf_FileOptions_clear_objc_class_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 13); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 14); } +UPB_INLINE void google_protobuf_FileOptions_clear_csharp_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 14); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 15); } +UPB_INLINE void google_protobuf_FileOptions_clear_swift_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 15); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 16); } +UPB_INLINE void google_protobuf_FileOptions_clear_php_class_prefix(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 16); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 17); } +UPB_INLINE void google_protobuf_FileOptions_clear_php_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 17); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 18); } +UPB_INLINE void google_protobuf_FileOptions_clear_php_generic_services(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = 0; + _upb_clearhas(msg, 18); +} UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); } UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 19); } +UPB_INLINE void google_protobuf_FileOptions_clear_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 19); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 20); } +UPB_INLINE void google_protobuf_FileOptions_clear_ruby_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 20); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView); } UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); } +UPB_INLINE void google_protobuf_FileOptions_clear_uninterpreted_option(const google_protobuf_FileOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(100, 184)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); } @@ -4012,30 +4112,49 @@ UPB_INLINE char* google_protobuf_MessageOptions_serialize_ex(const google_protob UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_MessageOptions_clear_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_MessageOptions_clear_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_MessageOptions_clear_deprecated(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); } UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_MessageOptions_clear_map_entry(const google_protobuf_MessageOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool); } UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); } +UPB_INLINE void google_protobuf_MessageOptions_clear_uninterpreted_option(const google_protobuf_MessageOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 8)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); } @@ -4103,48 +4222,79 @@ UPB_INLINE char* google_protobuf_FieldOptions_serialize_ex(const google_protobuf UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_FieldOptions_clear_ctype(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_FieldOptions_clear_packed(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_FieldOptions_clear_deprecated(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_FieldOptions_clear_lazy(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_FieldOptions_clear_jstype(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = 0; + _upb_clearhas(msg, 5); +} UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); + return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); } UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_FieldOptions_clear_weak(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = 0; + _upb_clearhas(msg, 6); +} UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_unverified_lazy(const google_protobuf_FieldOptions* msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE void google_protobuf_FieldOptions_clear_unverified_lazy(const google_protobuf_FieldOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = 0; + _upb_clearhas(msg, 7); +} UPB_INLINE bool google_protobuf_FieldOptions_unverified_lazy(const google_protobuf_FieldOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool); } UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); } +UPB_INLINE void google_protobuf_FieldOptions_clear_uninterpreted_option(const google_protobuf_FieldOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 24)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(20, 24), len); } @@ -4155,27 +4305,27 @@ UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOpti } UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, int32_t value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; } UPB_INLINE void google_protobuf_FieldOptions_set_unverified_lazy(google_protobuf_FieldOptions *msg, bool value) { _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = value; } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 24), len); @@ -4224,6 +4374,9 @@ UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } +UPB_INLINE void google_protobuf_OneofOptions_clear_uninterpreted_option(const google_protobuf_OneofOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } @@ -4275,18 +4428,29 @@ UPB_INLINE char* google_protobuf_EnumOptions_serialize_ex(const google_protobuf_ UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumOptions_clear_allow_alias(const google_protobuf_EnumOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_EnumOptions_clear_deprecated(const google_protobuf_EnumOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } +UPB_INLINE void google_protobuf_EnumOptions_clear_uninterpreted_option(const google_protobuf_EnumOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } @@ -4346,12 +4510,19 @@ UPB_INLINE char* google_protobuf_EnumValueOptions_serialize_ex(const google_prot UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_EnumValueOptions_clear_deprecated(const google_protobuf_EnumValueOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } +UPB_INLINE void google_protobuf_EnumValueOptions_clear_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } @@ -4407,12 +4578,19 @@ UPB_INLINE char* google_protobuf_ServiceOptions_serialize_ex(const google_protob UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_ServiceOptions_clear_deprecated(const google_protobuf_ServiceOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } +UPB_INLINE void google_protobuf_ServiceOptions_clear_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions* msg, size_t* len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } @@ -4468,39 +4646,50 @@ UPB_INLINE char* google_protobuf_MethodOptions_serialize_ex(const google_protobu UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_MethodOptions_clear_deprecated(const google_protobuf_MethodOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 1); +} UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); + return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_MethodOptions_clear_idempotency_level(const google_protobuf_MethodOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 16)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE void google_protobuf_MethodOptions_clear_uninterpreted_option(const google_protobuf_MethodOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 8)); } UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions* msg, size_t* len) { - return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); } UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, int32_t value) { _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t* len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len); + return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 16), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4537,83 +4726,110 @@ UPB_INLINE char* google_protobuf_UninterpretedOption_serialize_ex(const google_p return upb_Encode(msg, &google_protobuf_UninterpretedOption_msginit, options, arena, len); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(56, 80)); + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE void google_protobuf_UninterpretedOption_clear_name(const google_protobuf_UninterpretedOption* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); } UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption* msg, size_t* len) { - return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(56, 80), len); + return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_identifier_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t); + return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t); + return *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_double_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double) = 0; + _upb_clearhas(msg, 4); +} UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double); + return *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_string_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView); } UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE void google_protobuf_UninterpretedOption_clear_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 6); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView); } UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption* msg, size_t* len) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 80), len); + return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption* msg, size_t len, upb_Arena* arena) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 80), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); - bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 80), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(8, 16), upb_StringView) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(32, 64), uint64_t) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) { _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t) = value; + *UPB_PTR_AT(msg, UPB_SIZE(40, 72), int64_t) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) { _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double) = value; + *UPB_PTR_AT(msg, UPB_SIZE(48, 80), double) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 32), upb_StringView) = value; } UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(24, 48), upb_StringView) = value; } /* google.protobuf.UninterpretedOption.NamePart */ @@ -4650,12 +4866,20 @@ UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize_ex(const UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } @@ -4703,6 +4927,9 @@ UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protob UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } +UPB_INLINE void google_protobuf_SourceCodeInfo_clear_location(const google_protobuf_SourceCodeInfo* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo* msg, size_t* len) { return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } @@ -4751,53 +4978,70 @@ UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize_ex(const goog upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, options, arena, len); } +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_path(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(4, 8)); +} UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_span(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(8, 16)); } UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(8, 16), len); } UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); +} +UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + _upb_array_detach(msg, UPB_SIZE(28, 56)); } UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, 2, arena); + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, 2, arena); } UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), 2, &val, arena); + return _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), 2, &val, arena); } UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 16), len); } UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, 2, arena); + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 16), len, 2, arena); } UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), 2, &val, arena); + return _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 16), 2, &val, arena); } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value; } UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); @@ -4843,6 +5087,9 @@ UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_pro UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } +UPB_INLINE void google_protobuf_GeneratedCodeInfo_clear_annotation(const google_protobuf_GeneratedCodeInfo* msg) { + _upb_array_detach(msg, UPB_SIZE(0, 0)); +} UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo* msg, size_t* len) { return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } @@ -4891,62 +5138,446 @@ UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize_ex(const upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, options, arena, len); } +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + _upb_array_detach(msg, UPB_SIZE(12, 16)); +} UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { - return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 32), len); + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView); + return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_StringView); } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = 0; + _upb_clearhas(msg, 2); +} UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = 0; + _upb_clearhas(msg, 3); +} UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 32), len); + return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len); } UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t len, upb_Arena* arena) { - return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 32), len, 2, arena); + return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 16), len, 2, arena); } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t val, upb_Arena* arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 32), 2, &val, arena); + return _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 16), 2, &val, arena); } UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_StringView value) { _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView) = value; + *UPB_PTR_AT(msg, UPB_SIZE(16, 24), upb_StringView) = value; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + _upb_sethas(msg, 2); + *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + _upb_sethas(msg, 3); + *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; +} + +extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout; + +/* Max size 32 is google.protobuf.FileOptions */ +/* Max size 64 is google.protobuf.FileOptions */ +#define _UPB_MAXOPT_SIZE UPB_SIZE(104, 192) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { + bool bool_val; + float float_val; + double double_val; + int32_t int32_val; + int64_t int64_val; + uint32_t uint32_val; + uint64_t uint64_val; + const upb_Map* map_val; + const upb_Message* msg_val; + const upb_Array* array_val; + upb_StringView str_val; +} upb_MessageValue; + +typedef union { + upb_Map* map; + upb_Message* msg; + upb_Array* array; +} upb_MutableMessageValue; + +/** upb_Array *****************************************************************/ + +/* Creates a new array on the given arena that holds elements of this type. */ +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); + +/* Returns the size of the array. */ +size_t upb_Array_Size(const upb_Array* arr); + +/* Returns the given element, which must be within the array's current size. */ +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); + +/* Sets the given element, which must be within the array's current size. */ +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); + +/* Appends an element to the array. Returns false on allocation failure. */ +bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); + +/* Moves elements within the array using memmove(). Like memmove(), the source + * and destination elements may be overlapping. */ +void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, + size_t count); + +/* Inserts one or more empty elements into the array. Existing elements are + * shifted right. The new elements have undefined state and must be set with + * `upb_Array_Set()`. + * REQUIRES: `i <= upb_Array_Size(arr)` */ +bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, + upb_Arena* arena); + +/* Deletes one or more elements from the array. Existing elements are shifted + * left. + * REQUIRES: `i + count <= upb_Array_Size(arr)` */ +void upb_Array_Delete(upb_Array* array, size_t i, size_t count); + +/* Changes the size of a vector. New elements are initialized to empty/0. + * Returns false on allocation failure. */ +bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); + +/** upb_Map *******************************************************************/ + +/* Creates a new map on the given arena with the given key/value size. */ +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); + +/* Returns the number of entries in the map. */ +size_t upb_Map_Size(const upb_Map* map); + +/* Stores a value for the given key into |*val| (or the zero value if the key is + * not present). Returns whether the key was present. The |val| pointer may be + * NULL, in which case the function tests whether the given key is present. */ +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val); + +/* Removes all entries in the map. */ +void upb_Map_Clear(upb_Map* map); + +typedef enum { + // LINT.IfChange + kUpb_MapInsertStatus_Inserted = 0, + kUpb_MapInsertStatus_Replaced = 1, + kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/msg_internal.h) +} upb_MapInsertStatus; + +/* Sets the given key to the given value, returning whether the key was inserted + * or replaced. If the key was inserted, then any existing iterators will be + * invalidated. */ +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena); + +/* Sets the given key to the given value. Returns false if memory allocation + * failed. If the key is newly inserted, then any existing iterators will be + * invalidated. */ +UPB_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return upb_Map_Insert(map, key, val, arena) != + kUpb_MapInsertStatus_OutOfMemory; +} + +/* Deletes this key from the table. Returns true if the key was present. */ +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); + +/* Map iteration: + * + * size_t iter = kUpb_Map_Begin; + * while (upb_MapIterator_Next(map, &iter)) { + * upb_MessageValue key = upb_MapIterator_Key(map, iter); + * upb_MessageValue val = upb_MapIterator_Value(map, iter); + * + * // If mutating is desired. + * upb_MapIterator_SetValue(map, iter, value2); + * } + */ + +/* Advances to the next entry. Returns false if no more entries are present. */ +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); + +/* Returns true if the iterator still points to a valid entry, or false if the + * iterator is past the last element. It is an error to call this function with + * kUpb_Map_Begin (you must call next() at least once first). */ +bool upb_MapIterator_Done(const upb_Map* map, size_t iter); + +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); + +/* Sets the value for this entry. The iterator must not be done, and the + * iterator must not have been initialized const. */ +void upb_MapIterator_SetValue(upb_Map* map, size_t iter, + upb_MessageValue value); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_COLLECTIONS_H_ */ + +/** upb/decode_internal.h ************************************************************/ +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_DECODE_INT_H_ +#define UPB_DECODE_INT_H_ + +#include + +#include "third_party/utf8_range/utf8_range.h" + +/** upb/upb_internal.h ************************************************************/ +#ifndef UPB_INT_H_ +#define UPB_INT_H_ + + +struct mem_block; +typedef struct mem_block mem_block; + +struct upb_Arena { + _upb_ArenaHead head; + /* Stores cleanup metadata for this arena. + * - a pointer to the current cleanup counter. + * - a boolean indicating if there is an unowned initial block. */ + uintptr_t cleanup_metadata; + + /* Allocator to allocate arena blocks. We are responsible for freeing these + * when we are destroyed. */ + upb_alloc* block_alloc; + uint32_t last_size; + + /* When multiple arenas are fused together, each arena points to a parent + * arena (root points to itself). The root tracks how many live arenas + * reference it. */ + uint32_t refcount; /* Only used when a->parent == a */ + struct upb_Arena* parent; + + /* Linked list of blocks to free/cleanup. */ + mem_block *freelist, *freelist_tail; +}; + +// Encodes a float or double that is round-trippable, but as short as possible. +// These routines are not fully optimal (not guaranteed to be shortest), but are +// short-ish and match the implementation that has been used in protobuf since +// the beginning. +// +// The given buffer size must be at least kUpb_RoundTripBufferSize. +enum { kUpb_RoundTripBufferSize = 32 }; +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); + +#endif /* UPB_INT_H_ */ + +/* Must be last. */ + +#define DECODE_NOGROUP (uint32_t) - 1 + +typedef struct upb_Decoder { + const char* end; /* Can read up to 16 bytes slop beyond this. */ + const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */ + upb_Message* unknown_msg; /* Used for preserving unknown data. */ + const char* unknown; /* Start of unknown data, preserve at buffer flip. */ + const upb_ExtensionRegistry* + extreg; /* For looking up extensions during the parse. */ + int limit; /* Submessage limit relative to end. */ + int depth; /* Tracks recursion depth to bound stack usage. */ + uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ + uint16_t options; + bool missing_required; + char patch[32]; + upb_Arena arena; + jmp_buf err; + +#ifndef NDEBUG + const char* debug_tagstart; + const char* debug_valstart; +#endif +} upb_Decoder; + +/* Error function that will abort decoding with longjmp(). We can't declare this + * UPB_NORETURN, even though it is appropriate, because if we do then compilers + * will "helpfully" refuse to tailcall to it + * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal + * of our optimizations. That is also why we must declare it in a separate file, + * otherwise the compiler will see that it calls longjmp() and deduce that it is + * noreturn. */ +const char* fastdecode_err(upb_Decoder* d, int status); + +extern const uint8_t upb_utf8_offsets[]; + +UPB_INLINE +bool decode_verifyutf8_inl(const char* ptr, int len) { + const char* end = ptr + len; + + // Check 8 bytes at a time for any non-ASCII char. + while (end - ptr >= 8) { + uint64_t data; + memcpy(&data, ptr, 8); + if (data & 0x8080808080808080) goto non_ascii; + ptr += 8; + } + + // Check one byte at a time for non-ASCII. + while (ptr < end) { + if (*ptr & 0x80) goto non_ascii; + ptr++; + } + + return true; + +non_ascii: + return utf8_range2((const unsigned char*)ptr, end - ptr) == 0; +} + +const char* decode_checkrequired(upb_Decoder* d, const char* ptr, + const upb_Message* msg, + const upb_MiniTable* l); + +/* x86-64 pointers always have the high 16 bits matching. So we can shift + * left 8 and right 8 without loss of information. */ +UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) { + return ((intptr_t)tablep << 8) | tablep->table_mask; +} + +UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) { + return (const upb_MiniTable*)(table >> 8); +} + +UPB_INLINE +const char* decode_isdonefallback_inl(upb_Decoder* d, const char* ptr, + int overrun, int* status) { + if (overrun < d->limit) { + /* Need to copy remaining data into patch buffer. */ + UPB_ASSERT(overrun < 16); + if (d->unknown) { + if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown, + &d->arena)) { + *status = kUpb_DecodeStatus_OutOfMemory; + return NULL; + } + d->unknown = &d->patch[0] + overrun; + } + memset(d->patch + 16, 0, 16); + memcpy(d->patch, d->end, 16); + ptr = &d->patch[0] + overrun; + d->end = &d->patch[16]; + d->limit -= 16; + d->limit_ptr = d->end + d->limit; + d->options &= ~kUpb_DecodeOption_AliasString; + UPB_ASSERT(ptr < d->limit_ptr); + return ptr; + } else { + *status = kUpb_DecodeStatus_Malformed; + return NULL; + } +} + +const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, int overrun); + +UPB_INLINE +bool decode_isdone(upb_Decoder* d, const char** ptr) { + int overrun = *ptr - d->end; + if (UPB_LIKELY(*ptr < d->limit_ptr)) { + return false; + } else if (UPB_LIKELY(overrun == d->limit)) { + return true; + } else { + *ptr = decode_isdonefallback(d, *ptr, overrun); + return false; + } +} + +#if UPB_FASTTABLE +UPB_INLINE +const char* fastdecode_tagdispatch(upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t tag) { + const upb_MiniTable* table_p = decode_totablep(table); + uint8_t mask = table; + uint64_t data; + size_t idx = tag & mask; + UPB_ASSUME((idx & 7) == 0); + idx >>= 3; + data = table_p->fasttable[idx].field_data ^ tag; + UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table, + hasbits, data); +} +#endif + +UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) { + uint16_t tag; + memcpy(&tag, ptr, 2); + return tag; } -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; + +UPB_INLINE void decode_checklimit(upb_Decoder* d) { + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); } -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + +UPB_INLINE int decode_pushlimit(upb_Decoder* d, const char* ptr, int size) { + int limit = size + (int)(ptr - d->end); + int delta = d->limit - limit; + decode_checklimit(d); + d->limit = limit; + d->limit_ptr = d->end + UPB_MIN(0, limit); + decode_checklimit(d); + return delta; } -extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout; +UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr, + int saved_delta) { + UPB_ASSERT(ptr - d->end == d->limit); + decode_checklimit(d); + d->limit += saved_delta; + d->limit_ptr = d->end + UPB_MIN(0, d->limit); + decode_checklimit(d); +} -/* Max size 32 is google.protobuf.FileOptions */ -/* Max size 64 is google.protobuf.FileOptions */ -#define _UPB_MAXOPT_SIZE UPB_SIZE(104, 192) -#ifdef __cplusplus -} /* extern "C" */ -#endif +#endif /* UPB_DECODE_INT_H_ */ +/** upb/json_decode.h ************************************************************/ +#ifndef UPB_JSONDECODE_H_ +#define UPB_JSONDECODE_H_ -#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ /** upb/def.h ************************************************************/ #ifndef UPB_DEF_H_ @@ -4981,6 +5612,9 @@ struct upb_streamdef; typedef struct upb_streamdef upb_streamdef; struct upb_DefPool; typedef struct upb_DefPool upb_DefPool; +typedef struct upb_EnumReservedRange upb_EnumReservedRange; +typedef struct upb_MessageReservedRange upb_MessageReservedRange; +typedef struct symtab_addctx symtab_addctx; typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; @@ -5084,11 +5718,11 @@ const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, #define kUpb_Any_TypeFieldNumber 1 #define kUpb_Any_ValueFieldNumber 2 -/* Well-known field tag numbers for timestamp messages. */ +/* Well-known field tag numbers for duration messages. */ #define kUpb_Duration_SecondsFieldNumber 1 #define kUpb_Duration_NanosFieldNumber 2 -/* Well-known field tag numbers for duration messages. */ +/* Well-known field tag numbers for timestamp messages. */ #define kUpb_Timestamp_SecondsFieldNumber 1 #define kUpb_Timestamp_NanosFieldNumber 2 @@ -5130,6 +5764,11 @@ UPB_INLINE bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m)); } +UPB_INLINE bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(m)); +} + /* Nested entities. */ int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); @@ -5163,6 +5802,16 @@ UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName( return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name)); } +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m); + +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m); + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r); +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r); + /* upb_ExtensionRange *********************************************************/ const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( @@ -5195,6 +5844,16 @@ UPB_INLINE const upb_EnumValueDef* upb_EnumDef_FindValueByName( return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); } +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i); +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e); + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i); +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e); + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r); +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r); + /* upb_EnumValueDef ***********************************************************/ const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( @@ -5327,6 +5986,22 @@ UPB_INLINE bool _upb_DefPool_LoadDefInit(upb_DefPool* s, #endif /* UPB_DEF_H_ */ +#ifdef __cplusplus +extern "C" { +#endif + +enum { upb_JsonDecode_IgnoreUnknown = 1 }; + +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_JSONDECODE_H_ */ + /** upb/reflection.h ************************************************************/ #ifndef UPB_REFLECTION_H_ #define UPB_REFLECTION_H_ @@ -5336,26 +6011,6 @@ UPB_INLINE bool _upb_DefPool_LoadDefInit(upb_DefPool* s, extern "C" { #endif -typedef union { - bool bool_val; - float float_val; - double double_val; - int32_t int32_val; - int64_t int64_val; - uint32_t uint32_val; - uint64_t uint64_val; - const upb_Map* map_val; - const upb_Message* msg_val; - const upb_Array* array_val; - upb_StringView str_val; -} upb_MessageValue; - -typedef union { - upb_Map* map; - upb_Message* msg; - upb_Array* array; -} upb_MutableMessageValue; - upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); /** upb_Message @@ -5418,98 +6073,6 @@ bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, int maxdepth); -/** upb_Array *****************************************************************/ - -/* Creates a new array on the given arena that holds elements of this type. */ -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); - -/* Returns the size of the array. */ -size_t upb_Array_Size(const upb_Array* arr); - -/* Returns the given element, which must be within the array's current size. */ -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); - -/* Sets the given element, which must be within the array's current size. */ -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); - -/* Appends an element to the array. Returns false on allocation failure. */ -bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); - -/* Moves elements within the array using memmove(). Like memmove(), the source - * and destination elements may be overlapping. */ -void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, - size_t count); - -/* Inserts one or more empty elements into the array. Existing elements are - * shifted right. The new elements have undefined state and must be set with - * `upb_Array_Set()`. - * REQUIRES: `i <= upb_Array_Size(arr)` */ -bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, - upb_Arena* arena); - -/* Deletes one or more elements from the array. Existing elements are shifted - * left. - * REQUIRES: `i + count <= upb_Array_Size(arr)` */ -void upb_Array_Delete(upb_Array* array, size_t i, size_t count); - -/* Changes the size of a vector. New elements are initialized to empty/0. - * Returns false on allocation failure. */ -bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); - -/** upb_Map *******************************************************************/ - -/* Creates a new map on the given arena with the given key/value size. */ -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); - -/* Returns the number of entries in the map. */ -size_t upb_Map_Size(const upb_Map* map); - -/* Stores a value for the given key into |*val| (or the zero value if the key is - * not present). Returns whether the key was present. The |val| pointer may be - * NULL, in which case the function tests whether the given key is present. */ -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val); - -/* Removes all entries in the map. */ -void upb_Map_Clear(upb_Map* map); - -/* Sets the given key to the given value. Returns true if this was a new key in - * the map, or false if an existing key was replaced. */ -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena); - -/* Deletes this key from the table. Returns true if the key was present. */ -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); - -/* Map iteration: - * - * size_t iter = kUpb_Map_Begin; - * while (upb_MapIterator_Next(map, &iter)) { - * upb_MessageValue key = upb_MapIterator_Key(map, iter); - * upb_MessageValue val = upb_MapIterator_Value(map, iter); - * - * // If mutating is desired. - * upb_MapIterator_SetValue(map, iter, value2); - * } - */ - -/* Advances to the next entry. Returns false if no more entries are present. */ -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); - -/* Returns true if the iterator still points to a valid entry, or false if the - * iterator is past the last element. It is an error to call this function with - * kUpb_Map_Begin (you must call next() at least once first). */ -bool upb_MapIterator_Done(const upb_Map* map, size_t iter); - -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); - -/* Sets the value for this entry. The iterator must not be done, and the - * iterator must not have been initialized const. */ -void upb_MapIterator_SetValue(upb_Map* map, size_t iter, - upb_MessageValue value); - #ifdef __cplusplus } /* extern "C" */ #endif @@ -5517,27 +6080,6 @@ void upb_MapIterator_SetValue(upb_Map* map, size_t iter, #endif /* UPB_REFLECTION_H_ */ -/** upb/json_decode.h ************************************************************/ -#ifndef UPB_JSONDECODE_H_ -#define UPB_JSONDECODE_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - -enum { upb_JsonDecode_IgnoreUnknown = 1 }; - -bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, - const upb_MessageDef* m, const upb_DefPool* symtab, - int options, upb_Arena* arena, upb_Status* status); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_JSONDECODE_H_ */ - /** upb/json_encode.h ************************************************************/ #ifndef UPB_JSONENCODE_H_ #define UPB_JSONENCODE_H_ @@ -5574,6 +6116,192 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #endif /* UPB_JSONENCODE_H_ */ +/** upb/internal/vsnprintf_compat.h ************************************************************/ +#ifndef UPB_INTERNAL_VSNPRINTF_COMPAT_H_ +#define UPB_INTERNAL_VSNPRINTF_COMPAT_H_ + +#include + +// Must be last. + +UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, + va_list ap) { +#if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) + // The msvc runtime has a non-conforming vsnprintf() that requires the + // following compatibility code to become conformant. + int n = -1; + if (size != 0) n = _vsnprintf_s(buf, size, _TRUNCATE, fmt, ap); + if (n == -1) n = _vscprintf(fmt, ap); + return n; +#else + return vsnprintf(buf, size, fmt, ap); +#endif +} + + +#endif // UPB_INTERNAL_VSNPRINTF_COMPAT_H_ + +/** upb/mini_table.h ************************************************************/ +#ifndef UPB_MINI_TABLE_H_ +#define UPB_MINI_TABLE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number); + +UPB_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { + return mini_table->subs[field->submsg_index].submsg; +} + +UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, + int32_t val) { + uint32_t uval = (uint32_t)val; + if (uval < 64) return e->mask & (1ULL << uval); + // OPT: binary search long lists? + int n = e->value_count; + for (int i = 0; i < n; i++) { + if (e->values[i] == val) return true; + } + return false; +} + +/** upb_MtDataEncoder *********************************************************/ + +// Functions to encode a string in a format that can be loaded by +// upb_MiniTable_Build(). + +typedef enum { + kUpb_MessageModifier_ValidateUtf8 = 1 << 0, + kUpb_MessageModifier_DefaultIsPacked = 1 << 1, + kUpb_MessageModifier_IsExtendable = 1 << 2, +} kUpb_MessageModifier; + +typedef enum { + kUpb_FieldModifier_IsRepeated = 1 << 0, + kUpb_FieldModifier_IsPacked = 1 << 1, + kUpb_FieldModifier_IsClosedEnum = 1 << 2, + kUpb_FieldModifier_IsProto3Singular = 1 << 3, + kUpb_FieldModifier_IsRequired = 1 << 4, +} kUpb_FieldModifier; + +typedef struct { + char* end; // Limit of the buffer passed as a parameter. + // Aliased to internal-only members in .cc. + char internal[32]; +} upb_MtDataEncoder; + +// If the input buffer has at least this many bytes available, the encoder call +// is guaranteed to succeed (as long as field number order is maintained). +#define kUpb_MtDataEncoder_MinSize 16 + +// Encodes field/oneof information for a given message. The sequence of calls +// should look like: +// +// upb_MtDataEncoder e; +// char buf[256]; +// char* ptr = buf; +// e.end = ptr + sizeof(buf); +// ptr = upb_MtDataEncoder_StartMessage(&e, ptr); +// // Fields *must* be in field number order. +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// +// // If oneofs are present. Oneofs must be encoded after regular fields. +// ptr = upb_MiniTable_StartOneof(&e, ptr) +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// ptr = upb_MiniTable_StartOneof(&e, ptr); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// Oneofs must be encoded after all regular fields. +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod); +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod); +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr); +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num); + +// Encodes the set of values for a given enum. The values must be given in +// order (after casting to uint32_t), and repeats are not allowed. +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e); +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val); +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr); + +/** upb_MiniTable *************************************************************/ + +typedef enum { + kUpb_MiniTablePlatform_32Bit, + kUpb_MiniTablePlatform_64Bit, + kUpb_MiniTablePlatform_Native = + UPB_SIZE(kUpb_MiniTablePlatform_32Bit, kUpb_MiniTablePlatform_64Bit), +} upb_MiniTablePlatform; + +// Builds a mini table from the data encoded in the buffer [data, len]. If any +// errors occur, returns NULL and sets a status message. In the success case, +// the caller must call upb_MiniTable_SetSub*() for all message or proto2 enum +// fields to link the table to the appropriate sub-tables. +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status); +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub); +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub); + +bool upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + upb_MiniTable_Sub sub, upb_Status* status); + +// Special-case functions for MessageSet layout and map entries. +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena); +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena); + +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status); + +// Like upb_MiniTable_Build(), but the user provides a buffer of layout data so +// it can be reused from call to call, avoiding repeated realloc()/free(). +// +// The caller owns `*buf` both before and after the call, and must free() it +// when it is no longer in use. The function will realloc() `*buf` as +// necessary, updating `*size` accordingly. +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, upb_Status* status); + +// For testing only. +char upb_ToBase92(int8_t ch); +char upb_FromBase92(uint8_t ch); +bool upb_IsTypePackable(upb_FieldType type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_H_ */ + /** upb/port_undef.inc ************************************************************/ /* See port_def.inc. This should #undef all macros #defined there. */ @@ -5587,6 +6315,7 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_MALLOC_ALIGN #undef UPB_LIKELY #undef UPB_UNLIKELY #undef UPB_FORCEINLINE From a474c5b9ff43c4dda5d3132024eee8cef71b83fc Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Wed, 7 Dec 2022 18:41:29 -0800 Subject: [PATCH 02/10] Updating version.json and repo version numbers to: 21.11 --- Protobuf-C++.podspec | 2 +- Protobuf.podspec | 2 +- configure.ac | 2 +- csharp/Google.Protobuf.Tools.nuspec | 2 +- .../Google.Protobuf/Google.Protobuf.csproj | 2 +- java/README.md | 6 +++--- java/bom/pom.xml | 2 +- java/core/pom.xml | 2 +- java/kotlin-lite/pom.xml | 2 +- java/kotlin/pom.xml | 2 +- java/lite.md | 2 +- java/lite/pom.xml | 2 +- java/pom.xml | 2 +- java/util/pom.xml | 2 +- php/ext/google/protobuf/protobuf.h | 2 +- protobuf_version.bzl | 8 ++++---- protoc-artifacts/pom.xml | 2 +- python/google/protobuf/__init__.py | 2 +- ruby/google-protobuf.gemspec | 2 +- ruby/pom.xml | 4 ++-- src/Makefile.am | 2 +- src/google/protobuf/any.pb.h | 2 +- src/google/protobuf/api.pb.h | 2 +- src/google/protobuf/compiler/plugin.pb.h | 2 +- src/google/protobuf/descriptor.pb.h | 2 +- src/google/protobuf/duration.pb.h | 2 +- src/google/protobuf/empty.pb.h | 2 +- src/google/protobuf/field_mask.pb.h | 2 +- src/google/protobuf/port_def.inc | 2 +- src/google/protobuf/source_context.pb.h | 2 +- src/google/protobuf/struct.pb.h | 2 +- src/google/protobuf/stubs/common.h | 2 +- src/google/protobuf/timestamp.pb.h | 2 +- src/google/protobuf/type.pb.h | 2 +- src/google/protobuf/wrappers.pb.h | 2 +- version.json | 20 +++++++++---------- 36 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Protobuf-C++.podspec b/Protobuf-C++.podspec index 41fab1b6a9..0c61573c4a 100644 --- a/Protobuf-C++.podspec +++ b/Protobuf-C++.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Protobuf-C++' - s.version = '3.21.10' + s.version = '3.21.11' s.summary = 'Protocol Buffers v3 runtime library for C++.' s.homepage = 'https://github.com/google/protobuf' s.license = 'BSD-3-Clause' diff --git a/Protobuf.podspec b/Protobuf.podspec index b5fe42e763..9f9df1577c 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '3.21.10' + s.version = '3.21.11' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/protocolbuffers/protobuf' s.license = 'BSD-3-Clause' diff --git a/configure.ac b/configure.ac index ed00950472..517b497222 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ AC_PREREQ(2.59) # In the SVN trunk, the version should always be the next anticipated release # version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed # the size of one file name in the dist tarfile over the 99-char limit.) -AC_INIT([Protocol Buffers],[3.21.10],[protobuf@googlegroups.com],[protobuf]) +AC_INIT([Protocol Buffers],[3.21.11],[protobuf@googlegroups.com],[protobuf]) AM_MAINTAINER_MODE([enable]) diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index 9ef830b681..8f1bf8bbcf 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Google Protocol Buffers tools Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.21.10 + 3.21.11 Google Inc. protobuf-packages https://github.com/protocolbuffers/protobuf/blob/main/LICENSE diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index bf535bd02f..8ebc31e91c 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -4,7 +4,7 @@ C# runtime library for Protocol Buffers - Google's data interchange format. Copyright 2015, Google Inc. Google Protocol Buffers - 3.21.10 + 3.21.11 7.2 Google Inc. diff --git a/java/README.md b/java/README.md index 17de94d665..1b0ac91b5c 100644 --- a/java/README.md +++ b/java/README.md @@ -23,7 +23,7 @@ If you are using Maven, use the following: com.google.protobuf protobuf-java - 3.21.10 + 3.21.11 ``` @@ -37,7 +37,7 @@ protobuf-java-util package: com.google.protobuf protobuf-java-util - 3.21.10 + 3.21.11 ``` @@ -45,7 +45,7 @@ protobuf-java-util package: If you are using Gradle, add the following to your `build.gradle` file's dependencies: ``` - implementation 'com.google.protobuf:protobuf-java:3.21.10' + implementation 'com.google.protobuf:protobuf-java:3.21.11' ``` Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using. diff --git a/java/bom/pom.xml b/java/bom/pom.xml index b3389a8c14..eaec5aaf55 100644 --- a/java/bom/pom.xml +++ b/java/bom/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-bom - 3.21.10 + 3.21.11 pom Protocol Buffers [BOM] diff --git a/java/core/pom.xml b/java/core/pom.xml index d1bd673997..79e75c9a81 100644 --- a/java/core/pom.xml +++ b/java/core/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.10 + 3.21.11 protobuf-java diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml index c8e2c34ce7..18a134c702 100644 --- a/java/kotlin-lite/pom.xml +++ b/java/kotlin-lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.10 + 3.21.11 protobuf-kotlin-lite diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml index cc563cf09d..ab24dda087 100644 --- a/java/kotlin/pom.xml +++ b/java/kotlin/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.10 + 3.21.11 protobuf-kotlin diff --git a/java/lite.md b/java/lite.md index a10e9595b6..9a6adcb861 100644 --- a/java/lite.md +++ b/java/lite.md @@ -29,7 +29,7 @@ protobuf Java Lite runtime. If you are using Maven, include the following: com.google.protobuf protobuf-javalite - 3.21.10 + 3.21.11 ``` diff --git a/java/lite/pom.xml b/java/lite/pom.xml index db67296da8..e394118607 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.10 + 3.21.11 protobuf-javalite diff --git a/java/pom.xml b/java/pom.xml index 77b8314377..16c6715ec2 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.10 + 3.21.11 pom Protocol Buffers [Parent] diff --git a/java/util/pom.xml b/java/util/pom.xml index d2baaf474b..05f7b97c7e 100644 --- a/java/util/pom.xml +++ b/java/util/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.10 + 3.21.11 protobuf-java-util diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index a47abf625a..616ab68566 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -127,7 +127,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() -#define PHP_PROTOBUF_VERSION "3.21.10" +#define PHP_PROTOBUF_VERSION "3.21.11" // ptr -> PHP object cache. This is a weak map that caches lazily-created // wrapper objects around upb types: diff --git a/protobuf_version.bzl b/protobuf_version.bzl index 2ea278cb8d..20c8577813 100644 --- a/protobuf_version.bzl +++ b/protobuf_version.bzl @@ -1,4 +1,4 @@ -PROTOC_VERSION = "21.10" -PROTOBUF_JAVA_VERSION = "3.21.10" -PROTOBUF_PYTHON_VERSION = "4.21.10" -PROTOBUF_PHP_VERSION = "3.21.10" +PROTOC_VERSION = "21.11" +PROTOBUF_JAVA_VERSION = "3.21.11" +PROTOBUF_PYTHON_VERSION = "4.21.11" +PROTOBUF_PHP_VERSION = "3.21.11" diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml index 019e85741f..af9b177d38 100644 --- a/protoc-artifacts/pom.xml +++ b/protoc-artifacts/pom.xml @@ -8,7 +8,7 @@ com.google.protobuf protoc - 3.21.10 + 3.21.11 pom Protobuf Compiler diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py index e0121a4f6c..7c66e4e207 100644 --- a/python/google/protobuf/__init__.py +++ b/python/google/protobuf/__init__.py @@ -30,4 +30,4 @@ # Copyright 2007 Google Inc. All Rights Reserved. -__version__ = '4.21.10' +__version__ = '4.21.11' diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index 73abc81509..dbfb04d7a1 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.21.10" + s.version = "3.21.11" git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag s.licenses = ["BSD-3-Clause"] s.summary = "Protocol Buffers" diff --git a/ruby/pom.xml b/ruby/pom.xml index e5ea175f89..537a504446 100644 --- a/ruby/pom.xml +++ b/ruby/pom.xml @@ -9,7 +9,7 @@ com.google.protobuf.jruby protobuf-jruby - 3.21.10 + 3.21.11 Protocol Buffer JRuby native extension Protocol Buffers are a way of encoding structured data in an efficient yet @@ -76,7 +76,7 @@ com.google.protobuf protobuf-java-util - 3.21.10 + 3.21.11 org.jruby diff --git a/src/Makefile.am b/src/Makefile.am index 02abe5503c..c5087f57e3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ else PTHREAD_DEF = endif -PROTOBUF_VERSION = 32:10:0 +PROTOBUF_VERSION = 32:11:0 if GCC # Turn on all warnings except for sign comparison (we ignore sign comparison diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index 40837ea90d..c35eaddaeb 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index b81b18e351..36f480c83d 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index fd6773b6e3..0c3c5b4e0c 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index cb83348231..f40e966543 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h index e3d89b93e3..0794e0af76 100644 --- a/src/google/protobuf/duration.pb.h +++ b/src/google/protobuf/duration.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h index ec897ea4cd..1dfbb1d2a0 100644 --- a/src/google/protobuf/empty.pb.h +++ b/src/google/protobuf/empty.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h index ca7887748f..27cbd7fab1 100644 --- a/src/google/protobuf/field_mask.pb.h +++ b/src/google/protobuf/field_mask.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index f4544112eb..2680acdbd5 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc @@ -178,7 +178,7 @@ #ifdef PROTOBUF_VERSION #error PROTOBUF_VERSION was previously defined #endif -#define PROTOBUF_VERSION 3021010 +#define PROTOBUF_VERSION 3021011 #ifdef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC #error PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC was previously defined diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h index 4ab7ec704f..833c1e735d 100644 --- a/src/google/protobuf/source_context.pb.h +++ b/src/google/protobuf/source_context.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h index fb47fce7c6..57e955c84e 100644 --- a/src/google/protobuf/struct.pb.h +++ b/src/google/protobuf/struct.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index a57165f8fa..c4e6f48fdf 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -82,7 +82,7 @@ namespace internal { // The current version, represented as a single integer to make comparison // easier: major * 10^6 + minor * 10^3 + micro -#define GOOGLE_PROTOBUF_VERSION 3021010 +#define GOOGLE_PROTOBUF_VERSION 3021011 // A suffix string for alpha, beta or rc releases. Empty for stable releases. #define GOOGLE_PROTOBUF_VERSION_SUFFIX "" diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h index b55d0a447e..44c53e97de 100644 --- a/src/google/protobuf/timestamp.pb.h +++ b/src/google/protobuf/timestamp.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index f6cba209d3..f152a8d95b 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index f8b51c0eb6..4270adfafa 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021010 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/version.json b/version.json index 0b703249d3..e76162bb20 100644 --- a/version.json +++ b/version.json @@ -1,17 +1,17 @@ { "21.x": { - "protoc_version": "21.11-dev", + "protoc_version": "21.11", "lts": false, - "date": "2022-11-30", + "date": "2022-12-07", "languages": { - "cpp": "3.21.11-dev", - "csharp": "3.21.11-dev", - "java": "3.21.11-dev", - "javascript": "3.21.11-dev", - "objectivec": "3.21.11-dev", - "php": "3.21.11-dev", - "python": "4.21.11-dev", - "ruby": "3.21.11-dev" + "cpp": "3.21.11", + "csharp": "3.21.11", + "java": "3.21.11", + "javascript": "3.21.11", + "objectivec": "3.21.11", + "php": "3.21.11", + "python": "4.21.11", + "ruby": "3.21.11" } } } \ No newline at end of file From aea4a275e28329f648e046469c095eef74254bb2 Mon Sep 17 00:00:00 2001 From: Eric Salo Date: Wed, 7 Dec 2022 20:46:08 -0800 Subject: [PATCH 03/10] Updating changelog --- CHANGES.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 98cdf2091c..cf6a74db8f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +2022-12-07 version 21.11 (C++/Java/Python/PHP/Objective-C/C#/Ruby) + Python + * Add license file to pypi wheels (#10936) + * Fix round-trip bug (#10158) + 2022-11-29 version 21.10 (C++/Java/Python/PHP/Objective-C/C#/Ruby) Java From 44eafb2f651436fd583051f137556ffcf43bd1d9 Mon Sep 17 00:00:00 2001 From: Eric Salo Date: Thu, 8 Dec 2022 00:56:59 -0800 Subject: [PATCH 04/10] Update version.json to: 21.12-dev --- version.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/version.json b/version.json index e76162bb20..d134b24033 100644 --- a/version.json +++ b/version.json @@ -1,17 +1,17 @@ { "21.x": { - "protoc_version": "21.11", + "protoc_version": "21.12-dev", "lts": false, - "date": "2022-12-07", + "date": "2022-12-08", "languages": { - "cpp": "3.21.11", - "csharp": "3.21.11", - "java": "3.21.11", - "javascript": "3.21.11", - "objectivec": "3.21.11", - "php": "3.21.11", - "python": "4.21.11", - "ruby": "3.21.11" + "cpp": "3.21.12-dev", + "csharp": "3.21.12-dev", + "java": "3.21.12-dev", + "javascript": "3.21.12-dev", + "objectivec": "3.21.12-dev", + "php": "3.21.12-dev", + "python": "4.21.12-dev", + "ruby": "3.21.12-dev" } } } \ No newline at end of file From 7b0ca6995da9c895ac1ca0005b705fa01f009b7f Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 12 Dec 2022 12:21:15 -0800 Subject: [PATCH 05/10] Updated release branch to latest upb. (#11258) * Updated release branch to latest upb. * Updated amalgamated files. --- php/ext/google/protobuf/php-upb.c | 5 ++--- protobuf_deps.bzl | 4 ++-- ruby/ext/google/protobuf_c/ruby-upb.c | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index 602509a64a..7ccb946143 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -6143,7 +6143,6 @@ upb_EnumReservedRange* _upb_EnumReservedRanges_New( google_protobuf_EnumDescriptorProto_EnumReservedRange_start(protos[i]); const int32_t end = google_protobuf_EnumDescriptorProto_EnumReservedRange_end(protos[i]); - const int32_t max = kUpb_MaxFieldNumber + 1; // A full validation would also check that each range is disjoint, and that // none of the fields overlap with the extension ranges, but we are just @@ -6151,7 +6150,7 @@ upb_EnumReservedRange* _upb_EnumReservedRanges_New( // Note: Not a typo! Unlike extension ranges and message reserved ranges, // the end value of an enum reserved range is *inclusive*! - if (start < 1 || end < start || end > max) { + if (end < start) { symtab_errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", (int)start, (int)end, upb_EnumDef_FullName(e)); } @@ -8184,7 +8183,7 @@ static void create_fielddef( CHK_OOM( upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); } else { - if (f->proto3_optional_) { + if (f->proto3_optional_ && !is_extension) { symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)", f->full_name); } diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl index 6aee8b76dd..0949ef370a 100644 --- a/protobuf_deps.bzl +++ b/protobuf_deps.bzl @@ -117,6 +117,6 @@ def protobuf_deps(): _github_archive( name = "upb", repo = "https://github.com/protocolbuffers/upb", - commit = "969f6fdb88e94ced87953e53716893c68ec7b1ce", - sha256 = "6754b7f95c92f69a832a82931aea40d066cc689dbc1eb3348b84c1ed95285296", + commit = "20b542a767139732548f7b8cf28c4c928cdcb07b", + sha256 = "c77158955326f9e9a0cf8481c118b8ad5c34df99e5db3af27f3d1662d8bedef7", ) diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index 85b1d0f2ff..3d3c35be93 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -5814,7 +5814,6 @@ upb_EnumReservedRange* _upb_EnumReservedRanges_New( google_protobuf_EnumDescriptorProto_EnumReservedRange_start(protos[i]); const int32_t end = google_protobuf_EnumDescriptorProto_EnumReservedRange_end(protos[i]); - const int32_t max = kUpb_MaxFieldNumber + 1; // A full validation would also check that each range is disjoint, and that // none of the fields overlap with the extension ranges, but we are just @@ -5822,7 +5821,7 @@ upb_EnumReservedRange* _upb_EnumReservedRanges_New( // Note: Not a typo! Unlike extension ranges and message reserved ranges, // the end value of an enum reserved range is *inclusive*! - if (start < 1 || end < start || end > max) { + if (end < start) { symtab_errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", (int)start, (int)end, upb_EnumDef_FullName(e)); } @@ -7855,7 +7854,7 @@ static void create_fielddef( CHK_OOM( upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena)); } else { - if (f->proto3_optional_) { + if (f->proto3_optional_ && !is_extension) { symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)", f->full_name); } From f0dc78d7e6e331b8c6bb2d5283e06aa26883ca7c Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Mon, 12 Dec 2022 16:03:12 -0800 Subject: [PATCH 06/10] Updating version.json and repo version numbers to: 21.12 --- Protobuf-C++.podspec | 2 +- Protobuf.podspec | 2 +- configure.ac | 2 +- csharp/Google.Protobuf.Tools.nuspec | 2 +- .../Google.Protobuf/Google.Protobuf.csproj | 2 +- java/README.md | 6 +++--- java/bom/pom.xml | 2 +- java/core/pom.xml | 2 +- java/kotlin-lite/pom.xml | 2 +- java/kotlin/pom.xml | 2 +- java/lite.md | 2 +- java/lite/pom.xml | 2 +- java/pom.xml | 2 +- java/util/pom.xml | 2 +- php/ext/google/protobuf/protobuf.h | 2 +- protobuf_version.bzl | 8 ++++---- protoc-artifacts/pom.xml | 2 +- python/google/protobuf/__init__.py | 2 +- ruby/google-protobuf.gemspec | 2 +- ruby/pom.xml | 4 ++-- src/Makefile.am | 2 +- src/google/protobuf/any.pb.h | 2 +- src/google/protobuf/api.pb.h | 2 +- src/google/protobuf/compiler/plugin.pb.h | 2 +- src/google/protobuf/descriptor.pb.h | 2 +- src/google/protobuf/duration.pb.h | 2 +- src/google/protobuf/empty.pb.h | 2 +- src/google/protobuf/field_mask.pb.h | 2 +- src/google/protobuf/port_def.inc | 2 +- src/google/protobuf/source_context.pb.h | 2 +- src/google/protobuf/struct.pb.h | 2 +- src/google/protobuf/stubs/common.h | 2 +- src/google/protobuf/timestamp.pb.h | 2 +- src/google/protobuf/type.pb.h | 2 +- src/google/protobuf/wrappers.pb.h | 2 +- version.json | 20 +++++++++---------- 36 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Protobuf-C++.podspec b/Protobuf-C++.podspec index 0c61573c4a..43a32132d0 100644 --- a/Protobuf-C++.podspec +++ b/Protobuf-C++.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Protobuf-C++' - s.version = '3.21.11' + s.version = '3.21.12' s.summary = 'Protocol Buffers v3 runtime library for C++.' s.homepage = 'https://github.com/google/protobuf' s.license = 'BSD-3-Clause' diff --git a/Protobuf.podspec b/Protobuf.podspec index 9f9df1577c..ebb533d2f4 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '3.21.11' + s.version = '3.21.12' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/protocolbuffers/protobuf' s.license = 'BSD-3-Clause' diff --git a/configure.ac b/configure.ac index 517b497222..7243fd3118 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ AC_PREREQ(2.59) # In the SVN trunk, the version should always be the next anticipated release # version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed # the size of one file name in the dist tarfile over the 99-char limit.) -AC_INIT([Protocol Buffers],[3.21.11],[protobuf@googlegroups.com],[protobuf]) +AC_INIT([Protocol Buffers],[3.21.12],[protobuf@googlegroups.com],[protobuf]) AM_MAINTAINER_MODE([enable]) diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index 8f1bf8bbcf..d74008a1c0 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Google Protocol Buffers tools Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.21.11 + 3.21.12 Google Inc. protobuf-packages https://github.com/protocolbuffers/protobuf/blob/main/LICENSE diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index 8ebc31e91c..3c42b9e92a 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -4,7 +4,7 @@ C# runtime library for Protocol Buffers - Google's data interchange format. Copyright 2015, Google Inc. Google Protocol Buffers - 3.21.11 + 3.21.12 7.2 Google Inc. diff --git a/java/README.md b/java/README.md index 1b0ac91b5c..5df8114b7d 100644 --- a/java/README.md +++ b/java/README.md @@ -23,7 +23,7 @@ If you are using Maven, use the following: com.google.protobuf protobuf-java - 3.21.11 + 3.21.12 ``` @@ -37,7 +37,7 @@ protobuf-java-util package: com.google.protobuf protobuf-java-util - 3.21.11 + 3.21.12 ``` @@ -45,7 +45,7 @@ protobuf-java-util package: If you are using Gradle, add the following to your `build.gradle` file's dependencies: ``` - implementation 'com.google.protobuf:protobuf-java:3.21.11' + implementation 'com.google.protobuf:protobuf-java:3.21.12' ``` Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using. diff --git a/java/bom/pom.xml b/java/bom/pom.xml index eaec5aaf55..31816764bf 100644 --- a/java/bom/pom.xml +++ b/java/bom/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-bom - 3.21.11 + 3.21.12 pom Protocol Buffers [BOM] diff --git a/java/core/pom.xml b/java/core/pom.xml index 79e75c9a81..83b7351f7e 100644 --- a/java/core/pom.xml +++ b/java/core/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.11 + 3.21.12 protobuf-java diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml index 18a134c702..50dcc8340b 100644 --- a/java/kotlin-lite/pom.xml +++ b/java/kotlin-lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.11 + 3.21.12 protobuf-kotlin-lite diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml index ab24dda087..9cc9ea0323 100644 --- a/java/kotlin/pom.xml +++ b/java/kotlin/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.11 + 3.21.12 protobuf-kotlin diff --git a/java/lite.md b/java/lite.md index 9a6adcb861..ad920792f3 100644 --- a/java/lite.md +++ b/java/lite.md @@ -29,7 +29,7 @@ protobuf Java Lite runtime. If you are using Maven, include the following: com.google.protobuf protobuf-javalite - 3.21.11 + 3.21.12 ``` diff --git a/java/lite/pom.xml b/java/lite/pom.xml index e394118607..367cd7aa59 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.11 + 3.21.12 protobuf-javalite diff --git a/java/pom.xml b/java/pom.xml index 16c6715ec2..863d07f869 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.11 + 3.21.12 pom Protocol Buffers [Parent] diff --git a/java/util/pom.xml b/java/util/pom.xml index 05f7b97c7e..c13df651c8 100644 --- a/java/util/pom.xml +++ b/java/util/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.21.11 + 3.21.12 protobuf-java-util diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 616ab68566..efbd45eac0 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -127,7 +127,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() -#define PHP_PROTOBUF_VERSION "3.21.11" +#define PHP_PROTOBUF_VERSION "3.21.12" // ptr -> PHP object cache. This is a weak map that caches lazily-created // wrapper objects around upb types: diff --git a/protobuf_version.bzl b/protobuf_version.bzl index 20c8577813..4ac031cb3b 100644 --- a/protobuf_version.bzl +++ b/protobuf_version.bzl @@ -1,4 +1,4 @@ -PROTOC_VERSION = "21.11" -PROTOBUF_JAVA_VERSION = "3.21.11" -PROTOBUF_PYTHON_VERSION = "4.21.11" -PROTOBUF_PHP_VERSION = "3.21.11" +PROTOC_VERSION = "21.12" +PROTOBUF_JAVA_VERSION = "3.21.12" +PROTOBUF_PYTHON_VERSION = "4.21.12" +PROTOBUF_PHP_VERSION = "3.21.12" diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml index af9b177d38..9d4c7f24f5 100644 --- a/protoc-artifacts/pom.xml +++ b/protoc-artifacts/pom.xml @@ -8,7 +8,7 @@ com.google.protobuf protoc - 3.21.11 + 3.21.12 pom Protobuf Compiler diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py index 7c66e4e207..e7555ee101 100644 --- a/python/google/protobuf/__init__.py +++ b/python/google/protobuf/__init__.py @@ -30,4 +30,4 @@ # Copyright 2007 Google Inc. All Rights Reserved. -__version__ = '4.21.11' +__version__ = '4.21.12' diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index dbfb04d7a1..a925fdcd04 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.21.11" + s.version = "3.21.12" git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag s.licenses = ["BSD-3-Clause"] s.summary = "Protocol Buffers" diff --git a/ruby/pom.xml b/ruby/pom.xml index 537a504446..68dadacfb0 100644 --- a/ruby/pom.xml +++ b/ruby/pom.xml @@ -9,7 +9,7 @@ com.google.protobuf.jruby protobuf-jruby - 3.21.11 + 3.21.12 Protocol Buffer JRuby native extension Protocol Buffers are a way of encoding structured data in an efficient yet @@ -76,7 +76,7 @@ com.google.protobuf protobuf-java-util - 3.21.11 + 3.21.12 org.jruby diff --git a/src/Makefile.am b/src/Makefile.am index c5087f57e3..f48f7d44df 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ else PTHREAD_DEF = endif -PROTOBUF_VERSION = 32:11:0 +PROTOBUF_VERSION = 32:12:0 if GCC # Turn on all warnings except for sign comparison (we ignore sign comparison diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index c35eaddaeb..2c0605267c 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index 36f480c83d..2c4548920b 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 0c3c5b4e0c..5f3fa52cd1 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index f40e966543..9ae046ab11 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h index 0794e0af76..a5272c8114 100644 --- a/src/google/protobuf/duration.pb.h +++ b/src/google/protobuf/duration.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h index 1dfbb1d2a0..bcb647863e 100644 --- a/src/google/protobuf/empty.pb.h +++ b/src/google/protobuf/empty.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h index 27cbd7fab1..8f90e4c04f 100644 --- a/src/google/protobuf/field_mask.pb.h +++ b/src/google/protobuf/field_mask.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index 2680acdbd5..6c6aa1834b 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc @@ -178,7 +178,7 @@ #ifdef PROTOBUF_VERSION #error PROTOBUF_VERSION was previously defined #endif -#define PROTOBUF_VERSION 3021011 +#define PROTOBUF_VERSION 3021012 #ifdef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC #error PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC was previously defined diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h index 833c1e735d..63e7d113cd 100644 --- a/src/google/protobuf/source_context.pb.h +++ b/src/google/protobuf/source_context.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h index 57e955c84e..002aa85dc1 100644 --- a/src/google/protobuf/struct.pb.h +++ b/src/google/protobuf/struct.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index c4e6f48fdf..0b9fa812da 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -82,7 +82,7 @@ namespace internal { // The current version, represented as a single integer to make comparison // easier: major * 10^6 + minor * 10^3 + micro -#define GOOGLE_PROTOBUF_VERSION 3021011 +#define GOOGLE_PROTOBUF_VERSION 3021012 // A suffix string for alpha, beta or rc releases. Empty for stable releases. #define GOOGLE_PROTOBUF_VERSION_SUFFIX "" diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h index 44c53e97de..540194bc8e 100644 --- a/src/google/protobuf/timestamp.pb.h +++ b/src/google/protobuf/timestamp.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index f152a8d95b..cb8105a423 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index 4270adfafa..0f4b8350b2 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3021011 < PROTOBUF_MIN_PROTOC_VERSION +#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/version.json b/version.json index d134b24033..fad4094f39 100644 --- a/version.json +++ b/version.json @@ -1,17 +1,17 @@ { "21.x": { - "protoc_version": "21.12-dev", + "protoc_version": "21.12", "lts": false, - "date": "2022-12-08", + "date": "2022-12-12", "languages": { - "cpp": "3.21.12-dev", - "csharp": "3.21.12-dev", - "java": "3.21.12-dev", - "javascript": "3.21.12-dev", - "objectivec": "3.21.12-dev", - "php": "3.21.12-dev", - "python": "4.21.12-dev", - "ruby": "3.21.12-dev" + "cpp": "3.21.12", + "csharp": "3.21.12", + "java": "3.21.12", + "javascript": "3.21.12", + "objectivec": "3.21.12", + "php": "3.21.12", + "python": "4.21.12", + "ruby": "3.21.12" } } } \ No newline at end of file From f4afdc712ee8e8d734516c9d411ed0c0ab608dd9 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Tue, 13 Dec 2022 11:23:52 -0800 Subject: [PATCH 07/10] cherry-pick: kokoro git config --- kokoro/release/collect_all_artifacts.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kokoro/release/collect_all_artifacts.sh b/kokoro/release/collect_all_artifacts.sh index 6e0d152408..49249d758f 100755 --- a/kokoro/release/collect_all_artifacts.sh +++ b/kokoro/release/collect_all_artifacts.sh @@ -6,6 +6,7 @@ set -ex cd $(dirname $0)/../.. # Initialize any submodules. +git config --global --add safe.directory '*' git submodule update --init --recursive # The directory with all resulting artifacts From d9c9fc74542f1f41286502b2d82d43c036f092ae Mon Sep 17 00:00:00 2001 From: Matt Kulukundis Date: Tue, 13 Dec 2022 17:07:15 -0500 Subject: [PATCH 08/10] Updating changelog --- CHANGES.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index cf6a74db8f..5dd6f2ea7c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,11 @@ +2022-12-13 version 21.12 (C++/Java/Python/PHP/Objective-C/C#/Ruby) + + Python + * Fix broken enum ranges (#11171) + * Stop requiring extension fields to have a sythetic oneof (#11091) + * Python runtime 4.21.10 not works generated code can not load valid proto. + (#11171) + 2022-12-07 version 21.11 (C++/Java/Python/PHP/Objective-C/C#/Ruby) Python * Add license file to pypi wheels (#10936) From 9de5cdda66789debd24557a9fc6fb847af99c13a Mon Sep 17 00:00:00 2001 From: Mike Kruskal <62662355+mkruskal-google@users.noreply.github.com> Date: Thu, 15 Dec 2022 10:02:46 -0800 Subject: [PATCH 09/10] Point python setup to zlib after mac update (#11315) * Manually install zlib after mac update * Point pyenv at homebrew's zlib --- kokoro/macos/prepare_build_macos_rc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kokoro/macos/prepare_build_macos_rc b/kokoro/macos/prepare_build_macos_rc index 7a150c79fb..d9677e966b 100755 --- a/kokoro/macos/prepare_build_macos_rc +++ b/kokoro/macos/prepare_build_macos_rc @@ -26,7 +26,6 @@ export CXX=g++ ## # Install Python 2 by default - eval "$(pyenv init -)" pyenv install -v -s 2.7.18 && pyenv global 2.7.18 @@ -34,6 +33,9 @@ pyenv install -v -s 2.7.18 && pyenv global 2.7.18 # Install Tox if [[ "${KOKORO_INSTALL_TOX:-}" == "yes" ]] ; then + # pyenv needs to be directed towards its dependencies. + CFLAGS="-I$(brew --prefix zlib)/include" \ + LDFLAGS="-L$(brew --prefix zlib)/lib" \ pyenv install -v -s 3.7.13 pyenv global 3.7.13 sudo python -m pip install --upgrade pip 'tox==3.27.1' tox-pyenv From 4d991033c365f3a145dd2164a5a71f67bf995af9 Mon Sep 17 00:00:00 2001 From: Matt Kulukundis Date: Fri, 16 Dec 2022 12:22:20 -0500 Subject: [PATCH 10/10] Update version.json to: 21.13-dev --- version.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/version.json b/version.json index fad4094f39..27f5e48990 100644 --- a/version.json +++ b/version.json @@ -1,17 +1,17 @@ { "21.x": { - "protoc_version": "21.12", + "protoc_version": "21.13-dev", "lts": false, - "date": "2022-12-12", + "date": "2022-12-16", "languages": { - "cpp": "3.21.12", - "csharp": "3.21.12", - "java": "3.21.12", - "javascript": "3.21.12", - "objectivec": "3.21.12", - "php": "3.21.12", - "python": "4.21.12", - "ruby": "3.21.12" + "cpp": "3.21.13-dev", + "csharp": "3.21.13-dev", + "java": "3.21.13-dev", + "javascript": "3.21.13-dev", + "objectivec": "3.21.13-dev", + "php": "3.21.13-dev", + "python": "4.21.13-dev", + "ruby": "3.21.13-dev" } } } \ No newline at end of file