diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index e097674e21..eabee0602a 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -2,10 +2,9 @@ #include "php-upb.h" /* - * This is where we define macros used across upb. + * This is where we define internal portability macros used across upb. * - * All of these macros are undef'd in port_undef.inc to avoid leaking them to - * users. + * All of these macros are undef'd in undef.inc to avoid leaking them to users. * * The correct usage is: * @@ -13,13 +12,13 @@ * #include "upb/baz.h" * * // MUST be last included header. - * #include "upb/port_def.inc" + * #include "upb/port/def.inc" * * // Code for this file. * // <...> * * // Can be omitted for .c files, required for .h. - * #include "upb/port_undef.inc" + * #include "upb/port/undef.inc" * * This file is private and must not be included by users! */ @@ -44,6 +43,7 @@ #include #include #include +#include #if UINTPTR_MAX == 0xffffffff #define UPB_SIZE(size32, size64) size32 @@ -56,11 +56,6 @@ */ #define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) -#define UPB_READ_ONEOF(msg, fieldtype, offset, case_offset, case_val, default) \ - *UPB_PTR_AT(msg, case_offset, int) == case_val \ - ? *UPB_PTR_AT(msg, offset, fieldtype) \ - : default - #define UPB_WRITE_ONEOF(msg, fieldtype, offset, value, case_offset, case_val) \ *UPB_PTR_AT(msg, case_offset, int) = case_val; \ *UPB_PTR_AT(msg, offset, fieldtype) = value; @@ -82,16 +77,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)) @@ -114,8 +109,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() @@ -269,43 +263,56 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #endif +#include +#include +#include +#include +#include + // Must be last. -const char* upb_BufToUint64(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) { - return NULL; // integer overflow - } - u64 *= 10; - u64 += ch; - ptr++; - } +void upb_Status_Clear(upb_Status* status) { + if (!status) return; + status->ok = true; + status->msg[0] = '\0'; +} - *val = u64; - return ptr; +bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } + +const char* upb_Status_ErrorMessage(const upb_Status* status) { + return status->msg; } -const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, - bool* is_neg) { - bool neg = false; - uint64_t u64; +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'; +} - if (ptr != end && *ptr == '-') { - ptr++; - neg = true; - } +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); +} - ptr = upb_BufToUint64(ptr, end, &u64); - if (!ptr || u64 > (uint64_t)INT64_MAX + neg) { - return NULL; // integer overflow - } +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'; +} - *val = neg ? -u64 : u64; - if (is_neg) *is_neg = neg; - return ptr; +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'; } #include @@ -497,6 +504,18 @@ bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { return _upb_Map_Delete(map, &key, map->key_size); } +bool upb_Map_Next(const upb_Map* map, upb_MessageValue* key, + upb_MessageValue* val, size_t* iter) { + upb_StringView k; + upb_value v; + const bool ok = upb_strtable_next2(&map->table, &k, &v, (intptr_t*)iter); + if (ok) { + _upb_map_fromkey(k, key, map->key_size); + _upb_map_fromvalue(v, val, map->val_size); + } + return ok; +} + bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { return _upb_map_next(map, iter); } @@ -509,7 +528,7 @@ bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { return upb_strtable_done(&i); } -/* Returns the key and value for this entry of the map. */ +// 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; @@ -528,8 +547,18 @@ upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { return ret; } -/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue - * value); */ +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +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; +} // Must be last. @@ -614,7 +643,7 @@ bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, // Grow s->entries if necessary. if (sorted->end > s->cap) { - s->cap = _upb_Log2CeilingSize(sorted->end); + s->cap = upb_Log2CeilingSize(sorted->end); s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); if (!s->entries) return false; } @@ -649,21 +678,21 @@ bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, #include -static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_FileDescriptorSet_submsgs[1] = { {.submsg = &google_protobuf_FileDescriptorProto_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { - {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FileDescriptorSet__fields[1] = { + {1, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FileDescriptorSet_msg_init = { &google_protobuf_FileDescriptorSet_submsgs[0], &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, + 8, 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { +static const upb_MiniTableSub google_protobuf_FileDescriptorProto_submsgs[6] = { {.submsg = &google_protobuf_DescriptorProto_msg_init}, {.submsg = &google_protobuf_EnumDescriptorProto_msg_init}, {.submsg = &google_protobuf_ServiceDescriptorProto_msg_init}, @@ -672,20 +701,20 @@ static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = {.submsg = &google_protobuf_SourceCodeInfo_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[13] = { - {1, UPB_SIZE(40, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(48, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 40), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 48), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(12, 56), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(16, 64), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(20, 72), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(24, 80), UPB_SIZE(3, 3), 4, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(28, 88), UPB_SIZE(4, 4), 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(32, 96), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {11, UPB_SIZE(36, 104), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {12, UPB_SIZE(56, 112), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {13, UPB_SIZE(64, 128), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FileDescriptorProto__fields[13] = { + {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(48, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 40), 0, kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 48), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(12, 56), 0, 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(16, 64), 0, 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(20, 72), 0, 3, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(24, 80), 3, 4, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(28, 88), 4, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(32, 96), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(36, 104), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {12, UPB_SIZE(56, 112), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {13, UPB_SIZE(64, 128), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FileDescriptorProto_msg_init = { @@ -694,7 +723,7 @@ const upb_MiniTable google_protobuf_FileDescriptorProto_msg_init = { UPB_SIZE(72, 144), 13, kUpb_ExtMode_NonExtendable, 13, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[8] = { +static const upb_MiniTableSub google_protobuf_DescriptorProto_submsgs[8] = { {.submsg = &google_protobuf_FieldDescriptorProto_msg_init}, {.submsg = &google_protobuf_DescriptorProto_msg_init}, {.submsg = &google_protobuf_EnumDescriptorProto_msg_init}, @@ -705,17 +734,17 @@ static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[8] = { {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(40, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 32), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 48), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(20, 56), UPB_SIZE(0, 0), 4, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(24, 64), UPB_SIZE(2, 2), 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 72), UPB_SIZE(0, 0), 6, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(32, 80), UPB_SIZE(0, 0), 7, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(36, 88), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_DescriptorProto__fields[10] = { + {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 24), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 32), 0, 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(12, 40), 0, 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(16, 48), 0, 3, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(20, 56), 0, 4, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(24, 64), 2, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(28, 72), 0, 6, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(32, 80), 0, 7, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(36, 88), 0, kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_DescriptorProto_msg_init = { @@ -724,14 +753,14 @@ const upb_MiniTable google_protobuf_DescriptorProto_msg_init = { UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { {.submsg = &google_protobuf_ExtensionRangeOptions_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { + {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msg_init = { @@ -740,49 +769,49 @@ const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msg_init = { UPB_SIZE(16, 24), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, }; -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)}, +static const upb_MiniTableField google_protobuf_DescriptorProto_ReservedRange__fields[2] = { + {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msg_init = { NULL, &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, + 16, 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_ExtensionRangeOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_ExtensionRangeOptions__fields[1] = { + {999, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_ExtensionRangeOptions_msg_init = { &google_protobuf_ExtensionRangeOptions_submsgs[0], &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, + 8, 1, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { +static const upb_MiniTableSub google_protobuf_FieldDescriptorProto_submsgs[3] = { {.subenum = &google_protobuf_FieldDescriptorProto_Label_enum_init}, {.subenum = &google_protobuf_FieldDescriptorProto_Type_enum_init}, {.submsg = &google_protobuf_FieldOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(28, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(36, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(44, 56), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(52, 72), UPB_SIZE(7, 7), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(16, 88), UPB_SIZE(8, 8), 2, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(20, 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_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {17, UPB_SIZE(24, 20), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FieldDescriptorProto__fields[11] = { + {1, UPB_SIZE(28, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(36, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, 4, 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, 8, 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(44, 56), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(52, 72), 7, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(16, 88), 8, 2, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(20, 16), 9, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(60, 96), 10, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(24, 20), 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FieldDescriptorProto_msg_init = { @@ -791,13 +820,13 @@ const upb_MiniTable google_protobuf_FieldDescriptorProto_msg_init = { UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_OneofDescriptorProto_submsgs[1] = { {.submsg = &google_protobuf_OneofOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(8, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 24), UPB_SIZE(2, 2), 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_OneofDescriptorProto__fields[2] = { + {1, 8, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_OneofDescriptorProto_msg_init = { @@ -806,18 +835,18 @@ const upb_MiniTable google_protobuf_OneofDescriptorProto_msg_init = { UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { +static const upb_MiniTableSub google_protobuf_EnumDescriptorProto_submsgs[3] = { {.submsg = &google_protobuf_EnumValueDescriptorProto_msg_init}, {.submsg = &google_protobuf_EnumOptions_msg_init}, {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(20, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 48), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_EnumDescriptorProto__fields[5] = { + {1, UPB_SIZE(20, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 24), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(12, 40), 0, 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(16, 48), 0, kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumDescriptorProto_msg_init = { @@ -826,25 +855,25 @@ const upb_MiniTable google_protobuf_EnumDescriptorProto_msg_init = { UPB_SIZE(32, 56), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, }; -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)}, +static const upb_MiniTableField google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { + {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init = { NULL, &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, + 16, 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { {.submsg = &google_protobuf_EnumValueOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(12, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(8, 24), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_EnumValueDescriptorProto__fields[3] = { + {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, 4, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msg_init = { @@ -853,15 +882,15 @@ const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msg_init = { UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { +static const upb_MiniTableSub google_protobuf_ServiceDescriptorProto_submsgs[2] = { {.submsg = &google_protobuf_MethodDescriptorProto_msg_init}, {.submsg = &google_protobuf_ServiceOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(12, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_ServiceDescriptorProto__fields[3] = { + {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 24), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_ServiceDescriptorProto_msg_init = { @@ -870,17 +899,17 @@ const upb_MiniTable google_protobuf_ServiceDescriptorProto_msg_init = { UPB_SIZE(24, 40), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_MethodDescriptorProto_submsgs[1] = { {.submsg = &google_protobuf_MethodOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(12, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(20, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(28, 40), UPB_SIZE(3, 3), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(4, 56), UPB_SIZE(4, 4), 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(8, 1), UPB_SIZE(5, 5), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(9, 2), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_MethodDescriptorProto__fields[6] = { + {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(20, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(28, 40), 3, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(4, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(8, 1), 5, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(9, 2), 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_MethodDescriptorProto_msg_init = { @@ -889,33 +918,33 @@ const upb_MiniTable google_protobuf_MethodDescriptorProto_msg_init = { UPB_SIZE(40, 64), 6, kUpb_ExtMode_NonExtendable, 6, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { +static const upb_MiniTableSub google_protobuf_FileOptions_submsgs[2] = { {.subenum = &google_protobuf_FileOptions_OptimizeMode_enum_init}, {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(24, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(32, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(40, 56), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(48, 72), UPB_SIZE(13, 13), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {37, UPB_SIZE(56, 88), UPB_SIZE(14, 14), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {39, UPB_SIZE(64, 104), UPB_SIZE(15, 15), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {40, UPB_SIZE(72, 120), UPB_SIZE(16, 16), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {41, UPB_SIZE(80, 136), UPB_SIZE(17, 17), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(88, 152), UPB_SIZE(19, 19), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {45, UPB_SIZE(96, 168), UPB_SIZE(20, 20), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(20, 184), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FileOptions__fields[21] = { + {1, 24, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(32, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {9, 4, 3, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, 8, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {16, 9, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, 10, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {18, 11, 8, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {20, 12, 9, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {23, 13, 10, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {27, 14, 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {31, 15, 12, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {36, UPB_SIZE(48, 72), 13, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {37, UPB_SIZE(56, 88), 14, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {39, UPB_SIZE(64, 104), 15, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {40, UPB_SIZE(72, 120), 16, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {41, UPB_SIZE(80, 136), 17, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {42, 16, 18, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {44, UPB_SIZE(88, 152), 19, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {45, UPB_SIZE(96, 168), 20, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 184), 0, 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FileOptions_msg_init = { @@ -924,39 +953,39 @@ const upb_MiniTable google_protobuf_FileOptions_msg_init = { UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_MessageOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_MessageOptions__fields[5] = { + {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 3, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, 4, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, 8, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_MessageOptions_msg_init = { &google_protobuf_MessageOptions_submsgs[0], &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(16, 16), 5, kUpb_ExtMode_Extendable, 3, 255, 0, + 16, 5, kUpb_ExtMode_Extendable, 3, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { +static const upb_MiniTableSub google_protobuf_FieldOptions_submsgs[3] = { {.subenum = &google_protobuf_FieldOptions_CType_enum_init}, {.subenum = &google_protobuf_FieldOptions_JSType_enum_init}, {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FieldOptions__fields[8] = { + {1, 4, 1, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 8, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 9, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {5, 10, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, 16, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {15, 17, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), 0, 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FieldOptions_msg_init = { @@ -965,28 +994,28 @@ const upb_MiniTable google_protobuf_FieldOptions_msg_init = { UPB_SIZE(24, 32), 8, kUpb_ExtMode_Extendable, 3, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_OneofOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_OneofOptions__fields[1] = { + {999, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_OneofOptions_msg_init = { &google_protobuf_OneofOptions_submsgs[0], &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, + 8, 1, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_EnumOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_EnumOptions__fields[3] = { + {2, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumOptions_msg_init = { @@ -995,13 +1024,13 @@ const upb_MiniTable google_protobuf_EnumOptions_msg_init = { UPB_SIZE(8, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_EnumValueOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_EnumValueOptions__fields[2] = { + {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumValueOptions_msg_init = { @@ -1010,13 +1039,13 @@ const upb_MiniTable google_protobuf_EnumValueOptions_msg_init = { UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 1, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_ServiceOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_ServiceOptions__fields[2] = { + {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_ServiceOptions_msg_init = { @@ -1025,35 +1054,35 @@ const upb_MiniTable google_protobuf_ServiceOptions_msg_init = { UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { +static const upb_MiniTableSub google_protobuf_MethodOptions_submsgs[2] = { {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enum_init}, {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_MethodOptions__fields[3] = { + {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, 4, 2, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {999, 8, 0, 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_MethodOptions_msg_init = { &google_protobuf_MethodOptions_submsgs[0], &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(16, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, + 16, 3, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_UninterpretedOption_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_NamePart_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { - {2, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 16), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(16, 32), UPB_SIZE(2, 2), kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(24, 40), UPB_SIZE(3, 3), kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(32, 48), UPB_SIZE(4, 4), kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(40, 56), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(48, 72), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_UninterpretedOption__fields[7] = { + {2, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 16), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(16, 32), 2, kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 40), 3, kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(32, 48), 4, kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(48, 72), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_UninterpretedOption_msg_init = { @@ -1062,9 +1091,9 @@ const upb_MiniTable google_protobuf_UninterpretedOption_msg_init = { 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_LabelFlags_IsAlternate | (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)}, +static const upb_MiniTableField google_protobuf_UninterpretedOption_NamePart__fields[2] = { + {1, UPB_SIZE(4, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, 1, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msg_init = { @@ -1073,26 +1102,26 @@ const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msg_init = { UPB_SIZE(16, 24), 2, kUpb_ExtMode_NonExtendable, 2, 255, 2, }; -static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_SourceCodeInfo_submsgs[1] = { {.submsg = &google_protobuf_SourceCodeInfo_Location_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_SourceCodeInfo__fields[1] = { + {1, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_SourceCodeInfo_msg_init = { &google_protobuf_SourceCodeInfo_submsgs[0], &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, + 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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(16, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(24, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(12, 56), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_SourceCodeInfo_Location__fields[5] = { + {1, UPB_SIZE(4, 8), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 16), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(24, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(12, 56), 0, kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msg_init = { @@ -1101,30 +1130,30 @@ const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msg_init = { UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 4, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_GeneratedCodeInfo_submsgs[1] = { {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_GeneratedCodeInfo__fields[1] = { + {1, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_GeneratedCodeInfo_msg_init = { &google_protobuf_GeneratedCodeInfo_submsgs[0], &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, + 8, 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_Annotation_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_GeneratedCodeInfo_Annotation_submsgs[1] = { {.subenum = &google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init}, }; -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[5] = { - {1, UPB_SIZE(4, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(20, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 8), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 12), UPB_SIZE(4, 4), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_GeneratedCodeInfo_Annotation__fields[5] = { + {1, UPB_SIZE(4, 16), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(20, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 4), 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(12, 8), 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(16, 12), 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msg_init = { @@ -1163,7 +1192,7 @@ static const upb_MiniTable *messages_layout[27] = { &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, }; -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init = { +const upb_MiniTableEnum google_protobuf_FieldDescriptorProto_Type_enum_init = { 64, 0, { @@ -1172,7 +1201,7 @@ const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init = { }, }; -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init = { +const upb_MiniTableEnum google_protobuf_FieldDescriptorProto_Label_enum_init = { 64, 0, { @@ -1181,7 +1210,7 @@ const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init = }, }; -const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init = { +const upb_MiniTableEnum google_protobuf_FileOptions_OptimizeMode_enum_init = { 64, 0, { @@ -1190,7 +1219,7 @@ const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init = { }, }; -const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init = { +const upb_MiniTableEnum google_protobuf_FieldOptions_CType_enum_init = { 64, 0, { @@ -1199,7 +1228,7 @@ const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init = { }, }; -const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init = { +const upb_MiniTableEnum google_protobuf_FieldOptions_JSType_enum_init = { 64, 0, { @@ -1208,7 +1237,7 @@ const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init = { }, }; -const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_init = { +const upb_MiniTableEnum google_protobuf_MethodOptions_IdempotencyLevel_enum_init = { 64, 0, { @@ -1217,7 +1246,7 @@ const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_ini }, }; -const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init = { +const upb_MiniTableEnum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init = { 64, 0, { @@ -1226,7 +1255,7 @@ const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_e }, }; -static const upb_MiniTable_Enum *enums_layout[7] = { +static const upb_MiniTableEnum *enums_layout[7] = { &google_protobuf_FieldDescriptorProto_Type_enum_init, &google_protobuf_FieldDescriptorProto_Label_enum_init, &google_protobuf_FileOptions_OptimizeMode_enum_init, @@ -1236,7 +1265,7 @@ static const upb_MiniTable_Enum *enums_layout[7] = { &google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init, }; -const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { +const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout = { messages_layout, enums_layout, NULL, @@ -1255,319 +1284,319 @@ const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { * regenerated. */ -static const char descriptor[7820] = {'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p', -'t', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\017', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', -'f', '\"', 'M', '\n', '\021', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'S', 'e', 't', '\022', '8', '\n', -'\004', 'f', 'i', 'l', 'e', '\030', '\001', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', -'o', 'b', 'u', 'f', '.', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', -'\004', 'f', 'i', 'l', 'e', '\"', '\376', '\004', '\n', '\023', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', -'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', -'\030', '\n', '\007', 'p', 'a', 'c', 'k', 'a', 'g', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 'p', 'a', 'c', 'k', 'a', 'g', 'e', -'\022', '\036', '\n', '\n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\n', 'd', 'e', 'p', -'e', 'n', 'd', 'e', 'n', 'c', 'y', '\022', '+', '\n', '\021', 'p', 'u', 'b', 'l', 'i', 'c', '_', 'd', 'e', 'p', 'e', 'n', 'd', 'e', -'n', 'c', 'y', '\030', '\n', ' ', '\003', '(', '\005', 'R', '\020', 'p', 'u', 'b', 'l', 'i', 'c', 'D', 'e', 'p', 'e', 'n', 'd', 'e', 'n', -'c', 'y', '\022', '\'', '\n', '\017', 'w', 'e', 'a', 'k', '_', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\030', '\013', ' ', '\003', -'(', '\005', 'R', '\016', 'w', 'e', 'a', 'k', 'D', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\022', 'C', '\n', '\014', 'm', 'e', 's', -'s', 'a', 'g', 'e', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\003', '(', '\013', '2', ' ', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', -'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', -'\013', 'm', 'e', 's', 's', 'a', 'g', 'e', 'T', 'y', 'p', 'e', '\022', 'A', '\n', '\t', 'e', 'n', 'u', 'm', '_', 't', 'y', 'p', 'e', -'\030', '\005', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', -'E', 'n', 'u', 'm', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\010', 'e', 'n', 'u', 'm', -'T', 'y', 'p', 'e', '\022', 'A', '\n', '\007', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\030', '\006', ' ', '\003', '(', '\013', '2', '\'', '.', 'g', -'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'D', 'e', 's', -'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\007', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 'C', '\n', '\t', -'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\007', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', -'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', -'r', 'o', 't', 'o', 'R', '\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', '6', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', -'s', '\030', '\010', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', -'.', 'F', 'i', 'l', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', 'I', '\n', '\020', -'s', 'o', 'u', 'r', 'c', 'e', '_', 'c', 'o', 'd', 'e', '_', 'i', 'n', 'f', 'o', '\030', '\t', ' ', '\001', '(', '\013', '2', '\037', '.', -'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', -'e', 'I', 'n', 'f', 'o', 'R', '\016', 's', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '\022', '\026', '\n', '\006', -'s', 'y', 'n', 't', 'a', 'x', '\030', '\014', ' ', '\001', '(', '\t', 'R', '\006', 's', 'y', 'n', 't', 'a', 'x', '\022', '\030', '\n', '\007', 'e', -'d', 'i', 't', 'i', 'o', 'n', '\030', '\r', ' ', '\001', '(', '\t', 'R', '\007', 'e', 'd', 'i', 't', 'i', 'o', 'n', '\"', '\271', '\006', '\n', -'\017', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', -'\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ';', '\n', '\005', 'f', 'i', 'e', 'l', 'd', '\030', '\002', ' ', '\003', '(', -'\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', -'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\005', 'f', 'i', 'e', 'l', 'd', '\022', 'C', '\n', -'\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\006', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', -'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', -'P', 'r', 'o', 't', 'o', 'R', '\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', 'A', '\n', '\013', 'n', 'e', 's', 't', 'e', -'d', '_', 't', 'y', 'p', 'e', '\030', '\003', ' ', '\003', '(', '\013', '2', ' ', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', -'t', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\n', 'n', 'e', -'s', 't', 'e', 'd', 'T', 'y', 'p', 'e', '\022', 'A', '\n', '\t', 'e', 'n', 'u', 'm', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\003', -'(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', -'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\010', 'e', 'n', 'u', 'm', 'T', 'y', 'p', 'e', -'\022', 'X', '\n', '\017', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\005', ' ', '\003', '(', '\013', -'2', '/', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', -'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', 'R', -'\016', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', '\022', 'D', '\n', '\n', 'o', 'n', 'e', 'o', 'f', '_', -'d', 'e', 'c', 'l', '\030', '\010', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', -'b', 'u', 'f', '.', 'O', 'n', 'e', 'o', 'f', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', -'\t', 'o', 'n', 'e', 'o', 'f', 'D', 'e', 'c', 'l', '\022', '9', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\007', ' ', '\001', -'(', '\013', '2', '\037', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 's', 's', -'a', 'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', 'U', '\n', '\016', 'r', 'e', -'s', 'e', 'r', 'v', 'e', 'd', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\t', ' ', '\003', '(', '\013', '2', '.', '.', 'g', 'o', 'o', 'g', -'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', -'t', 'o', '.', 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', 'R', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', -'d', 'R', 'a', 'n', 'g', 'e', '\022', '#', '\n', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'n', 'a', 'm', 'e', '\030', '\n', -' ', '\003', '(', '\t', 'R', '\014', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'N', 'a', 'm', 'e', '\032', 'z', '\n', '\016', 'E', 'x', 't', -'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', -'\005', 'R', '\005', 's', 't', 'a', 'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', -'d', '\022', '@', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '&', '.', 'g', 'o', 'o', 'g', -'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', -'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\032', '7', '\n', '\r', 'R', 'e', 's', 'e', -'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', '\005', 'R', -'\005', 's', 't', 'a', 'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\"', -'|', '\n', '\025', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', -'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', -'\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', -'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', -'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', -'\"', '\301', '\006', '\n', '\024', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', -'\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\026', '\n', '\006', 'n', -'u', 'm', 'b', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\005', 'R', '\006', 'n', 'u', 'm', 'b', 'e', 'r', '\022', 'A', '\n', '\005', 'l', 'a', -'b', 'e', 'l', '\030', '\004', ' ', '\001', '(', '\016', '2', '+', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', -'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'L', -'a', 'b', 'e', 'l', 'R', '\005', 'l', 'a', 'b', 'e', 'l', '\022', '>', '\n', '\004', 't', 'y', 'p', 'e', '\030', '\005', ' ', '\001', '(', '\016', -'2', '*', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', -'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'T', 'y', 'p', 'e', 'R', '\004', 't', 'y', 'p', 'e', -'\022', '\033', '\n', '\t', 't', 'y', 'p', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\006', ' ', '\001', '(', '\t', 'R', '\010', 't', 'y', 'p', 'e', -'N', 'a', 'm', 'e', '\022', '\032', '\n', '\010', 'e', 'x', 't', 'e', 'n', 'd', 'e', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\010', 'e', -'x', 't', 'e', 'n', 'd', 'e', 'e', '\022', '#', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', -'\007', ' ', '\001', '(', '\t', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '\037', '\n', '\013', 'o', 'n', -'e', 'o', 'f', '_', 'i', 'n', 'd', 'e', 'x', '\030', '\t', ' ', '\001', '(', '\005', 'R', '\n', 'o', 'n', 'e', 'o', 'f', 'I', 'n', 'd', -'e', 'x', '\022', '\033', '\n', '\t', 'j', 's', 'o', 'n', '_', 'n', 'a', 'm', 'e', '\030', '\n', ' ', '\001', '(', '\t', 'R', '\010', 'j', 's', -'o', 'n', 'N', 'a', 'm', 'e', '\022', '7', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\010', ' ', '\001', '(', '\013', '2', '\035', -'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', -'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', '\'', '\n', '\017', 'p', 'r', 'o', 't', 'o', '3', '_', 'o', -'p', 't', 'i', 'o', 'n', 'a', 'l', '\030', '\021', ' ', '\001', '(', '\010', 'R', '\016', 'p', 'r', 'o', 't', 'o', '3', 'O', 'p', 't', 'i', -'o', 'n', 'a', 'l', '\"', '\266', '\002', '\n', '\004', 'T', 'y', 'p', 'e', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'D', 'O', 'U', -'B', 'L', 'E', '\020', '\001', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'F', 'L', 'O', 'A', 'T', '\020', '\002', '\022', '\016', '\n', '\n', -'T', 'Y', 'P', 'E', '_', 'I', 'N', 'T', '6', '4', '\020', '\003', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'U', 'I', 'N', 'T', -'6', '4', '\020', '\004', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'I', 'N', 'T', '3', '2', '\020', '\005', '\022', '\020', '\n', '\014', 'T', -'Y', 'P', 'E', '_', 'F', 'I', 'X', 'E', 'D', '6', '4', '\020', '\006', '\022', '\020', '\n', '\014', 'T', 'Y', 'P', 'E', '_', 'F', 'I', 'X', -'E', 'D', '3', '2', '\020', '\007', '\022', '\r', '\n', '\t', 'T', 'Y', 'P', 'E', '_', 'B', 'O', 'O', 'L', '\020', '\010', '\022', '\017', '\n', '\013', -'T', 'Y', 'P', 'E', '_', 'S', 'T', 'R', 'I', 'N', 'G', '\020', '\t', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'G', 'R', 'O', -'U', 'P', '\020', '\n', '\022', '\020', '\n', '\014', 'T', 'Y', 'P', 'E', '_', 'M', 'E', 'S', 'S', 'A', 'G', 'E', '\020', '\013', '\022', '\016', '\n', -'\n', 'T', 'Y', 'P', 'E', '_', 'B', 'Y', 'T', 'E', 'S', '\020', '\014', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'U', 'I', 'N', -'T', '3', '2', '\020', '\r', '\022', '\r', '\n', '\t', 'T', 'Y', 'P', 'E', '_', 'E', 'N', 'U', 'M', '\020', '\016', '\022', '\021', '\n', '\r', 'T', -'Y', 'P', 'E', '_', 'S', 'F', 'I', 'X', 'E', 'D', '3', '2', '\020', '\017', '\022', '\021', '\n', '\r', 'T', 'Y', 'P', 'E', '_', 'S', 'F', -'I', 'X', 'E', 'D', '6', '4', '\020', '\020', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'S', 'I', 'N', 'T', '3', '2', '\020', '\021', -'\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'S', 'I', 'N', 'T', '6', '4', '\020', '\022', '\"', 'C', '\n', '\005', 'L', 'a', 'b', 'e', -'l', '\022', '\022', '\n', '\016', 'L', 'A', 'B', 'E', 'L', '_', 'O', 'P', 'T', 'I', 'O', 'N', 'A', 'L', '\020', '\001', '\022', '\022', '\n', '\016', -'L', 'A', 'B', 'E', 'L', '_', 'R', 'E', 'Q', 'U', 'I', 'R', 'E', 'D', '\020', '\002', '\022', '\022', '\n', '\016', 'L', 'A', 'B', 'E', 'L', -'_', 'R', 'E', 'P', 'E', 'A', 'T', 'E', 'D', '\020', '\003', '\"', 'c', '\n', '\024', 'O', 'n', 'e', 'o', 'f', 'D', 'e', 's', 'c', 'r', -'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', -'\004', 'n', 'a', 'm', 'e', '\022', '7', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\035', '.', -'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'O', 'n', 'e', 'o', 'f', 'O', 'p', 't', 'i', -'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\"', '\343', '\002', '\n', '\023', 'E', 'n', 'u', 'm', 'D', 'e', 's', 'c', -'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', -'R', '\004', 'n', 'a', 'm', 'e', '\022', '?', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\003', '(', '\013', '2', ')', '.', 'g', -'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'D', -'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\005', 'v', 'a', 'l', 'u', 'e', '\022', '6', '\n', '\007', -'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', -'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', -'n', 's', '\022', ']', '\n', '\016', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\004', ' ', '\003', '(', -'\013', '2', '6', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'D', -'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'E', 'n', 'u', 'm', 'R', 'e', 's', 'e', 'r', 'v', -'e', 'd', 'R', 'a', 'n', 'g', 'e', 'R', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', '\022', '#', '\n', -'\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'n', 'a', 'm', 'e', '\030', '\005', ' ', '\003', '(', '\t', 'R', '\014', 'r', 'e', 's', -'e', 'r', 'v', 'e', 'd', 'N', 'a', 'm', 'e', '\032', ';', '\n', '\021', 'E', 'n', 'u', 'm', 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', -'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', '\005', 'R', '\005', 's', 't', 'a', -'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\"', '\203', '\001', '\n', '\030', -'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', -'\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\026', '\n', '\006', 'n', 'u', -'m', 'b', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\006', 'n', 'u', 'm', 'b', 'e', 'r', '\022', ';', '\n', '\007', 'o', 'p', 't', -'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '!', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', -'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', -'i', 'o', 'n', 's', '\"', '\247', '\001', '\n', '\026', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', -'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', -'e', '\022', '>', '\n', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\030', '\002', ' ', '\003', '(', '\013', '2', '&', '.', 'g', 'o', 'o', 'g', 'l', -'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', -'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\022', '9', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', -'s', '\030', '\003', ' ', '\001', '(', '\013', '2', '\037', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', -'.', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\"', -'\211', '\002', '\n', '\025', 'M', 'e', 't', 'h', 'o', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', -'\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\035', '\n', '\n', 'i', -'n', 'p', 'u', 't', '_', 't', 'y', 'p', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\t', 'i', 'n', 'p', 'u', 't', 'T', 'y', 'p', -'e', '\022', '\037', '\n', '\013', 'o', 'u', 't', 'p', 'u', 't', '_', 't', 'y', 'p', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\n', 'o', -'u', 't', 'p', 'u', 't', 'T', 'y', 'p', 'e', '\022', '8', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\004', ' ', '\001', '(', -'\013', '2', '\036', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', -'d', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', '0', '\n', '\020', 'c', 'l', 'i', 'e', -'n', 't', '_', 's', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\030', '\005', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', -'R', '\017', 'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\022', '0', '\n', '\020', 's', 'e', 'r', 'v', -'e', 'r', '_', 's', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\030', '\006', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', -'R', '\017', 's', 'e', 'r', 'v', 'e', 'r', 'S', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\"', '\221', '\t', '\n', '\013', 'F', 'i', 'l', -'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '!', '\n', '\014', 'j', 'a', 'v', 'a', '_', 'p', 'a', 'c', 'k', 'a', 'g', 'e', '\030', -'\001', ' ', '\001', '(', '\t', 'R', '\013', 'j', 'a', 'v', 'a', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', '0', '\n', '\024', 'j', 'a', 'v', -'a', '_', 'o', 'u', 't', 'e', 'r', '_', 'c', 'l', 'a', 's', 's', 'n', 'a', 'm', 'e', '\030', '\010', ' ', '\001', '(', '\t', 'R', '\022', -'j', 'a', 'v', 'a', 'O', 'u', 't', 'e', 'r', 'C', 'l', 'a', 's', 's', 'n', 'a', 'm', 'e', '\022', '5', '\n', '\023', 'j', 'a', 'v', -'a', '_', 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', '_', 'f', 'i', 'l', 'e', 's', '\030', '\n', ' ', '\001', '(', '\010', ':', '\005', 'f', -'a', 'l', 's', 'e', 'R', '\021', 'j', 'a', 'v', 'a', 'M', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'F', 'i', 'l', 'e', 's', '\022', 'D', -'\n', '\035', 'j', 'a', 'v', 'a', '_', 'g', 'e', 'n', 'e', 'r', 'a', 't', 'e', '_', 'e', 'q', 'u', 'a', 'l', 's', '_', 'a', 'n', -'d', '_', 'h', 'a', 's', 'h', '\030', '\024', ' ', '\001', '(', '\010', 'B', '\002', '\030', '\001', 'R', '\031', 'j', 'a', 'v', 'a', 'G', 'e', 'n', -'e', 'r', 'a', 't', 'e', 'E', 'q', 'u', 'a', 'l', 's', 'A', 'n', 'd', 'H', 'a', 's', 'h', '\022', ':', '\n', '\026', 'j', 'a', 'v', -'a', '_', 's', 't', 'r', 'i', 'n', 'g', '_', 'c', 'h', 'e', 'c', 'k', '_', 'u', 't', 'f', '8', '\030', '\033', ' ', '\001', '(', '\010', -':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\023', 'j', 'a', 'v', 'a', 'S', 't', 'r', 'i', 'n', 'g', 'C', 'h', 'e', 'c', 'k', 'U', -'t', 'f', '8', '\022', 'S', '\n', '\014', 'o', 'p', 't', 'i', 'm', 'i', 'z', 'e', '_', 'f', 'o', 'r', '\030', '\t', ' ', '\001', '(', '\016', -'2', ')', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'l', 'e', 'O', 'p', -'t', 'i', 'o', 'n', 's', '.', 'O', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'M', 'o', 'd', 'e', ':', '\005', 'S', 'P', 'E', 'E', 'D', -'R', '\013', 'o', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'F', 'o', 'r', '\022', '\035', '\n', '\n', 'g', 'o', '_', 'p', 'a', 'c', 'k', 'a', -'g', 'e', '\030', '\013', ' ', '\001', '(', '\t', 'R', '\t', 'g', 'o', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', '5', '\n', '\023', 'c', 'c', -'_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', '\020', ' ', '\001', '(', '\010', ':', '\005', -'f', 'a', 'l', 's', 'e', 'R', '\021', 'c', 'c', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', -'9', '\n', '\025', 'j', 'a', 'v', 'a', '_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', -'\021', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\023', 'j', 'a', 'v', 'a', 'G', 'e', 'n', 'e', 'r', 'i', 'c', -'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '5', '\n', '\023', 'p', 'y', '_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', -'r', 'v', 'i', 'c', 'e', 's', '\030', '\022', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\021', 'p', 'y', 'G', 'e', -'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '7', '\n', '\024', 'p', 'h', 'p', '_', 'g', 'e', 'n', 'e', -'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', '*', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', -'R', '\022', 'p', 'h', 'p', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '%', '\n', '\n', 'd', -'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\027', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', -'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '.', '\n', '\020', 'c', 'c', '_', 'e', 'n', 'a', 'b', 'l', 'e', '_', 'a', 'r', -'e', 'n', 'a', 's', '\030', '\037', ' ', '\001', '(', '\010', ':', '\004', 't', 'r', 'u', 'e', 'R', '\016', 'c', 'c', 'E', 'n', 'a', 'b', 'l', -'e', 'A', 'r', 'e', 'n', 'a', 's', '\022', '*', '\n', '\021', 'o', 'b', 'j', 'c', '_', 'c', 'l', 'a', 's', 's', '_', 'p', 'r', 'e', -'f', 'i', 'x', '\030', '$', ' ', '\001', '(', '\t', 'R', '\017', 'o', 'b', 'j', 'c', 'C', 'l', 'a', 's', 's', 'P', 'r', 'e', 'f', 'i', -'x', '\022', ')', '\n', '\020', 'c', 's', 'h', 'a', 'r', 'p', '_', 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', '%', ' ', '\001', -'(', '\t', 'R', '\017', 'c', 's', 'h', 'a', 'r', 'p', 'N', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '!', '\n', '\014', 's', 'w', -'i', 'f', 't', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\'', ' ', '\001', '(', '\t', 'R', '\013', 's', 'w', 'i', 'f', 't', 'P', 'r', -'e', 'f', 'i', 'x', '\022', '(', '\n', '\020', 'p', 'h', 'p', '_', 'c', 'l', 'a', 's', 's', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', -'(', ' ', '\001', '(', '\t', 'R', '\016', 'p', 'h', 'p', 'C', 'l', 'a', 's', 's', 'P', 'r', 'e', 'f', 'i', 'x', '\022', '#', '\n', '\r', -'p', 'h', 'p', '_', 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', ')', ' ', '\001', '(', '\t', 'R', '\014', 'p', 'h', 'p', 'N', -'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '4', '\n', '\026', 'p', 'h', 'p', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_', -'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', ',', ' ', '\001', '(', '\t', 'R', '\024', 'p', 'h', 'p', 'M', 'e', 't', 'a', 'd', -'a', 't', 'a', 'N', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '!', '\n', '\014', 'r', 'u', 'b', 'y', '_', 'p', 'a', 'c', 'k', -'a', 'g', 'e', '\030', '-', ' ', '\001', '(', '\t', 'R', '\013', 'r', 'u', 'b', 'y', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', 'X', '\n', -'\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', -'\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', -'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', -'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', ':', '\n', '\014', 'O', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'M', -'o', 'd', 'e', '\022', '\t', '\n', '\005', 'S', 'P', 'E', 'E', 'D', '\020', '\001', '\022', '\r', '\n', '\t', 'C', 'O', 'D', 'E', '_', 'S', 'I', -'Z', 'E', '\020', '\002', '\022', '\020', '\n', '\014', 'L', 'I', 'T', 'E', '_', 'R', 'U', 'N', 'T', 'I', 'M', 'E', '\020', '\003', '*', '\t', '\010', -'\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '&', '\020', '\'', '\"', '\343', '\002', '\n', '\016', 'M', 'e', 's', 's', 'a', 'g', -'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '<', '\n', '\027', 'm', 'e', 's', 's', 'a', 'g', 'e', '_', 's', 'e', 't', '_', 'w', -'i', 'r', 'e', '_', 'f', 'o', 'r', 'm', 'a', 't', '\030', '\001', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\024', -'m', 'e', 's', 's', 'a', 'g', 'e', 'S', 'e', 't', 'W', 'i', 'r', 'e', 'F', 'o', 'r', 'm', 'a', 't', '\022', 'L', '\n', '\037', 'n', -'o', '_', 's', 't', 'a', 'n', 'd', 'a', 'r', 'd', '_', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'a', 'c', 'c', -'e', 's', 's', 'o', 'r', '\030', '\002', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\034', 'n', 'o', 'S', 't', 'a', -'n', 'd', 'a', 'r', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'A', 'c', 'c', 'e', 's', 's', 'o', 'r', '\022', '%', -'\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', -'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '\033', '\n', '\t', 'm', 'a', 'p', '_', 'e', 'n', 't', 'r', 'y', -'\030', '\007', ' ', '\001', '(', '\010', 'R', '\010', 'm', 'a', 'p', 'E', 'n', 't', 'r', 'y', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', -'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', -'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', -'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', -'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '\004', '\020', '\005', 'J', '\004', -'\010', '\005', '\020', '\006', 'J', '\004', '\010', '\006', '\020', '\007', 'J', '\004', '\010', '\010', '\020', '\t', 'J', '\004', '\010', '\t', '\020', '\n', '\"', '\222', '\004', -'\n', '\014', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'A', '\n', '\005', 'c', 't', 'y', 'p', 'e', '\030', '\001', -' ', '\001', '(', '\016', '2', '#', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', -'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', 's', '.', 'C', 'T', 'y', 'p', 'e', ':', '\006', 'S', 'T', 'R', 'I', 'N', 'G', 'R', -'\005', 'c', 't', 'y', 'p', 'e', '\022', '\026', '\n', '\006', 'p', 'a', 'c', 'k', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\006', 'p', -'a', 'c', 'k', 'e', 'd', '\022', 'G', '\n', '\006', 'j', 's', 't', 'y', 'p', 'e', '\030', '\006', ' ', '\001', '(', '\016', '2', '$', '.', 'g', -'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', -'n', 's', '.', 'J', 'S', 'T', 'y', 'p', 'e', ':', '\t', 'J', 'S', '_', 'N', 'O', 'R', 'M', 'A', 'L', 'R', '\006', 'j', 's', 't', -'y', 'p', 'e', '\022', '\031', '\n', '\004', 'l', 'a', 'z', 'y', '\030', '\005', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', -'\004', 'l', 'a', 'z', 'y', '\022', '.', '\n', '\017', 'u', 'n', 'v', 'e', 'r', 'i', 'f', 'i', 'e', 'd', '_', 'l', 'a', 'z', 'y', '\030', -'\017', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\016', 'u', 'n', 'v', 'e', 'r', 'i', 'f', 'i', 'e', 'd', 'L', -'a', 'z', 'y', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', -'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '\031', '\n', '\004', 'w', 'e', 'a', 'k', -'\030', '\n', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\004', 'w', 'e', 'a', 'k', '\022', 'X', '\n', '\024', 'u', 'n', -'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', -'2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', -'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', -'t', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', '/', '\n', '\005', 'C', 'T', 'y', 'p', 'e', '\022', '\n', '\n', '\006', 'S', 'T', 'R', -'I', 'N', 'G', '\020', '\000', '\022', '\010', '\n', '\004', 'C', 'O', 'R', 'D', '\020', '\001', '\022', '\020', '\n', '\014', 'S', 'T', 'R', 'I', 'N', 'G', -'_', 'P', 'I', 'E', 'C', 'E', '\020', '\002', '\"', '5', '\n', '\006', 'J', 'S', 'T', 'y', 'p', 'e', '\022', '\r', '\n', '\t', 'J', 'S', '_', -'N', 'O', 'R', 'M', 'A', 'L', '\020', '\000', '\022', '\r', '\n', '\t', 'J', 'S', '_', 'S', 'T', 'R', 'I', 'N', 'G', '\020', '\001', '\022', '\r', -'\n', '\t', 'J', 'S', '_', 'N', 'U', 'M', 'B', 'E', 'R', '\020', '\002', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', -'\004', '\010', '\004', '\020', '\005', '\"', 's', '\n', '\014', 'O', 'n', 'e', 'o', 'f', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'X', '\n', '\024', -'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', -'(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', -'t', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', -'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\300', '\001', -'\n', '\013', 'E', 'n', 'u', 'm', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '\037', '\n', '\013', 'a', 'l', 'l', 'o', 'w', '_', 'a', 'l', -'i', 'a', 's', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\n', 'a', 'l', 'l', 'o', 'w', 'A', 'l', 'i', 'a', 's', '\022', '%', '\n', '\n', -'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', -'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', -'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', -'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', -'t', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', -'*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '\005', '\020', '\006', '\"', '\236', '\001', '\n', '\020', 'E', 'n', 'u', -'m', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', -'e', 'd', '\030', '\001', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', -'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', -'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', -'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', -'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', -'\200', '\200', '\002', '\"', '\234', '\001', '\n', '\016', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', -'\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '!', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', -'\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', -'t', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', -'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', -'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', -'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\340', '\002', '\n', '\r', 'M', 'e', 't', 'h', 'o', 'd', 'O', 'p', -'t', 'i', 'o', 'n', 's', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '!', ' ', '\001', '(', '\010', -':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'q', '\n', '\021', 'i', 'd', -'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', '_', 'l', 'e', 'v', 'e', 'l', '\030', '\"', ' ', '\001', '(', '\016', '2', '/', '.', 'g', -'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', 'd', 'O', 'p', 't', 'i', -'o', 'n', 's', '.', 'I', 'd', 'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', ':', '\023', 'I', 'D', 'E', -'M', 'P', 'O', 'T', 'E', 'N', 'C', 'Y', '_', 'U', 'N', 'K', 'N', 'O', 'W', 'N', 'R', '\020', 'i', 'd', 'e', 'm', 'p', 'o', 't', -'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', -'d', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', -'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', -'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', -'P', '\n', '\020', 'I', 'd', 'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', '\022', '\027', '\n', '\023', 'I', 'D', -'E', 'M', 'P', 'O', 'T', 'E', 'N', 'C', 'Y', '_', 'U', 'N', 'K', 'N', 'O', 'W', 'N', '\020', '\000', '\022', '\023', '\n', '\017', 'N', 'O', -'_', 'S', 'I', 'D', 'E', '_', 'E', 'F', 'F', 'E', 'C', 'T', 'S', '\020', '\001', '\022', '\016', '\n', '\n', 'I', 'D', 'E', 'M', 'P', 'O', -'T', 'E', 'N', 'T', '\020', '\002', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\232', '\003', '\n', '\023', 'U', 'n', 'i', -'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\022', 'A', '\n', '\004', 'n', 'a', 'm', 'e', '\030', -'\002', ' ', '\003', '(', '\013', '2', '-', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', -'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '.', 'N', 'a', 'm', 'e', 'P', 'a', -'r', 't', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ')', '\n', '\020', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', '_', 'v', 'a', -'l', 'u', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\017', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', 'V', 'a', 'l', 'u', -'e', '\022', ',', '\n', '\022', 'p', 'o', 's', 'i', 't', 'i', 'v', 'e', '_', 'i', 'n', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\004', -' ', '\001', '(', '\004', 'R', '\020', 'p', 'o', 's', 'i', 't', 'i', 'v', 'e', 'I', 'n', 't', 'V', 'a', 'l', 'u', 'e', '\022', ',', '\n', -'\022', 'n', 'e', 'g', 'a', 't', 'i', 'v', 'e', '_', 'i', 'n', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\005', ' ', '\001', '(', '\003', -'R', '\020', 'n', 'e', 'g', 'a', 't', 'i', 'v', 'e', 'I', 'n', 't', 'V', 'a', 'l', 'u', 'e', '\022', '!', '\n', '\014', 'd', 'o', 'u', -'b', 'l', 'e', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\006', ' ', '\001', '(', '\001', 'R', '\013', 'd', 'o', 'u', 'b', 'l', 'e', 'V', 'a', -'l', 'u', 'e', '\022', '!', '\n', '\014', 's', 't', 'r', 'i', 'n', 'g', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\007', ' ', '\001', '(', '\014', -'R', '\013', 's', 't', 'r', 'i', 'n', 'g', 'V', 'a', 'l', 'u', 'e', '\022', '\'', '\n', '\017', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', -'e', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\010', ' ', '\001', '(', '\t', 'R', '\016', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'V', -'a', 'l', 'u', 'e', '\032', 'J', '\n', '\010', 'N', 'a', 'm', 'e', 'P', 'a', 'r', 't', '\022', '\033', '\n', '\t', 'n', 'a', 'm', 'e', '_', -'p', 'a', 'r', 't', '\030', '\001', ' ', '\002', '(', '\t', 'R', '\010', 'n', 'a', 'm', 'e', 'P', 'a', 'r', 't', '\022', '!', '\n', '\014', 'i', -'s', '_', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\002', ' ', '\002', '(', '\010', 'R', '\013', 'i', 's', 'E', 'x', 't', 'e', -'n', 's', 'i', 'o', 'n', '\"', '\247', '\002', '\n', '\016', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '\022', -'D', '\n', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\003', '(', '\013', '2', '(', '.', 'g', 'o', 'o', 'g', 'l', -'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', -'.', 'L', 'o', 'c', 'a', 't', 'i', 'o', 'n', 'R', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\032', '\316', '\001', '\n', '\010', 'L', -'o', 'c', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\001', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', -'R', '\004', 'p', 'a', 't', 'h', '\022', '\026', '\n', '\004', 's', 'p', 'a', 'n', '\030', '\002', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', 'R', -'\004', 's', 'p', 'a', 'n', '\022', ')', '\n', '\020', 'l', 'e', 'a', 'd', 'i', 'n', 'g', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', -'\030', '\003', ' ', '\001', '(', '\t', 'R', '\017', 'l', 'e', 'a', 'd', 'i', 'n', 'g', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '\022', '+', -'\n', '\021', 't', 'r', 'a', 'i', 'l', 'i', 'n', 'g', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', '\030', '\004', ' ', '\001', '(', '\t', -'R', '\020', 't', 'r', 'a', 'i', 'l', 'i', 'n', 'g', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '\022', ':', '\n', '\031', 'l', 'e', 'a', -'d', 'i', 'n', 'g', '_', 'd', 'e', 't', 'a', 'c', 'h', 'e', 'd', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', '\030', '\006', ' ', -'\003', '(', '\t', 'R', '\027', 'l', 'e', 'a', 'd', 'i', 'n', 'g', 'D', 'e', 't', 'a', 'c', 'h', 'e', 'd', 'C', 'o', 'm', 'm', 'e', -'n', 't', 's', '\"', '\320', '\002', '\n', '\021', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', -'\022', 'M', '\n', '\n', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\003', '(', '\013', '2', '-', '.', 'g', 'o', -'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', -'d', 'e', 'I', 'n', 'f', 'o', '.', 'A', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 'R', '\n', 'a', 'n', 'n', 'o', 't', 'a', -'t', 'i', 'o', 'n', '\032', '\353', '\001', '\n', '\n', 'A', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\004', 'p', 'a', -'t', 'h', '\030', '\001', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', 'R', '\004', 'p', 'a', 't', 'h', '\022', '\037', '\n', '\013', 's', 'o', 'u', -'r', 'c', 'e', '_', 'f', 'i', 'l', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\n', 's', 'o', 'u', 'r', 'c', 'e', 'F', 'i', 'l', -'e', '\022', '\024', '\n', '\005', 'b', 'e', 'g', 'i', 'n', '\030', '\003', ' ', '\001', '(', '\005', 'R', '\005', 'b', 'e', 'g', 'i', 'n', '\022', '\020', -'\n', '\003', 'e', 'n', 'd', '\030', '\004', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\022', 'R', '\n', '\010', 's', 'e', 'm', 'a', 'n', -'t', 'i', 'c', '\030', '\005', ' ', '\001', '(', '\016', '2', '6', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', -'u', 'f', '.', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '.', 'A', 'n', 'n', 'o', -'t', 'a', 't', 'i', 'o', 'n', '.', 'S', 'e', 'm', 'a', 'n', 't', 'i', 'c', 'R', '\010', 's', 'e', 'm', 'a', 'n', 't', 'i', 'c', -'\"', '(', '\n', '\010', 'S', 'e', 'm', 'a', 'n', 't', 'i', 'c', '\022', '\010', '\n', '\004', 'N', 'O', 'N', 'E', '\020', '\000', '\022', '\007', '\n', -'\003', 'S', 'E', 'T', '\020', '\001', '\022', '\t', '\n', '\005', 'A', 'L', 'I', 'A', 'S', '\020', '\002', 'B', '~', '\n', '\023', 'c', 'o', 'm', '.', -'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 'B', '\020', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', -'o', 'r', 'P', 'r', 'o', 't', 'o', 's', 'H', '\001', 'Z', '-', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'g', 'o', 'l', 'a', 'n', 'g', -'.', 'o', 'r', 'g', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 't', 'y', 'p', 'e', 's', '/', 'd', 'e', 's', 'c', 'r', -'i', 'p', 't', 'o', 'r', 'p', 'b', '\370', '\001', '\001', '\242', '\002', '\003', 'G', 'P', 'B', '\252', '\002', '\032', 'G', 'o', 'o', 'g', 'l', 'e', -'.', 'P', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n', +static const char descriptor[7820] = {'\n', ' ', 'g', 'o', 'o', 'g', 'l', 'e', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 'd', 'e', 's', 'c', 'r', 'i', 'p', +'t', 'o', 'r', '.', 'p', 'r', 'o', 't', 'o', '\022', '\017', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', +'f', '\"', 'M', '\n', '\021', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'S', 'e', 't', '\022', '8', '\n', +'\004', 'f', 'i', 'l', 'e', '\030', '\001', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', +'o', 'b', 'u', 'f', '.', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', +'\004', 'f', 'i', 'l', 'e', '\"', '\376', '\004', '\n', '\023', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', +'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', +'\030', '\n', '\007', 'p', 'a', 'c', 'k', 'a', 'g', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\007', 'p', 'a', 'c', 'k', 'a', 'g', 'e', +'\022', '\036', '\n', '\n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\030', '\003', ' ', '\003', '(', '\t', 'R', '\n', 'd', 'e', 'p', +'e', 'n', 'd', 'e', 'n', 'c', 'y', '\022', '+', '\n', '\021', 'p', 'u', 'b', 'l', 'i', 'c', '_', 'd', 'e', 'p', 'e', 'n', 'd', 'e', +'n', 'c', 'y', '\030', '\n', ' ', '\003', '(', '\005', 'R', '\020', 'p', 'u', 'b', 'l', 'i', 'c', 'D', 'e', 'p', 'e', 'n', 'd', 'e', 'n', +'c', 'y', '\022', '\'', '\n', '\017', 'w', 'e', 'a', 'k', '_', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\030', '\013', ' ', '\003', +'(', '\005', 'R', '\016', 'w', 'e', 'a', 'k', 'D', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'y', '\022', 'C', '\n', '\014', 'm', 'e', 's', +'s', 'a', 'g', 'e', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\003', '(', '\013', '2', ' ', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', +'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', +'\013', 'm', 'e', 's', 's', 'a', 'g', 'e', 'T', 'y', 'p', 'e', '\022', 'A', '\n', '\t', 'e', 'n', 'u', 'm', '_', 't', 'y', 'p', 'e', +'\030', '\005', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', +'E', 'n', 'u', 'm', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\010', 'e', 'n', 'u', 'm', +'T', 'y', 'p', 'e', '\022', 'A', '\n', '\007', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\030', '\006', ' ', '\003', '(', '\013', '2', '\'', '.', 'g', +'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'D', 'e', 's', +'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\007', 's', 'e', 'r', 'v', 'i', 'c', 'e', '\022', 'C', '\n', '\t', +'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\007', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', +'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', +'r', 'o', 't', 'o', 'R', '\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', '6', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', +'s', '\030', '\010', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', +'.', 'F', 'i', 'l', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', 'I', '\n', '\020', +'s', 'o', 'u', 'r', 'c', 'e', '_', 'c', 'o', 'd', 'e', '_', 'i', 'n', 'f', 'o', '\030', '\t', ' ', '\001', '(', '\013', '2', '\037', '.', +'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', +'e', 'I', 'n', 'f', 'o', 'R', '\016', 's', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '\022', '\026', '\n', '\006', +'s', 'y', 'n', 't', 'a', 'x', '\030', '\014', ' ', '\001', '(', '\t', 'R', '\006', 's', 'y', 'n', 't', 'a', 'x', '\022', '\030', '\n', '\007', 'e', +'d', 'i', 't', 'i', 'o', 'n', '\030', '\r', ' ', '\001', '(', '\t', 'R', '\007', 'e', 'd', 'i', 't', 'i', 'o', 'n', '\"', '\271', '\006', '\n', +'\017', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', +'\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ';', '\n', '\005', 'f', 'i', 'e', 'l', 'd', '\030', '\002', ' ', '\003', '(', +'\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', +'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\005', 'f', 'i', 'e', 'l', 'd', '\022', 'C', '\n', +'\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\006', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', +'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', +'P', 'r', 'o', 't', 'o', 'R', '\t', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\022', 'A', '\n', '\013', 'n', 'e', 's', 't', 'e', +'d', '_', 't', 'y', 'p', 'e', '\030', '\003', ' ', '\003', '(', '\013', '2', ' ', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', +'t', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\n', 'n', 'e', +'s', 't', 'e', 'd', 'T', 'y', 'p', 'e', '\022', 'A', '\n', '\t', 'e', 'n', 'u', 'm', '_', 't', 'y', 'p', 'e', '\030', '\004', ' ', '\003', +'(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', +'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\010', 'e', 'n', 'u', 'm', 'T', 'y', 'p', 'e', +'\022', 'X', '\n', '\017', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\005', ' ', '\003', '(', '\013', +'2', '/', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', +'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', 'R', +'\016', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', '\022', 'D', '\n', '\n', 'o', 'n', 'e', 'o', 'f', '_', +'d', 'e', 'c', 'l', '\030', '\010', ' ', '\003', '(', '\013', '2', '%', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', +'b', 'u', 'f', '.', 'O', 'n', 'e', 'o', 'f', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', +'\t', 'o', 'n', 'e', 'o', 'f', 'D', 'e', 'c', 'l', '\022', '9', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\007', ' ', '\001', +'(', '\013', '2', '\037', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 's', 's', +'a', 'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', 'U', '\n', '\016', 'r', 'e', +'s', 'e', 'r', 'v', 'e', 'd', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\t', ' ', '\003', '(', '\013', '2', '.', '.', 'g', 'o', 'o', 'g', +'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', +'t', 'o', '.', 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', 'R', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', +'d', 'R', 'a', 'n', 'g', 'e', '\022', '#', '\n', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'n', 'a', 'm', 'e', '\030', '\n', +' ', '\003', '(', '\t', 'R', '\014', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'N', 'a', 'm', 'e', '\032', 'z', '\n', '\016', 'E', 'x', 't', +'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', +'\005', 'R', '\005', 's', 't', 'a', 'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', +'d', '\022', '@', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '&', '.', 'g', 'o', 'o', 'g', +'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', +'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\032', '7', '\n', '\r', 'R', 'e', 's', 'e', +'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', '\005', 'R', +'\005', 's', 't', 'a', 'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\"', +'|', '\n', '\025', 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 'R', 'a', 'n', 'g', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', +'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', +'\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', +'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', +'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', +'\"', '\301', '\006', '\n', '\024', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', +'\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\026', '\n', '\006', 'n', +'u', 'm', 'b', 'e', 'r', '\030', '\003', ' ', '\001', '(', '\005', 'R', '\006', 'n', 'u', 'm', 'b', 'e', 'r', '\022', 'A', '\n', '\005', 'l', 'a', +'b', 'e', 'l', '\030', '\004', ' ', '\001', '(', '\016', '2', '+', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', +'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'L', +'a', 'b', 'e', 'l', 'R', '\005', 'l', 'a', 'b', 'e', 'l', '\022', '>', '\n', '\004', 't', 'y', 'p', 'e', '\030', '\005', ' ', '\001', '(', '\016', +'2', '*', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'D', +'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'T', 'y', 'p', 'e', 'R', '\004', 't', 'y', 'p', 'e', +'\022', '\033', '\n', '\t', 't', 'y', 'p', 'e', '_', 'n', 'a', 'm', 'e', '\030', '\006', ' ', '\001', '(', '\t', 'R', '\010', 't', 'y', 'p', 'e', +'N', 'a', 'm', 'e', '\022', '\032', '\n', '\010', 'e', 'x', 't', 'e', 'n', 'd', 'e', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\010', 'e', +'x', 't', 'e', 'n', 'd', 'e', 'e', '\022', '#', '\n', '\r', 'd', 'e', 'f', 'a', 'u', 'l', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', +'\007', ' ', '\001', '(', '\t', 'R', '\014', 'd', 'e', 'f', 'a', 'u', 'l', 't', 'V', 'a', 'l', 'u', 'e', '\022', '\037', '\n', '\013', 'o', 'n', +'e', 'o', 'f', '_', 'i', 'n', 'd', 'e', 'x', '\030', '\t', ' ', '\001', '(', '\005', 'R', '\n', 'o', 'n', 'e', 'o', 'f', 'I', 'n', 'd', +'e', 'x', '\022', '\033', '\n', '\t', 'j', 's', 'o', 'n', '_', 'n', 'a', 'm', 'e', '\030', '\n', ' ', '\001', '(', '\t', 'R', '\010', 'j', 's', +'o', 'n', 'N', 'a', 'm', 'e', '\022', '7', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\010', ' ', '\001', '(', '\013', '2', '\035', +'.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', +'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', '\'', '\n', '\017', 'p', 'r', 'o', 't', 'o', '3', '_', 'o', +'p', 't', 'i', 'o', 'n', 'a', 'l', '\030', '\021', ' ', '\001', '(', '\010', 'R', '\016', 'p', 'r', 'o', 't', 'o', '3', 'O', 'p', 't', 'i', +'o', 'n', 'a', 'l', '\"', '\266', '\002', '\n', '\004', 'T', 'y', 'p', 'e', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'D', 'O', 'U', +'B', 'L', 'E', '\020', '\001', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'F', 'L', 'O', 'A', 'T', '\020', '\002', '\022', '\016', '\n', '\n', +'T', 'Y', 'P', 'E', '_', 'I', 'N', 'T', '6', '4', '\020', '\003', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'U', 'I', 'N', 'T', +'6', '4', '\020', '\004', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'I', 'N', 'T', '3', '2', '\020', '\005', '\022', '\020', '\n', '\014', 'T', +'Y', 'P', 'E', '_', 'F', 'I', 'X', 'E', 'D', '6', '4', '\020', '\006', '\022', '\020', '\n', '\014', 'T', 'Y', 'P', 'E', '_', 'F', 'I', 'X', +'E', 'D', '3', '2', '\020', '\007', '\022', '\r', '\n', '\t', 'T', 'Y', 'P', 'E', '_', 'B', 'O', 'O', 'L', '\020', '\010', '\022', '\017', '\n', '\013', +'T', 'Y', 'P', 'E', '_', 'S', 'T', 'R', 'I', 'N', 'G', '\020', '\t', '\022', '\016', '\n', '\n', 'T', 'Y', 'P', 'E', '_', 'G', 'R', 'O', +'U', 'P', '\020', '\n', '\022', '\020', '\n', '\014', 'T', 'Y', 'P', 'E', '_', 'M', 'E', 'S', 'S', 'A', 'G', 'E', '\020', '\013', '\022', '\016', '\n', +'\n', 'T', 'Y', 'P', 'E', '_', 'B', 'Y', 'T', 'E', 'S', '\020', '\014', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'U', 'I', 'N', +'T', '3', '2', '\020', '\r', '\022', '\r', '\n', '\t', 'T', 'Y', 'P', 'E', '_', 'E', 'N', 'U', 'M', '\020', '\016', '\022', '\021', '\n', '\r', 'T', +'Y', 'P', 'E', '_', 'S', 'F', 'I', 'X', 'E', 'D', '3', '2', '\020', '\017', '\022', '\021', '\n', '\r', 'T', 'Y', 'P', 'E', '_', 'S', 'F', +'I', 'X', 'E', 'D', '6', '4', '\020', '\020', '\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'S', 'I', 'N', 'T', '3', '2', '\020', '\021', +'\022', '\017', '\n', '\013', 'T', 'Y', 'P', 'E', '_', 'S', 'I', 'N', 'T', '6', '4', '\020', '\022', '\"', 'C', '\n', '\005', 'L', 'a', 'b', 'e', +'l', '\022', '\022', '\n', '\016', 'L', 'A', 'B', 'E', 'L', '_', 'O', 'P', 'T', 'I', 'O', 'N', 'A', 'L', '\020', '\001', '\022', '\022', '\n', '\016', +'L', 'A', 'B', 'E', 'L', '_', 'R', 'E', 'Q', 'U', 'I', 'R', 'E', 'D', '\020', '\002', '\022', '\022', '\n', '\016', 'L', 'A', 'B', 'E', 'L', +'_', 'R', 'E', 'P', 'E', 'A', 'T', 'E', 'D', '\020', '\003', '\"', 'c', '\n', '\024', 'O', 'n', 'e', 'o', 'f', 'D', 'e', 's', 'c', 'r', +'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', +'\004', 'n', 'a', 'm', 'e', '\022', '7', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\002', ' ', '\001', '(', '\013', '2', '\035', '.', +'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'O', 'n', 'e', 'o', 'f', 'O', 'p', 't', 'i', +'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\"', '\343', '\002', '\n', '\023', 'E', 'n', 'u', 'm', 'D', 'e', 's', 'c', +'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', +'R', '\004', 'n', 'a', 'm', 'e', '\022', '?', '\n', '\005', 'v', 'a', 'l', 'u', 'e', '\030', '\002', ' ', '\003', '(', '\013', '2', ')', '.', 'g', +'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'D', +'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\005', 'v', 'a', 'l', 'u', 'e', '\022', '6', '\n', '\007', +'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '\034', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', +'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', +'n', 's', '\022', ']', '\n', '\016', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'r', 'a', 'n', 'g', 'e', '\030', '\004', ' ', '\003', '(', +'\013', '2', '6', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'D', +'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '.', 'E', 'n', 'u', 'm', 'R', 'e', 's', 'e', 'r', 'v', +'e', 'd', 'R', 'a', 'n', 'g', 'e', 'R', '\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', 'R', 'a', 'n', 'g', 'e', '\022', '#', '\n', +'\r', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'd', '_', 'n', 'a', 'm', 'e', '\030', '\005', ' ', '\003', '(', '\t', 'R', '\014', 'r', 'e', 's', +'e', 'r', 'v', 'e', 'd', 'N', 'a', 'm', 'e', '\032', ';', '\n', '\021', 'E', 'n', 'u', 'm', 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', +'R', 'a', 'n', 'g', 'e', '\022', '\024', '\n', '\005', 's', 't', 'a', 'r', 't', '\030', '\001', ' ', '\001', '(', '\005', 'R', '\005', 's', 't', 'a', +'r', 't', '\022', '\020', '\n', '\003', 'e', 'n', 'd', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\"', '\203', '\001', '\n', '\030', +'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', '\022', +'\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\026', '\n', '\006', 'n', 'u', +'m', 'b', 'e', 'r', '\030', '\002', ' ', '\001', '(', '\005', 'R', '\006', 'n', 'u', 'm', 'b', 'e', 'r', '\022', ';', '\n', '\007', 'o', 'p', 't', +'i', 'o', 'n', 's', '\030', '\003', ' ', '\001', '(', '\013', '2', '!', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', +'b', 'u', 'f', '.', 'E', 'n', 'u', 'm', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', +'i', 'o', 'n', 's', '\"', '\247', '\001', '\n', '\026', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', +'r', 'P', 'r', 'o', 't', 'o', '\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', +'e', '\022', '>', '\n', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\030', '\002', ' ', '\003', '(', '\013', '2', '&', '.', 'g', 'o', 'o', 'g', 'l', +'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', +'o', 'r', 'P', 'r', 'o', 't', 'o', 'R', '\006', 'm', 'e', 't', 'h', 'o', 'd', '\022', '9', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', +'s', '\030', '\003', ' ', '\001', '(', '\013', '2', '\037', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', +'.', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\"', +'\211', '\002', '\n', '\025', 'M', 'e', 't', 'h', 'o', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'P', 'r', 'o', 't', 'o', +'\022', '\022', '\n', '\004', 'n', 'a', 'm', 'e', '\030', '\001', ' ', '\001', '(', '\t', 'R', '\004', 'n', 'a', 'm', 'e', '\022', '\035', '\n', '\n', 'i', +'n', 'p', 'u', 't', '_', 't', 'y', 'p', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\t', 'i', 'n', 'p', 'u', 't', 'T', 'y', 'p', +'e', '\022', '\037', '\n', '\013', 'o', 'u', 't', 'p', 'u', 't', '_', 't', 'y', 'p', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\n', 'o', +'u', 't', 'p', 'u', 't', 'T', 'y', 'p', 'e', '\022', '8', '\n', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\030', '\004', ' ', '\001', '(', +'\013', '2', '\036', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', +'d', 'O', 'p', 't', 'i', 'o', 'n', 's', 'R', '\007', 'o', 'p', 't', 'i', 'o', 'n', 's', '\022', '0', '\n', '\020', 'c', 'l', 'i', 'e', +'n', 't', '_', 's', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\030', '\005', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', +'R', '\017', 'c', 'l', 'i', 'e', 'n', 't', 'S', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\022', '0', '\n', '\020', 's', 'e', 'r', 'v', +'e', 'r', '_', 's', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\030', '\006', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', +'R', '\017', 's', 'e', 'r', 'v', 'e', 'r', 'S', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '\"', '\221', '\t', '\n', '\013', 'F', 'i', 'l', +'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '!', '\n', '\014', 'j', 'a', 'v', 'a', '_', 'p', 'a', 'c', 'k', 'a', 'g', 'e', '\030', +'\001', ' ', '\001', '(', '\t', 'R', '\013', 'j', 'a', 'v', 'a', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', '0', '\n', '\024', 'j', 'a', 'v', +'a', '_', 'o', 'u', 't', 'e', 'r', '_', 'c', 'l', 'a', 's', 's', 'n', 'a', 'm', 'e', '\030', '\010', ' ', '\001', '(', '\t', 'R', '\022', +'j', 'a', 'v', 'a', 'O', 'u', 't', 'e', 'r', 'C', 'l', 'a', 's', 's', 'n', 'a', 'm', 'e', '\022', '5', '\n', '\023', 'j', 'a', 'v', +'a', '_', 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', '_', 'f', 'i', 'l', 'e', 's', '\030', '\n', ' ', '\001', '(', '\010', ':', '\005', 'f', +'a', 'l', 's', 'e', 'R', '\021', 'j', 'a', 'v', 'a', 'M', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'F', 'i', 'l', 'e', 's', '\022', 'D', +'\n', '\035', 'j', 'a', 'v', 'a', '_', 'g', 'e', 'n', 'e', 'r', 'a', 't', 'e', '_', 'e', 'q', 'u', 'a', 'l', 's', '_', 'a', 'n', +'d', '_', 'h', 'a', 's', 'h', '\030', '\024', ' ', '\001', '(', '\010', 'B', '\002', '\030', '\001', 'R', '\031', 'j', 'a', 'v', 'a', 'G', 'e', 'n', +'e', 'r', 'a', 't', 'e', 'E', 'q', 'u', 'a', 'l', 's', 'A', 'n', 'd', 'H', 'a', 's', 'h', '\022', ':', '\n', '\026', 'j', 'a', 'v', +'a', '_', 's', 't', 'r', 'i', 'n', 'g', '_', 'c', 'h', 'e', 'c', 'k', '_', 'u', 't', 'f', '8', '\030', '\033', ' ', '\001', '(', '\010', +':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\023', 'j', 'a', 'v', 'a', 'S', 't', 'r', 'i', 'n', 'g', 'C', 'h', 'e', 'c', 'k', 'U', +'t', 'f', '8', '\022', 'S', '\n', '\014', 'o', 'p', 't', 'i', 'm', 'i', 'z', 'e', '_', 'f', 'o', 'r', '\030', '\t', ' ', '\001', '(', '\016', +'2', ')', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'l', 'e', 'O', 'p', +'t', 'i', 'o', 'n', 's', '.', 'O', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'M', 'o', 'd', 'e', ':', '\005', 'S', 'P', 'E', 'E', 'D', +'R', '\013', 'o', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'F', 'o', 'r', '\022', '\035', '\n', '\n', 'g', 'o', '_', 'p', 'a', 'c', 'k', 'a', +'g', 'e', '\030', '\013', ' ', '\001', '(', '\t', 'R', '\t', 'g', 'o', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', '5', '\n', '\023', 'c', 'c', +'_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', '\020', ' ', '\001', '(', '\010', ':', '\005', +'f', 'a', 'l', 's', 'e', 'R', '\021', 'c', 'c', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', +'9', '\n', '\025', 'j', 'a', 'v', 'a', '_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', +'\021', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\023', 'j', 'a', 'v', 'a', 'G', 'e', 'n', 'e', 'r', 'i', 'c', +'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '5', '\n', '\023', 'p', 'y', '_', 'g', 'e', 'n', 'e', 'r', 'i', 'c', '_', 's', 'e', +'r', 'v', 'i', 'c', 'e', 's', '\030', '\022', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\021', 'p', 'y', 'G', 'e', +'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '7', '\n', '\024', 'p', 'h', 'p', '_', 'g', 'e', 'n', 'e', +'r', 'i', 'c', '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\030', '*', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', +'R', '\022', 'p', 'h', 'p', 'G', 'e', 'n', 'e', 'r', 'i', 'c', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '\022', '%', '\n', '\n', 'd', +'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\027', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', +'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '.', '\n', '\020', 'c', 'c', '_', 'e', 'n', 'a', 'b', 'l', 'e', '_', 'a', 'r', +'e', 'n', 'a', 's', '\030', '\037', ' ', '\001', '(', '\010', ':', '\004', 't', 'r', 'u', 'e', 'R', '\016', 'c', 'c', 'E', 'n', 'a', 'b', 'l', +'e', 'A', 'r', 'e', 'n', 'a', 's', '\022', '*', '\n', '\021', 'o', 'b', 'j', 'c', '_', 'c', 'l', 'a', 's', 's', '_', 'p', 'r', 'e', +'f', 'i', 'x', '\030', '$', ' ', '\001', '(', '\t', 'R', '\017', 'o', 'b', 'j', 'c', 'C', 'l', 'a', 's', 's', 'P', 'r', 'e', 'f', 'i', +'x', '\022', ')', '\n', '\020', 'c', 's', 'h', 'a', 'r', 'p', '_', 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', '%', ' ', '\001', +'(', '\t', 'R', '\017', 'c', 's', 'h', 'a', 'r', 'p', 'N', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '!', '\n', '\014', 's', 'w', +'i', 'f', 't', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', '\'', ' ', '\001', '(', '\t', 'R', '\013', 's', 'w', 'i', 'f', 't', 'P', 'r', +'e', 'f', 'i', 'x', '\022', '(', '\n', '\020', 'p', 'h', 'p', '_', 'c', 'l', 'a', 's', 's', '_', 'p', 'r', 'e', 'f', 'i', 'x', '\030', +'(', ' ', '\001', '(', '\t', 'R', '\016', 'p', 'h', 'p', 'C', 'l', 'a', 's', 's', 'P', 'r', 'e', 'f', 'i', 'x', '\022', '#', '\n', '\r', +'p', 'h', 'p', '_', 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', ')', ' ', '\001', '(', '\t', 'R', '\014', 'p', 'h', 'p', 'N', +'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '4', '\n', '\026', 'p', 'h', 'p', '_', 'm', 'e', 't', 'a', 'd', 'a', 't', 'a', '_', +'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\030', ',', ' ', '\001', '(', '\t', 'R', '\024', 'p', 'h', 'p', 'M', 'e', 't', 'a', 'd', +'a', 't', 'a', 'N', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\022', '!', '\n', '\014', 'r', 'u', 'b', 'y', '_', 'p', 'a', 'c', 'k', +'a', 'g', 'e', '\030', '-', ' ', '\001', '(', '\t', 'R', '\013', 'r', 'u', 'b', 'y', 'P', 'a', 'c', 'k', 'a', 'g', 'e', '\022', 'X', '\n', +'\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', +'\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', +'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', +'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', ':', '\n', '\014', 'O', 'p', 't', 'i', 'm', 'i', 'z', 'e', 'M', +'o', 'd', 'e', '\022', '\t', '\n', '\005', 'S', 'P', 'E', 'E', 'D', '\020', '\001', '\022', '\r', '\n', '\t', 'C', 'O', 'D', 'E', '_', 'S', 'I', +'Z', 'E', '\020', '\002', '\022', '\020', '\n', '\014', 'L', 'I', 'T', 'E', '_', 'R', 'U', 'N', 'T', 'I', 'M', 'E', '\020', '\003', '*', '\t', '\010', +'\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '&', '\020', '\'', '\"', '\343', '\002', '\n', '\016', 'M', 'e', 's', 's', 'a', 'g', +'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '<', '\n', '\027', 'm', 'e', 's', 's', 'a', 'g', 'e', '_', 's', 'e', 't', '_', 'w', +'i', 'r', 'e', '_', 'f', 'o', 'r', 'm', 'a', 't', '\030', '\001', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\024', +'m', 'e', 's', 's', 'a', 'g', 'e', 'S', 'e', 't', 'W', 'i', 'r', 'e', 'F', 'o', 'r', 'm', 'a', 't', '\022', 'L', '\n', '\037', 'n', +'o', '_', 's', 't', 'a', 'n', 'd', 'a', 'r', 'd', '_', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '_', 'a', 'c', 'c', +'e', 's', 's', 'o', 'r', '\030', '\002', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\034', 'n', 'o', 'S', 't', 'a', +'n', 'd', 'a', 'r', 'd', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'A', 'c', 'c', 'e', 's', 's', 'o', 'r', '\022', '%', +'\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', +'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '\033', '\n', '\t', 'm', 'a', 'p', '_', 'e', 'n', 't', 'r', 'y', +'\030', '\007', ' ', '\001', '(', '\010', 'R', '\010', 'm', 'a', 'p', 'E', 'n', 't', 'r', 'y', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', +'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', +'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', +'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', +'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '\004', '\020', '\005', 'J', '\004', +'\010', '\005', '\020', '\006', 'J', '\004', '\010', '\006', '\020', '\007', 'J', '\004', '\010', '\010', '\020', '\t', 'J', '\004', '\010', '\t', '\020', '\n', '\"', '\222', '\004', +'\n', '\014', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'A', '\n', '\005', 'c', 't', 'y', 'p', 'e', '\030', '\001', +' ', '\001', '(', '\016', '2', '#', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', +'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', 'n', 's', '.', 'C', 'T', 'y', 'p', 'e', ':', '\006', 'S', 'T', 'R', 'I', 'N', 'G', 'R', +'\005', 'c', 't', 'y', 'p', 'e', '\022', '\026', '\n', '\006', 'p', 'a', 'c', 'k', 'e', 'd', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\006', 'p', +'a', 'c', 'k', 'e', 'd', '\022', 'G', '\n', '\006', 'j', 's', 't', 'y', 'p', 'e', '\030', '\006', ' ', '\001', '(', '\016', '2', '$', '.', 'g', +'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'F', 'i', 'e', 'l', 'd', 'O', 'p', 't', 'i', 'o', +'n', 's', '.', 'J', 'S', 'T', 'y', 'p', 'e', ':', '\t', 'J', 'S', '_', 'N', 'O', 'R', 'M', 'A', 'L', 'R', '\006', 'j', 's', 't', +'y', 'p', 'e', '\022', '\031', '\n', '\004', 'l', 'a', 'z', 'y', '\030', '\005', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', +'\004', 'l', 'a', 'z', 'y', '\022', '.', '\n', '\017', 'u', 'n', 'v', 'e', 'r', 'i', 'f', 'i', 'e', 'd', '_', 'l', 'a', 'z', 'y', '\030', +'\017', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\016', 'u', 'n', 'v', 'e', 'r', 'i', 'f', 'i', 'e', 'd', 'L', +'a', 'z', 'y', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', +'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', '\031', '\n', '\004', 'w', 'e', 'a', 'k', +'\030', '\n', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\004', 'w', 'e', 'a', 'k', '\022', 'X', '\n', '\024', 'u', 'n', +'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', +'2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', +'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', +'t', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', '/', '\n', '\005', 'C', 'T', 'y', 'p', 'e', '\022', '\n', '\n', '\006', 'S', 'T', 'R', +'I', 'N', 'G', '\020', '\000', '\022', '\010', '\n', '\004', 'C', 'O', 'R', 'D', '\020', '\001', '\022', '\020', '\n', '\014', 'S', 'T', 'R', 'I', 'N', 'G', +'_', 'P', 'I', 'E', 'C', 'E', '\020', '\002', '\"', '5', '\n', '\006', 'J', 'S', 'T', 'y', 'p', 'e', '\022', '\r', '\n', '\t', 'J', 'S', '_', +'N', 'O', 'R', 'M', 'A', 'L', '\020', '\000', '\022', '\r', '\n', '\t', 'J', 'S', '_', 'S', 'T', 'R', 'I', 'N', 'G', '\020', '\001', '\022', '\r', +'\n', '\t', 'J', 'S', '_', 'N', 'U', 'M', 'B', 'E', 'R', '\020', '\002', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', +'\004', '\010', '\004', '\020', '\005', '\"', 's', '\n', '\014', 'O', 'n', 'e', 'o', 'f', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', 'X', '\n', '\024', +'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', +'(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', +'t', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', +'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\300', '\001', +'\n', '\013', 'E', 'n', 'u', 'm', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '\037', '\n', '\013', 'a', 'l', 'l', 'o', 'w', '_', 'a', 'l', +'i', 'a', 's', '\030', '\002', ' ', '\001', '(', '\010', 'R', '\n', 'a', 'l', 'l', 'o', 'w', 'A', 'l', 'i', 'a', 's', '\022', '%', '\n', '\n', +'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '\003', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', +'d', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', +'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', +'.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', +'t', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', +'*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', 'J', '\004', '\010', '\005', '\020', '\006', '\"', '\236', '\001', '\n', '\020', 'E', 'n', 'u', +'m', 'V', 'a', 'l', 'u', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', +'e', 'd', '\030', '\001', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', +'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', +'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', +'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', +'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', +'\200', '\200', '\002', '\"', '\234', '\001', '\n', '\016', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 'O', 'p', 't', 'i', 'o', 'n', 's', '\022', '%', '\n', +'\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '!', ' ', '\001', '(', '\010', ':', '\005', 'f', 'a', 'l', 's', 'e', 'R', +'\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', +'t', 'e', 'd', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', +'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', +'p', 't', 'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', +'n', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\340', '\002', '\n', '\r', 'M', 'e', 't', 'h', 'o', 'd', 'O', 'p', +'t', 'i', 'o', 'n', 's', '\022', '%', '\n', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\030', '!', ' ', '\001', '(', '\010', +':', '\005', 'f', 'a', 'l', 's', 'e', 'R', '\n', 'd', 'e', 'p', 'r', 'e', 'c', 'a', 't', 'e', 'd', '\022', 'q', '\n', '\021', 'i', 'd', +'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', '_', 'l', 'e', 'v', 'e', 'l', '\030', '\"', ' ', '\001', '(', '\016', '2', '/', '.', 'g', +'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'M', 'e', 't', 'h', 'o', 'd', 'O', 'p', 't', 'i', +'o', 'n', 's', '.', 'I', 'd', 'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', ':', '\023', 'I', 'D', 'E', +'M', 'P', 'O', 'T', 'E', 'N', 'C', 'Y', '_', 'U', 'N', 'K', 'N', 'O', 'W', 'N', 'R', '\020', 'i', 'd', 'e', 'm', 'p', 'o', 't', +'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', '\022', 'X', '\n', '\024', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', +'d', '_', 'o', 'p', 't', 'i', 'o', 'n', '\030', '\347', '\007', ' ', '\003', '(', '\013', '2', '$', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', +'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', +'i', 'o', 'n', 'R', '\023', 'u', 'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\"', +'P', '\n', '\020', 'I', 'd', 'e', 'm', 'p', 'o', 't', 'e', 'n', 'c', 'y', 'L', 'e', 'v', 'e', 'l', '\022', '\027', '\n', '\023', 'I', 'D', +'E', 'M', 'P', 'O', 'T', 'E', 'N', 'C', 'Y', '_', 'U', 'N', 'K', 'N', 'O', 'W', 'N', '\020', '\000', '\022', '\023', '\n', '\017', 'N', 'O', +'_', 'S', 'I', 'D', 'E', '_', 'E', 'F', 'F', 'E', 'C', 'T', 'S', '\020', '\001', '\022', '\016', '\n', '\n', 'I', 'D', 'E', 'M', 'P', 'O', +'T', 'E', 'N', 'T', '\020', '\002', '*', '\t', '\010', '\350', '\007', '\020', '\200', '\200', '\200', '\200', '\002', '\"', '\232', '\003', '\n', '\023', 'U', 'n', 'i', +'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '\022', 'A', '\n', '\004', 'n', 'a', 'm', 'e', '\030', +'\002', ' ', '\003', '(', '\013', '2', '-', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'U', +'n', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'e', 'd', 'O', 'p', 't', 'i', 'o', 'n', '.', 'N', 'a', 'm', 'e', 'P', 'a', +'r', 't', 'R', '\004', 'n', 'a', 'm', 'e', '\022', ')', '\n', '\020', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', '_', 'v', 'a', +'l', 'u', 'e', '\030', '\003', ' ', '\001', '(', '\t', 'R', '\017', 'i', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r', 'V', 'a', 'l', 'u', +'e', '\022', ',', '\n', '\022', 'p', 'o', 's', 'i', 't', 'i', 'v', 'e', '_', 'i', 'n', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\004', +' ', '\001', '(', '\004', 'R', '\020', 'p', 'o', 's', 'i', 't', 'i', 'v', 'e', 'I', 'n', 't', 'V', 'a', 'l', 'u', 'e', '\022', ',', '\n', +'\022', 'n', 'e', 'g', 'a', 't', 'i', 'v', 'e', '_', 'i', 'n', 't', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\005', ' ', '\001', '(', '\003', +'R', '\020', 'n', 'e', 'g', 'a', 't', 'i', 'v', 'e', 'I', 'n', 't', 'V', 'a', 'l', 'u', 'e', '\022', '!', '\n', '\014', 'd', 'o', 'u', +'b', 'l', 'e', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\006', ' ', '\001', '(', '\001', 'R', '\013', 'd', 'o', 'u', 'b', 'l', 'e', 'V', 'a', +'l', 'u', 'e', '\022', '!', '\n', '\014', 's', 't', 'r', 'i', 'n', 'g', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\007', ' ', '\001', '(', '\014', +'R', '\013', 's', 't', 'r', 'i', 'n', 'g', 'V', 'a', 'l', 'u', 'e', '\022', '\'', '\n', '\017', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', +'e', '_', 'v', 'a', 'l', 'u', 'e', '\030', '\010', ' ', '\001', '(', '\t', 'R', '\016', 'a', 'g', 'g', 'r', 'e', 'g', 'a', 't', 'e', 'V', +'a', 'l', 'u', 'e', '\032', 'J', '\n', '\010', 'N', 'a', 'm', 'e', 'P', 'a', 'r', 't', '\022', '\033', '\n', '\t', 'n', 'a', 'm', 'e', '_', +'p', 'a', 'r', 't', '\030', '\001', ' ', '\002', '(', '\t', 'R', '\010', 'n', 'a', 'm', 'e', 'P', 'a', 'r', 't', '\022', '!', '\n', '\014', 'i', +'s', '_', 'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', '\030', '\002', ' ', '\002', '(', '\010', 'R', '\013', 'i', 's', 'E', 'x', 't', 'e', +'n', 's', 'i', 'o', 'n', '\"', '\247', '\002', '\n', '\016', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '\022', +'D', '\n', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\003', '(', '\013', '2', '(', '.', 'g', 'o', 'o', 'g', 'l', +'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'S', 'o', 'u', 'r', 'c', 'e', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', +'.', 'L', 'o', 'c', 'a', 't', 'i', 'o', 'n', 'R', '\010', 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n', '\032', '\316', '\001', '\n', '\010', 'L', +'o', 'c', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\004', 'p', 'a', 't', 'h', '\030', '\001', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', +'R', '\004', 'p', 'a', 't', 'h', '\022', '\026', '\n', '\004', 's', 'p', 'a', 'n', '\030', '\002', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', 'R', +'\004', 's', 'p', 'a', 'n', '\022', ')', '\n', '\020', 'l', 'e', 'a', 'd', 'i', 'n', 'g', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', +'\030', '\003', ' ', '\001', '(', '\t', 'R', '\017', 'l', 'e', 'a', 'd', 'i', 'n', 'g', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '\022', '+', +'\n', '\021', 't', 'r', 'a', 'i', 'l', 'i', 'n', 'g', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', '\030', '\004', ' ', '\001', '(', '\t', +'R', '\020', 't', 'r', 'a', 'i', 'l', 'i', 'n', 'g', 'C', 'o', 'm', 'm', 'e', 'n', 't', 's', '\022', ':', '\n', '\031', 'l', 'e', 'a', +'d', 'i', 'n', 'g', '_', 'd', 'e', 't', 'a', 'c', 'h', 'e', 'd', '_', 'c', 'o', 'm', 'm', 'e', 'n', 't', 's', '\030', '\006', ' ', +'\003', '(', '\t', 'R', '\027', 'l', 'e', 'a', 'd', 'i', 'n', 'g', 'D', 'e', 't', 'a', 'c', 'h', 'e', 'd', 'C', 'o', 'm', 'm', 'e', +'n', 't', 's', '\"', '\320', '\002', '\n', '\021', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', +'\022', 'M', '\n', '\n', 'a', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', '\030', '\001', ' ', '\003', '(', '\013', '2', '-', '.', 'g', 'o', +'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', +'d', 'e', 'I', 'n', 'f', 'o', '.', 'A', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', 'R', '\n', 'a', 'n', 'n', 'o', 't', 'a', +'t', 'i', 'o', 'n', '\032', '\353', '\001', '\n', '\n', 'A', 'n', 'n', 'o', 't', 'a', 't', 'i', 'o', 'n', '\022', '\026', '\n', '\004', 'p', 'a', +'t', 'h', '\030', '\001', ' ', '\003', '(', '\005', 'B', '\002', '\020', '\001', 'R', '\004', 'p', 'a', 't', 'h', '\022', '\037', '\n', '\013', 's', 'o', 'u', +'r', 'c', 'e', '_', 'f', 'i', 'l', 'e', '\030', '\002', ' ', '\001', '(', '\t', 'R', '\n', 's', 'o', 'u', 'r', 'c', 'e', 'F', 'i', 'l', +'e', '\022', '\024', '\n', '\005', 'b', 'e', 'g', 'i', 'n', '\030', '\003', ' ', '\001', '(', '\005', 'R', '\005', 'b', 'e', 'g', 'i', 'n', '\022', '\020', +'\n', '\003', 'e', 'n', 'd', '\030', '\004', ' ', '\001', '(', '\005', 'R', '\003', 'e', 'n', 'd', '\022', 'R', '\n', '\010', 's', 'e', 'm', 'a', 'n', +'t', 'i', 'c', '\030', '\005', ' ', '\001', '(', '\016', '2', '6', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', +'u', 'f', '.', 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', 'C', 'o', 'd', 'e', 'I', 'n', 'f', 'o', '.', 'A', 'n', 'n', 'o', +'t', 'a', 't', 'i', 'o', 'n', '.', 'S', 'e', 'm', 'a', 'n', 't', 'i', 'c', 'R', '\010', 's', 'e', 'm', 'a', 'n', 't', 'i', 'c', +'\"', '(', '\n', '\010', 'S', 'e', 'm', 'a', 'n', 't', 'i', 'c', '\022', '\010', '\n', '\004', 'N', 'O', 'N', 'E', '\020', '\000', '\022', '\007', '\n', +'\003', 'S', 'E', 'T', '\020', '\001', '\022', '\t', '\n', '\005', 'A', 'L', 'I', 'A', 'S', '\020', '\002', 'B', '~', '\n', '\023', 'c', 'o', 'm', '.', +'g', 'o', 'o', 'g', 'l', 'e', '.', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', 'B', '\020', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', +'o', 'r', 'P', 'r', 'o', 't', 'o', 's', 'H', '\001', 'Z', '-', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'g', 'o', 'l', 'a', 'n', 'g', +'.', 'o', 'r', 'g', '/', 'p', 'r', 'o', 't', 'o', 'b', 'u', 'f', '/', 't', 'y', 'p', 'e', 's', '/', 'd', 'e', 's', 'c', 'r', +'i', 'p', 't', 'o', 'r', 'p', 'b', '\370', '\001', '\001', '\242', '\002', '\003', 'G', 'P', 'B', '\252', '\002', '\032', 'G', 'o', 'o', 'g', 'l', 'e', +'.', 'P', 'r', 'o', 't', 'o', 'b', 'u', 'f', '.', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n', }; static _upb_DefPool_Init *deps[1] = { @@ -1585,13 +1614,13 @@ _upb_DefPool_Init google_protobuf_descriptor_proto_upbdefinit = { // Must be last. +#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) + struct upb_ExtensionRegistry { upb_Arena* arena; - upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ + 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)); @@ -1606,13 +1635,13 @@ upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { } bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, + const upb_MiniTableExtension** e, size_t count) { char buf[EXTREG_KEY_SIZE]; - const upb_MiniTable_Extension** start = e; - const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); + const upb_MiniTableExtension** start = e; + const upb_MiniTableExtension** end = UPB_PTRADD(e, count); for (; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; + const upb_MiniTableExtension* ext = *e; extreg_key(buf, ext->extendee, ext->field.number); upb_value v; if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { @@ -1626,16 +1655,16 @@ bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, return true; failure: - /* Back out the entries previously added. */ + // Back out the entries previously added. for (end = e, e = start; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; + const upb_MiniTableExtension* 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_ExtensionRegistry_Lookup( +const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) { char buf[EXTREG_KEY_SIZE]; upb_value v; @@ -1647,3005 +1676,2239 @@ const upb_MiniTable_Extension* upb_ExtensionRegistry_Lookup( } } -// 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. +/* + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ +#include // Must be last. -#if UPB_FASTTABLE +#define UPB_MAXARRSIZE 16 // 2**16 = 64k. -// 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 +// From Chromium. +#define ARRAY_SIZE(x) \ + ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) -#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data +static const double MAX_LOAD = 0.85; -#define RETURN_GENERIC(m) \ - /* Uncomment either of these for debugging purposes. */ \ - /* fprintf(stderr, m); */ \ - /*__builtin_trap(); */ \ - return _upb_FastDecoder_DecodeGeneric(d, ptr, msg, table, hasbits, 0); +/* 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; -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 bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } -UPB_NOINLINE -static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { - int overrun = data; - int status; - ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); - if (ptr == NULL) _upb_FastDecoder_ErrorJmp(d, status); - data = _upb_FastDecoder_LoadTag(ptr); - UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); +static upb_value _upb_value_val(uint64_t val) { + upb_value ret; + _upb_value_setval(&ret, val); + return ret; } -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) - ? _upb_Decoder_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 = _upb_FastDecoder_LoadTag(ptr); - UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); +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); } -UPB_FORCEINLINE -static bool fastdecode_checktag(uint16_t data, int tagbytes) { - if (tagbytes == 1) { - return (data & 0xff) == 0; - } else { - return data == 0; - } -} +char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { + size_t n; + char* p; -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; + /* 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; } - 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; + return p; } -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; +/* 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_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; +static lookupkey_t intkey(uintptr_t key) { + lookupkey_t k; + k.num = key; + return k; } -typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, - void* ctx); +typedef uint32_t hashfunc_t(upb_tabkey key); +typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); -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 = _upb_Decoder_PushLimit(d, ptr, len); - ptr = func(d, ptr, ctx); - _upb_Decoder_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; -} +/* Base table (shared code) ***************************************************/ -/* singular, oneof, repeated field handling ***********************************/ +static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } -typedef struct { - upb_Array* arr; - void* end; -} fastdecode_arr; +static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { + return t->entries + (hash & t->mask); +} -typedef enum { - FD_NEXT_ATLIMIT, - FD_NEXT_SAMEFIELD, - FD_NEXT_OTHERFIELD -} fastdecode_next; +static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } -typedef struct { - void* dst; - fastdecode_next next; - uint32_t tag; -} fastdecode_nextret; +static bool isfull(upb_table* t) { return t->count == t->max_count; } -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->capacity; - 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->capacity = 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)); +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 dst; + 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; +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; } -UPB_FORCEINLINE -static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, - int valbytes) { - farr->arr->size = - (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; +static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { + return (upb_tabent*)upb_getentry(t, hash); } -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; +static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e; - if (UPB_LIKELY(!_upb_Decoder_IsDone(d, ptr))) { - ret.tag = _upb_FastDecoder_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; + 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; } - - 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; +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); } -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->capacity * valbytes); - *data = _upb_FastDecoder_LoadTag(ptr); - return begin + (farr->arr->size * valbytes); +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); } - default: - UPB_UNREACHABLE(); + return true; + } else { + return false; } } -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); -} +/* 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; -#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_ASSERT(findentry(t, key, hash, eql) == NULL); -/* varint fields **************************************************************/ + t->count++; + mainpos_e = getentry_mutable(t, hash); + our_e = mainpos_e; -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); + 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; } - UPB_UNREACHABLE(); } - return val; + our_e->key = tabkey; + our_e->val.val = val.val; + UPB_ASSERT(findentry(t, key, hash, eql) == our_e); } -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; +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. */ } - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - if (byte > 1) { - return NULL; + 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; } - *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) _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +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])); -typedef struct { - uint8_t valbytes; - bool zigzag; - void* dst; - fastdecode_arr farr; -} fastdecode_varintdata; + return i; +} -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 size_t begin(const upb_table* t) { return next(t, -1); } - while (!_upb_Decoder_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_strtable ***************************************************************/ - fastdecode_commitarr(dst, &data->farr, data->valbytes); - return ptr; +/* 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; } -#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)) { \ - _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); +/* Adapted from ABSL's wyhash. */ -#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); \ - } +static uint64_t UnalignedLoad64(const void* p) { + uint64_t val; + memcpy(&val, p, 8); + return val; +} -#define z_ZZ true -#define b_ZZ false -#define v_ZZ false +static uint32_t UnalignedLoad32(const void* p) { + uint32_t val; + memcpy(&val, p, 4); + return val; +} -/* Generate all combinations: - * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ +#if defined(_MSC_VER) && defined(_M_X64) +#include +#endif -#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); \ - } +/* 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 +} -#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 uint64_t WyhashMix(uint64_t v0, uint64_t v1) { + uint64_t high; + uint64_t low = upb_umul128(v0, v1, &high); + return low ^ high; +} -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) +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]; -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) + 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; -#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 + 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); -/* fixed fields ***************************************************************/ + uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); + current_state = (cs0 ^ cs1); -#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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); + uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); + duplicated_state = (ds0 ^ ds1); -#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)) { \ - _upb_FastDecoder_ErrorJmp(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) { \ - _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ - } \ - } else { \ - _upb_Array_Resize(arr, elems, &d->arena); \ - } \ - \ - char* dst = _upb_array_ptr(arr); \ - memcpy(dst, ptr, size); \ - arr->size = elems; \ - \ - ptr += size; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + ptr += 64; + len -= 64; + } while (len > 64); -#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); \ + current_state = current_state ^ duplicated_state; } -/* 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); \ - } + // 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); -#define TYPES(card, tagbytes) \ - F(card, 4, tagbytes) \ - F(card, 8, tagbytes) + current_state = WyhashMix(a ^ salt[1], b ^ current_state); -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) + ptr += 16; + len -= 16; + } -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) + // 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; + } -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDFIXED -#undef FASTDECODE_PACKEDFIXED + uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t z = salt[1] ^ starting_length; + return WyhashMix(w, z); +} -/* string fields **************************************************************/ +const uint64_t kWyhashSalt[5] = { + 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, + 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, +}; -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); +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); +} -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 (!_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { - _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); - } - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, 0); } -#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; \ - _upb_FastDecoder_ErrorJmp(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) { \ - _upb_FastDecoder_ErrorJmp(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 uint32_t strhash(upb_tabkey key) { + uint32_t len; + char* str = upb_tabstr(key, &len); + return _upb_Hash_NoSeed(str, len); +} -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); +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_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); +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); } -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); +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); } -#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 && \ - !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ - _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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); \ +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { + upb_strtable new_table; + if (!init(&new_table.t, size_lg2, a)) return false; + + intptr_t iter = UPB_STRTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(t, &key, &val, &iter)) { + upb_strtable_insert(&new_table, key.data, key.size, val, a); } + *t = new_table; + return true; +} -#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 && \ - !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ - _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ - } \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return _upb_FastDecoder_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); +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; -/* Generate all combinations: - * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ + 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; + } + } -#define s_VALIDATE true -#define b_VALIDATE false + key = strkey2(k, len); + tabkey = strcopy(key, a); + if (tabkey == 0) return 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); \ - } + hash = _upb_Hash_NoSeed(key.str.str, key.str.len); + insert(&t->t, key, tabkey, v, hash, &strhash, &streql); + return true; +} -#define UTF8(card, tagbytes) \ - F(card, tagbytes, s) \ - F(card, tagbytes, b) +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); +} -#define TAGBYTES(card) \ - UTF8(card, 1) \ - UTF8(card, 2) +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); +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +/* Iteration */ -#undef s_VALIDATE -#undef b_VALIDATE -#undef F -#undef TAGBYTES -#undef FASTDECODE_LONGSTRING -#undef FASTDECODE_COPYSTRING -#undef FASTDECODE_STRING +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { + i->t = t; + i->index = begin(&t->t); +} -/* message fields *************************************************************/ +void upb_strtable_next(upb_strtable_iter* i) { + i->index = next(&i->t->t, i->index); +} -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); +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)); } -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; +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; } -#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) { \ - _upb_FastDecoder_ErrorJmp(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)) { \ - _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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 */ - - -#include -#include -#include -#include -#include -#include -#include +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; +} -// Must be last. +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; +} -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_inttable ***************************************************************/ -enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; +/* For inttables we use a hybrid structure where small keys are kept in an + * array and large keys are put in the hash table. */ -/* 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 uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } -static bool jsondec_streql(upb_StringView str, const char* lit) { - return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; -} +static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } -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 upb_tabval* mutable_array(upb_inttable* t) { + return (upb_tabval*)t->array; } -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); +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; + } } -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 const upb_tabval* inttable_val_const(const upb_inttable* t, + uintptr_t key) { + return inttable_val((upb_inttable*)t, key); } -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); +size_t upb_inttable_count(const upb_inttable* t) { + return t->t.count + t->array_count; } -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; +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; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + UPB_ASSERT(upb_inttable_lookup(t, key, NULL)); } + UPB_ASSERT(count == upb_inttable_count(t)); } - jsondec_err(d, "Unexpected EOF"); +#endif } -static bool jsondec_tryparsech(jsondec* d, char ch) { - if (d->ptr == d->end || *d->ptr != ch) return false; - d->ptr++; - return true; -} +bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, + upb_Arena* a) { + size_t array_bytes; -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; + 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 jsondec_wsch(jsondec* d, char ch) { - jsondec_skipws(d); - if (!jsondec_tryparsech(d, ch)) { - jsondec_errf(d, "Expected: '%c'", ch); - } +bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { + return upb_inttable_sizedinit(t, 0, 4, a); } -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"); } +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. */ -static void jsondec_entrysep(jsondec* d) { - jsondec_skipws(d); - jsondec_parselit(d, ":"); -} + 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; -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); - } -} + if (!init(&new_table, t->t.size_lg2 + 1, a)) { + return false; + } -/* JSON object/array **********************************************************/ + 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; -/* These are used like so: - * - * jsondec_objstart(d); - * while (jsondec_objnext(d)) { - * ... - * } - * jsondec_objend(d) */ + _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 int jsondec_peek(jsondec* d) { - jsondec_skipws(d); - return jsondec_rawpeek(d); -} + UPB_ASSERT(t->t.count == new_table.count); -static void jsondec_push(jsondec* d) { - if (--d->depth < 0) { - jsondec_err(d, "Recursion limit exceeded"); + t->t = new_table; + } + insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); } - 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, ","); + check(t); 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, '}'); +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 jsondec_objnext(jsondec* d) { - if (!jsondec_seqnext(d, '}')) return false; - if (jsondec_peek(d) != JD_STRING) { - jsondec_err(d, "Object must start with string"); - } +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; } -/* 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; +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; } - d->ptr++; - } - - return d->ptr != start; -} - -static void jsondec_skipdigits(jsondec* d) { - if (!jsondec_tryskipdigits(d)) { - jsondec_err(d, "Expected one or more digits"); + } else { + success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); } + check(t); + return success; } -static double jsondec_number(jsondec* d) { - const char* start = d->ptr; - - assert(jsondec_rawpeek(d) == JD_NUMBER); +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}; - /* Skip over the syntax of a number, as specified by JSON. */ - if (*d->ptr == '-') d->ptr++; + /* The max key in each bucket. */ + uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; - if (jsondec_tryparsech(d, '0')) { - if (jsondec_tryskipdigits(d)) { - jsondec_err(d, "number cannot have leading zero"); + { + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + int bucket = log2ceil(key); + max[bucket] = UPB_MAX(max[bucket], key); + counts[bucket]++; } - } 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; + /* Find the largest power of two that satisfies the MIN_DENSITY + * definition (while actually having some keys). */ + size_t arr_count = upb_inttable_count(t); + int size_lg2; + upb_inttable new_t; - 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++; + 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; } - jsondec_skipdigits(d); + + arr_count -= counts[size_lg2]; } -parse: - /* Having verified the syntax of a JSON number, use strtod() to parse - * (strtod() accepts a superset of JSON syntax). */ - errno = 0; + UPB_ASSERT(arr_count <= upb_inttable_count(t)); + { - char* end; - double val = strtod(start, &end); - assert(end == d->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); - /* 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"); - } - */ + upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); - if (val > DBL_MAX || val < -DBL_MAX) { - jsondec_err(d, "Number out of range"); + { + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + upb_inttable_insert(&new_t, key, val, a); + } } - return val; + UPB_ASSERT(new_t.array_size == arr_size); + UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); } + *t = new_t; } -/* JSON string ****************************************************************/ +// Iteration. -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"); +bool upb_inttable_next(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter) { + intptr_t i = *iter; + if ((size_t)(i + 1) <= 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; + } + } + i--; // Back up to exactly one position before the start of the table. + } + + size_t tab_idx = next(&t->t, 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; } -static uint32_t jsondec_codepoint(jsondec* d) { - uint32_t cp = 0; - const char* end; +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; - if (d->end - d->ptr < 4) { - jsondec_err(d, "EOF inside string"); - } + // 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; + } + } - 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"); + if (prev) { + prev->next = ent->next; } - cp = (cp << 4) | ch; - } - return cp; + t->t.count--; + ent->key = 0; + ent->next = NULL; + } } -/* 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 (upb_Unicode_IsHigh(cp)) { - /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ - jsondec_parselit(d, "\\u"); - uint32_t low = jsondec_codepoint(d); - if (!upb_Unicode_IsLow(low)) jsondec_err(d, "Invalid low surrogate"); - cp = upb_Unicode_FromPair(cp, low); - } else if (upb_Unicode_IsLow(cp)) { - jsondec_err(d, "Unpaired low surrogate"); +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; } - /* Write to UTF-8 */ - int bytes = upb_Unicode_ToUTF8(cp, out); - if (bytes == 0) jsondec_err(d, "Invalid codepoint"); - return bytes; + 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); +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; - *buf = upb_Arena_Realloc(d->arena, *buf, len, size); - if (!*buf) jsondec_err(d, "Out of memory"); + // 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; + } + } - *end = *buf + len; - *buf_end = *buf + size; + if (prev) { + prev->next = ent->next; + } + + t->t.count--; + ent->key = 0; + ent->next = NULL; } -static upb_StringView jsondec_string(jsondec* d) { - char* buf = NULL; - char* end = NULL; - char* buf_end = NULL; - jsondec_skipws(d); +#include +#include +#include +#include +#include +#include +#include - if (*d->ptr++ != '"') { - jsondec_err(d, "Expected string"); - } - while (d->ptr < d->end) { - char ch = *d->ptr++; +// Must be last. - if (end == buf_end) { - jsondec_resize(d, &buf, &end, &buf_end); - } +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; - 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 codepoint (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; - } - } +enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; -eof: - jsondec_err(d, "EOF inside string"); +/* 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 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; - } +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; } -/* Base64 decoding for bytes fields. ******************************************/ +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); +} -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}; +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); +} - /* Sign-extend return value so high bit will be set on any unexpected char. */ - return table[(unsigned)ch]; +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 char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, - char* out) { - int32_t val = -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"); +} - 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 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; +} - if (val < 0) { - jsondec_err(d, "Corrupt base64"); +static void jsondec_wsch(jsondec* d, char ch) { + jsondec_skipws(d); + if (!jsondec_tryparsech(d, ch)) { + jsondec_errf(d, "Expected: '%c'", ch); } +} - return out; +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 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 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); + } +} - 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; +/* JSON object/array **********************************************************/ - 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; - } +/* These are used like so: + * + * jsondec_objstart(d); + * while (jsondec_objnext(d)) { + * ... + * } + * jsondec_objend(d) */ - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out[2] = val & 0xff; - } +static int jsondec_peek(jsondec* d) { + jsondec_skipws(d); + return jsondec_rawpeek(d); +} - if (ptr < end) { - /* Process remaining chars. We do not require padding. */ - out = jsondec_partialbase64(d, ptr, end, out); +static void jsondec_push(jsondec* d) { + if (--d->depth < 0) { + jsondec_err(d, "Recursion limit exceeded"); } + d->is_first = true; +} - return out - str.data; +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; } -/* Low-level integer parsing **************************************************/ +static void jsondec_arrstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '['); +} -static const char* jsondec_buftouint64(jsondec* d, const char* ptr, - const char* end, uint64_t* val) { - const char* out = upb_BufToUint64(ptr, end, val); - if (!out) jsondec_err(d, "Integer overflow"); - return out; +static void jsondec_arrend(jsondec* d) { + d->depth++; + jsondec_wsch(d, ']'); } -static const char* jsondec_buftoint64(jsondec* d, const char* ptr, - const char* end, int64_t* val, - bool* is_neg) { - const char* out = upb_BufToInt64(ptr, end, val, is_neg); - if (!out) jsondec_err(d, "Integer overflow"); - return out; +static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } + +static void jsondec_objstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '{'); } -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 void jsondec_objend(jsondec* d) { + d->depth++; + jsondec_wsch(d, '}'); } -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, NULL) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); +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 ret; + return true; } -/* Primitive value types ******************************************************/ - -/* Parse INT32 or INT64 value. */ -static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; +/* JSON number ****************************************************************/ - 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"); - } +static bool jsondec_tryskipdigits(jsondec* d) { + const char* start = d->ptr; - 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."); + while (d->ptr < d->end) { + if (*d->ptr < '0' || *d->ptr > '9') { + break; } - val.int32_val = (int32_t)val.int64_val; + d->ptr++; } - return val; + return d->ptr != start; } -/* 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; +static void jsondec_skipdigits(jsondec* d) { + if (!jsondec_tryskipdigits(d)) { + jsondec_err(d, "Expected one or more digits"); } - - 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}; +static double jsondec_number(jsondec* d) { + const char* start = d->ptr; - 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"); - } + assert(jsondec_rawpeek(d) == JD_NUMBER); - if (upb_FieldDef_CType(f) == kUpb_CType_Float) { - float f = val.double_val; - if (val.double_val != INFINITY && val.double_val != -INFINITY) { - if (f == INFINITY || f == -INFINITY) jsondec_err(d, "Float out of range"); + /* 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"); } - val.float_val = f; + } else { + jsondec_skipdigits(d); } - 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); + if (d->ptr == d->end) goto parse; + if (jsondec_tryparsech(d, '.')) { + jsondec_skipdigits(d); } - return val; -} + if (d->ptr == d->end) goto parse; -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; + if (*d->ptr == 'e' || *d->ptr == 'E') { + d->ptr++; + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF in number"); } - case JD_NULL: { - if (jsondec_isnullvalue(f)) { - upb_MessageValue val; - jsondec_null(d); - val.int32_val = 0; - return val; - } + if (*d->ptr == '+' || *d->ptr == '-') { + d->ptr++; } - /* Fallthrough. */ - default: - return jsondec_int(d, f); + jsondec_skipdigits(d); } -} -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; +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); - 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"); + /* 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"); } - } 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"); + */ + + if (val > DBL_MAX || val < -DBL_MAX) { + jsondec_err(d, "Number out of range"); } - } - return val; + 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; +/* JSON string ****************************************************************/ - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_MessageValue elem = jsondec_value(d, f); - upb_Array_Append(arr, elem, d->arena); +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"); } - 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); +static uint32_t jsondec_codepoint(jsondec* d) { + uint32_t cp = 0; + const char* end; - 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); + if (d->end - d->ptr < 4) { + jsondec_err(d, "EOF inside string"); } - 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); - const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); - upb_Message* msg = upb_Message_New(layout, 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)); + 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"); } - 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."); + cp = (cp << 4) | ch; } - preserved = d->debug_field; - d->debug_field = f; + return cp; +} - 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); +/* 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 (upb_Unicode_IsHigh(cp)) { + /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ + jsondec_parselit(d, "\\u"); + uint32_t low = jsondec_codepoint(d); + if (!upb_Unicode_IsLow(low)) jsondec_err(d, "Invalid low surrogate"); + cp = upb_Unicode_FromPair(cp, low); + } else if (upb_Unicode_IsLow(cp)) { + jsondec_err(d, "Unpaired low surrogate"); } - d->debug_field = preserved; + /* Write to UTF-8 */ + int bytes = upb_Unicode_ToUTF8(cp, out); + if (bytes == 0) jsondec_err(d, "Invalid codepoint"); + return bytes; } -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 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); -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(); - } -} + *buf = upb_Arena_Realloc(d->arena, *buf, len, size); + if (!*buf) jsondec_err(d, "Out of memory"); -/* Well-known types ***********************************************************/ + *end = *buf + len; + *buf_end = *buf + size; +} -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; +static upb_StringView jsondec_string(jsondec* d) { + char* buf = NULL; + char* end = NULL; + char* buf_end = NULL; - UPB_ASSERT(digits <= 9); /* int can't overflow. */ + jsondec_skipws(d); - if (jsondec_buftouint64(d, p, end, &val) != end || - (after_len && memcmp(end, after, after_len) != 0)) { - jsondec_err(d, "Malformed timestamp"); + if (*d->ptr++ != '"') { + jsondec_err(d, "Expected string"); } - UPB_ASSERT(val < INT_MAX); - - *ptr = end + after_len; - return (int)val; -} + while (d->ptr < d->end) { + char ch = *d->ptr++; -static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { - uint64_t nanos = 0; - const char* p = *ptr; + if (end == buf_end) { + jsondec_resize(d, &buf, &end, &buf_end); + } - 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"); + 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 codepoint (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; } - while (exp_lg10--) nanos *= 10; - *ptr = nano_end; } - UPB_ASSERT(nanos < INT_MAX); +eof: + jsondec_err(d, "EOF inside string"); +} - return (int)nanos; +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; + } } -/* 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); - } +/* Base64 decoding for bytes fields. ******************************************/ - nanos.int32_val = jsondec_nanos(d, &ptr, end); +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}; - { - /* [+-]08:00 or Z */ - int ofs_hour = 0; - int ofs_min = 0; - bool neg = false; + /* Sign-extend return value so high bit will be set on any unexpected char. */ + return table[(unsigned)ch]; +} - if (ptr == end) goto malformed; +static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, + char* out) { + int32_t val = -1; - 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; - } + 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 (seconds.int64_val < -62135596800) { - jsondec_err(d, "Timestamp out of range"); + if (val < 0) { + jsondec_err(d, "Corrupt base64"); } - 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"); + return out; } -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); +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 int64_t max = (uint64_t)3652500 * 86400; - bool neg = false; + const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ - /* "3.000000001s", "3s", etc. */ - ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); - nanos.int32_val = jsondec_nanos(d, &ptr, end); + 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 (end - ptr != 1 || *ptr != 's') { - jsondec_err(d, "Malformed duration"); - } + 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; + } - if (seconds.int64_val < -max || seconds.int64_val > max) { - jsondec_err(d, "Duration out of range"); + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; } - if (neg) { - nanos.int32_val = -nanos.int32_val; + if (ptr < end) { + /* Process remaining chars. We do not require padding. */ + out = jsondec_partialbase64(d, ptr, end, out); } - 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 out - str.data; } -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); - const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); - upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; +/* Low-level integer parsing **************************************************/ - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_Message* value_msg = upb_Message_New(value_layout, 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 const char* jsondec_buftouint64(jsondec* d, const char* ptr, + const char* end, uint64_t* val) { + const char* out = upb_BufToUint64(ptr, end, val); + if (!out) jsondec_err(d, "Integer overflow"); + return out; } -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); - const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); - upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; +static const char* jsondec_buftoint64(jsondec* d, const char* ptr, + const char* end, int64_t* val, + bool* is_neg) { + const char* out = upb_BufToInt64(ptr, end, val, is_neg); + if (!out) jsondec_err(d, "Integer overflow"); + return out; +} - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, value; - upb_Message* value_msg = upb_Message_New(value_layout, 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); +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"); } - jsondec_objend(d); + return ret; } -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { +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, NULL) != 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; - 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); + 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_NULL: - /* NullValue null_value = 1; */ - f = upb_MessageDef_FindFieldByNumber(m, 1); - val.int32_val = 0; - jsondec_null(d); + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.int64_val = jsondec_strtoint64(d, str); 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++; + jsondec_err(d, "Expected number or string"); } - 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; + 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 ret; + return 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; +/* Parse UINT32 or UINT64 value. */ +static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val = {0}; - 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; + 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; } - upb_Array_Append(arr, val, d->arena); + 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"); } -} -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'"); + if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { + if (val.uint64_val > UINT32_MAX) { + jsondec_err(d, "Integer out of range."); } - jsondec_wellknown(d, msg, m); + val.uint32_val = (uint32_t)val.uint64_val; } -} -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; + return val; +} - val.str_val = type_url; - upb_Message_Set(msg, type_url_f, val, d->arena); +/* Parse DOUBLE or FLOAT value. */ +static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { + upb_StringView str; + upb_MessageValue val = {0}; - /* Find message name after the last '/' */ - while (ptr > type_url.data && *--ptr != '/') { + 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 (ptr == type_url.data || ptr == end) { - jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + if (upb_FieldDef_CType(f) == kUpb_CType_Float) { + float f = val.double_val; + if (val.double_val != INFINITY && val.double_val != -INFINITY) { + if (f == INFINITY || f == -INFINITY) jsondec_err(d, "Float out of range"); + } + val.float_val = f; } - ptr++; - type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); + return val; +} - if (!type_m) { - jsondec_err(d, "Type was not found"); +/* 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 type_m; + 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; - - 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--; +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; } - } else { - if (!pre_type_data) pre_type_data = start; - jsondec_skipval(d); } + /* Fallthrough. */ + default: + return jsondec_int(d, f); } +} - if (!any_m) { - jsondec_err(d, "Any object didn't contain a '@type' field"); - } - - const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); - any_msg = upb_Message_New(any_layout, d->arena); +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 (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); + 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"); } - d->ptr = saved_ptr; - d->end = saved_end; } - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); - } + return val; +} - jsondec_objend(d); +/* Composite types (array/message/map) ****************************************/ - upb_EncodeStatus status = - upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, - (char**)&encoded.str_val.data, &encoded.str_val.size); - // TODO(b/235839510): We should fail gracefully here on a bad return status. - UPB_ASSERT(status == kUpb_EncodeStatus_Ok); - upb_Message_Set(msg, value_f, encoded, d->arena); +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_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_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_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(); +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); } } -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; +static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); + upb_Message* msg = upb_Message_New(layout, d->arena); + upb_MessageValue val; - if (size == 0) return true; + jsondec_tomsg(d, msg, m); + val.msg_val = msg; + return val; +} - 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 void jsondec_field(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_StringView name; + const upb_FieldDef* f; + const upb_FieldDef* preserved; - if (UPB_SETJMP(d.err)) return false; + name = jsondec_string(d); + jsondec_entrysep(d); - jsondec_tomsg(&d, msg, m); - return true; -} + 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; + } -#include -#include -#include -#include -#include -#include -#include + 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."); + } -// Must be last. + preserved = d->debug_field; + d->debug_field = f; -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; + 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); + } -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); + d->debug_field = preserved; +} -UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { - upb_Status_SetErrorMessage(e->status, msg); - longjmp(e->err, 1); +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_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_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(); + } } -static upb_Arena* jsonenc_arena(jsonenc* e) { - /* Create lazily, since it's only needed for Any */ - if (!e->arena) { - e->arena = upb_Arena_New(); +/* 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"); } - return e->arena; + + UPB_ASSERT(val < INT_MAX); + + *ptr = end + after_len; + return (int)val; } -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; +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"); } - e->overflow += (len - have); + while (exp_lg10--) nanos *= 10; + *ptr = nano_end; } + + UPB_ASSERT(nanos < INT_MAX); + + return (int)nanos; } -static void jsonenc_putstr(jsonenc* e, const char* str) { - jsonenc_putbytes(e, str, strlen(str)); +/* 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; } -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; +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; +} - va_start(args, fmt); - n = _upb_vsnprintf(e->ptr, have, fmt, args); - va_end(args); +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 (UPB_LIKELY(have > n)) { - e->ptr += n; - } else { - e->ptr = UPB_PTRADD(e->ptr, have); - e->overflow += (n - have); - } -} + if (str.size < 20) goto malformed; -static void jsonenc_nanos(jsonenc* e, int32_t nanos) { - int digits = 9; + { + /* 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); - if (nanos == 0) return; - if (nanos < 0 || nanos >= 1000000000) { - jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); + seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); } - while (nanos % 1000 == 0) { - nanos /= 1000; - digits -= 3; - } + nanos.int32_val = jsondec_nanos(d, &ptr, end); - jsonenc_printf(e, ".%.*" PRId32, digits, nanos); -} + { + /* [+-]08:00 or Z */ + int ofs_hour = 0; + int ofs_min = 0; + bool neg = false; -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 (ptr == end) goto malformed; - 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"); + 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; + } } - /* 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; + if (seconds.int64_val < -62135596800) { + jsondec_err(d, "Timestamp out of range"); + } - sec = seconds % 60; - min = (seconds / 60) % 60; - hour = (seconds / 3600) % 24; + 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; - jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "Z\""); +malformed: + jsondec_err(d, "Malformed timestamp"); } -static void jsonenc_duration(jsonenc* e, const upb_Message* msg, +static void jsondec_duration(jsondec* d, 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; - bool negative = false; + 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; + bool neg = false; - if (seconds > 315576000000 || seconds < -315576000000 || - (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { - jsonenc_err(e, "bad duration"); - } + /* "3.000000001s", "3s", etc. */ + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); + nanos.int32_val = jsondec_nanos(d, &ptr, end); - if (seconds < 0) { - negative = true; - seconds = -seconds; + if (end - ptr != 1 || *ptr != 's') { + jsondec_err(d, "Malformed duration"); } - if (nanos < 0) { - negative = true; - nanos = -nanos; + + if (seconds.int64_val < -max || seconds.int64_val > max) { + jsondec_err(d, "Duration out of range"); } - jsonenc_putstr(e, "\""); - if (negative) { - jsonenc_putstr(e, "-"); + if (neg) { + nanos.int32_val = -nanos.int32_val; } - jsonenc_printf(e, "%" PRId64, seconds); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "s\""); + + 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 jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { - const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); +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); + const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); + upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; - if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { - jsonenc_putstr(e, "null"); - } else { - const upb_EnumValueDef* ev = - (e->options & upb_JsonEncode_FormatEnumsAsIntegers) - ? NULL - : upb_EnumDef_FindValueByNumber(e_def, val); - - if (ev) { - jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); - } else { - jsonenc_printf(e, "%" PRId32, val); - } + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_Message* value_msg = upb_Message_New(value_layout, 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 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, "\""); +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); + const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); + upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; - 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; + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, value; + upb_Message* value_msg = upb_Message_New(value_layout, 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); +} - 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); +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 1: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4)]; - buf[2] = '='; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); + 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(); } - jsonenc_putstr(e, "\""); + upb_Message_Set(msg, f, val, d->arena); } -static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { - const char* ptr = str.data; - const char* end = UPB_PTRADD(ptr, str.size); +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) { - 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; - } + ret.size += (*ptr >= 'A' && *ptr <= 'Z'); ptr++; } -} -static void jsonenc_string(jsonenc* e, upb_StringView str) { - jsonenc_putstr(e, "\""); - jsonenc_stringbody(e, str); - jsonenc_putstr(e, "\""); -} + out = upb_Arena_Malloc(d->arena, ret.size); + ptr = buf; + ret.data = out; -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; + 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 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); + return ret; } -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 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 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 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* jsonenc_getanymsg(jsonenc* e, - upb_StringView type_url) { - /* Find last '/', if any. */ +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; - const upb_MessageDef* ret; + upb_MessageValue val; - 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); + val.str_val = type_url; + upb_Message_Set(msg, type_url_f, val, d->arena); - if (!ret) { - jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + /* Find message name after the last '/' */ + while (ptr > type_url.data && *--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_layout, 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"); + if (ptr == type_url.data || ptr == end) { + jsondec_err(d, "Type url must have at least one '/' and non-empty host"); } - jsonenc_putstr(e, "{\"@type\":"); - jsonenc_string(e, type_url); + ptr++; + type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); - 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); + if (!type_m) { + jsondec_err(d, "Type was not found"); } - jsonenc_putstr(e, "}"); -} - -static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { - if (*first) { - *first = false; - } else { - jsonenc_putstr(e, str); - } + return type_m; } -static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { - const char* ptr = path.data; - const char* end = ptr + path.size; +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; - while (ptr < end) { - char ch = *ptr; + jsondec_objstart(d); - 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."); + /* 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--; } - ch = *++ptr - 32; + } else { + if (!pre_type_data) pre_type_data = start; + jsondec_skipval(d); } - - 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); + if (!any_m) { + jsondec_err(d, "Any object didn't contain a '@type' field"); } - 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); + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + any_msg = upb_Message_New(any_layout, d->arena); - jsonenc_putsep(e, ",", &first); - jsonenc_string(e, key.str_val); - jsonenc_putstr(e, ":"); - jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + 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; } - 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); - } + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_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; + jsondec_objend(d); - if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { - jsonenc_err(e, "No value set in Value proto"); - } + upb_EncodeStatus status = + upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, + (char**)&encoded.str_val.data, &encoded.str_val.size); + // TODO(b/235839510): We should fail gracefully here on a bad return status. + UPB_ASSERT(status == kUpb_EncodeStatus_Ok); + upb_Message_Set(msg, value_f, encoded, d->arena); +} - 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 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 jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { +static void jsondec_wellknown(jsondec* d, 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); + jsondec_any(d, msg, m); break; case kUpb_WellKnown_FieldMask: - jsonenc_fieldmask(e, msg, m); + jsondec_fieldmask(d, msg, m); break; case kUpb_WellKnown_Duration: - jsonenc_duration(e, msg, m); + jsondec_duration(d, msg, m); break; case kUpb_WellKnown_Timestamp: - jsonenc_timestamp(e, msg, m); + 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: @@ -4656,3735 +3919,4039 @@ static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, 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); + jsondec_wrapper(d, msg, m); break; + default: + UPB_UNREACHABLE(); } } -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; - } -} +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; -static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - jsonenc_putstr(e, "\""); + if (size == 0) return true; - 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(); - } + 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; - jsonenc_putstr(e, "\":"); -} + if (UPB_SETJMP(d.err)) return false; -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; + jsondec_tomsg(&d, msg, m); + return true; +} - jsonenc_putstr(e, "["); - for (i = 0; i < size; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_scalar(e, upb_Array_Get(arr, i), f); - } +#include +#include +#include +#include +#include +#include - 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; +// Must be last. - jsonenc_putstr(e, "{"); +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; - 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); - } - } +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); - jsonenc_putstr(e, "}"); +UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { + upb_Status_SetErrorMessage(e->status, msg); + longjmp(e->err, 1); } -static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, - upb_MessageValue val, bool* first) { - const char* name; +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); +} - jsonenc_putsep(e, ",", first); +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; +} - 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)); +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 (e->options & upb_JsonEncode_UseProtoNames) { - name = upb_FieldDef_Name(f); - } else { - name = upb_FieldDef_JsonName(f); + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; } - jsonenc_printf(e, "\"%s\":", name); + e->overflow += (len - have); } +} - 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_putstr(jsonenc* e, const char* str) { + jsonenc_putbytes(e, str, strlen(str)); } -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first) { - upb_MessageValue val; - const upb_FieldDef* f; +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; - 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); - } - } + va_start(args, fmt); + n = _upb_vsnprintf(e->ptr, have, fmt, args); + va_end(args); + + if (UPB_LIKELY(have > n)) { + e->ptr += n; } 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); - } + e->ptr = UPB_PTRADD(e->ptr, have); + e->overflow += (n - have); } } -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 void jsonenc_nanos(jsonenc* e, int32_t nanos) { + int digits = 9; -static size_t jsonenc_nullz(jsonenc* e, size_t size) { - size_t ret = e->ptr - e->buf + e->overflow; + if (nanos == 0) return; + if (nanos < 0 || nanos >= 1000000000) { + jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); + } - if (size > 0) { - if (e->ptr == e->end) e->ptr--; - *e->ptr = '\0'; + while (nanos % 1000 == 0) { + nanos /= 1000; + digits -= 3; } - return ret; + jsonenc_printf(e, ".%.*" PRId32, digits, nanos); } -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); -} +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"); + } -#include + /* 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; -// Must be last. + sec = seconds % 60; + min = (seconds / 60) % 60; + hour = (seconds / 3600) % 24; -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); - } + jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "Z\""); } -upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - - -// Must be last. +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; + bool negative = false; -static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { - return (uint32_t*)(cleanup_metadata & ~0x1); -} + if (seconds > 315576000000 || seconds < -315576000000 || + (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { + jsonenc_err(e, "bad duration"); + } -static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { - return cleanup_metadata & 0x1; -} + if (seconds < 0) { + negative = true; + seconds = -seconds; + } + if (nanos < 0) { + negative = true; + nanos = -nanos; + } -static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, - bool has_initial_block) { - return (uintptr_t)cleanup | has_initial_block; + jsonenc_putstr(e, "\""); + if (negative) { + jsonenc_putstr(e, "-"); + } + jsonenc_printf(e, "%" PRId64, seconds); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "s\""); } -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 void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { + const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); -static const size_t memblock_reserve = - UPB_ALIGN_UP(sizeof(mem_block), UPB_MALLOC_ALIGN); + if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { + jsonenc_putstr(e, "null"); + } else { + const upb_EnumValueDef* ev = + (e->options & upb_JsonEncode_FormatEnumsAsIntegers) + ? NULL + : upb_EnumDef_FindValueByNumber(e_def, val); -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; + if (ev) { + jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); + } else { + jsonenc_printf(e, "%" PRId32, val); + } } - return a; } -size_t upb_Arena_SpaceAllocated(upb_Arena* arena) { - arena = arena_findroot(arena); - size_t memsize = 0; +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]; - mem_block* block = arena->freelist; + jsonenc_putstr(e, "\""); - while (block) { - memsize += sizeof(mem_block) + block->size; - block = block->next; + 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; } - return memsize; -} + 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; + } -uint32_t upb_Arena_DebugRefCount(upb_Arena* arena) { - return arena_findroot(arena)->refcount; + 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)); +static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { + const char* ptr = str.data; + const char* end = UPB_PTRADD(ptr, str.size); - UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); + 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 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); +static void jsonenc_string(jsonenc* e, upb_StringView str) { + jsonenc_putstr(e, "\""); + jsonenc_stringbody(e, str); + jsonenc_putstr(e, "\""); +} - if (!block) return false; - upb_Arena_addblock(a, root, block, block_size); +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; } -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_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_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 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); } -/* Public Arena API ***********************************************************/ +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 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; +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; - /* We need to malloc the initial block. */ - n = first_block_overhead + 256; - if (!alloc || !(mem = upb_malloc(alloc, n))) { - return NULL; + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); } - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - n -= sizeof(*a); + if (type_url.size == 0) goto badurl; - 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); + while (true) { + if (--ptr == type_url.data) { + /* Type URL must contain at least one '/', with host before. */ + goto badurl; + } + if (*ptr == '/') { + ptr++; + break; + } + } - upb_Arena_addblock(a, a, mem, n); + ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); - return a; -} + if (!ret) { + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + } -upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { - upb_Arena* a; + return ret; - 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; - } +badurl: + jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(type_url)); +} - /* 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)); +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_layout, arena); - if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { - return arena_initslow(mem, n, alloc); + if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + jsonenc_err(e, "Error decoding message in Any"); } - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + jsonenc_putstr(e, "{\"@type\":"); + jsonenc_string(e, type_url); - 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->freelist_tail = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, 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); + } - return a; + jsonenc_putstr(e, "}"); } -static void arena_dofree(upb_Arena* a) { - mem_block* block = a->freelist; - UPB_ASSERT(a->parent == a); - UPB_ASSERT(a->refcount == 0); +static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { + if (*first) { + *first = false; + } else { + jsonenc_putstr(e, str); + } +} - while (block) { - /* Load first since we are deleting block. */ - mem_block* next = block->next; +static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { + const char* ptr = path.data; + const char* end = ptr + path.size; - if (block->cleanups > 0) { - cleanup_ent* end = UPB_PTR_AT(block, block->size, void); - cleanup_ent* ptr = end - block->cleanups; + while (ptr < end) { + char ch = *ptr; - for (; ptr < end; ptr++) { - ptr->cleanup(ptr->ud); + 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; } - upb_free(a->block_alloc, block); - block = next; + jsonenc_putbytes(e, &ch, 1); + ptr++; } } -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); +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 (!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); - } + if (paths) n = upb_Array_Size(paths); - a->head.end -= sizeof(cleanup_ent); - ent = (cleanup_ent*)a->head.end; - (*cleanups)++; - UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); + jsonenc_putstr(e, "\""); - ent->cleanup = func; - ent->ud = ud; + for (i = 0; i < n; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); + } - return true; + jsonenc_putstr(e, "\""); } -bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { - upb_Arena* r1 = arena_findroot(a1); - upb_Arena* r2 = arena_findroot(a2); +static void jsonenc_struct(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); - if (r1 == r2) return true; /* Already fused. */ + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; - /* 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; + if (fields) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - /* Only allow fuse with a common allocator */ - if (r1->block_alloc != r2->block_alloc) return false; + size_t iter = kUpb_Map_Begin; + bool first = true; - /* 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; + upb_MessageValue key, val; + while (upb_Map_Next(fields, &key, &val, &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)); + } } - /* 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; + 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; -#include - - -// Must be last. - -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', '{', '|', '}', '~', -}; + jsonenc_putstr(e, "["); -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 (values) { + const size_t size = upb_Array_Size(values); + for (i = 0; i < size; i++) { + upb_MessageValue elem = upb_Array_Get(values, i); -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]; + jsonenc_putsep(e, ",", &first); + jsonenc_value(e, elem.msg_val, values_m); } } - return NULL; + + jsonenc_putstr(e, "]"); } -upb_FieldType upb_MiniTableField_Type(const upb_MiniTable_Field* field) { - if (field->mode & kUpb_LabelFlags_IsAlternate) { - if (field->descriptortype == kUpb_FieldType_Int32) { - return kUpb_FieldType_Enum; - } else if (field->descriptortype == kUpb_FieldType_Bytes) { - return kUpb_FieldType_String; - } else { - UPB_ASSERT(false); - } +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; } - return field->descriptortype; } +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; + } +} -#include +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, "\""); -// Must be last. + 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(); + } -// 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. + jsonenc_putstr(e, "\":"); +} - kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, -} upb_LayoutItemType; +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; -#define kUpb_LayoutItem_IndexSentinel ((uint16_t)-1) + jsonenc_putstr(e, "["); -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; + for (i = 0; i < size; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_scalar(e, upb_Array_Get(arr, i), f); + } -typedef struct { - upb_LayoutItem* data; - size_t size; - size_t capacity; -} upb_LayoutItemVector; + jsonenc_putstr(e, "]"); +} -typedef struct { - const char* end; - upb_MiniTable* table; - upb_MiniTable_Field* fields; - upb_MiniTablePlatform platform; - upb_LayoutItemVector vec; - upb_Arena* arena; - upb_Status* status; +static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { + jsonenc_putstr(e, "{"); - // When building enums. - upb_MiniTable_Enum* enum_table; - uint32_t enum_value_count; - uint32_t enum_data_count; - uint32_t enum_data_capacity; + 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); - jmp_buf err; -} upb_MtDecoder; + if (map) { + size_t iter = kUpb_Map_Begin; + bool first = true; -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); -} + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_mapkey(e, key, key_f); + jsonenc_scalar(e, val, val_f); + } + } -static void upb_MtDecoder_CheckOutOfMemory(upb_MtDecoder* d, const void* ptr) { - if (!ptr) upb_MtDecoder_ErrorFormat(d, "Out of memory"); + jsonenc_putstr(e, "}"); } -// 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 void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, + upb_MessageValue val, bool* first) { + const char* name; -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); - val |= bits << shift; - if (ptr == d->end || *ptr < min || max < *ptr) { - *out_val = val; - return ptr; - } - ch = *ptr++; - shift += bits_per_char; - if (shift >= 32) upb_MtDecoder_ErrorFormat(d, "Overlong varint"); - } -} + jsonenc_putsep(e, ",", first); -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; - field->mode |= kUpb_LabelFlags_IsAlternate; - } - return false; - default: - return false; + 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); } -} -static bool upb_MtDecoder_FieldIsPackable(upb_MiniTable_Field* field) { - return (field->mode & kUpb_FieldMode_Array) && - _upb_FieldType_IsPackable(field->descriptortype); + 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 upb_MiniTable_SetTypeAndSub(upb_MiniTable_Field* field, - upb_FieldType type, uint32_t* sub_count, - uint64_t msg_modifiers, - bool is_proto3_enum) { - field->descriptortype = type; - - if (is_proto3_enum) { - UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum); - field->descriptortype = kUpb_FieldType_Int32; - field->mode |= kUpb_LabelFlags_IsAlternate; - } +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first) { + upb_MessageValue val; + const upb_FieldDef* f; - if (upb_MiniTable_HasSub(field, msg_modifiers)) { - field->submsg_index = sub_count ? (*sub_count)++ : 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); + } + } } else { - field->submsg_index = kUpb_NoSub; + /* 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); + } } +} - if (upb_MtDecoder_FieldIsPackable(field) && - (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { - field->mode |= kUpb_LabelFlags_IsPacked; +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; } -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_OpenEnum] = 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, - [kUpb_EncodedType_ClosedEnum] = kUpb_FieldType_Enum, -}; +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; -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_Bytes] = kUpb_FieldRep_StringView, - [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, - [kUpb_EncodedType_OpenEnum] = 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, - [kUpb_EncodedType_ClosedEnum] = kUpb_FieldRep_4Byte, - }; + 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; - char pointer_rep = d->platform == kUpb_MiniTablePlatform_32Bit - ? kUpb_FieldRep_4Byte - : kUpb_FieldRep_8Byte; + if (UPB_SETJMP(e.err)) return -1; - int8_t type = _upb_FromBase92(ch); - if (ch >= _upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { - type -= kUpb_EncodedType_RepeatedBase; - field->mode = kUpb_FieldMode_Array; - field->mode |= pointer_rep << kUpb_FieldRep_Shift; - field->offset = kNoPresence; - } else { - field->mode = kUpb_FieldMode_Scalar; - field->offset = kHasbitPresence; - if (type == kUpb_EncodedType_Group || type == kUpb_EncodedType_Message) { - field->mode |= pointer_rep << kUpb_FieldRep_Shift; - } else if (type >= sizeof(kUpb_EncodedToFieldRep)) { - upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); - UPB_UNREACHABLE(); - } else { - field->mode |= kUpb_EncodedToFieldRep[type] << kUpb_FieldRep_Shift; - } - } - if (type >= sizeof(kUpb_EncodedToType)) { - upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); - UPB_UNREACHABLE(); - } - upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_count, - msg_modifiers, type == kUpb_EncodedType_OpenEnum); + jsonenc_msgfield(&e, msg, m); + if (e.arena) upb_Arena_Free(e.arena); + return jsonenc_nullz(&e, size); } -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(); + +// Must be last. + +const char* upb_BufToUint64(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) { + return NULL; // integer overflow } - field->mode ^= kUpb_LabelFlags_IsPacked; + u64 *= 10; + u64 += ch; + ptr++; } - bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; - bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; + *val = u64; + return ptr; +} - // 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 char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg) { + bool neg = false; + uint64_t u64; - if (singular) field->offset = kNoPresence; - if (required) { - field->offset = kRequiredPresence; + if (ptr != end && *ptr == '-') { + ptr++; + neg = true; } -} -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; + ptr = upb_BufToUint64(ptr, end, &u64); + if (!ptr || u64 > (uint64_t)INT64_MAX + neg) { + return NULL; // integer overflow } - d->vec.data[d->vec.size++] = item; + + *val = neg ? -u64 : u64; + if (is_neg) *is_neg = neg; + return ptr; } -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); +#include +#include - // Push oneof case. - item.rep = kUpb_FieldRep_4Byte; // Field Number. - item.type = kUpb_LayoutItemType_OneofCase; - upb_MtDecoder_PushItem(d, item); +// Must be last. + +/* 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 = '.'; + } } -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_StringView] = 8, - [kUpb_FieldRep_8Byte] = 8, - }; - static const uint8_t kRepToSize64[] = { - [kUpb_FieldRep_1Byte] = 1, - [kUpb_FieldRep_4Byte] = 4, - [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]; +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); } -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_StringView] = 4, - [kUpb_FieldRep_8Byte] = 8, - }; - static const uint8_t kRepToAlign64[] = { - [kUpb_FieldRep_1Byte] = 1, - [kUpb_FieldRep_4Byte] = 4, - [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]; +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); } -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(); - } +#include +#include - // 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; +// Must be last. + +// Determine the locale-specific radix character by calling sprintf() to print +// the number 1.5, then stripping off the digits. As far as I can tell, this +// is the only portable, thread-safe way to get the C library to divulge the +// locale's radix character. No, localeconv() is NOT thread-safe. + +static int GetLocaleRadix(char *data, size_t capacity) { + char temp[16]; + const int size = snprintf(temp, sizeof(temp), "%.1f", 1.5); + UPB_ASSERT(temp[0] == '1'); + UPB_ASSERT(temp[size - 1] == '5'); + UPB_ASSERT(size < capacity); + temp[size - 1] = '\0'; + strcpy(data, temp + 1); + return size - 2; } -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); - } - } +// Populates a string identical to *input except that the character pointed to +// by pos (which should be '.') is replaced with the locale-specific radix. - // Push final oneof. - upb_MtDecoder_PushOneof(d, item); - return ptr; +static void LocalizeRadix(const char *input, const char *pos, char *output) { + const int len1 = pos - input; + + char radix[8]; + const int len2 = GetLocaleRadix(radix, sizeof(radix)); + + memcpy(output, input, len1); + memcpy(output + len1, radix, len2); + strcpy(output + len1 + len2, input + len1 + 1); } -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(); +double _upb_NoLocaleStrtod(const char *str, char **endptr) { + // We cannot simply set the locale to "C" temporarily with setlocale() + // as this is not thread-safe. Instead, we try to parse in the current + // locale first. If parsing stops at a '.' character, then this is a + // pretty good hint that we're actually in some other locale in which + // '.' is not the radix character. + + char *temp_endptr; + double result = strtod(str, &temp_endptr); + if (endptr != NULL) *endptr = temp_endptr; + if (*temp_endptr != '.') return result; + + // Parsing halted on a '.'. Perhaps we're in a different locale? Let's + // try to replace the '.' with a locale-specific radix character and + // try again. + + char localized[80]; + LocalizeRadix(str, temp_endptr, localized); + char *localized_endptr; + result = strtod(localized, &localized_endptr); + if ((localized_endptr - &localized[0]) > (temp_endptr - str)) { + // This attempt got further, so replacing the decimal must have helped. + // Update endptr to point at the right location. + if (endptr != NULL) { + // size_diff is non-zero if the localized radix has multiple bytes. + int size_diff = strlen(localized) - strlen(str); + *endptr = (char *)str + (localized_endptr - &localized[0] - size_diff); } - *msg_modifiers = mod; } - return ptr; + return result; } -static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, uint32_t sub_count) { - size_t subs_bytes = sizeof(*d->table->subs) * sub_count; - void* subs = upb_Arena_Malloc(d->arena, subs_bytes); - memset(subs, 0, subs_bytes); - d->table->subs = subs; - upb_MtDecoder_CheckOutOfMemory(d, d->table->subs); + +// Must be last. + +int upb_Unicode_ToUTF8(uint32_t cp, char* out) { + if (cp <= 0x7f) { + out[0] = cp; + return 1; + } + if (cp <= 0x07ff) { + out[0] = (cp >> 6) | 0xc0; + out[1] = (cp & 0x3f) | 0x80; + return 2; + } + if (cp <= 0xffff) { + out[0] = (cp >> 12) | 0xe0; + out[1] = ((cp >> 6) & 0x3f) | 0x80; + out[2] = (cp & 0x3f) | 0x80; + return 3; + } + if (cp <= 0x10ffff) { + out[0] = (cp >> 18) | 0xf0; + out[1] = ((cp >> 12) & 0x3f) | 0x80; + out[2] = ((cp >> 6) & 0x3f) | 0x80; + out[3] = (cp & 0x3f) | 0x80; + return 4; + } + return 0; } -static const char* 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); +#include - while (ptr < d->end) { - char ch = *ptr++; - if (ch <= kUpb_EncodedValue_MaxField) { - if (!d->table && last_field) { - // For extensions, consume only a single field and then return. - return --ptr; - } - 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. - } else { - upb_MtDecoder_ErrorFormat(d, "Invalid char: %c", ch); - UPB_UNREACHABLE(); - } - } +// Must be last. - if (need_dense_below) { - d->table->dense_below = d->table->field_count; +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); } - - return ptr; } -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); +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - 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); +// Must be last. + +static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { + return (uint32_t*)(cleanup_metadata & ~0x1); } -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_cleanup_has_initial_block(uintptr_t cleanup_metadata) { + return cleanup_metadata & 0x1; } -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); - } +static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, + bool has_initial_block) { + return (uintptr_t)cleanup | has_initial_block; +} - if (d->vec.size) { - qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), - upb_MtDecoder_CompareFields); - } +struct _upb_MemBlock { + struct _upb_MemBlock* next; + uint32_t size; + uint32_t cleanups; + // Data follows. +}; - return true; -} +typedef struct cleanup_ent { + upb_CleanupFunc* cleanup; + void* ud; +} cleanup_ent; -static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { - return (n + d - 1) / d; +static const size_t memblock_reserve = + UPB_ALIGN_UP(sizeof(_upb_MemBlock), 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; } -static void upb_MtDecoder_AssignHasbits(upb_MiniTable* ret) { - int n = ret->field_count; - int last_hasbit = 0; // 0 cannot be used. +size_t upb_Arena_SpaceAllocated(upb_Arena* arena) { + arena = arena_findroot(arena); + size_t memsize = 0; - // 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; + _upb_MemBlock* block = arena->freelist; - // 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; - } + while (block) { + memsize += sizeof(_upb_MemBlock) + block->size; + block = block->next; } - ret->size = last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; + return memsize; } -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); - static const size_t max = UINT16_MAX; - size_t new_size = ret + size; - if (new_size > max) { - upb_MtDecoder_ErrorFormat( - d, "Message size exceeded maximum size of %zu bytes", max); - } - d->table->size = new_size; - return ret; +uint32_t upb_Arena_DebugRefCount(upb_Arena* arena) { + return arena_findroot(arena)->refcount; } -static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { - upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); +static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, + size_t size) { + _upb_MemBlock* block = ptr; - // Compute offsets. - for (upb_LayoutItem* item = d->vec.data; item < end; item++) { - item->offset = upb_MtDecoder_Place(d, item->rep); - } + /* 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; - // 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]; - } - } + 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)); - // 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; - } - } + UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); +} - // 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); +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; + _upb_MemBlock* block = upb_malloc(root->block_alloc, block_size); + + if (!block) return false; + upb_Arena_addblock(a, root, block, block_size); + return true; } -static void upb_MiniTable_BuildMapEntry(upb_MtDecoder* d, - upb_FieldType key_type, - upb_FieldType value_type, - bool value_is_proto3_enum) { - upb_MiniTable_Field* fields = upb_Arena_Malloc(d->arena, sizeof(*fields) * 2); - if (!fields) { - upb_MtDecoder_ErrorFormat(d, "OOM while building map mini table field"); - UPB_UNREACHABLE(); - } +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); +} - upb_MiniTable_Sub* subs = NULL; - if (value_is_proto3_enum) { - UPB_ASSERT(value_type == kUpb_FieldType_Enum); - // No sub needed. - } else if (value_type == kUpb_FieldType_Message || - value_type == kUpb_FieldType_Group || - value_type == kUpb_FieldType_Enum) { - subs = upb_Arena_Malloc(d->arena, sizeof(*subs)); - if (!subs) { - upb_MtDecoder_ErrorFormat(d, "OOM while building map mini table sub"); - UPB_UNREACHABLE(); - } +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 ***********************************************************/ + +static 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; } - size_t field_size = - upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, d->platform); + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + n -= sizeof(*a); - 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; + 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_MiniTable_SetTypeAndSub(&fields[0], key_type, NULL, 0, false); - upb_MiniTable_SetTypeAndSub(&fields[1], value_type, NULL, 0, - value_is_proto3_enum); + upb_Arena_addblock(a, a, mem, n); - upb_MiniTable* ret = d->table; - 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 a; } -static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data, - size_t len) { - if (len < 2) { - upb_MtDecoder_ErrorFormat(d, "Invalid map encode length: %zu", len); - UPB_UNREACHABLE(); - } - const upb_EncodedType e0 = _upb_FromBase92(data[0]); - const upb_EncodedType e1 = _upb_FromBase92(data[1]); - switch (e0) { - case kUpb_EncodedType_Fixed32: - case kUpb_EncodedType_Fixed64: - case kUpb_EncodedType_SFixed32: - case kUpb_EncodedType_SFixed64: - case kUpb_EncodedType_Int32: - case kUpb_EncodedType_UInt32: - case kUpb_EncodedType_SInt32: - case kUpb_EncodedType_Int64: - case kUpb_EncodedType_UInt64: - case kUpb_EncodedType_SInt64: - case kUpb_EncodedType_Bool: - case kUpb_EncodedType_String: - break; +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { + upb_Arena* a; - default: - upb_MtDecoder_ErrorFormat(d, "Invalid map key field type: %d", e0); - UPB_UNREACHABLE(); - } - if (e1 >= sizeof(kUpb_EncodedToType)) { - upb_MtDecoder_ErrorFormat(d, "Invalid map value field type: %d", e1); - UPB_UNREACHABLE(); + 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; } - const upb_FieldType key_type = kUpb_EncodedToType[e0]; - const upb_FieldType val_type = kUpb_EncodedToType[e1]; - const bool value_is_proto3_enum = (e1 == kUpb_EncodedType_OpenEnum); - upb_MiniTable_BuildMapEntry(d, key_type, val_type, value_is_proto3_enum); -} -static void upb_MtDecoder_ParseMessageSet(upb_MtDecoder* d, const char* data, - size_t len) { - if (len > 0) { - upb_MtDecoder_ErrorFormat(d, "Invalid message set encode length: %zu", len); - UPB_UNREACHABLE(); + /* 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); } - upb_MiniTable* ret = d->table; - ret->size = 0; - ret->field_count = 0; - ret->ext = kUpb_ExtMode_IsMessageSet; - ret->dense_below = 0; - ret->table_mask = -1; - ret->required_count = 0; -} - -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; - } + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table); + 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->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, true); - 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; + return a; +} - // Strip off and verify the version tag. - if (!len--) goto done; - const char vers = *data++; +static void arena_dofree(upb_Arena* a) { + _upb_MemBlock* block = a->freelist; + UPB_ASSERT(a->parent == a); + UPB_ASSERT(a->refcount == 0); - switch (vers) { - case kUpb_EncodedVersion_MapV1: - upb_MtDecoder_ParseMap(&decoder, data, len); - break; + while (block) { + /* Load first since we are deleting block. */ + _upb_MemBlock* next = block->next; - case kUpb_EncodedVersion_MessageV1: - upb_MtDecoder_ParseMessage(&decoder, data, len); - upb_MtDecoder_AssignHasbits(decoder.table); - upb_MtDecoder_SortLayoutItems(&decoder); - upb_MtDecoder_AssignOffsets(&decoder); - break; + if (block->cleanups > 0) { + cleanup_ent* end = UPB_PTR_AT(block, block->size, void); + cleanup_ent* ptr = end - block->cleanups; - case kUpb_EncodedVersion_MessageSetV1: - upb_MtDecoder_ParseMessageSet(&decoder, data, len); - break; + for (; ptr < end; ptr++) { + ptr->cleanup(ptr->ud); + } + } - default: - upb_MtDecoder_ErrorFormat(&decoder, "Invalid message version: %c", vers); - UPB_UNREACHABLE(); + upb_free(a->block_alloc, block); + block = next; } - -done: - *buf = decoder.vec.data; - *buf_size = decoder.vec.capacity * sizeof(*decoder.vec.data); - return decoder.table; } -static size_t upb_MiniTable_EnumSize(size_t count) { - return sizeof(upb_MiniTable_Enum) + count * sizeof(uint32_t); +void upb_Arena_Free(upb_Arena* a) { + a = arena_findroot(a); + if (--a->refcount == 0) arena_dofree(a); } -static upb_MiniTable_Enum* _upb_MiniTable_AddEnumDataMember(upb_MtDecoder* d, - uint32_t val) { - if (d->enum_data_count == d->enum_data_capacity) { - size_t old_sz = upb_MiniTable_EnumSize(d->enum_data_capacity); - d->enum_data_capacity = UPB_MAX(2, d->enum_data_capacity * 2); - size_t new_sz = upb_MiniTable_EnumSize(d->enum_data_capacity); - d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); - upb_MtDecoder_CheckOutOfMemory(d, d->enum_table); - } - d->enum_table->data[d->enum_data_count++] = val; - return d->enum_table; -} +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 upb_MiniTable_BuildEnumValue(upb_MtDecoder* d, uint32_t val) { - upb_MiniTable_Enum* table = d->enum_table; - d->enum_value_count++; - if (table->value_count || (val > 512 && d->enum_value_count < val / 32)) { - if (table->value_count == 0) { - assert(d->enum_data_count == table->mask_limit / 32); - } - table = _upb_MiniTable_AddEnumDataMember(d, val); - table->value_count++; - } else { - uint32_t new_mask_limit = ((val / 32) + 1) * 32; - while (table->mask_limit < new_mask_limit) { - table = _upb_MiniTable_AddEnumDataMember(d, 0); - table->mask_limit += 32; - } - table->data[val / 32] |= 1ULL << (val % 32); + 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); } -} -upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, - upb_Arena* arena, - upb_Status* status) { - upb_MtDecoder decoder = { - .enum_table = upb_Arena_Malloc(arena, upb_MiniTable_EnumSize(2)), - .enum_value_count = 0, - .enum_data_count = 0, - .enum_data_capacity = 1, - .status = status, - .end = UPB_PTRADD(data, len), - .arena = arena, - }; + a->head.end -= sizeof(cleanup_ent); + ent = (cleanup_ent*)a->head.end; + (*cleanups)++; + UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); - if (UPB_SETJMP(decoder.err)) return NULL; + ent->cleanup = func; + ent->ud = ud; - // If the string is non-empty then it must begin with a version tag. - if (len) { - if (*data != kUpb_EncodedVersion_EnumV1) { - upb_MtDecoder_ErrorFormat(&decoder, "Invalid enum version: %c", *data); - UPB_UNREACHABLE(); - } - data++; - len--; - } + return true; +} - upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.enum_table); +bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { + upb_Arena* r1 = arena_findroot(a1); + upb_Arena* r2 = arena_findroot(a2); - // Guarantee at least 64 bits of mask without checking mask size. - decoder.enum_table->mask_limit = 64; - decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); - decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); + if (r1 == r2) return true; /* Already fused. */ - decoder.enum_table->value_count = 0; + /* 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; - const char* ptr = data; - uint32_t base = 0; + /* Only allow fuse with a common allocator */ + if (r1->block_alloc != r2->block_alloc) return false; - while (ptr < decoder.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) upb_MiniTable_BuildEnumValue(&decoder, base); - } - } else if (kUpb_EncodedValue_MinSkip <= ch && - ch <= kUpb_EncodedValue_MaxSkip) { - uint32_t skip; - ptr = upb_MiniTable_DecodeBase92Varint(&decoder, ptr, ch, - kUpb_EncodedValue_MinSkip, - kUpb_EncodedValue_MaxSkip, &skip); - base += skip; - } else { - upb_Status_SetErrorFormat(status, "Unexpected character: %c", ch); - return NULL; - } + /* 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; } - return decoder.enum_table; + /* 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; } -const char* upb_MiniTable_BuildExtension(const char* data, size_t len, - upb_MiniTable_Extension* ext, - const upb_MiniTable* extendee, - upb_MiniTable_Sub sub, - upb_Status* status) { - upb_MtDecoder decoder = { - .arena = NULL, - .status = status, - .table = NULL, - }; - - if (UPB_SETJMP(decoder.err)) return NULL; - - // If the string is non-empty then it must begin with a version tag. - if (len) { - if (*data != kUpb_EncodedVersion_ExtensionV1) { - upb_MtDecoder_ErrorFormat(&decoder, "Invalid ext version: %c", *data); - UPB_UNREACHABLE(); - } - data++; - len--; - } - uint16_t count = 0; - const char* ret = - upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); - if (!ret || count != 1) return NULL; - upb_MiniTable_Field* f = &ext->field; +// Must be last. - f->mode |= kUpb_LabelFlags_IsExtension; - f->offset = 0; - f->presence = 0; +static size_t _upb_MiniTableField_Size(const upb_MiniTableField* 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]; +} - if (extendee->ext & kUpb_ExtMode_IsMessageSet) { - // Extensions of MessageSet must be messages. - if (!upb_IsSubMessage(f)) return NULL; +// Maps descriptor type to elem_size_lg2. +static int _upb_MiniTableField_CTypeLg2Size(const upb_MiniTableField* f) { + static const uint8_t sizes[] = { + -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 */ + }; + return sizes[f->descriptortype]; +} - // Extensions of MessageSet must be non-repeating. - if ((f->mode & kUpb_FieldMode_Mask) == kUpb_FieldMode_Array) return NULL; +void upb_MiniTable_ClearField(upb_Message* msg, + const upb_MiniTableField* field) { + char* mem = UPB_PTR_AT(msg, field->offset, char); + if (field->presence > 0) { + _upb_clearhas_field(msg, field); + } else if (_upb_MiniTableField_InOneOf(field)) { + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (*oneof_case != field->number) return; + *oneof_case = 0; } + memset(mem, 0, _upb_MiniTableField_Size(field)); +} - ext->extendee = extendee; - ext->sub = sub; - - return ret; +void* upb_MiniTable_ResizeArray(upb_Message* msg, + const upb_MiniTableField* field, size_t len, + upb_Arena* arena) { + return _upb_Array_Resize_accessor2( + msg, field->offset, len, _upb_MiniTableField_CTypeLg2Size(field), arena); } -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); +typedef struct { + const char* ptr; + uint64_t val; +} decode_vret; + +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; } -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 = (field->mode & ~kUpb_FieldMode_Mask) | kUpb_FieldMode_Map; +UPB_FORCEINLINE +static const char* decode_varint64(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 NULL; + *val = res.val; + return res.ptr; } - 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_FORCEINLINE +static const char* decode_tag(const char* ptr, uint32_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = (uint32_t)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 NULL; // Malformed. + } + *val = (uint32_t)res.val; + return res.ptr; + } } -#include - - -// Must be last. - -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; +// Parses unknown data by merging into existing base_message or creating a +// new message usingg mini_table. +static upb_UnknownToMessageRet upb_MiniTable_ParseUnknownMessage( + const char* unknown_data, size_t unknown_size, + const upb_MiniTable* mini_table, upb_Message* base_message, + int decode_options, upb_Arena* arena) { + upb_UnknownToMessageRet ret; + ret.message = + base_message ? base_message : _upb_Message_New(mini_table, arena); + if (!ret.message) { + ret.status = kUpb_UnknownToMessage_OutOfMemory; + return ret; + } + // Decode sub message using unknown field contents. + const char* data = unknown_data; + uint32_t tag; + uint64_t message_len = 0; + data = decode_tag(data, &tag); + data = decode_varint64(data, &message_len); + upb_DecodeStatus status = upb_Decode(data, message_len, ret.message, + mini_table, NULL, decode_options, arena); + if (status == kUpb_DecodeStatus_OutOfMemory) { + ret.status = kUpb_UnknownToMessage_OutOfMemory; + } else if (status == kUpb_DecodeStatus_Ok) { + ret.status = kUpb_UnknownToMessage_Ok; + } else { + ret.status = kUpb_UnknownToMessage_ParseError; + } return ret; } -static char* upb_MtDataEncoder_PutRaw(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++ = ch; - return ptr; +upb_GetExtension_Status upb_MiniTable_GetOrPromoteExtension( + upb_Message* msg, const upb_MiniTableExtension* ext_table, + int decode_options, upb_Arena* arena, + const upb_Message_Extension** extension) { + UPB_ASSERT(ext_table->field.descriptortype == kUpb_FieldType_Message); + *extension = _upb_Message_Getext(msg, ext_table); + if (*extension) { + return kUpb_GetExtension_Ok; + } + + // Check unknown fields, if available promote. + int field_number = ext_table->field.number; + upb_FindUnknownRet result = upb_MiniTable_FindUnknown(msg, field_number); + if (result.status != kUpb_FindUnknown_Ok) { + return kUpb_GetExtension_NotPresent; + } + // Decode and promote from unknown. + const upb_MiniTable* extension_table = ext_table->sub.submsg; + upb_UnknownToMessageRet parse_result = upb_MiniTable_ParseUnknownMessage( + result.ptr, result.len, extension_table, + /* base_message= */ NULL, decode_options, arena); + switch (parse_result.status) { + case kUpb_UnknownToMessage_OutOfMemory: + return kUpb_GetExtension_OutOfMemory; + case kUpb_UnknownToMessage_ParseError: + return kUpb_GetExtension_ParseError; + case kUpb_UnknownToMessage_NotFound: + return kUpb_GetExtension_NotPresent; + case kUpb_UnknownToMessage_Ok: + break; + } + upb_Message* extension_msg = parse_result.message; + // Add to extensions. + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, ext_table, arena); + if (!ext) { + return kUpb_GetExtension_OutOfMemory; + } + memcpy(&ext->data, &extension_msg, sizeof(extension_msg)); + *extension = ext; + upb_Message_DeleteUnknown(msg, result.ptr, result.len); + return kUpb_GetExtension_Ok; +} + +upb_GetExtensionAsBytes_Status upb_MiniTable_GetExtensionAsBytes( + const upb_Message* msg, const upb_MiniTableExtension* ext_table, + int encode_options, upb_Arena* arena, const char** extension_data, + size_t* len) { + const upb_Message_Extension* msg_ext = _upb_Message_Getext(msg, ext_table); + UPB_ASSERT(ext_table->field.descriptortype == kUpb_FieldType_Message); + if (msg_ext) { + upb_EncodeStatus status = + upb_Encode(msg_ext->data.ptr, msg_ext->ext->sub.submsg, encode_options, + arena, (char**)extension_data, len); + if (status != kUpb_EncodeStatus_Ok) { + return kUpb_GetExtensionAsBytes_EncodeError; + } + return kUpb_GetExtensionAsBytes_Ok; + } + int field_number = ext_table->field.number; + upb_FindUnknownRet result = upb_MiniTable_FindUnknown(msg, field_number); + if (result.status != kUpb_FindUnknown_Ok) { + return kUpb_GetExtensionAsBytes_NotPresent; + } + const char* data = result.ptr; + uint32_t tag; + uint64_t message_len = 0; + data = decode_tag(data, &tag); + data = decode_varint64(data, &message_len); + *extension_data = data; + *len = message_len; + return kUpb_GetExtensionAsBytes_Ok; } -static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { - return upb_MtDataEncoder_PutRaw(e, ptr, _upb_ToBase92(ch)); +static const char* UnknownFieldSet_SkipGroup(const char* ptr, const char* end, + int group_number); + +static const char* UnknownFieldSet_SkipField(const char* ptr, const char* end, + 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(ptr, &val); + } + case kUpb_WireType_64Bit: + if (end - ptr < 8) return NULL; + return ptr + 8; + case kUpb_WireType_32Bit: + if (end - ptr < 4) return NULL; + return ptr + 4; + case kUpb_WireType_Delimited: { + uint64_t size; + ptr = decode_varint64(ptr, &size); + if (!ptr || end - ptr < size) return NULL; + return ptr + size; + } + case kUpb_WireType_StartGroup: + return UnknownFieldSet_SkipGroup(ptr, end, field_number); + case kUpb_WireType_EndGroup: + return NULL; + default: + assert(0); + return NULL; + } } -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)); +static const char* UnknownFieldSet_SkipGroup(const char* ptr, const char* end, + int group_number) { + uint32_t end_tag = (group_number << 3) | kUpb_WireType_EndGroup; + while (true) { + if (ptr == end) return NULL; + uint64_t tag; + ptr = decode_varint64(ptr, &tag); if (!ptr) return NULL; - val >>= shift; - } while (val); + if (tag == end_tag) return ptr; + ptr = UnknownFieldSet_SkipField(ptr, end, (uint32_t)tag); + if (!ptr) return NULL; + } 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); +enum { + kUpb_MessageSet_StartItemTag = (1 << 3) | kUpb_WireType_StartGroup, + kUpb_MessageSet_EndItemTag = (1 << 3) | kUpb_WireType_EndGroup, + kUpb_MessageSet_TypeIdTag = (2 << 3) | kUpb_WireType_Varint, + kUpb_MessageSet_MessageTag = (3 << 3) | kUpb_WireType_Delimited, +}; + +upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg, + uint32_t field_number) { + size_t size; + upb_FindUnknownRet ret; + + const char* ptr = upb_Message_GetUnknown(msg, &size); + if (size == 0) { + ret.status = kUpb_FindUnknown_NotPresent; + ret.ptr = NULL; + ret.len = 0; + return ret; } - return ptr; -} + const char* end = ptr + size; + uint64_t uint64_val; -char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr, - upb_FieldType type, uint32_t field_num, - uint64_t field_mod) { - upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); - in->state.msg_state.msg_modifiers = 0; - in->state.msg_state.last_field_num = 0; - in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + while (ptr < end) { + uint32_t tag = 0; + int field; + int wire_type; + const char* unknown_begin = ptr; + ptr = decode_tag(ptr, &tag); + field = tag >> 3; + wire_type = tag & 7; + switch (wire_type) { + case kUpb_WireType_EndGroup: + ret.status = kUpb_FindUnknown_ParseError; + return ret; + case kUpb_WireType_Varint: + ptr = decode_varint64(ptr, &uint64_val); + if (!ptr) { + ret.status = kUpb_FindUnknown_ParseError; + return ret; + } + break; + case kUpb_WireType_32Bit: + ptr += 4; + break; + case kUpb_WireType_64Bit: + ptr += 8; + break; + case kUpb_WireType_Delimited: + // Read size. + ptr = decode_varint64(ptr, &uint64_val); + if (uint64_val >= INT32_MAX || !ptr) { + ret.status = kUpb_FindUnknown_ParseError; + return ret; + } + ptr += uint64_val; + break; + case kUpb_WireType_StartGroup: + // tag >> 3 specifies the group number, recurse and skip + // until we see group end tag. + ptr = UnknownFieldSet_SkipGroup(ptr, end, field_number); + break; + default: + ret.status = kUpb_FindUnknown_ParseError; + return ret; + } + if (field_number == field) { + ret.status = kUpb_FindUnknown_Ok; + ret.ptr = unknown_begin; + ret.len = ptr - unknown_begin; + return ret; + } + } + ret.status = kUpb_FindUnknown_NotPresent; + ret.ptr = NULL; + ret.len = 0; + return ret; +} - ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_ExtensionV1); - if (!ptr) return NULL; +upb_UnknownToMessageRet upb_MiniTable_PromoteUnknownToMessage( + upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTableField* field, const upb_MiniTable* sub_mini_table, + int decode_options, upb_Arena* arena) { + upb_FindUnknownRet unknown; + // We need to loop and merge unknowns that have matching tag field->number. + upb_Message* message = NULL; + // Callers should check that message is not set first before calling + // PromotoUnknownToMessage. + UPB_ASSERT(upb_MiniTable_GetMessage(msg, field, NULL) == NULL); + upb_UnknownToMessageRet ret; + ret.status = kUpb_UnknownToMessage_Ok; + do { + unknown = upb_MiniTable_FindUnknown(msg, field->number); + switch (unknown.status) { + case kUpb_FindUnknown_Ok: { + const char* unknown_data = unknown.ptr; + size_t unknown_size = unknown.len; + ret = upb_MiniTable_ParseUnknownMessage(unknown_data, unknown_size, + sub_mini_table, message, + decode_options, arena); + if (ret.status == kUpb_UnknownToMessage_Ok) { + message = ret.message; + upb_Message_DeleteUnknown(msg, unknown_data, unknown_size); + } + } break; + case kUpb_FindUnknown_ParseError: + ret.status = kUpb_UnknownToMessage_ParseError; + break; + case kUpb_FindUnknown_NotPresent: + // If we parsed at least one unknown, we are done. + ret.status = + message ? kUpb_UnknownToMessage_Ok : kUpb_UnknownToMessage_NotFound; + break; + } + } while (unknown.status == kUpb_FindUnknown_Ok); + if (message) { + upb_MiniTable_SetMessage(msg, mini_table, field, message); + ret.message = message; + } + return ret; +} - return upb_MtDataEncoder_PutField(e, ptr, type, field_num, field_mod); +// Moves repeated messages in unknowns to a upb_Array. +// +// Since the repeated field is not a scalar type we don't check for +// kUpb_LabelFlags_IsPacked. +// TODO(b/251007554): Optimize. Instead of converting messages one at a time, +// scan all unknown data once and compact. +upb_UnknownToMessage_Status upb_MiniTable_PromoteUnknownToMessageArray( + upb_Message* msg, const upb_MiniTableField* field, + const upb_MiniTable* mini_table, int decode_options, upb_Arena* arena) { + upb_Array* repeated_messages = upb_MiniTable_GetMutableArray(msg, field); + // Find all unknowns with given field number and parse. + upb_FindUnknownRet unknown; + do { + unknown = upb_MiniTable_FindUnknown(msg, field->number); + if (unknown.status == kUpb_FindUnknown_Ok) { + upb_UnknownToMessageRet ret = upb_MiniTable_ParseUnknownMessage( + unknown.ptr, unknown.len, mini_table, + /* base_message= */ NULL, decode_options, arena); + if (ret.status == kUpb_UnknownToMessage_Ok) { + upb_MessageValue value; + value.msg_val = ret.message; + if (!upb_Array_Append(repeated_messages, value, arena)) { + return kUpb_UnknownToMessage_OutOfMemory; + } + upb_Message_DeleteUnknown(msg, unknown.ptr, unknown.len); + } else { + return ret.status; + } + } + } while (unknown.status == kUpb_FindUnknown_Ok); + return kUpb_UnknownToMessage_Ok; } -char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr, - upb_FieldType key_type, - upb_FieldType value_type, - uint64_t value_mod) { - upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); - in->state.msg_state.msg_modifiers = 0; - in->state.msg_state.last_field_num = 0; - in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; - ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MapV1); - if (!ptr) return NULL; +#include - ptr = upb_MtDataEncoder_PutField(e, ptr, key_type, 1, 0); - if (!ptr) return NULL; - return upb_MtDataEncoder_PutField(e, ptr, value_type, 2, value_mod); -} +// Must be last. -char* upb_MtDataEncoder_EncodeMessageSet(upb_MtDataEncoder* e, char* ptr) { - (void)upb_MtDataEncoder_GetInternal(e, ptr); - return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageSetV1); -} +const float kUpb_FltInfinity = INFINITY; +const double kUpb_Infinity = INFINITY; +const double kUpb_NaN = NAN; -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; +static const size_t overhead = sizeof(upb_Message_InternalData); - ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageV1); - if (!ptr) return NULL; +upb_Message* upb_Message_New(const upb_MiniTable* mini_table, + upb_Arena* arena) { + return _upb_Message_New(mini_table, arena); +} - return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); +void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { + // Note: Can't use UPB_PTR_AT() here because we are doing pointer subtraction. + char* mem = (char*)msg - sizeof(upb_Message_Internal); + memset(mem, 0, upb_msg_sizeof(l)); } -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_OpenEnum, - [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. - int encoded_type = kUpb_TypeToEncoded[type]; - if (field_mod & kUpb_FieldModifier_IsClosedEnum) { - UPB_ASSERT(type == kUpb_FieldType_Enum); - encoded_type = kUpb_EncodedType_ClosedEnum; - } - 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_FieldType_IsPackable(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; - } +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; } - ptr = upb_MtDataEncoder_Put(e, ptr, encoded_type); - if (!ptr) return NULL; + UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); + return true; +} - if (field_mod & kUpb_FieldModifier_IsProto3Singular) { - encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; - } - if (field_mod & kUpb_FieldModifier_IsRequired) { - encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; +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; } - 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)); +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { + const upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (in->internal) { + *len = in->internal->unknown_end - overhead; + return (char*)(in->internal + 1); } else { - ptr = upb_MtDataEncoder_Put( - e, ptr, _upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); + *len = 0; + return NULL; } - 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; +void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + const char* internal_unknown_end = + UPB_PTR_AT(in->internal, in->internal->unknown_end, char); +#ifndef NDEBUG + size_t full_unknown_size; + const char* full_unknown = upb_Message_GetUnknown(msg, &full_unknown_size); + UPB_ASSERT((uintptr_t)data >= (uintptr_t)full_unknown); + UPB_ASSERT((uintptr_t)data < (uintptr_t)(full_unknown + full_unknown_size)); + UPB_ASSERT((uintptr_t)(data + len) > (uintptr_t)data); + UPB_ASSERT((uintptr_t)(data + len) <= (uintptr_t)internal_unknown_end); +#endif + if ((data + len) != internal_unknown_end) { + memmove((char*)data, data + len, internal_unknown_end - data - len); } - 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; + in->internal->unknown_end -= len; } -char* upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e, char* ptr) { - upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); - in->state.enum_state.present_values_mask = 0; - in->state.enum_state.last_written_value = 0; - - return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_EnumV1); +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count) { + const upb_Message_Internal* in = upb_Message_Getinternal(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; + } } -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_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTableExtension* e) { + size_t n; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); -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); - if (!ptr) { - return NULL; + /* 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]; } - 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; + return NULL; +} + +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTableExtension* 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_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); - in->state.enum_state.present_values_mask |= 1ULL << delta; - return ptr; +upb_Message_Extension* _upb_Message_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTableExtension* 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; } -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); +size_t upb_Message_ExtensionCount(const upb_Message* msg) { + size_t count; + _upb_Message_Getexts(msg, &count); + return count; } -#include + +#include // Must be last. -/* 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}; -const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; +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', '{', '|', '}', '~', +}; -const char* _upb_DefBuilder_FullToShort(const char* fullname) { - const char* p; +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 (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_MiniTableField* 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; } -void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); } - -void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(ctx->status, fmt, argp); - va_end(argp); - _upb_DefBuilder_FailJmp(ctx); +upb_FieldType upb_MiniTableField_Type(const upb_MiniTableField* field) { + if (field->mode & kUpb_LabelFlags_IsAlternate) { + if (field->descriptortype == kUpb_FieldType_Int32) { + return kUpb_FieldType_Enum; + } else if (field->descriptortype == kUpb_FieldType_Bytes) { + return kUpb_FieldType_String; + } else { + UPB_ASSERT(false); + } + } + return field->descriptortype; } -void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { - upb_Status_SetErrorMessage(ctx->status, "out of memory"); - _upb_DefBuilder_FailJmp(ctx); -} -const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, - const char* prefix, - upb_StringView name) { - if (prefix) { - // ret = prefix + '.' + name; - size_t n = strlen(prefix); - char* ret = _upb_DefBuilder_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 { - char* ret = upb_strdup2(name.data, name.size, ctx->arena); - if (!ret) _upb_DefBuilder_OomErr(ctx); - return ret; - } -} +#include +#include -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; - } - } +// Must be last. - *len = 0; - return true; -} +// 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. -const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, - const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t* type) { - 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_DefPool_LookupSym(ctx->symtab, 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_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) { - break; - } - if (!remove_component(tmp, &baselen)) { - free(tmp); - goto notfound; - } - } - free(tmp); - } + kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, +} upb_LayoutItemType; - *type = _upb_DefType_Type(v); - return _upb_DefType_Unpack(v, *type); +#define kUpb_LayoutItem_IndexSentinel ((uint16_t)-1) -notfound: - _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(sym)); -} +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; -const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, - const char* from_name_dbg, const char* base, - upb_StringView sym, upb_deftype_t type) { - upb_deftype_t found_type; - const void* ret = - _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); - if (ret && found_type != type) { - _upb_DefBuilder_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; -} +typedef struct { + upb_LayoutItem* data; + size_t size; + size_t capacity; +} upb_LayoutItemVector; -// 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. -static char upb_ascii_lower(char ch) { return ch | 0x20; } +typedef struct { + const char* end; + upb_MiniTable* table; + upb_MiniTableField* fields; + upb_MiniTablePlatform platform; + upb_LayoutItemVector vec; + upb_Arena* arena; + upb_Status* status; -// 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 low <= c && c <= high; -} + // When building enums. + upb_MiniTableEnum* enum_table; + uint32_t enum_value_count; + uint32_t enum_data_count; + uint32_t enum_data_capacity; -static bool upb_isletter(char c) { - char lower = upb_ascii_lower(c); - return upb_isbetween(lower, 'a', 'z') || c == '_'; -} + jmp_buf err; +} upb_MtDecoder; -static bool upb_isalphanum(char c) { - return upb_isletter(c) || upb_isbetween(c, '0', '9'); +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 bool TryGetChar(const char** src, const char* end, char* ch) { - if (*src == end) return false; - *ch = **src; - *src += 1; - return true; +static void upb_MtDecoder_CheckOutOfMemory(upb_MtDecoder* d, const void* ptr) { + if (!ptr) upb_MtDecoder_ErrorFormat(d, "Out of memory"); } -static char TryGetHexDigit(const char** src, const char* end) { - char ch; - if (!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; +// 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); + val |= bits << shift; + if (ptr == d->end || *ptr < min || max < *ptr) { + *out_val = val; + return ptr; + } + ch = *ptr++; + shift += bits_per_char; + if (shift >= 32) upb_MtDecoder_ErrorFormat(d, "Overlong varint"); } - *src -= 1; // Char wasn't actually a hex digit. - return -1; } -static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, - const upb_FieldDef* f, - const char** src, const char* end) { - char hex_digit = TryGetHexDigit(src, end); - if (hex_digit < 0) { - _upb_DefBuilder_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 = TryGetHexDigit(src, end)) >= 0) { - ret = (ret << 4) | hex_digit; - } - if (ret > 0xff) { - _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", - upb_FieldDef_FullName(f)); - return 0; +static bool upb_MiniTable_HasSub(upb_MiniTableField* 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; + field->mode |= kUpb_LabelFlags_IsAlternate; + } + return false; + default: + return false; } - return ret; } -static char TryGetOctalDigit(const char** src, const char* end) { - char ch; - if (!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; +static bool upb_MtDecoder_FieldIsPackable(upb_MiniTableField* field) { + return (field->mode & kUpb_FieldMode_Array) && + _upb_FieldType_IsPackable(field->descriptortype); } -static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* 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 = TryGetOctalDigit(src, end)) >= 0) { - ch = (ch << 3) | digit; - } +static void upb_MiniTable_SetTypeAndSub(upb_MiniTableField* field, + upb_FieldType type, uint32_t* sub_count, + uint64_t msg_modifiers, + bool is_proto3_enum) { + field->descriptortype = type; + + if (is_proto3_enum) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum); + field->descriptortype = kUpb_FieldType_Int32; + field->mode |= kUpb_LabelFlags_IsAlternate; } - return ch; -} -char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, - const char** src, const char* end) { - char ch; - if (!TryGetChar(src, end, &ch)) { - _upb_DefBuilder_Errf(ctx, "unterminated escape sequence in field %s", - upb_FieldDef_FullName(f)); - return 0; + if (upb_MiniTable_HasSub(field, msg_modifiers)) { + field->submsg_index = sub_count ? (*sub_count)++ : 0; + } else { + field->submsg_index = kUpb_NoSub; } - 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_DefBuilder_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_DefBuilder_ParseOctalEscape(ctx, f, src, end); + + if (upb_MtDecoder_FieldIsPackable(field) && + (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { + field->mode |= kUpb_LabelFlags_IsPacked; } - _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); } -void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, - bool full) { - const char* str = name.data; - const size_t len = name.size; - bool start = true; - for (size_t i = 0; i < len; i++) { - const char c = str[i]; - if (c == '.') { - if (start || !full) { - _upb_DefBuilder_Errf( - ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", - UPB_STRINGVIEW_ARGS(name)); - } - start = true; - } else if (start) { - if (!upb_isletter(c)) { - _upb_DefBuilder_Errf(ctx, - "invalid name: path components must start with a " - "letter (" UPB_STRINGVIEW_FORMAT ")", - UPB_STRINGVIEW_ARGS(name)); - } - start = false; - } else if (!upb_isalphanum(c)) { - _upb_DefBuilder_Errf( - ctx, - "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT - ")", - UPB_STRINGVIEW_ARGS(name)); +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_OpenEnum] = 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, + [kUpb_EncodedType_ClosedEnum] = kUpb_FieldType_Enum, +}; + +static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, + upb_MiniTableField* 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_Bytes] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_OpenEnum] = 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, + [kUpb_EncodedType_ClosedEnum] = kUpb_FieldRep_4Byte, + }; + + char pointer_rep = d->platform == kUpb_MiniTablePlatform_32Bit + ? kUpb_FieldRep_4Byte + : kUpb_FieldRep_8Byte; + + int8_t type = _upb_FromBase92(ch); + if (ch >= _upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { + type -= kUpb_EncodedType_RepeatedBase; + field->mode = kUpb_FieldMode_Array; + field->mode |= pointer_rep << kUpb_FieldRep_Shift; + field->offset = kNoPresence; + } else { + field->mode = kUpb_FieldMode_Scalar; + field->offset = kHasbitPresence; + if (type == kUpb_EncodedType_Group || type == kUpb_EncodedType_Message) { + field->mode |= pointer_rep << kUpb_FieldRep_Shift; + } else if (type >= sizeof(kUpb_EncodedToFieldRep)) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); + } else { + field->mode |= kUpb_EncodedToFieldRep[type] << kUpb_FieldRep_Shift; } } - if (start) { - _upb_DefBuilder_Errf(ctx, - "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", - UPB_STRINGVIEW_ARGS(name)); + if (type >= sizeof(kUpb_EncodedToType)) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); } - - // We should never reach this point. - UPB_ASSERT(false); + upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_count, + msg_modifiers, type == kUpb_EncodedType_OpenEnum); } +static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, + uint32_t message_modifiers, + uint32_t field_modifiers, + upb_MiniTableField* 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; + } -// Must be last. + bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; + bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; -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; - void* scratch_data; - size_t scratch_size; - size_t bytes_loaded; -}; + // 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(); + } -void upb_DefPool_Free(upb_DefPool* s) { - upb_Arena_Free(s->arena); - upb_gfree(s->scratch_data); - upb_gfree(s); + if (singular) field->offset = kNoPresence; + if (required) { + field->offset = kRequiredPresence; + } } -upb_DefPool* upb_DefPool_New(void) { - upb_DefPool* s = upb_gmalloc(sizeof(*s)); - if (!s) return NULL; - - s->arena = upb_Arena_New(); - s->bytes_loaded = 0; +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; +} - s->scratch_size = 240; - s->scratch_data = upb_gmalloc(s->scratch_size); - if (!s->scratch_data) goto err; +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; - if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; - if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; - if (!upb_inttable_init(&s->exts, s->arena)) goto err; + // Push oneof data. + item.type = kUpb_LayoutItemType_OneofField; + upb_MtDecoder_PushItem(d, item); - s->extreg = upb_ExtensionRegistry_New(s->arena); - if (!s->extreg) goto err; + // Push oneof case. + item.rep = kUpb_FieldRep_4Byte; // Field Number. + item.type = kUpb_LayoutItemType_OneofCase; + upb_MtDecoder_PushItem(d, item); +} - return s; - -err: - upb_DefPool_Free(s); - return NULL; +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_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToSize64[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [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]; } -bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, - upb_FieldDef* f) { - return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), - s->arena); +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_StringView] = 4, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToAlign64[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [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]; } -bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, - upb_Status* status) { - // TODO: table should support an operation "tryinsert" to avoid the double - // lookup. - if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) { - upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data); - return false; +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_MiniTableField* 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 (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) { - upb_Status_SetErrorMessage(status, "out of memory"); - return false; + if (f->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, + "Cannot add repeated, required, or singular field %" PRIu32 + " to oneof.", + field_num); + UPB_UNREACHABLE(); } - return true; -} - -static const void* _upb_DefPool_Unpack(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) - ? _upb_DefType_Unpack(v, type) - : NULL; -} - -bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, - upb_value* v) { - return upb_strtable_lookup2(&s->syms, sym, size, v); -} - -upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { - return s->extreg; -} - -void** _upb_DefPool_ScratchData(const upb_DefPool* s) { - return (void**)&s->scratch_data; -} -size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) { - return (size_t*)&s->scratch_size; + // 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; } -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym) { - return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_MSG); -} +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_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len) { - return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG); + // Push final oneof. + upb_MtDecoder_PushOneof(d, item); + return ptr; } -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym) { - return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUM); -} +static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, + const char* ptr, char first_ch, + upb_MiniTableField* 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; + } -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym) { - return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUMVAL); + return ptr; } -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name) { - upb_value v; - return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) - : NULL; +static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, uint32_t sub_count) { + size_t subs_bytes = sizeof(*d->table->subs) * sub_count; + void* subs = upb_Arena_Malloc(d->arena, subs_bytes); + memset(subs, 0, subs_bytes); + d->table->subs = subs; + upb_MtDecoder_CheckOutOfMemory(d, d->table->subs); } -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) - ? upb_value_getconstptr(v) - : NULL; -} +static const char* 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_MiniTableField* last_field = NULL; + bool need_dense_below = d->table != 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; + d->end = UPB_PTRADD(ptr, len); - switch (_upb_DefType_Type(v)) { - case UPB_DEFTYPE_FIELD: - return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); - return _upb_MessageDef_InMessageSet(m) - ? upb_MessageDef_NestedExtension(m, 0) - : NULL; + while (ptr < d->end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxField) { + if (!d->table && last_field) { + // For extensions, consume only a single field and then return. + return --ptr; + } + upb_MiniTableField* 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. + } else { + upb_MtDecoder_ErrorFormat(d, "Invalid char: %c", ch); + UPB_UNREACHABLE(); } - 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)); -} + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + } -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name) { - return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE); + return ptr; } -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE); -} +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); -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 (_upb_DefType_Type(v)) { - case UPB_DEFTYPE_EXT: { - const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); - return upb_FieldDef_File(f); - } - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); - return upb_MessageDef_File(m); - } - case UPB_DEFTYPE_ENUM: { - const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); - return upb_EnumDef_File(e); - } - case UPB_DEFTYPE_ENUMVAL: { - const upb_EnumValueDef* ev = - _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); - return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); - } - case UPB_DEFTYPE_SERVICE: { - const upb_ServiceDef* service = - _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); - return upb_ServiceDef_File(service); - } - default: - UPB_UNREACHABLE(); - } - } + 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); - 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); - } - } - } + 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); +} - return NULL; +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 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 (_upb_DefType_Type(val)) { - case UPB_DEFTYPE_EXT: - f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); - break; - case UPB_DEFTYPE_MSG: - f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); - break; - case UPB_DEFTYPE_ENUM: - f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); - break; - case UPB_DEFTYPE_ENUMVAL: - f = upb_EnumDef_File(upb_EnumValueDef_Enum( - _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); - break; - case UPB_DEFTYPE_SERVICE: - f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); - break; - default: - UPB_UNREACHABLE(); - } +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_MiniTableField* 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 (f == file) upb_strtable_removeiter(&s->syms, &iter); + if (d->vec.size) { + qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), + upb_MtDecoder_CompareFields); } + + return true; } -static const upb_FileDef* _upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - const upb_MiniTable_File* layout, upb_Status* status) { - const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); +static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { + return (n + d - 1) / d; +} - if (name.size == 0) { - upb_Status_SetErrorFormat(status, - "missing name in google_protobuf_FileDescriptorProto"); - return NULL; - } +static void upb_MtDecoder_AssignHasbits(upb_MiniTable* ret) { + int n = ret->field_count; + int last_hasbit = 0; // 0 cannot be used. - // Determine whether we already know about this file. - { - upb_value v; - if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { - upb_Status_SetErrorFormat(status, - "duplicate file name " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(name)); - return NULL; + // First assign required fields, which must have the lowest hasbits. + for (int i = 0; i < n; i++) { + upb_MiniTableField* field = (upb_MiniTableField*)&ret->fields[i]; + if (field->offset == kRequiredPresence) { + field->presence = ++last_hasbit; + } else if (field->offset == kNoPresence) { + field->presence = 0; } } + ret->required_count = last_hasbit; - upb_DefBuilder ctx = { - .symtab = s, - .layout = layout, - .msg_count = 0, - .enum_count = 0, - .ext_count = 0, - .status = status, - .file = NULL, - .arena = upb_Arena_New(), - .tmp_arena = upb_Arena_New(), - }; - - if (UPB_SETJMP(ctx.err)) { - UPB_ASSERT(!upb_Status_IsOk(status)); - if (ctx.file) { - remove_filedef(s, ctx.file); - ctx.file = NULL; + // Next assign non-required hasbit fields. + for (int i = 0; i < n; i++) { + upb_MiniTableField* field = (upb_MiniTableField*)&ret->fields[i]; + if (field->offset == kHasbitPresence) { + field->presence = ++last_hasbit; } - } else if (!ctx.arena || !ctx.tmp_arena) { - _upb_DefBuilder_OomErr(&ctx); - } else { - _upb_FileDef_Create(&ctx, file_proto); - upb_strtable_insert(&s->files, name.data, name.size, - upb_value_constptr(ctx.file), ctx.arena); - UPB_ASSERT(upb_Status_IsOk(status)); - upb_Arena_Fuse(s->arena, ctx.arena); } - if (ctx.arena) upb_Arena_Free(ctx.arena); - if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); - return ctx.file; + ret->size = last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; } -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); +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); + static const size_t max = UINT16_MAX; + size_t new_size = ret + size; + if (new_size > max) { + upb_MtDecoder_ErrorFormat( + d, "Message size exceeded maximum size of %zu bytes", max); + } + d->table->size = new_size; + return ret; } -/* 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); +static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { + upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); - if (upb_DefPool_FindFileByName(s, init->filename)) { - return true; + // Compute offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + item->offset = upb_MtDecoder_Place(d, item->rep); } - arena = upb_Arena_New(); - - for (; *deps; deps++) { - if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; + // 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_MiniTableField* 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]; + } } - file = google_protobuf_FileDescriptorProto_parse_ex( - init->descriptor.data, init->descriptor.size, NULL, - kUpb_DecodeOption_AliasString, arena); - s->bytes_loaded += init->descriptor.size; + // Assign offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + upb_MiniTableField* 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; + } + } - if (!file) { - upb_Status_SetErrorFormat( - &status, - "Failed to parse compiled-in descriptor for file '%s'. This should " - "never happen.", - init->filename); - goto err; - } + // 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); +} - const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; - if (!_upb_DefPool_AddFile(s, file, mt, &status)) { - goto err; +static void upb_MiniTable_BuildMapEntry(upb_MtDecoder* d, char key_type, + char val_type) { + upb_MiniTableField* fields = upb_Arena_Malloc(d->arena, sizeof(*fields) * 2); + if (!fields) { + upb_MtDecoder_ErrorFormat(d, "OOM while building map mini table field"); + UPB_UNREACHABLE(); } - 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; -} + size_t field_size = + upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, d->platform); -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { - return s->bytes_loaded; -} + uint32_t sub_count = 0; + fields[0].number = 1; + fields[1].number = 2; + upb_MiniTable_SetField(d, key_type, &fields[0], 0, &sub_count); + upb_MiniTable_SetField(d, val_type, &fields[1], 0, &sub_count); + upb_MtDecoder_AllocateSubs(d, sub_count); -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } + // Map entries have a pre-determined layout, regardless of types. + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].offset = 0; + fields[1].offset = field_size; -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_MiniTable* ret = d->table; + 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->fields = fields; } -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum) { - const upb_MiniTable* t = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Extension* ext = - upb_ExtensionRegistry_Lookup(s->extreg, t, fieldnum); - return ext ? upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; -} +static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data, + size_t len) { + if (len < 2) { + upb_MtDecoder_ErrorFormat(d, "Invalid map encode length: %zu", len); + UPB_UNREACHABLE(); + } + const upb_EncodedType key_type = _upb_FromBase92(data[0]); + switch (key_type) { + case kUpb_EncodedType_Fixed32: + case kUpb_EncodedType_Fixed64: + case kUpb_EncodedType_SFixed32: + case kUpb_EncodedType_SFixed64: + case kUpb_EncodedType_Int32: + case kUpb_EncodedType_UInt32: + case kUpb_EncodedType_SInt32: + case kUpb_EncodedType_Int64: + case kUpb_EncodedType_UInt64: + case kUpb_EncodedType_SInt64: + case kUpb_EncodedType_Bool: + case kUpb_EncodedType_String: + break; -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s) { - return s->extreg; + default: + upb_MtDecoder_ErrorFormat(d, "Invalid map key field type: %d", key_type); + UPB_UNREACHABLE(); + } + upb_MiniTable_BuildMapEntry(d, data[0], data[1]); } -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_MtDecoder_ParseMessageSet(upb_MtDecoder* d, const char* data, + size_t len) { + if (len > 0) { + upb_MtDecoder_ErrorFormat(d, "Invalid message set encode length: %zu", len); + UPB_UNREACHABLE(); } - *count = n; - return exts; -} -bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { - return _upb_DefPool_LoadDefInitEx(s, init, false); + upb_MiniTable* ret = d->table; + ret->size = 0; + ret->field_count = 0; + ret->ext = kUpb_ExtMode_IsMessageSet; + ret->dense_below = 0; + ret->table_mask = -1; + ret->required_count = 0; } +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)), + }; -// Must be last. + if (UPB_SETJMP(decoder.err)) { + decoder.table = NULL; + goto done; + } -upb_deftype_t _upb_DefType_Type(upb_value v) { - const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return num & UPB_DEFTYPE_MASK; -} + upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table); -upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { - uintptr_t num = (uintptr_t)ptr; - UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); - num |= type; - return upb_value_constptr((const void*)num); -} + 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; -const void* _upb_DefType_Unpack(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; -} + // Strip off and verify the version tag. + if (!len--) goto done; + const char vers = *data++; + switch (vers) { + case kUpb_EncodedVersion_MapV1: + upb_MtDecoder_ParseMap(&decoder, data, len); + break; -// Must be last. + case kUpb_EncodedVersion_MessageV1: + upb_MtDecoder_ParseMessage(&decoder, data, len); + upb_MtDecoder_AssignHasbits(decoder.table); + upb_MtDecoder_SortLayoutItems(&decoder); + upb_MtDecoder_AssignOffsets(&decoder); + break; -bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { - const size_t oldbufsize = d->bufsize; - const int used = d->ptr - d->buf; + case kUpb_EncodedVersion_MessageSetV1: + upb_MtDecoder_ParseMessageSet(&decoder, data, len); + break; - if (!d->buf) { - d->buf = upb_Arena_Malloc(a, d->bufsize); - if (!d->buf) return false; - d->ptr = d->buf; - d->e.end = d->buf + d->bufsize; + default: + upb_MtDecoder_ErrorFormat(&decoder, "Invalid message version: %c", vers); + UPB_UNREACHABLE(); } - if (oldbufsize - used < kUpb_MtDataEncoder_MinSize) { - d->bufsize *= 2; - d->buf = upb_Arena_Realloc(a, d->buf, oldbufsize, d->bufsize); - if (!d->buf) return false; - d->ptr = d->buf + used; - d->e.end = d->buf + d->bufsize; +done: + *buf = decoder.vec.data; + *buf_size = decoder.vec.capacity * sizeof(*decoder.vec.data); + return decoder.table; +} + +static size_t upb_MiniTableEnum_Size(size_t count) { + return sizeof(upb_MiniTableEnum) + count * sizeof(uint32_t); +} + +static upb_MiniTableEnum* _upb_MiniTable_AddEnumDataMember(upb_MtDecoder* d, + uint32_t val) { + if (d->enum_data_count == d->enum_data_capacity) { + size_t old_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); + d->enum_data_capacity = UPB_MAX(2, d->enum_data_capacity * 2); + size_t new_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); + d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); + upb_MtDecoder_CheckOutOfMemory(d, d->enum_table); } + d->enum_table->data[d->enum_data_count++] = val; + return d->enum_table; +} - return true; +static void upb_MiniTable_BuildEnumValue(upb_MtDecoder* d, uint32_t val) { + upb_MiniTableEnum* table = d->enum_table; + d->enum_value_count++; + if (table->value_count || (val > 512 && d->enum_value_count < val / 32)) { + if (table->value_count == 0) { + assert(d->enum_data_count == table->mask_limit / 32); + } + table = _upb_MiniTable_AddEnumDataMember(d, val); + table->value_count++; + } else { + uint32_t new_mask_limit = ((val / 32) + 1) * 32; + while (table->mask_limit < new_mask_limit) { + table = _upb_MiniTable_AddEnumDataMember(d, 0); + table->mask_limit += 32; + } + table->data[val / 32] |= 1ULL << (val % 32); + } } -#include +upb_MiniTableEnum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + upb_MtDecoder decoder = { + .enum_table = upb_Arena_Malloc(arena, upb_MiniTableEnum_Size(2)), + .enum_value_count = 0, + .enum_data_count = 0, + .enum_data_capacity = 1, + .status = status, + .end = UPB_PTRADD(data, len), + .arena = arena, + }; + if (UPB_SETJMP(decoder.err)) return NULL; -// Must be last. + // If the string is non-empty then it must begin with a version tag. + if (len) { + if (*data != kUpb_EncodedVersion_EnumV1) { + upb_MtDecoder_ErrorFormat(&decoder, "Invalid enum version: %c", *data); + UPB_UNREACHABLE(); + } + data++; + len--; + } -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; - bool is_sorted; // Whether all of the values are defined in ascending order. -}; - -upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { - return (upb_EnumDef*)&e[i]; -} + upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.enum_table); -// TODO: Maybe implement this on top of a ZCOS instead? -void _upb_EnumDef_Debug(const upb_EnumDef* e) { - fprintf(stderr, "enum %s (%p) {\n", e->full_name, e); - fprintf(stderr, " value_count: %d\n", e->value_count); - fprintf(stderr, " default: %d\n", e->defaultval); - fprintf(stderr, " is_sorted: %d\n", e->is_sorted); - fprintf(stderr, "}\n"); -} + // Guarantee at least 64 bits of mask without checking mask size. + decoder.enum_table->mask_limit = 64; + decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); + decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); -const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { - return e->layout; -} + decoder.enum_table->value_count = 0; -bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a) { - const char* name = upb_EnumValueDef_Name(v); - const upb_value val = upb_value_constptr(v); - bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, a); - if (!ok) return false; + const char* ptr = data; + uint32_t base = 0; - // Multiple enumerators can have the same number, first one wins. - const int number = upb_EnumValueDef_Number(v); - if (!upb_inttable_lookup(&e->iton, number, NULL)) { - return upb_inttable_insert(&e->iton, number, val, a); + while (ptr < decoder.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) upb_MiniTable_BuildEnumValue(&decoder, base); + } + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(&decoder, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + base += skip; + } else { + upb_Status_SetErrorFormat(status, "Unexpected character: %c", ch); + return NULL; + } } - return true; -} -const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { - return e->opts; + return decoder.enum_table; } -bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { - return e->opts != (void*)kUpbDefOptDefault; -} +const char* _upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, + upb_MiniTableSub sub, + upb_MiniTablePlatform platform, + upb_Status* status) { + upb_MtDecoder decoder = { + .arena = NULL, + .status = status, + .table = NULL, + .platform = platform, + }; -const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } + if (UPB_SETJMP(decoder.err)) return NULL; -const char* upb_EnumDef_Name(const upb_EnumDef* e) { - return _upb_DefBuilder_FullToShort(e->full_name); -} + // If the string is non-empty then it must begin with a version tag. + if (len) { + if (*data != kUpb_EncodedVersion_ExtensionV1) { + upb_MtDecoder_ErrorFormat(&decoder, "Invalid ext version: %c", *data); + UPB_UNREACHABLE(); + } + data++; + len--; + } -const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } + uint16_t count = 0; + const char* ret = + upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); + if (!ret || count != 1) return NULL; -const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { - return e->containing_type; -} + upb_MiniTableField* f = &ext->field; -int32_t upb_EnumDef_Default(const upb_EnumDef* e) { - UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); - return e->defaultval; -} + f->mode |= kUpb_LabelFlags_IsExtension; + f->offset = 0; + f->presence = 0; -int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } + if (extendee->ext & kUpb_ExtMode_IsMessageSet) { + // Extensions of MessageSet must be messages. + if (!upb_IsSubMessage(f)) return NULL; -const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, - const char* name) { - return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); -} + // Extensions of MessageSet must be non-repeating. + if ((f->mode & kUpb_FieldMode_Mask) == kUpb_FieldMode_Array) return NULL; + } -const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( - const upb_EnumDef* e, const char* name, size_t size) { - upb_value v; - return upb_strtable_lookup2(&e->ntoi, name, size, &v) - ? upb_value_getconstptr(v) - : NULL; -} + ext->extendee = extendee; + ext->sub = sub; -const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, - int32_t num) { - upb_value v; - return upb_inttable_lookup(&e->iton, num, &v) ? upb_value_getconstptr(v) - : NULL; + return ret; } -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); +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; } -const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { - UPB_ASSERT(0 <= i && i < e->value_count); - return _upb_EnumValueDef_At(e->values, i); +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTableField* 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 = (field->mode & ~kUpb_FieldMode_Mask) | kUpb_FieldMode_Map; + } + upb_MiniTableSub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->submsg = sub; } -bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { - if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; - return upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2; +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTableField* field, + const upb_MiniTableEnum* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + upb_MiniTableSub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->subenum = sub; } -bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, - upb_StringView* out) { - upb_DescState s; - _upb_DescState_Init(&s); - - const upb_EnumValueDef** sorted = NULL; - if (!e->is_sorted) { - sorted = _upb_EnumValueDefs_Sorted(e->values, e->value_count, a); - if (!sorted) return false; - } +#include - if (!_upb_DescState_Grow(&s, a)) return false; - s.ptr = upb_MtDataEncoder_StartEnum(&s.e, s.ptr); - // Duplicate values are allowed but we only encode each value once. - uint32_t previous = 0; +// Must be last. - for (size_t i = 0; i < e->value_count; i++) { - const uint32_t current = - upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i)); - if (i != 0 && previous == current) continue; +typedef struct { + uint64_t present_values_mask; + uint32_t last_written_value; +} upb_MtDataEncoderInternal_EnumState; - if (!_upb_DescState_Grow(&s, a)) return false; - s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current); - previous = current; - } +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; - if (!_upb_DescState_Grow(&s, a)) return false; - s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr); +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; - // There will always be room for this '\0' in the encoder buffer because - // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum(). - UPB_ASSERT(s.ptr < s.buf + s.bufsize); - *s.ptr = '\0'; +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; +} - out->data = s.buf; - out->size = s.ptr - s.buf; - return true; +static char* upb_MtDataEncoder_PutRaw(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++ = ch; + return ptr; } -static upb_MiniTable_Enum* create_enumlayout(upb_DefBuilder* ctx, - const upb_EnumDef* e) { - upb_StringView sv; - bool ok = upb_EnumDef_MiniDescriptorEncode(e, ctx->tmp_arena, &sv); - if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); +static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { + return upb_MtDataEncoder_PutRaw(e, ptr, _upb_ToBase92(ch)); +} - upb_Status status; - upb_MiniTable_Enum* layout = - upb_MiniTable_BuildEnum(sv.data, sv.size, ctx->arena, &status); - if (!layout) - _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); - return layout; +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; } -static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_EnumDescriptorProto* enum_proto, - upb_EnumDef* e) { - const google_protobuf_EnumValueDescriptorProto* const* values; - upb_StringView name; - size_t n; +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; +} - // Must happen before _upb_DefBuilder_Add() - e->file = _upb_DefBuilder_File(ctx); +char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = 0; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; - name = google_protobuf_EnumDescriptorProto_name(enum_proto); - _upb_DefBuilder_CheckIdentNotFull(ctx, name); + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_ExtensionV1); + if (!ptr) return NULL; - e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - _upb_DefBuilder_Add(ctx, e->full_name, - _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); + return upb_MtDataEncoder_PutField(e, ptr, type, field_num, field_mod); +} - values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); +char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr, + upb_FieldType key_type, + upb_FieldType value_type, + uint64_t value_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = 0; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; - bool ok = upb_strtable_init(&e->ntoi, n, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MapV1); + if (!ptr) return NULL; - ok = upb_inttable_init(&e->iton, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + ptr = upb_MtDataEncoder_PutField(e, ptr, key_type, 1, 0); + if (!ptr) return NULL; - e->defaultval = 0; - e->value_count = n; - e->values = _upb_EnumValueDefs_New(ctx, prefix, n, values, e, &e->is_sorted); + return upb_MtDataEncoder_PutField(e, ptr, value_type, 2, value_mod); +} - if (n == 0) { - _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", - e->full_name); - } +char* upb_MtDataEncoder_EncodeMessageSet(upb_MtDataEncoder* e, char* ptr) { + (void)upb_MtDataEncoder_GetInternal(e, ptr); + return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageSetV1); +} - UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); +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; - upb_inttable_compact(&e->iton, ctx->arena); + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageV1); + if (!ptr) return NULL; - if (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2) { - if (ctx->layout) { - UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); - e->layout = ctx->layout->enums[ctx->enum_count++]; - } else { - e->layout = create_enumlayout(ctx, e); - } - } else { - e->layout = NULL; - } + return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); } -upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, - const google_protobuf_EnumDescriptorProto* const* protos, - const upb_MessageDef* containing_type) { - _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); - - // If a containing type is defined then get the full name from that. - // Otherwise use the package name from the file def. - const char* name = containing_type ? upb_MessageDef_FullName(containing_type) - : _upb_FileDef_RawPackage(ctx->file); +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_OpenEnum, + [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_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); - for (size_t i = 0; i < n; i++) { - create_enumdef(ctx, name, protos[i], &e[i]); - e[i].containing_type = containing_type; + 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; } - return e; -} + in->state.msg_state.last_field_num = field_num; + uint32_t encoded_modifiers = 0; -// Must be last. + // Put field type. + int encoded_type = kUpb_TypeToEncoded[type]; + if (field_mod & kUpb_FieldModifier_IsClosedEnum) { + UPB_ASSERT(type == kUpb_FieldType_Enum); + encoded_type = kUpb_EncodedType_ClosedEnum; + } + 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; -struct upb_EnumValueDef { - const google_protobuf_EnumValueOptions* opts; - const upb_EnumDef* parent; - const char* full_name; - int32_t number; -}; + if (_upb_FieldType_IsPackable(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; -upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { - return (upb_EnumValueDef*)&v[i]; + 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 int _upb_EnumValueDef_Compare(const void* p1, const void* p2) { - const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number; - const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number; - return (v1 < v2) ? -1 : (v1 > v2); +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; } -const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, - int n, upb_Arena* a) { - // TODO: Try to replace this arena alloc with a persistent scratch buffer. - upb_EnumValueDef** out = - (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*)); - if (!out) return NULL; - - for (int i = 0; i < n; i++) { - out[i] = (upb_EnumValueDef*)&v[i]; +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; } - qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare); - - return (const upb_EnumValueDef**)out; + 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 google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( - const upb_EnumValueDef* v) { - return v->opts; -} +char* upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value = 0; -bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { - return v->opts != (void*)kUpbDefOptDefault; + return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_EnumV1); } -const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { - return v->parent; +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 char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { - return v->full_name; +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); + if (!ptr) { + return NULL; + } + 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; } -const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { - return _upb_DefBuilder_FullToShort(v->full_name); +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); } -int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } +#include -uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { - // Compute index in our parent's array. - return v - upb_EnumDef_Value(v->parent, 0); -} -static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_EnumValueDescriptorProto* val_proto, - upb_EnumDef* e, upb_EnumValueDef* v) { - upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); +// Must be last. - v->parent = e; // Must happen prior to _upb_DefBuilder_Add() - v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); - _upb_DefBuilder_Add(ctx, v->full_name, - _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); +/* 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}; +const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; - UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, - val_proto); +const char* _upb_DefBuilder_FullToShort(const char* fullname) { + const char* p; - bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + 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; + } } -// Allocate and initialize an array of |n| enum value defs owned by |e|. -upb_EnumValueDef* _upb_EnumValueDefs_New( - upb_DefBuilder* ctx, const char* prefix, int n, - const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, - bool* is_sorted) { - _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); +void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); } - upb_EnumValueDef* v = - _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n); +void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(ctx->status, fmt, argp); + va_end(argp); + _upb_DefBuilder_FailJmp(ctx); +} - *is_sorted = true; - uint32_t previous = 0; - for (size_t i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); +void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { + upb_Status_SetErrorMessage(ctx->status, "out of memory"); + _upb_DefBuilder_FailJmp(ctx); +} - const uint32_t current = v[i].number; - if (previous > current) *is_sorted = false; - previous = current; +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name) { + if (prefix) { + // ret = prefix + '.' + name; + size_t n = strlen(prefix); + char* ret = _upb_DefBuilder_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 { + char* ret = upb_strdup2(name.data, name.size, ctx->arena); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; } +} - if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && - v[0].number != 0) { - _upb_DefBuilder_Errf(ctx, - "for proto3, the first enum value must be zero (%s)", - upb_EnumDef_FullName(e)); +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; + } } - return v; + *len = 0; + return true; } +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type) { + 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_DefPool_LookupSym(ctx->symtab, 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_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) { + break; + } + if (!remove_component(tmp, &baselen)) { + free(tmp); + goto notfound; + } + } + free(tmp); + } -// Must be last. - -struct upb_ExtensionRange { - const google_protobuf_ExtensionRangeOptions* opts; - int32_t start; - int32_t end; -}; + *type = _upb_DefType_Type(v); + return _upb_DefType_Unpack(v, *type); -upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { - return (upb_ExtensionRange*)&r[i]; +notfound: + _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(sym)); } -const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( - const upb_ExtensionRange* r) { - return r->opts; +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type) { + upb_deftype_t found_type; + const void* ret = + _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); + if (ret && found_type != type) { + _upb_DefBuilder_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; } -bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { - return r->opts != (void*)kUpbDefOptDefault; -} +// 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. +static char upb_ascii_lower(char ch) { return ch | 0x20; } -int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { - return r->start; +// 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 low <= c && c <= high; } -int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } - -upb_ExtensionRange* _upb_ExtensionRanges_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_DescriptorProto_ExtensionRange* const* protos, - const upb_MessageDef* m) { - upb_ExtensionRange* r = - _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); +static bool upb_isletter(char c) { + char lower = upb_ascii_lower(c); + return upb_isbetween(lower, 'a', 'z') || c == '_'; +} - for (int i = 0; i < n; i++) { - const int32_t start = - google_protobuf_DescriptorProto_ExtensionRange_start(protos[i]); - const int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(protos[i]); - const int32_t max = - google_protobuf_MessageOptions_message_set_wire_format(upb_MessageDef_Options(m)) - ? INT32_MAX - : kUpb_MaxFieldNumber + 1; +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} - // 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) { - _upb_DefBuilder_Errf(ctx, - "Extension range (%d, %d) is invalid, message=%s\n", - (int)start, (int)end, upb_MessageDef_FullName(m)); - } +static bool TryGetChar(const char** src, const char* end, char* ch) { + if (*src == end) return false; + *ch = **src; + *src += 1; + return true; +} - r[i].start = start; - r[i].end = end; - UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, protos[i]); +static char TryGetHexDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '9') { + return ch - '0'; } - - return r; + 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; } -#include -#include +static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char hex_digit = TryGetHexDigit(src, end); + if (hex_digit < 0) { + _upb_DefBuilder_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 = TryGetHexDigit(src, end)) >= 0) { + ret = (ret << 4) | hex_digit; + } + if (ret > 0xff) { + _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", + upb_FieldDef_FullName(f)); + return 0; + } + return ret; +} +static char TryGetOctalDigit(const char** src, const char* end) { + char ch; + if (!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; +} -// Must be last. - -#define UPB_FIELD_TYPE_UNSPECIFIED 0 +static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* 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 = TryGetOctalDigit(src, end)) >= 0) { + ch = (ch << 3) | digit; + } + } + return ch; +} -typedef struct { - size_t len; - char str[1]; // Null-terminated string data follows. -} str_t; +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) { + _upb_DefBuilder_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_DefBuilder_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_DefBuilder_ParseOctalEscape(ctx, f, src, end); + } + _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); +} -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 is_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 -}; +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full) { + const char* str = name.data; + const size_t len = name.size; + bool start = true; + for (size_t i = 0; i < len; i++) { + const char c = str[i]; + if (c == '.') { + if (start || !full) { + _upb_DefBuilder_Errf( + ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + _upb_DefBuilder_Errf(ctx, + "invalid name: path components must start with a " + "letter (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = false; + } else if (!upb_isalphanum(c)) { + _upb_DefBuilder_Errf( + ctx, + "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT + ")", + UPB_STRINGVIEW_ARGS(name)); + } + } + if (start) { + _upb_DefBuilder_Errf(ctx, + "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } -upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { - return (upb_FieldDef*)&f[i]; + // We should never reach this point. + UPB_ASSERT(false); } -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*)kUpbDefOptDefault; -} +// Must be last. -const char* upb_FieldDef_FullName(const upb_FieldDef* f) { - return f->full_name; -} +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_MiniTableExtension*) -> (upb_FieldDef*) + upb_ExtensionRegistry* extreg; + void* scratch_data; + size_t scratch_size; + size_t bytes_loaded; +}; -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(); +void upb_DefPool_Free(upb_DefPool* s) { + upb_Arena_Free(s->arena); + upb_gfree(s->scratch_data); + upb_gfree(s); } -upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } +upb_DefPool* upb_DefPool_New(void) { + upb_DefPool* s = upb_gmalloc(sizeof(*s)); + if (!s) return NULL; -uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } + s->arena = upb_Arena_New(); + s->bytes_loaded = 0; -upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } + s->scratch_size = 240; + s->scratch_data = upb_gmalloc(s->scratch_size); + if (!s->scratch_data) goto err; -uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } + if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; + if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; + if (!upb_inttable_init(&s->exts, s->arena)) goto err; -bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { - return f->is_extension_; -} + s->extreg = upb_ExtensionRegistry_New(s->arena); + if (!s->extreg) goto err; -bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->is_packed_; } + return s; -const char* upb_FieldDef_Name(const upb_FieldDef* f) { - return _upb_DefBuilder_FullToShort(f->full_name); +err: + upb_DefPool_Free(s); + return NULL; } -const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { - return f->json_name; +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, + upb_FieldDef* f) { + return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), + s->arena); } -bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { - return f->has_json_name_; +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status) { + // TODO: table should support an operation "tryinsert" to avoid the double + // lookup. + if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) { + upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data); + return false; + } + if (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) { + upb_Status_SetErrorMessage(status, "out of memory"); + return false; + } + return true; } -const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } - -const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { - return f->msgdef; +static const void* _upb_DefPool_Unpack(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) + ? _upb_DefType_Unpack(v, type) + : NULL; } -const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { - return f->is_extension_ ? f->scope.extension_scope : NULL; +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v) { + return upb_strtable_lookup2(&s->syms, sym, size, v); } -const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { - return f->is_extension_ ? NULL : f->scope.oneof; +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { + return s->extreg; } -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; +void** _upb_DefPool_ScratchData(const upb_DefPool* s) { + return (void**)&s->scratch_data; } -upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); - upb_MessageValue ret; - - 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(); - } - - return ret; +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) { + return (size_t*)&s->scratch_size; } -const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_MSG); } -const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG); } -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsExtension(f)); - const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); - return &layout->fields[f->layout_index]; +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUM); } -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( - const upb_FieldDef* f) { - UPB_ASSERT(upb_FieldDef_IsExtension(f)); - const upb_FileDef* file = upb_FieldDef_File(f); - return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUMVAL); } -bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) { - if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; - if (f->type_ != kUpb_FieldType_Enum) return false; - - // TODO: Maybe make is_proto2 a bool at creation? - const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef); - return upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) + : NULL; } -bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { - return f->proto3_optional_; +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) + ? upb_value_getconstptr(v) + : NULL; } -int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } - -uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { - uint64_t out = f->is_packed_ ? kUpb_FieldModifier_IsPacked : 0; +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 (f->label_) { - case kUpb_Label_Optional: - if (!upb_FieldDef_HasPresence(f)) { - out |= kUpb_FieldModifier_IsProto3Singular; - } - break; - case kUpb_Label_Repeated: - out |= kUpb_FieldModifier_IsRepeated; - break; - case kUpb_Label_Required: - out |= kUpb_FieldModifier_IsRequired; + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_FIELD: + return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return _upb_MessageDef_InMessageSet(m) + ? upb_MessageDef_NestedExtension(m, 0) + : NULL; + } + default: break; } - if (_upb_FieldDef_IsClosedEnum(f)) { - out |= kUpb_FieldModifier_IsClosedEnum; - } - return out; -} - -bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } - -bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { - if (upb_FieldDef_IsRepeated(f)) return false; - const upb_FileDef* file = upb_FieldDef_File(f); - return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || - upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; + return NULL; } -bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { - return upb_FieldDef_IsSubMessage(f) || - upb_FieldDef_CType(f) == kUpb_CType_Enum; +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); } -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_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name) { + return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE); } -bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Optional; +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE); } -bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { - return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); -} +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 (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_EXT: { + const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); + return upb_FieldDef_File(f); + } + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return upb_MessageDef_File(m); + } + case UPB_DEFTYPE_ENUM: { + const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); + return upb_EnumDef_File(e); + } + case UPB_DEFTYPE_ENUMVAL: { + const upb_EnumValueDef* ev = + _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); + return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); + } + case UPB_DEFTYPE_SERVICE: { + const upb_ServiceDef* service = + _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); + return upb_ServiceDef_File(service); + } + default: + UPB_UNREACHABLE(); + } + } -bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Repeated; -} + 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); + } + } + } -bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Required; + return NULL; } -bool upb_FieldDef_IsString(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_String || - upb_FieldDef_CType(f) == kUpb_CType_Bytes; -} +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 (_upb_DefType_Type(val)) { + case UPB_DEFTYPE_EXT: + f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); + break; + case UPB_DEFTYPE_MSG: + f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); + break; + case UPB_DEFTYPE_ENUM: + f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); + break; + case UPB_DEFTYPE_ENUMVAL: + f = upb_EnumDef_File(upb_EnumValueDef_Enum( + _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); + break; + case UPB_DEFTYPE_SERVICE: + f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); + break; + default: + UPB_UNREACHABLE(); + } -bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message; + if (f == file) upb_strtable_removeiter(&s->syms, &iter); + } } -static bool between(int32_t x, int32_t low, int32_t high) { - return x >= low && x <= high; -} +static const upb_FileDef* _upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + const upb_MiniTableFile* layout, upb_Status* status) { + const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); -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); } + if (name.size == 0) { + upb_Status_SetErrorFormat(status, + "missing name in google_protobuf_FileDescriptorProto"); + return NULL; + } -bool upb_FieldDef_checkdescriptortype(int32_t type) { - return between(type, 1, 18); -} - -static bool streql2(const char* a, size_t n, const char* b) { - return n == strlen(b) && memcmp(a, b, n) == 0; -} + // Determine whether we already know about this file. + { + upb_value v; + if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { + upb_Status_SetErrorFormat(status, + "duplicate file name " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + return NULL; + } + } -// Implement the transformation as described in the spec: -// 1. upper case all letters after an underscore. -// 2. remove all underscores. -static char* make_json_name(const char* name, size_t size, upb_Arena* a) { - char* out = upb_Arena_Malloc(a, size + 1); // +1 is to add a trailing '\0' - if (out == NULL) return NULL; + upb_DefBuilder ctx = { + .symtab = s, + .layout = layout, + .msg_count = 0, + .enum_count = 0, + .ext_count = 0, + .status = status, + .file = NULL, + .arena = upb_Arena_New(), + .tmp_arena = upb_Arena_New(), + }; - bool ucase_next = false; - char* des = out; - for (size_t i = 0; i < size; i++) { - if (name[i] == '_') { - ucase_next = true; - } else { - *des++ = ucase_next ? toupper(name[i]) : name[i]; - ucase_next = false; + if (UPB_SETJMP(ctx.err)) { + UPB_ASSERT(!upb_Status_IsOk(status)); + if (ctx.file) { + remove_filedef(s, ctx.file); + ctx.file = NULL; } + } else if (!ctx.arena || !ctx.tmp_arena) { + _upb_DefBuilder_OomErr(&ctx); + } else { + _upb_FileDef_Create(&ctx, file_proto); + upb_strtable_insert(&s->files, name.data, name.size, + upb_value_constptr(ctx.file), ctx.arena); + UPB_ASSERT(upb_Status_IsOk(status)); + upb_Arena_Fuse(s->arena, ctx.arena); } - *des++ = '\0'; - return out; + + if (ctx.arena) upb_Arena_Free(ctx.arena); + if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); + return ctx.file; } -static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { - str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); - if (!ret) _upb_DefBuilder_OomErr(ctx); - ret->len = len; - if (len) memcpy(ret->str, data, len); - ret->str[len] = '\0'; - return ret; +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 str_t* unescape(upb_DefBuilder* 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 = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); - char* dst = &ret->str[0]; - const char* src = data; - const char* end = data + len; +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; - while (src < end) { - if (*src == '\\') { - src++; - *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); - } else { - *dst++ = *src++; - } + upb_Status_Clear(&status); + + if (upb_DefPool_FindFileByName(s, init->filename)) { + return true; } - ret->len = dst - &ret->str[0]; - return ret; -} + arena = upb_Arena_New(); -static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, - upb_FieldDef* f) { - char* end; - char nullz[64]; - errno = 0; + for (; *deps; deps++) { + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; + } - 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) { - _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); - } - memcpy(nullz, str, len); - nullz[len] = '\0'; - str = nullz; - break; - default: - break; + file = google_protobuf_FileDescriptorProto_parse_ex( + init->descriptor.data, init->descriptor.size, NULL, + kUpb_DecodeOption_AliasString, arena); + s->bytes_loaded += init->descriptor.size; + + if (!file) { + upb_Status_SetErrorFormat( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; } - 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 = upb_EnumValueDef_Number(ev); - 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. */ - _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", - upb_FieldDef_FullName(f)); + const upb_MiniTableFile* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { + goto err; } - return; + upb_Arena_Free(arena); + return true; -invalid: - _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", - (int)len, str, upb_FieldDef_FullName(f), - (int)upb_FieldDef_Type(f)); +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 set_default_default(upb_DefBuilder* 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: { - const upb_EnumValueDef* v = upb_EnumDef_Value(f->sub.enumdef, 0); - f->defaultval.sint = upb_EnumValueDef_Number(v); - } - case kUpb_CType_Message: - break; - } +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { + return s->bytes_loaded; } -static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_FieldDescriptorProto* field_proto, - upb_MessageDef* m, upb_FieldDef* f) { - // Must happen before _upb_DefBuilder_Add() - f->file = _upb_DefBuilder_File(ctx); - - if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - _upb_DefBuilder_Errf(ctx, "field has no name"); - } - - const upb_StringView name = google_protobuf_FieldDescriptorProto_name(field_proto); - _upb_DefBuilder_CheckIdentNotFull(ctx, name); - - f->has_json_name_ = google_protobuf_FieldDescriptorProto_has_json_name(field_proto); - if (f->has_json_name_) { - const upb_StringView sv = - google_protobuf_FieldDescriptorProto_json_name(field_proto); - f->json_name = upb_strdup2(sv.data, sv.size, ctx->arena); - } else { - f->json_name = make_json_name(name.data, name.size, ctx->arena); - } - if (!f->json_name) _upb_DefBuilder_OomErr(ctx); +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } - f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); - f->number_ = google_protobuf_FieldDescriptorProto_number(field_proto); - f->proto3_optional_ = - google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); - f->msgdef = m; - f->scope.oneof = NULL; +const upb_FieldDef* upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTableExtension* ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} - const bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); - const bool has_type_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum) { + const upb_MiniTable* t = upb_MessageDef_MiniTable(m); + const upb_MiniTableExtension* ext = + upb_ExtensionRegistry_Lookup(s->extreg, t, fieldnum); + return ext ? upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +} - f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s) { + return s->extreg; +} - if (has_type) { - switch (f->type_) { - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - case kUpb_FieldType_Enum: - if (!has_type_name) { - _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", - (int)f->type_, f->full_name); - } - break; - default: - if (has_type_name) { - _upb_DefBuilder_Errf( - ctx, "invalid type for field with type_name set (%s, %d)", - f->full_name, (int)f->type_); - } - } - } else if (has_type_name) { - f->type_ = - UPB_FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef() +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_next(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) n++; } - - if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { - _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, - f->type_); + const upb_FieldDef** exts = malloc(n * sizeof(*exts)); + iter = UPB_INTTABLE_BEGIN; + size_t i = 0; + while (upb_inttable_next(&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; +} - if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { - _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, - f->label_); - } +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { + return _upb_DefPool_LoadDefInitEx(s, init, false); +} - /* 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 && - upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { - _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", - f->full_name); - } +// Must be last. - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); +upb_deftype_t _upb_DefType_Type(upb_value v) { + const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return num & UPB_DEFTYPE_MASK; +} - if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { - _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", - f->full_name); - } +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { + uintptr_t num = (uintptr_t)ptr; + UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); + num |= type; + return upb_value_constptr((const void*)num); +} - if (!m) { - _upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg", - f->full_name); - } +const void* _upb_DefType_Unpack(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; +} - if (oneof_index >= upb_MessageDef_OneofCount(m)) { - _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); - } - upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); - f->scope.oneof = oneof; +// Must be last. - bool ok = _upb_OneofDef_Insert(oneof, f, name.data, name.size, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - } +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { + const size_t oldbufsize = d->bufsize; + const int used = d->ptr - d->buf; - UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + if (!d->buf) { + d->buf = upb_Arena_Malloc(a, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf; + d->e.end = d->buf + d->bufsize; + } - if (google_protobuf_FieldOptions_has_packed(f->opts)) { - f->is_packed_ = google_protobuf_FieldOptions_packed(f->opts); - } else { - // Repeated fields default to packed for proto3 only. - f->is_packed_ = upb_FieldDef_IsPrimitive(f) && - f->label_ == kUpb_Label_Repeated && - upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; + if (oldbufsize - used < kUpb_MtDataEncoder_MinSize) { + d->bufsize *= 2; + d->buf = upb_Arena_Realloc(a, d->buf, oldbufsize, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf + used; + d->e.end = d->buf + d->bufsize; } + + return true; } -static void _upb_FieldDef_CreateExt( - upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, - upb_FieldDef* f) { - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); - f->is_extension_ = true; - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", - f->full_name); - } +// Must be last. - f->scope.extension_scope = m; - _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); - f->layout_index = ctx->ext_count++; +struct upb_EnumDef { + const google_protobuf_EnumOptions* opts; + const upb_MiniTableEnum* 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; + bool is_sorted; // Whether all of the values are defined in ascending order. +}; - if (ctx->layout) { - UPB_ASSERT(_upb_FieldDef_ExtensionMiniTable(f)->field.number == f->number_); - } +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { + return (upb_EnumDef*)&e[i]; } -static void _upb_FieldDef_CreateNotExt( - upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, - upb_FieldDef* f) { - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); - f->is_extension_ = false; - - if (!google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - if (f->proto3_optional_) { - _upb_DefBuilder_Errf( - ctx, - "non-extension field (%s) with proto3_optional was not in a oneof", - f->full_name); - } - } +// TODO: Maybe implement this on top of a ZCOS instead? +void _upb_EnumDef_Debug(const upb_EnumDef* e) { + fprintf(stderr, "enum %s (%p) {\n", e->full_name, e); + fprintf(stderr, " value_count: %d\n", e->value_count); + fprintf(stderr, " default: %d\n", e->defaultval); + fprintf(stderr, " is_sorted: %d\n", e->is_sorted); + fprintf(stderr, "}\n"); +} - _upb_MessageDef_InsertField(ctx, m, f); +const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { + return e->layout; +} - if (!ctx->layout) return; +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a) { + const char* name = upb_EnumValueDef_Name(v); + const upb_value val = upb_value_constptr(v); + bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, a); + if (!ok) return false; - const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Field* fields = mt->fields; - for (int i = 0; i < mt->field_count; i++) { - if (fields[i].number == f->number_) { - f->layout_index = i; - return; - } + // Multiple enumerators can have the same number, first one wins. + const int number = upb_EnumValueDef_Number(v); + if (!upb_inttable_lookup(&e->iton, number, NULL)) { + return upb_inttable_insert(&e->iton, number, val, a); } + return true; +} - UPB_ASSERT(false); // It should be impossible to reach this point. +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { + return e->opts; } -upb_FieldDef* _upb_FieldDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, - upb_MessageDef* m, bool* is_sorted) { - _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); - upb_FieldDef* defs = - (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); +bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { + return e->opts != (void*)kUpbDefOptDefault; +} - // If we are creating extensions then is_sorted will be NULL. - // If we are not creating extensions then is_sorted will be non-NULL. - if (is_sorted) { - uint32_t previous = 0; - for (int i = 0; i < n; i++) { - upb_FieldDef* f = &defs[i]; +const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } - _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f); - f->index_ = i; - if (!ctx->layout) f->layout_index = i; +const char* upb_EnumDef_Name(const upb_EnumDef* e) { + return _upb_DefBuilder_FullToShort(e->full_name); +} - const uint32_t current = f->number_; - if (previous > current) *is_sorted = false; - previous = current; - } - } else { - for (int i = 0; i < n; i++) { - upb_FieldDef* f = &defs[i]; +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } - _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f); - f->index_ = i; - } - } +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { + return e->containing_type; +} - return defs; +int32_t upb_EnumDef_Default(const upb_EnumDef* e) { + UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); + return e->defaultval; } -static void resolve_subdef(upb_DefBuilder* 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 UPB_FIELD_TYPE_UNSPECIFIED: { - // Type was not specified and must be inferred. - UPB_ASSERT(has_name); - upb_deftype_t type; - const void* def = - _upb_DefBuilder_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: - _upb_DefBuilder_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 = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, - UPB_DEFTYPE_MSG); - break; - case kUpb_FieldType_Enum: - UPB_ASSERT(has_name); - f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, - UPB_DEFTYPE_ENUM); - break; - default: - // No resolution necessary. - break; - } +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e) { + return e->res_range_count; } -static int _upb_FieldDef_Compare(const void* p1, const void* p2) { - const uint32_t v1 = (*(upb_FieldDef**)p1)->number_; - const uint32_t v2 = (*(upb_FieldDef**)p2)->number_; - return (v1 < v2) ? -1 : (v1 > v2); +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_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, - upb_Arena* a) { - // TODO: Try to replace this arena alloc with a persistent scratch buffer. - upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*)); - if (!out) return NULL; +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e) { + return e->res_name_count; +} - for (int i = 0; i < n; i++) { - out[i] = (upb_FieldDef*)&f[i]; - } - qsort(out, n, sizeof(void*), _upb_FieldDef_Compare); +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]; +} - for (int i = 0; i < n; i++) { - out[i]->layout_index = i; - } - return (const upb_FieldDef**)out; +int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } + +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name) { + return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); } -bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, - upb_StringView* out) { - UPB_ASSERT(f->is_extension_); +const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size) { + upb_value v; + return upb_strtable_lookup2(&e->ntoi, name, size, &v) + ? upb_value_getconstptr(v) + : NULL; +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, + int32_t num) { + upb_value v; + return upb_inttable_lookup(&e->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_MiniTableEnum_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 _upb_EnumValueDef_At(e->values, i); +} + +bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; + return upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2; +} +bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, + upb_StringView* out) { upb_DescState s; _upb_DescState_Init(&s); - const int number = upb_FieldDef_Number(f); - const uint64_t modifiers = _upb_FieldDef_Modifiers(f); + const upb_EnumValueDef** sorted = NULL; + if (!e->is_sorted) { + sorted = _upb_EnumValueDefs_Sorted(e->values, e->value_count, a); + if (!sorted) return false; + } if (!_upb_DescState_Grow(&s, a)) return false; - s.ptr = upb_MtDataEncoder_EncodeExtension(&s.e, s.ptr, f->type_, number, - modifiers); + s.ptr = upb_MtDataEncoder_StartEnum(&s.e, s.ptr); + + // Duplicate values are allowed but we only encode each value once. + uint32_t previous = 0; + + for (size_t i = 0; i < e->value_count; i++) { + const uint32_t current = + upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i)); + if (i != 0 && previous == current) continue; + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current); + previous = current; + } + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr); + + // There will always be room for this '\0' in the encoder buffer because + // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum(). + UPB_ASSERT(s.ptr < s.buf + s.bufsize); *s.ptr = '\0'; out->data = s.buf; @@ -8392,1203 +7959,1134 @@ bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, return true; } -static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, - upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { - _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", - f->full_name); - } +static upb_MiniTableEnum* create_enumlayout(upb_DefBuilder* ctx, + const upb_EnumDef* e) { + upb_StringView sv; + bool ok = upb_EnumDef_MiniDescriptorEncode(e, ctx->tmp_arena, &sv); + if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); - upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); - const upb_MessageDef* m = - _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - f->msgdef = m; + upb_Status status; + upb_MiniTableEnum* layout = + upb_MiniTable_BuildEnum(sv.data, sv.size, ctx->arena, &status); + if (!layout) + _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); + return layout; +} - if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) { - _upb_DefBuilder_Errf( - ctx, - "field number %u in extension %s has no extension range in message %s", - (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m)); +static upb_StringView* _upb_EnumReservedNames_New( + upb_DefBuilder* ctx, int n, const upb_StringView* protos) { + upb_StringView* sv = _upb_DefBuilder_Alloc(ctx, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; } + return sv; +} - const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); +static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumDescriptorProto* enum_proto, + 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 n_value, n_res_range, n_res_name; - if (ctx->layout) { - UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); - } else { - upb_StringView desc; - if (!upb_FieldDef_MiniDescriptorEncode(f, ctx->tmp_arena, &desc)) { - _upb_DefBuilder_OomErr(ctx); - } + // Must happen before _upb_DefBuilder_Add() + e->file = _upb_DefBuilder_File(ctx); - upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; - upb_MiniTable_Sub sub = {NULL}; - if (upb_FieldDef_IsSubMessage(f)) { - sub.submsg = upb_MessageDef_MiniTable(f->sub.msgdef); - } else if (_upb_FieldDef_IsClosedEnum(f)) { - sub.subenum = _upb_EnumDef_MiniTable(f->sub.enumdef); - } - bool ok2 = upb_MiniTable_BuildExtension(desc.data, desc.size, mut_ext, - upb_MessageDef_MiniTable(m), sub, - ctx->status); - if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table"); - } + name = google_protobuf_EnumDescriptorProto_name(enum_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); - bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f); + e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, e->full_name, + _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); + + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n_value); + + bool ok = upb_strtable_init(&e->ntoi, n_value, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); -} -static void resolve_default(upb_DefBuilder* 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); + ok = upb_inttable_init(&e->iton, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); - if (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { - _upb_DefBuilder_Errf(ctx, - "proto3 fields cannot have explicit defaults (%s)", - f->full_name); - } + e->defaultval = 0; + e->value_count = n_value; + e->values = + _upb_EnumValueDefs_New(ctx, prefix, n_value, values, e, &e->is_sorted); - if (upb_FieldDef_IsSubMessage(f)) { - _upb_DefBuilder_Errf(ctx, - "message fields cannot have explicit defaults (%s)", - f->full_name); - } + if (n_value == 0) { + _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", + e->full_name); + } - parse_default(ctx, defaultval.data, defaultval.size, f); - f->has_default = true; + 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); + + UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); + + upb_inttable_compact(&e->iton, ctx->arena); + + if (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2) { + if (ctx->layout) { + UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); + e->layout = ctx->layout->enums[ctx->enum_count++]; + } else { + e->layout = create_enumlayout(ctx, e); + } } else { - set_default_default(ctx, f); - f->has_default = false; + e->layout = NULL; } } -void _upb_FieldDef_Resolve(upb_DefBuilder* 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; +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); - resolve_subdef(ctx, prefix, f); - resolve_default(ctx, f, field_proto); + // If a containing type is defined then get the full name from that. + // Otherwise use the package name from the file def. + const char* name = containing_type ? upb_MessageDef_FullName(containing_type) + : _upb_FileDef_RawPackage(ctx->file); - if (f->is_extension_) { - resolve_extension(ctx, prefix, f, field_proto); + upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); + for (size_t i = 0; i < n; i++) { + create_enumdef(ctx, name, protos[i], &e[i]); + e[i].containing_type = containing_type; } + return e; } +// #include "upb/reflection/extension_range_internal.h" +// #include "upb/reflection/message_def.h" // Must be last. -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_EnumReservedRange { + int32_t start; + int32_t end; }; -const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { - return f->opts; +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i) { + return (upb_EnumReservedRange*)&r[i]; } -bool upb_FileDef_HasOptions(const upb_FileDef* f) { - return f->opts != (void*)kUpbDefOptDefault; +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r) { + return r->start; } - -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 : ""; +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r) { + return r->end; } -const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e) { + upb_EnumReservedRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumReservedRange) * n); -upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } + 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; -int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { - return f->top_lvl_msg_count; -} + // 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. -int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } + // 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) { + _upb_DefBuilder_Errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", + (int)start, (int)end, upb_EnumDef_FullName(e)); + } -int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { - return f->public_dep_count; -} + r[i].start = start; + r[i].end = end; + } -int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { - return f->weak_dep_count; + return r; } -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; -} +// Must be last. -int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { - return f->top_lvl_enum_count; +struct upb_EnumValueDef { + const google_protobuf_EnumValueOptions* opts; + const upb_EnumDef* parent; + const char* full_name; + int32_t number; +}; + +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { + return (upb_EnumValueDef*)&v[i]; } -int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { - return f->top_lvl_ext_count; +static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number; + const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number; + return (v1 < v2) ? -1 : (v1 > v2); } -int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + int n, upb_Arena* a) { + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_EnumValueDef** out = + (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; -const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->dep_count); - return f->deps[i]; -} + for (int i = 0; i < n; i++) { + out[i] = (upb_EnumValueDef*)&v[i]; + } + qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare); -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]]; + return (const upb_EnumValueDef**)out; } -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]]; +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* v) { + return v->opts; } -const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); - return _upb_MessageDef_At(f->top_lvl_msgs, i); +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { + return v->opts != (void*)kUpbDefOptDefault; } -const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); - return _upb_EnumDef_At(f->top_lvl_enums, i); +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { + return v->parent; } -const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); - return _upb_FieldDef_At(f->top_lvl_exts, i); +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { + return v->full_name; } -const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->service_count); - return _upb_ServiceDef_At(f->services, i); +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { + return _upb_DefBuilder_FullToShort(v->full_name); } -const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } -const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( - const upb_FileDef* f, int i) { - return f->ext_layouts[i]; +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { + // Compute index in our parent's array. + return v - upb_EnumDef_Value(v->parent, 0); } -static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { - char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); - if (!ret) _upb_DefBuilder_OomErr(ctx); - return ret; -} +static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumValueDescriptorProto* val_proto, + upb_EnumDef* e, upb_EnumValueDef* v) { + upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); -static bool streql_view(upb_StringView view, const char* b) { - return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; + v->parent = e; // Must happen prior to _upb_DefBuilder_Add() + v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); + _upb_DefBuilder_Add(ctx, v->full_name, + _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); + + UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); + + bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -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; +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, + bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); - const google_protobuf_DescriptorProto* const* nested_msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + upb_EnumValueDef* v = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n); + + *is_sorted = true; + uint32_t previous = 0; for (size_t i = 0; i < n; i++) { - ext_count += count_exts_in_msg(nested_msgs[i]); + create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); + + const uint32_t current = v[i].number; + if (previous > current) *is_sorted = false; + previous = current; } - return ext_count; + if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && + v[0].number != 0) { + _upb_DefBuilder_Errf(ctx, + "for proto3, the first enum value must be zero (%s)", + upb_EnumDef_FullName(e)); + } + + return v; } -// Allocate and initialize one file def, and add it to the context object. -void _upb_FileDef_Create(upb_DefBuilder* ctx, - const google_protobuf_FileDescriptorProto* file_proto) { - upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); - ctx->file = file; - 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 n; +// Must be last. - file->symtab = ctx->symtab; +struct upb_ExtensionRange { + const google_protobuf_ExtensionRangeOptions* opts; + int32_t start; + int32_t end; +}; - // 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_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { + return (upb_ExtensionRange*)&r[i]; +} - 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) { - _upb_DefBuilder_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 = _upb_DefBuilder_Alloc( - ctx, sizeof(*file->ext_layouts) * file->ext_count); - upb_MiniTable_Extension* ext = - _upb_DefBuilder_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)) { - _upb_DefBuilder_Errf(ctx, "File has no name"); - } - - file->name = strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r) { + return r->opts; +} - upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); - if (package.size) { - _upb_DefBuilder_CheckIdentFull(ctx, package); - file->package = strviewdup(ctx, package); - } else { - file->package = NULL; - } +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { + return r->opts != (void*)kUpbDefOptDefault; +} - if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { - upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { + return r->start; +} - if (streql_view(syntax, "proto2")) { - file->syntax = kUpb_Syntax_Proto2; - } else if (streql_view(syntax, "proto3")) { - file->syntax = kUpb_Syntax_Proto3; - } else { - _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(syntax)); - } - } else { - file->syntax = kUpb_Syntax_Proto2; - } +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } - // Read options. - UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const upb_MessageDef* m) { + upb_ExtensionRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); - // Verify dependencies. - strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); - file->dep_count = n; - file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n); + for (int i = 0; i < n; i++) { + const int32_t start = + google_protobuf_DescriptorProto_ExtensionRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(protos[i]); + const int32_t max = + google_protobuf_MessageOptions_message_set_wire_format(upb_MessageDef_Options(m)) + ? INT32_MAX + : kUpb_MaxFieldNumber + 1; - for (size_t 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]) { + // 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) { _upb_DefBuilder_Errf(ctx, - "Depends on file '" UPB_STRINGVIEW_FORMAT - "', but it has not been loaded", - UPB_STRINGVIEW_ARGS(str)); + "Extension range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); } - } - public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); - file->public_dep_count = n; - file->public_deps = - _upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n); - int32_t* mutable_public_deps = (int32_t*)file->public_deps; - for (size_t i = 0; i < n; i++) { - if (public_deps[i] >= file->dep_count) { - _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", - (int)public_deps[i]); - } - mutable_public_deps[i] = public_deps[i]; + r[i].start = start; + r[i].end = end; + UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); } - weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); - file->weak_dep_count = n; - file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n); - int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; - for (size_t i = 0; i < n; i++) { - if (weak_deps[i] >= file->dep_count) { - _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", - (int)weak_deps[i]); - } - mutable_weak_deps[i] = weak_deps[i]; - } + return r; +} - // Create enums. - enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); - file->top_lvl_enum_count = n; - file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); +#include +#include - // Create extensions. - exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); - file->top_lvl_ext_count = n; - file->top_lvl_exts = - _upb_FieldDefs_New(ctx, n, exts, file->package, NULL, NULL); - // Create messages. - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - file->top_lvl_msg_count = n; - file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); +// Must be last. - // Create services. - services = google_protobuf_FileDescriptorProto_service(file_proto, &n); - file->service_count = n; - file->services = _upb_ServiceDefs_New(ctx, n, services); +#define UPB_FIELD_TYPE_UNSPECIFIED 0 - // Now that all names are in the table, build layouts and resolve refs. +typedef struct { + size_t len; + char str[1]; // Null-terminated string data follows. +} str_t; - for (int i = 0; i < file->top_lvl_msg_count; i++) { - upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); - _upb_MessageDef_Resolve(ctx, m); - } +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; + void* msg; // Always NULL. + } 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 is_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 +}; - for (int i = 0; i < file->top_lvl_ext_count; i++) { - upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); - _upb_FieldDef_Resolve(ctx, file->package, f); - } +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { + return (upb_FieldDef*)&f[i]; +} - if (!ctx->layout) { - for (int i = 0; i < file->top_lvl_msg_count; i++) { - upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); - _upb_MessageDef_LinkMiniTable(ctx, m); - } - } +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f) { + return f->opts; +} - if (file->ext_count) { - bool ok = upb_ExtensionRegistry_AddArray( - _upb_DefPool_ExtReg(ctx->symtab), file->ext_layouts, file->ext_count); - if (!ok) _upb_DefBuilder_OomErr(ctx); +bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { + return f->opts != (void*)kUpbDefOptDefault; +} + +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_; } -#include +uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } +upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } -// Must be last. +uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } -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]; +bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { + return f->is_extension_; } -static bool in_oneof(const upb_MiniTable_Field* field) { - return field->presence < 0; +bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->is_packed_; } + +const char* upb_FieldDef_Name(const upb_FieldDef* f) { + return _upb_DefBuilder_FullToShort(f->full_name); } -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; +const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { + return f->json_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; - } - } +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { + return f->has_json_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; - } +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } + +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { + return f->msgdef; } -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); +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { + return f->is_extension_ ? f->scope.extension_scope : NULL; } -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_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { + return f->is_extension_ ? NULL : f->scope.oneof; +} - upb_MessageValue val = upb_Message_Get(msg, f); - if (val.array_val) { - return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; - } +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_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)); - const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); - ret.msg = upb_Message_New(upb_MessageDef_MiniTable(m), a); +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { + upb_MessageValue ret; + + if (upb_FieldDef_IsRepeated(f) || upb_FieldDef_IsSubMessage(f)) { + return (upb_MessageValue){.msg_val = NULL}; } - val.array_val = ret.array; - upb_Message_Set(msg, f, val, a); + 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(); + } return ret; } -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); - - // Building reflection should always cause all sub-message types to be - // linked, but double-check here just for extra assurance. - UPB_ASSERT(!upb_FieldDef_IsSubMessage(f) || - upb_MessageDef_MiniTable(upb_FieldDef_ContainingType(f)) - ->subs[field->submsg_index] - .submsg); +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; +} - 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; +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; } -void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { +const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f) { if (upb_FieldDef_IsExtension(f)) { - _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + const upb_FileDef* file = upb_FieldDef_File(f); + return (upb_MiniTableField*)_upb_FileDef_ExtensionMiniTable( + file, f->layout_index); } 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; - } - - memset(mem, 0, get_field_size(field)); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); + return &layout->fields[f->layout_index]; } } -void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { - _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +const upb_MiniTableExtension* _upb_FieldDef_ExtensionMiniTable( + const upb_FieldDef* f) { + UPB_ASSERT(upb_FieldDef_IsExtension(f)); + const upb_FileDef* file = upb_FieldDef_File(f); + return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); } -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); +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) { + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; + if (f->type_ != kUpb_FieldType_Enum) return false; - /* 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); + // TODO: Maybe make is_proto2 a bool at creation? + const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef); + return upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; +} - /* 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; +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { + return f->proto3_optional_; +} - /* 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; - } - } +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } - *out_val = val; - *out_f = f; - *iter = i; - return true; +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { + uint64_t out = f->is_packed_ ? kUpb_FieldModifier_IsPacked : 0; + + switch (f->label_) { + case kUpb_Label_Optional: + if (!upb_FieldDef_HasPresence(f)) { + out |= kUpb_FieldModifier_IsProto3Singular; + } + break; + case kUpb_Label_Repeated: + out |= kUpb_FieldModifier_IsRepeated; + break; + case kUpb_Label_Required: + out |= kUpb_FieldModifier_IsRequired; + break; } - 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 (_upb_FieldDef_IsClosedEnum(f)) { + out |= kUpb_FieldModifier_IsClosedEnum; } + return out; +} - *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; - - 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; - } - } - } +bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } - return ret; +bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { + if (upb_FieldDef_IsRepeated(f)) return false; + const upb_FileDef* file = upb_FieldDef_File(f); + return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || + upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; } -bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int maxdepth) { - return _upb_Message_DiscardUnknown(msg, m, maxdepth); +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) || + upb_FieldDef_CType(f) == kUpb_CType_Enum; } - -// Must be last. - -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_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; - bool is_sorted; - upb_WellKnown well_known_type; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; - -static void assign_msg_wellknowntype(upb_MessageDef* m) { - const char* name = m->full_name; - 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; - } +bool upb_FieldDef_IsMap(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && + upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); } -upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { - return (upb_MessageDef*)&m[i]; +bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Optional; } -bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) { - for (int i = 0; i < m->ext_range_count; i++) { - const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); - if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) { - return true; - } - } - return false; +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { + return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); } -const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m) { - return m->opts; +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Repeated; } -bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { - return m->opts != (void*)kUpbDefOptDefault; +bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Required; } -const char* upb_MessageDef_FullName(const upb_MessageDef* m) { - return m->full_name; +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_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { - return m->file; +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message; } -const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { - return m->containing_type; +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; } -const char* upb_MessageDef_Name(const upb_MessageDef* m) { - return _upb_DefBuilder_FullToShort(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); } -upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { - return upb_FileDef_Syntax(m->file); +bool upb_FieldDef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); } -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 bool streql2(const char* a, size_t n, const char* b) { + return n == strlen(b) && memcmp(a, b, n) == 0; } -const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( - const upb_MessageDef* m, const char* name, size_t size) { - upb_value val; +// Implement the transformation as described in the spec: +// 1. upper case all letters after an underscore. +// 2. remove all underscores. +static char* make_json_name(const char* name, size_t size, upb_Arena* a) { + char* out = upb_Arena_Malloc(a, size + 1); // +1 is to add a trailing '\0' + if (out == NULL) return NULL; - if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { - return NULL; + bool ucase_next = false; + char* des = out; + for (size_t i = 0; i < size; i++) { + if (name[i] == '_') { + ucase_next = true; + } else { + *des++ = ucase_next ? toupper(name[i]) : name[i]; + ucase_next = false; + } } + *des++ = '\0'; + return out; +} - return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + if (!ret) _upb_DefBuilder_OomErr(ctx); + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; } -const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( - const upb_MessageDef* m, const char* name, size_t size) { - upb_value val; +static str_t* unescape(upb_DefBuilder* 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 = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + char* dst = &ret->str[0]; + const char* src = data; + const char* end = data + len; - if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { - return NULL; + while (src < end) { + if (*src == '\\') { + src++; + *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); + } else { + *dst++ = *src++; + } } - return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); + ret->len = dst - &ret->str[0]; + return ret; } -bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, - upb_value v, upb_Arena* a) { - return upb_strtable_insert(&m->ntof, name, len, v, a); -} +static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, + upb_FieldDef* f) { + char* end; + char nullz[64]; + errno = 0; -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; + 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) { + _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; } - const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); - const upb_OneofDef* o = _upb_DefType_Unpack(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 size) { - upb_value val; - const upb_FieldDef* f; - - if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { - return NULL; + 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 = upb_EnumValueDef_Number(ev); + 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. */ + _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", + upb_FieldDef_FullName(f)); } - f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); - if (!f) f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD_JSONNAME); - - return f; -} + return; -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { - return m->ext_range_count; +invalid: + _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", + (int)len, str, upb_FieldDef_FullName(f), + (int)upb_FieldDef_Type(f)); } -int upb_MessageDef_FieldCount(const upb_MessageDef* m) { - return m->field_count; +static void set_default_default(upb_DefBuilder* 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: { + const upb_EnumValueDef* v = upb_EnumDef_Value(f->sub.enumdef, 0); + f->defaultval.sint = upb_EnumValueDef_Number(v); + break; + } + case kUpb_CType_Message: + break; + } } -int upb_MessageDef_OneofCount(const upb_MessageDef* m) { - return m->oneof_count; -} +static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, + upb_MessageDef* m, upb_FieldDef* f) { + // Must happen before _upb_DefBuilder_Add() + f->file = _upb_DefBuilder_File(ctx); -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { - return m->nested_msg_count; -} + if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { - return m->nested_enum_count; -} + const upb_StringView name = google_protobuf_FieldDescriptorProto_name(field_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { - return m->nested_ext_count; -} + f->has_json_name_ = google_protobuf_FieldDescriptorProto_has_json_name(field_proto); + if (f->has_json_name_) { + const upb_StringView sv = + google_protobuf_FieldDescriptorProto_json_name(field_proto); + f->json_name = upb_strdup2(sv.data, sv.size, ctx->arena); + } else { + f->json_name = make_json_name(name.data, name.size, ctx->arena); + } + if (!f->json_name) _upb_DefBuilder_OomErr(ctx); -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { - return m->layout; -} + f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); + f->number_ = google_protobuf_FieldDescriptorProto_number(field_proto); + f->proto3_optional_ = + google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + f->msgdef = m; + f->scope.oneof = NULL; -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->ext_range_count); - return _upb_ExtensionRange_At(m->ext_ranges, i); -} + const bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); + const bool has_type_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->field_count); - return _upb_FieldDef_At(m->fields, i); -} + f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->oneof_count); - return _upb_OneofDef_At(m->oneofs, i); -} + if (has_type) { + switch (f->type_) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + if (!has_type_name) { + _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", + (int)f->type_, f->full_name); + } + break; + default: + if (has_type_name) { + _upb_DefBuilder_Errf( + ctx, "invalid type for field with type_name set (%s, %d)", + f->full_name, (int)f->type_); + } + } + } else if (has_type_name) { + f->type_ = + UPB_FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_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]; -} + if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { + _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, + f->type_); + } -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->nested_enum_count); - return _upb_EnumDef_At(m->nested_enums, i); -} + if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { + _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, + f->label_); + } -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_ext_count); - return _upb_FieldDef_At(m->nested_exts, i); -} - -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { - return m->well_known_type; -} - -bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { - return m->in_message_set; -} - -const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, - const char* name) { - return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); -} - -const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, - const char* name) { - return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(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; -bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { - return google_protobuf_MessageOptions_map_entry(m->opts); -} + if (f->label_ == kUpb_Label_Required && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } -bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { - return google_protobuf_MessageOptions_message_set_wire_format(m->opts); -} + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); -static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx, - const upb_MessageDef* m) { - upb_StringView desc; - bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc); - if (!ok) _upb_DefBuilder_OomErr(ctx); + if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { + _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } - void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab); - size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab); - upb_MiniTable* ret = upb_MiniTable_BuildWithBuf( - desc.data, desc.size, kUpb_MiniTablePlatform_Native, ctx->arena, - scratch_data, scratch_size, ctx->status); - if (!ret) _upb_DefBuilder_FailJmp(ctx); - return ret; -} + if (!m) { + _upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg", + f->full_name); + } -void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { - for (int i = 0; i < m->field_count; i++) { - upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); - _upb_FieldDef_Resolve(ctx, m->full_name, f); - } + if (oneof_index >= upb_MessageDef_OneofCount(m)) { + _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); + } - if (!ctx->layout) { - m->layout = _upb_MessageDef_MakeMiniTable(ctx, m); - if (!m->layout) _upb_DefBuilder_OomErr(ctx); - } + upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); + f->scope.oneof = oneof; -#ifndef NDEBUG - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - const int layout_index = _upb_FieldDef_LayoutIndex(f); - UPB_ASSERT(layout_index < m->layout->field_count); - const upb_MiniTable_Field* mt_f = &m->layout->fields[layout_index]; - UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f)); + bool ok = _upb_OneofDef_Insert(oneof, f, name.data, name.size, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -#endif - m->in_message_set = false; - for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { - upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); - _upb_FieldDef_Resolve(ctx, m->full_name, ext); - if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && - upb_FieldDef_Label(ext) == kUpb_Label_Optional && - upb_FieldDef_MessageSubDef(ext) == m && - google_protobuf_MessageOptions_message_set_wire_format( - upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { - m->in_message_set = true; - } - } + UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); - for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { - upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); - _upb_MessageDef_Resolve(ctx, n); + if (google_protobuf_FieldOptions_has_packed(f->opts)) { + f->is_packed_ = google_protobuf_FieldOptions_packed(f->opts); + } else { + // Repeated fields default to packed for proto3 only. + f->is_packed_ = upb_FieldDef_IsPrimitive(f) && + f->label_ == kUpb_Label_Repeated && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; } } -void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, - const upb_FieldDef* f) { - const int32_t field_number = upb_FieldDef_Number(f); +static void _upb_FieldDef_CreateExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + f->is_extension_ = true; - if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { - _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); } - const char* json_name = upb_FieldDef_JsonName(f); - const char* shortname = upb_FieldDef_Name(f); - const size_t shortnamelen = strlen(shortname); - - upb_value v = upb_value_constptr(f); + f->scope.extension_scope = m; + _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); + f->layout_index = ctx->ext_count++; - upb_value existing_v; - if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { - _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); + if (ctx->layout) { + UPB_ASSERT(_upb_FieldDef_ExtensionMiniTable(f)->field.number == f->number_); } +} - const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); - bool ok = - _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); +static void _upb_FieldDef_CreateNotExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + f->is_extension_ = false; - if (strcmp(shortname, json_name) != 0) { - if (upb_strtable_lookup(&m->ntof, json_name, &v)) { - _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); + if (!google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + if (f->proto3_optional_) { + _upb_DefBuilder_Errf( + ctx, + "non-extension field (%s) with proto3_optional was not in a oneof", + f->full_name); } - - const size_t json_size = strlen(json_name); - const upb_value json_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD_JSONNAME); - ok = _upb_MessageDef_Insert(m, json_name, json_size, json_v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - } - - if (upb_inttable_lookup(&m->itof, field_number, NULL)) { - _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); } - ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); -} + _upb_MessageDef_InsertField(ctx, m, f); -void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, - const upb_MessageDef* m) { - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); - const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f); - const int layout_index = _upb_FieldDef_LayoutIndex(f); - upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m); + if (!ctx->layout) return; - UPB_ASSERT(layout_index < m->field_count); - upb_MiniTable_Field* mt_f = - (upb_MiniTable_Field*)&m->layout->fields[layout_index]; - if (sub_m) { - if (!mt->subs) { - _upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name); - } - UPB_ASSERT(mt_f); - UPB_ASSERT(sub_m->layout); - upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout); - } else if (_upb_FieldDef_IsClosedEnum(f)) { - upb_MiniTable_SetSubEnum(mt, mt_f, _upb_EnumDef_MiniTable(sub_e)); + const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); + const upb_MiniTableField* fields = mt->fields; + for (int i = 0; i < mt->field_count; i++) { + if (fields[i].number == f->number_) { + f->layout_index = i; + return; } } - for (int i = 0; i < m->nested_msg_count; i++) { - _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i)); - } -} - -static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { - uint64_t out = 0; - if (upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3) { - out |= kUpb_MessageModifier_ValidateUtf8; - out |= kUpb_MessageModifier_DefaultIsPacked; - } - if (m->ext_range_count) { - out |= kUpb_MessageModifier_IsExtendable; - } - return out; + UPB_ASSERT(false); // It should be impossible to reach this point. } -static bool _upb_MessageDef_EncodeMap(upb_DescState* s, const upb_MessageDef* m, - upb_Arena* a) { - if (m->field_count != 2) return false; +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, + upb_MessageDef* m, bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); + upb_FieldDef* defs = + (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); - const upb_FieldDef* key_field = upb_MessageDef_Field(m, 0); - const upb_FieldDef* val_field = upb_MessageDef_Field(m, 1); - if (key_field == NULL || val_field == NULL) return false; + // If we are creating extensions then is_sorted will be NULL. + // If we are not creating extensions then is_sorted will be non-NULL. + if (is_sorted) { + uint32_t previous = 0; + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; - UPB_ASSERT(_upb_FieldDef_LayoutIndex(key_field) == 0); - UPB_ASSERT(_upb_FieldDef_LayoutIndex(val_field) == 1); + _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f); + f->index_ = i; + if (!ctx->layout) f->layout_index = i; - const upb_FieldType key_type = upb_FieldDef_Type(key_field); - const upb_FieldType val_type = upb_FieldDef_Type(val_field); + const uint32_t current = f->number_; + if (previous > current) *is_sorted = false; + previous = current; + } + } else { + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; - const uint64_t val_mod = _upb_FieldDef_IsClosedEnum(val_field) - ? kUpb_FieldModifier_IsClosedEnum - : 0; + _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f); + f->index_ = i; + } + } - s->ptr = - upb_MtDataEncoder_EncodeMap(&s->e, s->ptr, key_type, val_type, val_mod); - return true; + return defs; } -static bool _upb_MessageDef_EncodeMessage(upb_DescState* s, - const upb_MessageDef* m, - upb_Arena* a) { - const upb_FieldDef** sorted = NULL; - if (!m->is_sorted) { - sorted = _upb_FieldDefs_Sorted(m->fields, m->field_count, a); - if (!sorted) return false; +static void resolve_subdef(upb_DefBuilder* 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 UPB_FIELD_TYPE_UNSPECIFIED: { + // Type was not specified and must be inferred. + UPB_ASSERT(has_name); + upb_deftype_t type; + const void* def = + _upb_DefBuilder_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: + _upb_DefBuilder_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 = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_MSG); + break; + case kUpb_FieldType_Enum: + UPB_ASSERT(has_name); + f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_ENUM); + break; + default: + // No resolution necessary. + break; } +} - s->ptr = upb_MtDataEncoder_StartMessage(&s->e, s->ptr, - _upb_MessageDef_Modifiers(m)); +static int _upb_FieldDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(upb_FieldDef**)p1)->number_; + const uint32_t v2 = (*(upb_FieldDef**)p2)->number_; + return (v1 < v2) ? -1 : (v1 > v2); +} - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i); - const upb_FieldType type = upb_FieldDef_Type(f); - const int number = upb_FieldDef_Number(f); - const uint64_t modifiers = _upb_FieldDef_Modifiers(f); +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a) { + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; - if (!_upb_DescState_Grow(s, a)) return false; - s->ptr = upb_MtDataEncoder_PutField(&s->e, s->ptr, type, number, modifiers); + for (int i = 0; i < n; i++) { + out[i] = (upb_FieldDef*)&f[i]; } + qsort(out, n, sizeof(void*), _upb_FieldDef_Compare); - for (int i = 0; i < m->real_oneof_count; i++) { - if (!_upb_DescState_Grow(s, a)) return false; - s->ptr = upb_MtDataEncoder_StartOneof(&s->e, s->ptr); - - const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); - const int field_count = upb_OneofDef_FieldCount(o); - for (int j = 0; j < field_count; j++) { - const int number = upb_FieldDef_Number(upb_OneofDef_Field(o, j)); - - if (!_upb_DescState_Grow(s, a)) return false; - s->ptr = upb_MtDataEncoder_PutOneofField(&s->e, s->ptr, number); - } + for (int i = 0; i < n; i++) { + out[i]->layout_index = i; } - - return true; + return (const upb_FieldDef**)out; } -static bool _upb_MessageDef_EncodeMessageSet(upb_DescState* s, - const upb_MessageDef* m, - upb_Arena* a) { - s->ptr = upb_MtDataEncoder_EncodeMessageSet(&s->e, s->ptr); - - return true; -} +bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, + upb_StringView* out) { + UPB_ASSERT(f->is_extension_); -bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, - upb_StringView* out) { upb_DescState s; _upb_DescState_Init(&s); - if (!_upb_DescState_Grow(&s, a)) return false; - - if (upb_MessageDef_IsMapEntry(m)) { - if (!_upb_MessageDef_EncodeMap(&s, m, a)) return false; - } else if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { - if (!_upb_MessageDef_EncodeMessageSet(&s, m, a)) return false; - } else { - if (!_upb_MessageDef_EncodeMessage(&s, m, a)) return false; - } + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EncodeExtension(&s.e, s.ptr, f->type_, number, + modifiers); *s.ptr = '\0'; out->data = s.buf; @@ -9596,2932 +9094,4022 @@ bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, return true; } -static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_DescriptorProto* msg_proto, - const upb_MessageDef* containing_type, - 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 n_oneof, n_field, n_ext_range, n_enum, n_ext, n_msg; - upb_StringView name; - - // Must happen before _upb_DefBuilder_Add() - m->file = _upb_DefBuilder_File(ctx); - - m->containing_type = containing_type; - m->is_sorted = true; - - name = google_protobuf_DescriptorProto_name(msg_proto); - _upb_DefBuilder_CheckIdentNotFull(ctx, name); - - m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); +static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { + _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", + f->full_name); + } - 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); + upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); + const upb_MessageDef* m = + _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); + f->msgdef = m; - bool ok = upb_inttable_init(&m->itof, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) { + _upb_DefBuilder_Errf( + ctx, + "field number %u in extension %s has no extension range in message %s", + (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m)); + } - ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + const upb_MiniTableExtension* ext = _upb_FieldDef_ExtensionMiniTable(f); 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); + UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); } else { - /* Allocate now (to allow cross-linking), populate later. */ - m->layout = _upb_DefBuilder_Alloc( - ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); - } - - UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); - - m->oneof_count = n_oneof; - m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); - - m->field_count = n_field; - m->fields = - _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted); + upb_StringView desc; + if (!upb_FieldDef_MiniDescriptorEncode(f, ctx->tmp_arena, &desc)) { + _upb_DefBuilder_OomErr(ctx); + } - // Message Sets may not contain fields. - if (UPB_UNLIKELY(google_protobuf_MessageOptions_message_set_wire_format(m->opts))) { - if (UPB_UNLIKELY(n_field > 0)) { - _upb_DefBuilder_Errf(ctx, "invalid message set (%s)", m->full_name); + upb_MiniTableExtension* mut_ext = (upb_MiniTableExtension*)ext; + upb_MiniTableSub sub = {NULL}; + if (upb_FieldDef_IsSubMessage(f)) { + sub.submsg = upb_MessageDef_MiniTable(f->sub.msgdef); + } else if (_upb_FieldDef_IsClosedEnum(f)) { + sub.subenum = _upb_EnumDef_MiniTable(f->sub.enumdef); } + bool ok2 = upb_MiniTable_BuildExtension(desc.data, desc.size, mut_ext, + upb_MessageDef_MiniTable(m), sub, + ctx->status); + if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table"); } - m->ext_range_count = n_ext_range; - m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); - - const size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); - m->real_oneof_count = m->oneof_count - synthetic_count; + bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} - assign_msg_wellknowntype(m); - upb_inttable_compact(&m->itof, ctx->arena); +static void resolve_default(upb_DefBuilder* 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); - const google_protobuf_EnumDescriptorProto* const* enums = - google_protobuf_DescriptorProto_enum_type(msg_proto, &n_enum); - m->nested_enum_count = n_enum; - m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m); + if (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, + "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } - const google_protobuf_FieldDescriptorProto* const* exts = - google_protobuf_DescriptorProto_extension(msg_proto, &n_ext); - m->nested_ext_count = n_ext; - m->nested_exts = _upb_FieldDefs_New(ctx, n_ext, exts, m->full_name, m, NULL); + if (upb_FieldDef_IsSubMessage(f)) { + _upb_DefBuilder_Errf(ctx, + "message fields cannot have explicit defaults (%s)", + f->full_name); + } - const google_protobuf_DescriptorProto* const* msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n_msg); - m->nested_msg_count = n_msg; - m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m); + parse_default(ctx, defaultval.data, defaultval.size, f); + f->has_default = true; + } else { + set_default_default(ctx, f); + f->has_default = false; + } } -// Allocate and initialize an array of |n| message defs. -upb_MessageDef* _upb_MessageDefs_New( - upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, - const upb_MessageDef* containing_type) { - _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); +void _upb_FieldDef_Resolve(upb_DefBuilder* 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; - const char* name = containing_type ? containing_type->full_name - : _upb_FileDef_RawPackage(ctx->file); + resolve_subdef(ctx, prefix, f); + resolve_default(ctx, f, field_proto); - upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); - for (int i = 0; i < n; i++) { - create_msgdef(ctx, name, protos[i], containing_type, &m[i]); + if (f->is_extension_) { + resolve_extension(ctx, prefix, f, field_proto); } - return m; } // Must be last. -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_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_MiniTableExtension** 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; }; -upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { - return (upb_MethodDef*)&m[i]; +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { + return f->opts; } -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { - return m->service; +bool upb_FileDef_HasOptions(const upb_FileDef* f) { + return f->opts != (void*)kUpbDefOptDefault; } -const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { - return m->opts; -} +const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } -bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { - return m->opts != (void*)kUpbDefOptDefault; +const char* upb_FileDef_Package(const upb_FileDef* f) { + return f->package ? f->package : ""; } -const char* upb_MethodDef_FullName(const upb_MethodDef* m) { - return m->full_name; -} +const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } -const char* upb_MethodDef_Name(const upb_MethodDef* m) { - return _upb_DefBuilder_FullToShort(m->full_name); +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_MethodDef_Index(const upb_MethodDef* m) { return m->index; } +int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { - return m->input_type; +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { + return f->public_dep_count; } -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { - return m->output_type; +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { + return f->weak_dep_count; } -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { - return m->client_streaming; +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { + return f->public_deps; } -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { - return m->server_streaming; +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { + return f->weak_deps; } -static void create_method(upb_DefBuilder* ctx, - const google_protobuf_MethodDescriptorProto* method_proto, - upb_ServiceDef* s, upb_MethodDef* m) { - upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); - - m->service = s; - m->full_name = - _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); - m->client_streaming = - google_protobuf_MethodDescriptorProto_client_streaming(method_proto); - m->server_streaming = - google_protobuf_MethodDescriptorProto_server_streaming(method_proto); - m->input_type = _upb_DefBuilder_Resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); - m->output_type = _upb_DefBuilder_Resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); - - UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, - method_proto); +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { + return f->top_lvl_enum_count; } -// Allocate and initialize an array of |n| method defs belonging to |s|. -upb_MethodDef* _upb_MethodDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s) { - upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); - for (int i = 0; i < n; i++) { - create_method(ctx, protos[i], s, &m[i]); - m[i].index = i; - } - return m; +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { + return f->top_lvl_ext_count; } -#include -#include -#include - - -// Must be last. - -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; // lookup a field by name - upb_inttable itof; // lookup a field by number (index) -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; +int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } -upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { - return (upb_OneofDef*)&o[i]; +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 google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o) { - return o->opts; +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_OneofDef_HasOptions(const upb_OneofDef* o) { - return o->opts != (void*)kUpbDefOptDefault; +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]]; } -const char* upb_OneofDef_FullName(const upb_OneofDef* o) { - return o->full_name; +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); + return _upb_MessageDef_At(f->top_lvl_msgs, i); } -const char* upb_OneofDef_Name(const upb_OneofDef* o) { - return _upb_DefBuilder_FullToShort(o->full_name); +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); + return _upb_EnumDef_At(f->top_lvl_enums, i); } -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { - return o->parent; +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); + return _upb_FieldDef_At(f->top_lvl_exts, i); } -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]; +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->service_count); + return _upb_ServiceDef_At(f->services, i); } -int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } -uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { - // Compute index in our parent's array. - return o - upb_MessageDef_Oneof(o->parent, 0); +const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i) { + return f->ext_layouts[i]; } -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 size) { - upb_value val; - return upb_strtable_lookup2(&o->ntof, name, size, &val) - ? upb_value_getptr(val) - : NULL; +static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { + char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; } -const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, - const char* name) { - return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); +static bool streql_view(upb_StringView view, const char* b) { + return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; } -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; -} +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_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, - const char* name, size_t size, upb_Arena* a) { - o->field_count++; - if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = 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]); + } - const int number = upb_FieldDef_Number(f); - const upb_value v = upb_value_constptr(f); - return upb_inttable_insert(&o->itof, number, v, a) && - upb_strtable_insert(&o->ntof, name, size, v, a); + return ext_count; } -// Returns the synthetic count. -size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { - int synthetic_count = 0; - - for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { - upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); +// Allocate and initialize one file def, and add it to the context object. +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto) { + upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); + ctx->file = file; - if (o->synthetic && o->field_count != 1) { - _upb_DefBuilder_Errf(ctx, - "Synthetic oneofs must have one field, not %d: %s", - o->field_count, upb_OneofDef_Name(o)); - } + 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 n; - if (o->synthetic) { - synthetic_count++; - } else if (synthetic_count != 0) { - _upb_DefBuilder_Errf( - ctx, "Synthetic oneofs must be after all other oneofs: %s", - upb_OneofDef_Name(o)); - } + file->symtab = ctx->symtab; - o->fields = - _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); - o->field_count = 0; + // 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; - for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); - if (o) { - o->fields[o->field_count++] = f; + 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) { + _upb_DefBuilder_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 = _upb_DefBuilder_Alloc( + ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_MiniTableExtension* ext = + _upb_DefBuilder_Alloc(ctx, sizeof(*ext) * file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; } } - return synthetic_count; -} + if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { + _upb_DefBuilder_Errf(ctx, "File has no name"); + } -static void create_oneofdef(upb_DefBuilder* 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); + file->name = strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); - o->parent = m; - o->full_name = - _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); - o->field_count = 0; - o->synthetic = false; + upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); + if (package.size) { + _upb_DefBuilder_CheckIdentFull(ctx, package); + file->package = strviewdup(ctx, package); + } else { + file->package = NULL; + } - UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { + upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); - if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { - _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); + if (streql_view(syntax, "proto2")) { + file->syntax = kUpb_Syntax_Proto2; + } else if (streql_view(syntax, "proto3")) { + file->syntax = kUpb_Syntax_Proto3; + } else { + _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(syntax)); + } + } else { + file->syntax = kUpb_Syntax_Proto2; } - upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); - bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + // Read options. + UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); - ok = upb_inttable_init(&o->itof, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + // Verify dependencies. + strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); + file->dep_count = n; + file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n); - ok = upb_strtable_init(&o->ntof, 4, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); -} + for (size_t 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]) { + _upb_DefBuilder_Errf(ctx, + "Depends on file '" UPB_STRINGVIEW_FORMAT + "', but it has not been loaded", + UPB_STRINGVIEW_ARGS(str)); + } + } -// Allocate and initialize an array of |n| oneof defs. -upb_OneofDef* _upb_OneofDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m) { - _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); + public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); + file->public_dep_count = n; + file->public_deps = + _upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n); + int32_t* mutable_public_deps = (int32_t*)file->public_deps; + for (size_t i = 0; i < n; i++) { + if (public_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", + (int)public_deps[i]); + } + mutable_public_deps[i] = public_deps[i]; + } - upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); - for (int i = 0; i < n; i++) { - create_oneofdef(ctx, m, protos[i], &o[i]); + weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); + file->weak_dep_count = n; + file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n); + int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; + for (size_t i = 0; i < n; i++) { + if (weak_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", + (int)weak_deps[i]); + } + mutable_weak_deps[i] = weak_deps[i]; } - return o; -} + // Create enums. + enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + file->top_lvl_enum_count = n; + file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); -// Must be last. + // Create extensions. + exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->top_lvl_ext_count = n; + file->top_lvl_exts = + _upb_FieldDefs_New(ctx, n, exts, file->package, NULL, NULL); -struct upb_ServiceDef { - const google_protobuf_ServiceOptions* opts; - const upb_FileDef* file; - const char* full_name; - upb_MethodDef* methods; - int method_count; - int index; -}; + // Create messages. + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + file->top_lvl_msg_count = n; + file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); -upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { - return (upb_ServiceDef*)&s[index]; -} + // Create services. + services = google_protobuf_FileDescriptorProto_service(file_proto, &n); + file->service_count = n; + file->services = _upb_ServiceDefs_New(ctx, n, services); -const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { - return s->opts; -} + // Now that all names are in the table, build layouts and resolve refs. -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { - return s->opts != (void*)kUpbDefOptDefault; -} + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_Resolve(ctx, m); + } -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { - return s->full_name; -} + for (int i = 0; i < file->top_lvl_ext_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); + _upb_FieldDef_Resolve(ctx, file->package, f); + } -const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { - return _upb_DefBuilder_FullToShort(s->full_name); + if (!ctx->layout) { + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_LinkMiniTable(ctx, m); + } + } + + if (file->ext_count) { + bool ok = upb_ExtensionRegistry_AddArray( + _upb_DefPool_ExtReg(ctx->symtab), file->ext_layouts, file->ext_count); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } } -int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { - return s->file; +#include + + +// Must be last. + +static size_t get_field_size(const upb_MiniTableField* 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]; } -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { - return s->method_count; +static bool in_oneof(const upb_MiniTableField* field) { + return field->presence < 0; } -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { - return (i < 0 || i >= s->method_count) ? NULL - : _upb_MethodDef_At(s->methods, i); +static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, + const upb_FieldDef* f) { + const upb_MiniTableField* 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; } -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name) { - for (int i = 0; i < s->method_count; i++) { - const upb_MethodDef* m = _upb_MethodDef_At(s->methods, i); - if (strcmp(name, upb_MethodDef_Name(m)) == 0) { - return m; +bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { + assert(upb_FieldDef_HasPresence(f)); + if (upb_FieldDef_IsExtension(f)) { + const upb_MiniTableExtension* ext = _upb_FieldDef_ExtensionMiniTable(f); + return _upb_Message_Getext(msg, ext) != NULL; + } else { + const upb_MiniTableField* 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; } } - return NULL; } -static void create_service(upb_DefBuilder* ctx, - const google_protobuf_ServiceDescriptorProto* svc_proto, - upb_ServiceDef* s) { - upb_StringView name; - size_t n; - - // Must happen before _upb_DefBuilder_Add() - s->file = _upb_DefBuilder_File(ctx); - - name = google_protobuf_ServiceDescriptorProto_name(svc_proto); - _upb_DefBuilder_CheckIdentNotFull(ctx, name); - const char* package = _upb_FileDef_RawPackage(s->file); - s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); - _upb_DefBuilder_Add(ctx, s->full_name, - _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); - - const google_protobuf_MethodDescriptorProto* const* methods = - google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); - s->method_count = n; - s->methods = _upb_MethodDefs_New(ctx, n, methods, s); - - UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, - svc_proto); -} - -upb_ServiceDef* _upb_ServiceDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_ServiceDescriptorProto* const* protos) { - _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); - - upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); - for (int i = 0; i < n; i++) { - create_service(ctx, protos[i], &s[i]); - s[i].index = i; +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_MiniTableField* 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; } - return s; } -/* - * 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); +upb_MessageValue upb_Message_Get(const upb_Message* msg, + const upb_FieldDef* f) { + upb_MessageValue default_val = upb_FieldDef_Default(f); + upb_MessageValue ret; + _upb_MiniTable_GetField(msg, upb_FieldDef_MiniTable(f), &default_val, &ret); 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); -} +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; + } -char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { - size_t n; - char* p; + upb_MessageValue val = upb_Message_Get(msg, f); + if (val.array_val) { + return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; + } - /* 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; + 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)); + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + ret.msg = upb_Message_New(upb_MessageDef_MiniTable(m), a); } - 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; + val.array_val = ret.array; + upb_Message_Set(msg, f, val, a); -static lookupkey_t strkey2(const char* str, size_t len) { - lookupkey_t k; - k.str.str = str; - k.str.len = len; - return k; + return ret; } -static lookupkey_t intkey(uintptr_t key) { - lookupkey_t k; - k.num = key; - return k; +bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a) { + return _upb_MiniTable_SetField(msg, upb_FieldDef_MiniTable(f), &val, a); } -typedef uint32_t hashfunc_t(upb_tabkey key); -typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); +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_MiniTableField* field = upb_FieldDef_MiniTable(f); + char* mem = UPB_PTR_AT(msg, field->offset, char); -/* Base table (shared code) ***************************************************/ + 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 uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } + memset(mem, 0, get_field_size(field)); + } +} -static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { - return t->entries + (hash & t->mask); +void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { + _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); } -static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } +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 bool isfull(upb_table* t) { return t->count == t->max_count; } + /* 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 bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { - size_t bytes; + /* 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; - 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; -} + /* 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; + } + } -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; + *out_val = val; + *out_f = f; + *iter = i; + return true; } - for (e = begin; e < end; e++) { - if (upb_tabent_isempty(e)) return e; + + 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; + } } - UPB_ASSERT(false); - return NULL; -} -static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { - return (upb_tabent*)upb_getentry(t, hash); + *iter = i; + return false; } -static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e; +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 (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; - } -} + if (--depth == 0) return false; -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); -} + _upb_Message_DiscardUnknown_shallow(msg); -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); + 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; + + upb_MessageValue map_key, map_val; + while (upb_Map_Next(map, &map_key, &map_val, &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 true; - } else { - return false; } + + return ret; } -/* 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; +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth) { + return _upb_Message_DiscardUnknown(msg, m, maxdepth); +} - UPB_ASSERT(findentry(t, key, hash, eql) == NULL); - t->count++; - mainpos_e = getentry_mutable(t, hash); - our_e = mainpos_e; +// Must be last. - if (upb_tabent_isempty(mainpos_e)) { - /* Our main position is empty; use it. */ - our_e->next = NULL; +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; + + // TODO(salo): These counters don't need anywhere near 32 bits. + 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; + bool is_sorted; + upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +static void assign_msg_wellknowntype(upb_MessageDef* m) { + const char* name = m->full_name; + 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 { - /* 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; - } + m->well_known_type = kUpb_WellKnown_Unspecified; } - 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; +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { + return (upb_MessageDef*)&m[i]; +} + +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) { + for (int i = 0; i < m->ext_range_count; i++) { + const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); + if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) { return true; - } else { - /* Element to remove is not in the table. */ - return false; } } + 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; +const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m) { + return m->opts; } -static size_t begin(const upb_table* t) { return next(t, -1); } - -/* upb_strtable ***************************************************************/ +bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} -/* A simple "subclass" of upb_table that only adds a hash function for strings. - */ +const char* upb_MessageDef_FullName(const upb_MessageDef* m) { + return m->full_name; +} -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; +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { + return m->file; } -/* Adapted from ABSL's wyhash. */ +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { + return m->containing_type; +} -static uint64_t UnalignedLoad64(const void* p) { - uint64_t val; - memcpy(&val, p, 8); - return val; +const char* upb_MessageDef_Name(const upb_MessageDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); } -static uint32_t UnalignedLoad32(const void* p) { - uint32_t val; - memcpy(&val, p, 4); - return val; +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { + return upb_FileDef_Syntax(m->file); } -#if defined(_MSC_VER) && defined(_M_X64) -#include -#endif +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; +} -/* 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 -} +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; -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 (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } -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]; + return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +} - 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; +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; - 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); + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } - uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); - current_state = (cs0 ^ cs1); + return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); +} - uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); - uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); - duplicated_state = (ds0 ^ ds1); +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, + upb_value v, upb_Arena* a) { + return upb_strtable_insert(&m->ntof, name, len, v, a); +} - ptr += 64; - len -= 64; - } while (len > 64); +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; - current_state = current_state ^ duplicated_state; + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; } - // 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); + const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + const upb_OneofDef* o = _upb_DefType_Unpack(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. */ +} - current_state = WyhashMix(a ^ salt[1], b ^ current_state); +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + const upb_FieldDef* f; - ptr += 16; - len -= 16; + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; } - // 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; - } + f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + if (!f) f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD_JSONNAME); - uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t z = salt[1] ^ starting_length; - return WyhashMix(w, z); + return f; } -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); +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { + return m->ext_range_count; } -static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { - return _upb_Hash(p, n, 0); +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m) { + return m->res_range_count; } -static uint32_t strhash(upb_tabkey key) { - uint32_t len; - char* str = upb_tabstr(key, &len); - return _upb_Hash_NoSeed(str, len); +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m) { + return m->res_name_count; } -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); +int upb_MessageDef_FieldCount(const upb_MessageDef* m) { + return m->field_count; } -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); +int upb_MessageDef_OneofCount(const upb_MessageDef* m) { + return m->oneof_count; } -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); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { + return m->nested_msg_count; } -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; +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { + return m->nested_enum_count; } -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 = _upb_Hash_NoSeed(key.str.str, key.str.len); - insert(&t->t, key, tabkey, v, hash, &strhash, &streql); - return true; +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { + return m->nested_ext_count; } -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); +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { + return m->layout; } -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); +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->ext_range_count); + return _upb_ExtensionRange_At(m->ext_ranges, i); } -/* Iteration */ - -void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { - i->t = t; - i->index = begin(&t->t); +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); } -void upb_strtable_next(upb_strtable_iter* i) { - i->index = next(&i->t->t, i->index); +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]; } -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)); +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->field_count); + return _upb_FieldDef_At(m->fields, 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; +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->oneof_count); + return _upb_OneofDef_At(m->oneofs, i); } -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); +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]; } -void upb_strtable_iter_setdone(upb_strtable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->nested_enum_count); + return _upb_EnumDef_At(m->nested_enums, i); } -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; +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_ext_count); + return _upb_FieldDef_At(m->nested_exts, i); } -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; - } +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { + return m->well_known_type; } -static const upb_tabval* inttable_val_const(const upb_inttable* t, - uintptr_t key) { - return inttable_val((upb_inttable*)t, key); +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { + return m->in_message_set; } -size_t upb_inttable_count(const upb_inttable* t) { - return t->t.count + t->array_count; +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); } -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 +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); } -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_MessageDef_IsMapEntry(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_map_entry(m->opts); } -bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { - return upb_inttable_sizedinit(t, 0, 4, a); +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_message_set_wire_format(m->opts); } -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; +static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + upb_StringView desc; + bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc); + if (!ok) _upb_DefBuilder_OomErr(ctx); - if (!init(&new_table, t->t.size_lg2 + 1, a)) { - return false; - } + void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab); + size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab); + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf( + desc.data, desc.size, kUpb_MiniTablePlatform_Native, ctx->arena, + scratch_data, scratch_size, ctx->status); + if (!ret) _upb_DefBuilder_FailJmp(ctx); + return ret; +} - 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; +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); + _upb_FieldDef_Resolve(ctx, m->full_name, f); + } - _upb_value_setval(&v, e->val.val); - hash = upb_inthash(e->key); - insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); - } + if (!ctx->layout) { + m->layout = _upb_MessageDef_MakeMiniTable(ctx, m); + if (!m->layout) _upb_DefBuilder_OomErr(ctx); + } - UPB_ASSERT(t->t.count == new_table.count); +#ifndef NDEBUG + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + UPB_ASSERT(layout_index < m->layout->field_count); + const upb_MiniTableField* mt_f = &m->layout->fields[layout_index]; + UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f)); + } +#endif - t->t = new_table; + m->in_message_set = false; + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); + _upb_FieldDef_Resolve(ctx, m->full_name, ext); + if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && + upb_FieldDef_Label(ext) == kUpb_Label_Optional && + upb_FieldDef_MessageSubDef(ext) == m && + google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { + m->in_message_set = true; } - 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; + for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { + upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); + _upb_MessageDef_Resolve(ctx, n); + } } -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; -} +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f) { + const int32_t field_number = upb_FieldDef_Number(f); -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); + if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { + _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); } - 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}; + const char* json_name = upb_FieldDef_JsonName(f); + const char* shortname = upb_FieldDef_Name(f); + const size_t shortnamelen = strlen(shortname); - upb_inttable_iter i; - size_t arr_count; - int size_lg2; - upb_inttable new_t; + upb_value v = upb_value_constptr(f); - 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]++; + upb_value existing_v; + if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { + _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); } - /* Find the largest power of two that satisfies the MIN_DENSITY - * definition (while actually having some keys). */ - arr_count = upb_inttable_count(t); + const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); + bool ok = + _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); - 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; + if (strcmp(shortname, json_name) != 0) { + if (upb_strtable_lookup(&m->ntof, json_name, &v)) { + _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); } - arr_count -= counts[size_lg2]; + const size_t json_size = strlen(json_name); + const upb_value json_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD_JSONNAME); + ok = _upb_MessageDef_Insert(m, json_name, json_size, json_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } - 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); + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); } - *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]; + ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -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_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); + const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m); -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; + UPB_ASSERT(layout_index < m->field_count); + upb_MiniTableField* mt_f = + (upb_MiniTableField*)&m->layout->fields[layout_index]; + if (sub_m) { + if (!mt->subs) { + _upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name); } + UPB_ASSERT(mt_f); + UPB_ASSERT(sub_m->layout); + upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout); + } else if (_upb_FieldDef_IsClosedEnum(f)) { + upb_MiniTable_SetSubEnum(mt, mt_f, _upb_EnumDef_MiniTable(sub_e)); } - 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; - } - } + for (int i = 0; i < m->nested_msg_count; i++) { + _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i)); } +} - 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; +static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { + uint64_t out = 0; + if (upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3) { + out |= kUpb_MessageModifier_ValidateUtf8; + out |= kUpb_MessageModifier_DefaultIsPacked; } - - return false; + if (m->ext_range_count) { + out |= kUpb_MessageModifier_IsExtendable; + } + return out; } -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; +static bool _upb_MessageDef_EncodeMap(upb_DescState* s, const upb_MessageDef* m, + upb_Arena* a) { + if (m->field_count != 2) return false; - // 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; - } - } + const upb_FieldDef* key_field = upb_MessageDef_Field(m, 0); + const upb_FieldDef* val_field = upb_MessageDef_Field(m, 1); + if (key_field == NULL || val_field == NULL) return false; - if (prev) { - prev->next = ent->next; - } + UPB_ASSERT(_upb_FieldDef_LayoutIndex(key_field) == 0); + UPB_ASSERT(_upb_FieldDef_LayoutIndex(val_field) == 1); - t->t.count--; - ent->key = 0; - ent->next = NULL; - } + const upb_FieldType key_type = upb_FieldDef_Type(key_field); + const upb_FieldType val_type = upb_FieldDef_Type(val_field); + + const uint64_t val_mod = _upb_FieldDef_IsClosedEnum(val_field) + ? kUpb_FieldModifier_IsClosedEnum + : 0; + + s->ptr = + upb_MtDataEncoder_EncodeMap(&s->e, s->ptr, key_type, val_type, val_mod); + return true; } -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; +static bool _upb_MessageDef_EncodeMessage(upb_DescState* s, + const upb_MessageDef* m, + upb_Arena* a) { + const upb_FieldDef** sorted = NULL; + if (!m->is_sorted) { + sorted = _upb_FieldDefs_Sorted(m->fields, m->field_count, a); + if (!sorted) return false; } - return false; -} + s->ptr = upb_MtDataEncoder_StartMessage(&s->e, s->ptr, + _upb_MessageDef_Modifiers(m)); -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; + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i); + const upb_FieldType type = upb_FieldDef_Type(f); + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); - // 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 (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_PutField(&s->e, s->ptr, type, number, modifiers); } - if (prev) { - prev->next = ent->next; + for (int i = 0; i < m->real_oneof_count; i++) { + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_StartOneof(&s->e, s->ptr); + + const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); + const int field_count = upb_OneofDef_FieldCount(o); + for (int j = 0; j < field_count; j++) { + const int number = upb_FieldDef_Number(upb_OneofDef_Field(o, j)); + + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_PutOneofField(&s->e, s->ptr, number); + } } - t->t.count--; - ent->key = 0; - ent->next = NULL; + return true; } -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 bool _upb_MessageDef_EncodeMessageSet(upb_DescState* s, + const upb_MessageDef* m, + upb_Arena* a) { + s->ptr = upb_MtDataEncoder_EncodeMessageSet(&s->e, s->ptr); + + return true; +} + +bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); + + if (!_upb_DescState_Grow(&s, a)) return false; + + if (upb_MessageDef_IsMapEntry(m)) { + if (!_upb_MessageDef_EncodeMap(&s, m, a)) return false; + } else if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { + if (!_upb_MessageDef_EncodeMessageSet(&s, m, a)) return false; } else { - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(int_tabent(i)); + if (!_upb_MessageDef_EncodeMessage(&s, m, a)) return 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; -} + if (!_upb_DescState_Grow(&s, a)) return false; + *s.ptr = '\0'; -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); + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; } -void upb_inttable_iter_setdone(upb_inttable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; - i->array_part = false; +static upb_StringView* _upb_ReservedNames_New(upb_DefBuilder* ctx, int n, + const upb_StringView* protos) { + upb_StringView* sv = _upb_DefBuilder_Alloc(ctx, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; + } + return sv; } -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 create_msgdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_DescriptorProto* msg_proto, + const upb_MessageDef* containing_type, + 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 n_oneof, n_field, n_enum, n_ext, n_msg; + size_t n_ext_range, n_res_range, n_res_name; + upb_StringView name; + // Must happen before _upb_DefBuilder_Add() + m->file = _upb_DefBuilder_File(ctx); -// Must be last. + m->containing_type = containing_type; + m->is_sorted = true; -int upb_Unicode_ToUTF8(uint32_t cp, char* out) { - if (cp <= 0x7f) { - out[0] = cp; - return 1; - } - if (cp <= 0x07ff) { - out[0] = (cp >> 6) | 0xc0; - out[1] = (cp & 0x3f) | 0x80; - return 2; - } - if (cp <= 0xffff) { - out[0] = (cp >> 12) | 0xe0; - out[1] = ((cp >> 6) & 0x3f) | 0x80; - out[2] = (cp & 0x3f) | 0x80; - return 3; - } - if (cp <= 0x10ffff) { - out[0] = (cp >> 18) | 0xf0; - out[1] = ((cp >> 12) & 0x3f) | 0x80; - out[2] = ((cp >> 6) & 0x3f) | 0x80; - out[3] = (cp & 0x3f) | 0x80; - return 4; - } - return 0; -} + name = google_protobuf_DescriptorProto_name(msg_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); -#include + 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); + bool ok = upb_inttable_init(&m->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); -// Must be last. + ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); -/** upb_Message ***************************************************************/ + 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 = _upb_DefBuilder_Alloc( + ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); + } -static const size_t overhead = sizeof(upb_Message_InternalData); + UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); -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); -} + m->oneof_count = n_oneof; + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); -upb_Message* upb_Message_New(const upb_MiniTable* mini_table, - upb_Arena* arena) { - return _upb_Message_New(mini_table, arena); -} + m->field_count = n_field; + m->fields = + _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted); -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)); -} + // Message Sets may not contain fields. + if (UPB_UNLIKELY(google_protobuf_MessageOptions_message_set_wire_format(m->opts))) { + if (UPB_UNLIKELY(n_field > 0)) { + _upb_DefBuilder_Errf(ctx, "invalid message set (%s)", m->full_name); + } + } -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; -} + m->ext_range_count = n_ext_range; + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); -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; -} + m->res_range_count = n_res_range; + m->res_ranges = + _upb_MessageReservedRanges_New(ctx, n_res_range, res_ranges, m); -void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (in->internal) { - in->internal->unknown_end = overhead; - } -} + m->res_name_count = n_res_name; + m->res_names = _upb_ReservedNames_New(ctx, n_res_name, res_names); -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 size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); + m->real_oneof_count = m->oneof_count - synthetic_count; -void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - const char* internal_unknown_end = - UPB_PTR_AT(in->internal, in->internal->unknown_end, char); -#ifndef NDEBUG - size_t full_unknown_size; - const char* full_unknown = upb_Message_GetUnknown(msg, &full_unknown_size); - UPB_ASSERT((uintptr_t)data >= (uintptr_t)full_unknown); - UPB_ASSERT((uintptr_t)data < (uintptr_t)(full_unknown + full_unknown_size)); - UPB_ASSERT((uintptr_t)(data + len) > (uintptr_t)data); - UPB_ASSERT((uintptr_t)(data + len) <= (uintptr_t)internal_unknown_end); -#endif - if ((data + len) != internal_unknown_end) { - memmove((char*)data, data + len, internal_unknown_end - data - len); - } - in->internal->unknown_end -= len; + assign_msg_wellknowntype(m); + upb_inttable_compact(&m->itof, ctx->arena); + + const google_protobuf_EnumDescriptorProto* const* enums = + google_protobuf_DescriptorProto_enum_type(msg_proto, &n_enum); + m->nested_enum_count = n_enum; + m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m); + + const google_protobuf_FieldDescriptorProto* const* exts = + google_protobuf_DescriptorProto_extension(msg_proto, &n_ext); + m->nested_ext_count = n_ext; + m->nested_exts = _upb_FieldDefs_New(ctx, n_ext, exts, m->full_name, m, NULL); + + const google_protobuf_DescriptorProto* const* msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n_msg); + m->nested_msg_count = n_msg; + m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m); } -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; +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); + + const char* name = containing_type ? containing_type->full_name + : _upb_FileDef_RawPackage(ctx->file); + + upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); + for (int i = 0; i < n; i++) { + create_msgdef(ctx, name, protos[i], containing_type, &m[i]); } + return m; } -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]; - } - } +// Must be last. - return NULL; -} +struct upb_MessageReservedRange { + int32_t start; + int32_t end; +}; -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_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i) { + return (upb_MessageReservedRange*)&r[i]; } -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; +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r) { + return r->start; } - -size_t upb_Message_ExtensionCount(const upb_Message* msg) { - size_t count; - _upb_Message_Getexts(msg, &count); - return count; +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r) { + return r->end; } -/** upb_Map *******************************************************************/ +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m) { + upb_MessageReservedRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageReservedRange) * n); -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)); + 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; - if (!map) { - return NULL; - } + // 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) { + _upb_DefBuilder_Errf(ctx, + "Reserved range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } - upb_strtable_init(&map->table, 4, a); - map->key_size = key_size; - map->val_size = value_size; + r[i].start = start; + r[i].end = end; + } - return map; + return r; } -const float kUpb_FltInfinity = INFINITY; -const double kUpb_Infinity = INFINITY; - - -#include -#include -#include -#include -#include -#include // Must be last. -void upb_Status_Clear(upb_Status* status) { - if (!status) return; - status->ok = true; - status->msg[0] = '\0'; -} +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; +}; -bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { + return (upb_MethodDef*)&m[i]; +} -const char* upb_Status_ErrorMessage(const upb_Status* status) { - return status->msg; +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { + return m->service; } -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'; +const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { + return m->opts; } -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); +bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { + return m->opts != (void*)kUpbDefOptDefault; } -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'; +const char* upb_MethodDef_FullName(const upb_MethodDef* m) { + return m->full_name; } -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'; +const char* upb_MethodDef_Name(const upb_MethodDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); } -#include -#include -#include +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { + return m->input_type; +} -// Must be last. +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { + return m->output_type; +} -/* Miscellaneous utilities ****************************************************/ +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { + return m->client_streaming; +} -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 = '.'; - } +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { + return m->server_streaming; } -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); +static void create_method(upb_DefBuilder* ctx, + const google_protobuf_MethodDescriptorProto* method_proto, + upb_ServiceDef* s, upb_MethodDef* m) { + upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); + + m->service = s; + m->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); + m->client_streaming = + google_protobuf_MethodDescriptorProto_client_streaming(method_proto); + m->server_streaming = + google_protobuf_MethodDescriptorProto_server_streaming(method_proto); + m->input_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); + m->output_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); + + UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); } -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); +// Allocate and initialize an array of |n| method defs belonging to |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s) { + upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); + for (int i = 0; i < n; i++) { + create_method(ctx, protos[i], s, &m[i]); + m[i].index = i; } - upb_FixLocale(buf); + return m; } - +#include +#include #include // Must be last. -// A few fake field types for our tables. -enum { - kUpb_FakeFieldType_FieldNotFound = 0, - kUpb_FakeFieldType_MessageSetItem = 19, +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; // lookup a field by name + upb_inttable itof; // lookup a field by number (index) +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; -// DecodeOp: an action to be performed for a wire-type/field-type combination. -enum { - // Special ops: we don't write data to regular fields for these. - kUpb_DecodeOp_UnknownField = -1, - kUpb_DecodeOp_MessageSetItem = -2, +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { + return (upb_OneofDef*)&o[i]; +} - // Scalar-only ops. - kUpb_DecodeOp_Scalar1Byte = 0, - kUpb_DecodeOp_Scalar4Byte = 2, - kUpb_DecodeOp_Scalar8Byte = 3, - kUpb_DecodeOp_Enum = 1, +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o) { + return o->opts; +} - // Scalar/repeated ops. - kUpb_DecodeOp_String = 4, - kUpb_DecodeOp_Bytes = 5, - kUpb_DecodeOp_SubMessage = 6, +bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { + return o->opts != (void*)kUpbDefOptDefault; +} - // Repeated-only ops (also see macros below). - kUpb_DecodeOp_PackedEnum = 13, -}; +const char* upb_OneofDef_FullName(const upb_OneofDef* o) { + return o->full_name; +} -// For packed fields it is helpful to be able to recover the lg2 of the data -// size from the 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] */ +const char* upb_OneofDef_Name(const upb_OneofDef* o) { + return _upb_DefBuilder_FullToShort(o->full_name); +} -typedef union { - bool bool_val; - uint32_t uint32_val; - uint64_t uint64_val; - uint32_t size; -} wireval; +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { + return o->parent; +} -static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable* layout); +int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } -UPB_NORETURN static void* _upb_Decoder_ErrorJmp(upb_Decoder* d, - upb_DecodeStatus status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; } -const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); - return NULL; -} -static void _upb_Decoder_VerifyUtf8(upb_Decoder* d, const char* buf, int len) { - if (!_upb_Decoder_VerifyUtf8Inline(buf, len)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); - } -} +int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } -static bool _upb_Decoder_Reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { - bool need_realloc = arr->capacity - arr->size < elem; - if (need_realloc && !_upb_array_realloc(arr, arr->size + elem, &d->arena)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - } - return need_realloc; +uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { + // Compute index in our parent's array. + return o - upb_MessageDef_Oneof(o->parent, 0); } -typedef struct { - const char* ptr; - uint64_t val; -} _upb_DecodeLongVarintReturn; +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } -UPB_NOINLINE -static _upb_DecodeLongVarintReturn _upb_Decoder_DecodeLongVarint( - const char* ptr, uint64_t val) { - _upb_DecodeLongVarintReturn 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; +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, size, &val) + ? upb_value_getptr(val) + : NULL; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeVarint(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 { - _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); - if (!res.ptr) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - *val = res.val; - return res.ptr; - } +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name) { + return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeTag(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; - _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); - if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } - *val = res.val; - return res.ptr; - } +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_FORCEINLINE -static const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, - uint32_t* size) { - uint64_t size64; - ptr = _upb_Decoder_DecodeVarint(d, ptr, &size64); - if (size64 >= INT32_MAX || ptr - d->end + (int)size64 > d->limit) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } - *size = size64; - return ptr; -} +bool _upb_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, + const char* name, size_t size, upb_Arena* a) { + o->field_count++; + if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = true; -static void _upb_Decoder_MungeInt32(wireval* val) { - if (!_upb_IsLittleEndian()) { - /* The next stage will memcpy(dst, &val, 4) */ - val->uint32_val = val->uint64_val; - } + const int number = upb_FieldDef_Number(f); + const upb_value v = upb_value_constptr(f); + return upb_inttable_insert(&o->itof, number, v, a) && + upb_strtable_insert(&o->ntof, name, size, v, a); } -static void _upb_Decoder_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; +// Returns the synthetic count. +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { + int synthetic_count = 0; + + for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { + upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); + + if (o->synthetic && o->field_count != 1) { + _upb_DefBuilder_Errf(ctx, + "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_OneofDef_Name(o)); } - case kUpb_FieldType_Int32: - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Enum: - _upb_Decoder_MungeInt32(val); - break; + + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + _upb_DefBuilder_Errf( + ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_OneofDef_Name(o)); + } + + o->fields = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); + o->field_count = 0; } -} -static upb_Message* _upb_Decoder_NewSubMessage( - upb_Decoder* d, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - UPB_ASSERT(subl); - upb_Message* msg = _upb_Message_New(subl, &d->arena); - if (!msg) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - return msg; -} + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); + if (o) { + o->fields[o->field_count++] = f; + } + } -UPB_NOINLINE -const char* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, - int overrun) { - int status; - ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); - if (ptr == NULL) _upb_Decoder_ErrorJmp(d, status); - return ptr; + return synthetic_count; } -static const char* _upb_Decoder_ReadString(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) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - memcpy(data, ptr, size); - str->data = data; +static void create_oneofdef(upb_DefBuilder* 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); + + o->parent = m; + o->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); + o->field_count = 0; + o->synthetic = false; + + UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + + if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); } - str->size = size; - return ptr + size; + + upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); + bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_inttable_init(&o->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&o->ntof, 4, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -UPB_FORCEINLINE -static const char* _upb_Decoder_RecurseSubMessage(upb_Decoder* d, - const char* ptr, - upb_Message* submsg, - const upb_MiniTable* subl, - uint32_t expected_end_group) { - if (--d->depth < 0) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); - } - ptr = _upb_Decoder_DecodeMessage(d, ptr, submsg, subl); - d->depth++; - if (d->end_group != expected_end_group) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +// Allocate and initialize an array of |n| oneof defs. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m) { + _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); + + upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); + for (int i = 0; i < n; i++) { + create_oneofdef(ctx, m, protos[i], &o[i]); } - return ptr; + return o; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeSubMessage( - upb_Decoder* d, const char* ptr, upb_Message* submsg, - const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, int size) { - int saved_delta = _upb_Decoder_PushLimit(d, ptr, size); - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - UPB_ASSERT(subl); - ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, DECODE_NOGROUP); - _upb_Decoder_PopLimit(d, ptr, saved_delta); - return ptr; + +// Must be last. + +struct upb_ServiceDef { + const google_protobuf_ServiceOptions* opts; + const upb_FileDef* file; + const char* full_name; + upb_MethodDef* methods; + int method_count; + int index; +}; + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { + return (upb_ServiceDef*)&s[index]; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeGroup(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable* subl, - uint32_t number) { - if (_upb_Decoder_IsDone(d, &ptr)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } - ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, number); - d->end_group = DECODE_NOGROUP; - return ptr; +const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { + return s->opts; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeUnknownGroup(upb_Decoder* d, - const char* ptr, - uint32_t number) { - return _upb_Decoder_DecodeGroup(d, ptr, NULL, NULL, number); +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { + return s->opts != (void*)kUpbDefOptDefault; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeKnownGroup( - 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; - UPB_ASSERT(subl); - return _upb_Decoder_DecodeGroup(d, ptr, submsg, subl, field->number); +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { + return s->full_name; } -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 char* upb_ServiceDef_Name(const upb_ServiceDef* s) { + return _upb_DefBuilder_FullToShort(s->full_name); } -static void _upb_Decoder_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); +int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } - if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - } +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { + return s->file; } -UPB_NOINLINE -static bool _upb_Decoder_CheckEnumSlow(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, - uint32_t v) { - if (_upb_MiniTable_CheckEnumValueSlow(e, v)) return true; - - // 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_Decoder_AddUnknownVarints(d, unknown_msg, tag, v); - return false; +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { + return s->method_count; } -UPB_FORCEINLINE -static bool _upb_Decoder_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; +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { + return (i < 0 || i >= s->method_count) ? NULL + : _upb_MethodDef_At(s->methods, i); +} - _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, v); - if (UPB_LIKELY(status == _kUpb_FastEnumCheck_ValueIsInEnum)) return true; - return _upb_Decoder_CheckEnumSlow(d, ptr, msg, e, field, v); +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name) { + for (int i = 0; i < s->method_count; i++) { + const upb_MethodDef* m = _upb_MethodDef_At(s->methods, i); + if (strcmp(name, upb_MethodDef_Name(m)) == 0) { + return m; + } + } + return NULL; } -UPB_NOINLINE -static const char* _upb_Decoder_DecodeEnumArray( - 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 (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, val)) return ptr; - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); - arr->size++; - memcpy(mem, val, 4); - return ptr; +static void create_service(upb_DefBuilder* ctx, + const google_protobuf_ServiceDescriptorProto* svc_proto, + upb_ServiceDef* s) { + upb_StringView name; + size_t n; + + // Must happen before _upb_DefBuilder_Add() + s->file = _upb_DefBuilder_File(ctx); + + name = google_protobuf_ServiceDescriptorProto_name(svc_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + const char* package = _upb_FileDef_RawPackage(s->file); + s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); + _upb_DefBuilder_Add(ctx, s->full_name, + _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + + const google_protobuf_MethodDescriptorProto* const* methods = + google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); + s->method_count = n; + s->methods = _upb_MethodDefs_New(ctx, n, methods, s); + + UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeFixedPacked( - 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. - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } - _upb_Decoder_Reserve(d, arr, count); - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); - arr->size += 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_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos) { + _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); + + upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); + for (int i = 0; i < n; i++) { + create_service(ctx, protos[i], &s[i]); + s[i].index = i; } + return s; +} - return ptr; + +#include + + +// Must be last. + +// A few fake field types for our tables. +enum { + kUpb_FakeFieldType_FieldNotFound = 0, + kUpb_FakeFieldType_MessageSetItem = 19, +}; + +// DecodeOp: an action to be performed for a wire-type/field-type combination. +enum { + // Special ops: we don't write data to regular fields for these. + kUpb_DecodeOp_UnknownField = -1, + kUpb_DecodeOp_MessageSetItem = -2, + + // Scalar-only ops. + kUpb_DecodeOp_Scalar1Byte = 0, + kUpb_DecodeOp_Scalar4Byte = 2, + kUpb_DecodeOp_Scalar8Byte = 3, + kUpb_DecodeOp_Enum = 1, + + // Scalar/repeated ops. + kUpb_DecodeOp_String = 4, + kUpb_DecodeOp_Bytes = 5, + kUpb_DecodeOp_SubMessage = 6, + + // Repeated-only ops (also see macros below). + kUpb_DecodeOp_PackedEnum = 13, +}; + +// For packed fields it is helpful to be able to recover the lg2 of the data +// size from the 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] */ + +typedef union { + bool bool_val; + uint32_t uint32_val; + uint64_t uint64_val; + uint32_t size; +} wireval; + +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout); + +UPB_NORETURN static void* _upb_Decoder_ErrorJmp(upb_Decoder* d, + upb_DecodeStatus status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeVarintPacked( - 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 = _upb_Decoder_PushLimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); - while (!_upb_Decoder_IsDone(d, &ptr)) { - wireval elem; - ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); - _upb_Decoder_Munge(field->descriptortype, &elem); - if (_upb_Decoder_Reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); - } - arr->size++; - memcpy(out, &elem, scale); - out += scale; +const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); + return NULL; +} +static void _upb_Decoder_VerifyUtf8(upb_Decoder* d, const char* buf, int len) { + if (!_upb_Decoder_VerifyUtf8Inline(buf, len)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); } - _upb_Decoder_PopLimit(d, ptr, saved_limit); - return ptr; } -UPB_NOINLINE -static const char* _upb_Decoder_DecodeEnumPacked( - 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 = _upb_Decoder_PushLimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); - while (!_upb_Decoder_IsDone(d, &ptr)) { - wireval elem; - ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); - _upb_Decoder_MungeInt32(&elem); - if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, &elem)) { - continue; - } - if (_upb_Decoder_Reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); - } - arr->size++; - memcpy(out, &elem, 4); - out += 4; +static bool _upb_Decoder_Reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { + bool need_realloc = arr->capacity - arr->size < elem; + if (need_realloc && !_upb_array_realloc(arr, arr->size + elem, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } - _upb_Decoder_PopLimit(d, ptr, saved_limit); - return ptr; + return need_realloc; } -upb_Array* _upb_Decoder_CreateArray(upb_Decoder* d, - const upb_MiniTable_Field* field) { - /* Maps descriptor type -> elem_size_lg2. */ - static const uint8_t kElemSizeLg2[] = { - [0] = -1, // invalid descriptor type - [kUpb_FieldType_Double] = 3, - [kUpb_FieldType_Float] = 2, - [kUpb_FieldType_Int64] = 3, - [kUpb_FieldType_UInt64] = 3, - [kUpb_FieldType_Int32] = 2, - [kUpb_FieldType_Fixed64] = 3, - [kUpb_FieldType_Fixed32] = 2, - [kUpb_FieldType_Bool] = 0, - [kUpb_FieldType_String] = UPB_SIZE(3, 4), - [kUpb_FieldType_Group] = UPB_SIZE(2, 3), - [kUpb_FieldType_Message] = UPB_SIZE(2, 3), - [kUpb_FieldType_Bytes] = UPB_SIZE(3, 4), - [kUpb_FieldType_UInt32] = 2, - [kUpb_FieldType_Enum] = 2, - [kUpb_FieldType_SFixed32] = 2, - [kUpb_FieldType_SFixed64] = 3, - [kUpb_FieldType_SInt32] = 2, - [kUpb_FieldType_SInt64] = 3, - }; +typedef struct { + const char* ptr; + uint64_t val; +} _upb_DecodeLongVarintReturn; - size_t lg2 = kElemSizeLg2[field->descriptortype]; - upb_Array* ret = _upb_Array_New(&d->arena, 4, lg2); - if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); +UPB_NOINLINE +static _upb_DecodeLongVarintReturn _upb_Decoder_DecodeLongVarint( + const char* ptr, uint64_t val) { + _upb_DecodeLongVarintReturn 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; } -static const char* _upb_Decoder_DecodeToArray(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; - - if (arr) { - _upb_Decoder_Reserve(d, arr, 1); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeVarint(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 { - arr = _upb_Decoder_CreateArray(d, field); - *arrp = arr; + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + *val = res.val; + return res.ptr; } +} - switch (op) { - case kUpb_DecodeOp_Scalar1Byte: - case kUpb_DecodeOp_Scalar4Byte: - case kUpb_DecodeOp_Scalar8Byte: - /* Append scalar value. */ - mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << op, void); - arr->size++; - memcpy(mem, val, 1 << op); - return ptr; - case kUpb_DecodeOp_String: - _upb_Decoder_VerifyUtf8(d, ptr, val->size); - /* Fallthrough. */ - case kUpb_DecodeOp_Bytes: { - /* Append bytes. */ - upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->size; - arr->size++; - return _upb_Decoder_ReadString(d, ptr, val->size, str); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeTag(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; + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } - case kUpb_DecodeOp_SubMessage: { - /* Append submessage / group. */ - upb_Message* submsg = _upb_Decoder_NewSubMessage(d, subs, field); - *UPB_PTR_AT(_upb_array_ptr(arr), arr->size * sizeof(void*), - upb_Message*) = submsg; - arr->size++; - if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { - return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); - } else { - return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, - val->size); - } - } - case OP_FIXPCK_LG2(2): - case OP_FIXPCK_LG2(3): - return _upb_Decoder_DecodeFixedPacked(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 _upb_Decoder_DecodeVarintPacked(d, ptr, arr, val, field, - op - OP_VARPCK_LG2(0)); - case kUpb_DecodeOp_Enum: - return _upb_Decoder_DecodeEnumArray(d, ptr, msg, arr, subs, field, val); - case kUpb_DecodeOp_PackedEnum: - return _upb_Decoder_DecodeEnumPacked(d, ptr, msg, arr, subs, field, val); - default: - UPB_UNREACHABLE(); + *val = res.val; + return res.ptr; } } -upb_Map* _upb_Decoder_CreateMap(upb_Decoder* d, const upb_MiniTable* entry) { - /* Maps descriptor type -> upb map size. */ - static const uint8_t kSizeInMap[] = { - [0] = -1, // invalid descriptor type */ - [kUpb_FieldType_Double] = 8, - [kUpb_FieldType_Float] = 4, - [kUpb_FieldType_Int64] = 8, - [kUpb_FieldType_UInt64] = 8, - [kUpb_FieldType_Int32] = 4, - [kUpb_FieldType_Fixed64] = 8, - [kUpb_FieldType_Fixed32] = 4, - [kUpb_FieldType_Bool] = 1, - [kUpb_FieldType_String] = UPB_MAPTYPE_STRING, - [kUpb_FieldType_Group] = sizeof(void*), - [kUpb_FieldType_Message] = sizeof(void*), - [kUpb_FieldType_Bytes] = UPB_MAPTYPE_STRING, - [kUpb_FieldType_UInt32] = 4, - [kUpb_FieldType_Enum] = 4, - [kUpb_FieldType_SFixed32] = 4, - [kUpb_FieldType_SFixed64] = 8, - [kUpb_FieldType_SInt32] = 4, - [kUpb_FieldType_SInt64] = 8, - }; - - const upb_MiniTable_Field* key_field = &entry->fields[0]; - const upb_MiniTable_Field* val_field = &entry->fields[1]; - char key_size = kSizeInMap[key_field->descriptortype]; - char val_size = kSizeInMap[val_field->descriptortype]; - UPB_ASSERT(key_field->offset == 0); - UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); - upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size); - if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - return ret; -} - -static const char* _upb_Decoder_DecodeToMap(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) { - map = _upb_Decoder_CreateMap(d, entry); - *map_p = map; - } - - /* 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 = _upb_Decoder_DecodeSubMessage(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_Decoder_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); - if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { - _upb_Decoder_ErrorJmp(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) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - } +UPB_FORCEINLINE +static const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, + uint32_t* size) { + uint64_t size64; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &size64); + if (size64 >= INT32_MAX || ptr - d->end + (int)size64 > d->limit) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } + *size = size64; return ptr; } -static const char* _upb_Decoder_DecodeToSubMessage( - 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 == kUpb_DecodeOp_Enum) && - !_upb_Decoder_CheckEnum(d, ptr, msg, subs[field->submsg_index].subenum, - field, val)) { - return ptr; - } - - /* 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 == kUpb_DecodeOp_SubMessage && *oneof_case != field->number) { - memset(mem, 0, sizeof(void*)); - } - *oneof_case = field->number; +static void _upb_Decoder_MungeInt32(wireval* val) { + if (!_upb_IsLittleEndian()) { + /* The next stage will memcpy(dst, &val, 4) */ + val->uint32_val = val->uint64_val; } +} - /* Store into message. */ - switch (op) { - case kUpb_DecodeOp_SubMessage: { - upb_Message** submsgp = mem; - upb_Message* submsg = *submsgp; - if (!submsg) { - submsg = _upb_Decoder_NewSubMessage(d, subs, field); - *submsgp = submsg; - } - if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { - ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); - } else { - ptr = _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, - val->size); - } +static void _upb_Decoder_Munge(int type, wireval* val) { + switch (type) { + case kUpb_FieldType_Bool: + val->bool_val = val->uint64_val != 0; break; - } - case kUpb_DecodeOp_String: - _upb_Decoder_VerifyUtf8(d, ptr, val->size); - /* Fallthrough. */ - case kUpb_DecodeOp_Bytes: - return _upb_Decoder_ReadString(d, ptr, val->size, mem); - case kUpb_DecodeOp_Scalar8Byte: - memcpy(mem, val, 8); + case kUpb_FieldType_SInt32: { + uint32_t n = val->uint64_val; + val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); break; - case kUpb_DecodeOp_Enum: - case kUpb_DecodeOp_Scalar4Byte: - memcpy(mem, val, 4); + } + case kUpb_FieldType_SInt64: { + uint64_t n = val->uint64_val; + val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); break; - case kUpb_DecodeOp_Scalar1Byte: - memcpy(mem, val, 1); + } + case kUpb_FieldType_Int32: + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Enum: + _upb_Decoder_MungeInt32(val); break; - default: - UPB_UNREACHABLE(); } +} - return ptr; +static upb_Message* _upb_Decoder_NewSubMessage( + upb_Decoder* d, const upb_MiniTableSub* subs, + const upb_MiniTableField* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + UPB_ASSERT(subl); + upb_Message* msg = _upb_Message_New(subl, &d->arena); + if (!msg) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return msg; } UPB_NOINLINE -const char* _upb_Decoder_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; +const char* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, + int overrun) { + int status; + ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); + if (ptr == NULL) _upb_Decoder_ErrorJmp(d, status); + return ptr; +} + +static const char* _upb_Decoder_ReadString(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) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + memcpy(data, ptr, size); + str->data = data; } - 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; + str->size = size; + return ptr + size; +} + +UPB_FORCEINLINE +static const char* _upb_Decoder_RecurseSubMessage(upb_Decoder* d, + const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t expected_end_group) { + if (--d->depth < 0) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); + } + ptr = _upb_Decoder_DecodeMessage(d, ptr, submsg, subl); + d->depth++; + if (d->end_group != expected_end_group) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } return ptr; } UPB_FORCEINLINE -static bool _upb_Decoder_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 = _upb_FastDecoder_LoadTag(*ptr); - intptr_t table = decode_totable(layout); - *ptr = _upb_FastDecoder_TagDispatch(d, *ptr, msg, table, 0, tag); - return true; +static const char* _upb_Decoder_DecodeSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* submsg, + const upb_MiniTableSub* subs, const upb_MiniTableField* field, int size) { + int saved_delta = _upb_Decoder_PushLimit(d, ptr, size); + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + UPB_ASSERT(subl); + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, DECODE_NOGROUP); + _upb_Decoder_PopLimit(d, ptr, saved_delta); + return ptr; +} + +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeGroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t number) { + if (_upb_Decoder_IsDone(d, &ptr)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } -#endif - return false; + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, number); + d->end_group = DECODE_NOGROUP; + return ptr; } -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 _upb_Decoder_DecodeVarint(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 _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); - default: - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeUnknownGroup(upb_Decoder* d, + const char* ptr, + uint32_t number) { + return _upb_Decoder_DecodeGroup(d, ptr, NULL, NULL, number); } -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), -}; - -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)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - } - upb_Message* submsg = - _upb_Decoder_NewSubMessage(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) _upb_Decoder_ErrorJmp(d, status); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeKnownGroup( + upb_Decoder* d, const char* ptr, upb_Message* submsg, + const upb_MiniTableSub* subs, const upb_MiniTableField* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + UPB_ASSERT(subl); + return _upb_Decoder_DecodeGroup(d, ptr, submsg, subl, field->number); } -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; +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; +} - ptr = upb_Decoder_EncodeVarint32(kEndItemTag, ptr); - char* end = ptr; +static void _upb_Decoder_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, split - buf, &d->arena) || - !_upb_Message_AddUnknown(msg, message_data, message_size, &d->arena) || - !_upb_Message_AddUnknown(msg, split, end - split, &d->arena)) { + if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } } -static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, - const upb_MiniTable* t, - uint32_t type_id, const char* data, - uint32_t size) { - const upb_MiniTable_Extension* item_mt = - upb_ExtensionRegistry_Lookup(d->extreg, t, type_id); - if (item_mt) { - upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); - } else { - upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); - } -} +UPB_NOINLINE +static bool _upb_Decoder_CheckEnumSlow(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTableEnum* e, + const upb_MiniTableField* field, + uint32_t v) { + if (_upb_MiniTable_CheckEnumValueSlow(e, v)) return true; -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 (!_upb_Decoder_IsDone(d, &ptr)) { - uint32_t tag; - ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); - switch (tag) { - case kEndItemTag: - return ptr; - case kTypeIdTag: { - uint64_t tmp; - ptr = _upb_Decoder_DecodeVarint(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; - } - } - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + // 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_Decoder_AddUnknownVarints(d, unknown_msg, tag, v); + return false; } -static const upb_MiniTable_Field* _upb_Decoder_FindField( - upb_Decoder* d, const upb_MiniTable* t, uint32_t field_number, - int* last_field_index) { - static upb_MiniTable_Field none = { - 0, 0, 0, 0, kUpb_FakeFieldType_FieldNotFound, 0}; - if (t == NULL) return &none; +UPB_FORCEINLINE +static bool _upb_Decoder_CheckEnum(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTableEnum* e, + const upb_MiniTableField* field, + wireval* val) { + uint32_t v = val->uint32_val; - size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX - if (idx < t->dense_below) { - /* Fastest case: index into dense fields. */ - goto found; - } + _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, v); + if (UPB_LIKELY(status == _kUpb_FastEnumCheck_ValueIsInEnum)) return true; + return _upb_Decoder_CheckEnumSlow(d, ptr, msg, e, field, v); +} - if (t->dense_below < t->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 < t->field_count; idx++) { - if (t->fields[idx].number == field_number) { - goto found; - } - } +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumArray(upb_Decoder* d, const char* ptr, + upb_Message* msg, + upb_Array* arr, + const upb_MiniTableSub* subs, + const upb_MiniTableField* field, + wireval* val) { + const upb_MiniTableEnum* e = subs[field->submsg_index].subenum; + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, val)) return ptr; + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + arr->size++; + memcpy(mem, val, 4); + return ptr; +} - for (idx = t->dense_below; idx < last; idx++) { - if (t->fields[idx].number == field_number) { - goto found; - } - } +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeFixedPacked( + upb_Decoder* d, const char* ptr, upb_Array* arr, wireval* val, + const upb_MiniTableField* 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. + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } - - if (d->extreg) { - switch (t->ext) { - case kUpb_ExtMode_Extendable: { - const upb_MiniTable_Extension* ext = - upb_ExtensionRegistry_Lookup(d->extreg, t, field_number); - if (ext) return &ext->field; - break; + _upb_Decoder_Reserve(d, arr, count); + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + arr->size += 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)); } - case kUpb_ExtMode_IsMessageSet: - if (field_number == _UPB_MSGSET_ITEM) { - static upb_MiniTable_Field item = { - 0, 0, 0, 0, kUpb_FakeFieldType_MessageSetItem, 0}; - return &item; - } - break; + ptr += 1 << lg2; + dst += 1 << lg2; } } - return &none; /* Unknown field. */ - -found: - UPB_ASSERT(t->fields[idx].number == field_number); - *last_field_index = idx; - return &t->fields[idx]; + return ptr; } -int _upb_Decoder_GetVarintOp(const upb_MiniTable_Field* field) { - static const int8_t kVarintOps[] = { - [kUpb_FakeFieldType_FieldNotFound] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Int64] = kUpb_DecodeOp_Scalar8Byte, - [kUpb_FieldType_UInt64] = kUpb_DecodeOp_Scalar8Byte, - [kUpb_FieldType_Int32] = kUpb_DecodeOp_Scalar4Byte, - [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Bool] = kUpb_DecodeOp_Scalar1Byte, - [kUpb_FieldType_String] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Message] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Bytes] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_UInt32] = kUpb_DecodeOp_Scalar4Byte, - [kUpb_FieldType_Enum] = kUpb_DecodeOp_Enum, - [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SInt32] = kUpb_DecodeOp_Scalar4Byte, - [kUpb_FieldType_SInt64] = kUpb_DecodeOp_Scalar8Byte, - [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, - }; - - return kVarintOps[field->descriptortype]; +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeVarintPacked( + upb_Decoder* d, const char* ptr, upb_Array* arr, wireval* val, + const upb_MiniTableField* field, int lg2) { + int scale = 1 << lg2; + int saved_limit = _upb_Decoder_PushLimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_Munge(field->descriptortype, &elem); + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + } + arr->size++; + memcpy(out, &elem, scale); + out += scale; + } + _upb_Decoder_PopLimit(d, ptr, saved_limit); + return ptr; } -int _upb_Decoder_GetDelimitedOp(const upb_MiniTable* mt, - const upb_MiniTable_Field* field) { - enum { kRepeatedBase = 19 }; - - static const int8_t kDelimitedOps[] = { - /* For non-repeated field type. */ - [kUpb_FakeFieldType_FieldNotFound] = - kUpb_DecodeOp_UnknownField, // Field not found. - [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Int64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_UInt64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Int32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Bool] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_String] = kUpb_DecodeOp_String, - [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, - [kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, - [kUpb_FieldType_UInt32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Enum] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SInt32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SInt64] = kUpb_DecodeOp_UnknownField, - [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, - // For repeated field type. */ - [kRepeatedBase + kUpb_FieldType_Double] = OP_FIXPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_Float] = OP_FIXPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_Int64] = OP_VARPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_UInt64] = OP_VARPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_Int32] = OP_VARPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_Fixed64] = OP_FIXPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_Fixed32] = OP_FIXPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_Bool] = OP_VARPCK_LG2(0), - [kRepeatedBase + kUpb_FieldType_String] = kUpb_DecodeOp_String, - [kRepeatedBase + kUpb_FieldType_Group] = kUpb_DecodeOp_SubMessage, - [kRepeatedBase + kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, - [kRepeatedBase + kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, - [kRepeatedBase + kUpb_FieldType_UInt32] = OP_VARPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_Enum] = kUpb_DecodeOp_PackedEnum, - [kRepeatedBase + kUpb_FieldType_SFixed32] = OP_FIXPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_SFixed64] = OP_FIXPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_SInt32] = OP_VARPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_SInt64] = OP_VARPCK_LG2(3), - // Omitting kUpb_FakeFieldType_MessageSetItem, because we never emit a - // repeated msgset type - }; - - int ndx = field->descriptortype; - if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += kRepeatedBase; - int op = kDelimitedOps[ndx]; - - // If sub-message is not linked, treat as unknown. - if (op == kUpb_DecodeOp_SubMessage && - !(field->mode & kUpb_LabelFlags_IsExtension)) { - const upb_MiniTable_Sub* sub = &mt->subs[field->submsg_index]; - if (!sub->submsg) { - op = kUpb_DecodeOp_UnknownField; +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumPacked( + upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, + const upb_MiniTableSub* subs, const upb_MiniTableField* field, + wireval* val) { + const upb_MiniTableEnum* e = subs[field->submsg_index].subenum; + int saved_limit = _upb_Decoder_PushLimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_MungeInt32(&elem); + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, &elem)) { + continue; } + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + } + arr->size++; + memcpy(out, &elem, 4); + out += 4; } + _upb_Decoder_PopLimit(d, ptr, saved_limit); + return ptr; +} - return op; +upb_Array* _upb_Decoder_CreateArray(upb_Decoder* d, + const upb_MiniTableField* field) { + /* Maps descriptor type -> elem_size_lg2. */ + static const uint8_t kElemSizeLg2[] = { + [0] = -1, // invalid descriptor type + [kUpb_FieldType_Double] = 3, + [kUpb_FieldType_Float] = 2, + [kUpb_FieldType_Int64] = 3, + [kUpb_FieldType_UInt64] = 3, + [kUpb_FieldType_Int32] = 2, + [kUpb_FieldType_Fixed64] = 3, + [kUpb_FieldType_Fixed32] = 2, + [kUpb_FieldType_Bool] = 0, + [kUpb_FieldType_String] = UPB_SIZE(3, 4), + [kUpb_FieldType_Group] = UPB_SIZE(2, 3), + [kUpb_FieldType_Message] = UPB_SIZE(2, 3), + [kUpb_FieldType_Bytes] = UPB_SIZE(3, 4), + [kUpb_FieldType_UInt32] = 2, + [kUpb_FieldType_Enum] = 2, + [kUpb_FieldType_SFixed32] = 2, + [kUpb_FieldType_SFixed64] = 3, + [kUpb_FieldType_SInt32] = 2, + [kUpb_FieldType_SInt64] = 3, + }; + + size_t lg2 = kElemSizeLg2[field->descriptortype]; + upb_Array* ret = _upb_Array_New(&d->arena, 4, lg2); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeWireValue( - upb_Decoder* d, const char* ptr, const upb_MiniTable* mt, - const upb_MiniTable_Field* field, int wire_type, wireval* val, int* op) { - static const unsigned kFixed32OkMask = (1 << kUpb_FieldType_Float) | - (1 << kUpb_FieldType_Fixed32) | - (1 << kUpb_FieldType_SFixed32); +static const char* _upb_Decoder_DecodeToArray(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTableSub* subs, + const upb_MiniTableField* field, + wireval* val, int op) { + upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); + upb_Array* arr = *arrp; + void* mem; - static const unsigned kFixed64OkMask = (1 << kUpb_FieldType_Double) | - (1 << kUpb_FieldType_Fixed64) | - (1 << kUpb_FieldType_SFixed64); + if (arr) { + _upb_Decoder_Reserve(d, arr, 1); + } else { + arr = _upb_Decoder_CreateArray(d, field); + *arrp = arr; + } - switch (wire_type) { - case kUpb_WireType_Varint: - ptr = _upb_Decoder_DecodeVarint(d, ptr, &val->uint64_val); - *op = _upb_Decoder_GetVarintOp(field); - _upb_Decoder_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 = kUpb_DecodeOp_Scalar4Byte; - if (((1 << field->descriptortype) & kFixed32OkMask) == 0) { - *op = kUpb_DecodeOp_UnknownField; - } - return ptr + 4; - case kUpb_WireType_64Bit: - memcpy(&val->uint64_val, ptr, 8); - val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); - *op = kUpb_DecodeOp_Scalar8Byte; - if (((1 << field->descriptortype) & kFixed64OkMask) == 0) { - *op = kUpb_DecodeOp_UnknownField; - } - return ptr + 8; - case kUpb_WireType_Delimited: - ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); - *op = _upb_Decoder_GetDelimitedOp(mt, field); + switch (op) { + case kUpb_DecodeOp_Scalar1Byte: + case kUpb_DecodeOp_Scalar4Byte: + case kUpb_DecodeOp_Scalar8Byte: + /* Append scalar value. */ + mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << op, void); + arr->size++; + memcpy(mem, val, 1 << op); return ptr; - case kUpb_WireType_StartGroup: - val->uint32_val = field->number; - if (field->descriptortype == kUpb_FieldType_Group) { - *op = kUpb_DecodeOp_SubMessage; - } else if (field->descriptortype == kUpb_FakeFieldType_MessageSetItem) { - *op = kUpb_DecodeOp_MessageSetItem; + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: { + /* Append bytes. */ + upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->size; + arr->size++; + return _upb_Decoder_ReadString(d, ptr, val->size, str); + } + case kUpb_DecodeOp_SubMessage: { + /* Append submessage / group. */ + upb_Message* submsg = _upb_Decoder_NewSubMessage(d, subs, field); + *UPB_PTR_AT(_upb_array_ptr(arr), arr->size * sizeof(void*), + upb_Message*) = submsg; + arr->size++; + if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { + return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); } else { - *op = kUpb_DecodeOp_UnknownField; + return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); } - return ptr; + } + case OP_FIXPCK_LG2(2): + case OP_FIXPCK_LG2(3): + return _upb_Decoder_DecodeFixedPacked(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 _upb_Decoder_DecodeVarintPacked(d, ptr, arr, val, field, + op - OP_VARPCK_LG2(0)); + case kUpb_DecodeOp_Enum: + return _upb_Decoder_DecodeEnumArray(d, ptr, msg, arr, subs, field, val); + case kUpb_DecodeOp_PackedEnum: + return _upb_Decoder_DecodeEnumPacked(d, ptr, msg, arr, subs, field, val); default: - break; + UPB_UNREACHABLE(); } - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeKnownField( - 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)) { - _upb_Decoder_ErrorJmp(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 _upb_Decoder_DecodeToArray(d, ptr, msg, subs, field, val, op); - case kUpb_FieldMode_Map: - return _upb_Decoder_DecodeToMap(d, ptr, msg, subs, field, val); - case kUpb_FieldMode_Scalar: - return _upb_Decoder_DecodeToSubMessage(d, ptr, msg, subs, field, val, op); - default: - UPB_UNREACHABLE(); - } -} +upb_Map* _upb_Decoder_CreateMap(upb_Decoder* d, const upb_MiniTable* entry) { + /* Maps descriptor type -> upb map size. */ + static const uint8_t kSizeInMap[] = { + [0] = -1, // invalid descriptor type */ + [kUpb_FieldType_Double] = 8, + [kUpb_FieldType_Float] = 4, + [kUpb_FieldType_Int64] = 8, + [kUpb_FieldType_UInt64] = 8, + [kUpb_FieldType_Int32] = 4, + [kUpb_FieldType_Fixed64] = 8, + [kUpb_FieldType_Fixed32] = 4, + [kUpb_FieldType_Bool] = 1, + [kUpb_FieldType_String] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_Group] = sizeof(void*), + [kUpb_FieldType_Message] = sizeof(void*), + [kUpb_FieldType_Bytes] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_UInt32] = 4, + [kUpb_FieldType_Enum] = 4, + [kUpb_FieldType_SFixed32] = 4, + [kUpb_FieldType_SFixed64] = 8, + [kUpb_FieldType_SInt32] = 4, + [kUpb_FieldType_SInt64] = 8, + }; -static const char* _upb_Decoder_ReverseSkipVarint(const char* ptr, - uint32_t val) { - uint32_t seen = 0; - do { - ptr--; - seen <<= 7; - seen |= *ptr & 0x7f; - } while (seen != val); - return ptr; + const upb_MiniTableField* key_field = &entry->fields[0]; + const upb_MiniTableField* val_field = &entry->fields[1]; + char key_size = kSizeInMap[key_field->descriptortype]; + char val_size = kSizeInMap[val_field->descriptortype]; + UPB_ASSERT(key_field->offset == 0); + UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); + upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; } -static const char* _upb_Decoder_DecodeUnknownField(upb_Decoder* d, - const char* ptr, - upb_Message* msg, - int field_number, - int wire_type, wireval val) { - if (field_number == 0) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +static const char* _upb_Decoder_DecodeToMap(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTableSub* subs, + const upb_MiniTableField* 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; - // 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; + if (!map) { + map = _upb_Decoder_CreateMap(d, entry); + *map_p = map; + } - 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; - } + /* Parse map entry. */ + memset(&ent, 0, sizeof(ent)); - assert(start == d->debug_valstart); - uint32_t tag = ((uint32_t)field_number << 3) | wire_type; - start = _upb_Decoder_ReverseSkipVarint(start, tag); - assert(start == d->debug_tagstart); + 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)); + } - if (wire_type == kUpb_WireType_StartGroup) { - d->unknown = start; - d->unknown_msg = msg; - ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); - start = d->unknown; - d->unknown = NULL; - } + const char* start = ptr; + ptr = _upb_Decoder_DecodeSubMessage(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_Decoder_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } - } else if (wire_type == kUpb_WireType_StartGroup) { - ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + } else { + if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, + &d->arena) == kUpb_MapInsertStatus_OutOfMemory) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } + return ptr; +} + +static const char* _upb_Decoder_DecodeToSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTableSub* subs, const upb_MiniTableField* field, wireval* val, + int op) { + void* mem = UPB_PTR_AT(msg, field->offset, void); + int type = field->descriptortype; + + if (UPB_UNLIKELY(op == kUpb_DecodeOp_Enum) && + !_upb_Decoder_CheckEnum(d, ptr, msg, subs[field->submsg_index].subenum, + field, val)) { + return ptr; + } + + /* 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 == kUpb_DecodeOp_SubMessage && *oneof_case != field->number) { + memset(mem, 0, sizeof(void*)); + } + *oneof_case = field->number; + } + + /* Store into message. */ + switch (op) { + case kUpb_DecodeOp_SubMessage: { + upb_Message** submsgp = mem; + upb_Message* submsg = *submsgp; + if (!submsg) { + submsg = _upb_Decoder_NewSubMessage(d, subs, field); + *submsgp = submsg; + } + if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { + ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); + } else { + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); + } + break; + } + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: + return _upb_Decoder_ReadString(d, ptr, val->size, mem); + case kUpb_DecodeOp_Scalar8Byte: + memcpy(mem, val, 8); + break; + case kUpb_DecodeOp_Enum: + case kUpb_DecodeOp_Scalar4Byte: + memcpy(mem, val, 4); + break; + case kUpb_DecodeOp_Scalar1Byte: + memcpy(mem, val, 1); + break; + default: + UPB_UNREACHABLE(); } + return ptr; } UPB_NOINLINE -static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable* layout) { - int last_field_index = 0; +const char* _upb_Decoder_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 _upb_Decoder_TryFastDispatch(upb_Decoder* d, const char** ptr, + upb_Message* msg, + const upb_MiniTable* layout) { #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 (!_upb_Decoder_IsDone(d, &ptr)) goto nofast; + if (layout && layout->table_mask != (unsigned char)-1) { + uint16_t tag = _upb_FastDecoder_LoadTag(*ptr); + intptr_t table = decode_totable(layout); + *ptr = _upb_FastDecoder_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 _upb_Decoder_DecodeVarint(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 _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + default: + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } +} + +enum { + kStartItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_StartGroup), + kEndItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_EndGroup), + kTypeIdTag = ((kUpb_MsgSet_TypeId << 3) | kUpb_WireType_Varint), + kMessageTag = ((kUpb_MsgSet_Message << 3) | kUpb_WireType_Delimited), +}; + +static void upb_Decoder_AddKnownMessageSetItem( + upb_Decoder* d, upb_Message* msg, const upb_MiniTableExtension* item_mt, + const char* data, uint32_t size) { + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, item_mt, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + upb_Message* submsg = + _upb_Decoder_NewSubMessage(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) _upb_Decoder_ErrorJmp(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)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } +} + +static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, + const upb_MiniTable* t, + uint32_t type_id, const char* data, + uint32_t size) { + const upb_MiniTableExtension* item_mt = + upb_ExtensionRegistry_Lookup(d->extreg, t, type_id); + if (item_mt) { + upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); + } else { + upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); + } +} + +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 (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + switch (tag) { + case kEndItemTag: + return ptr; + case kTypeIdTag: { + uint64_t tmp; + ptr = _upb_Decoder_DecodeVarint(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; + } + } + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +} + +static const upb_MiniTableField* _upb_Decoder_FindField(upb_Decoder* d, + const upb_MiniTable* t, + uint32_t field_number, + int* last_field_index) { + static upb_MiniTableField none = { + 0, 0, 0, 0, kUpb_FakeFieldType_FieldNotFound, 0}; + if (t == NULL) return &none; + + size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX + if (idx < t->dense_below) { + /* Fastest case: index into dense fields. */ + goto found; + } + + if (t->dense_below < t->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 < t->field_count; idx++) { + if (t->fields[idx].number == field_number) { + goto found; + } + } + + for (idx = t->dense_below; idx < last; idx++) { + if (t->fields[idx].number == field_number) { + goto found; + } + } + } + + if (d->extreg) { + switch (t->ext) { + case kUpb_ExtMode_Extendable: { + const upb_MiniTableExtension* ext = + upb_ExtensionRegistry_Lookup(d->extreg, t, field_number); + if (ext) return &ext->field; + break; + } + case kUpb_ExtMode_IsMessageSet: + if (field_number == kUpb_MsgSet_Item) { + static upb_MiniTableField item = { + 0, 0, 0, 0, kUpb_FakeFieldType_MessageSetItem, 0}; + return &item; + } + break; + } + } + + return &none; /* Unknown field. */ + +found: + UPB_ASSERT(t->fields[idx].number == field_number); + *last_field_index = idx; + return &t->fields[idx]; +} + +int _upb_Decoder_GetVarintOp(const upb_MiniTableField* field) { + static const int8_t kVarintOps[] = { + [kUpb_FakeFieldType_FieldNotFound] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_Scalar1Byte, + [kUpb_FieldType_String] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_Enum, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + }; + + return kVarintOps[field->descriptortype]; +} + +int _upb_Decoder_GetDelimitedOp(const upb_MiniTable* mt, + const upb_MiniTableField* field) { + enum { kRepeatedBase = 19 }; + + static const int8_t kDelimitedOps[] = { + /* For non-repeated field type. */ + [kUpb_FakeFieldType_FieldNotFound] = + kUpb_DecodeOp_UnknownField, // Field not found. + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + // For repeated field type. */ + [kRepeatedBase + kUpb_FieldType_Double] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Float] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Int64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_UInt64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Int32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Fixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Fixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Bool] = OP_VARPCK_LG2(0), + [kRepeatedBase + kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kRepeatedBase + kUpb_FieldType_Group] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kRepeatedBase + kUpb_FieldType_UInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Enum] = kUpb_DecodeOp_PackedEnum, + [kRepeatedBase + kUpb_FieldType_SFixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SFixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_SInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SInt64] = OP_VARPCK_LG2(3), + // Omitting kUpb_FakeFieldType_MessageSetItem, because we never emit a + // repeated msgset type + }; + + int ndx = field->descriptortype; + if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += kRepeatedBase; + int op = kDelimitedOps[ndx]; + + // If sub-message is not linked, treat as unknown. + if (op == kUpb_DecodeOp_SubMessage && + !(field->mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTableSub* sub = &mt->subs[field->submsg_index]; + if (!sub->submsg) { + op = kUpb_DecodeOp_UnknownField; + } + } + + return op; +} + +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeWireValue(upb_Decoder* d, const char* ptr, + const upb_MiniTable* mt, + const upb_MiniTableField* field, + int wire_type, wireval* val, + int* op) { + static const unsigned kFixed32OkMask = (1 << kUpb_FieldType_Float) | + (1 << kUpb_FieldType_Fixed32) | + (1 << kUpb_FieldType_SFixed32); + + static const unsigned kFixed64OkMask = (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Fixed64) | + (1 << kUpb_FieldType_SFixed64); + + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = _upb_Decoder_DecodeVarint(d, ptr, &val->uint64_val); + *op = _upb_Decoder_GetVarintOp(field); + _upb_Decoder_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 = kUpb_DecodeOp_Scalar4Byte; + if (((1 << field->descriptortype) & kFixed32OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr + 4; + case kUpb_WireType_64Bit: + memcpy(&val->uint64_val, ptr, 8); + val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); + *op = kUpb_DecodeOp_Scalar8Byte; + if (((1 << field->descriptortype) & kFixed64OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr + 8; + case kUpb_WireType_Delimited: + ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); + *op = _upb_Decoder_GetDelimitedOp(mt, field); + return ptr; + case kUpb_WireType_StartGroup: + val->uint32_val = field->number; + if (field->descriptortype == kUpb_FieldType_Group) { + *op = kUpb_DecodeOp_SubMessage; + } else if (field->descriptortype == kUpb_FakeFieldType_MessageSetItem) { + *op = kUpb_DecodeOp_MessageSetItem; + } else { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr; + default: + break; + } + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +} + +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeKnownField( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout, const upb_MiniTableField* field, int op, + wireval* val) { + const upb_MiniTableSub* subs = layout->subs; + uint8_t mode = field->mode; + + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTableExtension* ext_layout = + (const upb_MiniTableExtension*)field; + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, ext_layout, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(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 _upb_Decoder_DecodeToArray(d, ptr, msg, subs, field, val, op); + case kUpb_FieldMode_Map: + return _upb_Decoder_DecodeToMap(d, ptr, msg, subs, field, val); + case kUpb_FieldMode_Scalar: + return _upb_Decoder_DecodeToSubMessage(d, ptr, msg, subs, field, val, op); + default: + UPB_UNREACHABLE(); + } +} + +static const char* _upb_Decoder_ReverseSkipVarint(const char* ptr, + uint32_t val) { + uint32_t seen = 0; + do { + ptr--; + seen <<= 7; + seen |= *ptr & 0x7f; + } while (seen != val); + return ptr; +} + +static const char* _upb_Decoder_DecodeUnknownField(upb_Decoder* d, + const char* ptr, + upb_Message* msg, + int field_number, + int wire_type, wireval val) { + if (field_number == 0) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + + // 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; + + 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; + } + + assert(start == d->debug_valstart); + uint32_t tag = ((uint32_t)field_number << 3) | wire_type; + start = _upb_Decoder_ReverseSkipVarint(start, tag); + assert(start == d->debug_tagstart); + + if (wire_type == kUpb_WireType_StartGroup) { + d->unknown = start; + d->unknown_msg = msg; + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + start = d->unknown; + d->unknown = NULL; + } + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } else if (wire_type == kUpb_WireType_StartGroup) { + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + } + return ptr; +} + +UPB_NOINLINE +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout) { + int last_field_index = 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 (!_upb_Decoder_IsDone(d, &ptr)) goto nofast; +#endif + + while (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + const upb_MiniTableField* field; + int field_number; + int wire_type; + wireval val; + int op; + + if (_upb_Decoder_TryFastDispatch(d, &ptr, msg, layout)) break; + +#if UPB_FASTTABLE + nofast: +#endif + +#ifndef NDEBUG + d->debug_tagstart = ptr; +#endif + + UPB_ASSERT(ptr < d->limit_ptr); + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + field_number = tag >> 3; + wire_type = tag & 7; + +#ifndef NDEBUG + d->debug_valstart = ptr; +#endif + + if (wire_type == kUpb_WireType_EndGroup) { + d->end_group = field_number; + return ptr; + } + + field = _upb_Decoder_FindField(d, layout, field_number, &last_field_index); + ptr = _upb_Decoder_DecodeWireValue(d, ptr, layout, field, wire_type, &val, + &op); + + if (op >= 0) { + ptr = _upb_Decoder_DecodeKnownField(d, ptr, msg, layout, field, op, &val); + } else { + switch (op) { + case kUpb_DecodeOp_UnknownField: + ptr = _upb_Decoder_DecodeUnknownField(d, ptr, msg, field_number, + wire_type, val); + break; + case kUpb_DecodeOp_MessageSetItem: + ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); + break; + } + } + } + + return UPB_UNLIKELY(layout && layout->required_count) + ? _upb_Decoder_CheckRequired(d, ptr, msg, layout) + : ptr; +} + +const char* _upb_FastDecoder_DecodeGeneric(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 _upb_Decoder_DecodeMessage(d, ptr, msg, decode_totablep(table)); +} + +static upb_DecodeStatus _upb_Decoder_DecodeTop(struct upb_Decoder* d, + const char* buf, void* msg, + const upb_MiniTable* l) { + if (!_upb_Decoder_TryFastDispatch(d, &buf, msg, l)) { + _upb_Decoder_DecodeMessage(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_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 = _upb_Decoder_DecodeTop(&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; +} + +#undef OP_FIXPCK_LG2 +#undef OP_VARPCK_LG2 + +// 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 _upb_FastDecoder_DecodeGeneric(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 = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); + if (ptr == NULL) _upb_FastDecoder_ErrorJmp(d, status); + data = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_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) + ? _upb_Decoder_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 = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_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 = _upb_Decoder_PushLimit(d, ptr, len); + ptr = func(d, ptr, ctx); + _upb_Decoder_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->capacity; + 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->capacity = 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->size = + (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(!_upb_Decoder_IsDone(d, ptr))) { + ret.tag = _upb_FastDecoder_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->capacity * valbytes); + *data = _upb_FastDecoder_LoadTag(ptr); + return begin + (farr->arr->size * 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) _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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 (!_upb_Decoder_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)) { \ + _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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)) { \ + _upb_FastDecoder_ErrorJmp(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) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + } else { \ + _upb_Array_Resize(arr, elems, &d->arena); \ + } \ + \ + char* dst = _upb_array_ptr(arr); \ + memcpy(dst, ptr, size); \ + arr->size = 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 (!_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { + _upb_FastDecoder_ErrorJmp(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; \ + _upb_FastDecoder_ErrorJmp(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) { \ + _upb_FastDecoder_ErrorJmp(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 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + } \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_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); - while (!_upb_Decoder_IsDone(d, &ptr)) { - uint32_t tag; - const upb_MiniTable_Field* field; - int field_number; - int wire_type; - wireval val; - int op; +/* Generate all combinations: + * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ - if (_upb_Decoder_TryFastDispatch(d, &ptr, msg, layout)) break; +#define s_VALIDATE true +#define b_VALIDATE false -#if UPB_FASTTABLE - nofast: -#endif +#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); \ + } -#ifndef NDEBUG - d->debug_tagstart = ptr; -#endif +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) - UPB_ASSERT(ptr < d->limit_ptr); - ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); - field_number = tag >> 3; - wire_type = tag & 7; +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) -#ifndef NDEBUG - d->debug_valstart = ptr; -#endif +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) - if (wire_type == kUpb_WireType_EndGroup) { - d->end_group = field_number; - return ptr; - } +#undef s_VALIDATE +#undef b_VALIDATE +#undef F +#undef TAGBYTES +#undef FASTDECODE_LONGSTRING +#undef FASTDECODE_COPYSTRING +#undef FASTDECODE_STRING - field = _upb_Decoder_FindField(d, layout, field_number, &last_field_index); - ptr = _upb_Decoder_DecodeWireValue(d, ptr, layout, field, wire_type, &val, - &op); +/* message fields *************************************************************/ - if (op >= 0) { - ptr = _upb_Decoder_DecodeKnownField(d, ptr, msg, layout, field, op, &val); - } else { - switch (op) { - case kUpb_DecodeOp_UnknownField: - ptr = _upb_Decoder_DecodeUnknownField(d, ptr, msg, field_number, - wire_type, val); - break; - case kUpb_DecodeOp_MessageSetItem: - ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); - break; - } - } +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 UPB_UNLIKELY(layout && layout->required_count) - ? _upb_Decoder_CheckRequired(d, ptr, msg, layout) - : ptr; + return msg_data + sizeof(upb_Message_Internal); } -const char* _upb_FastDecoder_DecodeGeneric(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 _upb_Decoder_DecodeMessage(d, ptr, msg, decode_totablep(table)); -} +typedef struct { + intptr_t table; + upb_Message* msg; +} fastdecode_submsgdata; -static upb_DecodeStatus _upb_Decoder_DecodeTop(struct upb_Decoder* d, - const char* buf, void* msg, - const upb_MiniTable* l) { - if (!_upb_Decoder_TryFastDispatch(d, &buf, msg, l)) { - _upb_Decoder_DecodeMessage(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_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; } -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; +#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) { \ + _upb_FastDecoder_ErrorJmp(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)) { \ + _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + d->depth++; \ + return ptr; \ + } \ + } \ + \ + d->depth++; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - 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; +#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); \ } - 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; +#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) - upb_DecodeStatus status = UPB_SETJMP(state.err); - if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { - status = _upb_Decoder_DecodeTop(&state, buf, msg, l); - } +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) - arena->head.ptr = state.arena.head.ptr; - arena->head.end = state.arena.head.end; - arena->cleanup_metadata = state.arena.cleanup_metadata; - return status; -} +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) -#undef OP_FIXPCK_LG2 -#undef OP_VARPCK_LG2 +#undef TAGBYTES +#undef SIZES +#undef F +#undef FASTDECODE_SUBMSG + +#endif /* UPB_FASTTABLE */ // We encode backwards, to avoid pre-computing lengths (one-pass encode). @@ -12699,8 +13287,8 @@ 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 upb_MiniTableSub* subs, + const upb_MiniTableField* f) { const char* field_mem = _field_mem; int wire_type; @@ -12782,8 +13370,8 @@ static void encode_scalar(upb_encstate* e, const void* _field_mem, } static void encode_array(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { + const upb_MiniTableSub* subs, + const upb_MiniTableField* 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; @@ -12890,8 +13478,8 @@ static void encode_array(upb_encstate* e, const upb_Message* msg, 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]; + const upb_MiniTableField* key_field = &layout->fields[0]; + const upb_MiniTableField* 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); @@ -12902,8 +13490,8 @@ static void encode_mapentry(upb_encstate* e, uint32_t number, } static void encode_map(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { + const upb_MiniTableSub* subs, + const upb_MiniTableField* 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); @@ -12920,11 +13508,10 @@ static void encode_map(upb_encstate* e, const upb_Message* msg, } _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); + intptr_t iter = UPB_STRTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&map->table, &key, &val, &iter)) { upb_MapEntry ent; _upb_map_fromkey(key, &ent.k, map->key_size); _upb_map_fromvalue(val, &ent.v, map->val_size); @@ -12934,12 +13521,12 @@ static void encode_map(upb_encstate* e, const upb_Message* msg, } static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { + const upb_MiniTableSub* subs, + const upb_MiniTableField* 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) { + switch (_upb_MiniTableField_GetRep(f)) { case kUpb_FieldRep_1Byte: { char ch; memcpy(&ch, mem, 1); @@ -12972,8 +13559,8 @@ static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, } static void encode_field(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { + const upb_MiniTableSub* subs, + const upb_MiniTableField* field) { switch (upb_FieldMode_Get(field)) { case kUpb_FieldMode_Array: encode_array(e, msg, subs, field); @@ -12989,22 +13576,16 @@ static void encode_field(upb_encstate* e, const upb_Message* msg, } } -/* 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_tag(e, kUpb_MsgSet_Item, 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_tag(e, kUpb_MsgSet_Message, kUpb_WireType_Delimited); encode_varint(e, ext->ext->field.number); - encode_tag(e, 2, kUpb_WireType_Varint); - encode_tag(e, 1, kUpb_WireType_StartGroup); + encode_tag(e, kUpb_MsgSet_TypeId, kUpb_WireType_Varint); + encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup); } static void encode_message(upb_encstate* e, const upb_Message* msg, @@ -13048,8 +13629,8 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, } if (m->field_count) { - const upb_MiniTable_Field* f = &m->fields[m->field_count]; - const upb_MiniTable_Field* first = &m->fields[0]; + const upb_MiniTableField* f = &m->fields[m->field_count]; + const upb_MiniTableField* first = &m->fields[0]; while (f != first) { f--; if (encode_shouldencode(e, msg, m->subs, f)) { @@ -13100,7 +13681,7 @@ upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l, return status; } -/* See port_def.inc. This should #undef all macros #defined there. */ +// This should #undef all macros #defined in def.inc #undef UPB_SIZE #undef UPB_PTR_AT diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h index d0552eeaf2..50aaa0d39c 100644 --- a/php/ext/google/protobuf/php-upb.h +++ b/php/ext/google/protobuf/php-upb.h @@ -1,10 +1,9 @@ /* Amalgamated source file */ /* - * This is where we define macros used across upb. + * This is where we define internal portability macros used across upb. * - * All of these macros are undef'd in port_undef.inc to avoid leaking them to - * users. + * All of these macros are undef'd in undef.inc to avoid leaking them to users. * * The correct usage is: * @@ -12,13 +11,13 @@ * #include "upb/baz.h" * * // MUST be last included header. - * #include "upb/port_def.inc" + * #include "upb/port/def.inc" * * // Code for this file. * // <...> * * // Can be omitted for .c files, required for .h. - * #include "upb/port_undef.inc" + * #include "upb/port/undef.inc" * * This file is private and must not be included by users! */ @@ -43,6 +42,7 @@ #include #include #include +#include #if UINTPTR_MAX == 0xffffffff #define UPB_SIZE(size32, size64) size32 @@ -55,11 +55,6 @@ */ #define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) -#define UPB_READ_ONEOF(msg, fieldtype, offset, case_offset, case_val, default) \ - *UPB_PTR_AT(msg, case_offset, int) == case_val \ - ? *UPB_PTR_AT(msg, offset, fieldtype) \ - : default - #define UPB_WRITE_ONEOF(msg, fieldtype, offset, value, case_offset, case_val) \ *UPB_PTR_AT(msg, case_offset, int) = case_val; \ *UPB_PTR_AT(msg, offset, fieldtype) = value; @@ -81,16 +76,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)) @@ -113,8 +108,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() @@ -267,30 +261,43 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #define UPB_DEPRECATED #endif -#ifndef UPB_INTERNAL_ATOI_H_ -#define UPB_INTERNAL_ATOI_H_ +#ifndef UPB_BASE_STATUS_H_ +#define UPB_BASE_STATUS_H_ + +#include // Must be last. +#define _kUpb_Status_MaxMessage 127 + +typedef struct { + bool ok; + char msg[_kUpb_Status_MaxMessage]; // Error message; NULL-terminated. +} upb_Status; + #ifdef __cplusplus extern "C" { #endif -// 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. -// Return the new position of the pointer after parsing the int, or NULL on -// integer overflow. +const char* upb_Status_ErrorMessage(const upb_Status* status); +bool upb_Status_IsOk(const upb_Status* status); -const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val); -const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, - bool* is_neg); +// These are no-op if |status| is NULL. +void upb_Status_Clear(upb_Status* status); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) + UPB_PRINTF(2, 3); +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_INTERNAL_ATOI_H_ */ +#endif /* UPB_BASE_STATUS_H_ */ #ifndef UPB_INTERNAL_ARRAY_INTERNAL_H_ #define UPB_INTERNAL_ARRAY_INTERNAL_H_ @@ -302,21 +309,167 @@ const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, #define UPB_COLLECTIONS_ARRAY_H_ +#ifndef UPB_BASE_DESCRIPTOR_CONSTANTS_H_ +#define UPB_BASE_DESCRIPTOR_CONSTANTS_H_ + +// The types a field can have. Note that this list is not identical to the +// types defined in descriptor.proto, which gives INT32 and SINT32 separate +// types (we distinguish the two with the "integer encoding" enum below). +// This enum is an internal convenience only and has no meaning outside of upb. +typedef enum { + kUpb_CType_Bool = 1, + kUpb_CType_Float = 2, + kUpb_CType_Int32 = 3, + kUpb_CType_UInt32 = 4, + kUpb_CType_Enum = 5, // Enum values are int32. + kUpb_CType_Message = 6, + kUpb_CType_Double = 7, + kUpb_CType_Int64 = 8, + kUpb_CType_UInt64 = 9, + kUpb_CType_String = 10, + kUpb_CType_Bytes = 11 +} upb_CType; + +// The repeated-ness of each field; this matches descriptor.proto. +typedef enum { + kUpb_Label_Optional = 1, + kUpb_Label_Required = 2, + kUpb_Label_Repeated = 3 +} upb_Label; + +// Descriptor types, as defined in descriptor.proto. +typedef enum { + kUpb_FieldType_Double = 1, + kUpb_FieldType_Float = 2, + kUpb_FieldType_Int64 = 3, + kUpb_FieldType_UInt64 = 4, + kUpb_FieldType_Int32 = 5, + kUpb_FieldType_Fixed64 = 6, + kUpb_FieldType_Fixed32 = 7, + kUpb_FieldType_Bool = 8, + kUpb_FieldType_String = 9, + kUpb_FieldType_Group = 10, + kUpb_FieldType_Message = 11, + kUpb_FieldType_Bytes = 12, + kUpb_FieldType_UInt32 = 13, + kUpb_FieldType_Enum = 14, + kUpb_FieldType_SFixed32 = 15, + kUpb_FieldType_SFixed64 = 16, + kUpb_FieldType_SInt32 = 17, + kUpb_FieldType_SInt64 = 18, +} upb_FieldType; + +#define kUpb_FieldType_SizeOf 19 + +#endif /* UPB_BASE_DESCRIPTOR_CONSTANTS_H_ */ + +// Users should include array.h or map.h instead. +// IWYU pragma: private, include "upb/collections/array.h" + #ifndef UPB_MESSAGE_VALUE_H_ #define UPB_MESSAGE_VALUE_H_ -/* - * Public APIs for message operations that do not require descriptors. - * These functions can be used even in build that does not want to depend on - * reflection or descriptors. - * - * Descriptor-based reflection functionality lives in reflection.h. - */ +#ifndef UPB_BASE_STRING_VIEW_H_ +#define UPB_BASE_STRING_VIEW_H_ + +#include + +// Must be last. + +#define UPB_STRINGVIEW_INIT(ptr, len) \ + { ptr, len } + +#define UPB_STRINGVIEW_FORMAT "%.*s" +#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data + +// LINT.IfChange(struct_definition) +typedef struct { + const char* data; + size_t size; +} upb_StringView; +// LINT.ThenChange(GoogleInternalName0) + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, + size_t size) { + upb_StringView ret; + ret.data = data; + ret.size = size; + return ret; +} + +UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { + return upb_StringView_FromDataAndSize(data, strlen(data)); +} + +UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { + return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_STRING_VIEW_H_ */ + +#ifndef UPB_MINI_TABLE_TYPES_H_ +#define UPB_MINI_TABLE_TYPES_H_ + +typedef void upb_Message; + +typedef struct upb_MiniTable upb_MiniTable; +typedef struct upb_MiniTableEnum upb_MiniTableEnum; +typedef struct upb_MiniTableExtension upb_MiniTableExtension; +typedef struct upb_MiniTableField upb_MiniTableField; +typedef struct upb_MiniTableFile upb_MiniTableFile; +typedef union upb_MiniTableSub upb_MiniTableSub; + +#endif /* UPB_MINI_TABLE_TYPES_H_ */ + +// Must be last. + +typedef struct upb_Array upb_Array; +typedef struct upb_Map upb_Map; + +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_Array* array_val; + const upb_Map* map_val; + const upb_Message* msg_val; + upb_StringView str_val; +} upb_MessageValue; + +typedef union { + upb_Array* array; + upb_Map* map; + upb_Message* msg; +} upb_MutableMessageValue; -#ifndef UPB_MSG_H_ -#define UPB_MSG_H_ +#endif /* UPB_MESSAGE_VALUE_H_ */ + +/* upb_Arena is a specific allocator implementation that uses arena allocation. + * The user provides an allocator that will be used to allocate the underlying + * arena blocks. Arenas by nature do not require the individual allocations + * to be freed. However the Arena does allow users to register cleanup + * functions that will run when the arena is destroyed. + * + * A upb_Arena is *not* thread-safe. + * + * You could write a thread-safe arena allocator that satisfies the + * upb_alloc interface, but it would not be as efficient for the + * single-threaded case. */ #ifndef UPB_MEM_ARENA_H_ #define UPB_MEM_ARENA_H_ @@ -396,26 +549,10 @@ UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } // Must be last. -#ifdef __cplusplus -extern "C" { -#endif - -/* upb_Arena is a specific allocator implementation that uses arena allocation. - * The user provides an allocator that will be used to allocate the underlying - * arena blocks. Arenas by nature do not require the individual allocations - * to be freed. However the Arena does allow users to register cleanup - * functions that will run when the arena is destroyed. - * - * A upb_Arena is *not* thread-safe. - * - * You could write a thread-safe arena allocator that satisfies the - * upb_alloc interface, but it would not be as efficient for the - * single-threaded case. */ - -typedef void upb_CleanupFunc(void* ud); - typedef struct upb_Arena upb_Arena; +typedef void upb_CleanupFunc(void* context); + typedef struct { /* We implement the allocator interface. * This must be the first member of upb_Arena! @@ -425,6 +562,10 @@ typedef struct { char *ptr, *end; } _upb_ArenaHead; +#ifdef __cplusplus +extern "C" { +#endif + /* Creates an arena from the given initial block (if any -- n may be 0). * Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this * is a fixed-size arena and cannot grow. */ @@ -443,7 +584,13 @@ UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) { return (size_t)(h->end - h->ptr); } -UPB_INLINE void* _upb_Arena_FastMalloc(upb_Arena* a, size_t size) { +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); + } + + // We have enough space to do a fast malloc. _upb_ArenaHead* h = (_upb_ArenaHead*)a; void* ret = h->ptr; UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret); @@ -466,16 +613,6 @@ UPB_INLINE void* _upb_Arena_FastMalloc(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 @@ -533,40 +670,48 @@ UPB_INLINE upb_Arena* upb_Arena_New(void) { extern "C" { #endif -typedef void upb_Message; +/* 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); -/* For users these are opaque. They can be obtained from - * upb_MessageDef_MiniTable() but users cannot access any of the members. */ -typedef struct upb_MiniTable upb_MiniTable; +/* Returns the number of elements in the array. */ +size_t upb_Array_Size(const upb_Array* arr); -/* Creates a new message with the given mini_table on the given arena. */ -upb_Message* upb_Message_New(const upb_MiniTable* mini_table, upb_Arena* arena); +/* 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); -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ -void upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, - upb_Arena* arena); +/* 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); -/* Returns a reference to the message's unknown data. */ -const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len); +/* Appends an element to the array. Returns false on allocation failure. */ +bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); -/* Removes partial unknown data from message. */ -void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len); +/* 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); -/* Returns the number of extensions present in this message. */ -size_t upb_Message_ExtensionCount(const upb_Message* msg); +/* 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); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_MSG_INT_H_ */ - -#ifndef UPB_STRING_VIEW_H_ -#define UPB_STRING_VIEW_H_ - -#include +#endif /* UPB_COLLECTIONS_ARRAY_H_ */ // Must be last. @@ -574,296 +719,14 @@ size_t upb_Message_ExtensionCount(const upb_Message* msg); extern "C" { #endif -typedef struct { - const char* data; - size_t size; -} upb_StringView; - -UPB_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, - size_t size) { - upb_StringView ret; - ret.data = data; - ret.size = size; - return ret; -} - -UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { - return upb_StringView_FromDataAndSize(data, strlen(data)); -} - -UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { - return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; -} - -#define UPB_STRINGVIEW_INIT(ptr, len) \ - { ptr, len } - -#define UPB_STRINGVIEW_FORMAT "%.*s" -#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_STRING_VIEW_H_ */ - -/* - * This file contains shared definitions that are widely used across upb. - */ - -#ifndef UPB_H_ -#define UPB_H_ - -#include -#include -#include -#include -#include -#include - -// TODO(b/232091617): Remove these and fix everything that breaks as a result. - -#ifndef UPB_STATUS_H_ -#define UPB_STATUS_H_ - -#include - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -#define _kUpb_Status_MaxMessage 127 - -typedef struct { - bool ok; - char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */ -} upb_Status; - -const char* upb_Status_ErrorMessage(const upb_Status* status); -bool upb_Status_IsOk(const upb_Status* status); - -/* These are no-op if |status| is NULL. */ -void upb_Status_Clear(upb_Status* status); -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) - UPB_PRINTF(2, 3); -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_STATUS_H_ */ - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -// These types appear in circular references so we need to forward-declare them. -// There is no obviously good place for this so let's just put it here. -typedef struct upb_Array upb_Array; -typedef struct upb_Map upb_Map; - -/* Constants ******************************************************************/ - -/* A list of types as they are encoded on-the-wire. */ -typedef enum { - kUpb_WireType_Varint = 0, - kUpb_WireType_64Bit = 1, - kUpb_WireType_Delimited = 2, - kUpb_WireType_StartGroup = 3, - kUpb_WireType_EndGroup = 4, - kUpb_WireType_32Bit = 5 -} upb_WireType; - -/* The types a field can have. Note that this list is not identical to the - * types defined in descriptor.proto, which gives INT32 and SINT32 separate - * types (we distinguish the two with the "integer encoding" enum below). */ -typedef enum { - kUpb_CType_Bool = 1, - kUpb_CType_Float = 2, - kUpb_CType_Int32 = 3, - kUpb_CType_UInt32 = 4, - kUpb_CType_Enum = 5, /* Enum values are int32. */ - kUpb_CType_Message = 6, - kUpb_CType_Double = 7, - kUpb_CType_Int64 = 8, - kUpb_CType_UInt64 = 9, - kUpb_CType_String = 10, - kUpb_CType_Bytes = 11 -} upb_CType; - -/* The repeated-ness of each field; this matches descriptor.proto. */ -typedef enum { - kUpb_Label_Optional = 1, - kUpb_Label_Required = 2, - kUpb_Label_Repeated = 3 -} upb_Label; - -/* Descriptor types, as defined in descriptor.proto. */ -typedef enum { - kUpb_FieldType_Double = 1, - kUpb_FieldType_Float = 2, - kUpb_FieldType_Int64 = 3, - kUpb_FieldType_UInt64 = 4, - kUpb_FieldType_Int32 = 5, - kUpb_FieldType_Fixed64 = 6, - kUpb_FieldType_Fixed32 = 7, - kUpb_FieldType_Bool = 8, - kUpb_FieldType_String = 9, - kUpb_FieldType_Group = 10, - kUpb_FieldType_Message = 11, - kUpb_FieldType_Bytes = 12, - kUpb_FieldType_UInt32 = 13, - kUpb_FieldType_Enum = 14, - kUpb_FieldType_SFixed32 = 15, - kUpb_FieldType_SFixed64 = 16, - kUpb_FieldType_SInt32 = 17, - kUpb_FieldType_SInt64 = 18, -} upb_FieldType; - -#define kUpb_FieldType_SizeOf 19 - -#define kUpb_Map_Begin ((size_t)-1) - -UPB_INLINE bool _upb_IsLittleEndian(void) { - int x = 1; - return *(char*)&x == 1; -} - -UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) { - if (_upb_IsLittleEndian()) { - return val; - } else { - return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | - ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); - } -} - -UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { - if (_upb_IsLittleEndian()) { - return val; - } else { - return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | - _upb_BigEndian_Swap32((uint32_t)(val >> 32)); - } -} - -UPB_INLINE int _upb_Log2Ceiling(int x) { - if (x <= 1) return 0; -#ifdef __GNUC__ - return 32 - __builtin_clz(x - 1); -#else - int lg2 = 0; - while (1 << lg2 < x) lg2++; - return lg2; -#endif -} - -UPB_INLINE int _upb_Log2CeilingSize(int x) { return 1 << _upb_Log2Ceiling(x); } - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_H_ */ - -// Must be last. - -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_Array* array_val; - const upb_Map* map_val; - const upb_Message* msg_val; - upb_StringView str_val; -} upb_MessageValue; - -typedef union { - upb_Array* array; - upb_Map* map; - upb_Message* msg; -} upb_MutableMessageValue; - - -#endif /* UPB_MESSAGE_VALUE_H_ */ - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -/* 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 number of elements in 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); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_COLLECTIONS_ARRAY_H_ */ - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -// Our internal representation for repeated fields. -struct upb_Array { - uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ - size_t size; /* The number of elements in the array. */ - size_t capacity; /* Allocated storage. Measured in elements. */ -}; +// LINT.IfChange(struct_definition) +// Our internal representation for repeated fields. +struct upb_Array { + uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ + size_t size; /* The number of elements in the array. */ + size_t capacity; /* Allocated storage. Measured in elements. */ +}; +// LINT.ThenChange(GoogleInternalName1) UPB_INLINE const void* _upb_array_constptr(const upb_Array* arr) { UPB_ASSERT((arr->data & 7) <= 4); @@ -1046,11 +909,9 @@ bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, 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 @@ -1068,22 +929,36 @@ UPB_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key, kUpb_MapInsertStatus_OutOfMemory; } -/* Deletes this key from the table. Returns true if the key was present. */ +// 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; +// upb_MessageValue key, val; +// while (upb_Map_Next(map, &key, &val, &iter)) { +// ... +// } + +#define kUpb_Map_Begin ((size_t)-1) + +// Advances to the next entry. Returns false if no more entries are present. +// Otherwise returns true and populates both *key and *value. +bool upb_Map_Next(const upb_Map* map, upb_MessageValue* key, + upb_MessageValue* val, size_t* iter); + +// DEPRECATED iterator, slated for removal. + /* 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. */ +// 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 @@ -1095,11 +970,6 @@ bool upb_MapIterator_Done(const upb_Map* map, size_t iter); 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 @@ -1107,91 +977,15 @@ void upb_MapIterator_SetValue(upb_Map* map, size_t iter, #endif /* UPB_COLLECTIONS_MAP_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 - - -#ifndef UPB_EXTENSION_REGISTRY_H_ -#define UPB_EXTENSION_REGISTRY_H_ - - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -/* Extension registry: a dynamic data structure that stores a map of: - * (upb_MiniTable, number) -> extension info - * - * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing - * binary format. - * - * upb_ExtensionRegistry is part of the mini-table (msglayout) family of - * objects. Like all mini-table objects, it is suitable for reflection-less - * builds that do not want to expose names into the binary. - * - * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory - * allocation and dynamic initialization: - * * If reflection is being used, then upb_DefPool will construct an appropriate - * upb_ExtensionRegistry automatically. - * * For a mini-table only build, the user must manually construct the - * upb_ExtensionRegistry and populate it with all of the extensions the user - * cares about. - * * A third alternative is to manually unpack relevant extensions after the - * main parse is complete, similar to how Any works. This is perhaps the - * nicest solution from the perspective of reducing dependencies, avoiding - * dynamic memory allocation, and avoiding the need to parse uninteresting - * extensions. The downsides are: - * (1) parse errors are not caught during the main parse - * (2) the CPU hit of parsing comes during access, which could cause an - * undesirable stutter in application performance. - * - * Users cannot directly get or put into this map. Users can only add the - * extensions from a generated module and pass the extension registry to the - * binary decoder. - * - * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use - * reflection do not need to populate a upb_ExtensionRegistry directly. - */ - -typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; -typedef struct upb_MiniTable_Extension upb_MiniTable_Extension; - -// Creates a upb_ExtensionRegistry in the given arena. -// The arena must outlive any use of the extreg. -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); - -// Adds the given extension info for the array |e| of size |count| into the -// registry. If there are any errors, the entire array is backed out. -// The extensions must outlive the registry. -// Possible errors include OOM or an extension number that already exists. -// TODO: There is currently no way to determine the exact reason for failure. -bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, - size_t count); +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// -// Looks up the extension (if any) defined for message type |t| and field -// number |num|. Returns the extension if found, otherwise NULL. -const upb_MiniTable_Extension* upb_ExtensionRegistry_Lookup( - const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num); +#ifndef UPB_COLLECTIONS_MAP_INTERNAL_H_ +#define UPB_COLLECTIONS_MAP_INTERNAL_H_ -#ifdef __cplusplus -} /* extern "C" */ -#endif +#ifndef UPB_HASH_STR_TABLE_H_ +#define UPB_HASH_STR_TABLE_H_ -#endif /* UPB_EXTENSION_REGISTRY_H_ */ /* * upb_table @@ -1212,8 +1006,8 @@ const upb_MiniTable_Extension* upb_ExtensionRegistry_Lookup( * mode, we check this on insert and lookup. */ -#ifndef UPB_INTERNAL_TABLE_H_ -#define UPB_INTERNAL_TABLE_H_ +#ifndef UPB_HASH_COMMON_H_ +#define UPB_HASH_COMMON_H_ #include @@ -1345,67 +1139,63 @@ typedef struct { upb_tabent* entries; } upb_table; -typedef struct { - upb_table t; -} upb_strtable; - -typedef struct { - upb_table t; /* For entries that don't fit in the array part. */ - const upb_tabval* array; /* Array part of the table. See const note above. */ - size_t array_size; /* Array part size. */ - size_t array_count; /* Array part number of elements. */ -} upb_inttable; - UPB_INLINE size_t upb_table_size(const upb_table* t) { - if (t->size_lg2 == 0) - return 0; - else - return 1 << t->size_lg2; + return t->size_lg2 ? 1 << t->size_lg2 : 0; } -/* Internal-only functions, in .h file only out of necessity. */ +// Internal-only functions, in .h file only out of necessity. UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; } -/* Initialize and uninitialize a table, respectively. If memory allocation - * failed, false is returned that the table is uninitialized. */ -bool upb_inttable_init(upb_inttable* table, upb_Arena* a); +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_HASH_COMMON_H_ */ + +// Must be last. + +typedef struct { + upb_table t; +} upb_strtable; + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize a table. If memory allocation failed, false is returned and +// the table is uninitialized. bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a); -/* Returns the number of values in the table. */ -size_t upb_inttable_count(const upb_inttable* t); +// Returns the number of values in the table. UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) { return t->t.count; } void upb_strtable_clear(upb_strtable* t); -/* Inserts the given key into the hashtable with the given value. The key must - * not already exist in the hash table. For strtables, the key is not required - * to be NULL-terminated, and the table will make an internal copy of the key. - * Inttables must not insert a value of UINTPTR_MAX. - * - * If a table resize was required but memory allocation failed, false is - * returned and the table is unchanged. */ -bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, - upb_Arena* a); +// Inserts the given key into the hashtable with the given value. +// The key must not already exist in the hash table. The key is not required +// to be NULL-terminated, and the table will make an internal copy of the key. +// +// If a table resize was required but memory allocation failed, false is +// returned and the table is unchanged. */ bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len, upb_value val, upb_Arena* a); -/* Looks up key in this table, returning "true" if the key was found. - * If v is non-NULL, copies the value for this key into *v. */ -bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); +// Looks up key in this table, returning "true" if the key was found. +// If v is non-NULL, copies the value for this key into *v. bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, upb_value* v); -/* For NULL-terminated strings. */ +// For NULL-terminated strings. UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key, upb_value* v) { return upb_strtable_lookup2(t, key, strlen(key), v); } -/* Removes an item from the table. Returns true if the remove was successful, - * and stores the removed item in *val if non-NULL. */ -bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); +// Removes an item from the table. Returns true if the remove was successful, +// and stores the removed item in *val if non-NULL. bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, upb_value* val); @@ -1414,40 +1204,12 @@ UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key, return upb_strtable_remove2(t, key, strlen(key), v); } -/* Updates an existing entry in an inttable. If the entry does not exist, - * returns false and does nothing. Unlike insert/remove, this does not - * invalidate iterators. */ -bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); - -/* Optimizes the table for the current set of entries, for both memory use and - * lookup time. Client should call this after all entries have been inserted; - * inserting more entries is legal, but will likely require a table resize. */ -void upb_inttable_compact(upb_inttable* t, upb_Arena* a); - -/* Exposed for testing only. */ +// Exposed for testing only. bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a); -/* Iterators ******************************************************************/ - -/* Iteration over inttable. - * - * intptr_t iter = UPB_INTTABLE_BEGIN; - * uintptr_t key; - * upb_value val; - * while (upb_inttable_next2(t, &key, &val, &iter)) { - * // ... - * } - */ - -#define UPB_INTTABLE_BEGIN -1 - -bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, - intptr_t* iter); -void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); - -/* Iteration over strtable. +/* Iteration over strtable: * - * intptr_t iter = UPB_INTTABLE_BEGIN; + * intptr_t iter = UPB_STRTABLE_BEGIN; * upb_StringView key; * upb_value val; * while (upb_strtable_next2(t, &key, &val, &iter)) { @@ -1463,7 +1225,7 @@ void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); /* DEPRECATED iterators, slated for removal. * - * Iterators for int and string tables. We are subject to some kind of unusual + * Iterators for string tables. We are subject to some kind of unusual * design constraints: * * For high-level languages: @@ -1483,7 +1245,6 @@ void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); * an invalidated iterator yields unspecified elements from the table, but it is * guaranteed not to crash and to return real table elements (except when done() * is true). */ - /* upb_strtable_iter **********************************************************/ /* upb_strtable_iter i; @@ -1500,6 +1261,10 @@ typedef struct { size_t index; } upb_strtable_iter; +UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { + return &i->t->t.entries[i->index]; +} + void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t); void upb_strtable_next(upb_strtable_iter* i); bool upb_strtable_done(const upb_strtable_iter* i); @@ -1509,104 +1274,345 @@ void upb_strtable_iter_setdone(upb_strtable_iter* i); bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, const upb_strtable_iter* i2); -/* upb_inttable_iter **********************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* upb_inttable_iter i; - * upb_inttable_begin(&i, t); - * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - * uintptr_t key = upb_inttable_iter_key(&i); - * upb_value val = upb_inttable_iter_value(&i); - * // ... - * } - */ -typedef struct { - const upb_inttable* t; - size_t index; - bool array_part; -} upb_inttable_iter; +#endif /* UPB_HASH_STR_TABLE_H_ */ -UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { - return &i->t->t.entries[i->index]; -} +// Must be last. -void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t); -void upb_inttable_next(upb_inttable_iter* i); -bool upb_inttable_done(const upb_inttable_iter* i); -uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i); -upb_value upb_inttable_iter_value(const upb_inttable_iter* i); -void upb_inttable_iter_setdone(upb_inttable_iter* i); -bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, - const upb_inttable_iter* i2); +struct upb_Map { + // Size of key and val, based on the map type. + // Strings are represented as '0' because they must be handled specially. + char key_size; + char val_size; -uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); + upb_strtable table; +}; #ifdef __cplusplus -} /* extern "C" */ +extern "C" { #endif +// Converting between internal table representation and user values. +// +// _upb_map_tokey() and _upb_map_fromkey() are inverses. +// _upb_map_tovalue() and _upb_map_fromvalue() are inverses. +// +// These functions account for the fact that strings are treated differently +// from other types when stored in a map. -#endif /* UPB_INTERNAL_TABLE_H_ */ +UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + return *(upb_StringView*)key; + } else { + return upb_StringView_FromDataAndSize((const char*)key, size); + } +} -// Must be last. +UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + memcpy(out, &key, sizeof(key)); + } else { + memcpy(out, key.data, size); + } +} -#ifdef __cplusplus -extern "C" { -#endif +UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, + upb_value* msgval, upb_Arena* a) { + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); + if (!strp) return false; + *strp = *(upb_StringView*)val; + *msgval = upb_value_ptr(strp); + } else { + memcpy(msgval, val, size); + } + return true; +} -/** upb_*Int* conversion routines ********************************************/ +UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); + memcpy(out, strp, sizeof(upb_StringView)); + } else { + memcpy(out, &val, size); + } +} -UPB_INLINE int32_t _upb_Int32_FromI(int v) { return (int32_t)v; } +UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { + upb_strtable_iter it; + it.t = &map->table; + it.index = *iter; + upb_strtable_next(&it); + *iter = it.index; + if (upb_strtable_done(&it)) return NULL; + return (void*)str_tabent(&it); +} -UPB_INLINE int64_t _upb_Int64_FromLL(long long v) { return (int64_t)v; } +UPB_INLINE void _upb_Map_Clear(upb_Map* map) { + upb_strtable_clear(&map->table); +} -UPB_INLINE uint32_t _upb_UInt32_FromU(unsigned v) { return (uint32_t)v; } +UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, + size_t key_size) { + upb_StringView k = _upb_map_tokey(key, key_size); + return upb_strtable_remove2(&map->table, k.data, k.size, NULL); +} -UPB_INLINE uint64_t _upb_UInt64_FromULL(unsigned long long v) { - return (uint64_t)v; +UPB_INLINE bool _upb_Map_Get(const upb_Map* map, const void* key, + size_t key_size, void* val, size_t val_size) { + upb_value tabval; + upb_StringView k = _upb_map_tokey(key, key_size); + bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); + if (ret && val) { + _upb_map_fromvalue(tabval, val, val_size); + } + return ret; } -extern const float kUpb_FltInfinity; -extern const double kUpb_Infinity; +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 kUpb_MapInsertStatus_OutOfMemory; + } -/** upb_MiniTable *************************************************************/ + // TODO(haberman): add overwrite operation to minimize number of lookups. + 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_MiniTable represents the memory layout of a given upb_MessageDef. The - * members are public so generated code can initialize them, but users MUST NOT - * read or write any of its members. */ +UPB_INLINE size_t _upb_Map_Size(const upb_Map* map) { + return map->table.t.count; +} -typedef struct { - uint32_t number; - uint16_t offset; - int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index - 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; +// Creates a new map on the given arena with this key/value type. +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); -#define kUpb_NoSub ((uint16_t)-1) +#ifdef __cplusplus +} /* extern "C" */ +#endif -typedef enum { - kUpb_FieldMode_Map = 0, - kUpb_FieldMode_Array = 1, - kUpb_FieldMode_Scalar = 2, -} upb_FieldMode; -// Mask to isolate the upb_FieldMode from field.mode. -#define kUpb_FieldMode_Mask 3 +#endif /* UPB_COLLECTIONS_MAP_INTERNAL_H_ */ -/* Extra flags on the mode field. */ -typedef enum { - kUpb_LabelFlags_IsPacked = 4, - kUpb_LabelFlags_IsExtension = 8, - // Indicates that this descriptor type is an "alternate type": - // - for Int32, this indicates that the actual type is Enum (but was - // rewritten to Int32 because it is an open enum that requires no check). - // - for Bytes, this indicates that the actual type is String (but does - // not require any UTF-8 check). - kUpb_LabelFlags_IsAlternate = 16, -} upb_LabelFlags; +// Public APIs for message operations that do not require descriptors. +// These functions can be used even in build that does not want to depend on +// reflection or descriptors. +// +// Descriptor-based reflection functionality lives in reflection.h. + +#ifndef UPB_MESSAGE_MESSAGE_H_ +#define UPB_MESSAGE_MESSAGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new message with the given mini_table on the given arena. +upb_Message* upb_Message_New(const upb_MiniTable* mini_table, upb_Arena* arena); + +// Adds unknown data (serialized protobuf data) to the given message. +// The data is copied into the message instance. +void upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, + upb_Arena* arena); + +// Returns a reference to the message's unknown data. +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len); + +// Removes partial unknown data from message. +void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len); + +// Returns the number of extensions present in this message. +size_t upb_Message_ExtensionCount(const upb_Message* msg); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_MESSAGE_H_ */ + +#ifndef UPB_BASE_LOG2_H_ +#define UPB_BASE_LOG2_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE int upb_Log2Ceiling(int x) { + if (x <= 1) return 0; +#ifdef __GNUC__ + return 32 - __builtin_clz(x - 1); +#else + int lg2 = 0; + while (1 << lg2 < x) lg2++; + return lg2; +#endif +} + +UPB_INLINE int upb_Log2CeilingSize(int x) { return 1 << upb_Log2Ceiling(x); } + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_LOG2_H_ */ + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +#ifndef UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ +#define UPB_COLLECTIONS_MAP_SORTER_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_MESSAGE_INTERNAL_H_ +#define UPB_MESSAGE_INTERNAL_H_ + +#include +#include + + +#ifndef UPB_EXTENSION_REGISTRY_H_ +#define UPB_EXTENSION_REGISTRY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +/* Extension registry: a dynamic data structure that stores a map of: + * (upb_MiniTable, number) -> extension info + * + * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing + * binary format. + * + * upb_ExtensionRegistry is part of the mini-table (msglayout) family of + * objects. Like all mini-table objects, it is suitable for reflection-less + * builds that do not want to expose names into the binary. + * + * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory + * allocation and dynamic initialization: + * * If reflection is being used, then upb_DefPool will construct an appropriate + * upb_ExtensionRegistry automatically. + * * For a mini-table only build, the user must manually construct the + * upb_ExtensionRegistry and populate it with all of the extensions the user + * cares about. + * * A third alternative is to manually unpack relevant extensions after the + * main parse is complete, similar to how Any works. This is perhaps the + * nicest solution from the perspective of reducing dependencies, avoiding + * dynamic memory allocation, and avoiding the need to parse uninteresting + * extensions. The downsides are: + * (1) parse errors are not caught during the main parse + * (2) the CPU hit of parsing comes during access, which could cause an + * undesirable stutter in application performance. + * + * Users cannot directly get or put into this map. Users can only add the + * extensions from a generated module and pass the extension registry to the + * binary decoder. + * + * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use + * reflection do not need to populate a upb_ExtensionRegistry directly. + */ + +typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; + +// Creates a upb_ExtensionRegistry in the given arena. +// The arena must outlive any use of the extreg. +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); + +// Adds the given extension info for the array |e| of size |count| into the +// registry. If there are any errors, the entire array is backed out. +// The extensions must outlive the registry. +// Possible errors include OOM or an extension number that already exists. +// TODO: There is currently no way to determine the exact reason for failure. +bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, + const upb_MiniTableExtension** e, + size_t count); + +// Looks up the extension (if any) defined for message type |t| and field +// number |num|. Returns the extension if found, otherwise NULL. +const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( + const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_EXTENSION_REGISTRY_H_ */ + +#ifndef UPB_MESSAGE_EXTENSION_INTERNAL_H_ +#define UPB_MESSAGE_EXTENSION_INTERNAL_H_ + + +#ifndef UPB_MINI_TABLE_EXTENSION_INTERNAL_H_ +#define UPB_MINI_TABLE_EXTENSION_INTERNAL_H_ + + +#ifndef UPB_MINI_TABLE_FIELD_INTERNAL_H_ +#define UPB_MINI_TABLE_FIELD_INTERNAL_H_ + + +// Must be last. + +struct upb_MiniTableField { + uint32_t number; + uint16_t offset; + int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index + uint16_t submsg_index; // kUpb_NoSub if descriptortype != MESSAGE/GROUP/ENUM + uint8_t descriptortype; + + // upb_FieldMode | upb_LabelFlags | (upb_FieldRep << kUpb_FieldRep_Shift) + uint8_t mode; +}; + +#define kUpb_NoSub ((uint16_t)-1) + +typedef enum { + kUpb_FieldMode_Map = 0, + kUpb_FieldMode_Array = 1, + kUpb_FieldMode_Scalar = 2, +} 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, + kUpb_LabelFlags_IsExtension = 8, + // Indicates that this descriptor type is an "alternate type": + // - for Int32, this indicates that the actual type is Enum (but was + // rewritten to Int32 because it is an open enum that requires no check). + // - for Bytes, this indicates that the actual type is String (but does + // not require any UTF-8 check). + kUpb_LabelFlags_IsAlternate = 16, +} upb_LabelFlags; // Note: we sort by this number when calculating layout order. typedef enum { @@ -1615,82 +1621,215 @@ typedef enum { kUpb_FieldRep_StringView = 2, kUpb_FieldRep_8Byte = 3, - kUpb_FieldRep_Shift = 6, // 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) { +#define kUpb_FieldRep_Shift 6 + +UPB_INLINE upb_FieldRep +_upb_MiniTableField_GetRep(const upb_MiniTableField* field) { + return (upb_FieldRep)(field->mode >> kUpb_FieldRep_Shift); +} + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTableField* field) { return (upb_FieldMode)(field->mode & 3); } -UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTable_Field* field) { - /* This works because upb_FieldMode has no value 3. */ +UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTableField* field) { + // This works because upb_FieldMode has no value 3. return !(field->mode & kUpb_FieldMode_Scalar); } -UPB_INLINE bool upb_IsSubMessage(const upb_MiniTable_Field* field) { +UPB_INLINE bool upb_IsSubMessage(const upb_MiniTableField* field) { return field->descriptortype == kUpb_FieldType_Message || field->descriptortype == kUpb_FieldType_Group; } -struct upb_Decoder; -struct upb_MiniTable; +// LINT.IfChange(presence_logic) -typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data); +// Hasbit access /////////////////////////////////////////////////////////////// -typedef struct { - uint64_t field_data; - _upb_FieldParser* field_parser; -} _upb_FastTable_Entry; +UPB_INLINE size_t _upb_hasbit_ofs(size_t idx) { return idx / 8; } -typedef struct { - uint32_t mask_limit; // Limit enum value that can be tested with mask. - uint32_t value_count; // Number of values after the bitfield. - uint32_t data[]; // Bitmask + enumerated values follow. -} upb_MiniTable_Enum; +UPB_INLINE char _upb_hasbit_mask(size_t idx) { return 1 << (idx % 8); } -typedef enum { - _kUpb_FastEnumCheck_ValueIsInEnum = 0, - _kUpb_FastEnumCheck_ValueIsNotInEnum = 1, - _kUpb_FastEnumCheck_CannotCheckFast = 2, -} _kUpb_FastEnumCheck_Status; +UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) { + return (*UPB_PTR_AT(msg, _upb_hasbit_ofs(idx), const char) & + _upb_hasbit_mask(idx)) != 0; +} -UPB_INLINE _kUpb_FastEnumCheck_Status -_upb_MiniTable_CheckEnumValueFast(const upb_MiniTable_Enum* e, uint32_t val) { - if (UPB_UNLIKELY(val >= 64)) return _kUpb_FastEnumCheck_CannotCheckFast; - uint64_t mask = e->data[0] | ((uint64_t)e->data[1] << 32); - return (mask & (1ULL << val)) ? _kUpb_FastEnumCheck_ValueIsInEnum - : _kUpb_FastEnumCheck_ValueIsNotInEnum; +UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) { + (*UPB_PTR_AT(msg, _upb_hasbit_ofs(idx), char)) |= _upb_hasbit_mask(idx); } -UPB_INLINE bool _upb_MiniTable_CheckEnumValueSlow(const upb_MiniTable_Enum* e, - uint32_t val) { - if (val < e->mask_limit) return e->data[val / 32] & (1ULL << (val % 32)); - // OPT: binary search long lists? - const uint32_t* start = &e->data[e->mask_limit / 32]; - const uint32_t* limit = &e->data[(e->mask_limit / 32) + e->value_count]; - for (const uint32_t* p = start; p < limit; p++) { - if (*p == val) return true; - } - return false; +UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) { + (*UPB_PTR_AT(msg, _upb_hasbit_ofs(idx), char)) &= ~_upb_hasbit_mask(idx); } -// Validates enum value against range defined by enum mini table. -UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, - uint32_t val) { - _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, val); - if (UPB_UNLIKELY(status == _kUpb_FastEnumCheck_CannotCheckFast)) { - return _upb_MiniTable_CheckEnumValueSlow(e, val); - } - return status == _kUpb_FastEnumCheck_ValueIsInEnum ? true : false; +UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTableField* f) { + UPB_ASSERT(f->presence > 0); + return f->presence; } -typedef union { - const struct upb_MiniTable* submsg; - const upb_MiniTable_Enum* subenum; -} upb_MiniTable_Sub; +UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg, + const upb_MiniTableField* f) { + return _upb_hasbit(msg, _upb_Message_Hasidx(f)); +} + +UPB_INLINE void _upb_sethas_field(const upb_Message* msg, + const upb_MiniTableField* f) { + _upb_sethas(msg, _upb_Message_Hasidx(f)); +} + +UPB_INLINE void _upb_clearhas_field(const upb_Message* msg, + const upb_MiniTableField* f) { + _upb_clearhas(msg, _upb_Message_Hasidx(f)); +} + +// Oneof case access /////////////////////////////////////////////////////////// + +UPB_INLINE uint32_t* _upb_oneofcase(upb_Message* msg, size_t case_ofs) { + return UPB_PTR_AT(msg, case_ofs, uint32_t); +} + +UPB_INLINE uint32_t _upb_getoneofcase(const void* msg, size_t case_ofs) { + return *UPB_PTR_AT(msg, case_ofs, uint32_t); +} + +UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTableField* f) { + UPB_ASSERT(f->presence < 0); + return ~(ptrdiff_t)f->presence; +} + +UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg, + const upb_MiniTableField* f) { + return _upb_oneofcase(msg, _upb_oneofcase_ofs(f)); +} + +UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg, + const upb_MiniTableField* f) { + return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f)); +} + +UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_Message* msg, size_t ofs) { + return *UPB_PTR_AT(msg, ofs, const upb_Message*) != NULL; +} + +// LINT.ThenChange(GoogleInternalName2) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_FIELD_INTERNAL_H_ */ + +#ifndef UPB_MINI_TABLE_SUB_INTERNAL_H_ +#define UPB_MINI_TABLE_SUB_INTERNAL_H_ + + +union upb_MiniTableSub { + const upb_MiniTable* submsg; + const upb_MiniTableEnum* subenum; +}; + +#endif /* UPB_MINI_TABLE_SUB_INTERNAL_H_ */ + +// Must be last. + +struct upb_MiniTableExtension { + upb_MiniTableField field; + const upb_MiniTable* extendee; + upb_MiniTableSub sub; // NULL unless submessage or proto2 enum +}; + + +#endif /* UPB_MINI_TABLE_EXTENSION_INTERNAL_H_ */ + +// Must be last. + +// The internal representation of an extension is self-describing: it contains +// enough information that we can serialize it to binary format without needing +// to look it up in a upb_ExtensionRegistry. +// +// This representation allocates 16 bytes to data on 64-bit platforms. +// This is rather wasteful for scalars (in the extreme case of bool, +// it wastes 15 bytes). We accept this because we expect messages to be +// the most common extension type. +typedef struct { + const upb_MiniTableExtension* ext; + union { + upb_StringView str; + void* ptr; + char scalar_data[8]; + } data; +} upb_Message_Extension; + +#ifdef __cplusplus +extern "C" { +#endif + +// 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_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTableExtension* ext, upb_Arena* arena); + +// Returns an array of extensions for this message. +// Note: the array is ordered in reverse relative to the order of creation. +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count); + +// Returns an extension for the given field number, or NULL if no extension +// exists for this field number. +const upb_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTableExtension* ext); + +void _upb_Message_Clearext(upb_Message* msg, const upb_MiniTableExtension* ext); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_EXTENSION_INTERNAL_H_ */ + +#ifndef UPB_MINI_TABLE_FILE_INTERNAL_H_ +#define UPB_MINI_TABLE_FILE_INTERNAL_H_ + + +// Must be last. + +struct upb_MiniTableFile { + const upb_MiniTable** msgs; + const upb_MiniTableEnum** enums; + const upb_MiniTableExtension** exts; + int msg_count; + int enum_count; + int ext_count; +}; + + +#endif /* UPB_MINI_TABLE_FILE_INTERNAL_H_ */ + +#ifndef UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ +#define UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ + + +// Must be last. + +struct upb_Decoder; +typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data); +typedef struct { + uint64_t field_data; + _upb_FieldParser* field_parser; +} _upb_FastTable_Entry; typedef enum { kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. @@ -1704,51 +1843,32 @@ typedef enum { kUpb_ExtMode_IsMapEntry = 4, } upb_ExtMode; -/* MessageSet wire format is: - * message MessageSet { - * repeated group Item = 1 { - * required int32 type_id = 2; - * required bytes message = 3; - * } - * } - */ -typedef enum { - _UPB_MSGSET_ITEM = 1, - _UPB_MSGSET_TYPEID = 2, - _UPB_MSGSET_MESSAGE = 3, -} upb_msgext_fieldnum; - +// upb_MiniTable represents the memory layout of a given upb_MessageDef. +// The members are public so generated code can initialize them, +// but users MUST NOT directly read or write any of its members. struct upb_MiniTable { - const upb_MiniTable_Sub* subs; - const upb_MiniTable_Field* fields; - /* Must be aligned to sizeof(void*). Doesn't include internal members like - * unknown fields, extension dict, pointer to msglayout, etc. */ + const upb_MiniTableSub* subs; + const upb_MiniTableField* fields; + + // Must be aligned to sizeof(void*). Doesn't include internal members like + // unknown fields, extension dict, pointer to msglayout, etc. uint16_t size; + uint16_t field_count; uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1 uint8_t dense_below; uint8_t table_mask; uint8_t required_count; // Required fields have the lowest hasbits. - /* To statically initialize the tables of variable length, we need a flexible - * array member, and we need to compile in gnu99 mode (constant initialization - * of flexible array members is a GNU extension, not in C99 unfortunately. */ - _upb_FastTable_Entry fasttable[]; -}; -struct upb_MiniTable_Extension { - upb_MiniTable_Field field; - const upb_MiniTable* extendee; - upb_MiniTable_Sub sub; /* NULL unless submessage or proto2 enum */ + // To statically initialize the tables of variable length, we need a flexible + // array member, and we need to compile in gnu99 mode (constant initialization + // of flexible array members is a GNU extension, not in C99 unfortunately. + _upb_FastTable_Entry fasttable[]; }; -typedef struct { - const upb_MiniTable** msgs; - const upb_MiniTable_Enum** enums; - const upb_MiniTable_Extension** exts; - int msg_count; - int enum_count; - int ext_count; -} upb_MiniTable_File; +#ifdef __cplusplus +extern "C" { +#endif // Computes a bitmask in which the |l->required_count| lowest bits are set, // except that we skip the lowest bit (because upb never uses hasbit 0). @@ -1762,7 +1882,22 @@ UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) { return ((1ULL << n) - 1) << 1; } -/** upb_Message ***************************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +extern const float kUpb_FltInfinity; +extern const double kUpb_Infinity; +extern const double kUpb_NaN; /* Internal members of a upb_Message that track unknown fields and/or * extensions. We can change this without breaking binary compatibility. We put @@ -1801,11 +1936,11 @@ typedef struct { /* Maps upb_CType -> memory size. */ extern char _upb_CTypeo_size[12]; -UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) { - return l->size + sizeof(upb_Message_Internal); +UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* t) { + return t->size + sizeof(upb_Message_Internal); } -/* Inline version upb_Message_New(), for internal use */ +// Inline version upb_Message_New(), for internal use. UPB_INLINE upb_Message* _upb_Message_New(const upb_MiniTable* mini_table, upb_Arena* arena) { size_t size = upb_msg_sizeof(mini_table); @@ -1816,266 +1951,186 @@ UPB_INLINE upb_Message* _upb_Message_New(const upb_MiniTable* mini_table, return msg; } -UPB_INLINE upb_Message_Internal* upb_Message_Getinternal(upb_Message* msg) { +UPB_INLINE upb_Message_Internal* upb_Message_Getinternal( + const upb_Message* msg) { ptrdiff_t size = sizeof(upb_Message_Internal); return (upb_Message_Internal*)((char*)msg - size); } -/* Clears the given message. */ +// Clears the given message. void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l); -/* Discards the unknown fields for this message only. */ +// Discards the unknown fields for this message only. void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ +// Adds unknown data (serialized protobuf data) to the given message. +// The data is copied into the message instance. bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, upb_Arena* arena); -/** 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 - * to look it up in a upb_ExtensionRegistry. - * - * This representation allocates 16 bytes to data on 64-bit platforms. This is - * rather wasteful for scalars (in the extreme case of bool, it wastes 15 - * bytes). We accept this because we expect messages to be the most common - * extension type. */ +/* Map entries aren't actually stored, they are only used during parsing. For + * parsing, it helps a lot if all map entry messages have the same layout. + * The compiler and def.c must ensure that all map entries have this layout. */ typedef struct { - const upb_MiniTable_Extension* ext; + upb_Message_Internal internal; union { - upb_StringView str; - void* ptr; - char scalar_data[8]; - } data; -} upb_Message_Extension; - -/* 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_GetOrCreateExtension( - upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena); - -/* Returns an array of extensions for this message. Note: the array is - * ordered in reverse relative to the order of creation. */ -const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, - size_t* count); - -/* Returns an extension for the given field number, or NULL if no extension - * exists for this field number. */ -const upb_Message_Extension* _upb_Message_Getext( - const upb_Message* msg, const upb_MiniTable_Extension* ext); + upb_StringView str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } k; + union { + upb_StringView str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } v; +} upb_MapEntry; -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext); +#ifdef __cplusplus +} /* extern "C" */ +#endif -/** Hasbit access *************************************************************/ -UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) { - return (*UPB_PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; -} +#endif /* UPB_MESSAGE_INTERNAL_H_ */ -UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) { - (*UPB_PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); -} +// Must be last. -UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) { - (*UPB_PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTable_Field* f) { - UPB_ASSERT(f->presence > 0); - return f->presence; -} +// _upb_mapsorter sorts maps and provides ordered iteration over the entries. +// Since maps can be recursive (map values can be messages which contain other +// maps), _upb_mapsorter can contain a stack of maps. -UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_hasbit(msg, _upb_Message_Hasidx(f)); -} +typedef struct { + upb_tabent const** entries; + int size; + int cap; +} _upb_mapsorter; -UPB_INLINE void _upb_sethas_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - _upb_sethas(msg, _upb_Message_Hasidx(f)); -} +typedef struct { + int start; + int pos; + int end; +} _upb_sortedmap; -UPB_INLINE void _upb_clearhas_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - _upb_clearhas(msg, _upb_Message_Hasidx(f)); +UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { + s->entries = NULL; + s->size = 0; + s->cap = 0; } -/** Oneof case access *********************************************************/ - -UPB_INLINE uint32_t* _upb_oneofcase(upb_Message* msg, size_t case_ofs) { - return UPB_PTR_AT(msg, case_ofs, uint32_t); +UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { + if (s->entries) free(s->entries); } -UPB_INLINE uint32_t _upb_getoneofcase(const void* msg, size_t case_ofs) { - return *UPB_PTR_AT(msg, case_ofs, uint32_t); +UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, + _upb_sortedmap* sorted, upb_MapEntry* ent) { + if (sorted->pos == sorted->end) return false; + const upb_tabent* tabent = s->entries[sorted->pos++]; + upb_StringView key = upb_tabstrview(tabent->key); + _upb_map_fromkey(key, &ent->k, map->key_size); + upb_value val = {tabent->val.val}; + _upb_map_fromvalue(val, &ent->v, map->val_size); + return true; } -UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTable_Field* f) { - UPB_ASSERT(f->presence < 0); - return ~(ptrdiff_t)f->presence; +UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, + _upb_sortedmap* sorted) { + s->size = sorted->start; } -UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_oneofcase(msg, _upb_oneofcase_ofs(f)); -} +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted); -UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f)); -} +#ifdef __cplusplus +} /* extern "C" */ +#endif -UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_Message* msg, size_t ofs) { - return *UPB_PTR_AT(msg, ofs, const upb_Message*) != NULL; -} -/** upb_Map *******************************************************************/ +#endif /* UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ */ -/* Right now we use strmaps for everything. We'll likely want to use - * integer-specific maps for integer-keyed maps.*/ -struct upb_Map { - /* Size of key and val, based on the map type. Strings are represented as '0' - * because they must be handled specially. */ - char key_size; - char val_size; +#ifndef UPB_MINI_TABLE_ENUM_INTERNAL_H_ +#define UPB_MINI_TABLE_ENUM_INTERNAL_H_ - upb_strtable table; -}; -/* Map entries aren't actually stored, they are only used during parsing. For - * parsing, it helps a lot if all map entry messages have the same layout. - * The compiler and def.c must ensure that all map entries have this layout. */ -typedef struct { - upb_Message_Internal internal; - union { - upb_StringView str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } k; - union { - upb_StringView str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } v; -} upb_MapEntry; +// Must be last. -/* Creates a new map on the given arena with this key/value type. */ -upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); +struct upb_MiniTableEnum { + uint32_t mask_limit; // Limit enum value that can be tested with mask. + uint32_t value_count; // Number of values after the bitfield. + uint32_t data[]; // Bitmask + enumerated values follow. +}; -/* Converting between internal table representation and user values. - * - * _upb_map_tokey() and _upb_map_fromkey() are inverses. - * _upb_map_tovalue() and _upb_map_fromvalue() are inverses. - * - * These functions account for the fact that strings are treated differently - * from other types when stored in a map. - */ +typedef enum { + _kUpb_FastEnumCheck_ValueIsInEnum = 0, + _kUpb_FastEnumCheck_ValueIsNotInEnum = 1, + _kUpb_FastEnumCheck_CannotCheckFast = 2, +} _kUpb_FastEnumCheck_Status; -UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - return *(upb_StringView*)key; - } else { - return upb_StringView_FromDataAndSize((const char*)key, size); - } -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - memcpy(out, &key, sizeof(key)); - } else { - memcpy(out, key.data, size); - } +UPB_INLINE _kUpb_FastEnumCheck_Status +_upb_MiniTable_CheckEnumValueFast(const upb_MiniTableEnum* e, uint32_t val) { + if (UPB_UNLIKELY(val >= 64)) return _kUpb_FastEnumCheck_CannotCheckFast; + uint64_t mask = e->data[0] | ((uint64_t)e->data[1] << 32); + return (mask & (1ULL << val)) ? _kUpb_FastEnumCheck_ValueIsInEnum + : _kUpb_FastEnumCheck_ValueIsNotInEnum; } -UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, - upb_value* msgval, upb_Arena* a) { - if (size == UPB_MAPTYPE_STRING) { - upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); - if (!strp) return false; - *strp = *(upb_StringView*)val; - *msgval = upb_value_ptr(strp); - } else { - memcpy(msgval, val, size); +UPB_INLINE bool _upb_MiniTable_CheckEnumValueSlow(const upb_MiniTableEnum* e, + uint32_t val) { + if (val < e->mask_limit) return e->data[val / 32] & (1ULL << (val % 32)); + // OPT: binary search long lists? + const uint32_t* start = &e->data[e->mask_limit / 32]; + const uint32_t* limit = &e->data[(e->mask_limit / 32) + e->value_count]; + for (const uint32_t* p = start; p < limit; p++) { + if (*p == val) return true; } - return true; + return false; } -UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); - memcpy(out, strp, sizeof(upb_StringView)); - } else { - memcpy(out, &val, size); +// Validates enum value against range defined by enum mini table. +UPB_INLINE bool upb_MiniTableEnum_CheckValue(const upb_MiniTableEnum* e, + uint32_t val) { + _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, val); + if (UPB_UNLIKELY(status == _kUpb_FastEnumCheck_CannotCheckFast)) { + return _upb_MiniTable_CheckEnumValueSlow(e, val); } + return status == _kUpb_FastEnumCheck_ValueIsInEnum ? true : false; } -/* Map operations, shared by reflection and generated code. */ +#ifdef __cplusplus +} /* extern "C" */ +#endif -UPB_INLINE size_t _upb_Map_Size(const upb_Map* map) { - return map->table.t.count; -} -UPB_INLINE bool _upb_Map_Get(const upb_Map* map, const void* key, - size_t key_size, void* val, size_t val_size) { - upb_value tabval; - upb_StringView k = _upb_map_tokey(key, key_size); - bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); - if (ret && val) { - _upb_map_fromvalue(tabval, val, val_size); - } - return ret; -} +#endif /* UPB_MINI_TABLE_ENUM_INTERNAL_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_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { - upb_strtable_iter it; - it.t = &map->table; - it.index = *iter; - upb_strtable_next(&it); - *iter = it.index; - if (upb_strtable_done(&it)) return NULL; - return (void*)str_tabent(&it); -} +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ -typedef enum { - // LINT.IfChange - _kUpb_MapInsertStatus_Inserted = 0, - _kUpb_MapInsertStatus_Replaced = 1, - _kUpb_MapInsertStatus_OutOfMemory = 2, - // LINT.ThenChange(//depot/google3/third_party/upb/upb/map.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 _kUpb_MapInsertStatus_OutOfMemory; - } - /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - 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; -} +// These functions are only used by generated code. -UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, - size_t key_size) { - upb_StringView k = _upb_map_tokey(key, key_size); - return upb_strtable_remove2(&map->table, k.data, k.size, NULL); -} +#ifndef UPB_COLLECTIONS_MAP_GENCODE_UTIL_H_ +#define UPB_COLLECTIONS_MAP_GENCODE_UTIL_H_ -UPB_INLINE void _upb_Map_Clear(upb_Map* map) { - upb_strtable_clear(&map->table); -} -/* Message map operations, these get the map from the message first. */ +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Message map operations, these get the map from the message first. UPB_INLINE size_t _upb_msg_map_size(const upb_Message* msg, size_t ofs) { upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); @@ -2105,7 +2160,7 @@ UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, *map = _upb_Map_New(arena, key_size, val_size); } return _upb_Map_Insert(*map, key, key_size, val, val_size, arena) != - _kUpb_MapInsertStatus_OutOfMemory; + kUpb_MapInsertStatus_OutOfMemory; } UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs, @@ -2121,8 +2176,6 @@ UPB_INLINE void _upb_msg_map_clear(upb_Message* msg, size_t ofs) { _upb_Map_Clear(map); } -/* Accessing map key/value from a pointer, used by generated code only. */ - UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { const upb_tabent* ent = (const upb_tabent*)msg; uint32_t u32len; @@ -2141,8 +2194,8 @@ UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size) { upb_tabent* ent = (upb_tabent*)msg; - /* This is like _upb_map_tovalue() except the entry already exists so we can - * reuse the allocated upb_StringView for string fields. */ + // This is like _upb_map_tovalue() except the entry already exists + // so we can reuse the allocated upb_StringView for string fields. if (size == UPB_MAPTYPE_STRING) { upb_StringView* strp = (upb_StringView*)(uintptr_t)ent->val.val; memcpy(strp, val, sizeof(*strp)); @@ -2156,82 +2209,577 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, #endif -#endif /* UPB_MSG_INT_H_ */ +#endif /* UPB_COLLECTIONS_MAP_GENCODE_UTIL_H_ */ + +#ifndef UPB_MESSAGE_ACCESSORS_H_ +#define UPB_MESSAGE_ACCESSORS_H_ + + +#ifndef UPB_MINI_TABLE_COMMON_H_ +#define UPB_MINI_TABLE_COMMON_H_ + + +// Must be last. + +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 enum { + kUpb_MessageModifier_ValidateUtf8 = 1 << 0, + kUpb_MessageModifier_DefaultIsPacked = 1 << 1, + kUpb_MessageModifier_IsExtendable = 1 << 2, +} kUpb_MessageModifier; + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MiniTableField* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number); + +upb_FieldType upb_MiniTableField_Type(const upb_MiniTableField* field); + +UPB_INLINE bool upb_MiniTableField_IsExtension( + const upb_MiniTableField* field) { + return field->mode & kUpb_LabelFlags_IsExtension; +} + +UPB_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* mini_table, const upb_MiniTableField* field) { + return mini_table->subs[field->submsg_index].submsg; +} + +UPB_INLINE const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable( + const upb_MiniTable* mini_table, const upb_MiniTableField* field) { + return mini_table->subs[field->submsg_index].subenum; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_COMMON_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool _upb_MiniTableField_InOneOf(const upb_MiniTableField* field) { + return field->presence < 0; +} + +UPB_INLINE void* _upb_MiniTableField_GetPtr(upb_Message* msg, + const upb_MiniTableField* field) { + return (char*)msg + field->offset; +} + +UPB_INLINE const void* _upb_MiniTableField_GetConstPtr( + const upb_Message* msg, const upb_MiniTableField* field) { + return (char*)msg + field->offset; +} + +UPB_INLINE void _upb_MiniTable_SetPresence(upb_Message* msg, + const upb_MiniTableField* field) { + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (_upb_MiniTableField_InOneOf(field)) { + *_upb_oneofcase_field(msg, field) = field->number; + } +} + +UPB_INLINE bool upb_MiniTable_HasField(const upb_Message* msg, + const upb_MiniTableField* field); + +UPB_INLINE bool _upb_MiniTable_DefaultIsNonZero( + const void* default_val, const upb_MiniTableField* field) { + char zero[16] = {0}; + switch (_upb_MiniTableField_GetRep(field)) { + case kUpb_FieldRep_1Byte: + return memcmp(&zero, default_val, 1) != 0; + case kUpb_FieldRep_4Byte: + return memcmp(&zero, default_val, 4) != 0; + case kUpb_FieldRep_8Byte: + return memcmp(&zero, default_val, 8) != 0; + case kUpb_FieldRep_StringView: { + const upb_StringView* sv = (const upb_StringView*)default_val; + return sv->size != 0; + } + } + UPB_UNREACHABLE(); +} + +UPB_INLINE void _upb_MiniTable_CopyFieldData(void* to, const void* from, + const upb_MiniTableField* field) { + switch (_upb_MiniTableField_GetRep(field)) { + case kUpb_FieldRep_1Byte: + memcpy(to, from, 1); + return; + case kUpb_FieldRep_4Byte: + memcpy(to, from, 4); + return; + case kUpb_FieldRep_8Byte: + memcpy(to, from, 8); + return; + case kUpb_FieldRep_StringView: { + memcpy(to, from, sizeof(upb_StringView)); + return; + } + } + UPB_UNREACHABLE(); +} + +// Here we define universal getter/setter functions for message fields. +// These look very branchy and inefficient, but as long as the MiniTableField +// values are known at compile time, all the branches are optimized away and +// we are left with ideal code. This can happen either through through +// literals or UPB_ASSUME(): +// +// // Via string literals. +// bool FooMessage_set_bool_field(const upb_Message* msg, bool val) { +// const upb_MiniTableField field = {1, 0, 0, /* etc... */}; +// // All value in "field" are compile-time known. +// _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +// } +// +// // Via UPB_ASSUME(). +// UPB_INLINE void upb_MiniTable_SetBool(upb_Message* msg, +// const upb_MiniTableField* field, +// bool value) { +// UPB_ASSUME(field->descriptortype == kUpb_FieldType_Bool); +// UPB_ASSUME(!upb_IsRepeatedOrMap(field)); +// UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte); +// _upb_MiniTable_SetNonExtensionField(msg, field, &value); +// } +// +// As a result, we can use these universal getters/setters for *all* message +// accessors: generated code, MiniTable accessors, and reflection. The only +// exception is the binary encoder/decoder, which need to be a bit more clever +// about how the read/write the message data, for efficiency. + +static UPB_FORCEINLINE void _upb_MiniTable_GetNonExtensionField( + const upb_Message* msg, const upb_MiniTableField* field, + const void* default_val, void* val) { + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + if ((_upb_MiniTableField_InOneOf(field) || + _upb_MiniTable_DefaultIsNonZero(default_val, field)) && + !upb_MiniTable_HasField(msg, field)) { + _upb_MiniTable_CopyFieldData(val, default_val, field); + return; + } + _upb_MiniTable_CopyFieldData(val, _upb_MiniTableField_GetConstPtr(msg, field), + field); +} + +UPB_INLINE void _upb_MiniTable_GetExtensionField( + const upb_Message* msg, const upb_MiniTableExtension* mt_ext, + const void* default_val, void* val) { + UPB_ASSUME(upb_MiniTableField_IsExtension(&mt_ext->field)); + const upb_Message_Extension* ext = _upb_Message_Getext(msg, mt_ext); + if (ext) { + _upb_MiniTable_CopyFieldData(val, &ext->data, &mt_ext->field); + } else { + _upb_MiniTable_CopyFieldData(val, default_val, &mt_ext->field); + } +} + +UPB_INLINE void _upb_MiniTable_GetField(const upb_Message* msg, + const upb_MiniTableField* field, + const void* default_val, void* val) { + if (upb_MiniTableField_IsExtension(field)) { + _upb_MiniTable_GetExtensionField(msg, (upb_MiniTableExtension*)field, + default_val, val); + } else { + _upb_MiniTable_GetNonExtensionField(msg, field, default_val, val); + } +} + +UPB_INLINE void _upb_MiniTable_SetNonExtensionField( + upb_Message* msg, const upb_MiniTableField* field, const void* val) { + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + _upb_MiniTable_SetPresence(msg, field); + _upb_MiniTable_CopyFieldData(_upb_MiniTableField_GetPtr(msg, field), val, + field); +} + +UPB_INLINE bool _upb_MiniTable_SetExtensionField( + upb_Message* msg, const upb_MiniTableExtension* mt_ext, const void* val, + upb_Arena* a) { + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, mt_ext, a); + if (!ext) return false; + _upb_MiniTable_CopyFieldData(&ext->data, val, &mt_ext->field); + return true; +} + +UPB_INLINE bool _upb_MiniTable_SetField(upb_Message* msg, + const upb_MiniTableField* field, + const void* val, upb_Arena* a) { + if (upb_MiniTableField_IsExtension(field)) { + return _upb_MiniTable_SetExtensionField( + msg, (const upb_MiniTableExtension*)field, val, a); + } else { + _upb_MiniTable_SetNonExtensionField(msg, field, val); + return true; + } +} + +// EVERYTHING ABOVE THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +void upb_MiniTable_ClearField(upb_Message* msg, + const upb_MiniTableField* field); + +UPB_INLINE bool upb_MiniTable_HasField(const upb_Message* msg, + const upb_MiniTableField* field) { + if (_upb_MiniTableField_InOneOf(field)) { + return _upb_getoneofcase_field(msg, field) == field->number; + } + + UPB_ASSERT(field->presence > 0); + return _upb_hasbit_field(msg, field); +} + +UPB_INLINE bool upb_MiniTable_GetBool(const upb_Message* msg, + const upb_MiniTableField* field, + bool default_val) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_Bool); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte); + bool ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} + +UPB_INLINE void upb_MiniTable_SetBool(upb_Message* msg, + const upb_MiniTableField* field, + bool value) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_Bool); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE int32_t upb_MiniTable_GetInt32(const upb_Message* msg, + const upb_MiniTableField* field, + int32_t default_val) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_Int32 || + field->descriptortype == kUpb_FieldType_SInt32 || + field->descriptortype == kUpb_FieldType_SFixed32 || + field->descriptortype == kUpb_FieldType_Enum); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + int32_t ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} + +UPB_INLINE void upb_MiniTable_SetInt32(upb_Message* msg, + const upb_MiniTableField* field, + int32_t value) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_Int32 || + field->descriptortype == kUpb_FieldType_SInt32 || + field->descriptortype == kUpb_FieldType_SFixed32); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE uint32_t upb_MiniTable_GetUInt32(const upb_Message* msg, + const upb_MiniTableField* field, + uint32_t default_val) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_UInt32 || + field->descriptortype == kUpb_FieldType_Fixed32); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + uint32_t ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} + +UPB_INLINE void upb_MiniTable_SetUInt32(upb_Message* msg, + const upb_MiniTableField* field, + uint32_t value) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_UInt32 || + field->descriptortype == kUpb_FieldType_Fixed32); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE void upb_MiniTable_SetEnumProto2(upb_Message* msg, + const upb_MiniTable* msg_mini_table, + const upb_MiniTableField* field, + int32_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + UPB_ASSERT(upb_MiniTableEnum_CheckValue( + upb_MiniTable_GetSubEnumTable(msg_mini_table, field), value)); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE int64_t upb_MiniTable_GetInt64(const upb_Message* msg, + const upb_MiniTableField* field, + uint64_t default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int64 || + field->descriptortype == kUpb_FieldType_SInt64 || + field->descriptortype == kUpb_FieldType_SFixed64); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + int64_t ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} + +UPB_INLINE void upb_MiniTable_SetInt64(upb_Message* msg, + const upb_MiniTableField* field, + int64_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int64 || + field->descriptortype == kUpb_FieldType_SInt64 || + field->descriptortype == kUpb_FieldType_SFixed64); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE uint64_t upb_MiniTable_GetUInt64(const upb_Message* msg, + const upb_MiniTableField* field, + uint64_t default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt64 || + field->descriptortype == kUpb_FieldType_Fixed64); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + uint64_t ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} + +UPB_INLINE void upb_MiniTable_SetUInt64(upb_Message* msg, + const upb_MiniTableField* field, + uint64_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt64 || + field->descriptortype == kUpb_FieldType_Fixed64); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE float upb_MiniTable_GetFloat(const upb_Message* msg, + const upb_MiniTableField* field, + float default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Float); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + float ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} + +UPB_INLINE void upb_MiniTable_SetFloat(upb_Message* msg, + const upb_MiniTableField* field, + float value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Float); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE double upb_MiniTable_GetDouble(const upb_Message* msg, + const upb_MiniTableField* field, + double default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Double); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + double ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} + +UPB_INLINE void upb_MiniTable_SetDouble(upb_Message* msg, + const upb_MiniTableField* field, + double value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Double); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE upb_StringView +upb_MiniTable_GetString(const upb_Message* msg, const upb_MiniTableField* field, + upb_StringView def_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bytes || + field->descriptortype == kUpb_FieldType_String); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_StringView); + upb_StringView ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &def_val, &ret); + return ret; +} + +UPB_INLINE void upb_MiniTable_SetString(upb_Message* msg, + const upb_MiniTableField* field, + upb_StringView value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bytes || + field->descriptortype == kUpb_FieldType_String); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_StringView); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE const upb_Message* upb_MiniTable_GetMessage( + const upb_Message* msg, const upb_MiniTableField* field, + upb_Message* default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + upb_Message* ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} -// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// +UPB_INLINE void upb_MiniTable_SetMessage(upb_Message* msg, + const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* sub_message) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + UPB_ASSERT(mini_table->subs[field->submsg_index].submsg); + _upb_MiniTable_SetNonExtensionField(msg, field, &sub_message); +} + +UPB_INLINE upb_Message* upb_MiniTable_GetMutableMessage( + upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTableField* field, upb_Arena* arena) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + upb_Message* sub_message = *UPB_PTR_AT(msg, field->offset, upb_Message*); + if (!sub_message) { + const upb_MiniTable* sub_mini_table = + mini_table->subs[field->submsg_index].submsg; + UPB_ASSERT(sub_mini_table); + sub_message = _upb_Message_New(sub_mini_table, arena); + *UPB_PTR_AT(msg, field->offset, upb_Message*) = sub_message; + _upb_MiniTable_SetPresence(msg, field); + } + return sub_message; +} -#ifndef UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ -#define UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ +UPB_INLINE const upb_Array* upb_MiniTable_GetArray( + const upb_Message* msg, const upb_MiniTableField* field) { + const upb_Array* ret; + const upb_Array* default_val = NULL; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} +UPB_INLINE upb_Array* upb_MiniTable_GetMutableArray( + upb_Message* msg, const upb_MiniTableField* field) { + return (upb_Array*)upb_MiniTable_GetArray(msg, field); +} -// Must be last. +void* upb_MiniTable_ResizeArray(upb_Message* msg, + const upb_MiniTableField* field, size_t len, + upb_Arena* arena); +typedef enum { + kUpb_GetExtension_Ok, + kUpb_GetExtension_NotPresent, + kUpb_GetExtension_ParseError, + kUpb_GetExtension_OutOfMemory, +} upb_GetExtension_Status; -#ifdef __cplusplus -extern "C" { -#endif +typedef enum { + kUpb_GetExtensionAsBytes_Ok, + kUpb_GetExtensionAsBytes_NotPresent, + kUpb_GetExtensionAsBytes_EncodeError, +} upb_GetExtensionAsBytes_Status; -// _upb_mapsorter sorts maps and provides ordered iteration over the entries. -// Since maps can be recursive (map values can be messages which contain other -// maps), _upb_mapsorter can contain a stack of maps. +// Returns a message extension or promotes an unknown field to +// an extension. +// +// TODO(ferhat): Only supports extension fields that are messages, +// expand support to include non-message types. +upb_GetExtension_Status upb_MiniTable_GetOrPromoteExtension( + upb_Message* msg, const upb_MiniTableExtension* ext_table, + int decode_options, upb_Arena* arena, + const upb_Message_Extension** extension); + +// Returns a message extension or unknown field matching the extension +// data as bytes. +// +// If an extension has already been decoded it will be re-encoded +// to bytes. +upb_GetExtensionAsBytes_Status upb_MiniTable_GetExtensionAsBytes( + const upb_Message* msg, const upb_MiniTableExtension* ext_table, + int encode_options, upb_Arena* arena, const char** extension_data, + size_t* len); -typedef struct { - upb_tabent const** entries; - int size; - int cap; -} _upb_mapsorter; +typedef enum { + kUpb_FindUnknown_Ok, + kUpb_FindUnknown_NotPresent, + kUpb_FindUnknown_ParseError, +} upb_FindUnknown_Status; typedef struct { - int start; - int pos; - int end; -} _upb_sortedmap; - -UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { - s->entries = NULL; - s->size = 0; - s->cap = 0; -} + upb_FindUnknown_Status status; + // Start of unknown field data in message arena. + const char* ptr; + // Size of unknown field data. + size_t len; +} upb_FindUnknownRet; -UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { - if (s->entries) free(s->entries); -} +// Finds first occurrence of unknown data by tag id in message. +upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg, + uint32_t field_number); -UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, - _upb_sortedmap* sorted, upb_MapEntry* ent) { - if (sorted->pos == sorted->end) return false; - const upb_tabent* tabent = s->entries[sorted->pos++]; - upb_StringView key = upb_tabstrview(tabent->key); - _upb_map_fromkey(key, &ent->k, map->key_size); - upb_value val = {tabent->val.val}; - _upb_map_fromvalue(val, &ent->v, map->val_size); - return true; -} +typedef enum { + kUpb_UnknownToMessage_Ok, + kUpb_UnknownToMessage_ParseError, + kUpb_UnknownToMessage_OutOfMemory, + kUpb_UnknownToMessage_NotFound, +} upb_UnknownToMessage_Status; -UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, - _upb_sortedmap* sorted) { - s->size = sorted->start; -} +typedef struct { + upb_UnknownToMessage_Status status; + upb_Message* message; +} upb_UnknownToMessageRet; -bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, - const upb_Map* map, _upb_sortedmap* sorted); +// Promotes unknown data inside message to a upb_Message parsing the unknown. +// +// The unknown data is removed from message after field value is set +// using upb_MiniTable_SetMessage. +upb_UnknownToMessageRet upb_MiniTable_PromoteUnknownToMessage( + upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTableField* field, const upb_MiniTable* sub_mini_table, + int decode_options, upb_Arena* arena); + +// Promotes all unknown data that matches field tag id to repeated messages +// in upb_Array. +// +// The unknown data is removed from message after upb_Array is populated. +// Since repeated messages can't be packed we remove each unknown that +// contains the target tag id. +upb_UnknownToMessage_Status upb_MiniTable_PromoteUnknownToMessageArray( + upb_Message* msg, const upb_MiniTableField* field, + const upb_MiniTable* mini_table, int decode_options, upb_Arena* arena); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_COLLECTIONS_MAP_SORTER_INTERNAL_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_ - +#endif // UPB_MESSAGE_ACCESSORS_H_ // upb_decode: parsing into a upb_Message using a upb_MiniTable. @@ -2434,9 +2982,7 @@ TAGBYTES(r) #endif /* UPB_WIRE_DECODE_FAST_H_ */ -/* - * upb_Encode: parsing from a upb_Message using a upb_MiniTable. - */ +// upb_Encode: parsing from a upb_Message using a upb_MiniTable. #ifndef UPB_WIRE_ENCODE_H_ #define UPB_WIRE_ENCODE_H_ @@ -2604,13 +3150,13 @@ typedef enum { } google_protobuf_MethodOptions_IdempotencyLevel; -extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init; -extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init; -extern const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init; -extern const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init; -extern const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init; -extern const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init; -extern const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_init; +extern const upb_MiniTableEnum google_protobuf_FieldDescriptorProto_Label_enum_init; +extern const upb_MiniTableEnum google_protobuf_FieldDescriptorProto_Type_enum_init; +extern const upb_MiniTableEnum google_protobuf_FieldOptions_CType_enum_init; +extern const upb_MiniTableEnum google_protobuf_FieldOptions_JSType_enum_init; +extern const upb_MiniTableEnum google_protobuf_FileOptions_OptimizeMode_enum_init; +extern const upb_MiniTableEnum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init; +extern const upb_MiniTableEnum google_protobuf_MethodOptions_IdempotencyLevel_enum_init; /* google.protobuf.FileDescriptorSet */ @@ -2648,24 +3194,24 @@ UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_pro return ptr; } UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_FileDescriptorSet_clear_file(const google_protobuf_FileDescriptorSet* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_FileDescriptorProto**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -2713,7 +3259,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_name(const google_prot _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(40, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 2); @@ -2723,7 +3273,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_package(const google_p _upb_clearhas(msg, 2); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(48, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(48, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_FileDescriptorProto_clear_dependency(const google_protobuf_FileDescriptorProto* msg) { _upb_array_detach(msg, UPB_SIZE(4, 40)); @@ -2775,7 +3329,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_options(const google_p _upb_clearhas(msg, 3); } UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 80), const google_protobuf_FileOptions*); + const google_protobuf_FileOptions* default_val = NULL; + const google_protobuf_FileOptions* ret; + const upb_MiniTableField field = {8, UPB_SIZE(24, 80), 3, 4, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 4); @@ -2785,7 +3343,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_source_code_info(const _upb_clearhas(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(28, 88), const google_protobuf_SourceCodeInfo*); + const google_protobuf_SourceCodeInfo* default_val = NULL; + const google_protobuf_SourceCodeInfo* ret; + const upb_MiniTableField field = {9, UPB_SIZE(28, 88), 4, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_FileDescriptorProto_clear_public_dependency(const google_protobuf_FileDescriptorProto* msg) { _upb_array_detach(msg, UPB_SIZE(32, 96)); @@ -2807,7 +3369,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_syntax(const google_pr _upb_clearhas(msg, 5); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {12, UPB_SIZE(56, 112), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_edition(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 6); @@ -2817,18 +3383,20 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_edition(const google_p _upb_clearhas(msg, 6); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_edition(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {13, UPB_SIZE(64, 128), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(40, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(48, 24), upb_StringView) = value; -} -UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { + const upb_MiniTableField field = {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(48, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(4, 40), len); } UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { @@ -2886,28 +3454,24 @@ UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDesc 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(24, 80), google_protobuf_FileOptions*) = value; -} -UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {8, UPB_SIZE(24, 80), 3, 4, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_FileDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_FileDescriptorProto_set_options(msg, sub); } return sub; } 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(28, 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) { + const upb_MiniTableField field = {9, UPB_SIZE(28, 88), 4, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msg_init, arena); - if (!sub) return NULL; - google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); + if (sub) google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); } return sub; } @@ -2930,14 +3494,12 @@ UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_p return _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 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(56, 112), upb_StringView) = value; + const upb_MiniTableField field = {12, UPB_SIZE(56, 112), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileDescriptorProto_set_edition(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {13, UPB_SIZE(64, 128), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } -UPB_INLINE void google_protobuf_FileDescriptorProto_set_edition(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView) = value; -} - /* google.protobuf.DescriptorProto */ UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_new(upb_Arena* arena) { @@ -2981,7 +3543,11 @@ UPB_INLINE void google_protobuf_DescriptorProto_clear_name(const google_protobuf _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(40, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 24)); @@ -3036,7 +3602,11 @@ UPB_INLINE void google_protobuf_DescriptorProto_clear_options(const google_proto _upb_clearhas(msg, 2); } UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 64), const google_protobuf_MessageOptions*); + const google_protobuf_MessageOptions* default_val = NULL; + const google_protobuf_MessageOptions* ret; + const upb_MiniTableField field = {7, UPB_SIZE(24, 64), 2, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 72)); @@ -3064,10 +3634,9 @@ UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(c } 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(40, 8), upb_StringView) = value; -} -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto* msg, size_t* len) { + const upb_MiniTableField field = {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(4, 24), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { @@ -3128,15 +3697,13 @@ UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_Descript 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(24, 64), google_protobuf_MessageOptions*) = value; -} -UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {7, UPB_SIZE(24, 64), 2, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_DescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_DescriptorProto_set_options(msg, sub); } return sub; } @@ -3213,21 +3780,29 @@ UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const g 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return _upb_hasbit(msg, 3); @@ -3237,27 +3812,27 @@ UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_options(con _upb_clearhas(msg, 3); } 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*); + const google_protobuf_ExtensionRangeOptions* default_val = NULL; + const google_protobuf_ExtensionRangeOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_start(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_end(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(google_protobuf_DescriptorProto_ExtensionRange *msg, google_protobuf_ExtensionRangeOptions* value) { - _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) { + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_end(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(google_protobuf_DescriptorProto_ExtensionRange *msg, google_protobuf_ExtensionRangeOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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_msg_init, arena); - if (!sub) return NULL; - google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); + if (sub) google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); } return sub; } @@ -3301,32 +3876,38 @@ UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const go 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_start(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } - /* google.protobuf.ExtensionRangeOptions */ UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_new(upb_Arena* arena) { @@ -3363,24 +3944,24 @@ UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google return ptr; } UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3428,7 +4009,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_name(const google_pro _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(28, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(28, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 2); @@ -3438,37 +4023,53 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_extendee(const google _upb_clearhas(msg, 2); } UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(36, 40), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(36, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(4, 4), int32_t); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {3, 4, 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(8, 8), int32_t) : 1; + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {4, 8, 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(12, 12), int32_t) : 1; + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {5, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 6); @@ -3478,7 +4079,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type_name(const googl _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(44, 56), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {6, UPB_SIZE(44, 56), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 7); @@ -3488,7 +4093,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_default_value(const g _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(52, 72), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {7, UPB_SIZE(52, 72), 7, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 8); @@ -3498,7 +4107,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_options(const google_ _upb_clearhas(msg, 8); } UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 88), const google_protobuf_FieldOptions*); + const google_protobuf_FieldOptions* default_val = NULL; + const google_protobuf_FieldOptions* ret; + const upb_MiniTableField field = {8, UPB_SIZE(16, 88), 8, 2, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 9); @@ -3508,7 +4121,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_oneof_index(const goo _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(20, 16), int32_t); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {9, UPB_SIZE(20, 16), 9, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 10); @@ -3518,7 +4135,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_json_name(const googl _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(60, 96), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {10, UPB_SIZE(60, 96), 10, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 11); @@ -3528,63 +4149,55 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_proto3_optional(const _upb_clearhas(msg, 11); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 20), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {17, UPB_SIZE(24, 20), 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(28, 24), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(36, 40), upb_StringView) = value; -} -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(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(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(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); - *UPB_PTR_AT(msg, UPB_SIZE(44, 56), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(52, 72), upb_StringView) = value; -} -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(16, 88), google_protobuf_FieldOptions*) = value; -} -UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(28, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(36, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {3, 4, 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {4, 8, 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {5, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {6, UPB_SIZE(44, 56), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {7, UPB_SIZE(52, 72), 7, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) { + const upb_MiniTableField field = {8, UPB_SIZE(16, 88), 8, 2, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_FieldDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_FieldDescriptorProto_set_options(msg, sub); } return sub; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_protobuf_FieldDescriptorProto *msg, int32_t value) { - _upb_sethas(msg, 9); - *UPB_PTR_AT(msg, UPB_SIZE(20, 16), int32_t) = value; -} -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(60, 96), upb_StringView) = value; + const upb_MiniTableField field = {9, UPB_SIZE(20, 16), 9, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {10, UPB_SIZE(60, 96), 10, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { + const upb_MiniTableField field = {17, UPB_SIZE(24, 20), 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { - _upb_sethas(msg, 11); - *UPB_PTR_AT(msg, UPB_SIZE(24, 20), bool) = value; -} - /* google.protobuf.OneofDescriptorProto */ UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_new(upb_Arena* arena) { @@ -3624,11 +4237,15 @@ UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_proto return _upb_hasbit(msg, 1); } UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_name(const google_protobuf_OneofDescriptorProto* msg) { - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + *UPB_PTR_AT(msg, 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(8, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, 8, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto* msg) { return _upb_hasbit(msg, 2); @@ -3638,23 +4255,24 @@ UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_options(const google_ _upb_clearhas(msg, 2); } UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 24), const google_protobuf_OneofOptions*); + const google_protobuf_OneofOptions* default_val = NULL; + const google_protobuf_OneofOptions* ret; + const upb_MiniTableField field = {2, UPB_SIZE(4, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto *msg, google_protobuf_OneofOptions* value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(4, 24), google_protobuf_OneofOptions*) = value; -} -UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {1, 8, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto *msg, google_protobuf_OneofOptions* value) { + const upb_MiniTableField field = {2, UPB_SIZE(4, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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_msg_init, arena); - if (!sub) return NULL; - google_protobuf_OneofDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_OneofDescriptorProto_set_options(msg, sub); } return sub; } @@ -3702,7 +4320,11 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_name(const google_prot _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(20, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(20, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 24)); @@ -3721,7 +4343,11 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_options(const google_p _upb_clearhas(msg, 2); } UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 32), const google_protobuf_EnumOptions*); + const google_protobuf_EnumOptions* default_val = NULL; + const google_protobuf_EnumOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 40)); @@ -3740,10 +4366,9 @@ UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_na } 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(20, 8), upb_StringView) = value; -} -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto* msg, size_t* len) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(4, 24), len); } UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { @@ -3756,15 +4381,13 @@ UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_Enum 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(8, 32), google_protobuf_EnumOptions*) = value; -} -UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_EnumDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_EnumDescriptorProto_set_options(msg, sub); } return sub; } @@ -3829,32 +4452,38 @@ UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start( 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } -UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} - /* google.protobuf.EnumValueDescriptorProto */ UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_new(upb_Arena* arena) { @@ -3898,17 +4527,25 @@ UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_name(const google _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 4, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto* msg) { return _upb_hasbit(msg, 3); @@ -3918,27 +4555,27 @@ UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_options(const goo _upb_clearhas(msg, 3); } UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 24), const google_protobuf_EnumValueOptions*); + const google_protobuf_EnumValueOptions* default_val = NULL; + const google_protobuf_EnumValueOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto *msg, google_protobuf_EnumValueOptions* value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(8, 24), google_protobuf_EnumValueOptions*) = value; -} -UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {2, 4, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto *msg, google_protobuf_EnumValueOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(8, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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_msg_init, arena); - if (!sub) return NULL; - google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); } return sub; } @@ -3986,7 +4623,11 @@ UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_name(const google_p _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 24)); @@ -4005,14 +4646,17 @@ UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_options(const googl _upb_clearhas(msg, 2); } UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 32), const google_protobuf_ServiceOptions*); + const google_protobuf_ServiceOptions* default_val = NULL; + const google_protobuf_ServiceOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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(12, 8), upb_StringView) = value; -} -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto* msg, size_t* len) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(4, 24), len); } UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto* msg, size_t len, upb_Arena* arena) { @@ -4025,15 +4669,13 @@ UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_Service 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(8, 32), google_protobuf_ServiceOptions*) = value; -} -UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_ServiceDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_ServiceDescriptorProto_set_options(msg, sub); } return sub; } @@ -4081,7 +4723,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_name(const google_pr _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 2); @@ -4091,7 +4737,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_input_type(const goo _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(20, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 3); @@ -4101,7 +4751,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_output_type(const go _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(28, 40), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(28, 40), 3, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 4); @@ -4111,7 +4765,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_options(const google _upb_clearhas(msg, 4); } UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 56), const google_protobuf_MethodOptions*); + const google_protobuf_MethodOptions* default_val = NULL; + const google_protobuf_MethodOptions* ret; + const upb_MiniTableField field = {4, UPB_SIZE(4, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 5); @@ -4121,7 +4779,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_client_streaming(con _upb_clearhas(msg, 5); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 1), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, UPB_SIZE(8, 1), 5, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 6); @@ -4131,43 +4793,40 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_server_streaming(con _upb_clearhas(msg, 6); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(9, 2), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {6, UPB_SIZE(9, 2), 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(4, 56), google_protobuf_MethodOptions*) = value; -} -UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {3, UPB_SIZE(28, 40), 3, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value) { + const upb_MiniTableField field = {4, UPB_SIZE(4, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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_msg_init, arena); - if (!sub) return NULL; - google_protobuf_MethodDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_MethodDescriptorProto_set_options(msg, sub); } return sub; } UPB_INLINE void google_protobuf_MethodDescriptorProto_set_client_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 1), bool) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(9, 2), bool) = value; + const upb_MiniTableField field = {5, UPB_SIZE(8, 1), 5, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { + const upb_MiniTableField field = {6, UPB_SIZE(9, 2), 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } - /* google.protobuf.FileOptions */ UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_new(upb_Arena* arena) { @@ -4207,11 +4866,15 @@ UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protob 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(24, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + *UPB_PTR_AT(msg, 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(24, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, 24, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 2); @@ -4221,27 +4884,39 @@ UPB_INLINE void google_protobuf_FileOptions_clear_java_outer_classname(const goo _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(32, 40), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {8, UPB_SIZE(32, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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; + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {9, 4, 3, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {10, 8, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 5); @@ -4251,77 +4926,109 @@ UPB_INLINE void google_protobuf_FileOptions_clear_go_package(const google_protob _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(40, 56), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {11, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {16, 9, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {17, 10, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {18, 11, 8, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {20, 12, 9, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {23, 13, 10, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {27, 14, 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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; + bool default_val = true; + bool ret; + const upb_MiniTableField field = {31, 15, 12, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 13); @@ -4331,7 +5038,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_objc_class_prefix(const google _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(48, 72), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {36, UPB_SIZE(48, 72), 13, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 14); @@ -4341,7 +5052,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_csharp_namespace(const google_ _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(56, 88), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {37, UPB_SIZE(56, 88), 14, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 15); @@ -4351,7 +5066,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_swift_prefix(const google_prot _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(64, 104), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {39, UPB_SIZE(64, 104), 15, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 16); @@ -4361,7 +5080,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_php_class_prefix(const google_ _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(72, 120), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {40, UPB_SIZE(72, 120), 16, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 17); @@ -4371,17 +5094,25 @@ UPB_INLINE void google_protobuf_FileOptions_clear_php_namespace(const google_pro _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(80, 136), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {41, UPB_SIZE(80, 136), 17, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {42, 16, 18, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 19); @@ -4391,7 +5122,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_php_metadata_namespace(const g _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(88, 152), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {44, UPB_SIZE(88, 152), 19, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 20); @@ -4401,7 +5136,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_ruby_package(const google_prot _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(96, 168), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {45, UPB_SIZE(96, 168), 20, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 184)); @@ -4414,86 +5153,66 @@ UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_Fil } UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, int32_t value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 8); - *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 9); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 10); - *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 11); - *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 12); - *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 13); - *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 14); - *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 15); - *UPB_PTR_AT(msg, UPB_SIZE(64, 104), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 16); - *UPB_PTR_AT(msg, UPB_SIZE(72, 120), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 17); - *UPB_PTR_AT(msg, UPB_SIZE(80, 136), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 18); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 19); - *UPB_PTR_AT(msg, UPB_SIZE(88, 152), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 20); - *UPB_PTR_AT(msg, UPB_SIZE(96, 168), upb_StringView) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions* msg, size_t* len) { + const upb_MiniTableField field = {1, 24, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, int32_t value) { + const upb_MiniTableField field = {9, 4, 3, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {10, 8, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {11, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {16, 9, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {17, 10, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {18, 11, 8, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {20, 12, 9, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {23, 13, 10, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {27, 14, 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {31, 15, 12, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {36, UPB_SIZE(48, 72), 13, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {37, UPB_SIZE(56, 88), 14, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {39, UPB_SIZE(64, 104), 15, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {40, UPB_SIZE(72, 120), 16, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {41, UPB_SIZE(80, 136), 17, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_php_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {42, 16, 18, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {44, UPB_SIZE(88, 152), 19, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {45, UPB_SIZE(96, 168), 20, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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(20, 184), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions* msg, size_t len, upb_Arena* arena) { @@ -4545,77 +5264,89 @@ UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 3, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {7, 4, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); + return _upb_has_submsg_nohasbit(msg, 8); } UPB_INLINE void google_protobuf_MessageOptions_clear_uninterpreted_option(const google_protobuf_MessageOptions* msg) { - _upb_array_detach(msg, UPB_SIZE(8, 8)); + _upb_array_detach(msg, 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); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, 8, len); } UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_no_standard_descriptor_accessor(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_deprecated(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_MessageOptions *msg, bool value) { - _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) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); + const upb_MiniTableField field = {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MessageOptions_set_no_standard_descriptor_accessor(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {2, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MessageOptions_set_deprecated(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {3, 3, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {7, 4, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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, 8, len); } 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); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, 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, 8, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4659,71 +5390,99 @@ UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_Fie 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_PTR_AT(msg, 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); + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {1, 4, 1, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(8, 8), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(9, 9), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 9, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(10, 10), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, 10, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(12, 12), int32_t); + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {6, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(16, 16), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {10, 16, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(17, 17), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {15, 17, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); @@ -4736,34 +5495,27 @@ UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_Fie } UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { - _upb_sethas(msg, 2); - *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(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(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(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(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(17, 17), bool) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t* len) { + const upb_MiniTableField field = {1, 4, 1, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {3, 9, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {5, 10, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, int32_t value) { + const upb_MiniTableField field = {6, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {10, 16, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_unverified_lazy(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {15, 17, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t len, upb_Arena* arena) { @@ -4812,24 +5564,24 @@ UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf return ptr; } UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_OneofOptions_clear_uninterpreted_option(const google_protobuf_OneofOptions* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4873,21 +5625,29 @@ UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobu 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); @@ -4900,14 +5660,12 @@ UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_Enu } UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} -UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumOptions *msg, bool value) { - _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) { + const upb_MiniTableField field = {2, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumOptions *msg, bool value) { + const upb_MiniTableField field = {3, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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) { @@ -4959,11 +5717,15 @@ UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_pro 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); @@ -4976,10 +5738,9 @@ UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_Enu } 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) { + const upb_MiniTableField field = {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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) { @@ -5031,11 +5792,15 @@ UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_proto 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); @@ -5048,10 +5813,9 @@ UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_Ser } 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) { + const upb_MiniTableField field = {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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) { @@ -5103,49 +5867,55 @@ UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protob 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_PTR_AT(msg, 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(1, 1), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {34, 4, 2, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); + return _upb_has_submsg_nohasbit(msg, 8); } UPB_INLINE void google_protobuf_MethodOptions_clear_uninterpreted_option(const google_protobuf_MethodOptions* msg) { - _upb_array_detach(msg, UPB_SIZE(8, 8)); + _upb_array_detach(msg, 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); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, 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(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(8, 8), len); +UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) { + const upb_MiniTableField field = {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, int32_t value) { + const upb_MiniTableField field = {34, 4, 2, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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, 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(8, 8), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, 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_msg_init, 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, 8, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -5202,7 +5972,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_identifier_value(const _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(8, 16), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 16), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 2); @@ -5212,7 +5986,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_positive_int_value(con _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(16, 32), uint64_t); + uint64_t default_val = (uint64_t)0ull; + uint64_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(16, 32), 2, kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 3); @@ -5222,7 +6000,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_negative_int_value(con _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(24, 40), int64_t); + int64_t default_val = (int64_t)0ll; + int64_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(24, 40), 3, kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 4); @@ -5232,7 +6014,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_double_value(const goo _upb_clearhas(msg, 4); } UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 48), double); + double default_val = 0; + double ret; + const upb_MiniTableField field = {6, UPB_SIZE(32, 48), 4, kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 5); @@ -5242,7 +6028,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_string_value(const goo _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, 56), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {7, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 6); @@ -5252,7 +6042,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_aggregate_value(const _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, 72), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {8, UPB_SIZE(48, 72), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption* msg, size_t* len) { @@ -5268,30 +6062,24 @@ UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_ 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(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(16, 32), 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(24, 40), int64_t) = value; + const upb_MiniTableField field = {3, UPB_SIZE(8, 16), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 32), 2, kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 40), 3, kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) { + const upb_MiniTableField field = {6, UPB_SIZE(32, 48), 4, kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { + const upb_MiniTableField field = {7, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { + const upb_MiniTableField field = {8, UPB_SIZE(48, 72), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(32, 48), 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, 56), 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, 72), upb_StringView) = value; -} - /* google.protobuf.UninterpretedOption.NamePart */ UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_new(upb_Arena* arena) { @@ -5335,28 +6123,34 @@ UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_name_part(con _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_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(4, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 1, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; + const upb_MiniTableField field = {1, UPB_SIZE(4, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value) { + const upb_MiniTableField field = {2, 1, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } - /* google.protobuf.SourceCodeInfo */ UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new(upb_Arena* arena) { @@ -5393,24 +6187,24 @@ UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protob return ptr; } UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_SourceCodeInfo_clear_location(const google_protobuf_SourceCodeInfo* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_SourceCodeInfo_Location**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -5470,7 +6264,11 @@ UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_comments(c _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(16, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { return _upb_hasbit(msg, 2); @@ -5480,7 +6278,11 @@ UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_trailing_comments( _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(24, 40), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {4, UPB_SIZE(24, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg) { _upb_array_detach(msg, UPB_SIZE(12, 56)); @@ -5508,14 +6310,12 @@ UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf 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(16, 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(24, 40), upb_StringView) = value; -} -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { + const upb_MiniTableField field = {4, UPB_SIZE(24, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(12, 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) { @@ -5561,24 +6361,24 @@ UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_pro return ptr; } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_GeneratedCodeInfo_clear_annotation(const google_protobuf_GeneratedCodeInfo* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -5632,7 +6432,11 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_source_file(c _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(20, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return _upb_hasbit(msg, 2); @@ -5642,7 +6446,11 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_begin(const g _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(8, 4), int32_t); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 4), 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return _upb_hasbit(msg, 3); @@ -5652,7 +6460,11 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_end(const goo _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(12, 8), int32_t); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(12, 8), 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return _upb_hasbit(msg, 4); @@ -5662,7 +6474,11 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_semantic(cons _upb_clearhas(msg, 4); } UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 12), int32_t); + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(16, 12), 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { @@ -5675,23 +6491,19 @@ UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_pro return _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 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(20, 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(8, 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(12, 8), int32_t) = value; -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_semantic(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(16, 12), int32_t) = value; -} - -extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout; + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + const upb_MiniTableField field = {3, UPB_SIZE(8, 4), 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(12, 8), 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_semantic(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(16, 12), 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +} +extern const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout; /* Max size 32 is google.protobuf.FileOptions */ /* Max size 64 is google.protobuf.FileOptions */ @@ -5708,13 +6520,13 @@ extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout #define UPB_REFLECTION_DEF_H_ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_DEF_POOL_H_ #define UPB_REFLECTION_DEF_POOL_H_ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" // Declarations common to all public def types. @@ -5727,11 +6539,13 @@ typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; // Forward declarations for circular references. typedef struct upb_DefPool upb_DefPool; typedef struct upb_EnumDef upb_EnumDef; +typedef struct upb_EnumReservedRange upb_EnumReservedRange; typedef struct upb_EnumValueDef upb_EnumValueDef; typedef struct upb_ExtensionRange upb_ExtensionRange; typedef struct upb_FieldDef upb_FieldDef; typedef struct upb_FileDef upb_FileDef; typedef struct upb_MessageDef upb_MessageDef; +typedef struct upb_MessageReservedRange upb_MessageReservedRange; typedef struct upb_MethodDef upb_MethodDef; typedef struct upb_OneofDef upb_OneofDef; typedef struct upb_ServiceDef upb_ServiceDef; @@ -5824,7 +6638,7 @@ const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, size_t len); const upb_FieldDef* upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext); + const upb_DefPool* s, const upb_MiniTableExtension* ext); const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, const char* sym); @@ -5863,7 +6677,7 @@ const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, #endif /* UPB_REFLECTION_DEF_POOL_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_ENUM_DEF_H_ #define UPB_REFLECTION_ENUM_DEF_H_ @@ -5895,6 +6709,14 @@ bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, const char* upb_EnumDef_Name(const upb_EnumDef* e); const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); + +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); + const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); int upb_EnumDef_ValueCount(const upb_EnumDef* e); @@ -5905,7 +6727,7 @@ int upb_EnumDef_ValueCount(const upb_EnumDef* e); #endif /* UPB_REFLECTION_ENUM_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_ENUM_VALUE_DEF_H_ #define UPB_REFLECTION_ENUM_VALUE_DEF_H_ @@ -5933,7 +6755,7 @@ const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( #endif /* UPB_REFLECTION_ENUM_VALUE_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_EXTENSION_RANGE_H_ #define UPB_REFLECTION_EXTENSION_RANGE_H_ @@ -5959,7 +6781,7 @@ const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( #endif /* UPB_REFLECTION_EXTENSION_RANGE_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_FIELD_DEF_H_ #define UPB_REFLECTION_FIELD_DEF_H_ @@ -6005,7 +6827,7 @@ const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, upb_StringView* out); -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f); +const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f); const char* upb_FieldDef_Name(const upb_FieldDef* f); uint32_t upb_FieldDef_Number(const upb_FieldDef* f); const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f); @@ -6019,7 +6841,7 @@ upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); #endif /* UPB_REFLECTION_FIELD_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_FILE_DEF_H_ #define UPB_REFLECTION_FILE_DEF_H_ @@ -6066,7 +6888,7 @@ int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); #endif /* UPB_REFLECTION_FILE_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_MESSAGE_DEF_H_ #define UPB_REFLECTION_MESSAGE_DEF_H_ @@ -6190,6 +7012,14 @@ const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); int upb_MessageDef_OneofCount(const upb_MessageDef* m); const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m); + +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); + upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); @@ -6200,7 +7030,7 @@ upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); #endif /* UPB_REFLECTION_MESSAGE_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_METHOD_DEF_H_ #define UPB_REFLECTION_METHOD_DEF_H_ @@ -6230,7 +7060,7 @@ const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); #endif /* UPB_REFLECTION_METHOD_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_ONEOF_DEF_H_ #define UPB_REFLECTION_ONEOF_DEF_H_ @@ -6267,7 +7097,7 @@ const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o); #endif /* UPB_REFLECTION_ONEOF_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_SERVICE_DEF_H_ #define UPB_REFLECTION_SERVICE_DEF_H_ @@ -6324,7 +7154,7 @@ upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s); -bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, upb_FieldDef* f); bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, upb_Status* status); @@ -6337,7 +7167,7 @@ size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s); // For generated code only: loads a generated descriptor. typedef struct _upb_DefPool_Init { struct _upb_DefPool_Init** deps; // Dependencies of this file. - const upb_MiniTable_File* layout; + const upb_MiniTableFile* layout; const char* filename; upb_StringView descriptor; // Serialized descriptor. } _upb_DefPool_Init; @@ -6459,272 +7289,124 @@ UPB_INLINE const upb_MessageDef *google_protobuf_EnumValueOptions_getmsgdef(upb_ } UPB_INLINE const upb_MessageDef *google_protobuf_ServiceOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.ServiceOptions"); -} - -UPB_INLINE const upb_MessageDef *google_protobuf_MethodOptions_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.MethodOptions"); -} - -UPB_INLINE const upb_MessageDef *google_protobuf_UninterpretedOption_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.UninterpretedOption"); -} - -UPB_INLINE const upb_MessageDef *google_protobuf_UninterpretedOption_NamePart_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.UninterpretedOption.NamePart"); -} - -UPB_INLINE const upb_MessageDef *google_protobuf_SourceCodeInfo_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.SourceCodeInfo"); -} - -UPB_INLINE const upb_MessageDef *google_protobuf_SourceCodeInfo_Location_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.SourceCodeInfo.Location"); -} - -UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.GeneratedCodeInfo"); -} - -UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_Annotation_getmsgdef(upb_DefPool *s) { - _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); - return upb_DefPool_FindMessageByName(s, "google.protobuf.GeneratedCodeInfo.Annotation"); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ */ - -/* - * Internal implementation details of the decoder that are shared between - * decode.c and decode_fast.c. - */ - -#ifndef UPB_WIRE_DECODE_INTERNAL_H_ -#define UPB_WIRE_DECODE_INTERNAL_H_ - - -#ifndef UPB_MEM_ARENA_INTERNAL_H_ -#define UPB_MEM_ARENA_INTERNAL_H_ - - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -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; -}; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MEM_ARENA_INTERNAL_H_ */ -#include "third_party/utf8_range/utf8_range.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* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status); - -extern const uint8_t upb_utf8_offsets[]; - -UPB_INLINE -bool _upb_Decoder_VerifyUtf8Inline(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* _upb_Decoder_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* _upb_Decoder_IsDoneFallbackInline(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* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, - int overrun); - -UPB_INLINE -bool _upb_Decoder_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 = _upb_Decoder_IsDoneFallback(d, *ptr, overrun); - return false; - } + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.ServiceOptions"); } -#if UPB_FASTTABLE -UPB_INLINE -const char* _upb_FastDecoder_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); +UPB_INLINE const upb_MessageDef *google_protobuf_MethodOptions_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.MethodOptions"); } -#endif -UPB_INLINE uint32_t _upb_FastDecoder_LoadTag(const char* ptr) { - uint16_t tag; - memcpy(&tag, ptr, 2); - return tag; +UPB_INLINE const upb_MessageDef *google_protobuf_UninterpretedOption_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.UninterpretedOption"); } -UPB_INLINE void _upb_Decoder_CheckLimit(upb_Decoder* d) { - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +UPB_INLINE const upb_MessageDef *google_protobuf_UninterpretedOption_NamePart_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.UninterpretedOption.NamePart"); } -UPB_INLINE int _upb_Decoder_PushLimit(upb_Decoder* d, const char* ptr, - int size) { - int limit = size + (int)(ptr - d->end); - int delta = d->limit - limit; - _upb_Decoder_CheckLimit(d); - d->limit = limit; - d->limit_ptr = d->end + UPB_MIN(0, limit); - _upb_Decoder_CheckLimit(d); - return delta; +UPB_INLINE const upb_MessageDef *google_protobuf_SourceCodeInfo_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.SourceCodeInfo"); } -UPB_INLINE void _upb_Decoder_PopLimit(upb_Decoder* d, const char* ptr, - int saved_delta) { - UPB_ASSERT(ptr - d->end == d->limit); - _upb_Decoder_CheckLimit(d); - d->limit += saved_delta; - d->limit_ptr = d->end + UPB_MIN(0, d->limit); - _upb_Decoder_CheckLimit(d); +UPB_INLINE const upb_MessageDef *google_protobuf_SourceCodeInfo_Location_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.SourceCodeInfo.Location"); +} + +UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.GeneratedCodeInfo"); } +UPB_INLINE const upb_MessageDef *google_protobuf_GeneratedCodeInfo_Annotation_getmsgdef(upb_DefPool *s) { + _upb_DefPool_LoadDefInit(s, &google_protobuf_descriptor_proto_upbdefinit); + return upb_DefPool_FindMessageByName(s, "google.protobuf.GeneratedCodeInfo.Annotation"); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPBDEFS_H_ */ + +#ifndef UPB_HASH_INT_TABLE_H_ +#define UPB_HASH_INT_TABLE_H_ + + +// Must be last. + +typedef struct { + upb_table t; // For entries that don't fit in the array part. + const upb_tabval* array; // Array part of the table. See const note above. + size_t array_size; // Array part size. + size_t array_count; // Array part number of elements. +} upb_inttable; + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize a table. If memory allocation failed, false is returned and +// the table is uninitialized. +bool upb_inttable_init(upb_inttable* table, upb_Arena* a); + +// Returns the number of values in the table. +size_t upb_inttable_count(const upb_inttable* t); + +// Inserts the given key into the hashtable with the given value. +// The key must not already exist in the hash table. +// The value must not be UINTPTR_MAX. +// +// If a table resize was required but memory allocation failed, false is +// returned and the table is unchanged. +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a); + +// Looks up key in this table, returning "true" if the key was found. +// If v is non-NULL, copies the value for this key into *v. +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); + +// Removes an item from the table. Returns true if the remove was successful, +// and stores the removed item in *val if non-NULL. +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); + +// Updates an existing entry in an inttable. +// If the entry does not exist, returns false and does nothing. +// Unlike insert/remove, this does not invalidate iterators. +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); + +// Optimizes the table for the current set of entries, for both memory use and +// lookup time. Client should call this after all entries have been inserted; +// inserting more entries is legal, but will likely require a table resize. +void upb_inttable_compact(upb_inttable* t, upb_Arena* a); + +// Iteration over inttable: +// +// intptr_t iter = UPB_INTTABLE_BEGIN; +// uintptr_t key; +// upb_value val; +// while (upb_inttable_next(t, &key, &val, &iter)) { +// // ... +// } + +#define UPB_INTTABLE_BEGIN -1 + +bool upb_inttable_next(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter); +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); + +#ifdef __cplusplus +} /* extern "C" */ +#endif -#endif /* UPB_WIRE_DECODE_INTERNAL_H_ */ + +#endif /* UPB_HASH_INT_TABLE_H_ */ #ifndef UPB_JSON_DECODE_H_ #define UPB_JSON_DECODE_H_ @@ -6749,8 +7431,33 @@ bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, #endif /* UPB_JSONDECODE_H_ */ -#ifndef UPB_INTERNAL_UNICODE_H_ -#define UPB_INTERNAL_UNICODE_H_ +#ifndef UPB_LEX_ATOI_H_ +#define UPB_LEX_ATOI_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// 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. +// Return the new position of the pointer after parsing the int, or NULL on +// integer overflow. + +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val); +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_ATOI_H_ */ + +#ifndef UPB_LEX_UNICODE_H_ +#define UPB_LEX_UNICODE_H_ // Must be last. @@ -6796,7 +7503,7 @@ int upb_Unicode_ToUTF8(uint32_t cp, char* out); #endif -#endif /* UPB_INTERNAL_UNICODE_H_ */ +#endif /* UPB_LEX_UNICODE_H_ */ #ifndef UPB_REFLECTION_MESSAGE_H_ #define UPB_REFLECTION_MESSAGE_H_ @@ -6912,10 +7619,35 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #endif /* UPB_JSONENCODE_H_ */ -#ifndef UPB_INTERNAL_VSNPRINTF_COMPAT_H_ -#define UPB_INTERNAL_VSNPRINTF_COMPAT_H_ +#ifndef UPB_LEX_ROUND_TRIP_H_ +#define UPB_LEX_ROUND_TRIP_H_ -#include +// Must be last. + +// 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 }; + +#ifdef __cplusplus +extern "C" { +#endif + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_ROUND_TRIP_H_ */ + +#ifndef UPB_PORT_VSNPRINTF_COMPAT_H_ +#define UPB_PORT_VSNPRINTF_COMPAT_H_ // Must be last. @@ -6934,10 +7666,10 @@ UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, } -#endif // UPB_INTERNAL_VSNPRINTF_COMPAT_H_ +#endif // UPB_PORT_VSNPRINTF_COMPAT_H_ -#ifndef UPB_WIRE_ENCODE_INTERNAL_H_ -#define UPB_WIRE_ENCODE_INTERNAL_H_ +#ifndef UPB_LEX_STRTOD_H_ +#define UPB_LEX_STRTOD_H_ // Must be last. @@ -6945,68 +7677,70 @@ UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, extern "C" { #endif -// 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); +double _upb_NoLocaleStrtod(const char *str, char **endptr); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_WIRE_ENCODE_INTERNAL_H_ */ +#endif /* UPB_LEX_STRTOD_H_ */ -#ifndef UPB_MINI_TABLE_COMMON_H_ -#define UPB_MINI_TABLE_COMMON_H_ +#ifndef UPB_MEM_ARENA_INTERNAL_H_ +#define UPB_MEM_ARENA_INTERNAL_H_ // Must be last. -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 enum { - kUpb_MessageModifier_ValidateUtf8 = 1 << 0, - kUpb_MessageModifier_DefaultIsPacked = 1 << 1, - kUpb_MessageModifier_IsExtendable = 1 << 2, -} kUpb_MessageModifier; +typedef struct _upb_MemBlock _upb_MemBlock; -#ifdef __cplusplus -extern "C" { -#endif +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; -const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( - const upb_MiniTable* table, uint32_t number); + /* Allocator to allocate arena blocks. We are responsible for freeing these + * when we are destroyed. */ + upb_alloc* block_alloc; + uint32_t last_size; -upb_FieldType upb_MiniTableField_Type(const upb_MiniTable_Field* field); + /* 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; -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; -} + /* Linked list of blocks to free/cleanup. */ + _upb_MemBlock *freelist, *freelist_tail; +}; -UPB_INLINE const upb_MiniTable_Enum* upb_MiniTable_GetSubEnumTable( - const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { - return mini_table->subs[field->submsg_index].subenum; -} +#ifdef __cplusplus +extern "C" { +#endif #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_MINI_TABLE_COMMON_H_ */ +#endif /* UPB_MEM_ARENA_INTERNAL_H_ */ + +#ifndef UPB_WIRE_TYPES_H_ +#define UPB_WIRE_TYPES_H_ + +// A list of types as they are encoded on the wire. +typedef enum { + kUpb_WireType_Varint = 0, + kUpb_WireType_64Bit = 1, + kUpb_WireType_Delimited = 2, + kUpb_WireType_StartGroup = 3, + kUpb_WireType_EndGroup = 4, + kUpb_WireType_32Bit = 5 +} upb_WireType; + +#endif /* UPB_WIRE_TYPES_H_ */ #ifndef UPB_MINI_TABLE_COMMON_INTERNAL_H_ #define UPB_MINI_TABLE_COMMON_INTERNAL_H_ @@ -7134,23 +7868,31 @@ upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, // as unknown. However there is no synchronization for this operation, which // means parallel mutation requires external synchronization. void upb_MiniTable_SetSubMessage(upb_MiniTable* table, - upb_MiniTable_Field* field, + upb_MiniTableField* field, const upb_MiniTable* sub); // Links an enum field to a MiniTable for that enum. All enum fields must // be linked prior to parsing. -void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, - const upb_MiniTable_Enum* sub); +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTableField* field, + const upb_MiniTableEnum* sub); + +const char* _upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, + upb_MiniTableSub sub, + upb_MiniTablePlatform platform, + upb_Status* status); -const char* upb_MiniTable_BuildExtension(const char* data, size_t len, - upb_MiniTable_Extension* ext, - const upb_MiniTable* extendee, - upb_MiniTable_Sub sub, - upb_Status* status); +UPB_INLINE const char* upb_MiniTable_BuildExtension( + const char* data, size_t len, upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, upb_MiniTableSub sub, upb_Status* status) { + return _upb_MiniTable_BuildExtension(data, len, ext, extendee, sub, + kUpb_MiniTablePlatform_Native, status); +} -upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, - upb_Arena* arena, - upb_Status* status); +upb_MiniTableEnum* 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(). @@ -7281,7 +8023,7 @@ struct upb_DefBuilder { upb_Arena* arena; // Allocate defs here. upb_Arena* tmp_arena; // For temporary allocations. upb_Status* status; // Record errors here. - const upb_MiniTable_File* layout; // NULL if we should build layouts. + const upb_MiniTableFile* 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. @@ -7404,7 +8146,7 @@ extern "C" { upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i); bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a); -const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); +const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); // Allocate and initialize an array of |n| enum defs. upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, @@ -7458,7 +8200,7 @@ extern "C" { upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i); -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( +const upb_MiniTableExtension* _upb_FieldDef_ExtensionMiniTable( const upb_FieldDef* f); bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f); bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); @@ -7495,7 +8237,7 @@ const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, extern "C" { #endif -const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( +const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( const upb_FileDef* f, int i); const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); @@ -7595,14 +8337,62 @@ UPB_INLINE void _upb_DescState_Init(upb_DescState* d) { d->ptr = NULL; } -bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a); +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DESC_STATE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ + + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r); +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |e|. +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_REFLECTION_DESC_STATE_INTERNAL_H_ */ +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ */ #ifndef UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ #define UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ @@ -7657,6 +8447,54 @@ size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); #endif /* UPB_REFLECTION_ONEOF_DEF_INTERNAL_H_ */ +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ + + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r); +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |m|. +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ */ + #ifndef UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ #define UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ @@ -7681,7 +8519,244 @@ upb_MethodDef* _upb_MethodDefs_New( #endif /* UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ */ -/* See port_def.inc. This should #undef all macros #defined there. */ +#ifndef UPB_WIRE_COMMON_INTERNAL_H_ +#define UPB_WIRE_COMMON_INTERNAL_H_ + +// Must be last. + +// MessageSet wire format is: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required bytes message = 3; +// } +// } + +enum { + kUpb_MsgSet_Item = 1, + kUpb_MsgSet_TypeId = 2, + kUpb_MsgSet_Message = 3, +}; + + +#endif /* UPB_WIRE_COMMON_INTERNAL_H_ */ + +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_WIRE_DECODE_INTERNAL_H_ +#define UPB_WIRE_DECODE_INTERNAL_H_ + +#include "third_party/utf8_range/utf8_range.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* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status); + +extern const uint8_t upb_utf8_offsets[]; + +UPB_INLINE +bool _upb_Decoder_VerifyUtf8Inline(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* _upb_Decoder_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* _upb_Decoder_IsDoneFallbackInline(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* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, + int overrun); + +UPB_INLINE +bool _upb_Decoder_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 = _upb_Decoder_IsDoneFallback(d, *ptr, overrun); + return false; + } +} + +#if UPB_FASTTABLE +UPB_INLINE +const char* _upb_FastDecoder_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 _upb_FastDecoder_LoadTag(const char* ptr) { + uint16_t tag; + memcpy(&tag, ptr, 2); + return tag; +} + +UPB_INLINE void _upb_Decoder_CheckLimit(upb_Decoder* d) { + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +} + +UPB_INLINE int _upb_Decoder_PushLimit(upb_Decoder* d, const char* ptr, + int size) { + int limit = size + (int)(ptr - d->end); + int delta = d->limit - limit; + _upb_Decoder_CheckLimit(d); + d->limit = limit; + d->limit_ptr = d->end + UPB_MIN(0, limit); + _upb_Decoder_CheckLimit(d); + return delta; +} + +UPB_INLINE void _upb_Decoder_PopLimit(upb_Decoder* d, const char* ptr, + int saved_delta) { + UPB_ASSERT(ptr - d->end == d->limit); + _upb_Decoder_CheckLimit(d); + d->limit += saved_delta; + d->limit_ptr = d->end + UPB_MIN(0, d->limit); + _upb_Decoder_CheckLimit(d); +} + + +#endif /* UPB_WIRE_DECODE_INTERNAL_H_ */ + +#ifndef UPB_WIRE_SWAP_INTERNAL_H_ +#define UPB_WIRE_SWAP_INTERNAL_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool _upb_IsLittleEndian(void) { + int x = 1; + return *(char*)&x == 1; +} + +UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) { + if (_upb_IsLittleEndian()) return val; + + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); +} + +UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { + if (_upb_IsLittleEndian()) return val; + + return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | + _upb_BigEndian_Swap32((uint32_t)(val >> 32)); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_WIRE_SWAP_INTERNAL_H_ */ + +// This should #undef all macros #defined in def.inc #undef UPB_SIZE #undef UPB_PTR_AT diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl index a5f7fc3ef3..97281d36d8 100644 --- a/protobuf_deps.bzl +++ b/protobuf_deps.bzl @@ -135,6 +135,6 @@ def protobuf_deps(): _github_archive( name = "upb", repo = "https://github.com/protocolbuffers/upb", - commit = "73661563dbb82bf7fdd614dd8da1186c0acc6b17", - sha256 = "0b2789aa957c665165fa66892a6402489d6491cb097391fd8ea5b5a248dbde35", + commit = "2644ae7507f8ca6c194b77fdebb71b3a57c8428c", + sha256 = "7cc1874ac409ce2c2dc71669a26471e22d5b02c340f895664aa923af08c58d19", ) diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c index 5d30319c19..200d644e7f 100644 --- a/ruby/ext/google/protobuf_c/map.c +++ b/ruby/ext/google/protobuf_c/map.c @@ -133,14 +133,13 @@ static upb_Map* Map_GetMutable(VALUE _self) { VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type, TypeInfo val_info) { VALUE hash = rb_hash_new(); - size_t iter = kUpb_Map_Begin; TypeInfo key_info = TypeInfo_from_type(key_type); if (!map) return hash; - while (upb_MapIterator_Next(map, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(map, iter); - upb_MessageValue val = upb_MapIterator_Value(map, iter); + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil); VALUE val_val = Scalar_CreateHash(val, val_info); rb_hash_aset(hash, key_val, val_val); @@ -156,9 +155,8 @@ VALUE Map_deep_copy(VALUE obj) { upb_Map* new_map = upb_Map_New(arena, self->key_type, self->value_type_info.type); size_t iter = kUpb_Map_Begin; - while (upb_MapIterator_Next(self->map, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(self->map, iter); - upb_MessageValue val = upb_MapIterator_Value(self->map, iter); + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { upb_MessageValue val_copy = Msgval_DeepCopy(val, self->value_type_info, arena); upb_Map_Set(new_map, key, val_copy, arena); @@ -202,9 +200,8 @@ void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type, StringBuilder_Printf(b, "{"); if (map) { 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); + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { if (first) { first = false; } else { @@ -239,7 +236,6 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) { Map* other = ruby_to_Map(hashmap); upb_Arena* arena = Arena_get(self->arena); upb_Message* self_msg = Map_GetMutable(_self); - size_t iter = kUpb_Map_Begin; Arena_fuse(other->arena, arena); @@ -249,9 +245,9 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) { rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types"); } - while (upb_MapIterator_Next(other->map, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(other->map, iter); - upb_MessageValue val = upb_MapIterator_Value(other->map, iter); + size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; + while (upb_Map_Next(other->map, &key, &val, &iter)) { upb_Map_Set(self_msg, key, val, arena); } } else { @@ -343,10 +339,9 @@ static VALUE Map_init(int argc, VALUE* argv, VALUE _self) { static VALUE Map_each(VALUE _self) { Map* self = ruby_to_Map(_self); size_t iter = kUpb_Map_Begin; + upb_MessageValue key, val; - while (upb_MapIterator_Next(self->map, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(self->map, iter); - upb_MessageValue val = upb_MapIterator_Value(self->map, iter); + while (upb_Map_Next(self->map, &key, &val, &iter)) { VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena); VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena); rb_yield_values(2, key_val, val_val); @@ -365,9 +360,9 @@ static VALUE Map_keys(VALUE _self) { Map* self = ruby_to_Map(_self); size_t iter = kUpb_Map_Begin; VALUE ret = rb_ary_new(); + upb_MessageValue key, val; - while (upb_MapIterator_Next(self->map, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(self->map, iter); + while (upb_Map_Next(self->map, &key, &val, &iter)) { VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena); rb_ary_push(ret, key_val); } @@ -385,9 +380,9 @@ static VALUE Map_values(VALUE _self) { Map* self = ruby_to_Map(_self); size_t iter = kUpb_Map_Begin; VALUE ret = rb_ary_new(); + upb_MessageValue key, val; - while (upb_MapIterator_Next(self->map, &iter)) { - upb_MessageValue val = upb_MapIterator_Value(self->map, iter); + while (upb_Map_Next(self->map, &key, &val, &iter)) { VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena); rb_ary_push(ret, val_val); } @@ -523,9 +518,8 @@ static VALUE Map_dup(VALUE _self) { Arena_fuse(self->arena, arena); - while (upb_MapIterator_Next(self->map, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(self->map, iter); - upb_MessageValue val = upb_MapIterator_Value(self->map, iter); + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { upb_Map_Set(new_map, key, val, arena); } @@ -574,9 +568,8 @@ VALUE Map_eq(VALUE _self, VALUE _other) { // For each member of self, check that an equal member exists at the same key // in other. size_t iter = kUpb_Map_Begin; - while (upb_MapIterator_Next(self->map, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(self->map, iter); - upb_MessageValue val = upb_MapIterator_Value(self->map, iter); + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { upb_MessageValue other_val; if (!upb_Map_Get(other->map, key, &other_val)) { // Not present in other map. @@ -619,9 +612,8 @@ VALUE Map_hash(VALUE _self) { size_t iter = kUpb_Map_Begin; TypeInfo key_info = {self->key_type}; - while (upb_MapIterator_Next(self->map, &iter)) { - upb_MessageValue key = upb_MapIterator_Key(self->map, iter); - upb_MessageValue val = upb_MapIterator_Value(self->map, iter); + upb_MessageValue key, val; + while (upb_Map_Next(self->map, &key, &val, &iter)) { hash = Msgval_GetHash(key, key_info, hash); hash = Msgval_GetHash(val, self->value_type_info, hash); } diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index 6f767d09ac..84c09b818a 100644 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -2,10 +2,9 @@ #include "ruby-upb.h" /* - * This is where we define macros used across upb. + * This is where we define internal portability macros used across upb. * - * All of these macros are undef'd in port_undef.inc to avoid leaking them to - * users. + * All of these macros are undef'd in undef.inc to avoid leaking them to users. * * The correct usage is: * @@ -13,13 +12,13 @@ * #include "upb/baz.h" * * // MUST be last included header. - * #include "upb/port_def.inc" + * #include "upb/port/def.inc" * * // Code for this file. * // <...> * * // Can be omitted for .c files, required for .h. - * #include "upb/port_undef.inc" + * #include "upb/port/undef.inc" * * This file is private and must not be included by users! */ @@ -44,6 +43,7 @@ #include #include #include +#include #if UINTPTR_MAX == 0xffffffff #define UPB_SIZE(size32, size64) size32 @@ -56,11 +56,6 @@ */ #define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) -#define UPB_READ_ONEOF(msg, fieldtype, offset, case_offset, case_val, default) \ - *UPB_PTR_AT(msg, case_offset, int) == case_val \ - ? *UPB_PTR_AT(msg, offset, fieldtype) \ - : default - #define UPB_WRITE_ONEOF(msg, fieldtype, offset, value, case_offset, case_val) \ *UPB_PTR_AT(msg, case_offset, int) = case_val; \ *UPB_PTR_AT(msg, offset, fieldtype) = value; @@ -82,16 +77,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)) @@ -114,8 +109,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() @@ -269,43 +263,56 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #endif +#include +#include +#include +#include +#include + // Must be last. -const char* upb_BufToUint64(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) { - return NULL; // integer overflow - } - u64 *= 10; - u64 += ch; - ptr++; - } +void upb_Status_Clear(upb_Status* status) { + if (!status) return; + status->ok = true; + status->msg[0] = '\0'; +} - *val = u64; - return ptr; +bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } + +const char* upb_Status_ErrorMessage(const upb_Status* status) { + return status->msg; } -const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, - bool* is_neg) { - bool neg = false; - uint64_t u64; +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'; +} - if (ptr != end && *ptr == '-') { - ptr++; - neg = true; - } +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); +} - ptr = upb_BufToUint64(ptr, end, &u64); - if (!ptr || u64 > (uint64_t)INT64_MAX + neg) { - return NULL; // integer overflow - } +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'; +} - *val = neg ? -u64 : u64; - if (is_neg) *is_neg = neg; - return ptr; +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'; } #include @@ -497,6 +504,18 @@ bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { return _upb_Map_Delete(map, &key, map->key_size); } +bool upb_Map_Next(const upb_Map* map, upb_MessageValue* key, + upb_MessageValue* val, size_t* iter) { + upb_StringView k; + upb_value v; + const bool ok = upb_strtable_next2(&map->table, &k, &v, (intptr_t*)iter); + if (ok) { + _upb_map_fromkey(k, key, map->key_size); + _upb_map_fromvalue(v, val, map->val_size); + } + return ok; +} + bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { return _upb_map_next(map, iter); } @@ -509,7 +528,7 @@ bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { return upb_strtable_done(&i); } -/* Returns the key and value for this entry of the map. */ +// 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; @@ -528,8 +547,18 @@ upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { return ret; } -/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue - * value); */ +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +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; +} // Must be last. @@ -614,7 +643,7 @@ bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, // Grow s->entries if necessary. if (sorted->end > s->cap) { - s->cap = _upb_Log2CeilingSize(sorted->end); + s->cap = upb_Log2CeilingSize(sorted->end); s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); if (!s->entries) return false; } @@ -649,21 +678,21 @@ bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, #include -static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_FileDescriptorSet_submsgs[1] = { {.submsg = &google_protobuf_FileDescriptorProto_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { - {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FileDescriptorSet__fields[1] = { + {1, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FileDescriptorSet_msg_init = { &google_protobuf_FileDescriptorSet_submsgs[0], &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, + 8, 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { +static const upb_MiniTableSub google_protobuf_FileDescriptorProto_submsgs[6] = { {.submsg = &google_protobuf_DescriptorProto_msg_init}, {.submsg = &google_protobuf_EnumDescriptorProto_msg_init}, {.submsg = &google_protobuf_ServiceDescriptorProto_msg_init}, @@ -672,20 +701,20 @@ static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = {.submsg = &google_protobuf_SourceCodeInfo_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[13] = { - {1, UPB_SIZE(40, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(48, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 40), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 48), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(12, 56), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(16, 64), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(20, 72), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(24, 80), UPB_SIZE(3, 3), 4, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(28, 88), UPB_SIZE(4, 4), 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(32, 96), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {11, UPB_SIZE(36, 104), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {12, UPB_SIZE(56, 112), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {13, UPB_SIZE(64, 128), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FileDescriptorProto__fields[13] = { + {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(48, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 40), 0, kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 48), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(12, 56), 0, 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(16, 64), 0, 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(20, 72), 0, 3, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(24, 80), 3, 4, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(28, 88), 4, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(32, 96), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(36, 104), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {12, UPB_SIZE(56, 112), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {13, UPB_SIZE(64, 128), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FileDescriptorProto_msg_init = { @@ -694,7 +723,7 @@ const upb_MiniTable google_protobuf_FileDescriptorProto_msg_init = { UPB_SIZE(72, 144), 13, kUpb_ExtMode_NonExtendable, 13, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[8] = { +static const upb_MiniTableSub google_protobuf_DescriptorProto_submsgs[8] = { {.submsg = &google_protobuf_FieldDescriptorProto_msg_init}, {.submsg = &google_protobuf_DescriptorProto_msg_init}, {.submsg = &google_protobuf_EnumDescriptorProto_msg_init}, @@ -705,17 +734,17 @@ static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[8] = { {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(40, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 32), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 48), UPB_SIZE(0, 0), 3, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(20, 56), UPB_SIZE(0, 0), 4, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(24, 64), UPB_SIZE(2, 2), 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 72), UPB_SIZE(0, 0), 6, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(32, 80), UPB_SIZE(0, 0), 7, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {10, UPB_SIZE(36, 88), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_DescriptorProto__fields[10] = { + {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 24), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 32), 0, 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(12, 40), 0, 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(16, 48), 0, 3, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(20, 56), 0, 4, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(24, 64), 2, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(28, 72), 0, 6, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(32, 80), 0, 7, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(36, 88), 0, kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_DescriptorProto_msg_init = { @@ -724,14 +753,14 @@ const upb_MiniTable google_protobuf_DescriptorProto_msg_init = { UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { {.submsg = &google_protobuf_ExtensionRangeOptions_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { + {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msg_init = { @@ -740,49 +769,49 @@ const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msg_init = { UPB_SIZE(16, 24), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, }; -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)}, +static const upb_MiniTableField google_protobuf_DescriptorProto_ReservedRange__fields[2] = { + {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msg_init = { NULL, &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, + 16, 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_ExtensionRangeOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_ExtensionRangeOptions__fields[1] = { + {999, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_ExtensionRangeOptions_msg_init = { &google_protobuf_ExtensionRangeOptions_submsgs[0], &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, + 8, 1, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { +static const upb_MiniTableSub google_protobuf_FieldDescriptorProto_submsgs[3] = { {.subenum = &google_protobuf_FieldDescriptorProto_Label_enum_init}, {.subenum = &google_protobuf_FieldDescriptorProto_Type_enum_init}, {.submsg = &google_protobuf_FieldOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(28, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(36, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(44, 56), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(52, 72), UPB_SIZE(7, 7), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(16, 88), UPB_SIZE(8, 8), 2, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {9, UPB_SIZE(20, 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_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {17, UPB_SIZE(24, 20), UPB_SIZE(11, 11), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FieldDescriptorProto__fields[11] = { + {1, UPB_SIZE(28, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(36, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, 4, 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, 8, 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(44, 56), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(52, 72), 7, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(16, 88), 8, 2, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(20, 16), 9, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(60, 96), 10, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(24, 20), 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FieldDescriptorProto_msg_init = { @@ -791,13 +820,13 @@ const upb_MiniTable google_protobuf_FieldDescriptorProto_msg_init = { UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_OneofDescriptorProto_submsgs[1] = { {.submsg = &google_protobuf_OneofOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(8, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 24), UPB_SIZE(2, 2), 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_OneofDescriptorProto__fields[2] = { + {1, 8, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_OneofDescriptorProto_msg_init = { @@ -806,18 +835,18 @@ const upb_MiniTable google_protobuf_OneofDescriptorProto_msg_init = { UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { +static const upb_MiniTableSub google_protobuf_EnumDescriptorProto_submsgs[3] = { {.submsg = &google_protobuf_EnumValueDescriptorProto_msg_init}, {.submsg = &google_protobuf_EnumOptions_msg_init}, {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(20, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 40), UPB_SIZE(0, 0), 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 48), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_EnumDescriptorProto__fields[5] = { + {1, UPB_SIZE(20, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 24), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(12, 40), 0, 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(16, 48), 0, kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumDescriptorProto_msg_init = { @@ -826,25 +855,25 @@ const upb_MiniTable google_protobuf_EnumDescriptorProto_msg_init = { UPB_SIZE(32, 56), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, }; -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)}, +static const upb_MiniTableField google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { + {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msg_init = { NULL, &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, + 16, 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { {.submsg = &google_protobuf_EnumValueOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(12, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(8, 24), UPB_SIZE(3, 3), 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_EnumValueDescriptorProto__fields[3] = { + {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, 4, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msg_init = { @@ -853,15 +882,15 @@ const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msg_init = { UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { +static const upb_MiniTableSub google_protobuf_ServiceDescriptorProto_submsgs[2] = { {.submsg = &google_protobuf_MethodDescriptorProto_msg_init}, {.submsg = &google_protobuf_ServiceOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(12, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 24), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 32), UPB_SIZE(2, 2), 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_ServiceDescriptorProto__fields[3] = { + {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 24), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_ServiceDescriptorProto_msg_init = { @@ -870,17 +899,17 @@ const upb_MiniTable google_protobuf_ServiceDescriptorProto_msg_init = { UPB_SIZE(24, 40), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_MethodDescriptorProto_submsgs[1] = { {.submsg = &google_protobuf_MethodOptions_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(12, 8), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(20, 24), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(28, 40), UPB_SIZE(3, 3), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(4, 56), UPB_SIZE(4, 4), 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(8, 1), UPB_SIZE(5, 5), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(9, 2), UPB_SIZE(6, 6), kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_MethodDescriptorProto__fields[6] = { + {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(20, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(28, 40), 3, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(4, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(8, 1), 5, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(9, 2), 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_MethodDescriptorProto_msg_init = { @@ -889,33 +918,33 @@ const upb_MiniTable google_protobuf_MethodDescriptorProto_msg_init = { UPB_SIZE(40, 64), 6, kUpb_ExtMode_NonExtendable, 6, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { +static const upb_MiniTableSub google_protobuf_FileOptions_submsgs[2] = { {.subenum = &google_protobuf_FileOptions_OptimizeMode_enum_init}, {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(24, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(32, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(40, 56), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(48, 72), UPB_SIZE(13, 13), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {37, UPB_SIZE(56, 88), UPB_SIZE(14, 14), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {39, UPB_SIZE(64, 104), UPB_SIZE(15, 15), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {40, UPB_SIZE(72, 120), UPB_SIZE(16, 16), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {41, UPB_SIZE(80, 136), UPB_SIZE(17, 17), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (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(88, 152), UPB_SIZE(19, 19), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {45, UPB_SIZE(96, 168), UPB_SIZE(20, 20), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {999, UPB_SIZE(20, 184), UPB_SIZE(0, 0), 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FileOptions__fields[21] = { + {1, 24, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(32, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {9, 4, 3, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, 8, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {16, 9, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, 10, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {18, 11, 8, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {20, 12, 9, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {23, 13, 10, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {27, 14, 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {31, 15, 12, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {36, UPB_SIZE(48, 72), 13, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {37, UPB_SIZE(56, 88), 14, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {39, UPB_SIZE(64, 104), 15, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {40, UPB_SIZE(72, 120), 16, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {41, UPB_SIZE(80, 136), 17, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {42, 16, 18, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {44, UPB_SIZE(88, 152), 19, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {45, UPB_SIZE(96, 168), 20, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 184), 0, 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FileOptions_msg_init = { @@ -924,39 +953,39 @@ const upb_MiniTable google_protobuf_FileOptions_msg_init = { UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_MessageOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_MessageOptions__fields[5] = { + {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 3, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, 4, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, 8, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_MessageOptions_msg_init = { &google_protobuf_MessageOptions_submsgs[0], &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(16, 16), 5, kUpb_ExtMode_Extendable, 3, 255, 0, + 16, 5, kUpb_ExtMode_Extendable, 3, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { +static const upb_MiniTableSub google_protobuf_FieldOptions_submsgs[3] = { {.subenum = &google_protobuf_FieldOptions_CType_enum_init}, {.subenum = &google_protobuf_FieldOptions_JSType_enum_init}, {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_FieldOptions__fields[8] = { + {1, 4, 1, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, 8, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 9, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {5, 10, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, 16, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {15, 17, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), 0, 2, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FieldOptions_msg_init = { @@ -965,28 +994,28 @@ const upb_MiniTable google_protobuf_FieldOptions_msg_init = { UPB_SIZE(24, 32), 8, kUpb_ExtMode_Extendable, 3, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_OneofOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_OneofOptions__fields[1] = { + {999, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_OneofOptions_msg_init = { &google_protobuf_OneofOptions_submsgs[0], &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, + 8, 1, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_EnumOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_EnumOptions__fields[3] = { + {2, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumOptions_msg_init = { @@ -995,13 +1024,13 @@ const upb_MiniTable google_protobuf_EnumOptions_msg_init = { UPB_SIZE(8, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_EnumValueOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_EnumValueOptions__fields[2] = { + {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumValueOptions_msg_init = { @@ -1010,13 +1039,13 @@ const upb_MiniTable google_protobuf_EnumValueOptions_msg_init = { UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 1, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_ServiceOptions_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_ServiceOptions__fields[2] = { + {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_ServiceOptions_msg_init = { @@ -1025,35 +1054,35 @@ const upb_MiniTable google_protobuf_ServiceOptions_msg_init = { UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { +static const upb_MiniTableSub google_protobuf_MethodOptions_submsgs[2] = { {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enum_init}, {.submsg = &google_protobuf_UninterpretedOption_msg_init}, }; -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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_MethodOptions__fields[3] = { + {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, 4, 2, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {999, 8, 0, 1, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_MethodOptions_msg_init = { &google_protobuf_MethodOptions_submsgs[0], &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(16, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, + 16, 3, kUpb_ExtMode_Extendable, 0, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_UninterpretedOption_submsgs[1] = { {.submsg = &google_protobuf_UninterpretedOption_NamePart_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { - {2, UPB_SIZE(4, 8), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 16), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(16, 32), UPB_SIZE(2, 2), kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(24, 40), UPB_SIZE(3, 3), kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(32, 48), UPB_SIZE(4, 4), kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, - {7, UPB_SIZE(40, 56), UPB_SIZE(5, 5), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {8, UPB_SIZE(48, 72), UPB_SIZE(6, 6), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_UninterpretedOption__fields[7] = { + {2, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 16), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(16, 32), 2, kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 40), 3, kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(32, 48), 4, kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(48, 72), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_UninterpretedOption_msg_init = { @@ -1062,9 +1091,9 @@ const upb_MiniTable google_protobuf_UninterpretedOption_msg_init = { 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_LabelFlags_IsAlternate | (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)}, +static const upb_MiniTableField google_protobuf_UninterpretedOption_NamePart__fields[2] = { + {1, UPB_SIZE(4, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, 1, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msg_init = { @@ -1073,26 +1102,26 @@ const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msg_init = { UPB_SIZE(16, 24), 2, kUpb_ExtMode_NonExtendable, 2, 255, 2, }; -static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_SourceCodeInfo_submsgs[1] = { {.submsg = &google_protobuf_SourceCodeInfo_Location_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_SourceCodeInfo__fields[1] = { + {1, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_SourceCodeInfo_msg_init = { &google_protobuf_SourceCodeInfo_submsgs[0], &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, + 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 | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(16, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(24, 40), UPB_SIZE(2, 2), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {6, UPB_SIZE(12, 56), UPB_SIZE(0, 0), kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_SourceCodeInfo_Location__fields[5] = { + {1, UPB_SIZE(4, 8), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 16), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(24, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(12, 56), 0, kUpb_NoSub, 12, kUpb_FieldMode_Array | kUpb_LabelFlags_IsAlternate | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msg_init = { @@ -1101,30 +1130,30 @@ const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msg_init = { UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 4, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_GeneratedCodeInfo_submsgs[1] = { {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msg_init}, }; -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), UPB_SIZE(0, 0), 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_GeneratedCodeInfo__fields[1] = { + {1, 0, 0, 0, 11, kUpb_FieldMode_Array | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_GeneratedCodeInfo_msg_init = { &google_protobuf_GeneratedCodeInfo_submsgs[0], &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, + 8, 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, }; -static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_Annotation_submsgs[1] = { +static const upb_MiniTableSub google_protobuf_GeneratedCodeInfo_Annotation_submsgs[1] = { {.subenum = &google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init}, }; -static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[5] = { - {1, UPB_SIZE(4, 16), UPB_SIZE(0, 0), kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, - {2, UPB_SIZE(20, 24), UPB_SIZE(1, 1), kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, - {3, UPB_SIZE(8, 4), UPB_SIZE(2, 2), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 8), UPB_SIZE(3, 3), kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 12), UPB_SIZE(4, 4), 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, +static const upb_MiniTableField google_protobuf_GeneratedCodeInfo_Annotation__fields[5] = { + {1, UPB_SIZE(4, 16), 0, kUpb_NoSub, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(20, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(8, 4), 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(12, 8), 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(16, 12), 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msg_init = { @@ -1163,7 +1192,7 @@ static const upb_MiniTable *messages_layout[27] = { &google_protobuf_GeneratedCodeInfo_Annotation_msg_init, }; -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init = { +const upb_MiniTableEnum google_protobuf_FieldDescriptorProto_Type_enum_init = { 64, 0, { @@ -1172,7 +1201,7 @@ const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init = { }, }; -const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init = { +const upb_MiniTableEnum google_protobuf_FieldDescriptorProto_Label_enum_init = { 64, 0, { @@ -1181,7 +1210,7 @@ const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init = }, }; -const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init = { +const upb_MiniTableEnum google_protobuf_FileOptions_OptimizeMode_enum_init = { 64, 0, { @@ -1190,7 +1219,7 @@ const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init = { }, }; -const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init = { +const upb_MiniTableEnum google_protobuf_FieldOptions_CType_enum_init = { 64, 0, { @@ -1199,7 +1228,7 @@ const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init = { }, }; -const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init = { +const upb_MiniTableEnum google_protobuf_FieldOptions_JSType_enum_init = { 64, 0, { @@ -1208,7 +1237,7 @@ const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init = { }, }; -const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_init = { +const upb_MiniTableEnum google_protobuf_MethodOptions_IdempotencyLevel_enum_init = { 64, 0, { @@ -1217,7 +1246,7 @@ const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_ini }, }; -const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init = { +const upb_MiniTableEnum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init = { 64, 0, { @@ -1226,7 +1255,7 @@ const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_e }, }; -static const upb_MiniTable_Enum *enums_layout[7] = { +static const upb_MiniTableEnum *enums_layout[7] = { &google_protobuf_FieldDescriptorProto_Type_enum_init, &google_protobuf_FieldDescriptorProto_Label_enum_init, &google_protobuf_FileOptions_OptimizeMode_enum_init, @@ -1236,7 +1265,7 @@ static const upb_MiniTable_Enum *enums_layout[7] = { &google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init, }; -const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { +const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout = { messages_layout, enums_layout, NULL, @@ -1251,13 +1280,13 @@ const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = { // Must be last. +#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) + struct upb_ExtensionRegistry { upb_Arena* arena; - upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ + 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)); @@ -1272,13 +1301,13 @@ upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { } bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, + const upb_MiniTableExtension** e, size_t count) { char buf[EXTREG_KEY_SIZE]; - const upb_MiniTable_Extension** start = e; - const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); + const upb_MiniTableExtension** start = e; + const upb_MiniTableExtension** end = UPB_PTRADD(e, count); for (; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; + const upb_MiniTableExtension* ext = *e; extreg_key(buf, ext->extendee, ext->field.number); upb_value v; if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { @@ -1292,16 +1321,16 @@ bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, return true; failure: - /* Back out the entries previously added. */ + // Back out the entries previously added. for (end = e, e = start; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; + const upb_MiniTableExtension* 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_ExtensionRegistry_Lookup( +const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) { char buf[EXTREG_KEY_SIZE]; upb_value v; @@ -1313,3005 +1342,2239 @@ const upb_MiniTable_Extension* upb_ExtensionRegistry_Lookup( } } -// 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. +/* + * upb_table Implementation + * + * Implementation is heavily inspired by Lua's ltable.c. + */ +#include // Must be last. -#if UPB_FASTTABLE +#define UPB_MAXARRSIZE 16 // 2**16 = 64k. -// 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 +// From Chromium. +#define ARRAY_SIZE(x) \ + ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x]))))) -#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data +static const double MAX_LOAD = 0.85; -#define RETURN_GENERIC(m) \ - /* Uncomment either of these for debugging purposes. */ \ - /* fprintf(stderr, m); */ \ - /*__builtin_trap(); */ \ - return _upb_FastDecoder_DecodeGeneric(d, ptr, msg, table, hasbits, 0); +/* 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; -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 bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } -UPB_NOINLINE -static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) { - int overrun = data; - int status; - ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); - if (ptr == NULL) _upb_FastDecoder_ErrorJmp(d, status); - data = _upb_FastDecoder_LoadTag(ptr); - UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); +static upb_value _upb_value_val(uint64_t val) { + upb_value ret; + _upb_value_setval(&ret, val); + return ret; } -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) - ? _upb_Decoder_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 = _upb_FastDecoder_LoadTag(ptr); - UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); +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); } -UPB_FORCEINLINE -static bool fastdecode_checktag(uint16_t data, int tagbytes) { - if (tagbytes == 1) { - return (data & 0xff) == 0; - } else { - return data == 0; - } -} +char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { + size_t n; + char* p; -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; + /* 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; } - 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; + return p; } -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; +/* 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_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; +static lookupkey_t intkey(uintptr_t key) { + lookupkey_t k; + k.num = key; + return k; } -typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr, - void* ctx); +typedef uint32_t hashfunc_t(upb_tabkey key); +typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); -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 = _upb_Decoder_PushLimit(d, ptr, len); - ptr = func(d, ptr, ctx); - _upb_Decoder_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; -} +/* Base table (shared code) ***************************************************/ -/* singular, oneof, repeated field handling ***********************************/ +static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } -typedef struct { - upb_Array* arr; - void* end; -} fastdecode_arr; +static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { + return t->entries + (hash & t->mask); +} -typedef enum { - FD_NEXT_ATLIMIT, - FD_NEXT_SAMEFIELD, - FD_NEXT_OTHERFIELD -} fastdecode_next; +static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } -typedef struct { - void* dst; - fastdecode_next next; - uint32_t tag; -} fastdecode_nextret; +static bool isfull(upb_table* t) { return t->count == t->max_count; } -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->capacity; - 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->capacity = 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)); +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 dst; + 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; +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; } -UPB_FORCEINLINE -static void fastdecode_commitarr(void* dst, fastdecode_arr* farr, - int valbytes) { - farr->arr->size = - (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes; +static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { + return (upb_tabent*)upb_getentry(t, hash); } -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; +static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, + uint32_t hash, eqlfunc_t* eql) { + const upb_tabent* e; - if (UPB_LIKELY(!_upb_Decoder_IsDone(d, ptr))) { - ret.tag = _upb_FastDecoder_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; + 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; } - - 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; +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); } -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->capacity * valbytes); - *data = _upb_FastDecoder_LoadTag(ptr); - return begin + (farr->arr->size * valbytes); +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); } - default: - UPB_UNREACHABLE(); + return true; + } else { + return false; } } -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); -} +/* 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; -#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_ASSERT(findentry(t, key, hash, eql) == NULL); -/* varint fields **************************************************************/ + t->count++; + mainpos_e = getentry_mutable(t, hash); + our_e = mainpos_e; -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); + 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; } - UPB_UNREACHABLE(); } - return val; + our_e->key = tabkey; + our_e->val.val = val.val; + UPB_ASSERT(findentry(t, key, hash, eql) == our_e); } -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; +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. */ } - ptr++; - uint64_t byte = (uint8_t)ptr[-1]; - if (byte > 1) { - return NULL; + 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; } - *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) _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +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])); -typedef struct { - uint8_t valbytes; - bool zigzag; - void* dst; - fastdecode_arr farr; -} fastdecode_varintdata; + return i; +} -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 size_t begin(const upb_table* t) { return next(t, -1); } - while (!_upb_Decoder_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_strtable ***************************************************************/ - fastdecode_commitarr(dst, &data->farr, data->valbytes); - return ptr; +/* 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; } -#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)) { \ - _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0); +/* Adapted from ABSL's wyhash. */ -#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); \ - } +static uint64_t UnalignedLoad64(const void* p) { + uint64_t val; + memcpy(&val, p, 8); + return val; +} -#define z_ZZ true -#define b_ZZ false -#define v_ZZ false +static uint32_t UnalignedLoad32(const void* p) { + uint32_t val; + memcpy(&val, p, 4); + return val; +} -/* Generate all combinations: - * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ +#if defined(_MSC_VER) && defined(_M_X64) +#include +#endif -#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); \ - } +/* 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 +} -#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 uint64_t WyhashMix(uint64_t v0, uint64_t v1) { + uint64_t high; + uint64_t low = upb_umul128(v0, v1, &high); + return low ^ high; +} -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) +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]; -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) + 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; -#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 + 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); -/* fixed fields ***************************************************************/ + uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); + current_state = (cs0 ^ cs1); -#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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ - case FD_NEXT_ATLIMIT: \ - return ptr; \ - } \ - } \ - \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); + uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); + duplicated_state = (ds0 ^ ds1); -#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)) { \ - _upb_FastDecoder_ErrorJmp(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) { \ - _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ - } \ - } else { \ - _upb_Array_Resize(arr, elems, &d->arena); \ - } \ - \ - char* dst = _upb_array_ptr(arr); \ - memcpy(dst, ptr, size); \ - arr->size = elems; \ - \ - ptr += size; \ - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); + ptr += 64; + len -= 64; + } while (len > 64); -#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); \ + current_state = current_state ^ duplicated_state; } -/* 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); \ - } + // 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); -#define TYPES(card, tagbytes) \ - F(card, 4, tagbytes) \ - F(card, 8, tagbytes) + current_state = WyhashMix(a ^ salt[1], b ^ current_state); -#define TAGBYTES(card) \ - TYPES(card, 1) \ - TYPES(card, 2) + ptr += 16; + len -= 16; + } -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) -TAGBYTES(p) + // 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; + } -#undef F -#undef TYPES -#undef TAGBYTES -#undef FASTDECODE_UNPACKEDFIXED -#undef FASTDECODE_PACKEDFIXED + uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); + uint64_t z = salt[1] ^ starting_length; + return WyhashMix(w, z); +} -/* string fields **************************************************************/ +const uint64_t kWyhashSalt[5] = { + 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, + 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, +}; -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); +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); +} -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 (!_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { - _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); - } - UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, 0); } -#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; \ - _upb_FastDecoder_ErrorJmp(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) { \ - _upb_FastDecoder_ErrorJmp(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 uint32_t strhash(upb_tabkey key) { + uint32_t len; + char* str = upb_tabstr(key, &len); + return _upb_Hash_NoSeed(str, len); +} -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); +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_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); +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); } -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); +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); } -#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 && \ - !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ - _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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); \ +bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { + upb_strtable new_table; + if (!init(&new_table.t, size_lg2, a)) return false; + + intptr_t iter = UPB_STRTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(t, &key, &val, &iter)) { + upb_strtable_insert(&new_table, key.data, key.size, val, a); } + *t = new_table; + return true; +} -#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 && \ - !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ - _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ - } \ - goto again; \ - case FD_NEXT_OTHERFIELD: \ - data = ret.tag; \ - UPB_MUSTTAIL return _upb_FastDecoder_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); +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; -/* Generate all combinations: - * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ + 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; + } + } -#define s_VALIDATE true -#define b_VALIDATE false + key = strkey2(k, len); + tabkey = strcopy(key, a); + if (tabkey == 0) return 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); \ - } + hash = _upb_Hash_NoSeed(key.str.str, key.str.len); + insert(&t->t, key, tabkey, v, hash, &strhash, &streql); + return true; +} -#define UTF8(card, tagbytes) \ - F(card, tagbytes, s) \ - F(card, tagbytes, b) +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); +} -#define TAGBYTES(card) \ - UTF8(card, 1) \ - UTF8(card, 2) +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); +} -TAGBYTES(s) -TAGBYTES(o) -TAGBYTES(r) +/* Iteration */ -#undef s_VALIDATE -#undef b_VALIDATE -#undef F -#undef TAGBYTES -#undef FASTDECODE_LONGSTRING -#undef FASTDECODE_COPYSTRING -#undef FASTDECODE_STRING +void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { + i->t = t; + i->index = begin(&t->t); +} -/* message fields *************************************************************/ +void upb_strtable_next(upb_strtable_iter* i) { + i->index = next(&i->t->t, i->index); +} -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); +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)); } -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; +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; } -#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) { \ - _upb_FastDecoder_ErrorJmp(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)) { \ - _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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 */ - - -#include -#include -#include -#include -#include -#include -#include +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; +} -// Must be last. +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; +} -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_inttable ***************************************************************/ -enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; +/* For inttables we use a hybrid structure where small keys are kept in an + * array and large keys are put in the hash table. */ -/* 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 uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } -static bool jsondec_streql(upb_StringView str, const char* lit) { - return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; -} +static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; } -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 upb_tabval* mutable_array(upb_inttable* t) { + return (upb_tabval*)t->array; } -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); +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; + } } -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 const upb_tabval* inttable_val_const(const upb_inttable* t, + uintptr_t key) { + return inttable_val((upb_inttable*)t, key); } -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); +size_t upb_inttable_count(const upb_inttable* t) { + return t->t.count + t->array_count; } -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; +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; + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + UPB_ASSERT(upb_inttable_lookup(t, key, NULL)); } + UPB_ASSERT(count == upb_inttable_count(t)); } - jsondec_err(d, "Unexpected EOF"); +#endif } -static bool jsondec_tryparsech(jsondec* d, char ch) { - if (d->ptr == d->end || *d->ptr != ch) return false; - d->ptr++; - return true; -} +bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2, + upb_Arena* a) { + size_t array_bytes; -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; + 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 jsondec_wsch(jsondec* d, char ch) { - jsondec_skipws(d); - if (!jsondec_tryparsech(d, ch)) { - jsondec_errf(d, "Expected: '%c'", ch); - } +bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { + return upb_inttable_sizedinit(t, 0, 4, a); } -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"); } +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. */ -static void jsondec_entrysep(jsondec* d) { - jsondec_skipws(d); - jsondec_parselit(d, ":"); -} + 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; -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); - } -} + if (!init(&new_table, t->t.size_lg2 + 1, a)) { + return false; + } -/* JSON object/array **********************************************************/ + 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; -/* These are used like so: - * - * jsondec_objstart(d); - * while (jsondec_objnext(d)) { - * ... - * } - * jsondec_objend(d) */ + _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 int jsondec_peek(jsondec* d) { - jsondec_skipws(d); - return jsondec_rawpeek(d); -} + UPB_ASSERT(t->t.count == new_table.count); -static void jsondec_push(jsondec* d) { - if (--d->depth < 0) { - jsondec_err(d, "Recursion limit exceeded"); + t->t = new_table; + } + insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); } - 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, ","); + check(t); 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, '}'); +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 jsondec_objnext(jsondec* d) { - if (!jsondec_seqnext(d, '}')) return false; - if (jsondec_peek(d) != JD_STRING) { - jsondec_err(d, "Object must start with string"); - } +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; } -/* 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; +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; } - d->ptr++; - } - - return d->ptr != start; -} - -static void jsondec_skipdigits(jsondec* d) { - if (!jsondec_tryskipdigits(d)) { - jsondec_err(d, "Expected one or more digits"); + } else { + success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); } + check(t); + return success; } -static double jsondec_number(jsondec* d) { - const char* start = d->ptr; - - assert(jsondec_rawpeek(d) == JD_NUMBER); +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}; - /* Skip over the syntax of a number, as specified by JSON. */ - if (*d->ptr == '-') d->ptr++; + /* The max key in each bucket. */ + uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; - if (jsondec_tryparsech(d, '0')) { - if (jsondec_tryskipdigits(d)) { - jsondec_err(d, "number cannot have leading zero"); + { + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + int bucket = log2ceil(key); + max[bucket] = UPB_MAX(max[bucket], key); + counts[bucket]++; } - } 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; + /* Find the largest power of two that satisfies the MIN_DENSITY + * definition (while actually having some keys). */ + size_t arr_count = upb_inttable_count(t); + int size_lg2; + upb_inttable new_t; - 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++; + 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; } - jsondec_skipdigits(d); + + arr_count -= counts[size_lg2]; } -parse: - /* Having verified the syntax of a JSON number, use strtod() to parse - * (strtod() accepts a superset of JSON syntax). */ - errno = 0; + UPB_ASSERT(arr_count <= upb_inttable_count(t)); + { - char* end; - double val = strtod(start, &end); - assert(end == d->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); - /* 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"); - } - */ + upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); - if (val > DBL_MAX || val < -DBL_MAX) { - jsondec_err(d, "Number out of range"); + { + intptr_t iter = UPB_INTTABLE_BEGIN; + uintptr_t key; + upb_value val; + while (upb_inttable_next(t, &key, &val, &iter)) { + upb_inttable_insert(&new_t, key, val, a); + } } - return val; + UPB_ASSERT(new_t.array_size == arr_size); + UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); } + *t = new_t; } -/* JSON string ****************************************************************/ +// Iteration. -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"); +bool upb_inttable_next(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter) { + intptr_t i = *iter; + if ((size_t)(i + 1) <= 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; + } + } + i--; // Back up to exactly one position before the start of the table. + } + + size_t tab_idx = next(&t->t, 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; } -static uint32_t jsondec_codepoint(jsondec* d) { - uint32_t cp = 0; - const char* end; +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; - if (d->end - d->ptr < 4) { - jsondec_err(d, "EOF inside string"); - } + // 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; + } + } - 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"); + if (prev) { + prev->next = ent->next; } - cp = (cp << 4) | ch; - } - return cp; + t->t.count--; + ent->key = 0; + ent->next = NULL; + } } -/* 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 (upb_Unicode_IsHigh(cp)) { - /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ - jsondec_parselit(d, "\\u"); - uint32_t low = jsondec_codepoint(d); - if (!upb_Unicode_IsLow(low)) jsondec_err(d, "Invalid low surrogate"); - cp = upb_Unicode_FromPair(cp, low); - } else if (upb_Unicode_IsLow(cp)) { - jsondec_err(d, "Unpaired low surrogate"); +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; } - /* Write to UTF-8 */ - int bytes = upb_Unicode_ToUTF8(cp, out); - if (bytes == 0) jsondec_err(d, "Invalid codepoint"); - return bytes; + 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); +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; - *buf = upb_Arena_Realloc(d->arena, *buf, len, size); - if (!*buf) jsondec_err(d, "Out of memory"); + // 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; + } + } - *end = *buf + len; - *buf_end = *buf + size; + if (prev) { + prev->next = ent->next; + } + + t->t.count--; + ent->key = 0; + ent->next = NULL; } -static upb_StringView jsondec_string(jsondec* d) { - char* buf = NULL; - char* end = NULL; - char* buf_end = NULL; - jsondec_skipws(d); +#include +#include +#include +#include +#include +#include +#include - if (*d->ptr++ != '"') { - jsondec_err(d, "Expected string"); - } - while (d->ptr < d->end) { - char ch = *d->ptr++; +// Must be last. - if (end == buf_end) { - jsondec_resize(d, &buf, &end, &buf_end); - } +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; - 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 codepoint (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; - } - } +enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; -eof: - jsondec_err(d, "EOF inside string"); +/* 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 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; - } +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; } -/* Base64 decoding for bytes fields. ******************************************/ +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); +} -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}; +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); +} - /* Sign-extend return value so high bit will be set on any unexpected char. */ - return table[(unsigned)ch]; +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 char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, - char* out) { - int32_t val = -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"); +} - 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 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; +} - if (val < 0) { - jsondec_err(d, "Corrupt base64"); +static void jsondec_wsch(jsondec* d, char ch) { + jsondec_skipws(d); + if (!jsondec_tryparsech(d, ch)) { + jsondec_errf(d, "Expected: '%c'", ch); } +} - return out; +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 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 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); + } +} - 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; +/* JSON object/array **********************************************************/ - 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; - } +/* These are used like so: + * + * jsondec_objstart(d); + * while (jsondec_objnext(d)) { + * ... + * } + * jsondec_objend(d) */ - out[0] = val >> 16; - out[1] = (val >> 8) & 0xff; - out[2] = val & 0xff; - } +static int jsondec_peek(jsondec* d) { + jsondec_skipws(d); + return jsondec_rawpeek(d); +} - if (ptr < end) { - /* Process remaining chars. We do not require padding. */ - out = jsondec_partialbase64(d, ptr, end, out); +static void jsondec_push(jsondec* d) { + if (--d->depth < 0) { + jsondec_err(d, "Recursion limit exceeded"); } + d->is_first = true; +} - return out - str.data; +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; } -/* Low-level integer parsing **************************************************/ +static void jsondec_arrstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '['); +} -static const char* jsondec_buftouint64(jsondec* d, const char* ptr, - const char* end, uint64_t* val) { - const char* out = upb_BufToUint64(ptr, end, val); - if (!out) jsondec_err(d, "Integer overflow"); - return out; +static void jsondec_arrend(jsondec* d) { + d->depth++; + jsondec_wsch(d, ']'); } -static const char* jsondec_buftoint64(jsondec* d, const char* ptr, - const char* end, int64_t* val, - bool* is_neg) { - const char* out = upb_BufToInt64(ptr, end, val, is_neg); - if (!out) jsondec_err(d, "Integer overflow"); - return out; +static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } + +static void jsondec_objstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '{'); } -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 void jsondec_objend(jsondec* d) { + d->depth++; + jsondec_wsch(d, '}'); } -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, NULL) != end) { - jsondec_err(d, "Non-number characters in quoted integer"); +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 ret; + return true; } -/* Primitive value types ******************************************************/ - -/* Parse INT32 or INT64 value. */ -static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { - upb_MessageValue val; +/* JSON number ****************************************************************/ - 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"); - } +static bool jsondec_tryskipdigits(jsondec* d) { + const char* start = d->ptr; - 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."); + while (d->ptr < d->end) { + if (*d->ptr < '0' || *d->ptr > '9') { + break; } - val.int32_val = (int32_t)val.int64_val; + d->ptr++; } - return val; + return d->ptr != start; } -/* 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; +static void jsondec_skipdigits(jsondec* d) { + if (!jsondec_tryskipdigits(d)) { + jsondec_err(d, "Expected one or more digits"); } - - 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}; +static double jsondec_number(jsondec* d) { + const char* start = d->ptr; - 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"); - } + assert(jsondec_rawpeek(d) == JD_NUMBER); - if (upb_FieldDef_CType(f) == kUpb_CType_Float) { - float f = val.double_val; - if (val.double_val != INFINITY && val.double_val != -INFINITY) { - if (f == INFINITY || f == -INFINITY) jsondec_err(d, "Float out of range"); + /* 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"); } - val.float_val = f; + } else { + jsondec_skipdigits(d); } - 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); + if (d->ptr == d->end) goto parse; + if (jsondec_tryparsech(d, '.')) { + jsondec_skipdigits(d); } - return val; -} + if (d->ptr == d->end) goto parse; -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; + if (*d->ptr == 'e' || *d->ptr == 'E') { + d->ptr++; + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF in number"); } - case JD_NULL: { - if (jsondec_isnullvalue(f)) { - upb_MessageValue val; - jsondec_null(d); - val.int32_val = 0; - return val; - } + if (*d->ptr == '+' || *d->ptr == '-') { + d->ptr++; } - /* Fallthrough. */ - default: - return jsondec_int(d, f); + jsondec_skipdigits(d); } -} -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; +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); - 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"); + /* 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"); } - } 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"); + */ + + if (val > DBL_MAX || val < -DBL_MAX) { + jsondec_err(d, "Number out of range"); } - } - return val; + 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; +/* JSON string ****************************************************************/ - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_MessageValue elem = jsondec_value(d, f); - upb_Array_Append(arr, elem, d->arena); +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"); } - 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); +static uint32_t jsondec_codepoint(jsondec* d) { + uint32_t cp = 0; + const char* end; - 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); + if (d->end - d->ptr < 4) { + jsondec_err(d, "EOF inside string"); } - 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); - const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); - upb_Message* msg = upb_Message_New(layout, 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)); + 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"); } - 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."); + cp = (cp << 4) | ch; } - preserved = d->debug_field; - d->debug_field = f; + return cp; +} - 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); +/* 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 (upb_Unicode_IsHigh(cp)) { + /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ + jsondec_parselit(d, "\\u"); + uint32_t low = jsondec_codepoint(d); + if (!upb_Unicode_IsLow(low)) jsondec_err(d, "Invalid low surrogate"); + cp = upb_Unicode_FromPair(cp, low); + } else if (upb_Unicode_IsLow(cp)) { + jsondec_err(d, "Unpaired low surrogate"); } - d->debug_field = preserved; + /* Write to UTF-8 */ + int bytes = upb_Unicode_ToUTF8(cp, out); + if (bytes == 0) jsondec_err(d, "Invalid codepoint"); + return bytes; } -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 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); -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(); - } -} + *buf = upb_Arena_Realloc(d->arena, *buf, len, size); + if (!*buf) jsondec_err(d, "Out of memory"); -/* Well-known types ***********************************************************/ + *end = *buf + len; + *buf_end = *buf + size; +} -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; +static upb_StringView jsondec_string(jsondec* d) { + char* buf = NULL; + char* end = NULL; + char* buf_end = NULL; - UPB_ASSERT(digits <= 9); /* int can't overflow. */ + jsondec_skipws(d); - if (jsondec_buftouint64(d, p, end, &val) != end || - (after_len && memcmp(end, after, after_len) != 0)) { - jsondec_err(d, "Malformed timestamp"); + if (*d->ptr++ != '"') { + jsondec_err(d, "Expected string"); } - UPB_ASSERT(val < INT_MAX); - - *ptr = end + after_len; - return (int)val; -} + while (d->ptr < d->end) { + char ch = *d->ptr++; -static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { - uint64_t nanos = 0; - const char* p = *ptr; + if (end == buf_end) { + jsondec_resize(d, &buf, &end, &buf_end); + } - 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"); + 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 codepoint (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; } - while (exp_lg10--) nanos *= 10; - *ptr = nano_end; } - UPB_ASSERT(nanos < INT_MAX); +eof: + jsondec_err(d, "EOF inside string"); +} - return (int)nanos; +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; + } } -/* 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); - } +/* Base64 decoding for bytes fields. ******************************************/ - nanos.int32_val = jsondec_nanos(d, &ptr, end); +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}; - { - /* [+-]08:00 or Z */ - int ofs_hour = 0; - int ofs_min = 0; - bool neg = false; + /* Sign-extend return value so high bit will be set on any unexpected char. */ + return table[(unsigned)ch]; +} - if (ptr == end) goto malformed; +static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, + char* out) { + int32_t val = -1; - 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; - } + 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 (seconds.int64_val < -62135596800) { - jsondec_err(d, "Timestamp out of range"); + if (val < 0) { + jsondec_err(d, "Corrupt base64"); } - 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"); + return out; } -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); +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 int64_t max = (uint64_t)3652500 * 86400; - bool neg = false; + const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ - /* "3.000000001s", "3s", etc. */ - ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); - nanos.int32_val = jsondec_nanos(d, &ptr, end); + 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 (end - ptr != 1 || *ptr != 's') { - jsondec_err(d, "Malformed duration"); - } + 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; + } - if (seconds.int64_val < -max || seconds.int64_val > max) { - jsondec_err(d, "Duration out of range"); + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; } - if (neg) { - nanos.int32_val = -nanos.int32_val; + if (ptr < end) { + /* Process remaining chars. We do not require padding. */ + out = jsondec_partialbase64(d, ptr, end, out); } - 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 out - str.data; } -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); - const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); - upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; +/* Low-level integer parsing **************************************************/ - jsondec_arrstart(d); - while (jsondec_arrnext(d)) { - upb_Message* value_msg = upb_Message_New(value_layout, 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 const char* jsondec_buftouint64(jsondec* d, const char* ptr, + const char* end, uint64_t* val) { + const char* out = upb_BufToUint64(ptr, end, val); + if (!out) jsondec_err(d, "Integer overflow"); + return out; } -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); - const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); - upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; +static const char* jsondec_buftoint64(jsondec* d, const char* ptr, + const char* end, int64_t* val, + bool* is_neg) { + const char* out = upb_BufToInt64(ptr, end, val, is_neg); + if (!out) jsondec_err(d, "Integer overflow"); + return out; +} - jsondec_objstart(d); - while (jsondec_objnext(d)) { - upb_MessageValue key, value; - upb_Message* value_msg = upb_Message_New(value_layout, 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); +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"); } - jsondec_objend(d); + return ret; } -static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, - const upb_MessageDef* m) { +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, NULL) != 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; - 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); + 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_NULL: - /* NullValue null_value = 1; */ - f = upb_MessageDef_FindFieldByNumber(m, 1); - val.int32_val = 0; - jsondec_null(d); + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.int64_val = jsondec_strtoint64(d, str); 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++; + jsondec_err(d, "Expected number or string"); } - 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; + 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 ret; + return 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; +/* Parse UINT32 or UINT64 value. */ +static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val = {0}; - 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; + 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; } - upb_Array_Append(arr, val, d->arena); + 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"); } -} -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'"); + if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { + if (val.uint64_val > UINT32_MAX) { + jsondec_err(d, "Integer out of range."); } - jsondec_wellknown(d, msg, m); + val.uint32_val = (uint32_t)val.uint64_val; } -} -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; + return val; +} - val.str_val = type_url; - upb_Message_Set(msg, type_url_f, val, d->arena); +/* Parse DOUBLE or FLOAT value. */ +static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { + upb_StringView str; + upb_MessageValue val = {0}; - /* Find message name after the last '/' */ - while (ptr > type_url.data && *--ptr != '/') { + 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 (ptr == type_url.data || ptr == end) { - jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + if (upb_FieldDef_CType(f) == kUpb_CType_Float) { + float f = val.double_val; + if (val.double_val != INFINITY && val.double_val != -INFINITY) { + if (f == INFINITY || f == -INFINITY) jsondec_err(d, "Float out of range"); + } + val.float_val = f; } - ptr++; - type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); + return val; +} - if (!type_m) { - jsondec_err(d, "Type was not found"); +/* 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 type_m; + 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; - - 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--; +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; } - } else { - if (!pre_type_data) pre_type_data = start; - jsondec_skipval(d); } + /* Fallthrough. */ + default: + return jsondec_int(d, f); } +} - if (!any_m) { - jsondec_err(d, "Any object didn't contain a '@type' field"); - } - - const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); - any_msg = upb_Message_New(any_layout, d->arena); +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 (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); + 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"); } - d->ptr = saved_ptr; - d->end = saved_end; } - while (jsondec_objnext(d)) { - jsondec_anyfield(d, any_msg, any_m); - } + return val; +} - jsondec_objend(d); +/* Composite types (array/message/map) ****************************************/ - upb_EncodeStatus status = - upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, - (char**)&encoded.str_val.data, &encoded.str_val.size); - // TODO(b/235839510): We should fail gracefully here on a bad return status. - UPB_ASSERT(status == kUpb_EncodeStatus_Ok); - upb_Message_Set(msg, value_f, encoded, d->arena); +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_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_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_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(); +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); } } -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; +static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); + upb_Message* msg = upb_Message_New(layout, d->arena); + upb_MessageValue val; - if (size == 0) return true; + jsondec_tomsg(d, msg, m); + val.msg_val = msg; + return val; +} - 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 void jsondec_field(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_StringView name; + const upb_FieldDef* f; + const upb_FieldDef* preserved; - if (UPB_SETJMP(d.err)) return false; + name = jsondec_string(d); + jsondec_entrysep(d); - jsondec_tomsg(&d, msg, m); - return true; -} + 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; + } -#include -#include -#include -#include -#include -#include -#include + 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."); + } -// Must be last. + preserved = d->debug_field; + d->debug_field = f; -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; + 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); + } -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); + d->debug_field = preserved; +} -UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { - upb_Status_SetErrorMessage(e->status, msg); - longjmp(e->err, 1); +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_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_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(); + } } -static upb_Arena* jsonenc_arena(jsonenc* e) { - /* Create lazily, since it's only needed for Any */ - if (!e->arena) { - e->arena = upb_Arena_New(); +/* 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"); } - return e->arena; + + UPB_ASSERT(val < INT_MAX); + + *ptr = end + after_len; + return (int)val; } -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; +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"); } - e->overflow += (len - have); + while (exp_lg10--) nanos *= 10; + *ptr = nano_end; } + + UPB_ASSERT(nanos < INT_MAX); + + return (int)nanos; } -static void jsonenc_putstr(jsonenc* e, const char* str) { - jsonenc_putbytes(e, str, strlen(str)); +/* 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; } -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; +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; +} - va_start(args, fmt); - n = _upb_vsnprintf(e->ptr, have, fmt, args); - va_end(args); +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 (UPB_LIKELY(have > n)) { - e->ptr += n; - } else { - e->ptr = UPB_PTRADD(e->ptr, have); - e->overflow += (n - have); - } -} + if (str.size < 20) goto malformed; -static void jsonenc_nanos(jsonenc* e, int32_t nanos) { - int digits = 9; + { + /* 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); - if (nanos == 0) return; - if (nanos < 0 || nanos >= 1000000000) { - jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); + seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); } - while (nanos % 1000 == 0) { - nanos /= 1000; - digits -= 3; - } + nanos.int32_val = jsondec_nanos(d, &ptr, end); - jsonenc_printf(e, ".%.*" PRId32, digits, nanos); -} + { + /* [+-]08:00 or Z */ + int ofs_hour = 0; + int ofs_min = 0; + bool neg = false; -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 (ptr == end) goto malformed; - 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"); + 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; + } } - /* 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; + if (seconds.int64_val < -62135596800) { + jsondec_err(d, "Timestamp out of range"); + } - sec = seconds % 60; - min = (seconds / 60) % 60; - hour = (seconds / 3600) % 24; + 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; - jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "Z\""); +malformed: + jsondec_err(d, "Malformed timestamp"); } -static void jsonenc_duration(jsonenc* e, const upb_Message* msg, +static void jsondec_duration(jsondec* d, 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; - bool negative = false; + 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; + bool neg = false; - if (seconds > 315576000000 || seconds < -315576000000 || - (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { - jsonenc_err(e, "bad duration"); - } + /* "3.000000001s", "3s", etc. */ + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); + nanos.int32_val = jsondec_nanos(d, &ptr, end); - if (seconds < 0) { - negative = true; - seconds = -seconds; + if (end - ptr != 1 || *ptr != 's') { + jsondec_err(d, "Malformed duration"); } - if (nanos < 0) { - negative = true; - nanos = -nanos; + + if (seconds.int64_val < -max || seconds.int64_val > max) { + jsondec_err(d, "Duration out of range"); } - jsonenc_putstr(e, "\""); - if (negative) { - jsonenc_putstr(e, "-"); + if (neg) { + nanos.int32_val = -nanos.int32_val; } - jsonenc_printf(e, "%" PRId64, seconds); - jsonenc_nanos(e, nanos); - jsonenc_putstr(e, "s\""); + + 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 jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { - const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); +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); + const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); + upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; - if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { - jsonenc_putstr(e, "null"); - } else { - const upb_EnumValueDef* ev = - (e->options & upb_JsonEncode_FormatEnumsAsIntegers) - ? NULL - : upb_EnumDef_FindValueByNumber(e_def, val); - - if (ev) { - jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); - } else { - jsonenc_printf(e, "%" PRId32, val); - } + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_Message* value_msg = upb_Message_New(value_layout, 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 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, "\""); +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); + const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); + upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; - 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; + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, value; + upb_Message* value_msg = upb_Message_New(value_layout, 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); +} - 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); +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 1: - buf[0] = base64[ptr[0] >> 2]; - buf[1] = base64[((ptr[0] & 0x3) << 4)]; - buf[2] = '='; - buf[3] = '='; - jsonenc_putbytes(e, buf, 4); + 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(); } - jsonenc_putstr(e, "\""); + upb_Message_Set(msg, f, val, d->arena); } -static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { - const char* ptr = str.data; - const char* end = UPB_PTRADD(ptr, str.size); +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) { - 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; - } + ret.size += (*ptr >= 'A' && *ptr <= 'Z'); ptr++; } -} -static void jsonenc_string(jsonenc* e, upb_StringView str) { - jsonenc_putstr(e, "\""); - jsonenc_stringbody(e, str); - jsonenc_putstr(e, "\""); -} + out = upb_Arena_Malloc(d->arena, ret.size); + ptr = buf; + ret.data = out; -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; + 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 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); + return ret; } -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 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 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 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* jsonenc_getanymsg(jsonenc* e, - upb_StringView type_url) { - /* Find last '/', if any. */ +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; - const upb_MessageDef* ret; + upb_MessageValue val; - 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); + val.str_val = type_url; + upb_Message_Set(msg, type_url_f, val, d->arena); - if (!ret) { - jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + /* Find message name after the last '/' */ + while (ptr > type_url.data && *--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_layout, 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"); + if (ptr == type_url.data || ptr == end) { + jsondec_err(d, "Type url must have at least one '/' and non-empty host"); } - jsonenc_putstr(e, "{\"@type\":"); - jsonenc_string(e, type_url); + ptr++; + type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); - 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); + if (!type_m) { + jsondec_err(d, "Type was not found"); } - jsonenc_putstr(e, "}"); -} - -static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { - if (*first) { - *first = false; - } else { - jsonenc_putstr(e, str); - } + return type_m; } -static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { - const char* ptr = path.data; - const char* end = ptr + path.size; +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; - while (ptr < end) { - char ch = *ptr; + jsondec_objstart(d); - 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."); + /* 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--; } - ch = *++ptr - 32; + } else { + if (!pre_type_data) pre_type_data = start; + jsondec_skipval(d); } - - 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); + if (!any_m) { + jsondec_err(d, "Any object didn't contain a '@type' field"); } - 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); + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + any_msg = upb_Message_New(any_layout, d->arena); - jsonenc_putsep(e, ",", &first); - jsonenc_string(e, key.str_val); - jsonenc_putstr(e, ":"); - jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + 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; } - 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); - } + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_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; + jsondec_objend(d); - if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { - jsonenc_err(e, "No value set in Value proto"); - } + upb_EncodeStatus status = + upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, + (char**)&encoded.str_val.data, &encoded.str_val.size); + // TODO(b/235839510): We should fail gracefully here on a bad return status. + UPB_ASSERT(status == kUpb_EncodeStatus_Ok); + upb_Message_Set(msg, value_f, encoded, d->arena); +} - 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 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 jsonenc_msgfield(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m) { +static void jsondec_wellknown(jsondec* d, 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); + jsondec_any(d, msg, m); break; case kUpb_WellKnown_FieldMask: - jsonenc_fieldmask(e, msg, m); + jsondec_fieldmask(d, msg, m); break; case kUpb_WellKnown_Duration: - jsonenc_duration(e, msg, m); + jsondec_duration(d, msg, m); break; case kUpb_WellKnown_Timestamp: - jsonenc_timestamp(e, msg, m); + 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: @@ -4322,3735 +3585,4039 @@ static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, 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); + jsondec_wrapper(d, msg, m); break; + default: + UPB_UNREACHABLE(); } } -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; - } -} +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; -static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, - const upb_FieldDef* f) { - jsonenc_putstr(e, "\""); + if (size == 0) return true; - 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(); - } + 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; - jsonenc_putstr(e, "\":"); -} + if (UPB_SETJMP(d.err)) return false; -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; + jsondec_tomsg(&d, msg, m); + return true; +} - jsonenc_putstr(e, "["); - for (i = 0; i < size; i++) { - jsonenc_putsep(e, ",", &first); - jsonenc_scalar(e, upb_Array_Get(arr, i), f); - } +#include +#include +#include +#include +#include +#include - 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; +// Must be last. - jsonenc_putstr(e, "{"); +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; - 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); - } - } +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); - jsonenc_putstr(e, "}"); +UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { + upb_Status_SetErrorMessage(e->status, msg); + longjmp(e->err, 1); } -static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, - upb_MessageValue val, bool* first) { - const char* name; +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); +} - jsonenc_putsep(e, ",", first); +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; +} - 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)); +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 (e->options & upb_JsonEncode_UseProtoNames) { - name = upb_FieldDef_Name(f); - } else { - name = upb_FieldDef_JsonName(f); + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; } - jsonenc_printf(e, "\"%s\":", name); + e->overflow += (len - have); } +} - 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_putstr(jsonenc* e, const char* str) { + jsonenc_putbytes(e, str, strlen(str)); } -static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, - const upb_MessageDef* m, bool first) { - upb_MessageValue val; - const upb_FieldDef* f; +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; - 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); - } - } + va_start(args, fmt); + n = _upb_vsnprintf(e->ptr, have, fmt, args); + va_end(args); + + if (UPB_LIKELY(have > n)) { + e->ptr += n; } 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); - } + e->ptr = UPB_PTRADD(e->ptr, have); + e->overflow += (n - have); } } -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 void jsonenc_nanos(jsonenc* e, int32_t nanos) { + int digits = 9; -static size_t jsonenc_nullz(jsonenc* e, size_t size) { - size_t ret = e->ptr - e->buf + e->overflow; + if (nanos == 0) return; + if (nanos < 0 || nanos >= 1000000000) { + jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); + } - if (size > 0) { - if (e->ptr == e->end) e->ptr--; - *e->ptr = '\0'; + while (nanos % 1000 == 0) { + nanos /= 1000; + digits -= 3; } - return ret; + jsonenc_printf(e, ".%.*" PRId32, digits, nanos); } -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); -} +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"); + } -#include + /* 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; -// Must be last. + sec = seconds % 60; + min = (seconds / 60) % 60; + hour = (seconds / 3600) % 24; -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); - } + jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "Z\""); } -upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - - -// Must be last. +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; + bool negative = false; -static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { - return (uint32_t*)(cleanup_metadata & ~0x1); -} + if (seconds > 315576000000 || seconds < -315576000000 || + (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { + jsonenc_err(e, "bad duration"); + } -static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { - return cleanup_metadata & 0x1; -} + if (seconds < 0) { + negative = true; + seconds = -seconds; + } + if (nanos < 0) { + negative = true; + nanos = -nanos; + } -static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, - bool has_initial_block) { - return (uintptr_t)cleanup | has_initial_block; + jsonenc_putstr(e, "\""); + if (negative) { + jsonenc_putstr(e, "-"); + } + jsonenc_printf(e, "%" PRId64, seconds); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "s\""); } -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 void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { + const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); -static const size_t memblock_reserve = - UPB_ALIGN_UP(sizeof(mem_block), UPB_MALLOC_ALIGN); + if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { + jsonenc_putstr(e, "null"); + } else { + const upb_EnumValueDef* ev = + (e->options & upb_JsonEncode_FormatEnumsAsIntegers) + ? NULL + : upb_EnumDef_FindValueByNumber(e_def, val); -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; + if (ev) { + jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); + } else { + jsonenc_printf(e, "%" PRId32, val); + } } - return a; } -size_t upb_Arena_SpaceAllocated(upb_Arena* arena) { - arena = arena_findroot(arena); - size_t memsize = 0; +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]; - mem_block* block = arena->freelist; + jsonenc_putstr(e, "\""); - while (block) { - memsize += sizeof(mem_block) + block->size; - block = block->next; + 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; } - return memsize; -} + 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; + } -uint32_t upb_Arena_DebugRefCount(upb_Arena* arena) { - return arena_findroot(arena)->refcount; + 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)); +static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { + const char* ptr = str.data; + const char* end = UPB_PTRADD(ptr, str.size); - UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); + 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 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); +static void jsonenc_string(jsonenc* e, upb_StringView str) { + jsonenc_putstr(e, "\""); + jsonenc_stringbody(e, str); + jsonenc_putstr(e, "\""); +} - if (!block) return false; - upb_Arena_addblock(a, root, block, block_size); +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; } -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_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_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 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); } -/* Public Arena API ***********************************************************/ +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 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; +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; - /* We need to malloc the initial block. */ - n = first_block_overhead + 256; - if (!alloc || !(mem = upb_malloc(alloc, n))) { - return NULL; + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); } - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - n -= sizeof(*a); + if (type_url.size == 0) goto badurl; - 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); + while (true) { + if (--ptr == type_url.data) { + /* Type URL must contain at least one '/', with host before. */ + goto badurl; + } + if (*ptr == '/') { + ptr++; + break; + } + } - upb_Arena_addblock(a, a, mem, n); + ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); - return a; -} + if (!ret) { + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + } -upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { - upb_Arena* a; + return ret; - 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; - } +badurl: + jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(type_url)); +} - /* 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)); +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_layout, arena); - if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { - return arena_initslow(mem, n, alloc); + if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + jsonenc_err(e, "Error decoding message in Any"); } - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + jsonenc_putstr(e, "{\"@type\":"); + jsonenc_string(e, type_url); - 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->freelist_tail = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, 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); + } - return a; + jsonenc_putstr(e, "}"); } -static void arena_dofree(upb_Arena* a) { - mem_block* block = a->freelist; - UPB_ASSERT(a->parent == a); - UPB_ASSERT(a->refcount == 0); +static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { + if (*first) { + *first = false; + } else { + jsonenc_putstr(e, str); + } +} - while (block) { - /* Load first since we are deleting block. */ - mem_block* next = block->next; +static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { + const char* ptr = path.data; + const char* end = ptr + path.size; - if (block->cleanups > 0) { - cleanup_ent* end = UPB_PTR_AT(block, block->size, void); - cleanup_ent* ptr = end - block->cleanups; + while (ptr < end) { + char ch = *ptr; - for (; ptr < end; ptr++) { - ptr->cleanup(ptr->ud); + 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; } - upb_free(a->block_alloc, block); - block = next; + jsonenc_putbytes(e, &ch, 1); + ptr++; } } -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); +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 (!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); - } + if (paths) n = upb_Array_Size(paths); - a->head.end -= sizeof(cleanup_ent); - ent = (cleanup_ent*)a->head.end; - (*cleanups)++; - UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); + jsonenc_putstr(e, "\""); - ent->cleanup = func; - ent->ud = ud; + for (i = 0; i < n; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); + } - return true; + jsonenc_putstr(e, "\""); } -bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { - upb_Arena* r1 = arena_findroot(a1); - upb_Arena* r2 = arena_findroot(a2); +static void jsonenc_struct(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); - if (r1 == r2) return true; /* Already fused. */ + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; - /* 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; + if (fields) { + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); - /* Only allow fuse with a common allocator */ - if (r1->block_alloc != r2->block_alloc) return false; + size_t iter = kUpb_Map_Begin; + bool first = true; - /* 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; + upb_MessageValue key, val; + while (upb_Map_Next(fields, &key, &val, &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)); + } } - /* 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; + 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; -#include - - -// Must be last. - -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', '{', '|', '}', '~', -}; + jsonenc_putstr(e, "["); -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 (values) { + const size_t size = upb_Array_Size(values); + for (i = 0; i < size; i++) { + upb_MessageValue elem = upb_Array_Get(values, i); -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]; + jsonenc_putsep(e, ",", &first); + jsonenc_value(e, elem.msg_val, values_m); } } - return NULL; + + jsonenc_putstr(e, "]"); } -upb_FieldType upb_MiniTableField_Type(const upb_MiniTable_Field* field) { - if (field->mode & kUpb_LabelFlags_IsAlternate) { - if (field->descriptortype == kUpb_FieldType_Int32) { - return kUpb_FieldType_Enum; - } else if (field->descriptortype == kUpb_FieldType_Bytes) { - return kUpb_FieldType_String; - } else { - UPB_ASSERT(false); - } +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; } - return field->descriptortype; } +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; + } +} -#include +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, "\""); -// Must be last. + 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(); + } -// 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. + jsonenc_putstr(e, "\":"); +} - kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, -} upb_LayoutItemType; +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; -#define kUpb_LayoutItem_IndexSentinel ((uint16_t)-1) + jsonenc_putstr(e, "["); -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; + for (i = 0; i < size; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_scalar(e, upb_Array_Get(arr, i), f); + } -typedef struct { - upb_LayoutItem* data; - size_t size; - size_t capacity; -} upb_LayoutItemVector; + jsonenc_putstr(e, "]"); +} -typedef struct { - const char* end; - upb_MiniTable* table; - upb_MiniTable_Field* fields; - upb_MiniTablePlatform platform; - upb_LayoutItemVector vec; - upb_Arena* arena; - upb_Status* status; +static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { + jsonenc_putstr(e, "{"); - // When building enums. - upb_MiniTable_Enum* enum_table; - uint32_t enum_value_count; - uint32_t enum_data_count; - uint32_t enum_data_capacity; + 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); - jmp_buf err; -} upb_MtDecoder; + if (map) { + size_t iter = kUpb_Map_Begin; + bool first = true; -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); -} + upb_MessageValue key, val; + while (upb_Map_Next(map, &key, &val, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_mapkey(e, key, key_f); + jsonenc_scalar(e, val, val_f); + } + } -static void upb_MtDecoder_CheckOutOfMemory(upb_MtDecoder* d, const void* ptr) { - if (!ptr) upb_MtDecoder_ErrorFormat(d, "Out of memory"); + jsonenc_putstr(e, "}"); } -// 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 void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, + upb_MessageValue val, bool* first) { + const char* name; -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); - val |= bits << shift; - if (ptr == d->end || *ptr < min || max < *ptr) { - *out_val = val; - return ptr; - } - ch = *ptr++; - shift += bits_per_char; - if (shift >= 32) upb_MtDecoder_ErrorFormat(d, "Overlong varint"); - } -} + jsonenc_putsep(e, ",", first); -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; - field->mode |= kUpb_LabelFlags_IsAlternate; - } - return false; - default: - return false; + 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); } -} -static bool upb_MtDecoder_FieldIsPackable(upb_MiniTable_Field* field) { - return (field->mode & kUpb_FieldMode_Array) && - _upb_FieldType_IsPackable(field->descriptortype); + 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 upb_MiniTable_SetTypeAndSub(upb_MiniTable_Field* field, - upb_FieldType type, uint32_t* sub_count, - uint64_t msg_modifiers, - bool is_proto3_enum) { - field->descriptortype = type; - - if (is_proto3_enum) { - UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum); - field->descriptortype = kUpb_FieldType_Int32; - field->mode |= kUpb_LabelFlags_IsAlternate; - } +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first) { + upb_MessageValue val; + const upb_FieldDef* f; - if (upb_MiniTable_HasSub(field, msg_modifiers)) { - field->submsg_index = sub_count ? (*sub_count)++ : 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); + } + } } else { - field->submsg_index = kUpb_NoSub; + /* 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); + } } +} - if (upb_MtDecoder_FieldIsPackable(field) && - (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { - field->mode |= kUpb_LabelFlags_IsPacked; +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; } -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_OpenEnum] = 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, - [kUpb_EncodedType_ClosedEnum] = kUpb_FieldType_Enum, -}; +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; -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_Bytes] = kUpb_FieldRep_StringView, - [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, - [kUpb_EncodedType_OpenEnum] = 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, - [kUpb_EncodedType_ClosedEnum] = kUpb_FieldRep_4Byte, - }; + 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; - char pointer_rep = d->platform == kUpb_MiniTablePlatform_32Bit - ? kUpb_FieldRep_4Byte - : kUpb_FieldRep_8Byte; + if (UPB_SETJMP(e.err)) return -1; - int8_t type = _upb_FromBase92(ch); - if (ch >= _upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { - type -= kUpb_EncodedType_RepeatedBase; - field->mode = kUpb_FieldMode_Array; - field->mode |= pointer_rep << kUpb_FieldRep_Shift; - field->offset = kNoPresence; - } else { - field->mode = kUpb_FieldMode_Scalar; - field->offset = kHasbitPresence; - if (type == kUpb_EncodedType_Group || type == kUpb_EncodedType_Message) { - field->mode |= pointer_rep << kUpb_FieldRep_Shift; - } else if (type >= sizeof(kUpb_EncodedToFieldRep)) { - upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); - UPB_UNREACHABLE(); - } else { - field->mode |= kUpb_EncodedToFieldRep[type] << kUpb_FieldRep_Shift; - } - } - if (type >= sizeof(kUpb_EncodedToType)) { - upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); - UPB_UNREACHABLE(); - } - upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_count, - msg_modifiers, type == kUpb_EncodedType_OpenEnum); + jsonenc_msgfield(&e, msg, m); + if (e.arena) upb_Arena_Free(e.arena); + return jsonenc_nullz(&e, size); } -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(); + +// Must be last. + +const char* upb_BufToUint64(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) { + return NULL; // integer overflow } - field->mode ^= kUpb_LabelFlags_IsPacked; + u64 *= 10; + u64 += ch; + ptr++; } - bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; - bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; + *val = u64; + return ptr; +} - // 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 char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg) { + bool neg = false; + uint64_t u64; - if (singular) field->offset = kNoPresence; - if (required) { - field->offset = kRequiredPresence; + if (ptr != end && *ptr == '-') { + ptr++; + neg = true; } -} -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; + ptr = upb_BufToUint64(ptr, end, &u64); + if (!ptr || u64 > (uint64_t)INT64_MAX + neg) { + return NULL; // integer overflow } - d->vec.data[d->vec.size++] = item; + + *val = neg ? -u64 : u64; + if (is_neg) *is_neg = neg; + return ptr; } -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); +#include +#include - // Push oneof case. - item.rep = kUpb_FieldRep_4Byte; // Field Number. - item.type = kUpb_LayoutItemType_OneofCase; - upb_MtDecoder_PushItem(d, item); +// Must be last. + +/* 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 = '.'; + } } -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_StringView] = 8, - [kUpb_FieldRep_8Byte] = 8, - }; - static const uint8_t kRepToSize64[] = { - [kUpb_FieldRep_1Byte] = 1, - [kUpb_FieldRep_4Byte] = 4, - [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]; +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); } -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_StringView] = 4, - [kUpb_FieldRep_8Byte] = 8, - }; - static const uint8_t kRepToAlign64[] = { - [kUpb_FieldRep_1Byte] = 1, - [kUpb_FieldRep_4Byte] = 4, - [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]; +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); } -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(); - } +#include +#include - // 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; +// Must be last. + +// Determine the locale-specific radix character by calling sprintf() to print +// the number 1.5, then stripping off the digits. As far as I can tell, this +// is the only portable, thread-safe way to get the C library to divulge the +// locale's radix character. No, localeconv() is NOT thread-safe. + +static int GetLocaleRadix(char *data, size_t capacity) { + char temp[16]; + const int size = snprintf(temp, sizeof(temp), "%.1f", 1.5); + UPB_ASSERT(temp[0] == '1'); + UPB_ASSERT(temp[size - 1] == '5'); + UPB_ASSERT(size < capacity); + temp[size - 1] = '\0'; + strcpy(data, temp + 1); + return size - 2; } -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); - } - } +// Populates a string identical to *input except that the character pointed to +// by pos (which should be '.') is replaced with the locale-specific radix. - // Push final oneof. - upb_MtDecoder_PushOneof(d, item); - return ptr; +static void LocalizeRadix(const char *input, const char *pos, char *output) { + const int len1 = pos - input; + + char radix[8]; + const int len2 = GetLocaleRadix(radix, sizeof(radix)); + + memcpy(output, input, len1); + memcpy(output + len1, radix, len2); + strcpy(output + len1 + len2, input + len1 + 1); } -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(); +double _upb_NoLocaleStrtod(const char *str, char **endptr) { + // We cannot simply set the locale to "C" temporarily with setlocale() + // as this is not thread-safe. Instead, we try to parse in the current + // locale first. If parsing stops at a '.' character, then this is a + // pretty good hint that we're actually in some other locale in which + // '.' is not the radix character. + + char *temp_endptr; + double result = strtod(str, &temp_endptr); + if (endptr != NULL) *endptr = temp_endptr; + if (*temp_endptr != '.') return result; + + // Parsing halted on a '.'. Perhaps we're in a different locale? Let's + // try to replace the '.' with a locale-specific radix character and + // try again. + + char localized[80]; + LocalizeRadix(str, temp_endptr, localized); + char *localized_endptr; + result = strtod(localized, &localized_endptr); + if ((localized_endptr - &localized[0]) > (temp_endptr - str)) { + // This attempt got further, so replacing the decimal must have helped. + // Update endptr to point at the right location. + if (endptr != NULL) { + // size_diff is non-zero if the localized radix has multiple bytes. + int size_diff = strlen(localized) - strlen(str); + *endptr = (char *)str + (localized_endptr - &localized[0] - size_diff); } - *msg_modifiers = mod; } - return ptr; + return result; } -static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, uint32_t sub_count) { - size_t subs_bytes = sizeof(*d->table->subs) * sub_count; - void* subs = upb_Arena_Malloc(d->arena, subs_bytes); - memset(subs, 0, subs_bytes); - d->table->subs = subs; - upb_MtDecoder_CheckOutOfMemory(d, d->table->subs); + +// Must be last. + +int upb_Unicode_ToUTF8(uint32_t cp, char* out) { + if (cp <= 0x7f) { + out[0] = cp; + return 1; + } + if (cp <= 0x07ff) { + out[0] = (cp >> 6) | 0xc0; + out[1] = (cp & 0x3f) | 0x80; + return 2; + } + if (cp <= 0xffff) { + out[0] = (cp >> 12) | 0xe0; + out[1] = ((cp >> 6) & 0x3f) | 0x80; + out[2] = (cp & 0x3f) | 0x80; + return 3; + } + if (cp <= 0x10ffff) { + out[0] = (cp >> 18) | 0xf0; + out[1] = ((cp >> 12) & 0x3f) | 0x80; + out[2] = ((cp >> 6) & 0x3f) | 0x80; + out[3] = (cp & 0x3f) | 0x80; + return 4; + } + return 0; } -static const char* 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); +#include - while (ptr < d->end) { - char ch = *ptr++; - if (ch <= kUpb_EncodedValue_MaxField) { - if (!d->table && last_field) { - // For extensions, consume only a single field and then return. - return --ptr; - } - 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. - } else { - upb_MtDecoder_ErrorFormat(d, "Invalid char: %c", ch); - UPB_UNREACHABLE(); - } - } +// Must be last. - if (need_dense_below) { - d->table->dense_below = d->table->field_count; +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); } - - return ptr; } -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); +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - 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); +// Must be last. + +static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { + return (uint32_t*)(cleanup_metadata & ~0x1); } -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_cleanup_has_initial_block(uintptr_t cleanup_metadata) { + return cleanup_metadata & 0x1; } -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); - } +static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, + bool has_initial_block) { + return (uintptr_t)cleanup | has_initial_block; +} - if (d->vec.size) { - qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), - upb_MtDecoder_CompareFields); - } +struct _upb_MemBlock { + struct _upb_MemBlock* next; + uint32_t size; + uint32_t cleanups; + // Data follows. +}; - return true; -} +typedef struct cleanup_ent { + upb_CleanupFunc* cleanup; + void* ud; +} cleanup_ent; -static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { - return (n + d - 1) / d; +static const size_t memblock_reserve = + UPB_ALIGN_UP(sizeof(_upb_MemBlock), 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; } -static void upb_MtDecoder_AssignHasbits(upb_MiniTable* ret) { - int n = ret->field_count; - int last_hasbit = 0; // 0 cannot be used. +size_t upb_Arena_SpaceAllocated(upb_Arena* arena) { + arena = arena_findroot(arena); + size_t memsize = 0; - // 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; + _upb_MemBlock* block = arena->freelist; - // 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; - } + while (block) { + memsize += sizeof(_upb_MemBlock) + block->size; + block = block->next; } - ret->size = last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; + return memsize; } -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); - static const size_t max = UINT16_MAX; - size_t new_size = ret + size; - if (new_size > max) { - upb_MtDecoder_ErrorFormat( - d, "Message size exceeded maximum size of %zu bytes", max); - } - d->table->size = new_size; - return ret; +uint32_t upb_Arena_DebugRefCount(upb_Arena* arena) { + return arena_findroot(arena)->refcount; } -static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { - upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); +static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, + size_t size) { + _upb_MemBlock* block = ptr; - // Compute offsets. - for (upb_LayoutItem* item = d->vec.data; item < end; item++) { - item->offset = upb_MtDecoder_Place(d, item->rep); - } + /* 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; - // 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]; - } - } + 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)); - // 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; - } - } + UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); +} - // 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); +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; + _upb_MemBlock* block = upb_malloc(root->block_alloc, block_size); + + if (!block) return false; + upb_Arena_addblock(a, root, block, block_size); + return true; } -static void upb_MiniTable_BuildMapEntry(upb_MtDecoder* d, - upb_FieldType key_type, - upb_FieldType value_type, - bool value_is_proto3_enum) { - upb_MiniTable_Field* fields = upb_Arena_Malloc(d->arena, sizeof(*fields) * 2); - if (!fields) { - upb_MtDecoder_ErrorFormat(d, "OOM while building map mini table field"); - UPB_UNREACHABLE(); - } +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); +} - upb_MiniTable_Sub* subs = NULL; - if (value_is_proto3_enum) { - UPB_ASSERT(value_type == kUpb_FieldType_Enum); - // No sub needed. - } else if (value_type == kUpb_FieldType_Message || - value_type == kUpb_FieldType_Group || - value_type == kUpb_FieldType_Enum) { - subs = upb_Arena_Malloc(d->arena, sizeof(*subs)); - if (!subs) { - upb_MtDecoder_ErrorFormat(d, "OOM while building map mini table sub"); - UPB_UNREACHABLE(); - } +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 ***********************************************************/ + +static 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; } - size_t field_size = - upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, d->platform); + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + n -= sizeof(*a); - 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; + 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_MiniTable_SetTypeAndSub(&fields[0], key_type, NULL, 0, false); - upb_MiniTable_SetTypeAndSub(&fields[1], value_type, NULL, 0, - value_is_proto3_enum); + upb_Arena_addblock(a, a, mem, n); - upb_MiniTable* ret = d->table; - 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 a; } -static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data, - size_t len) { - if (len < 2) { - upb_MtDecoder_ErrorFormat(d, "Invalid map encode length: %zu", len); - UPB_UNREACHABLE(); - } - const upb_EncodedType e0 = _upb_FromBase92(data[0]); - const upb_EncodedType e1 = _upb_FromBase92(data[1]); - switch (e0) { - case kUpb_EncodedType_Fixed32: - case kUpb_EncodedType_Fixed64: - case kUpb_EncodedType_SFixed32: - case kUpb_EncodedType_SFixed64: - case kUpb_EncodedType_Int32: - case kUpb_EncodedType_UInt32: - case kUpb_EncodedType_SInt32: - case kUpb_EncodedType_Int64: - case kUpb_EncodedType_UInt64: - case kUpb_EncodedType_SInt64: - case kUpb_EncodedType_Bool: - case kUpb_EncodedType_String: - break; +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { + upb_Arena* a; - default: - upb_MtDecoder_ErrorFormat(d, "Invalid map key field type: %d", e0); - UPB_UNREACHABLE(); - } - if (e1 >= sizeof(kUpb_EncodedToType)) { - upb_MtDecoder_ErrorFormat(d, "Invalid map value field type: %d", e1); - UPB_UNREACHABLE(); + 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; } - const upb_FieldType key_type = kUpb_EncodedToType[e0]; - const upb_FieldType val_type = kUpb_EncodedToType[e1]; - const bool value_is_proto3_enum = (e1 == kUpb_EncodedType_OpenEnum); - upb_MiniTable_BuildMapEntry(d, key_type, val_type, value_is_proto3_enum); -} -static void upb_MtDecoder_ParseMessageSet(upb_MtDecoder* d, const char* data, - size_t len) { - if (len > 0) { - upb_MtDecoder_ErrorFormat(d, "Invalid message set encode length: %zu", len); - UPB_UNREACHABLE(); + /* 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); } - upb_MiniTable* ret = d->table; - ret->size = 0; - ret->field_count = 0; - ret->ext = kUpb_ExtMode_IsMessageSet; - ret->dense_below = 0; - ret->table_mask = -1; - ret->required_count = 0; -} - -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; - } + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table); + 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->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, true); - 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; + return a; +} - // Strip off and verify the version tag. - if (!len--) goto done; - const char vers = *data++; +static void arena_dofree(upb_Arena* a) { + _upb_MemBlock* block = a->freelist; + UPB_ASSERT(a->parent == a); + UPB_ASSERT(a->refcount == 0); - switch (vers) { - case kUpb_EncodedVersion_MapV1: - upb_MtDecoder_ParseMap(&decoder, data, len); - break; + while (block) { + /* Load first since we are deleting block. */ + _upb_MemBlock* next = block->next; - case kUpb_EncodedVersion_MessageV1: - upb_MtDecoder_ParseMessage(&decoder, data, len); - upb_MtDecoder_AssignHasbits(decoder.table); - upb_MtDecoder_SortLayoutItems(&decoder); - upb_MtDecoder_AssignOffsets(&decoder); - break; + if (block->cleanups > 0) { + cleanup_ent* end = UPB_PTR_AT(block, block->size, void); + cleanup_ent* ptr = end - block->cleanups; - case kUpb_EncodedVersion_MessageSetV1: - upb_MtDecoder_ParseMessageSet(&decoder, data, len); - break; + for (; ptr < end; ptr++) { + ptr->cleanup(ptr->ud); + } + } - default: - upb_MtDecoder_ErrorFormat(&decoder, "Invalid message version: %c", vers); - UPB_UNREACHABLE(); + upb_free(a->block_alloc, block); + block = next; } - -done: - *buf = decoder.vec.data; - *buf_size = decoder.vec.capacity * sizeof(*decoder.vec.data); - return decoder.table; } -static size_t upb_MiniTable_EnumSize(size_t count) { - return sizeof(upb_MiniTable_Enum) + count * sizeof(uint32_t); +void upb_Arena_Free(upb_Arena* a) { + a = arena_findroot(a); + if (--a->refcount == 0) arena_dofree(a); } -static upb_MiniTable_Enum* _upb_MiniTable_AddEnumDataMember(upb_MtDecoder* d, - uint32_t val) { - if (d->enum_data_count == d->enum_data_capacity) { - size_t old_sz = upb_MiniTable_EnumSize(d->enum_data_capacity); - d->enum_data_capacity = UPB_MAX(2, d->enum_data_capacity * 2); - size_t new_sz = upb_MiniTable_EnumSize(d->enum_data_capacity); - d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); - upb_MtDecoder_CheckOutOfMemory(d, d->enum_table); - } - d->enum_table->data[d->enum_data_count++] = val; - return d->enum_table; -} +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 upb_MiniTable_BuildEnumValue(upb_MtDecoder* d, uint32_t val) { - upb_MiniTable_Enum* table = d->enum_table; - d->enum_value_count++; - if (table->value_count || (val > 512 && d->enum_value_count < val / 32)) { - if (table->value_count == 0) { - assert(d->enum_data_count == table->mask_limit / 32); - } - table = _upb_MiniTable_AddEnumDataMember(d, val); - table->value_count++; - } else { - uint32_t new_mask_limit = ((val / 32) + 1) * 32; - while (table->mask_limit < new_mask_limit) { - table = _upb_MiniTable_AddEnumDataMember(d, 0); - table->mask_limit += 32; - } - table->data[val / 32] |= 1ULL << (val % 32); + 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); } -} -upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, - upb_Arena* arena, - upb_Status* status) { - upb_MtDecoder decoder = { - .enum_table = upb_Arena_Malloc(arena, upb_MiniTable_EnumSize(2)), - .enum_value_count = 0, - .enum_data_count = 0, - .enum_data_capacity = 1, - .status = status, - .end = UPB_PTRADD(data, len), - .arena = arena, - }; + a->head.end -= sizeof(cleanup_ent); + ent = (cleanup_ent*)a->head.end; + (*cleanups)++; + UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); - if (UPB_SETJMP(decoder.err)) return NULL; + ent->cleanup = func; + ent->ud = ud; - // If the string is non-empty then it must begin with a version tag. - if (len) { - if (*data != kUpb_EncodedVersion_EnumV1) { - upb_MtDecoder_ErrorFormat(&decoder, "Invalid enum version: %c", *data); - UPB_UNREACHABLE(); - } - data++; - len--; - } + return true; +} - upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.enum_table); +bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { + upb_Arena* r1 = arena_findroot(a1); + upb_Arena* r2 = arena_findroot(a2); - // Guarantee at least 64 bits of mask without checking mask size. - decoder.enum_table->mask_limit = 64; - decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); - decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); + if (r1 == r2) return true; /* Already fused. */ - decoder.enum_table->value_count = 0; + /* 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; - const char* ptr = data; - uint32_t base = 0; + /* Only allow fuse with a common allocator */ + if (r1->block_alloc != r2->block_alloc) return false; - while (ptr < decoder.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) upb_MiniTable_BuildEnumValue(&decoder, base); - } - } else if (kUpb_EncodedValue_MinSkip <= ch && - ch <= kUpb_EncodedValue_MaxSkip) { - uint32_t skip; - ptr = upb_MiniTable_DecodeBase92Varint(&decoder, ptr, ch, - kUpb_EncodedValue_MinSkip, - kUpb_EncodedValue_MaxSkip, &skip); - base += skip; - } else { - upb_Status_SetErrorFormat(status, "Unexpected character: %c", ch); - return NULL; - } + /* 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; } - return decoder.enum_table; + /* 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; } -const char* upb_MiniTable_BuildExtension(const char* data, size_t len, - upb_MiniTable_Extension* ext, - const upb_MiniTable* extendee, - upb_MiniTable_Sub sub, - upb_Status* status) { - upb_MtDecoder decoder = { - .arena = NULL, - .status = status, - .table = NULL, - }; - - if (UPB_SETJMP(decoder.err)) return NULL; - - // If the string is non-empty then it must begin with a version tag. - if (len) { - if (*data != kUpb_EncodedVersion_ExtensionV1) { - upb_MtDecoder_ErrorFormat(&decoder, "Invalid ext version: %c", *data); - UPB_UNREACHABLE(); - } - data++; - len--; - } - uint16_t count = 0; - const char* ret = - upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); - if (!ret || count != 1) return NULL; - upb_MiniTable_Field* f = &ext->field; +// Must be last. - f->mode |= kUpb_LabelFlags_IsExtension; - f->offset = 0; - f->presence = 0; +static size_t _upb_MiniTableField_Size(const upb_MiniTableField* 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]; +} - if (extendee->ext & kUpb_ExtMode_IsMessageSet) { - // Extensions of MessageSet must be messages. - if (!upb_IsSubMessage(f)) return NULL; +// Maps descriptor type to elem_size_lg2. +static int _upb_MiniTableField_CTypeLg2Size(const upb_MiniTableField* f) { + static const uint8_t sizes[] = { + -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 */ + }; + return sizes[f->descriptortype]; +} - // Extensions of MessageSet must be non-repeating. - if ((f->mode & kUpb_FieldMode_Mask) == kUpb_FieldMode_Array) return NULL; +void upb_MiniTable_ClearField(upb_Message* msg, + const upb_MiniTableField* field) { + char* mem = UPB_PTR_AT(msg, field->offset, char); + if (field->presence > 0) { + _upb_clearhas_field(msg, field); + } else if (_upb_MiniTableField_InOneOf(field)) { + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (*oneof_case != field->number) return; + *oneof_case = 0; } + memset(mem, 0, _upb_MiniTableField_Size(field)); +} - ext->extendee = extendee; - ext->sub = sub; - - return ret; +void* upb_MiniTable_ResizeArray(upb_Message* msg, + const upb_MiniTableField* field, size_t len, + upb_Arena* arena) { + return _upb_Array_Resize_accessor2( + msg, field->offset, len, _upb_MiniTableField_CTypeLg2Size(field), arena); } -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); +typedef struct { + const char* ptr; + uint64_t val; +} decode_vret; + +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; } -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 = (field->mode & ~kUpb_FieldMode_Mask) | kUpb_FieldMode_Map; +UPB_FORCEINLINE +static const char* decode_varint64(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 NULL; + *val = res.val; + return res.ptr; } - 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_FORCEINLINE +static const char* decode_tag(const char* ptr, uint32_t* val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = (uint32_t)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 NULL; // Malformed. + } + *val = (uint32_t)res.val; + return res.ptr; + } } -#include - - -// Must be last. - -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; +// Parses unknown data by merging into existing base_message or creating a +// new message usingg mini_table. +static upb_UnknownToMessageRet upb_MiniTable_ParseUnknownMessage( + const char* unknown_data, size_t unknown_size, + const upb_MiniTable* mini_table, upb_Message* base_message, + int decode_options, upb_Arena* arena) { + upb_UnknownToMessageRet ret; + ret.message = + base_message ? base_message : _upb_Message_New(mini_table, arena); + if (!ret.message) { + ret.status = kUpb_UnknownToMessage_OutOfMemory; + return ret; + } + // Decode sub message using unknown field contents. + const char* data = unknown_data; + uint32_t tag; + uint64_t message_len = 0; + data = decode_tag(data, &tag); + data = decode_varint64(data, &message_len); + upb_DecodeStatus status = upb_Decode(data, message_len, ret.message, + mini_table, NULL, decode_options, arena); + if (status == kUpb_DecodeStatus_OutOfMemory) { + ret.status = kUpb_UnknownToMessage_OutOfMemory; + } else if (status == kUpb_DecodeStatus_Ok) { + ret.status = kUpb_UnknownToMessage_Ok; + } else { + ret.status = kUpb_UnknownToMessage_ParseError; + } return ret; } -static char* upb_MtDataEncoder_PutRaw(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++ = ch; - return ptr; +upb_GetExtension_Status upb_MiniTable_GetOrPromoteExtension( + upb_Message* msg, const upb_MiniTableExtension* ext_table, + int decode_options, upb_Arena* arena, + const upb_Message_Extension** extension) { + UPB_ASSERT(ext_table->field.descriptortype == kUpb_FieldType_Message); + *extension = _upb_Message_Getext(msg, ext_table); + if (*extension) { + return kUpb_GetExtension_Ok; + } + + // Check unknown fields, if available promote. + int field_number = ext_table->field.number; + upb_FindUnknownRet result = upb_MiniTable_FindUnknown(msg, field_number); + if (result.status != kUpb_FindUnknown_Ok) { + return kUpb_GetExtension_NotPresent; + } + // Decode and promote from unknown. + const upb_MiniTable* extension_table = ext_table->sub.submsg; + upb_UnknownToMessageRet parse_result = upb_MiniTable_ParseUnknownMessage( + result.ptr, result.len, extension_table, + /* base_message= */ NULL, decode_options, arena); + switch (parse_result.status) { + case kUpb_UnknownToMessage_OutOfMemory: + return kUpb_GetExtension_OutOfMemory; + case kUpb_UnknownToMessage_ParseError: + return kUpb_GetExtension_ParseError; + case kUpb_UnknownToMessage_NotFound: + return kUpb_GetExtension_NotPresent; + case kUpb_UnknownToMessage_Ok: + break; + } + upb_Message* extension_msg = parse_result.message; + // Add to extensions. + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, ext_table, arena); + if (!ext) { + return kUpb_GetExtension_OutOfMemory; + } + memcpy(&ext->data, &extension_msg, sizeof(extension_msg)); + *extension = ext; + upb_Message_DeleteUnknown(msg, result.ptr, result.len); + return kUpb_GetExtension_Ok; +} + +upb_GetExtensionAsBytes_Status upb_MiniTable_GetExtensionAsBytes( + const upb_Message* msg, const upb_MiniTableExtension* ext_table, + int encode_options, upb_Arena* arena, const char** extension_data, + size_t* len) { + const upb_Message_Extension* msg_ext = _upb_Message_Getext(msg, ext_table); + UPB_ASSERT(ext_table->field.descriptortype == kUpb_FieldType_Message); + if (msg_ext) { + upb_EncodeStatus status = + upb_Encode(msg_ext->data.ptr, msg_ext->ext->sub.submsg, encode_options, + arena, (char**)extension_data, len); + if (status != kUpb_EncodeStatus_Ok) { + return kUpb_GetExtensionAsBytes_EncodeError; + } + return kUpb_GetExtensionAsBytes_Ok; + } + int field_number = ext_table->field.number; + upb_FindUnknownRet result = upb_MiniTable_FindUnknown(msg, field_number); + if (result.status != kUpb_FindUnknown_Ok) { + return kUpb_GetExtensionAsBytes_NotPresent; + } + const char* data = result.ptr; + uint32_t tag; + uint64_t message_len = 0; + data = decode_tag(data, &tag); + data = decode_varint64(data, &message_len); + *extension_data = data; + *len = message_len; + return kUpb_GetExtensionAsBytes_Ok; } -static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { - return upb_MtDataEncoder_PutRaw(e, ptr, _upb_ToBase92(ch)); +static const char* UnknownFieldSet_SkipGroup(const char* ptr, const char* end, + int group_number); + +static const char* UnknownFieldSet_SkipField(const char* ptr, const char* end, + 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(ptr, &val); + } + case kUpb_WireType_64Bit: + if (end - ptr < 8) return NULL; + return ptr + 8; + case kUpb_WireType_32Bit: + if (end - ptr < 4) return NULL; + return ptr + 4; + case kUpb_WireType_Delimited: { + uint64_t size; + ptr = decode_varint64(ptr, &size); + if (!ptr || end - ptr < size) return NULL; + return ptr + size; + } + case kUpb_WireType_StartGroup: + return UnknownFieldSet_SkipGroup(ptr, end, field_number); + case kUpb_WireType_EndGroup: + return NULL; + default: + assert(0); + return NULL; + } } -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)); +static const char* UnknownFieldSet_SkipGroup(const char* ptr, const char* end, + int group_number) { + uint32_t end_tag = (group_number << 3) | kUpb_WireType_EndGroup; + while (true) { + if (ptr == end) return NULL; + uint64_t tag; + ptr = decode_varint64(ptr, &tag); if (!ptr) return NULL; - val >>= shift; - } while (val); + if (tag == end_tag) return ptr; + ptr = UnknownFieldSet_SkipField(ptr, end, (uint32_t)tag); + if (!ptr) return NULL; + } 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); +enum { + kUpb_MessageSet_StartItemTag = (1 << 3) | kUpb_WireType_StartGroup, + kUpb_MessageSet_EndItemTag = (1 << 3) | kUpb_WireType_EndGroup, + kUpb_MessageSet_TypeIdTag = (2 << 3) | kUpb_WireType_Varint, + kUpb_MessageSet_MessageTag = (3 << 3) | kUpb_WireType_Delimited, +}; + +upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg, + uint32_t field_number) { + size_t size; + upb_FindUnknownRet ret; + + const char* ptr = upb_Message_GetUnknown(msg, &size); + if (size == 0) { + ret.status = kUpb_FindUnknown_NotPresent; + ret.ptr = NULL; + ret.len = 0; + return ret; } - return ptr; -} + const char* end = ptr + size; + uint64_t uint64_val; -char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr, - upb_FieldType type, uint32_t field_num, - uint64_t field_mod) { - upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); - in->state.msg_state.msg_modifiers = 0; - in->state.msg_state.last_field_num = 0; - in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + while (ptr < end) { + uint32_t tag = 0; + int field; + int wire_type; + const char* unknown_begin = ptr; + ptr = decode_tag(ptr, &tag); + field = tag >> 3; + wire_type = tag & 7; + switch (wire_type) { + case kUpb_WireType_EndGroup: + ret.status = kUpb_FindUnknown_ParseError; + return ret; + case kUpb_WireType_Varint: + ptr = decode_varint64(ptr, &uint64_val); + if (!ptr) { + ret.status = kUpb_FindUnknown_ParseError; + return ret; + } + break; + case kUpb_WireType_32Bit: + ptr += 4; + break; + case kUpb_WireType_64Bit: + ptr += 8; + break; + case kUpb_WireType_Delimited: + // Read size. + ptr = decode_varint64(ptr, &uint64_val); + if (uint64_val >= INT32_MAX || !ptr) { + ret.status = kUpb_FindUnknown_ParseError; + return ret; + } + ptr += uint64_val; + break; + case kUpb_WireType_StartGroup: + // tag >> 3 specifies the group number, recurse and skip + // until we see group end tag. + ptr = UnknownFieldSet_SkipGroup(ptr, end, field_number); + break; + default: + ret.status = kUpb_FindUnknown_ParseError; + return ret; + } + if (field_number == field) { + ret.status = kUpb_FindUnknown_Ok; + ret.ptr = unknown_begin; + ret.len = ptr - unknown_begin; + return ret; + } + } + ret.status = kUpb_FindUnknown_NotPresent; + ret.ptr = NULL; + ret.len = 0; + return ret; +} - ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_ExtensionV1); - if (!ptr) return NULL; +upb_UnknownToMessageRet upb_MiniTable_PromoteUnknownToMessage( + upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTableField* field, const upb_MiniTable* sub_mini_table, + int decode_options, upb_Arena* arena) { + upb_FindUnknownRet unknown; + // We need to loop and merge unknowns that have matching tag field->number. + upb_Message* message = NULL; + // Callers should check that message is not set first before calling + // PromotoUnknownToMessage. + UPB_ASSERT(upb_MiniTable_GetMessage(msg, field, NULL) == NULL); + upb_UnknownToMessageRet ret; + ret.status = kUpb_UnknownToMessage_Ok; + do { + unknown = upb_MiniTable_FindUnknown(msg, field->number); + switch (unknown.status) { + case kUpb_FindUnknown_Ok: { + const char* unknown_data = unknown.ptr; + size_t unknown_size = unknown.len; + ret = upb_MiniTable_ParseUnknownMessage(unknown_data, unknown_size, + sub_mini_table, message, + decode_options, arena); + if (ret.status == kUpb_UnknownToMessage_Ok) { + message = ret.message; + upb_Message_DeleteUnknown(msg, unknown_data, unknown_size); + } + } break; + case kUpb_FindUnknown_ParseError: + ret.status = kUpb_UnknownToMessage_ParseError; + break; + case kUpb_FindUnknown_NotPresent: + // If we parsed at least one unknown, we are done. + ret.status = + message ? kUpb_UnknownToMessage_Ok : kUpb_UnknownToMessage_NotFound; + break; + } + } while (unknown.status == kUpb_FindUnknown_Ok); + if (message) { + upb_MiniTable_SetMessage(msg, mini_table, field, message); + ret.message = message; + } + return ret; +} - return upb_MtDataEncoder_PutField(e, ptr, type, field_num, field_mod); +// Moves repeated messages in unknowns to a upb_Array. +// +// Since the repeated field is not a scalar type we don't check for +// kUpb_LabelFlags_IsPacked. +// TODO(b/251007554): Optimize. Instead of converting messages one at a time, +// scan all unknown data once and compact. +upb_UnknownToMessage_Status upb_MiniTable_PromoteUnknownToMessageArray( + upb_Message* msg, const upb_MiniTableField* field, + const upb_MiniTable* mini_table, int decode_options, upb_Arena* arena) { + upb_Array* repeated_messages = upb_MiniTable_GetMutableArray(msg, field); + // Find all unknowns with given field number and parse. + upb_FindUnknownRet unknown; + do { + unknown = upb_MiniTable_FindUnknown(msg, field->number); + if (unknown.status == kUpb_FindUnknown_Ok) { + upb_UnknownToMessageRet ret = upb_MiniTable_ParseUnknownMessage( + unknown.ptr, unknown.len, mini_table, + /* base_message= */ NULL, decode_options, arena); + if (ret.status == kUpb_UnknownToMessage_Ok) { + upb_MessageValue value; + value.msg_val = ret.message; + if (!upb_Array_Append(repeated_messages, value, arena)) { + return kUpb_UnknownToMessage_OutOfMemory; + } + upb_Message_DeleteUnknown(msg, unknown.ptr, unknown.len); + } else { + return ret.status; + } + } + } while (unknown.status == kUpb_FindUnknown_Ok); + return kUpb_UnknownToMessage_Ok; } -char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr, - upb_FieldType key_type, - upb_FieldType value_type, - uint64_t value_mod) { - upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); - in->state.msg_state.msg_modifiers = 0; - in->state.msg_state.last_field_num = 0; - in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; - ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MapV1); - if (!ptr) return NULL; +#include - ptr = upb_MtDataEncoder_PutField(e, ptr, key_type, 1, 0); - if (!ptr) return NULL; - return upb_MtDataEncoder_PutField(e, ptr, value_type, 2, value_mod); -} +// Must be last. -char* upb_MtDataEncoder_EncodeMessageSet(upb_MtDataEncoder* e, char* ptr) { - (void)upb_MtDataEncoder_GetInternal(e, ptr); - return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageSetV1); -} +const float kUpb_FltInfinity = INFINITY; +const double kUpb_Infinity = INFINITY; +const double kUpb_NaN = NAN; -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; +static const size_t overhead = sizeof(upb_Message_InternalData); - ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageV1); - if (!ptr) return NULL; +upb_Message* upb_Message_New(const upb_MiniTable* mini_table, + upb_Arena* arena) { + return _upb_Message_New(mini_table, arena); +} - return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); +void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) { + // Note: Can't use UPB_PTR_AT() here because we are doing pointer subtraction. + char* mem = (char*)msg - sizeof(upb_Message_Internal); + memset(mem, 0, upb_msg_sizeof(l)); } -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_OpenEnum, - [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. - int encoded_type = kUpb_TypeToEncoded[type]; - if (field_mod & kUpb_FieldModifier_IsClosedEnum) { - UPB_ASSERT(type == kUpb_FieldType_Enum); - encoded_type = kUpb_EncodedType_ClosedEnum; - } - 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_FieldType_IsPackable(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; - } +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; } - ptr = upb_MtDataEncoder_Put(e, ptr, encoded_type); - if (!ptr) return NULL; + UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need); + return true; +} - if (field_mod & kUpb_FieldModifier_IsProto3Singular) { - encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; - } - if (field_mod & kUpb_FieldModifier_IsRequired) { - encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; +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; } - 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)); +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) { + const upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (in->internal) { + *len = in->internal->unknown_end - overhead; + return (char*)(in->internal + 1); } else { - ptr = upb_MtDataEncoder_Put( - e, ptr, _upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); + *len = 0; + return NULL; } - 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; +void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + const char* internal_unknown_end = + UPB_PTR_AT(in->internal, in->internal->unknown_end, char); +#ifndef NDEBUG + size_t full_unknown_size; + const char* full_unknown = upb_Message_GetUnknown(msg, &full_unknown_size); + UPB_ASSERT((uintptr_t)data >= (uintptr_t)full_unknown); + UPB_ASSERT((uintptr_t)data < (uintptr_t)(full_unknown + full_unknown_size)); + UPB_ASSERT((uintptr_t)(data + len) > (uintptr_t)data); + UPB_ASSERT((uintptr_t)(data + len) <= (uintptr_t)internal_unknown_end); +#endif + if ((data + len) != internal_unknown_end) { + memmove((char*)data, data + len, internal_unknown_end - data - len); } - 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; + in->internal->unknown_end -= len; } -char* upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e, char* ptr) { - upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); - in->state.enum_state.present_values_mask = 0; - in->state.enum_state.last_written_value = 0; - - return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_EnumV1); +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count) { + const upb_Message_Internal* in = upb_Message_Getinternal(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; + } } -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_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTableExtension* e) { + size_t n; + const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n); -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); - if (!ptr) { - return NULL; + /* 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]; } - 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; + return NULL; +} + +void _upb_Message_Clearext(upb_Message* msg, + const upb_MiniTableExtension* 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_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); - in->state.enum_state.present_values_mask |= 1ULL << delta; - return ptr; +upb_Message_Extension* _upb_Message_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTableExtension* 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; } -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); +size_t upb_Message_ExtensionCount(const upb_Message* msg) { + size_t count; + _upb_Message_Getexts(msg, &count); + return count; } -#include + +#include // Must be last. -/* 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}; -const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; +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', '{', '|', '}', '~', +}; -const char* _upb_DefBuilder_FullToShort(const char* fullname) { - const char* p; +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 (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_MiniTableField* 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; } -void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); } - -void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { - va_list argp; - va_start(argp, fmt); - upb_Status_VSetErrorFormat(ctx->status, fmt, argp); - va_end(argp); - _upb_DefBuilder_FailJmp(ctx); +upb_FieldType upb_MiniTableField_Type(const upb_MiniTableField* field) { + if (field->mode & kUpb_LabelFlags_IsAlternate) { + if (field->descriptortype == kUpb_FieldType_Int32) { + return kUpb_FieldType_Enum; + } else if (field->descriptortype == kUpb_FieldType_Bytes) { + return kUpb_FieldType_String; + } else { + UPB_ASSERT(false); + } + } + return field->descriptortype; } -void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { - upb_Status_SetErrorMessage(ctx->status, "out of memory"); - _upb_DefBuilder_FailJmp(ctx); -} -const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, - const char* prefix, - upb_StringView name) { - if (prefix) { - // ret = prefix + '.' + name; - size_t n = strlen(prefix); - char* ret = _upb_DefBuilder_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 { - char* ret = upb_strdup2(name.data, name.size, ctx->arena); - if (!ret) _upb_DefBuilder_OomErr(ctx); - return ret; - } -} +#include +#include -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; - } - } +// Must be last. - *len = 0; - return true; -} +// 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. -const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, - const char* from_name_dbg, - const char* base, upb_StringView sym, - upb_deftype_t* type) { - 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_DefPool_LookupSym(ctx->symtab, 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_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) { - break; - } - if (!remove_component(tmp, &baselen)) { - free(tmp); - goto notfound; - } - } - free(tmp); - } + kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, +} upb_LayoutItemType; - *type = _upb_DefType_Type(v); - return _upb_DefType_Unpack(v, *type); +#define kUpb_LayoutItem_IndexSentinel ((uint16_t)-1) -notfound: - _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(sym)); -} +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; -const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, - const char* from_name_dbg, const char* base, - upb_StringView sym, upb_deftype_t type) { - upb_deftype_t found_type; - const void* ret = - _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); - if (ret && found_type != type) { - _upb_DefBuilder_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; -} +typedef struct { + upb_LayoutItem* data; + size_t size; + size_t capacity; +} upb_LayoutItemVector; -// 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. -static char upb_ascii_lower(char ch) { return ch | 0x20; } +typedef struct { + const char* end; + upb_MiniTable* table; + upb_MiniTableField* fields; + upb_MiniTablePlatform platform; + upb_LayoutItemVector vec; + upb_Arena* arena; + upb_Status* status; -// 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 low <= c && c <= high; -} + // When building enums. + upb_MiniTableEnum* enum_table; + uint32_t enum_value_count; + uint32_t enum_data_count; + uint32_t enum_data_capacity; -static bool upb_isletter(char c) { - char lower = upb_ascii_lower(c); - return upb_isbetween(lower, 'a', 'z') || c == '_'; -} + jmp_buf err; +} upb_MtDecoder; -static bool upb_isalphanum(char c) { - return upb_isletter(c) || upb_isbetween(c, '0', '9'); +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 bool TryGetChar(const char** src, const char* end, char* ch) { - if (*src == end) return false; - *ch = **src; - *src += 1; - return true; +static void upb_MtDecoder_CheckOutOfMemory(upb_MtDecoder* d, const void* ptr) { + if (!ptr) upb_MtDecoder_ErrorFormat(d, "Out of memory"); } -static char TryGetHexDigit(const char** src, const char* end) { - char ch; - if (!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; +// 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); + val |= bits << shift; + if (ptr == d->end || *ptr < min || max < *ptr) { + *out_val = val; + return ptr; + } + ch = *ptr++; + shift += bits_per_char; + if (shift >= 32) upb_MtDecoder_ErrorFormat(d, "Overlong varint"); } - *src -= 1; // Char wasn't actually a hex digit. - return -1; } -static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, - const upb_FieldDef* f, - const char** src, const char* end) { - char hex_digit = TryGetHexDigit(src, end); - if (hex_digit < 0) { - _upb_DefBuilder_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 = TryGetHexDigit(src, end)) >= 0) { - ret = (ret << 4) | hex_digit; - } - if (ret > 0xff) { - _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", - upb_FieldDef_FullName(f)); - return 0; +static bool upb_MiniTable_HasSub(upb_MiniTableField* 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; + field->mode |= kUpb_LabelFlags_IsAlternate; + } + return false; + default: + return false; } - return ret; } -static char TryGetOctalDigit(const char** src, const char* end) { - char ch; - if (!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; +static bool upb_MtDecoder_FieldIsPackable(upb_MiniTableField* field) { + return (field->mode & kUpb_FieldMode_Array) && + _upb_FieldType_IsPackable(field->descriptortype); } -static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* 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 = TryGetOctalDigit(src, end)) >= 0) { - ch = (ch << 3) | digit; - } +static void upb_MiniTable_SetTypeAndSub(upb_MiniTableField* field, + upb_FieldType type, uint32_t* sub_count, + uint64_t msg_modifiers, + bool is_proto3_enum) { + field->descriptortype = type; + + if (is_proto3_enum) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum); + field->descriptortype = kUpb_FieldType_Int32; + field->mode |= kUpb_LabelFlags_IsAlternate; } - return ch; -} -char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, - const char** src, const char* end) { - char ch; - if (!TryGetChar(src, end, &ch)) { - _upb_DefBuilder_Errf(ctx, "unterminated escape sequence in field %s", - upb_FieldDef_FullName(f)); - return 0; + if (upb_MiniTable_HasSub(field, msg_modifiers)) { + field->submsg_index = sub_count ? (*sub_count)++ : 0; + } else { + field->submsg_index = kUpb_NoSub; } - 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_DefBuilder_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_DefBuilder_ParseOctalEscape(ctx, f, src, end); + + if (upb_MtDecoder_FieldIsPackable(field) && + (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { + field->mode |= kUpb_LabelFlags_IsPacked; } - _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); } -void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, - bool full) { - const char* str = name.data; - const size_t len = name.size; - bool start = true; - for (size_t i = 0; i < len; i++) { - const char c = str[i]; - if (c == '.') { - if (start || !full) { - _upb_DefBuilder_Errf( - ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", - UPB_STRINGVIEW_ARGS(name)); - } - start = true; - } else if (start) { - if (!upb_isletter(c)) { - _upb_DefBuilder_Errf(ctx, - "invalid name: path components must start with a " - "letter (" UPB_STRINGVIEW_FORMAT ")", - UPB_STRINGVIEW_ARGS(name)); - } - start = false; - } else if (!upb_isalphanum(c)) { - _upb_DefBuilder_Errf( - ctx, - "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT - ")", - UPB_STRINGVIEW_ARGS(name)); +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_OpenEnum] = 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, + [kUpb_EncodedType_ClosedEnum] = kUpb_FieldType_Enum, +}; + +static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, + upb_MiniTableField* 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_Bytes] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_OpenEnum] = 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, + [kUpb_EncodedType_ClosedEnum] = kUpb_FieldRep_4Byte, + }; + + char pointer_rep = d->platform == kUpb_MiniTablePlatform_32Bit + ? kUpb_FieldRep_4Byte + : kUpb_FieldRep_8Byte; + + int8_t type = _upb_FromBase92(ch); + if (ch >= _upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { + type -= kUpb_EncodedType_RepeatedBase; + field->mode = kUpb_FieldMode_Array; + field->mode |= pointer_rep << kUpb_FieldRep_Shift; + field->offset = kNoPresence; + } else { + field->mode = kUpb_FieldMode_Scalar; + field->offset = kHasbitPresence; + if (type == kUpb_EncodedType_Group || type == kUpb_EncodedType_Message) { + field->mode |= pointer_rep << kUpb_FieldRep_Shift; + } else if (type >= sizeof(kUpb_EncodedToFieldRep)) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); + } else { + field->mode |= kUpb_EncodedToFieldRep[type] << kUpb_FieldRep_Shift; } } - if (start) { - _upb_DefBuilder_Errf(ctx, - "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", - UPB_STRINGVIEW_ARGS(name)); + if (type >= sizeof(kUpb_EncodedToType)) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); } - - // We should never reach this point. - UPB_ASSERT(false); + upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_count, + msg_modifiers, type == kUpb_EncodedType_OpenEnum); } +static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, + uint32_t message_modifiers, + uint32_t field_modifiers, + upb_MiniTableField* 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; + } -// Must be last. + bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; + bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; -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; - void* scratch_data; - size_t scratch_size; - size_t bytes_loaded; -}; + // 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(); + } -void upb_DefPool_Free(upb_DefPool* s) { - upb_Arena_Free(s->arena); - upb_gfree(s->scratch_data); - upb_gfree(s); + if (singular) field->offset = kNoPresence; + if (required) { + field->offset = kRequiredPresence; + } } -upb_DefPool* upb_DefPool_New(void) { - upb_DefPool* s = upb_gmalloc(sizeof(*s)); - if (!s) return NULL; - - s->arena = upb_Arena_New(); - s->bytes_loaded = 0; +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; +} - s->scratch_size = 240; - s->scratch_data = upb_gmalloc(s->scratch_size); - if (!s->scratch_data) goto err; +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; - if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; - if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; - if (!upb_inttable_init(&s->exts, s->arena)) goto err; + // Push oneof data. + item.type = kUpb_LayoutItemType_OneofField; + upb_MtDecoder_PushItem(d, item); - s->extreg = upb_ExtensionRegistry_New(s->arena); - if (!s->extreg) goto err; + // Push oneof case. + item.rep = kUpb_FieldRep_4Byte; // Field Number. + item.type = kUpb_LayoutItemType_OneofCase; + upb_MtDecoder_PushItem(d, item); +} - return s; - -err: - upb_DefPool_Free(s); - return NULL; +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_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToSize64[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [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]; } -bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, - upb_FieldDef* f) { - return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), - s->arena); +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_StringView] = 4, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToAlign64[] = { + [kUpb_FieldRep_1Byte] = 1, + [kUpb_FieldRep_4Byte] = 4, + [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]; } -bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, - upb_Status* status) { - // TODO: table should support an operation "tryinsert" to avoid the double - // lookup. - if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) { - upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data); - return false; +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_MiniTableField* 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 (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) { - upb_Status_SetErrorMessage(status, "out of memory"); - return false; + if (f->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, + "Cannot add repeated, required, or singular field %" PRIu32 + " to oneof.", + field_num); + UPB_UNREACHABLE(); } - return true; -} - -static const void* _upb_DefPool_Unpack(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) - ? _upb_DefType_Unpack(v, type) - : NULL; -} - -bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, - upb_value* v) { - return upb_strtable_lookup2(&s->syms, sym, size, v); -} - -upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { - return s->extreg; -} - -void** _upb_DefPool_ScratchData(const upb_DefPool* s) { - return (void**)&s->scratch_data; -} -size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) { - return (size_t*)&s->scratch_size; + // 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; } -const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, - const char* sym) { - return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_MSG); -} +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_MessageDef* upb_DefPool_FindMessageByNameWithSize( - const upb_DefPool* s, const char* sym, size_t len) { - return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG); + // Push final oneof. + upb_MtDecoder_PushOneof(d, item); + return ptr; } -const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, - const char* sym) { - return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUM); -} +static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, + const char* ptr, char first_ch, + upb_MiniTableField* 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; + } -const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, - const char* sym) { - return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUMVAL); + return ptr; } -const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, - const char* name) { - upb_value v; - return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) - : NULL; +static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, uint32_t sub_count) { + size_t subs_bytes = sizeof(*d->table->subs) * sub_count; + void* subs = upb_Arena_Malloc(d->arena, subs_bytes); + memset(subs, 0, subs_bytes); + d->table->subs = subs; + upb_MtDecoder_CheckOutOfMemory(d, d->table->subs); } -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) - ? upb_value_getconstptr(v) - : NULL; -} +static const char* 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_MiniTableField* last_field = NULL; + bool need_dense_below = d->table != 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; + d->end = UPB_PTRADD(ptr, len); - switch (_upb_DefType_Type(v)) { - case UPB_DEFTYPE_FIELD: - return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); - return _upb_MessageDef_InMessageSet(m) - ? upb_MessageDef_NestedExtension(m, 0) - : NULL; + while (ptr < d->end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxField) { + if (!d->table && last_field) { + // For extensions, consume only a single field and then return. + return --ptr; + } + upb_MiniTableField* 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. + } else { + upb_MtDecoder_ErrorFormat(d, "Invalid char: %c", ch); + UPB_UNREACHABLE(); } - 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)); -} + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + } -const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, - const char* name) { - return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE); + return ptr; } -const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( - const upb_DefPool* s, const char* name, size_t size) { - return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE); -} +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); -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 (_upb_DefType_Type(v)) { - case UPB_DEFTYPE_EXT: { - const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); - return upb_FieldDef_File(f); - } - case UPB_DEFTYPE_MSG: { - const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); - return upb_MessageDef_File(m); - } - case UPB_DEFTYPE_ENUM: { - const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); - return upb_EnumDef_File(e); - } - case UPB_DEFTYPE_ENUMVAL: { - const upb_EnumValueDef* ev = - _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); - return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); - } - case UPB_DEFTYPE_SERVICE: { - const upb_ServiceDef* service = - _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); - return upb_ServiceDef_File(service); - } - default: - UPB_UNREACHABLE(); - } - } + 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); - 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); - } - } - } + 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); +} - return NULL; +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 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 (_upb_DefType_Type(val)) { - case UPB_DEFTYPE_EXT: - f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); - break; - case UPB_DEFTYPE_MSG: - f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); - break; - case UPB_DEFTYPE_ENUM: - f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); - break; - case UPB_DEFTYPE_ENUMVAL: - f = upb_EnumDef_File(upb_EnumValueDef_Enum( - _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); - break; - case UPB_DEFTYPE_SERVICE: - f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); - break; - default: - UPB_UNREACHABLE(); - } +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_MiniTableField* 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 (f == file) upb_strtable_removeiter(&s->syms, &iter); + if (d->vec.size) { + qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), + upb_MtDecoder_CompareFields); } + + return true; } -static const upb_FileDef* _upb_DefPool_AddFile( - upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, - const upb_MiniTable_File* layout, upb_Status* status) { - const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); +static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { + return (n + d - 1) / d; +} - if (name.size == 0) { - upb_Status_SetErrorFormat(status, - "missing name in google_protobuf_FileDescriptorProto"); - return NULL; - } +static void upb_MtDecoder_AssignHasbits(upb_MiniTable* ret) { + int n = ret->field_count; + int last_hasbit = 0; // 0 cannot be used. - // Determine whether we already know about this file. - { - upb_value v; - if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { - upb_Status_SetErrorFormat(status, - "duplicate file name " UPB_STRINGVIEW_FORMAT, - UPB_STRINGVIEW_ARGS(name)); - return NULL; + // First assign required fields, which must have the lowest hasbits. + for (int i = 0; i < n; i++) { + upb_MiniTableField* field = (upb_MiniTableField*)&ret->fields[i]; + if (field->offset == kRequiredPresence) { + field->presence = ++last_hasbit; + } else if (field->offset == kNoPresence) { + field->presence = 0; } } + ret->required_count = last_hasbit; - upb_DefBuilder ctx = { - .symtab = s, - .layout = layout, - .msg_count = 0, - .enum_count = 0, - .ext_count = 0, - .status = status, - .file = NULL, - .arena = upb_Arena_New(), - .tmp_arena = upb_Arena_New(), - }; - - if (UPB_SETJMP(ctx.err)) { - UPB_ASSERT(!upb_Status_IsOk(status)); - if (ctx.file) { - remove_filedef(s, ctx.file); - ctx.file = NULL; + // Next assign non-required hasbit fields. + for (int i = 0; i < n; i++) { + upb_MiniTableField* field = (upb_MiniTableField*)&ret->fields[i]; + if (field->offset == kHasbitPresence) { + field->presence = ++last_hasbit; } - } else if (!ctx.arena || !ctx.tmp_arena) { - _upb_DefBuilder_OomErr(&ctx); - } else { - _upb_FileDef_Create(&ctx, file_proto); - upb_strtable_insert(&s->files, name.data, name.size, - upb_value_constptr(ctx.file), ctx.arena); - UPB_ASSERT(upb_Status_IsOk(status)); - upb_Arena_Fuse(s->arena, ctx.arena); } - if (ctx.arena) upb_Arena_Free(ctx.arena); - if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); - return ctx.file; + ret->size = last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; } -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); +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); + static const size_t max = UINT16_MAX; + size_t new_size = ret + size; + if (new_size > max) { + upb_MtDecoder_ErrorFormat( + d, "Message size exceeded maximum size of %zu bytes", max); + } + d->table->size = new_size; + return ret; } -/* 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); +static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { + upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); - if (upb_DefPool_FindFileByName(s, init->filename)) { - return true; + // Compute offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + item->offset = upb_MtDecoder_Place(d, item->rep); } - arena = upb_Arena_New(); - - for (; *deps; deps++) { - if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; + // 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_MiniTableField* 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]; + } } - file = google_protobuf_FileDescriptorProto_parse_ex( - init->descriptor.data, init->descriptor.size, NULL, - kUpb_DecodeOption_AliasString, arena); - s->bytes_loaded += init->descriptor.size; + // Assign offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + upb_MiniTableField* 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; + } + } - if (!file) { - upb_Status_SetErrorFormat( - &status, - "Failed to parse compiled-in descriptor for file '%s'. This should " - "never happen.", - init->filename); - goto err; - } + // 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); +} - const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; - if (!_upb_DefPool_AddFile(s, file, mt, &status)) { - goto err; +static void upb_MiniTable_BuildMapEntry(upb_MtDecoder* d, char key_type, + char val_type) { + upb_MiniTableField* fields = upb_Arena_Malloc(d->arena, sizeof(*fields) * 2); + if (!fields) { + upb_MtDecoder_ErrorFormat(d, "OOM while building map mini table field"); + UPB_UNREACHABLE(); } - 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; -} + size_t field_size = + upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, d->platform); -size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { - return s->bytes_loaded; -} + uint32_t sub_count = 0; + fields[0].number = 1; + fields[1].number = 2; + upb_MiniTable_SetField(d, key_type, &fields[0], 0, &sub_count); + upb_MiniTable_SetField(d, val_type, &fields[1], 0, &sub_count); + upb_MtDecoder_AllocateSubs(d, sub_count); -upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } + // Map entries have a pre-determined layout, regardless of types. + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].offset = 0; + fields[1].offset = field_size; -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_MiniTable* ret = d->table; + 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->fields = fields; } -const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, - const upb_MessageDef* m, - int32_t fieldnum) { - const upb_MiniTable* t = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Extension* ext = - upb_ExtensionRegistry_Lookup(s->extreg, t, fieldnum); - return ext ? upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; -} +static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data, + size_t len) { + if (len < 2) { + upb_MtDecoder_ErrorFormat(d, "Invalid map encode length: %zu", len); + UPB_UNREACHABLE(); + } + const upb_EncodedType key_type = _upb_FromBase92(data[0]); + switch (key_type) { + case kUpb_EncodedType_Fixed32: + case kUpb_EncodedType_Fixed64: + case kUpb_EncodedType_SFixed32: + case kUpb_EncodedType_SFixed64: + case kUpb_EncodedType_Int32: + case kUpb_EncodedType_UInt32: + case kUpb_EncodedType_SInt32: + case kUpb_EncodedType_Int64: + case kUpb_EncodedType_UInt64: + case kUpb_EncodedType_SInt64: + case kUpb_EncodedType_Bool: + case kUpb_EncodedType_String: + break; -const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( - const upb_DefPool* s) { - return s->extreg; + default: + upb_MtDecoder_ErrorFormat(d, "Invalid map key field type: %d", key_type); + UPB_UNREACHABLE(); + } + upb_MiniTable_BuildMapEntry(d, data[0], data[1]); } -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_MtDecoder_ParseMessageSet(upb_MtDecoder* d, const char* data, + size_t len) { + if (len > 0) { + upb_MtDecoder_ErrorFormat(d, "Invalid message set encode length: %zu", len); + UPB_UNREACHABLE(); } - *count = n; - return exts; -} -bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { - return _upb_DefPool_LoadDefInitEx(s, init, false); + upb_MiniTable* ret = d->table; + ret->size = 0; + ret->field_count = 0; + ret->ext = kUpb_ExtMode_IsMessageSet; + ret->dense_below = 0; + ret->table_mask = -1; + ret->required_count = 0; } +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)), + }; -// Must be last. + if (UPB_SETJMP(decoder.err)) { + decoder.table = NULL; + goto done; + } -upb_deftype_t _upb_DefType_Type(upb_value v) { - const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return num & UPB_DEFTYPE_MASK; -} + upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table); -upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { - uintptr_t num = (uintptr_t)ptr; - UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); - num |= type; - return upb_value_constptr((const void*)num); -} + 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; -const void* _upb_DefType_Unpack(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; -} + // Strip off and verify the version tag. + if (!len--) goto done; + const char vers = *data++; + switch (vers) { + case kUpb_EncodedVersion_MapV1: + upb_MtDecoder_ParseMap(&decoder, data, len); + break; -// Must be last. + case kUpb_EncodedVersion_MessageV1: + upb_MtDecoder_ParseMessage(&decoder, data, len); + upb_MtDecoder_AssignHasbits(decoder.table); + upb_MtDecoder_SortLayoutItems(&decoder); + upb_MtDecoder_AssignOffsets(&decoder); + break; -bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { - const size_t oldbufsize = d->bufsize; - const int used = d->ptr - d->buf; + case kUpb_EncodedVersion_MessageSetV1: + upb_MtDecoder_ParseMessageSet(&decoder, data, len); + break; - if (!d->buf) { - d->buf = upb_Arena_Malloc(a, d->bufsize); - if (!d->buf) return false; - d->ptr = d->buf; - d->e.end = d->buf + d->bufsize; + default: + upb_MtDecoder_ErrorFormat(&decoder, "Invalid message version: %c", vers); + UPB_UNREACHABLE(); } - if (oldbufsize - used < kUpb_MtDataEncoder_MinSize) { - d->bufsize *= 2; - d->buf = upb_Arena_Realloc(a, d->buf, oldbufsize, d->bufsize); - if (!d->buf) return false; - d->ptr = d->buf + used; - d->e.end = d->buf + d->bufsize; +done: + *buf = decoder.vec.data; + *buf_size = decoder.vec.capacity * sizeof(*decoder.vec.data); + return decoder.table; +} + +static size_t upb_MiniTableEnum_Size(size_t count) { + return sizeof(upb_MiniTableEnum) + count * sizeof(uint32_t); +} + +static upb_MiniTableEnum* _upb_MiniTable_AddEnumDataMember(upb_MtDecoder* d, + uint32_t val) { + if (d->enum_data_count == d->enum_data_capacity) { + size_t old_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); + d->enum_data_capacity = UPB_MAX(2, d->enum_data_capacity * 2); + size_t new_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); + d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); + upb_MtDecoder_CheckOutOfMemory(d, d->enum_table); } + d->enum_table->data[d->enum_data_count++] = val; + return d->enum_table; +} - return true; +static void upb_MiniTable_BuildEnumValue(upb_MtDecoder* d, uint32_t val) { + upb_MiniTableEnum* table = d->enum_table; + d->enum_value_count++; + if (table->value_count || (val > 512 && d->enum_value_count < val / 32)) { + if (table->value_count == 0) { + assert(d->enum_data_count == table->mask_limit / 32); + } + table = _upb_MiniTable_AddEnumDataMember(d, val); + table->value_count++; + } else { + uint32_t new_mask_limit = ((val / 32) + 1) * 32; + while (table->mask_limit < new_mask_limit) { + table = _upb_MiniTable_AddEnumDataMember(d, 0); + table->mask_limit += 32; + } + table->data[val / 32] |= 1ULL << (val % 32); + } } -#include +upb_MiniTableEnum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + upb_MtDecoder decoder = { + .enum_table = upb_Arena_Malloc(arena, upb_MiniTableEnum_Size(2)), + .enum_value_count = 0, + .enum_data_count = 0, + .enum_data_capacity = 1, + .status = status, + .end = UPB_PTRADD(data, len), + .arena = arena, + }; + if (UPB_SETJMP(decoder.err)) return NULL; -// Must be last. + // If the string is non-empty then it must begin with a version tag. + if (len) { + if (*data != kUpb_EncodedVersion_EnumV1) { + upb_MtDecoder_ErrorFormat(&decoder, "Invalid enum version: %c", *data); + UPB_UNREACHABLE(); + } + data++; + len--; + } -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; - bool is_sorted; // Whether all of the values are defined in ascending order. -}; - -upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { - return (upb_EnumDef*)&e[i]; -} + upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.enum_table); -// TODO: Maybe implement this on top of a ZCOS instead? -void _upb_EnumDef_Debug(const upb_EnumDef* e) { - fprintf(stderr, "enum %s (%p) {\n", e->full_name, e); - fprintf(stderr, " value_count: %d\n", e->value_count); - fprintf(stderr, " default: %d\n", e->defaultval); - fprintf(stderr, " is_sorted: %d\n", e->is_sorted); - fprintf(stderr, "}\n"); -} + // Guarantee at least 64 bits of mask without checking mask size. + decoder.enum_table->mask_limit = 64; + decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); + decoder.enum_table = _upb_MiniTable_AddEnumDataMember(&decoder, 0); -const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { - return e->layout; -} + decoder.enum_table->value_count = 0; -bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a) { - const char* name = upb_EnumValueDef_Name(v); - const upb_value val = upb_value_constptr(v); - bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, a); - if (!ok) return false; + const char* ptr = data; + uint32_t base = 0; - // Multiple enumerators can have the same number, first one wins. - const int number = upb_EnumValueDef_Number(v); - if (!upb_inttable_lookup(&e->iton, number, NULL)) { - return upb_inttable_insert(&e->iton, number, val, a); + while (ptr < decoder.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) upb_MiniTable_BuildEnumValue(&decoder, base); + } + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(&decoder, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + base += skip; + } else { + upb_Status_SetErrorFormat(status, "Unexpected character: %c", ch); + return NULL; + } } - return true; -} -const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { - return e->opts; + return decoder.enum_table; } -bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { - return e->opts != (void*)kUpbDefOptDefault; -} +const char* _upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, + upb_MiniTableSub sub, + upb_MiniTablePlatform platform, + upb_Status* status) { + upb_MtDecoder decoder = { + .arena = NULL, + .status = status, + .table = NULL, + .platform = platform, + }; -const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } + if (UPB_SETJMP(decoder.err)) return NULL; -const char* upb_EnumDef_Name(const upb_EnumDef* e) { - return _upb_DefBuilder_FullToShort(e->full_name); -} + // If the string is non-empty then it must begin with a version tag. + if (len) { + if (*data != kUpb_EncodedVersion_ExtensionV1) { + upb_MtDecoder_ErrorFormat(&decoder, "Invalid ext version: %c", *data); + UPB_UNREACHABLE(); + } + data++; + len--; + } -const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } + uint16_t count = 0; + const char* ret = + upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); + if (!ret || count != 1) return NULL; -const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { - return e->containing_type; -} + upb_MiniTableField* f = &ext->field; -int32_t upb_EnumDef_Default(const upb_EnumDef* e) { - UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); - return e->defaultval; -} + f->mode |= kUpb_LabelFlags_IsExtension; + f->offset = 0; + f->presence = 0; -int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } + if (extendee->ext & kUpb_ExtMode_IsMessageSet) { + // Extensions of MessageSet must be messages. + if (!upb_IsSubMessage(f)) return NULL; -const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, - const char* name) { - return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); -} + // Extensions of MessageSet must be non-repeating. + if ((f->mode & kUpb_FieldMode_Mask) == kUpb_FieldMode_Array) return NULL; + } -const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( - const upb_EnumDef* e, const char* name, size_t size) { - upb_value v; - return upb_strtable_lookup2(&e->ntoi, name, size, &v) - ? upb_value_getconstptr(v) - : NULL; -} + ext->extendee = extendee; + ext->sub = sub; -const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, - int32_t num) { - upb_value v; - return upb_inttable_lookup(&e->iton, num, &v) ? upb_value_getconstptr(v) - : NULL; + return ret; } -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); +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; } -const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { - UPB_ASSERT(0 <= i && i < e->value_count); - return _upb_EnumValueDef_At(e->values, i); +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTableField* 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 = (field->mode & ~kUpb_FieldMode_Mask) | kUpb_FieldMode_Map; + } + upb_MiniTableSub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->submsg = sub; } -bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { - if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; - return upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2; +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTableField* field, + const upb_MiniTableEnum* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + upb_MiniTableSub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->subenum = sub; } -bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, - upb_StringView* out) { - upb_DescState s; - _upb_DescState_Init(&s); - - const upb_EnumValueDef** sorted = NULL; - if (!e->is_sorted) { - sorted = _upb_EnumValueDefs_Sorted(e->values, e->value_count, a); - if (!sorted) return false; - } +#include - if (!_upb_DescState_Grow(&s, a)) return false; - s.ptr = upb_MtDataEncoder_StartEnum(&s.e, s.ptr); - // Duplicate values are allowed but we only encode each value once. - uint32_t previous = 0; +// Must be last. - for (size_t i = 0; i < e->value_count; i++) { - const uint32_t current = - upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i)); - if (i != 0 && previous == current) continue; +typedef struct { + uint64_t present_values_mask; + uint32_t last_written_value; +} upb_MtDataEncoderInternal_EnumState; - if (!_upb_DescState_Grow(&s, a)) return false; - s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current); - previous = current; - } +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; - if (!_upb_DescState_Grow(&s, a)) return false; - s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr); +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; - // There will always be room for this '\0' in the encoder buffer because - // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum(). - UPB_ASSERT(s.ptr < s.buf + s.bufsize); - *s.ptr = '\0'; +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; +} - out->data = s.buf; - out->size = s.ptr - s.buf; - return true; +static char* upb_MtDataEncoder_PutRaw(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++ = ch; + return ptr; } -static upb_MiniTable_Enum* create_enumlayout(upb_DefBuilder* ctx, - const upb_EnumDef* e) { - upb_StringView sv; - bool ok = upb_EnumDef_MiniDescriptorEncode(e, ctx->tmp_arena, &sv); - if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); +static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { + return upb_MtDataEncoder_PutRaw(e, ptr, _upb_ToBase92(ch)); +} - upb_Status status; - upb_MiniTable_Enum* layout = - upb_MiniTable_BuildEnum(sv.data, sv.size, ctx->arena, &status); - if (!layout) - _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); - return layout; +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; } -static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_EnumDescriptorProto* enum_proto, - upb_EnumDef* e) { - const google_protobuf_EnumValueDescriptorProto* const* values; - upb_StringView name; - size_t n; +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; +} - // Must happen before _upb_DefBuilder_Add() - e->file = _upb_DefBuilder_File(ctx); +char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = 0; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; - name = google_protobuf_EnumDescriptorProto_name(enum_proto); - _upb_DefBuilder_CheckIdentNotFull(ctx, name); + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_ExtensionV1); + if (!ptr) return NULL; - e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - _upb_DefBuilder_Add(ctx, e->full_name, - _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); + return upb_MtDataEncoder_PutField(e, ptr, type, field_num, field_mod); +} - values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); +char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr, + upb_FieldType key_type, + upb_FieldType value_type, + uint64_t value_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = 0; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; - bool ok = upb_strtable_init(&e->ntoi, n, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MapV1); + if (!ptr) return NULL; - ok = upb_inttable_init(&e->iton, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + ptr = upb_MtDataEncoder_PutField(e, ptr, key_type, 1, 0); + if (!ptr) return NULL; - e->defaultval = 0; - e->value_count = n; - e->values = _upb_EnumValueDefs_New(ctx, prefix, n, values, e, &e->is_sorted); + return upb_MtDataEncoder_PutField(e, ptr, value_type, 2, value_mod); +} - if (n == 0) { - _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", - e->full_name); - } +char* upb_MtDataEncoder_EncodeMessageSet(upb_MtDataEncoder* e, char* ptr) { + (void)upb_MtDataEncoder_GetInternal(e, ptr); + return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageSetV1); +} - UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); +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; - upb_inttable_compact(&e->iton, ctx->arena); + ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageV1); + if (!ptr) return NULL; - if (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2) { - if (ctx->layout) { - UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); - e->layout = ctx->layout->enums[ctx->enum_count++]; - } else { - e->layout = create_enumlayout(ctx, e); - } - } else { - e->layout = NULL; - } + return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); } -upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, - const google_protobuf_EnumDescriptorProto* const* protos, - const upb_MessageDef* containing_type) { - _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); - - // If a containing type is defined then get the full name from that. - // Otherwise use the package name from the file def. - const char* name = containing_type ? upb_MessageDef_FullName(containing_type) - : _upb_FileDef_RawPackage(ctx->file); +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_OpenEnum, + [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_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); - for (size_t i = 0; i < n; i++) { - create_enumdef(ctx, name, protos[i], &e[i]); - e[i].containing_type = containing_type; + 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; } - return e; -} + in->state.msg_state.last_field_num = field_num; + uint32_t encoded_modifiers = 0; -// Must be last. + // Put field type. + int encoded_type = kUpb_TypeToEncoded[type]; + if (field_mod & kUpb_FieldModifier_IsClosedEnum) { + UPB_ASSERT(type == kUpb_FieldType_Enum); + encoded_type = kUpb_EncodedType_ClosedEnum; + } + 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; -struct upb_EnumValueDef { - const google_protobuf_EnumValueOptions* opts; - const upb_EnumDef* parent; - const char* full_name; - int32_t number; -}; + if (_upb_FieldType_IsPackable(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; -upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { - return (upb_EnumValueDef*)&v[i]; + 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 int _upb_EnumValueDef_Compare(const void* p1, const void* p2) { - const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number; - const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number; - return (v1 < v2) ? -1 : (v1 > v2); +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; } -const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, - int n, upb_Arena* a) { - // TODO: Try to replace this arena alloc with a persistent scratch buffer. - upb_EnumValueDef** out = - (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*)); - if (!out) return NULL; - - for (int i = 0; i < n; i++) { - out[i] = (upb_EnumValueDef*)&v[i]; +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; } - qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare); - - return (const upb_EnumValueDef**)out; + 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 google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( - const upb_EnumValueDef* v) { - return v->opts; -} +char* upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value = 0; -bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { - return v->opts != (void*)kUpbDefOptDefault; + return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_EnumV1); } -const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { - return v->parent; +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 char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { - return v->full_name; +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); + if (!ptr) { + return NULL; + } + 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; } -const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { - return _upb_DefBuilder_FullToShort(v->full_name); +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); } -int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } +#include -uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { - // Compute index in our parent's array. - return v - upb_EnumDef_Value(v->parent, 0); -} -static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_EnumValueDescriptorProto* val_proto, - upb_EnumDef* e, upb_EnumValueDef* v) { - upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); +// Must be last. - v->parent = e; // Must happen prior to _upb_DefBuilder_Add() - v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); - _upb_DefBuilder_Add(ctx, v->full_name, - _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); +/* 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}; +const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; - UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, - val_proto); +const char* _upb_DefBuilder_FullToShort(const char* fullname) { + const char* p; - bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + 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; + } } -// Allocate and initialize an array of |n| enum value defs owned by |e|. -upb_EnumValueDef* _upb_EnumValueDefs_New( - upb_DefBuilder* ctx, const char* prefix, int n, - const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, - bool* is_sorted) { - _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); +void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); } - upb_EnumValueDef* v = - _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n); +void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(ctx->status, fmt, argp); + va_end(argp); + _upb_DefBuilder_FailJmp(ctx); +} - *is_sorted = true; - uint32_t previous = 0; - for (size_t i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); +void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { + upb_Status_SetErrorMessage(ctx->status, "out of memory"); + _upb_DefBuilder_FailJmp(ctx); +} - const uint32_t current = v[i].number; - if (previous > current) *is_sorted = false; - previous = current; +const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, + const char* prefix, + upb_StringView name) { + if (prefix) { + // ret = prefix + '.' + name; + size_t n = strlen(prefix); + char* ret = _upb_DefBuilder_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 { + char* ret = upb_strdup2(name.data, name.size, ctx->arena); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; } +} - if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && - v[0].number != 0) { - _upb_DefBuilder_Errf(ctx, - "for proto3, the first enum value must be zero (%s)", - upb_EnumDef_FullName(e)); +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; + } } - return v; + *len = 0; + return true; } +const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, + const char* from_name_dbg, + const char* base, upb_StringView sym, + upb_deftype_t* type) { + 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_DefPool_LookupSym(ctx->symtab, 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_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) { + break; + } + if (!remove_component(tmp, &baselen)) { + free(tmp); + goto notfound; + } + } + free(tmp); + } -// Must be last. - -struct upb_ExtensionRange { - const google_protobuf_ExtensionRangeOptions* opts; - int32_t start; - int32_t end; -}; + *type = _upb_DefType_Type(v); + return _upb_DefType_Unpack(v, *type); -upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { - return (upb_ExtensionRange*)&r[i]; +notfound: + _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(sym)); } -const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( - const upb_ExtensionRange* r) { - return r->opts; +const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, + const char* from_name_dbg, const char* base, + upb_StringView sym, upb_deftype_t type) { + upb_deftype_t found_type; + const void* ret = + _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); + if (ret && found_type != type) { + _upb_DefBuilder_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; } -bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { - return r->opts != (void*)kUpbDefOptDefault; -} +// 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. +static char upb_ascii_lower(char ch) { return ch | 0x20; } -int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { - return r->start; +// 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 low <= c && c <= high; } -int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } - -upb_ExtensionRange* _upb_ExtensionRanges_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_DescriptorProto_ExtensionRange* const* protos, - const upb_MessageDef* m) { - upb_ExtensionRange* r = - _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); +static bool upb_isletter(char c) { + char lower = upb_ascii_lower(c); + return upb_isbetween(lower, 'a', 'z') || c == '_'; +} - for (int i = 0; i < n; i++) { - const int32_t start = - google_protobuf_DescriptorProto_ExtensionRange_start(protos[i]); - const int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(protos[i]); - const int32_t max = - google_protobuf_MessageOptions_message_set_wire_format(upb_MessageDef_Options(m)) - ? INT32_MAX - : kUpb_MaxFieldNumber + 1; +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} - // 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) { - _upb_DefBuilder_Errf(ctx, - "Extension range (%d, %d) is invalid, message=%s\n", - (int)start, (int)end, upb_MessageDef_FullName(m)); - } +static bool TryGetChar(const char** src, const char* end, char* ch) { + if (*src == end) return false; + *ch = **src; + *src += 1; + return true; +} - r[i].start = start; - r[i].end = end; - UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, protos[i]); +static char TryGetHexDigit(const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) return -1; + if ('0' <= ch && ch <= '9') { + return ch - '0'; } - - return r; + 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; } -#include -#include +static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, + const upb_FieldDef* f, + const char** src, const char* end) { + char hex_digit = TryGetHexDigit(src, end); + if (hex_digit < 0) { + _upb_DefBuilder_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 = TryGetHexDigit(src, end)) >= 0) { + ret = (ret << 4) | hex_digit; + } + if (ret > 0xff) { + _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", + upb_FieldDef_FullName(f)); + return 0; + } + return ret; +} +static char TryGetOctalDigit(const char** src, const char* end) { + char ch; + if (!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; +} -// Must be last. - -#define UPB_FIELD_TYPE_UNSPECIFIED 0 +static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* 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 = TryGetOctalDigit(src, end)) >= 0) { + ch = (ch << 3) | digit; + } + } + return ch; +} -typedef struct { - size_t len; - char str[1]; // Null-terminated string data follows. -} str_t; +char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, + const char** src, const char* end) { + char ch; + if (!TryGetChar(src, end, &ch)) { + _upb_DefBuilder_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_DefBuilder_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_DefBuilder_ParseOctalEscape(ctx, f, src, end); + } + _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); +} -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 is_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 -}; +void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, + bool full) { + const char* str = name.data; + const size_t len = name.size; + bool start = true; + for (size_t i = 0; i < len; i++) { + const char c = str[i]; + if (c == '.') { + if (start || !full) { + _upb_DefBuilder_Errf( + ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + _upb_DefBuilder_Errf(ctx, + "invalid name: path components must start with a " + "letter (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } + start = false; + } else if (!upb_isalphanum(c)) { + _upb_DefBuilder_Errf( + ctx, + "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT + ")", + UPB_STRINGVIEW_ARGS(name)); + } + } + if (start) { + _upb_DefBuilder_Errf(ctx, + "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", + UPB_STRINGVIEW_ARGS(name)); + } -upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { - return (upb_FieldDef*)&f[i]; + // We should never reach this point. + UPB_ASSERT(false); } -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*)kUpbDefOptDefault; -} +// Must be last. -const char* upb_FieldDef_FullName(const upb_FieldDef* f) { - return f->full_name; -} +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_MiniTableExtension*) -> (upb_FieldDef*) + upb_ExtensionRegistry* extreg; + void* scratch_data; + size_t scratch_size; + size_t bytes_loaded; +}; -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(); +void upb_DefPool_Free(upb_DefPool* s) { + upb_Arena_Free(s->arena); + upb_gfree(s->scratch_data); + upb_gfree(s); } -upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } +upb_DefPool* upb_DefPool_New(void) { + upb_DefPool* s = upb_gmalloc(sizeof(*s)); + if (!s) return NULL; -uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } + s->arena = upb_Arena_New(); + s->bytes_loaded = 0; -upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } + s->scratch_size = 240; + s->scratch_data = upb_gmalloc(s->scratch_size); + if (!s->scratch_data) goto err; -uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } + if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; + if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; + if (!upb_inttable_init(&s->exts, s->arena)) goto err; -bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { - return f->is_extension_; -} + s->extreg = upb_ExtensionRegistry_New(s->arena); + if (!s->extreg) goto err; -bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->is_packed_; } + return s; -const char* upb_FieldDef_Name(const upb_FieldDef* f) { - return _upb_DefBuilder_FullToShort(f->full_name); +err: + upb_DefPool_Free(s); + return NULL; } -const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { - return f->json_name; +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, + upb_FieldDef* f) { + return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), + s->arena); } -bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { - return f->has_json_name_; +bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, + upb_Status* status) { + // TODO: table should support an operation "tryinsert" to avoid the double + // lookup. + if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) { + upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data); + return false; + } + if (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) { + upb_Status_SetErrorMessage(status, "out of memory"); + return false; + } + return true; } -const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } - -const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { - return f->msgdef; +static const void* _upb_DefPool_Unpack(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) + ? _upb_DefType_Unpack(v, type) + : NULL; } -const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { - return f->is_extension_ ? f->scope.extension_scope : NULL; +bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, + upb_value* v) { + return upb_strtable_lookup2(&s->syms, sym, size, v); } -const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { - return f->is_extension_ ? NULL : f->scope.oneof; +upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { + return s->extreg; } -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; +void** _upb_DefPool_ScratchData(const upb_DefPool* s) { + return (void**)&s->scratch_data; } -upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsSubMessage(f)); - upb_MessageValue ret; - - 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(); - } - - return ret; +size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) { + return (size_t*)&s->scratch_size; } -const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; +const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_MSG); } -const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; +const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( + const upb_DefPool* s, const char* sym, size_t len) { + return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG); } -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) { - UPB_ASSERT(!upb_FieldDef_IsExtension(f)); - const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); - return &layout->fields[f->layout_index]; +const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUM); } -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( - const upb_FieldDef* f) { - UPB_ASSERT(upb_FieldDef_IsExtension(f)); - const upb_FileDef* file = upb_FieldDef_File(f); - return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); +const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s, + const char* sym) { + return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUMVAL); } -bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) { - if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; - if (f->type_ != kUpb_FieldType_Enum) return false; - - // TODO: Maybe make is_proto2 a bool at creation? - const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef); - return upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; +const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, + const char* name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) + : NULL; } -bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { - return f->proto3_optional_; +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) + ? upb_value_getconstptr(v) + : NULL; } -int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } - -uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { - uint64_t out = f->is_packed_ ? kUpb_FieldModifier_IsPacked : 0; +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 (f->label_) { - case kUpb_Label_Optional: - if (!upb_FieldDef_HasPresence(f)) { - out |= kUpb_FieldModifier_IsProto3Singular; - } - break; - case kUpb_Label_Repeated: - out |= kUpb_FieldModifier_IsRepeated; - break; - case kUpb_Label_Required: - out |= kUpb_FieldModifier_IsRequired; + switch (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_FIELD: + return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return _upb_MessageDef_InMessageSet(m) + ? upb_MessageDef_NestedExtension(m, 0) + : NULL; + } + default: break; } - if (_upb_FieldDef_IsClosedEnum(f)) { - out |= kUpb_FieldModifier_IsClosedEnum; - } - return out; -} - -bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } - -bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { - if (upb_FieldDef_IsRepeated(f)) return false; - const upb_FileDef* file = upb_FieldDef_File(f); - return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || - upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; + return NULL; } -bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { - return upb_FieldDef_IsSubMessage(f) || - upb_FieldDef_CType(f) == kUpb_CType_Enum; +const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, + const char* sym) { + return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); } -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_DefPool_FindServiceByName(const upb_DefPool* s, + const char* name) { + return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE); } -bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Optional; +const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( + const upb_DefPool* s, const char* name, size_t size) { + return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE); } -bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { - return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); -} +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 (_upb_DefType_Type(v)) { + case UPB_DEFTYPE_EXT: { + const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); + return upb_FieldDef_File(f); + } + case UPB_DEFTYPE_MSG: { + const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); + return upb_MessageDef_File(m); + } + case UPB_DEFTYPE_ENUM: { + const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); + return upb_EnumDef_File(e); + } + case UPB_DEFTYPE_ENUMVAL: { + const upb_EnumValueDef* ev = + _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); + return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); + } + case UPB_DEFTYPE_SERVICE: { + const upb_ServiceDef* service = + _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); + return upb_ServiceDef_File(service); + } + default: + UPB_UNREACHABLE(); + } + } -bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Repeated; -} + 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); + } + } + } -bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Required; + return NULL; } -bool upb_FieldDef_IsString(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_String || - upb_FieldDef_CType(f) == kUpb_CType_Bytes; -} +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 (_upb_DefType_Type(val)) { + case UPB_DEFTYPE_EXT: + f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); + break; + case UPB_DEFTYPE_MSG: + f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); + break; + case UPB_DEFTYPE_ENUM: + f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); + break; + case UPB_DEFTYPE_ENUMVAL: + f = upb_EnumDef_File(upb_EnumValueDef_Enum( + _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); + break; + case UPB_DEFTYPE_SERVICE: + f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); + break; + default: + UPB_UNREACHABLE(); + } -bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Message; + if (f == file) upb_strtable_removeiter(&s->syms, &iter); + } } -static bool between(int32_t x, int32_t low, int32_t high) { - return x >= low && x <= high; -} +static const upb_FileDef* _upb_DefPool_AddFile( + upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, + const upb_MiniTableFile* layout, upb_Status* status) { + const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); -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); } + if (name.size == 0) { + upb_Status_SetErrorFormat(status, + "missing name in google_protobuf_FileDescriptorProto"); + return NULL; + } -bool upb_FieldDef_checkdescriptortype(int32_t type) { - return between(type, 1, 18); -} - -static bool streql2(const char* a, size_t n, const char* b) { - return n == strlen(b) && memcmp(a, b, n) == 0; -} + // Determine whether we already know about this file. + { + upb_value v; + if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { + upb_Status_SetErrorFormat(status, + "duplicate file name " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + return NULL; + } + } -// Implement the transformation as described in the spec: -// 1. upper case all letters after an underscore. -// 2. remove all underscores. -static char* make_json_name(const char* name, size_t size, upb_Arena* a) { - char* out = upb_Arena_Malloc(a, size + 1); // +1 is to add a trailing '\0' - if (out == NULL) return NULL; + upb_DefBuilder ctx = { + .symtab = s, + .layout = layout, + .msg_count = 0, + .enum_count = 0, + .ext_count = 0, + .status = status, + .file = NULL, + .arena = upb_Arena_New(), + .tmp_arena = upb_Arena_New(), + }; - bool ucase_next = false; - char* des = out; - for (size_t i = 0; i < size; i++) { - if (name[i] == '_') { - ucase_next = true; - } else { - *des++ = ucase_next ? toupper(name[i]) : name[i]; - ucase_next = false; + if (UPB_SETJMP(ctx.err)) { + UPB_ASSERT(!upb_Status_IsOk(status)); + if (ctx.file) { + remove_filedef(s, ctx.file); + ctx.file = NULL; } + } else if (!ctx.arena || !ctx.tmp_arena) { + _upb_DefBuilder_OomErr(&ctx); + } else { + _upb_FileDef_Create(&ctx, file_proto); + upb_strtable_insert(&s->files, name.data, name.size, + upb_value_constptr(ctx.file), ctx.arena); + UPB_ASSERT(upb_Status_IsOk(status)); + upb_Arena_Fuse(s->arena, ctx.arena); } - *des++ = '\0'; - return out; + + if (ctx.arena) upb_Arena_Free(ctx.arena); + if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena); + return ctx.file; } -static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { - str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); - if (!ret) _upb_DefBuilder_OomErr(ctx); - ret->len = len; - if (len) memcpy(ret->str, data, len); - ret->str[len] = '\0'; - return ret; +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 str_t* unescape(upb_DefBuilder* 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 = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); - char* dst = &ret->str[0]; - const char* src = data; - const char* end = data + len; +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; - while (src < end) { - if (*src == '\\') { - src++; - *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); - } else { - *dst++ = *src++; - } + upb_Status_Clear(&status); + + if (upb_DefPool_FindFileByName(s, init->filename)) { + return true; } - ret->len = dst - &ret->str[0]; - return ret; -} + arena = upb_Arena_New(); -static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, - upb_FieldDef* f) { - char* end; - char nullz[64]; - errno = 0; + for (; *deps; deps++) { + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; + } - 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) { - _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); - } - memcpy(nullz, str, len); - nullz[len] = '\0'; - str = nullz; - break; - default: - break; + file = google_protobuf_FileDescriptorProto_parse_ex( + init->descriptor.data, init->descriptor.size, NULL, + kUpb_DecodeOption_AliasString, arena); + s->bytes_loaded += init->descriptor.size; + + if (!file) { + upb_Status_SetErrorFormat( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; } - 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 = upb_EnumValueDef_Number(ev); - 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. */ - _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", - upb_FieldDef_FullName(f)); + const upb_MiniTableFile* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { + goto err; } - return; + upb_Arena_Free(arena); + return true; -invalid: - _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", - (int)len, str, upb_FieldDef_FullName(f), - (int)upb_FieldDef_Type(f)); +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 set_default_default(upb_DefBuilder* 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: { - const upb_EnumValueDef* v = upb_EnumDef_Value(f->sub.enumdef, 0); - f->defaultval.sint = upb_EnumValueDef_Number(v); - } - case kUpb_CType_Message: - break; - } +size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { + return s->bytes_loaded; } -static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_FieldDescriptorProto* field_proto, - upb_MessageDef* m, upb_FieldDef* f) { - // Must happen before _upb_DefBuilder_Add() - f->file = _upb_DefBuilder_File(ctx); - - if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - _upb_DefBuilder_Errf(ctx, "field has no name"); - } - - const upb_StringView name = google_protobuf_FieldDescriptorProto_name(field_proto); - _upb_DefBuilder_CheckIdentNotFull(ctx, name); - - f->has_json_name_ = google_protobuf_FieldDescriptorProto_has_json_name(field_proto); - if (f->has_json_name_) { - const upb_StringView sv = - google_protobuf_FieldDescriptorProto_json_name(field_proto); - f->json_name = upb_strdup2(sv.data, sv.size, ctx->arena); - } else { - f->json_name = make_json_name(name.data, name.size, ctx->arena); - } - if (!f->json_name) _upb_DefBuilder_OomErr(ctx); +upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } - f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); - f->number_ = google_protobuf_FieldDescriptorProto_number(field_proto); - f->proto3_optional_ = - google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); - f->msgdef = m; - f->scope.oneof = NULL; +const upb_FieldDef* upb_DefPool_FindExtensionByMiniTable( + const upb_DefPool* s, const upb_MiniTableExtension* ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} - const bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); - const bool has_type_name = - google_protobuf_FieldDescriptorProto_has_type_name(field_proto); +const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, + const upb_MessageDef* m, + int32_t fieldnum) { + const upb_MiniTable* t = upb_MessageDef_MiniTable(m); + const upb_MiniTableExtension* ext = + upb_ExtensionRegistry_Lookup(s->extreg, t, fieldnum); + return ext ? upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; +} - f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); +const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( + const upb_DefPool* s) { + return s->extreg; +} - if (has_type) { - switch (f->type_) { - case kUpb_FieldType_Message: - case kUpb_FieldType_Group: - case kUpb_FieldType_Enum: - if (!has_type_name) { - _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", - (int)f->type_, f->full_name); - } - break; - default: - if (has_type_name) { - _upb_DefBuilder_Errf( - ctx, "invalid type for field with type_name set (%s, %d)", - f->full_name, (int)f->type_); - } - } - } else if (has_type_name) { - f->type_ = - UPB_FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_fielddef() +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_next(&s->exts, &key, &val, &iter)) { + const upb_FieldDef* f = upb_value_getconstptr(val); + if (upb_FieldDef_ContainingType(f) == m) n++; } - - if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { - _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, - f->type_); + const upb_FieldDef** exts = malloc(n * sizeof(*exts)); + iter = UPB_INTTABLE_BEGIN; + size_t i = 0; + while (upb_inttable_next(&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; +} - if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { - _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, - f->label_); - } +bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { + return _upb_DefPool_LoadDefInitEx(s, init, false); +} - /* 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 && - upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { - _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", - f->full_name); - } +// Must be last. - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); +upb_deftype_t _upb_DefType_Type(upb_value v) { + const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return num & UPB_DEFTYPE_MASK; +} - if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { - _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", - f->full_name); - } +upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { + uintptr_t num = (uintptr_t)ptr; + UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); + num |= type; + return upb_value_constptr((const void*)num); +} - if (!m) { - _upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg", - f->full_name); - } +const void* _upb_DefType_Unpack(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; +} - if (oneof_index >= upb_MessageDef_OneofCount(m)) { - _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); - } - upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); - f->scope.oneof = oneof; +// Must be last. - bool ok = _upb_OneofDef_Insert(oneof, f, name.data, name.size, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - } +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { + const size_t oldbufsize = d->bufsize; + const int used = d->ptr - d->buf; - UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + if (!d->buf) { + d->buf = upb_Arena_Malloc(a, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf; + d->e.end = d->buf + d->bufsize; + } - if (google_protobuf_FieldOptions_has_packed(f->opts)) { - f->is_packed_ = google_protobuf_FieldOptions_packed(f->opts); - } else { - // Repeated fields default to packed for proto3 only. - f->is_packed_ = upb_FieldDef_IsPrimitive(f) && - f->label_ == kUpb_Label_Repeated && - upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; + if (oldbufsize - used < kUpb_MtDataEncoder_MinSize) { + d->bufsize *= 2; + d->buf = upb_Arena_Realloc(a, d->buf, oldbufsize, d->bufsize); + if (!d->buf) return false; + d->ptr = d->buf + used; + d->e.end = d->buf + d->bufsize; } + + return true; } -static void _upb_FieldDef_CreateExt( - upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, - upb_FieldDef* f) { - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); - f->is_extension_ = true; - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", - f->full_name); - } +// Must be last. - f->scope.extension_scope = m; - _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); - f->layout_index = ctx->ext_count++; +struct upb_EnumDef { + const google_protobuf_EnumOptions* opts; + const upb_MiniTableEnum* 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; + bool is_sorted; // Whether all of the values are defined in ascending order. +}; - if (ctx->layout) { - UPB_ASSERT(_upb_FieldDef_ExtensionMiniTable(f)->field.number == f->number_); - } +upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { + return (upb_EnumDef*)&e[i]; } -static void _upb_FieldDef_CreateNotExt( - upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, - upb_FieldDef* f) { - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); - f->is_extension_ = false; - - if (!google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - if (f->proto3_optional_) { - _upb_DefBuilder_Errf( - ctx, - "non-extension field (%s) with proto3_optional was not in a oneof", - f->full_name); - } - } +// TODO: Maybe implement this on top of a ZCOS instead? +void _upb_EnumDef_Debug(const upb_EnumDef* e) { + fprintf(stderr, "enum %s (%p) {\n", e->full_name, e); + fprintf(stderr, " value_count: %d\n", e->value_count); + fprintf(stderr, " default: %d\n", e->defaultval); + fprintf(stderr, " is_sorted: %d\n", e->is_sorted); + fprintf(stderr, "}\n"); +} - _upb_MessageDef_InsertField(ctx, m, f); +const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { + return e->layout; +} - if (!ctx->layout) return; +bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a) { + const char* name = upb_EnumValueDef_Name(v); + const upb_value val = upb_value_constptr(v); + bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, a); + if (!ok) return false; - const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); - const upb_MiniTable_Field* fields = mt->fields; - for (int i = 0; i < mt->field_count; i++) { - if (fields[i].number == f->number_) { - f->layout_index = i; - return; - } + // Multiple enumerators can have the same number, first one wins. + const int number = upb_EnumValueDef_Number(v); + if (!upb_inttable_lookup(&e->iton, number, NULL)) { + return upb_inttable_insert(&e->iton, number, val, a); } + return true; +} - UPB_ASSERT(false); // It should be impossible to reach this point. +const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { + return e->opts; } -upb_FieldDef* _upb_FieldDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, - upb_MessageDef* m, bool* is_sorted) { - _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); - upb_FieldDef* defs = - (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); +bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { + return e->opts != (void*)kUpbDefOptDefault; +} - // If we are creating extensions then is_sorted will be NULL. - // If we are not creating extensions then is_sorted will be non-NULL. - if (is_sorted) { - uint32_t previous = 0; - for (int i = 0; i < n; i++) { - upb_FieldDef* f = &defs[i]; +const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } - _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f); - f->index_ = i; - if (!ctx->layout) f->layout_index = i; +const char* upb_EnumDef_Name(const upb_EnumDef* e) { + return _upb_DefBuilder_FullToShort(e->full_name); +} - const uint32_t current = f->number_; - if (previous > current) *is_sorted = false; - previous = current; - } - } else { - for (int i = 0; i < n; i++) { - upb_FieldDef* f = &defs[i]; +const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } - _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f); - f->index_ = i; - } - } +const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { + return e->containing_type; +} - return defs; +int32_t upb_EnumDef_Default(const upb_EnumDef* e) { + UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); + return e->defaultval; } -static void resolve_subdef(upb_DefBuilder* 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 UPB_FIELD_TYPE_UNSPECIFIED: { - // Type was not specified and must be inferred. - UPB_ASSERT(has_name); - upb_deftype_t type; - const void* def = - _upb_DefBuilder_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: - _upb_DefBuilder_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 = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, - UPB_DEFTYPE_MSG); - break; - case kUpb_FieldType_Enum: - UPB_ASSERT(has_name); - f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, - UPB_DEFTYPE_ENUM); - break; - default: - // No resolution necessary. - break; - } +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e) { + return e->res_range_count; } -static int _upb_FieldDef_Compare(const void* p1, const void* p2) { - const uint32_t v1 = (*(upb_FieldDef**)p1)->number_; - const uint32_t v2 = (*(upb_FieldDef**)p2)->number_; - return (v1 < v2) ? -1 : (v1 > v2); +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_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, - upb_Arena* a) { - // TODO: Try to replace this arena alloc with a persistent scratch buffer. - upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*)); - if (!out) return NULL; +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e) { + return e->res_name_count; +} - for (int i = 0; i < n; i++) { - out[i] = (upb_FieldDef*)&f[i]; - } - qsort(out, n, sizeof(void*), _upb_FieldDef_Compare); +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]; +} - for (int i = 0; i < n; i++) { - out[i]->layout_index = i; - } - return (const upb_FieldDef**)out; +int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } + +const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, + const char* name) { + return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); } -bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, - upb_StringView* out) { - UPB_ASSERT(f->is_extension_); +const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( + const upb_EnumDef* e, const char* name, size_t size) { + upb_value v; + return upb_strtable_lookup2(&e->ntoi, name, size, &v) + ? upb_value_getconstptr(v) + : NULL; +} + +const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, + int32_t num) { + upb_value v; + return upb_inttable_lookup(&e->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_MiniTableEnum_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 _upb_EnumValueDef_At(e->values, i); +} + +bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; + return upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2; +} +bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, + upb_StringView* out) { upb_DescState s; _upb_DescState_Init(&s); - const int number = upb_FieldDef_Number(f); - const uint64_t modifiers = _upb_FieldDef_Modifiers(f); + const upb_EnumValueDef** sorted = NULL; + if (!e->is_sorted) { + sorted = _upb_EnumValueDefs_Sorted(e->values, e->value_count, a); + if (!sorted) return false; + } if (!_upb_DescState_Grow(&s, a)) return false; - s.ptr = upb_MtDataEncoder_EncodeExtension(&s.e, s.ptr, f->type_, number, - modifiers); + s.ptr = upb_MtDataEncoder_StartEnum(&s.e, s.ptr); + + // Duplicate values are allowed but we only encode each value once. + uint32_t previous = 0; + + for (size_t i = 0; i < e->value_count; i++) { + const uint32_t current = + upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i)); + if (i != 0 && previous == current) continue; + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current); + previous = current; + } + + if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr); + + // There will always be room for this '\0' in the encoder buffer because + // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum(). + UPB_ASSERT(s.ptr < s.buf + s.bufsize); *s.ptr = '\0'; out->data = s.buf; @@ -8058,1203 +7625,1134 @@ bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, return true; } -static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, - upb_FieldDef* f, - const google_protobuf_FieldDescriptorProto* field_proto) { - if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { - _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", - f->full_name); - } +static upb_MiniTableEnum* create_enumlayout(upb_DefBuilder* ctx, + const upb_EnumDef* e) { + upb_StringView sv; + bool ok = upb_EnumDef_MiniDescriptorEncode(e, ctx->tmp_arena, &sv); + if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); - upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); - const upb_MessageDef* m = - _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); - f->msgdef = m; + upb_Status status; + upb_MiniTableEnum* layout = + upb_MiniTable_BuildEnum(sv.data, sv.size, ctx->arena, &status); + if (!layout) + _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); + return layout; +} - if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) { - _upb_DefBuilder_Errf( - ctx, - "field number %u in extension %s has no extension range in message %s", - (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m)); +static upb_StringView* _upb_EnumReservedNames_New( + upb_DefBuilder* ctx, int n, const upb_StringView* protos) { + upb_StringView* sv = _upb_DefBuilder_Alloc(ctx, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; } + return sv; +} - const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f); +static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumDescriptorProto* enum_proto, + 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 n_value, n_res_range, n_res_name; - if (ctx->layout) { - UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); - } else { - upb_StringView desc; - if (!upb_FieldDef_MiniDescriptorEncode(f, ctx->tmp_arena, &desc)) { - _upb_DefBuilder_OomErr(ctx); - } + // Must happen before _upb_DefBuilder_Add() + e->file = _upb_DefBuilder_File(ctx); - upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext; - upb_MiniTable_Sub sub = {NULL}; - if (upb_FieldDef_IsSubMessage(f)) { - sub.submsg = upb_MessageDef_MiniTable(f->sub.msgdef); - } else if (_upb_FieldDef_IsClosedEnum(f)) { - sub.subenum = _upb_EnumDef_MiniTable(f->sub.enumdef); - } - bool ok2 = upb_MiniTable_BuildExtension(desc.data, desc.size, mut_ext, - upb_MessageDef_MiniTable(m), sub, - ctx->status); - if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table"); - } + name = google_protobuf_EnumDescriptorProto_name(enum_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); - bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f); + e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, e->full_name, + _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); + + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n_value); + + bool ok = upb_strtable_init(&e->ntoi, n_value, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); -} -static void resolve_default(upb_DefBuilder* 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); + ok = upb_inttable_init(&e->iton, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); - if (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { - _upb_DefBuilder_Errf(ctx, - "proto3 fields cannot have explicit defaults (%s)", - f->full_name); - } + e->defaultval = 0; + e->value_count = n_value; + e->values = + _upb_EnumValueDefs_New(ctx, prefix, n_value, values, e, &e->is_sorted); - if (upb_FieldDef_IsSubMessage(f)) { - _upb_DefBuilder_Errf(ctx, - "message fields cannot have explicit defaults (%s)", - f->full_name); - } + if (n_value == 0) { + _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", + e->full_name); + } - parse_default(ctx, defaultval.data, defaultval.size, f); - f->has_default = true; + 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); + + UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); + + upb_inttable_compact(&e->iton, ctx->arena); + + if (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2) { + if (ctx->layout) { + UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); + e->layout = ctx->layout->enums[ctx->enum_count++]; + } else { + e->layout = create_enumlayout(ctx, e); + } } else { - set_default_default(ctx, f); - f->has_default = false; + e->layout = NULL; } } -void _upb_FieldDef_Resolve(upb_DefBuilder* 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; +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); - resolve_subdef(ctx, prefix, f); - resolve_default(ctx, f, field_proto); + // If a containing type is defined then get the full name from that. + // Otherwise use the package name from the file def. + const char* name = containing_type ? upb_MessageDef_FullName(containing_type) + : _upb_FileDef_RawPackage(ctx->file); - if (f->is_extension_) { - resolve_extension(ctx, prefix, f, field_proto); + upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); + for (size_t i = 0; i < n; i++) { + create_enumdef(ctx, name, protos[i], &e[i]); + e[i].containing_type = containing_type; } + return e; } +// #include "upb/reflection/extension_range_internal.h" +// #include "upb/reflection/message_def.h" // Must be last. -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_EnumReservedRange { + int32_t start; + int32_t end; }; -const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { - return f->opts; +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i) { + return (upb_EnumReservedRange*)&r[i]; } -bool upb_FileDef_HasOptions(const upb_FileDef* f) { - return f->opts != (void*)kUpbDefOptDefault; +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r) { + return r->start; } - -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 : ""; +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r) { + return r->end; } -const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e) { + upb_EnumReservedRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumReservedRange) * n); -upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; } + 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; -int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { - return f->top_lvl_msg_count; -} + // 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. -int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } + // 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) { + _upb_DefBuilder_Errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", + (int)start, (int)end, upb_EnumDef_FullName(e)); + } -int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { - return f->public_dep_count; -} + r[i].start = start; + r[i].end = end; + } -int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { - return f->weak_dep_count; + return r; } -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; -} +// Must be last. -int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { - return f->top_lvl_enum_count; +struct upb_EnumValueDef { + const google_protobuf_EnumValueOptions* opts; + const upb_EnumDef* parent; + const char* full_name; + int32_t number; +}; + +upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { + return (upb_EnumValueDef*)&v[i]; } -int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { - return f->top_lvl_ext_count; +static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number; + const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number; + return (v1 < v2) ? -1 : (v1 > v2); } -int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } +const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, + int n, upb_Arena* a) { + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_EnumValueDef** out = + (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; -const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->dep_count); - return f->deps[i]; -} + for (int i = 0; i < n; i++) { + out[i] = (upb_EnumValueDef*)&v[i]; + } + qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare); -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]]; + return (const upb_EnumValueDef**)out; } -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]]; +const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( + const upb_EnumValueDef* v) { + return v->opts; } -const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); - return _upb_MessageDef_At(f->top_lvl_msgs, i); +bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { + return v->opts != (void*)kUpbDefOptDefault; } -const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); - return _upb_EnumDef_At(f->top_lvl_enums, i); +const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { + return v->parent; } -const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); - return _upb_FieldDef_At(f->top_lvl_exts, i); +const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { + return v->full_name; } -const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { - UPB_ASSERT(0 <= i && i < f->service_count); - return _upb_ServiceDef_At(f->services, i); +const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { + return _upb_DefBuilder_FullToShort(v->full_name); } -const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } +int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } -const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( - const upb_FileDef* f, int i) { - return f->ext_layouts[i]; +uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { + // Compute index in our parent's array. + return v - upb_EnumDef_Value(v->parent, 0); } -static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { - char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); - if (!ret) _upb_DefBuilder_OomErr(ctx); - return ret; -} +static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_EnumValueDescriptorProto* val_proto, + upb_EnumDef* e, upb_EnumValueDef* v) { + upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); -static bool streql_view(upb_StringView view, const char* b) { - return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; + v->parent = e; // Must happen prior to _upb_DefBuilder_Add() + v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); + _upb_DefBuilder_Add(ctx, v->full_name, + _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); + + UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); + + bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -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; +// Allocate and initialize an array of |n| enum value defs owned by |e|. +upb_EnumValueDef* _upb_EnumValueDefs_New( + upb_DefBuilder* ctx, const char* prefix, int n, + const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e, + bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); - const google_protobuf_DescriptorProto* const* nested_msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + upb_EnumValueDef* v = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n); + + *is_sorted = true; + uint32_t previous = 0; for (size_t i = 0; i < n; i++) { - ext_count += count_exts_in_msg(nested_msgs[i]); + create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); + + const uint32_t current = v[i].number; + if (previous > current) *is_sorted = false; + previous = current; } - return ext_count; + if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && + v[0].number != 0) { + _upb_DefBuilder_Errf(ctx, + "for proto3, the first enum value must be zero (%s)", + upb_EnumDef_FullName(e)); + } + + return v; } -// Allocate and initialize one file def, and add it to the context object. -void _upb_FileDef_Create(upb_DefBuilder* ctx, - const google_protobuf_FileDescriptorProto* file_proto) { - upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); - ctx->file = file; - 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 n; +// Must be last. - file->symtab = ctx->symtab; +struct upb_ExtensionRange { + const google_protobuf_ExtensionRangeOptions* opts; + int32_t start; + int32_t end; +}; - // 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_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { + return (upb_ExtensionRange*)&r[i]; +} - 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) { - _upb_DefBuilder_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 = _upb_DefBuilder_Alloc( - ctx, sizeof(*file->ext_layouts) * file->ext_count); - upb_MiniTable_Extension* ext = - _upb_DefBuilder_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)) { - _upb_DefBuilder_Errf(ctx, "File has no name"); - } - - file->name = strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); +const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( + const upb_ExtensionRange* r) { + return r->opts; +} - upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); - if (package.size) { - _upb_DefBuilder_CheckIdentFull(ctx, package); - file->package = strviewdup(ctx, package); - } else { - file->package = NULL; - } +bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { + return r->opts != (void*)kUpbDefOptDefault; +} - if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { - upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); +int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { + return r->start; +} - if (streql_view(syntax, "proto2")) { - file->syntax = kUpb_Syntax_Proto2; - } else if (streql_view(syntax, "proto3")) { - file->syntax = kUpb_Syntax_Proto3; - } else { - _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", - UPB_STRINGVIEW_ARGS(syntax)); - } - } else { - file->syntax = kUpb_Syntax_Proto2; - } +int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } - // Read options. - UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); +upb_ExtensionRange* _upb_ExtensionRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ExtensionRange* const* protos, + const upb_MessageDef* m) { + upb_ExtensionRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); - // Verify dependencies. - strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); - file->dep_count = n; - file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n); + for (int i = 0; i < n; i++) { + const int32_t start = + google_protobuf_DescriptorProto_ExtensionRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(protos[i]); + const int32_t max = + google_protobuf_MessageOptions_message_set_wire_format(upb_MessageDef_Options(m)) + ? INT32_MAX + : kUpb_MaxFieldNumber + 1; - for (size_t 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]) { + // 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) { _upb_DefBuilder_Errf(ctx, - "Depends on file '" UPB_STRINGVIEW_FORMAT - "', but it has not been loaded", - UPB_STRINGVIEW_ARGS(str)); + "Extension range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); } - } - public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); - file->public_dep_count = n; - file->public_deps = - _upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n); - int32_t* mutable_public_deps = (int32_t*)file->public_deps; - for (size_t i = 0; i < n; i++) { - if (public_deps[i] >= file->dep_count) { - _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", - (int)public_deps[i]); - } - mutable_public_deps[i] = public_deps[i]; + r[i].start = start; + r[i].end = end; + UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); } - weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); - file->weak_dep_count = n; - file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n); - int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; - for (size_t i = 0; i < n; i++) { - if (weak_deps[i] >= file->dep_count) { - _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", - (int)weak_deps[i]); - } - mutable_weak_deps[i] = weak_deps[i]; - } + return r; +} - // Create enums. - enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); - file->top_lvl_enum_count = n; - file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); +#include +#include - // Create extensions. - exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); - file->top_lvl_ext_count = n; - file->top_lvl_exts = - _upb_FieldDefs_New(ctx, n, exts, file->package, NULL, NULL); - // Create messages. - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - file->top_lvl_msg_count = n; - file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); +// Must be last. - // Create services. - services = google_protobuf_FileDescriptorProto_service(file_proto, &n); - file->service_count = n; - file->services = _upb_ServiceDefs_New(ctx, n, services); +#define UPB_FIELD_TYPE_UNSPECIFIED 0 - // Now that all names are in the table, build layouts and resolve refs. +typedef struct { + size_t len; + char str[1]; // Null-terminated string data follows. +} str_t; - for (int i = 0; i < file->top_lvl_msg_count; i++) { - upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); - _upb_MessageDef_Resolve(ctx, m); - } +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; + void* msg; // Always NULL. + } 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 is_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 +}; - for (int i = 0; i < file->top_lvl_ext_count; i++) { - upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); - _upb_FieldDef_Resolve(ctx, file->package, f); - } +upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { + return (upb_FieldDef*)&f[i]; +} - if (!ctx->layout) { - for (int i = 0; i < file->top_lvl_msg_count; i++) { - upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); - _upb_MessageDef_LinkMiniTable(ctx, m); - } - } +const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f) { + return f->opts; +} - if (file->ext_count) { - bool ok = upb_ExtensionRegistry_AddArray( - _upb_DefPool_ExtReg(ctx->symtab), file->ext_layouts, file->ext_count); - if (!ok) _upb_DefBuilder_OomErr(ctx); +bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { + return f->opts != (void*)kUpbDefOptDefault; +} + +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_; } -#include +uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } +upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } -// Must be last. +uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } -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]; +bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { + return f->is_extension_; } -static bool in_oneof(const upb_MiniTable_Field* field) { - return field->presence < 0; +bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->is_packed_; } + +const char* upb_FieldDef_Name(const upb_FieldDef* f) { + return _upb_DefBuilder_FullToShort(f->full_name); } -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; +const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { + return f->json_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; - } - } +bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { + return f->has_json_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; - } +const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } + +const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { + return f->msgdef; } -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); +const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { + return f->is_extension_ ? f->scope.extension_scope : NULL; } -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_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { + return f->is_extension_ ? NULL : f->scope.oneof; +} - upb_MessageValue val = upb_Message_Get(msg, f); - if (val.array_val) { - return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; - } +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_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)); - const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); - ret.msg = upb_Message_New(upb_MessageDef_MiniTable(m), a); +upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { + upb_MessageValue ret; + + if (upb_FieldDef_IsRepeated(f) || upb_FieldDef_IsSubMessage(f)) { + return (upb_MessageValue){.msg_val = NULL}; } - val.array_val = ret.array; - upb_Message_Set(msg, f, val, a); + 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(); + } return ret; } -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); - - // Building reflection should always cause all sub-message types to be - // linked, but double-check here just for extra assurance. - UPB_ASSERT(!upb_FieldDef_IsSubMessage(f) || - upb_MessageDef_MiniTable(upb_FieldDef_ContainingType(f)) - ->subs[field->submsg_index] - .submsg); +const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL; +} - 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; +const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL; } -void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) { +const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f) { if (upb_FieldDef_IsExtension(f)) { - _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f)); + const upb_FileDef* file = upb_FieldDef_File(f); + return (upb_MiniTableField*)_upb_FileDef_ExtensionMiniTable( + file, f->layout_index); } 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; - } - - memset(mem, 0, get_field_size(field)); + const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); + return &layout->fields[f->layout_index]; } } -void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { - _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); +const upb_MiniTableExtension* _upb_FieldDef_ExtensionMiniTable( + const upb_FieldDef* f) { + UPB_ASSERT(upb_FieldDef_IsExtension(f)); + const upb_FileDef* file = upb_FieldDef_File(f); + return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); } -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); +bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) { + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; + if (f->type_ != kUpb_FieldType_Enum) return false; - /* 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); + // TODO: Maybe make is_proto2 a bool at creation? + const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef); + return upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; +} - /* 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; +bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { + return f->proto3_optional_; +} - /* 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; - } - } +int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } - *out_val = val; - *out_f = f; - *iter = i; - return true; +uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { + uint64_t out = f->is_packed_ ? kUpb_FieldModifier_IsPacked : 0; + + switch (f->label_) { + case kUpb_Label_Optional: + if (!upb_FieldDef_HasPresence(f)) { + out |= kUpb_FieldModifier_IsProto3Singular; + } + break; + case kUpb_Label_Repeated: + out |= kUpb_FieldModifier_IsRepeated; + break; + case kUpb_Label_Required: + out |= kUpb_FieldModifier_IsRequired; + break; } - 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 (_upb_FieldDef_IsClosedEnum(f)) { + out |= kUpb_FieldModifier_IsClosedEnum; } + return out; +} - *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; - - 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; - } - } - } +bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } - return ret; +bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { + if (upb_FieldDef_IsRepeated(f)) return false; + const upb_FileDef* file = upb_FieldDef_File(f); + return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) || + upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2; } -bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, - int maxdepth) { - return _upb_Message_DiscardUnknown(msg, m, maxdepth); +bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { + return upb_FieldDef_IsSubMessage(f) || + upb_FieldDef_CType(f) == kUpb_CType_Enum; } - -// Must be last. - -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_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; - bool is_sorted; - upb_WellKnown well_known_type; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; - -static void assign_msg_wellknowntype(upb_MessageDef* m) { - const char* name = m->full_name; - 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; - } +bool upb_FieldDef_IsMap(const upb_FieldDef* f) { + return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && + upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); } -upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { - return (upb_MessageDef*)&m[i]; +bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Optional; } -bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) { - for (int i = 0; i < m->ext_range_count; i++) { - const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); - if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) { - return true; - } - } - return false; +bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { + return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); } -const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m) { - return m->opts; +bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Repeated; } -bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { - return m->opts != (void*)kUpbDefOptDefault; +bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Required; } -const char* upb_MessageDef_FullName(const upb_MessageDef* m) { - return m->full_name; +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_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { - return m->file; +bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Message; } -const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { - return m->containing_type; +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; } -const char* upb_MessageDef_Name(const upb_MessageDef* m) { - return _upb_DefBuilder_FullToShort(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); } -upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { - return upb_FileDef_Syntax(m->file); +bool upb_FieldDef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); } -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 bool streql2(const char* a, size_t n, const char* b) { + return n == strlen(b) && memcmp(a, b, n) == 0; } -const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( - const upb_MessageDef* m, const char* name, size_t size) { - upb_value val; +// Implement the transformation as described in the spec: +// 1. upper case all letters after an underscore. +// 2. remove all underscores. +static char* make_json_name(const char* name, size_t size, upb_Arena* a) { + char* out = upb_Arena_Malloc(a, size + 1); // +1 is to add a trailing '\0' + if (out == NULL) return NULL; - if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { - return NULL; + bool ucase_next = false; + char* des = out; + for (size_t i = 0; i < size; i++) { + if (name[i] == '_') { + ucase_next = true; + } else { + *des++ = ucase_next ? toupper(name[i]) : name[i]; + ucase_next = false; + } } + *des++ = '\0'; + return out; +} - return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { + str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + if (!ret) _upb_DefBuilder_OomErr(ctx); + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; } -const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( - const upb_MessageDef* m, const char* name, size_t size) { - upb_value val; +static str_t* unescape(upb_DefBuilder* 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 = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); + char* dst = &ret->str[0]; + const char* src = data; + const char* end = data + len; - if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { - return NULL; + while (src < end) { + if (*src == '\\') { + src++; + *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); + } else { + *dst++ = *src++; + } } - return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); + ret->len = dst - &ret->str[0]; + return ret; } -bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, - upb_value v, upb_Arena* a) { - return upb_strtable_insert(&m->ntof, name, len, v, a); -} +static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, + upb_FieldDef* f) { + char* end; + char nullz[64]; + errno = 0; -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; + 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) { + _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; } - const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); - const upb_OneofDef* o = _upb_DefType_Unpack(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 size) { - upb_value val; - const upb_FieldDef* f; - - if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { - return NULL; + 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 = upb_EnumValueDef_Number(ev); + 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. */ + _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", + upb_FieldDef_FullName(f)); } - f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); - if (!f) f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD_JSONNAME); - - return f; -} + return; -int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { - return m->ext_range_count; +invalid: + _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", + (int)len, str, upb_FieldDef_FullName(f), + (int)upb_FieldDef_Type(f)); } -int upb_MessageDef_FieldCount(const upb_MessageDef* m) { - return m->field_count; +static void set_default_default(upb_DefBuilder* 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: { + const upb_EnumValueDef* v = upb_EnumDef_Value(f->sub.enumdef, 0); + f->defaultval.sint = upb_EnumValueDef_Number(v); + break; + } + case kUpb_CType_Message: + break; + } } -int upb_MessageDef_OneofCount(const upb_MessageDef* m) { - return m->oneof_count; -} +static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, + upb_MessageDef* m, upb_FieldDef* f) { + // Must happen before _upb_DefBuilder_Add() + f->file = _upb_DefBuilder_File(ctx); -int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { - return m->nested_msg_count; -} + if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } -int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { - return m->nested_enum_count; -} + const upb_StringView name = google_protobuf_FieldDescriptorProto_name(field_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); -int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { - return m->nested_ext_count; -} + f->has_json_name_ = google_protobuf_FieldDescriptorProto_has_json_name(field_proto); + if (f->has_json_name_) { + const upb_StringView sv = + google_protobuf_FieldDescriptorProto_json_name(field_proto); + f->json_name = upb_strdup2(sv.data, sv.size, ctx->arena); + } else { + f->json_name = make_json_name(name.data, name.size, ctx->arena); + } + if (!f->json_name) _upb_DefBuilder_OomErr(ctx); -const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { - return m->layout; -} + f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); + f->number_ = google_protobuf_FieldDescriptorProto_number(field_proto); + f->proto3_optional_ = + google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + f->msgdef = m; + f->scope.oneof = NULL; -const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->ext_range_count); - return _upb_ExtensionRange_At(m->ext_ranges, i); -} + const bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); + const bool has_type_name = + google_protobuf_FieldDescriptorProto_has_type_name(field_proto); -const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->field_count); - return _upb_FieldDef_At(m->fields, i); -} + f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); -const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->oneof_count); - return _upb_OneofDef_At(m->oneofs, i); -} + if (has_type) { + switch (f->type_) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + if (!has_type_name) { + _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", + (int)f->type_, f->full_name); + } + break; + default: + if (has_type_name) { + _upb_DefBuilder_Errf( + ctx, "invalid type for field with type_name set (%s, %d)", + f->full_name, (int)f->type_); + } + } + } else if (has_type_name) { + f->type_ = + UPB_FIELD_TYPE_UNSPECIFIED; // We'll fill this in in resolve_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]; -} + if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { + _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, + f->type_); + } -const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { - UPB_ASSERT(0 <= i && i < m->nested_enum_count); - return _upb_EnumDef_At(m->nested_enums, i); -} + if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { + _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, + f->label_); + } -const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, - int i) { - UPB_ASSERT(0 <= i && i < m->nested_ext_count); - return _upb_FieldDef_At(m->nested_exts, i); -} - -upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { - return m->well_known_type; -} - -bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { - return m->in_message_set; -} - -const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, - const char* name) { - return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); -} - -const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, - const char* name) { - return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(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; -bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { - return google_protobuf_MessageOptions_map_entry(m->opts); -} + if (f->label_ == kUpb_Label_Required && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } -bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { - return google_protobuf_MessageOptions_message_set_wire_format(m->opts); -} + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); -static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx, - const upb_MessageDef* m) { - upb_StringView desc; - bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc); - if (!ok) _upb_DefBuilder_OomErr(ctx); + if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { + _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } - void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab); - size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab); - upb_MiniTable* ret = upb_MiniTable_BuildWithBuf( - desc.data, desc.size, kUpb_MiniTablePlatform_Native, ctx->arena, - scratch_data, scratch_size, ctx->status); - if (!ret) _upb_DefBuilder_FailJmp(ctx); - return ret; -} + if (!m) { + _upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg", + f->full_name); + } -void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { - for (int i = 0; i < m->field_count; i++) { - upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); - _upb_FieldDef_Resolve(ctx, m->full_name, f); - } + if (oneof_index >= upb_MessageDef_OneofCount(m)) { + _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); + } - if (!ctx->layout) { - m->layout = _upb_MessageDef_MakeMiniTable(ctx, m); - if (!m->layout) _upb_DefBuilder_OomErr(ctx); - } + upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); + f->scope.oneof = oneof; -#ifndef NDEBUG - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - const int layout_index = _upb_FieldDef_LayoutIndex(f); - UPB_ASSERT(layout_index < m->layout->field_count); - const upb_MiniTable_Field* mt_f = &m->layout->fields[layout_index]; - UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f)); + bool ok = _upb_OneofDef_Insert(oneof, f, name.data, name.size, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -#endif - m->in_message_set = false; - for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { - upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); - _upb_FieldDef_Resolve(ctx, m->full_name, ext); - if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && - upb_FieldDef_Label(ext) == kUpb_Label_Optional && - upb_FieldDef_MessageSubDef(ext) == m && - google_protobuf_MessageOptions_message_set_wire_format( - upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { - m->in_message_set = true; - } - } + UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); - for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { - upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); - _upb_MessageDef_Resolve(ctx, n); + if (google_protobuf_FieldOptions_has_packed(f->opts)) { + f->is_packed_ = google_protobuf_FieldOptions_packed(f->opts); + } else { + // Repeated fields default to packed for proto3 only. + f->is_packed_ = upb_FieldDef_IsPrimitive(f) && + f->label_ == kUpb_Label_Repeated && + upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; } } -void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, - const upb_FieldDef* f) { - const int32_t field_number = upb_FieldDef_Number(f); +static void _upb_FieldDef_CreateExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + f->is_extension_ = true; - if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { - _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); } - const char* json_name = upb_FieldDef_JsonName(f); - const char* shortname = upb_FieldDef_Name(f); - const size_t shortnamelen = strlen(shortname); - - upb_value v = upb_value_constptr(f); + f->scope.extension_scope = m; + _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); + f->layout_index = ctx->ext_count++; - upb_value existing_v; - if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { - _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); + if (ctx->layout) { + UPB_ASSERT(_upb_FieldDef_ExtensionMiniTable(f)->field.number == f->number_); } +} - const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); - bool ok = - _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); +static void _upb_FieldDef_CreateNotExt( + upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, + upb_FieldDef* f) { + _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + f->is_extension_ = false; - if (strcmp(shortname, json_name) != 0) { - if (upb_strtable_lookup(&m->ntof, json_name, &v)) { - _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); + if (!google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + if (f->proto3_optional_) { + _upb_DefBuilder_Errf( + ctx, + "non-extension field (%s) with proto3_optional was not in a oneof", + f->full_name); } - - const size_t json_size = strlen(json_name); - const upb_value json_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD_JSONNAME); - ok = _upb_MessageDef_Insert(m, json_name, json_size, json_v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); - } - - if (upb_inttable_lookup(&m->itof, field_number, NULL)) { - _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); } - ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); -} + _upb_MessageDef_InsertField(ctx, m, f); -void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, - const upb_MessageDef* m) { - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); - const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f); - const int layout_index = _upb_FieldDef_LayoutIndex(f); - upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m); + if (!ctx->layout) return; - UPB_ASSERT(layout_index < m->field_count); - upb_MiniTable_Field* mt_f = - (upb_MiniTable_Field*)&m->layout->fields[layout_index]; - if (sub_m) { - if (!mt->subs) { - _upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name); - } - UPB_ASSERT(mt_f); - UPB_ASSERT(sub_m->layout); - upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout); - } else if (_upb_FieldDef_IsClosedEnum(f)) { - upb_MiniTable_SetSubEnum(mt, mt_f, _upb_EnumDef_MiniTable(sub_e)); + const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); + const upb_MiniTableField* fields = mt->fields; + for (int i = 0; i < mt->field_count; i++) { + if (fields[i].number == f->number_) { + f->layout_index = i; + return; } } - for (int i = 0; i < m->nested_msg_count; i++) { - _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i)); - } -} - -static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { - uint64_t out = 0; - if (upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3) { - out |= kUpb_MessageModifier_ValidateUtf8; - out |= kUpb_MessageModifier_DefaultIsPacked; - } - if (m->ext_range_count) { - out |= kUpb_MessageModifier_IsExtendable; - } - return out; + UPB_ASSERT(false); // It should be impossible to reach this point. } -static bool _upb_MessageDef_EncodeMap(upb_DescState* s, const upb_MessageDef* m, - upb_Arena* a) { - if (m->field_count != 2) return false; +upb_FieldDef* _upb_FieldDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix, + upb_MessageDef* m, bool* is_sorted) { + _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); + upb_FieldDef* defs = + (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); - const upb_FieldDef* key_field = upb_MessageDef_Field(m, 0); - const upb_FieldDef* val_field = upb_MessageDef_Field(m, 1); - if (key_field == NULL || val_field == NULL) return false; + // If we are creating extensions then is_sorted will be NULL. + // If we are not creating extensions then is_sorted will be non-NULL. + if (is_sorted) { + uint32_t previous = 0; + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; - UPB_ASSERT(_upb_FieldDef_LayoutIndex(key_field) == 0); - UPB_ASSERT(_upb_FieldDef_LayoutIndex(val_field) == 1); + _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f); + f->index_ = i; + if (!ctx->layout) f->layout_index = i; - const upb_FieldType key_type = upb_FieldDef_Type(key_field); - const upb_FieldType val_type = upb_FieldDef_Type(val_field); + const uint32_t current = f->number_; + if (previous > current) *is_sorted = false; + previous = current; + } + } else { + for (int i = 0; i < n; i++) { + upb_FieldDef* f = &defs[i]; - const uint64_t val_mod = _upb_FieldDef_IsClosedEnum(val_field) - ? kUpb_FieldModifier_IsClosedEnum - : 0; + _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f); + f->index_ = i; + } + } - s->ptr = - upb_MtDataEncoder_EncodeMap(&s->e, s->ptr, key_type, val_type, val_mod); - return true; + return defs; } -static bool _upb_MessageDef_EncodeMessage(upb_DescState* s, - const upb_MessageDef* m, - upb_Arena* a) { - const upb_FieldDef** sorted = NULL; - if (!m->is_sorted) { - sorted = _upb_FieldDefs_Sorted(m->fields, m->field_count, a); - if (!sorted) return false; +static void resolve_subdef(upb_DefBuilder* 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 UPB_FIELD_TYPE_UNSPECIFIED: { + // Type was not specified and must be inferred. + UPB_ASSERT(has_name); + upb_deftype_t type; + const void* def = + _upb_DefBuilder_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: + _upb_DefBuilder_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 = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_MSG); + break; + case kUpb_FieldType_Enum: + UPB_ASSERT(has_name); + f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, + UPB_DEFTYPE_ENUM); + break; + default: + // No resolution necessary. + break; } +} - s->ptr = upb_MtDataEncoder_StartMessage(&s->e, s->ptr, - _upb_MessageDef_Modifiers(m)); +static int _upb_FieldDef_Compare(const void* p1, const void* p2) { + const uint32_t v1 = (*(upb_FieldDef**)p1)->number_; + const uint32_t v2 = (*(upb_FieldDef**)p2)->number_; + return (v1 < v2) ? -1 : (v1 > v2); +} - for (int i = 0; i < m->field_count; i++) { - const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i); - const upb_FieldType type = upb_FieldDef_Type(f); - const int number = upb_FieldDef_Number(f); - const uint64_t modifiers = _upb_FieldDef_Modifiers(f); +const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, + upb_Arena* a) { + // TODO: Try to replace this arena alloc with a persistent scratch buffer. + upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*)); + if (!out) return NULL; - if (!_upb_DescState_Grow(s, a)) return false; - s->ptr = upb_MtDataEncoder_PutField(&s->e, s->ptr, type, number, modifiers); + for (int i = 0; i < n; i++) { + out[i] = (upb_FieldDef*)&f[i]; } + qsort(out, n, sizeof(void*), _upb_FieldDef_Compare); - for (int i = 0; i < m->real_oneof_count; i++) { - if (!_upb_DescState_Grow(s, a)) return false; - s->ptr = upb_MtDataEncoder_StartOneof(&s->e, s->ptr); - - const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); - const int field_count = upb_OneofDef_FieldCount(o); - for (int j = 0; j < field_count; j++) { - const int number = upb_FieldDef_Number(upb_OneofDef_Field(o, j)); - - if (!_upb_DescState_Grow(s, a)) return false; - s->ptr = upb_MtDataEncoder_PutOneofField(&s->e, s->ptr, number); - } + for (int i = 0; i < n; i++) { + out[i]->layout_index = i; } - - return true; + return (const upb_FieldDef**)out; } -static bool _upb_MessageDef_EncodeMessageSet(upb_DescState* s, - const upb_MessageDef* m, - upb_Arena* a) { - s->ptr = upb_MtDataEncoder_EncodeMessageSet(&s->e, s->ptr); - - return true; -} +bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, + upb_StringView* out) { + UPB_ASSERT(f->is_extension_); -bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, - upb_StringView* out) { upb_DescState s; _upb_DescState_Init(&s); - if (!_upb_DescState_Grow(&s, a)) return false; - - if (upb_MessageDef_IsMapEntry(m)) { - if (!_upb_MessageDef_EncodeMap(&s, m, a)) return false; - } else if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { - if (!_upb_MessageDef_EncodeMessageSet(&s, m, a)) return false; - } else { - if (!_upb_MessageDef_EncodeMessage(&s, m, a)) return false; - } + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); if (!_upb_DescState_Grow(&s, a)) return false; + s.ptr = upb_MtDataEncoder_EncodeExtension(&s.e, s.ptr, f->type_, number, + modifiers); *s.ptr = '\0'; out->data = s.buf; @@ -9262,2932 +8760,4022 @@ bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, return true; } -static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, - const google_protobuf_DescriptorProto* msg_proto, - const upb_MessageDef* containing_type, - 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 n_oneof, n_field, n_ext_range, n_enum, n_ext, n_msg; - upb_StringView name; - - // Must happen before _upb_DefBuilder_Add() - m->file = _upb_DefBuilder_File(ctx); - - m->containing_type = containing_type; - m->is_sorted = true; - - name = google_protobuf_DescriptorProto_name(msg_proto); - _upb_DefBuilder_CheckIdentNotFull(ctx, name); - - m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); - _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); +static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, + upb_FieldDef* f, + const google_protobuf_FieldDescriptorProto* field_proto) { + if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { + _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", + f->full_name); + } - 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); + upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); + const upb_MessageDef* m = + _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); + f->msgdef = m; - bool ok = upb_inttable_init(&m->itof, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) { + _upb_DefBuilder_Errf( + ctx, + "field number %u in extension %s has no extension range in message %s", + (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m)); + } - ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + const upb_MiniTableExtension* ext = _upb_FieldDef_ExtensionMiniTable(f); 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); + UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number); } else { - /* Allocate now (to allow cross-linking), populate later. */ - m->layout = _upb_DefBuilder_Alloc( - ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); - } - - UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); - - m->oneof_count = n_oneof; - m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); - - m->field_count = n_field; - m->fields = - _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted); + upb_StringView desc; + if (!upb_FieldDef_MiniDescriptorEncode(f, ctx->tmp_arena, &desc)) { + _upb_DefBuilder_OomErr(ctx); + } - // Message Sets may not contain fields. - if (UPB_UNLIKELY(google_protobuf_MessageOptions_message_set_wire_format(m->opts))) { - if (UPB_UNLIKELY(n_field > 0)) { - _upb_DefBuilder_Errf(ctx, "invalid message set (%s)", m->full_name); + upb_MiniTableExtension* mut_ext = (upb_MiniTableExtension*)ext; + upb_MiniTableSub sub = {NULL}; + if (upb_FieldDef_IsSubMessage(f)) { + sub.submsg = upb_MessageDef_MiniTable(f->sub.msgdef); + } else if (_upb_FieldDef_IsClosedEnum(f)) { + sub.subenum = _upb_EnumDef_MiniTable(f->sub.enumdef); } + bool ok2 = upb_MiniTable_BuildExtension(desc.data, desc.size, mut_ext, + upb_MessageDef_MiniTable(m), sub, + ctx->status); + if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table"); } - m->ext_range_count = n_ext_range; - m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); - - const size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); - m->real_oneof_count = m->oneof_count - synthetic_count; + bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f); + if (!ok) _upb_DefBuilder_OomErr(ctx); +} - assign_msg_wellknowntype(m); - upb_inttable_compact(&m->itof, ctx->arena); +static void resolve_default(upb_DefBuilder* 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); - const google_protobuf_EnumDescriptorProto* const* enums = - google_protobuf_DescriptorProto_enum_type(msg_proto, &n_enum); - m->nested_enum_count = n_enum; - m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m); + if (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, + "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } - const google_protobuf_FieldDescriptorProto* const* exts = - google_protobuf_DescriptorProto_extension(msg_proto, &n_ext); - m->nested_ext_count = n_ext; - m->nested_exts = _upb_FieldDefs_New(ctx, n_ext, exts, m->full_name, m, NULL); + if (upb_FieldDef_IsSubMessage(f)) { + _upb_DefBuilder_Errf(ctx, + "message fields cannot have explicit defaults (%s)", + f->full_name); + } - const google_protobuf_DescriptorProto* const* msgs = - google_protobuf_DescriptorProto_nested_type(msg_proto, &n_msg); - m->nested_msg_count = n_msg; - m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m); + parse_default(ctx, defaultval.data, defaultval.size, f); + f->has_default = true; + } else { + set_default_default(ctx, f); + f->has_default = false; + } } -// Allocate and initialize an array of |n| message defs. -upb_MessageDef* _upb_MessageDefs_New( - upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, - const upb_MessageDef* containing_type) { - _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); +void _upb_FieldDef_Resolve(upb_DefBuilder* 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; - const char* name = containing_type ? containing_type->full_name - : _upb_FileDef_RawPackage(ctx->file); + resolve_subdef(ctx, prefix, f); + resolve_default(ctx, f, field_proto); - upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); - for (int i = 0; i < n; i++) { - create_msgdef(ctx, name, protos[i], containing_type, &m[i]); + if (f->is_extension_) { + resolve_extension(ctx, prefix, f, field_proto); } - return m; } // Must be last. -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_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_MiniTableExtension** 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; }; -upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { - return (upb_MethodDef*)&m[i]; +const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { + return f->opts; } -const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { - return m->service; +bool upb_FileDef_HasOptions(const upb_FileDef* f) { + return f->opts != (void*)kUpbDefOptDefault; } -const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { - return m->opts; -} +const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } -bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { - return m->opts != (void*)kUpbDefOptDefault; +const char* upb_FileDef_Package(const upb_FileDef* f) { + return f->package ? f->package : ""; } -const char* upb_MethodDef_FullName(const upb_MethodDef* m) { - return m->full_name; -} +const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } -const char* upb_MethodDef_Name(const upb_MethodDef* m) { - return _upb_DefBuilder_FullToShort(m->full_name); +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_MethodDef_Index(const upb_MethodDef* m) { return m->index; } +int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } -const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { - return m->input_type; +int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { + return f->public_dep_count; } -const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { - return m->output_type; +int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { + return f->weak_dep_count; } -bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { - return m->client_streaming; +const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { + return f->public_deps; } -bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { - return m->server_streaming; +const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { + return f->weak_deps; } -static void create_method(upb_DefBuilder* ctx, - const google_protobuf_MethodDescriptorProto* method_proto, - upb_ServiceDef* s, upb_MethodDef* m) { - upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); - - m->service = s; - m->full_name = - _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); - m->client_streaming = - google_protobuf_MethodDescriptorProto_client_streaming(method_proto); - m->server_streaming = - google_protobuf_MethodDescriptorProto_server_streaming(method_proto); - m->input_type = _upb_DefBuilder_Resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); - m->output_type = _upb_DefBuilder_Resolve( - ctx, m->full_name, m->full_name, - google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); - - UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, - method_proto); +int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { + return f->top_lvl_enum_count; } -// Allocate and initialize an array of |n| method defs belonging to |s|. -upb_MethodDef* _upb_MethodDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s) { - upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); - for (int i = 0; i < n; i++) { - create_method(ctx, protos[i], s, &m[i]); - m[i].index = i; - } - return m; +int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { + return f->top_lvl_ext_count; } -#include -#include -#include - - -// Must be last. - -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; // lookup a field by name - upb_inttable itof; // lookup a field by number (index) -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif -}; +int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } -upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { - return (upb_OneofDef*)&o[i]; +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 google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o) { - return o->opts; +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_OneofDef_HasOptions(const upb_OneofDef* o) { - return o->opts != (void*)kUpbDefOptDefault; +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]]; } -const char* upb_OneofDef_FullName(const upb_OneofDef* o) { - return o->full_name; +const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); + return _upb_MessageDef_At(f->top_lvl_msgs, i); } -const char* upb_OneofDef_Name(const upb_OneofDef* o) { - return _upb_DefBuilder_FullToShort(o->full_name); +const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); + return _upb_EnumDef_At(f->top_lvl_enums, i); } -const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { - return o->parent; +const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); + return _upb_FieldDef_At(f->top_lvl_exts, i); } -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]; +const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { + UPB_ASSERT(0 <= i && i < f->service_count); + return _upb_ServiceDef_At(f->services, i); } -int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } +const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } -uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { - // Compute index in our parent's array. - return o - upb_MessageDef_Oneof(o->parent, 0); +const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( + const upb_FileDef* f, int i) { + return f->ext_layouts[i]; } -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 size) { - upb_value val; - return upb_strtable_lookup2(&o->ntof, name, size, &val) - ? upb_value_getptr(val) - : NULL; +static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { + char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); + if (!ret) _upb_DefBuilder_OomErr(ctx); + return ret; } -const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, - const char* name) { - return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); +static bool streql_view(upb_StringView view, const char* b) { + return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; } -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; -} +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_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, - const char* name, size_t size, upb_Arena* a) { - o->field_count++; - if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = 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]); + } - const int number = upb_FieldDef_Number(f); - const upb_value v = upb_value_constptr(f); - return upb_inttable_insert(&o->itof, number, v, a) && - upb_strtable_insert(&o->ntof, name, size, v, a); + return ext_count; } -// Returns the synthetic count. -size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { - int synthetic_count = 0; - - for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { - upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); +// Allocate and initialize one file def, and add it to the context object. +void _upb_FileDef_Create(upb_DefBuilder* ctx, + const google_protobuf_FileDescriptorProto* file_proto) { + upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); + ctx->file = file; - if (o->synthetic && o->field_count != 1) { - _upb_DefBuilder_Errf(ctx, - "Synthetic oneofs must have one field, not %d: %s", - o->field_count, upb_OneofDef_Name(o)); - } + 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 n; - if (o->synthetic) { - synthetic_count++; - } else if (synthetic_count != 0) { - _upb_DefBuilder_Errf( - ctx, "Synthetic oneofs must be after all other oneofs: %s", - upb_OneofDef_Name(o)); - } + file->symtab = ctx->symtab; - o->fields = - _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); - o->field_count = 0; + // 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; - for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { - const upb_FieldDef* f = upb_MessageDef_Field(m, i); - upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); - if (o) { - o->fields[o->field_count++] = f; + 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) { + _upb_DefBuilder_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 = _upb_DefBuilder_Alloc( + ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_MiniTableExtension* ext = + _upb_DefBuilder_Alloc(ctx, sizeof(*ext) * file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; } } - return synthetic_count; -} + if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { + _upb_DefBuilder_Errf(ctx, "File has no name"); + } -static void create_oneofdef(upb_DefBuilder* 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); + file->name = strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); - o->parent = m; - o->full_name = - _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); - o->field_count = 0; - o->synthetic = false; + upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); + if (package.size) { + _upb_DefBuilder_CheckIdentFull(ctx, package); + file->package = strviewdup(ctx, package); + } else { + file->package = NULL; + } - UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { + upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); - if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { - _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); + if (streql_view(syntax, "proto2")) { + file->syntax = kUpb_Syntax_Proto2; + } else if (streql_view(syntax, "proto3")) { + file->syntax = kUpb_Syntax_Proto3; + } else { + _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(syntax)); + } + } else { + file->syntax = kUpb_Syntax_Proto2; } - upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); - bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + // Read options. + UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); - ok = upb_inttable_init(&o->itof, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); + // Verify dependencies. + strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); + file->dep_count = n; + file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n); - ok = upb_strtable_init(&o->ntof, 4, ctx->arena); - if (!ok) _upb_DefBuilder_OomErr(ctx); -} + for (size_t 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]) { + _upb_DefBuilder_Errf(ctx, + "Depends on file '" UPB_STRINGVIEW_FORMAT + "', but it has not been loaded", + UPB_STRINGVIEW_ARGS(str)); + } + } -// Allocate and initialize an array of |n| oneof defs. -upb_OneofDef* _upb_OneofDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m) { - _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); + public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); + file->public_dep_count = n; + file->public_deps = + _upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n); + int32_t* mutable_public_deps = (int32_t*)file->public_deps; + for (size_t i = 0; i < n; i++) { + if (public_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", + (int)public_deps[i]); + } + mutable_public_deps[i] = public_deps[i]; + } - upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); - for (int i = 0; i < n; i++) { - create_oneofdef(ctx, m, protos[i], &o[i]); + weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); + file->weak_dep_count = n; + file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n); + int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; + for (size_t i = 0; i < n; i++) { + if (weak_deps[i] >= file->dep_count) { + _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", + (int)weak_deps[i]); + } + mutable_weak_deps[i] = weak_deps[i]; } - return o; -} + // Create enums. + enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + file->top_lvl_enum_count = n; + file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); -// Must be last. + // Create extensions. + exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->top_lvl_ext_count = n; + file->top_lvl_exts = + _upb_FieldDefs_New(ctx, n, exts, file->package, NULL, NULL); -struct upb_ServiceDef { - const google_protobuf_ServiceOptions* opts; - const upb_FileDef* file; - const char* full_name; - upb_MethodDef* methods; - int method_count; - int index; -}; + // Create messages. + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + file->top_lvl_msg_count = n; + file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); -upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { - return (upb_ServiceDef*)&s[index]; -} + // Create services. + services = google_protobuf_FileDescriptorProto_service(file_proto, &n); + file->service_count = n; + file->services = _upb_ServiceDefs_New(ctx, n, services); -const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { - return s->opts; -} + // Now that all names are in the table, build layouts and resolve refs. -bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { - return s->opts != (void*)kUpbDefOptDefault; -} + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_Resolve(ctx, m); + } -const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { - return s->full_name; -} + for (int i = 0; i < file->top_lvl_ext_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); + _upb_FieldDef_Resolve(ctx, file->package, f); + } -const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { - return _upb_DefBuilder_FullToShort(s->full_name); + if (!ctx->layout) { + for (int i = 0; i < file->top_lvl_msg_count; i++) { + upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); + _upb_MessageDef_LinkMiniTable(ctx, m); + } + } + + if (file->ext_count) { + bool ok = upb_ExtensionRegistry_AddArray( + _upb_DefPool_ExtReg(ctx->symtab), file->ext_layouts, file->ext_count); + if (!ok) _upb_DefBuilder_OomErr(ctx); + } } -int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } -const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { - return s->file; +#include + + +// Must be last. + +static size_t get_field_size(const upb_MiniTableField* 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]; } -int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { - return s->method_count; +static bool in_oneof(const upb_MiniTableField* field) { + return field->presence < 0; } -const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { - return (i < 0 || i >= s->method_count) ? NULL - : _upb_MethodDef_At(s->methods, i); +static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg, + const upb_FieldDef* f) { + const upb_MiniTableField* 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; } -const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, - const char* name) { - for (int i = 0; i < s->method_count; i++) { - const upb_MethodDef* m = _upb_MethodDef_At(s->methods, i); - if (strcmp(name, upb_MethodDef_Name(m)) == 0) { - return m; +bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) { + assert(upb_FieldDef_HasPresence(f)); + if (upb_FieldDef_IsExtension(f)) { + const upb_MiniTableExtension* ext = _upb_FieldDef_ExtensionMiniTable(f); + return _upb_Message_Getext(msg, ext) != NULL; + } else { + const upb_MiniTableField* 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; } } - return NULL; } -static void create_service(upb_DefBuilder* ctx, - const google_protobuf_ServiceDescriptorProto* svc_proto, - upb_ServiceDef* s) { - upb_StringView name; - size_t n; - - // Must happen before _upb_DefBuilder_Add() - s->file = _upb_DefBuilder_File(ctx); - - name = google_protobuf_ServiceDescriptorProto_name(svc_proto); - _upb_DefBuilder_CheckIdentNotFull(ctx, name); - const char* package = _upb_FileDef_RawPackage(s->file); - s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); - _upb_DefBuilder_Add(ctx, s->full_name, - _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); - - const google_protobuf_MethodDescriptorProto* const* methods = - google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); - s->method_count = n; - s->methods = _upb_MethodDefs_New(ctx, n, methods, s); - - UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, - svc_proto); -} - -upb_ServiceDef* _upb_ServiceDefs_New( - upb_DefBuilder* ctx, int n, - const google_protobuf_ServiceDescriptorProto* const* protos) { - _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); - - upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); - for (int i = 0; i < n; i++) { - create_service(ctx, protos[i], &s[i]); - s[i].index = i; +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_MiniTableField* 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; } - return s; } -/* - * 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); +upb_MessageValue upb_Message_Get(const upb_Message* msg, + const upb_FieldDef* f) { + upb_MessageValue default_val = upb_FieldDef_Default(f); + upb_MessageValue ret; + _upb_MiniTable_GetField(msg, upb_FieldDef_MiniTable(f), &default_val, &ret); 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); -} +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; + } -char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { - size_t n; - char* p; + upb_MessageValue val = upb_Message_Get(msg, f); + if (val.array_val) { + return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; + } - /* 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; + 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)); + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + ret.msg = upb_Message_New(upb_MessageDef_MiniTable(m), a); } - 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; + val.array_val = ret.array; + upb_Message_Set(msg, f, val, a); -static lookupkey_t strkey2(const char* str, size_t len) { - lookupkey_t k; - k.str.str = str; - k.str.len = len; - return k; + return ret; } -static lookupkey_t intkey(uintptr_t key) { - lookupkey_t k; - k.num = key; - return k; +bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, + upb_MessageValue val, upb_Arena* a) { + return _upb_MiniTable_SetField(msg, upb_FieldDef_MiniTable(f), &val, a); } -typedef uint32_t hashfunc_t(upb_tabkey key); -typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); +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_MiniTableField* field = upb_FieldDef_MiniTable(f); + char* mem = UPB_PTR_AT(msg, field->offset, char); -/* Base table (shared code) ***************************************************/ + 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 uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; } + memset(mem, 0, get_field_size(field)); + } +} -static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) { - return t->entries + (hash & t->mask); +void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) { + _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); } -static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; } +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 bool isfull(upb_table* t) { return t->count == t->max_count; } + /* 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 bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { - size_t bytes; + /* 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; - 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; -} + /* 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; + } + } -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; + *out_val = val; + *out_f = f; + *iter = i; + return true; } - for (e = begin; e < end; e++) { - if (upb_tabent_isempty(e)) return e; + + 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; + } } - UPB_ASSERT(false); - return NULL; -} -static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { - return (upb_tabent*)upb_getentry(t, hash); + *iter = i; + return false; } -static const upb_tabent* findentry(const upb_table* t, lookupkey_t key, - uint32_t hash, eqlfunc_t* eql) { - const upb_tabent* e; +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 (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; - } -} + if (--depth == 0) return false; -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); -} + _upb_Message_DiscardUnknown_shallow(msg); -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); + 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; + + upb_MessageValue map_key, map_val; + while (upb_Map_Next(map, &map_key, &map_val, &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 true; - } else { - return false; } + + return ret; } -/* 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; +bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, + int maxdepth) { + return _upb_Message_DiscardUnknown(msg, m, maxdepth); +} - UPB_ASSERT(findentry(t, key, hash, eql) == NULL); - t->count++; - mainpos_e = getentry_mutable(t, hash); - our_e = mainpos_e; +// Must be last. - if (upb_tabent_isempty(mainpos_e)) { - /* Our main position is empty; use it. */ - our_e->next = NULL; +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; + + // TODO(salo): These counters don't need anywhere near 32 bits. + 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; + bool is_sorted; + upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif +}; + +static void assign_msg_wellknowntype(upb_MessageDef* m) { + const char* name = m->full_name; + 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 { - /* 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; - } + m->well_known_type = kUpb_WellKnown_Unspecified; } - 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; +upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { + return (upb_MessageDef*)&m[i]; +} + +bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) { + for (int i = 0; i < m->ext_range_count; i++) { + const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); + if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) { return true; - } else { - /* Element to remove is not in the table. */ - return false; } } + 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; +const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m) { + return m->opts; } -static size_t begin(const upb_table* t) { return next(t, -1); } - -/* upb_strtable ***************************************************************/ +bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { + return m->opts != (void*)kUpbDefOptDefault; +} -/* A simple "subclass" of upb_table that only adds a hash function for strings. - */ +const char* upb_MessageDef_FullName(const upb_MessageDef* m) { + return m->full_name; +} -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; +const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { + return m->file; } -/* Adapted from ABSL's wyhash. */ +const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { + return m->containing_type; +} -static uint64_t UnalignedLoad64(const void* p) { - uint64_t val; - memcpy(&val, p, 8); - return val; +const char* upb_MessageDef_Name(const upb_MessageDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); } -static uint32_t UnalignedLoad32(const void* p) { - uint32_t val; - memcpy(&val, p, 4); - return val; +upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { + return upb_FileDef_Syntax(m->file); } -#if defined(_MSC_VER) && defined(_M_X64) -#include -#endif +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; +} -/* 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 -} +const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; -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 (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } -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]; + return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); +} - 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; +const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; - 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); + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; + } - uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); - current_state = (cs0 ^ cs1); + return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); +} - uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); - uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); - duplicated_state = (ds0 ^ ds1); +bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, + upb_value v, upb_Arena* a) { + return upb_strtable_insert(&m->ntof, name, len, v, a); +} - ptr += 64; - len -= 64; - } while (len > 64); +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; - current_state = current_state ^ duplicated_state; + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; } - // 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); + const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + const upb_OneofDef* o = _upb_DefType_Unpack(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. */ +} - current_state = WyhashMix(a ^ salt[1], b ^ current_state); +const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( + const upb_MessageDef* m, const char* name, size_t size) { + upb_value val; + const upb_FieldDef* f; - ptr += 16; - len -= 16; + if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { + return NULL; } - // 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; - } + f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); + if (!f) f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD_JSONNAME); - uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); - uint64_t z = salt[1] ^ starting_length; - return WyhashMix(w, z); + return f; } -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); +int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { + return m->ext_range_count; } -static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { - return _upb_Hash(p, n, 0); +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m) { + return m->res_range_count; } -static uint32_t strhash(upb_tabkey key) { - uint32_t len; - char* str = upb_tabstr(key, &len); - return _upb_Hash_NoSeed(str, len); +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m) { + return m->res_name_count; } -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); +int upb_MessageDef_FieldCount(const upb_MessageDef* m) { + return m->field_count; } -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); +int upb_MessageDef_OneofCount(const upb_MessageDef* m) { + return m->oneof_count; } -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); +int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { + return m->nested_msg_count; } -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; +int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { + return m->nested_enum_count; } -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 = _upb_Hash_NoSeed(key.str.str, key.str.len); - insert(&t->t, key, tabkey, v, hash, &strhash, &streql); - return true; +int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { + return m->nested_ext_count; } -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); +const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { + return m->layout; } -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); +const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->ext_range_count); + return _upb_ExtensionRange_At(m->ext_ranges, i); } -/* Iteration */ - -void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { - i->t = t; - i->index = begin(&t->t); +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); } -void upb_strtable_next(upb_strtable_iter* i) { - i->index = next(&i->t->t, i->index); +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]; } -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)); +const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->field_count); + return _upb_FieldDef_At(m->fields, 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; +const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->oneof_count); + return _upb_OneofDef_At(m->oneofs, i); } -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); +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]; } -void upb_strtable_iter_setdone(upb_strtable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; +const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->nested_enum_count); + return _upb_EnumDef_At(m->nested_enums, i); } -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; +const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, + int i) { + UPB_ASSERT(0 <= i && i < m->nested_ext_count); + return _upb_FieldDef_At(m->nested_exts, i); } -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; - } +upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { + return m->well_known_type; } -static const upb_tabval* inttable_val_const(const upb_inttable* t, - uintptr_t key) { - return inttable_val((upb_inttable*)t, key); +bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { + return m->in_message_set; } -size_t upb_inttable_count(const upb_inttable* t) { - return t->t.count + t->array_count; +const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); } -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 +const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, + const char* name) { + return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); } -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_MessageDef_IsMapEntry(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_map_entry(m->opts); } -bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { - return upb_inttable_sizedinit(t, 0, 4, a); +bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_message_set_wire_format(m->opts); } -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; +static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + upb_StringView desc; + bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc); + if (!ok) _upb_DefBuilder_OomErr(ctx); - if (!init(&new_table, t->t.size_lg2 + 1, a)) { - return false; - } + void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab); + size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab); + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf( + desc.data, desc.size, kUpb_MiniTablePlatform_Native, ctx->arena, + scratch_data, scratch_size, ctx->status); + if (!ret) _upb_DefBuilder_FailJmp(ctx); + return ret; +} - 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; +void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); + _upb_FieldDef_Resolve(ctx, m->full_name, f); + } - _upb_value_setval(&v, e->val.val); - hash = upb_inthash(e->key); - insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); - } + if (!ctx->layout) { + m->layout = _upb_MessageDef_MakeMiniTable(ctx, m); + if (!m->layout) _upb_DefBuilder_OomErr(ctx); + } - UPB_ASSERT(t->t.count == new_table.count); +#ifndef NDEBUG + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + UPB_ASSERT(layout_index < m->layout->field_count); + const upb_MiniTableField* mt_f = &m->layout->fields[layout_index]; + UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f)); + } +#endif - t->t = new_table; + m->in_message_set = false; + for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { + upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); + _upb_FieldDef_Resolve(ctx, m->full_name, ext); + if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && + upb_FieldDef_Label(ext) == kUpb_Label_Optional && + upb_FieldDef_MessageSubDef(ext) == m && + google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { + m->in_message_set = true; } - 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; + for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { + upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); + _upb_MessageDef_Resolve(ctx, n); + } } -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; -} +void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, + const upb_FieldDef* f) { + const int32_t field_number = upb_FieldDef_Number(f); -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); + if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { + _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); } - 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}; + const char* json_name = upb_FieldDef_JsonName(f); + const char* shortname = upb_FieldDef_Name(f); + const size_t shortnamelen = strlen(shortname); - upb_inttable_iter i; - size_t arr_count; - int size_lg2; - upb_inttable new_t; + upb_value v = upb_value_constptr(f); - 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]++; + upb_value existing_v; + if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) { + _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); } - /* Find the largest power of two that satisfies the MIN_DENSITY - * definition (while actually having some keys). */ - arr_count = upb_inttable_count(t); + const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); + bool ok = + _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); - 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; + if (strcmp(shortname, json_name) != 0) { + if (upb_strtable_lookup(&m->ntof, json_name, &v)) { + _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); } - arr_count -= counts[size_lg2]; + const size_t json_size = strlen(json_name); + const upb_value json_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD_JSONNAME); + ok = _upb_MessageDef_Insert(m, json_name, json_size, json_v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } - 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); + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); } - *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]; + ok = upb_inttable_insert(&m->itof, field_number, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -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_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, + const upb_MessageDef* m) { + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); + const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f); + const int layout_index = _upb_FieldDef_LayoutIndex(f); + upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m); -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; + UPB_ASSERT(layout_index < m->field_count); + upb_MiniTableField* mt_f = + (upb_MiniTableField*)&m->layout->fields[layout_index]; + if (sub_m) { + if (!mt->subs) { + _upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name); } + UPB_ASSERT(mt_f); + UPB_ASSERT(sub_m->layout); + upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout); + } else if (_upb_FieldDef_IsClosedEnum(f)) { + upb_MiniTable_SetSubEnum(mt, mt_f, _upb_EnumDef_MiniTable(sub_e)); } - 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; - } - } + for (int i = 0; i < m->nested_msg_count; i++) { + _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i)); } +} - 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; +static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { + uint64_t out = 0; + if (upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3) { + out |= kUpb_MessageModifier_ValidateUtf8; + out |= kUpb_MessageModifier_DefaultIsPacked; } - - return false; + if (m->ext_range_count) { + out |= kUpb_MessageModifier_IsExtendable; + } + return out; } -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; +static bool _upb_MessageDef_EncodeMap(upb_DescState* s, const upb_MessageDef* m, + upb_Arena* a) { + if (m->field_count != 2) return false; - // 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; - } - } + const upb_FieldDef* key_field = upb_MessageDef_Field(m, 0); + const upb_FieldDef* val_field = upb_MessageDef_Field(m, 1); + if (key_field == NULL || val_field == NULL) return false; - if (prev) { - prev->next = ent->next; - } + UPB_ASSERT(_upb_FieldDef_LayoutIndex(key_field) == 0); + UPB_ASSERT(_upb_FieldDef_LayoutIndex(val_field) == 1); - t->t.count--; - ent->key = 0; - ent->next = NULL; - } + const upb_FieldType key_type = upb_FieldDef_Type(key_field); + const upb_FieldType val_type = upb_FieldDef_Type(val_field); + + const uint64_t val_mod = _upb_FieldDef_IsClosedEnum(val_field) + ? kUpb_FieldModifier_IsClosedEnum + : 0; + + s->ptr = + upb_MtDataEncoder_EncodeMap(&s->e, s->ptr, key_type, val_type, val_mod); + return true; } -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; +static bool _upb_MessageDef_EncodeMessage(upb_DescState* s, + const upb_MessageDef* m, + upb_Arena* a) { + const upb_FieldDef** sorted = NULL; + if (!m->is_sorted) { + sorted = _upb_FieldDefs_Sorted(m->fields, m->field_count, a); + if (!sorted) return false; } - return false; -} + s->ptr = upb_MtDataEncoder_StartMessage(&s->e, s->ptr, + _upb_MessageDef_Modifiers(m)); -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; + for (int i = 0; i < m->field_count; i++) { + const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i); + const upb_FieldType type = upb_FieldDef_Type(f); + const int number = upb_FieldDef_Number(f); + const uint64_t modifiers = _upb_FieldDef_Modifiers(f); - // 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 (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_PutField(&s->e, s->ptr, type, number, modifiers); } - if (prev) { - prev->next = ent->next; + for (int i = 0; i < m->real_oneof_count; i++) { + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_StartOneof(&s->e, s->ptr); + + const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); + const int field_count = upb_OneofDef_FieldCount(o); + for (int j = 0; j < field_count; j++) { + const int number = upb_FieldDef_Number(upb_OneofDef_Field(o, j)); + + if (!_upb_DescState_Grow(s, a)) return false; + s->ptr = upb_MtDataEncoder_PutOneofField(&s->e, s->ptr, number); + } } - t->t.count--; - ent->key = 0; - ent->next = NULL; + return true; } -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 bool _upb_MessageDef_EncodeMessageSet(upb_DescState* s, + const upb_MessageDef* m, + upb_Arena* a) { + s->ptr = upb_MtDataEncoder_EncodeMessageSet(&s->e, s->ptr); + + return true; +} + +bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, + upb_StringView* out) { + upb_DescState s; + _upb_DescState_Init(&s); + + if (!_upb_DescState_Grow(&s, a)) return false; + + if (upb_MessageDef_IsMapEntry(m)) { + if (!_upb_MessageDef_EncodeMap(&s, m, a)) return false; + } else if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { + if (!_upb_MessageDef_EncodeMessageSet(&s, m, a)) return false; } else { - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(int_tabent(i)); + if (!_upb_MessageDef_EncodeMessage(&s, m, a)) return 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; -} + if (!_upb_DescState_Grow(&s, a)) return false; + *s.ptr = '\0'; -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); + out->data = s.buf; + out->size = s.ptr - s.buf; + return true; } -void upb_inttable_iter_setdone(upb_inttable_iter* i) { - i->t = NULL; - i->index = SIZE_MAX; - i->array_part = false; +static upb_StringView* _upb_ReservedNames_New(upb_DefBuilder* ctx, int n, + const upb_StringView* protos) { + upb_StringView* sv = _upb_DefBuilder_Alloc(ctx, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; + } + return sv; } -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 create_msgdef(upb_DefBuilder* ctx, const char* prefix, + const google_protobuf_DescriptorProto* msg_proto, + const upb_MessageDef* containing_type, + 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 n_oneof, n_field, n_enum, n_ext, n_msg; + size_t n_ext_range, n_res_range, n_res_name; + upb_StringView name; + // Must happen before _upb_DefBuilder_Add() + m->file = _upb_DefBuilder_File(ctx); -// Must be last. + m->containing_type = containing_type; + m->is_sorted = true; -int upb_Unicode_ToUTF8(uint32_t cp, char* out) { - if (cp <= 0x7f) { - out[0] = cp; - return 1; - } - if (cp <= 0x07ff) { - out[0] = (cp >> 6) | 0xc0; - out[1] = (cp & 0x3f) | 0x80; - return 2; - } - if (cp <= 0xffff) { - out[0] = (cp >> 12) | 0xe0; - out[1] = ((cp >> 6) & 0x3f) | 0x80; - out[2] = (cp & 0x3f) | 0x80; - return 3; - } - if (cp <= 0x10ffff) { - out[0] = (cp >> 18) | 0xf0; - out[1] = ((cp >> 12) & 0x3f) | 0x80; - out[2] = ((cp >> 6) & 0x3f) | 0x80; - out[3] = (cp & 0x3f) | 0x80; - return 4; - } - return 0; -} + name = google_protobuf_DescriptorProto_name(msg_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); + _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); -#include + 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); + bool ok = upb_inttable_init(&m->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); -// Must be last. + ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); -/** upb_Message ***************************************************************/ + 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 = _upb_DefBuilder_Alloc( + ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry)); + } -static const size_t overhead = sizeof(upb_Message_InternalData); + UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); -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); -} + m->oneof_count = n_oneof; + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); -upb_Message* upb_Message_New(const upb_MiniTable* mini_table, - upb_Arena* arena) { - return _upb_Message_New(mini_table, arena); -} + m->field_count = n_field; + m->fields = + _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted); -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)); -} + // Message Sets may not contain fields. + if (UPB_UNLIKELY(google_protobuf_MessageOptions_message_set_wire_format(m->opts))) { + if (UPB_UNLIKELY(n_field > 0)) { + _upb_DefBuilder_Errf(ctx, "invalid message set (%s)", m->full_name); + } + } -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; -} + m->ext_range_count = n_ext_range; + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); -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; -} + m->res_range_count = n_res_range; + m->res_ranges = + _upb_MessageReservedRanges_New(ctx, n_res_range, res_ranges, m); -void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (in->internal) { - in->internal->unknown_end = overhead; - } -} + m->res_name_count = n_res_name; + m->res_names = _upb_ReservedNames_New(ctx, n_res_name, res_names); -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 size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); + m->real_oneof_count = m->oneof_count - synthetic_count; -void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - const char* internal_unknown_end = - UPB_PTR_AT(in->internal, in->internal->unknown_end, char); -#ifndef NDEBUG - size_t full_unknown_size; - const char* full_unknown = upb_Message_GetUnknown(msg, &full_unknown_size); - UPB_ASSERT((uintptr_t)data >= (uintptr_t)full_unknown); - UPB_ASSERT((uintptr_t)data < (uintptr_t)(full_unknown + full_unknown_size)); - UPB_ASSERT((uintptr_t)(data + len) > (uintptr_t)data); - UPB_ASSERT((uintptr_t)(data + len) <= (uintptr_t)internal_unknown_end); -#endif - if ((data + len) != internal_unknown_end) { - memmove((char*)data, data + len, internal_unknown_end - data - len); - } - in->internal->unknown_end -= len; + assign_msg_wellknowntype(m); + upb_inttable_compact(&m->itof, ctx->arena); + + const google_protobuf_EnumDescriptorProto* const* enums = + google_protobuf_DescriptorProto_enum_type(msg_proto, &n_enum); + m->nested_enum_count = n_enum; + m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m); + + const google_protobuf_FieldDescriptorProto* const* exts = + google_protobuf_DescriptorProto_extension(msg_proto, &n_ext); + m->nested_ext_count = n_ext; + m->nested_exts = _upb_FieldDefs_New(ctx, n_ext, exts, m->full_name, m, NULL); + + const google_protobuf_DescriptorProto* const* msgs = + google_protobuf_DescriptorProto_nested_type(msg_proto, &n_msg); + m->nested_msg_count = n_msg; + m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m); } -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; +// Allocate and initialize an array of |n| message defs. +upb_MessageDef* _upb_MessageDefs_New( + upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, + const upb_MessageDef* containing_type) { + _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); + + const char* name = containing_type ? containing_type->full_name + : _upb_FileDef_RawPackage(ctx->file); + + upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); + for (int i = 0; i < n; i++) { + create_msgdef(ctx, name, protos[i], containing_type, &m[i]); } + return m; } -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]; - } - } +// Must be last. - return NULL; -} +struct upb_MessageReservedRange { + int32_t start; + int32_t end; +}; -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_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i) { + return (upb_MessageReservedRange*)&r[i]; } -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; +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r) { + return r->start; } - -size_t upb_Message_ExtensionCount(const upb_Message* msg) { - size_t count; - _upb_Message_Getexts(msg, &count); - return count; +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r) { + return r->end; } -/** upb_Map *******************************************************************/ +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m) { + upb_MessageReservedRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageReservedRange) * n); -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)); + 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; - if (!map) { - return NULL; - } + // 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) { + _upb_DefBuilder_Errf(ctx, + "Reserved range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } - upb_strtable_init(&map->table, 4, a); - map->key_size = key_size; - map->val_size = value_size; + r[i].start = start; + r[i].end = end; + } - return map; + return r; } -const float kUpb_FltInfinity = INFINITY; -const double kUpb_Infinity = INFINITY; - - -#include -#include -#include -#include -#include -#include // Must be last. -void upb_Status_Clear(upb_Status* status) { - if (!status) return; - status->ok = true; - status->msg[0] = '\0'; -} +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; +}; -bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } +upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { + return (upb_MethodDef*)&m[i]; +} -const char* upb_Status_ErrorMessage(const upb_Status* status) { - return status->msg; +const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { + return m->service; } -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'; +const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { + return m->opts; } -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); +bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { + return m->opts != (void*)kUpbDefOptDefault; } -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'; +const char* upb_MethodDef_FullName(const upb_MethodDef* m) { + return m->full_name; } -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'; +const char* upb_MethodDef_Name(const upb_MethodDef* m) { + return _upb_DefBuilder_FullToShort(m->full_name); } -#include -#include -#include +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } +const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { + return m->input_type; +} -// Must be last. +const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { + return m->output_type; +} -/* Miscellaneous utilities ****************************************************/ +bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { + return m->client_streaming; +} -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 = '.'; - } +bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { + return m->server_streaming; } -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); +static void create_method(upb_DefBuilder* ctx, + const google_protobuf_MethodDescriptorProto* method_proto, + upb_ServiceDef* s, upb_MethodDef* m) { + upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); + + m->service = s; + m->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); + m->client_streaming = + google_protobuf_MethodDescriptorProto_client_streaming(method_proto); + m->server_streaming = + google_protobuf_MethodDescriptorProto_server_streaming(method_proto); + m->input_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); + m->output_type = _upb_DefBuilder_Resolve( + ctx, m->full_name, m->full_name, + google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); + + UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); } -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); +// Allocate and initialize an array of |n| method defs belonging to |s|. +upb_MethodDef* _upb_MethodDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_MethodDescriptorProto* const* protos, upb_ServiceDef* s) { + upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); + for (int i = 0; i < n; i++) { + create_method(ctx, protos[i], s, &m[i]); + m[i].index = i; } - upb_FixLocale(buf); + return m; } - +#include +#include #include // Must be last. -// A few fake field types for our tables. -enum { - kUpb_FakeFieldType_FieldNotFound = 0, - kUpb_FakeFieldType_MessageSetItem = 19, +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; // lookup a field by name + upb_inttable itof; // lookup a field by number (index) +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; -// DecodeOp: an action to be performed for a wire-type/field-type combination. -enum { - // Special ops: we don't write data to regular fields for these. - kUpb_DecodeOp_UnknownField = -1, - kUpb_DecodeOp_MessageSetItem = -2, +upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { + return (upb_OneofDef*)&o[i]; +} - // Scalar-only ops. - kUpb_DecodeOp_Scalar1Byte = 0, - kUpb_DecodeOp_Scalar4Byte = 2, - kUpb_DecodeOp_Scalar8Byte = 3, - kUpb_DecodeOp_Enum = 1, +const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o) { + return o->opts; +} - // Scalar/repeated ops. - kUpb_DecodeOp_String = 4, - kUpb_DecodeOp_Bytes = 5, - kUpb_DecodeOp_SubMessage = 6, +bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { + return o->opts != (void*)kUpbDefOptDefault; +} - // Repeated-only ops (also see macros below). - kUpb_DecodeOp_PackedEnum = 13, -}; +const char* upb_OneofDef_FullName(const upb_OneofDef* o) { + return o->full_name; +} -// For packed fields it is helpful to be able to recover the lg2 of the data -// size from the 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] */ +const char* upb_OneofDef_Name(const upb_OneofDef* o) { + return _upb_DefBuilder_FullToShort(o->full_name); +} -typedef union { - bool bool_val; - uint32_t uint32_val; - uint64_t uint64_val; - uint32_t size; -} wireval; +const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { + return o->parent; +} -static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable* layout); +int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } -UPB_NORETURN static void* _upb_Decoder_ErrorJmp(upb_Decoder* d, - upb_DecodeStatus status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); +const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; } -const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status) { - assert(status != kUpb_DecodeStatus_Ok); - UPB_LONGJMP(d->err, status); - return NULL; -} -static void _upb_Decoder_VerifyUtf8(upb_Decoder* d, const char* buf, int len) { - if (!_upb_Decoder_VerifyUtf8Inline(buf, len)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); - } -} +int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } -static bool _upb_Decoder_Reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { - bool need_realloc = arr->capacity - arr->size < elem; - if (need_realloc && !_upb_array_realloc(arr, arr->size + elem, &d->arena)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - } - return need_realloc; +uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { + // Compute index in our parent's array. + return o - upb_MessageDef_Oneof(o->parent, 0); } -typedef struct { - const char* ptr; - uint64_t val; -} _upb_DecodeLongVarintReturn; +bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } -UPB_NOINLINE -static _upb_DecodeLongVarintReturn _upb_Decoder_DecodeLongVarint( - const char* ptr, uint64_t val) { - _upb_DecodeLongVarintReturn 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; +const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, + const char* name, + size_t size) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, size, &val) + ? upb_value_getptr(val) + : NULL; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeVarint(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 { - _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); - if (!res.ptr) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - *val = res.val; - return res.ptr; - } +const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, + const char* name) { + return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeTag(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; - _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); - if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } - *val = res.val; - return res.ptr; - } +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_FORCEINLINE -static const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, - uint32_t* size) { - uint64_t size64; - ptr = _upb_Decoder_DecodeVarint(d, ptr, &size64); - if (size64 >= INT32_MAX || ptr - d->end + (int)size64 > d->limit) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } - *size = size64; - return ptr; -} +bool _upb_OneofDef_Insert(upb_OneofDef* o, const upb_FieldDef* f, + const char* name, size_t size, upb_Arena* a) { + o->field_count++; + if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = true; -static void _upb_Decoder_MungeInt32(wireval* val) { - if (!_upb_IsLittleEndian()) { - /* The next stage will memcpy(dst, &val, 4) */ - val->uint32_val = val->uint64_val; - } + const int number = upb_FieldDef_Number(f); + const upb_value v = upb_value_constptr(f); + return upb_inttable_insert(&o->itof, number, v, a) && + upb_strtable_insert(&o->ntof, name, size, v, a); } -static void _upb_Decoder_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; +// Returns the synthetic count. +size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { + int synthetic_count = 0; + + for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { + upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); + + if (o->synthetic && o->field_count != 1) { + _upb_DefBuilder_Errf(ctx, + "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_OneofDef_Name(o)); } - case kUpb_FieldType_Int32: - case kUpb_FieldType_UInt32: - case kUpb_FieldType_Enum: - _upb_Decoder_MungeInt32(val); - break; + + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + _upb_DefBuilder_Errf( + ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_OneofDef_Name(o)); + } + + o->fields = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef*) * o->field_count); + o->field_count = 0; } -} -static upb_Message* _upb_Decoder_NewSubMessage( - upb_Decoder* d, const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - UPB_ASSERT(subl); - upb_Message* msg = _upb_Message_New(subl, &d->arena); - if (!msg) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - return msg; -} + for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { + const upb_FieldDef* f = upb_MessageDef_Field(m, i); + upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); + if (o) { + o->fields[o->field_count++] = f; + } + } -UPB_NOINLINE -const char* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, - int overrun) { - int status; - ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); - if (ptr == NULL) _upb_Decoder_ErrorJmp(d, status); - return ptr; + return synthetic_count; } -static const char* _upb_Decoder_ReadString(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) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - memcpy(data, ptr, size); - str->data = data; +static void create_oneofdef(upb_DefBuilder* 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); + + o->parent = m; + o->full_name = + _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); + o->field_count = 0; + o->synthetic = false; + + UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + + if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { + _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); } - str->size = size; - return ptr + size; + + upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); + bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_inttable_init(&o->itof, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); + + ok = upb_strtable_init(&o->ntof, 4, ctx->arena); + if (!ok) _upb_DefBuilder_OomErr(ctx); } -UPB_FORCEINLINE -static const char* _upb_Decoder_RecurseSubMessage(upb_Decoder* d, - const char* ptr, - upb_Message* submsg, - const upb_MiniTable* subl, - uint32_t expected_end_group) { - if (--d->depth < 0) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); - } - ptr = _upb_Decoder_DecodeMessage(d, ptr, submsg, subl); - d->depth++; - if (d->end_group != expected_end_group) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +// Allocate and initialize an array of |n| oneof defs. +upb_OneofDef* _upb_OneofDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_OneofDescriptorProto* const* protos, upb_MessageDef* m) { + _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); + + upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); + for (int i = 0; i < n; i++) { + create_oneofdef(ctx, m, protos[i], &o[i]); } - return ptr; + return o; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeSubMessage( - upb_Decoder* d, const char* ptr, upb_Message* submsg, - const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field, int size) { - int saved_delta = _upb_Decoder_PushLimit(d, ptr, size); - const upb_MiniTable* subl = subs[field->submsg_index].submsg; - UPB_ASSERT(subl); - ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, DECODE_NOGROUP); - _upb_Decoder_PopLimit(d, ptr, saved_delta); - return ptr; + +// Must be last. + +struct upb_ServiceDef { + const google_protobuf_ServiceOptions* opts; + const upb_FileDef* file; + const char* full_name; + upb_MethodDef* methods; + int method_count; + int index; +}; + +upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { + return (upb_ServiceDef*)&s[index]; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeGroup(upb_Decoder* d, const char* ptr, - upb_Message* submsg, - const upb_MiniTable* subl, - uint32_t number) { - if (_upb_Decoder_IsDone(d, &ptr)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } - ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, number); - d->end_group = DECODE_NOGROUP; - return ptr; +const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { + return s->opts; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeUnknownGroup(upb_Decoder* d, - const char* ptr, - uint32_t number) { - return _upb_Decoder_DecodeGroup(d, ptr, NULL, NULL, number); +bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { + return s->opts != (void*)kUpbDefOptDefault; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeKnownGroup( - 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; - UPB_ASSERT(subl); - return _upb_Decoder_DecodeGroup(d, ptr, submsg, subl, field->number); +const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { + return s->full_name; } -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 char* upb_ServiceDef_Name(const upb_ServiceDef* s) { + return _upb_DefBuilder_FullToShort(s->full_name); } -static void _upb_Decoder_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); +int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } - if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - } +const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { + return s->file; } -UPB_NOINLINE -static bool _upb_Decoder_CheckEnumSlow(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable_Enum* e, - const upb_MiniTable_Field* field, - uint32_t v) { - if (_upb_MiniTable_CheckEnumValueSlow(e, v)) return true; - - // 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_Decoder_AddUnknownVarints(d, unknown_msg, tag, v); - return false; +int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { + return s->method_count; } -UPB_FORCEINLINE -static bool _upb_Decoder_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; +const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { + return (i < 0 || i >= s->method_count) ? NULL + : _upb_MethodDef_At(s->methods, i); +} - _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, v); - if (UPB_LIKELY(status == _kUpb_FastEnumCheck_ValueIsInEnum)) return true; - return _upb_Decoder_CheckEnumSlow(d, ptr, msg, e, field, v); +const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, + const char* name) { + for (int i = 0; i < s->method_count; i++) { + const upb_MethodDef* m = _upb_MethodDef_At(s->methods, i); + if (strcmp(name, upb_MethodDef_Name(m)) == 0) { + return m; + } + } + return NULL; } -UPB_NOINLINE -static const char* _upb_Decoder_DecodeEnumArray( - 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 (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, val)) return ptr; - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); - arr->size++; - memcpy(mem, val, 4); - return ptr; +static void create_service(upb_DefBuilder* ctx, + const google_protobuf_ServiceDescriptorProto* svc_proto, + upb_ServiceDef* s) { + upb_StringView name; + size_t n; + + // Must happen before _upb_DefBuilder_Add() + s->file = _upb_DefBuilder_File(ctx); + + name = google_protobuf_ServiceDescriptorProto_name(svc_proto); + _upb_DefBuilder_CheckIdentNotFull(ctx, name); + const char* package = _upb_FileDef_RawPackage(s->file); + s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); + _upb_DefBuilder_Add(ctx, s->full_name, + _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + + const google_protobuf_MethodDescriptorProto* const* methods = + google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); + s->method_count = n; + s->methods = _upb_MethodDefs_New(ctx, n, methods, s); + + UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeFixedPacked( - 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. - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } - _upb_Decoder_Reserve(d, arr, count); - void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); - arr->size += 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_ServiceDef* _upb_ServiceDefs_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_ServiceDescriptorProto* const* protos) { + _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); + + upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); + for (int i = 0; i < n; i++) { + create_service(ctx, protos[i], &s[i]); + s[i].index = i; } + return s; +} - return ptr; + +#include + + +// Must be last. + +// A few fake field types for our tables. +enum { + kUpb_FakeFieldType_FieldNotFound = 0, + kUpb_FakeFieldType_MessageSetItem = 19, +}; + +// DecodeOp: an action to be performed for a wire-type/field-type combination. +enum { + // Special ops: we don't write data to regular fields for these. + kUpb_DecodeOp_UnknownField = -1, + kUpb_DecodeOp_MessageSetItem = -2, + + // Scalar-only ops. + kUpb_DecodeOp_Scalar1Byte = 0, + kUpb_DecodeOp_Scalar4Byte = 2, + kUpb_DecodeOp_Scalar8Byte = 3, + kUpb_DecodeOp_Enum = 1, + + // Scalar/repeated ops. + kUpb_DecodeOp_String = 4, + kUpb_DecodeOp_Bytes = 5, + kUpb_DecodeOp_SubMessage = 6, + + // Repeated-only ops (also see macros below). + kUpb_DecodeOp_PackedEnum = 13, +}; + +// For packed fields it is helpful to be able to recover the lg2 of the data +// size from the 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] */ + +typedef union { + bool bool_val; + uint32_t uint32_val; + uint64_t uint64_val; + uint32_t size; +} wireval; + +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout); + +UPB_NORETURN static void* _upb_Decoder_ErrorJmp(upb_Decoder* d, + upb_DecodeStatus status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeVarintPacked( - 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 = _upb_Decoder_PushLimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); - while (!_upb_Decoder_IsDone(d, &ptr)) { - wireval elem; - ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); - _upb_Decoder_Munge(field->descriptortype, &elem); - if (_upb_Decoder_Reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); - } - arr->size++; - memcpy(out, &elem, scale); - out += scale; +const char* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status) { + assert(status != kUpb_DecodeStatus_Ok); + UPB_LONGJMP(d->err, status); + return NULL; +} +static void _upb_Decoder_VerifyUtf8(upb_Decoder* d, const char* buf, int len) { + if (!_upb_Decoder_VerifyUtf8Inline(buf, len)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_BadUtf8); } - _upb_Decoder_PopLimit(d, ptr, saved_limit); - return ptr; } -UPB_NOINLINE -static const char* _upb_Decoder_DecodeEnumPacked( - 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 = _upb_Decoder_PushLimit(d, ptr, val->size); - char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); - while (!_upb_Decoder_IsDone(d, &ptr)) { - wireval elem; - ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); - _upb_Decoder_MungeInt32(&elem); - if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, &elem)) { - continue; - } - if (_upb_Decoder_Reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); - } - arr->size++; - memcpy(out, &elem, 4); - out += 4; +static bool _upb_Decoder_Reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { + bool need_realloc = arr->capacity - arr->size < elem; + if (need_realloc && !_upb_array_realloc(arr, arr->size + elem, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } - _upb_Decoder_PopLimit(d, ptr, saved_limit); - return ptr; + return need_realloc; } -upb_Array* _upb_Decoder_CreateArray(upb_Decoder* d, - const upb_MiniTable_Field* field) { - /* Maps descriptor type -> elem_size_lg2. */ - static const uint8_t kElemSizeLg2[] = { - [0] = -1, // invalid descriptor type - [kUpb_FieldType_Double] = 3, - [kUpb_FieldType_Float] = 2, - [kUpb_FieldType_Int64] = 3, - [kUpb_FieldType_UInt64] = 3, - [kUpb_FieldType_Int32] = 2, - [kUpb_FieldType_Fixed64] = 3, - [kUpb_FieldType_Fixed32] = 2, - [kUpb_FieldType_Bool] = 0, - [kUpb_FieldType_String] = UPB_SIZE(3, 4), - [kUpb_FieldType_Group] = UPB_SIZE(2, 3), - [kUpb_FieldType_Message] = UPB_SIZE(2, 3), - [kUpb_FieldType_Bytes] = UPB_SIZE(3, 4), - [kUpb_FieldType_UInt32] = 2, - [kUpb_FieldType_Enum] = 2, - [kUpb_FieldType_SFixed32] = 2, - [kUpb_FieldType_SFixed64] = 3, - [kUpb_FieldType_SInt32] = 2, - [kUpb_FieldType_SInt64] = 3, - }; +typedef struct { + const char* ptr; + uint64_t val; +} _upb_DecodeLongVarintReturn; - size_t lg2 = kElemSizeLg2[field->descriptortype]; - upb_Array* ret = _upb_Array_New(&d->arena, 4, lg2); - if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); +UPB_NOINLINE +static _upb_DecodeLongVarintReturn _upb_Decoder_DecodeLongVarint( + const char* ptr, uint64_t val) { + _upb_DecodeLongVarintReturn 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; } -static const char* _upb_Decoder_DecodeToArray(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; - - if (arr) { - _upb_Decoder_Reserve(d, arr, 1); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeVarint(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 { - arr = _upb_Decoder_CreateArray(d, field); - *arrp = arr; + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + *val = res.val; + return res.ptr; } +} - switch (op) { - case kUpb_DecodeOp_Scalar1Byte: - case kUpb_DecodeOp_Scalar4Byte: - case kUpb_DecodeOp_Scalar8Byte: - /* Append scalar value. */ - mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << op, void); - arr->size++; - memcpy(mem, val, 1 << op); - return ptr; - case kUpb_DecodeOp_String: - _upb_Decoder_VerifyUtf8(d, ptr, val->size); - /* Fallthrough. */ - case kUpb_DecodeOp_Bytes: { - /* Append bytes. */ - upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->size; - arr->size++; - return _upb_Decoder_ReadString(d, ptr, val->size, str); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeTag(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; + _upb_DecodeLongVarintReturn res = _upb_Decoder_DecodeLongVarint(ptr, byte); + if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } - case kUpb_DecodeOp_SubMessage: { - /* Append submessage / group. */ - upb_Message* submsg = _upb_Decoder_NewSubMessage(d, subs, field); - *UPB_PTR_AT(_upb_array_ptr(arr), arr->size * sizeof(void*), - upb_Message*) = submsg; - arr->size++; - if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { - return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); - } else { - return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, - val->size); - } - } - case OP_FIXPCK_LG2(2): - case OP_FIXPCK_LG2(3): - return _upb_Decoder_DecodeFixedPacked(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 _upb_Decoder_DecodeVarintPacked(d, ptr, arr, val, field, - op - OP_VARPCK_LG2(0)); - case kUpb_DecodeOp_Enum: - return _upb_Decoder_DecodeEnumArray(d, ptr, msg, arr, subs, field, val); - case kUpb_DecodeOp_PackedEnum: - return _upb_Decoder_DecodeEnumPacked(d, ptr, msg, arr, subs, field, val); - default: - UPB_UNREACHABLE(); + *val = res.val; + return res.ptr; } } -upb_Map* _upb_Decoder_CreateMap(upb_Decoder* d, const upb_MiniTable* entry) { - /* Maps descriptor type -> upb map size. */ - static const uint8_t kSizeInMap[] = { - [0] = -1, // invalid descriptor type */ - [kUpb_FieldType_Double] = 8, - [kUpb_FieldType_Float] = 4, - [kUpb_FieldType_Int64] = 8, - [kUpb_FieldType_UInt64] = 8, - [kUpb_FieldType_Int32] = 4, - [kUpb_FieldType_Fixed64] = 8, - [kUpb_FieldType_Fixed32] = 4, - [kUpb_FieldType_Bool] = 1, - [kUpb_FieldType_String] = UPB_MAPTYPE_STRING, - [kUpb_FieldType_Group] = sizeof(void*), - [kUpb_FieldType_Message] = sizeof(void*), - [kUpb_FieldType_Bytes] = UPB_MAPTYPE_STRING, - [kUpb_FieldType_UInt32] = 4, - [kUpb_FieldType_Enum] = 4, - [kUpb_FieldType_SFixed32] = 4, - [kUpb_FieldType_SFixed64] = 8, - [kUpb_FieldType_SInt32] = 4, - [kUpb_FieldType_SInt64] = 8, - }; - - const upb_MiniTable_Field* key_field = &entry->fields[0]; - const upb_MiniTable_Field* val_field = &entry->fields[1]; - char key_size = kSizeInMap[key_field->descriptortype]; - char val_size = kSizeInMap[val_field->descriptortype]; - UPB_ASSERT(key_field->offset == 0); - UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); - upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size); - if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - return ret; -} - -static const char* _upb_Decoder_DecodeToMap(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) { - map = _upb_Decoder_CreateMap(d, entry); - *map_p = map; - } - - /* 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 = _upb_Decoder_DecodeSubMessage(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_Decoder_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); - if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { - _upb_Decoder_ErrorJmp(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) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - } +UPB_FORCEINLINE +static const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, + uint32_t* size) { + uint64_t size64; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &size64); + if (size64 >= INT32_MAX || ptr - d->end + (int)size64 > d->limit) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } + *size = size64; return ptr; } -static const char* _upb_Decoder_DecodeToSubMessage( - 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 == kUpb_DecodeOp_Enum) && - !_upb_Decoder_CheckEnum(d, ptr, msg, subs[field->submsg_index].subenum, - field, val)) { - return ptr; - } - - /* 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 == kUpb_DecodeOp_SubMessage && *oneof_case != field->number) { - memset(mem, 0, sizeof(void*)); - } - *oneof_case = field->number; +static void _upb_Decoder_MungeInt32(wireval* val) { + if (!_upb_IsLittleEndian()) { + /* The next stage will memcpy(dst, &val, 4) */ + val->uint32_val = val->uint64_val; } +} - /* Store into message. */ - switch (op) { - case kUpb_DecodeOp_SubMessage: { - upb_Message** submsgp = mem; - upb_Message* submsg = *submsgp; - if (!submsg) { - submsg = _upb_Decoder_NewSubMessage(d, subs, field); - *submsgp = submsg; - } - if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { - ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); - } else { - ptr = _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, - val->size); - } +static void _upb_Decoder_Munge(int type, wireval* val) { + switch (type) { + case kUpb_FieldType_Bool: + val->bool_val = val->uint64_val != 0; break; - } - case kUpb_DecodeOp_String: - _upb_Decoder_VerifyUtf8(d, ptr, val->size); - /* Fallthrough. */ - case kUpb_DecodeOp_Bytes: - return _upb_Decoder_ReadString(d, ptr, val->size, mem); - case kUpb_DecodeOp_Scalar8Byte: - memcpy(mem, val, 8); + case kUpb_FieldType_SInt32: { + uint32_t n = val->uint64_val; + val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1); break; - case kUpb_DecodeOp_Enum: - case kUpb_DecodeOp_Scalar4Byte: - memcpy(mem, val, 4); + } + case kUpb_FieldType_SInt64: { + uint64_t n = val->uint64_val; + val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1); break; - case kUpb_DecodeOp_Scalar1Byte: - memcpy(mem, val, 1); + } + case kUpb_FieldType_Int32: + case kUpb_FieldType_UInt32: + case kUpb_FieldType_Enum: + _upb_Decoder_MungeInt32(val); break; - default: - UPB_UNREACHABLE(); } +} - return ptr; +static upb_Message* _upb_Decoder_NewSubMessage( + upb_Decoder* d, const upb_MiniTableSub* subs, + const upb_MiniTableField* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + UPB_ASSERT(subl); + upb_Message* msg = _upb_Message_New(subl, &d->arena); + if (!msg) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return msg; } UPB_NOINLINE -const char* _upb_Decoder_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; +const char* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, + int overrun) { + int status; + ptr = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); + if (ptr == NULL) _upb_Decoder_ErrorJmp(d, status); + return ptr; +} + +static const char* _upb_Decoder_ReadString(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) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + memcpy(data, ptr, size); + str->data = data; } - 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; + str->size = size; + return ptr + size; +} + +UPB_FORCEINLINE +static const char* _upb_Decoder_RecurseSubMessage(upb_Decoder* d, + const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t expected_end_group) { + if (--d->depth < 0) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); + } + ptr = _upb_Decoder_DecodeMessage(d, ptr, submsg, subl); + d->depth++; + if (d->end_group != expected_end_group) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } return ptr; } UPB_FORCEINLINE -static bool _upb_Decoder_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 = _upb_FastDecoder_LoadTag(*ptr); - intptr_t table = decode_totable(layout); - *ptr = _upb_FastDecoder_TagDispatch(d, *ptr, msg, table, 0, tag); - return true; +static const char* _upb_Decoder_DecodeSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* submsg, + const upb_MiniTableSub* subs, const upb_MiniTableField* field, int size) { + int saved_delta = _upb_Decoder_PushLimit(d, ptr, size); + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + UPB_ASSERT(subl); + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, DECODE_NOGROUP); + _upb_Decoder_PopLimit(d, ptr, saved_delta); + return ptr; +} + +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeGroup(upb_Decoder* d, const char* ptr, + upb_Message* submsg, + const upb_MiniTable* subl, + uint32_t number) { + if (_upb_Decoder_IsDone(d, &ptr)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } -#endif - return false; + ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, number); + d->end_group = DECODE_NOGROUP; + return ptr; } -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 _upb_Decoder_DecodeVarint(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 _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); - default: - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); - } +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeUnknownGroup(upb_Decoder* d, + const char* ptr, + uint32_t number) { + return _upb_Decoder_DecodeGroup(d, ptr, NULL, NULL, number); } -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), -}; - -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)) { - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); - } - upb_Message* submsg = - _upb_Decoder_NewSubMessage(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) _upb_Decoder_ErrorJmp(d, status); +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeKnownGroup( + upb_Decoder* d, const char* ptr, upb_Message* submsg, + const upb_MiniTableSub* subs, const upb_MiniTableField* field) { + const upb_MiniTable* subl = subs[field->submsg_index].submsg; + UPB_ASSERT(subl); + return _upb_Decoder_DecodeGroup(d, ptr, submsg, subl, field->number); } -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; +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; +} - ptr = upb_Decoder_EncodeVarint32(kEndItemTag, ptr); - char* end = ptr; +static void _upb_Decoder_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, split - buf, &d->arena) || - !_upb_Message_AddUnknown(msg, message_data, message_size, &d->arena) || - !_upb_Message_AddUnknown(msg, split, end - split, &d->arena)) { + if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } } -static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, - const upb_MiniTable* t, - uint32_t type_id, const char* data, - uint32_t size) { - const upb_MiniTable_Extension* item_mt = - upb_ExtensionRegistry_Lookup(d->extreg, t, type_id); - if (item_mt) { - upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); - } else { - upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); - } -} +UPB_NOINLINE +static bool _upb_Decoder_CheckEnumSlow(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTableEnum* e, + const upb_MiniTableField* field, + uint32_t v) { + if (_upb_MiniTable_CheckEnumValueSlow(e, v)) return true; -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 (!_upb_Decoder_IsDone(d, &ptr)) { - uint32_t tag; - ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); - switch (tag) { - case kEndItemTag: - return ptr; - case kTypeIdTag: { - uint64_t tmp; - ptr = _upb_Decoder_DecodeVarint(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; - } - } - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + // 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_Decoder_AddUnknownVarints(d, unknown_msg, tag, v); + return false; } -static const upb_MiniTable_Field* _upb_Decoder_FindField( - upb_Decoder* d, const upb_MiniTable* t, uint32_t field_number, - int* last_field_index) { - static upb_MiniTable_Field none = { - 0, 0, 0, 0, kUpb_FakeFieldType_FieldNotFound, 0}; - if (t == NULL) return &none; +UPB_FORCEINLINE +static bool _upb_Decoder_CheckEnum(upb_Decoder* d, const char* ptr, + upb_Message* msg, const upb_MiniTableEnum* e, + const upb_MiniTableField* field, + wireval* val) { + uint32_t v = val->uint32_val; - size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX - if (idx < t->dense_below) { - /* Fastest case: index into dense fields. */ - goto found; - } + _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, v); + if (UPB_LIKELY(status == _kUpb_FastEnumCheck_ValueIsInEnum)) return true; + return _upb_Decoder_CheckEnumSlow(d, ptr, msg, e, field, v); +} - if (t->dense_below < t->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 < t->field_count; idx++) { - if (t->fields[idx].number == field_number) { - goto found; - } - } +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumArray(upb_Decoder* d, const char* ptr, + upb_Message* msg, + upb_Array* arr, + const upb_MiniTableSub* subs, + const upb_MiniTableField* field, + wireval* val) { + const upb_MiniTableEnum* e = subs[field->submsg_index].subenum; + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, val)) return ptr; + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + arr->size++; + memcpy(mem, val, 4); + return ptr; +} - for (idx = t->dense_below; idx < last; idx++) { - if (t->fields[idx].number == field_number) { - goto found; - } - } +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeFixedPacked( + upb_Decoder* d, const char* ptr, upb_Array* arr, wireval* val, + const upb_MiniTableField* 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. + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } - - if (d->extreg) { - switch (t->ext) { - case kUpb_ExtMode_Extendable: { - const upb_MiniTable_Extension* ext = - upb_ExtensionRegistry_Lookup(d->extreg, t, field_number); - if (ext) return &ext->field; - break; + _upb_Decoder_Reserve(d, arr, count); + void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + arr->size += 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)); } - case kUpb_ExtMode_IsMessageSet: - if (field_number == _UPB_MSGSET_ITEM) { - static upb_MiniTable_Field item = { - 0, 0, 0, 0, kUpb_FakeFieldType_MessageSetItem, 0}; - return &item; - } - break; + ptr += 1 << lg2; + dst += 1 << lg2; } } - return &none; /* Unknown field. */ - -found: - UPB_ASSERT(t->fields[idx].number == field_number); - *last_field_index = idx; - return &t->fields[idx]; + return ptr; } -int _upb_Decoder_GetVarintOp(const upb_MiniTable_Field* field) { - static const int8_t kVarintOps[] = { - [kUpb_FakeFieldType_FieldNotFound] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Int64] = kUpb_DecodeOp_Scalar8Byte, - [kUpb_FieldType_UInt64] = kUpb_DecodeOp_Scalar8Byte, - [kUpb_FieldType_Int32] = kUpb_DecodeOp_Scalar4Byte, - [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Bool] = kUpb_DecodeOp_Scalar1Byte, - [kUpb_FieldType_String] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Message] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Bytes] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_UInt32] = kUpb_DecodeOp_Scalar4Byte, - [kUpb_FieldType_Enum] = kUpb_DecodeOp_Enum, - [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SInt32] = kUpb_DecodeOp_Scalar4Byte, - [kUpb_FieldType_SInt64] = kUpb_DecodeOp_Scalar8Byte, - [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, - }; - - return kVarintOps[field->descriptortype]; +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeVarintPacked( + upb_Decoder* d, const char* ptr, upb_Array* arr, wireval* val, + const upb_MiniTableField* field, int lg2) { + int scale = 1 << lg2; + int saved_limit = _upb_Decoder_PushLimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_Munge(field->descriptortype, &elem); + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void); + } + arr->size++; + memcpy(out, &elem, scale); + out += scale; + } + _upb_Decoder_PopLimit(d, ptr, saved_limit); + return ptr; } -int _upb_Decoder_GetDelimitedOp(const upb_MiniTable* mt, - const upb_MiniTable_Field* field) { - enum { kRepeatedBase = 19 }; - - static const int8_t kDelimitedOps[] = { - /* For non-repeated field type. */ - [kUpb_FakeFieldType_FieldNotFound] = - kUpb_DecodeOp_UnknownField, // Field not found. - [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Int64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_UInt64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Int32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Bool] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_String] = kUpb_DecodeOp_String, - [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, - [kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, - [kUpb_FieldType_UInt32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_Enum] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SInt32] = kUpb_DecodeOp_UnknownField, - [kUpb_FieldType_SInt64] = kUpb_DecodeOp_UnknownField, - [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, - // For repeated field type. */ - [kRepeatedBase + kUpb_FieldType_Double] = OP_FIXPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_Float] = OP_FIXPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_Int64] = OP_VARPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_UInt64] = OP_VARPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_Int32] = OP_VARPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_Fixed64] = OP_FIXPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_Fixed32] = OP_FIXPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_Bool] = OP_VARPCK_LG2(0), - [kRepeatedBase + kUpb_FieldType_String] = kUpb_DecodeOp_String, - [kRepeatedBase + kUpb_FieldType_Group] = kUpb_DecodeOp_SubMessage, - [kRepeatedBase + kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, - [kRepeatedBase + kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, - [kRepeatedBase + kUpb_FieldType_UInt32] = OP_VARPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_Enum] = kUpb_DecodeOp_PackedEnum, - [kRepeatedBase + kUpb_FieldType_SFixed32] = OP_FIXPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_SFixed64] = OP_FIXPCK_LG2(3), - [kRepeatedBase + kUpb_FieldType_SInt32] = OP_VARPCK_LG2(2), - [kRepeatedBase + kUpb_FieldType_SInt64] = OP_VARPCK_LG2(3), - // Omitting kUpb_FakeFieldType_MessageSetItem, because we never emit a - // repeated msgset type - }; - - int ndx = field->descriptortype; - if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += kRepeatedBase; - int op = kDelimitedOps[ndx]; - - // If sub-message is not linked, treat as unknown. - if (op == kUpb_DecodeOp_SubMessage && - !(field->mode & kUpb_LabelFlags_IsExtension)) { - const upb_MiniTable_Sub* sub = &mt->subs[field->submsg_index]; - if (!sub->submsg) { - op = kUpb_DecodeOp_UnknownField; +UPB_NOINLINE +static const char* _upb_Decoder_DecodeEnumPacked( + upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, + const upb_MiniTableSub* subs, const upb_MiniTableField* field, + wireval* val) { + const upb_MiniTableEnum* e = subs[field->submsg_index].subenum; + int saved_limit = _upb_Decoder_PushLimit(d, ptr, val->size); + char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + while (!_upb_Decoder_IsDone(d, &ptr)) { + wireval elem; + ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val); + _upb_Decoder_MungeInt32(&elem); + if (!_upb_Decoder_CheckEnum(d, ptr, msg, e, field, &elem)) { + continue; } + if (_upb_Decoder_Reserve(d, arr, 1)) { + out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size * 4, void); + } + arr->size++; + memcpy(out, &elem, 4); + out += 4; } + _upb_Decoder_PopLimit(d, ptr, saved_limit); + return ptr; +} - return op; +upb_Array* _upb_Decoder_CreateArray(upb_Decoder* d, + const upb_MiniTableField* field) { + /* Maps descriptor type -> elem_size_lg2. */ + static const uint8_t kElemSizeLg2[] = { + [0] = -1, // invalid descriptor type + [kUpb_FieldType_Double] = 3, + [kUpb_FieldType_Float] = 2, + [kUpb_FieldType_Int64] = 3, + [kUpb_FieldType_UInt64] = 3, + [kUpb_FieldType_Int32] = 2, + [kUpb_FieldType_Fixed64] = 3, + [kUpb_FieldType_Fixed32] = 2, + [kUpb_FieldType_Bool] = 0, + [kUpb_FieldType_String] = UPB_SIZE(3, 4), + [kUpb_FieldType_Group] = UPB_SIZE(2, 3), + [kUpb_FieldType_Message] = UPB_SIZE(2, 3), + [kUpb_FieldType_Bytes] = UPB_SIZE(3, 4), + [kUpb_FieldType_UInt32] = 2, + [kUpb_FieldType_Enum] = 2, + [kUpb_FieldType_SFixed32] = 2, + [kUpb_FieldType_SFixed64] = 3, + [kUpb_FieldType_SInt32] = 2, + [kUpb_FieldType_SInt64] = 3, + }; + + size_t lg2 = kElemSizeLg2[field->descriptortype]; + upb_Array* ret = _upb_Array_New(&d->arena, 4, lg2); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeWireValue( - upb_Decoder* d, const char* ptr, const upb_MiniTable* mt, - const upb_MiniTable_Field* field, int wire_type, wireval* val, int* op) { - static const unsigned kFixed32OkMask = (1 << kUpb_FieldType_Float) | - (1 << kUpb_FieldType_Fixed32) | - (1 << kUpb_FieldType_SFixed32); +static const char* _upb_Decoder_DecodeToArray(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTableSub* subs, + const upb_MiniTableField* field, + wireval* val, int op) { + upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void); + upb_Array* arr = *arrp; + void* mem; - static const unsigned kFixed64OkMask = (1 << kUpb_FieldType_Double) | - (1 << kUpb_FieldType_Fixed64) | - (1 << kUpb_FieldType_SFixed64); + if (arr) { + _upb_Decoder_Reserve(d, arr, 1); + } else { + arr = _upb_Decoder_CreateArray(d, field); + *arrp = arr; + } - switch (wire_type) { - case kUpb_WireType_Varint: - ptr = _upb_Decoder_DecodeVarint(d, ptr, &val->uint64_val); - *op = _upb_Decoder_GetVarintOp(field); - _upb_Decoder_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 = kUpb_DecodeOp_Scalar4Byte; - if (((1 << field->descriptortype) & kFixed32OkMask) == 0) { - *op = kUpb_DecodeOp_UnknownField; - } - return ptr + 4; - case kUpb_WireType_64Bit: - memcpy(&val->uint64_val, ptr, 8); - val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); - *op = kUpb_DecodeOp_Scalar8Byte; - if (((1 << field->descriptortype) & kFixed64OkMask) == 0) { - *op = kUpb_DecodeOp_UnknownField; - } - return ptr + 8; - case kUpb_WireType_Delimited: - ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); - *op = _upb_Decoder_GetDelimitedOp(mt, field); + switch (op) { + case kUpb_DecodeOp_Scalar1Byte: + case kUpb_DecodeOp_Scalar4Byte: + case kUpb_DecodeOp_Scalar8Byte: + /* Append scalar value. */ + mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << op, void); + arr->size++; + memcpy(mem, val, 1 << op); return ptr; - case kUpb_WireType_StartGroup: - val->uint32_val = field->number; - if (field->descriptortype == kUpb_FieldType_Group) { - *op = kUpb_DecodeOp_SubMessage; - } else if (field->descriptortype == kUpb_FakeFieldType_MessageSetItem) { - *op = kUpb_DecodeOp_MessageSetItem; + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: { + /* Append bytes. */ + upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->size; + arr->size++; + return _upb_Decoder_ReadString(d, ptr, val->size, str); + } + case kUpb_DecodeOp_SubMessage: { + /* Append submessage / group. */ + upb_Message* submsg = _upb_Decoder_NewSubMessage(d, subs, field); + *UPB_PTR_AT(_upb_array_ptr(arr), arr->size * sizeof(void*), + upb_Message*) = submsg; + arr->size++; + if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) { + return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); } else { - *op = kUpb_DecodeOp_UnknownField; + return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); } - return ptr; + } + case OP_FIXPCK_LG2(2): + case OP_FIXPCK_LG2(3): + return _upb_Decoder_DecodeFixedPacked(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 _upb_Decoder_DecodeVarintPacked(d, ptr, arr, val, field, + op - OP_VARPCK_LG2(0)); + case kUpb_DecodeOp_Enum: + return _upb_Decoder_DecodeEnumArray(d, ptr, msg, arr, subs, field, val); + case kUpb_DecodeOp_PackedEnum: + return _upb_Decoder_DecodeEnumPacked(d, ptr, msg, arr, subs, field, val); default: - break; + UPB_UNREACHABLE(); } - _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); } -UPB_FORCEINLINE -static const char* _upb_Decoder_DecodeKnownField( - 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)) { - _upb_Decoder_ErrorJmp(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 _upb_Decoder_DecodeToArray(d, ptr, msg, subs, field, val, op); - case kUpb_FieldMode_Map: - return _upb_Decoder_DecodeToMap(d, ptr, msg, subs, field, val); - case kUpb_FieldMode_Scalar: - return _upb_Decoder_DecodeToSubMessage(d, ptr, msg, subs, field, val, op); - default: - UPB_UNREACHABLE(); - } -} +upb_Map* _upb_Decoder_CreateMap(upb_Decoder* d, const upb_MiniTable* entry) { + /* Maps descriptor type -> upb map size. */ + static const uint8_t kSizeInMap[] = { + [0] = -1, // invalid descriptor type */ + [kUpb_FieldType_Double] = 8, + [kUpb_FieldType_Float] = 4, + [kUpb_FieldType_Int64] = 8, + [kUpb_FieldType_UInt64] = 8, + [kUpb_FieldType_Int32] = 4, + [kUpb_FieldType_Fixed64] = 8, + [kUpb_FieldType_Fixed32] = 4, + [kUpb_FieldType_Bool] = 1, + [kUpb_FieldType_String] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_Group] = sizeof(void*), + [kUpb_FieldType_Message] = sizeof(void*), + [kUpb_FieldType_Bytes] = UPB_MAPTYPE_STRING, + [kUpb_FieldType_UInt32] = 4, + [kUpb_FieldType_Enum] = 4, + [kUpb_FieldType_SFixed32] = 4, + [kUpb_FieldType_SFixed64] = 8, + [kUpb_FieldType_SInt32] = 4, + [kUpb_FieldType_SInt64] = 8, + }; -static const char* _upb_Decoder_ReverseSkipVarint(const char* ptr, - uint32_t val) { - uint32_t seen = 0; - do { - ptr--; - seen <<= 7; - seen |= *ptr & 0x7f; - } while (seen != val); - return ptr; + const upb_MiniTableField* key_field = &entry->fields[0]; + const upb_MiniTableField* val_field = &entry->fields[1]; + char key_size = kSizeInMap[key_field->descriptortype]; + char val_size = kSizeInMap[val_field->descriptortype]; + UPB_ASSERT(key_field->offset == 0); + UPB_ASSERT(val_field->offset == sizeof(upb_StringView)); + upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size); + if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + return ret; } -static const char* _upb_Decoder_DecodeUnknownField(upb_Decoder* d, - const char* ptr, - upb_Message* msg, - int field_number, - int wire_type, wireval val) { - if (field_number == 0) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +static const char* _upb_Decoder_DecodeToMap(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTableSub* subs, + const upb_MiniTableField* 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; - // 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; + if (!map) { + map = _upb_Decoder_CreateMap(d, entry); + *map_p = map; + } - 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; - } + /* Parse map entry. */ + memset(&ent, 0, sizeof(ent)); - assert(start == d->debug_valstart); - uint32_t tag = ((uint32_t)field_number << 3) | wire_type; - start = _upb_Decoder_ReverseSkipVarint(start, tag); - assert(start == d->debug_tagstart); + 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)); + } - if (wire_type == kUpb_WireType_StartGroup) { - d->unknown = start; - d->unknown_msg = msg; - ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); - start = d->unknown; - d->unknown = NULL; - } + const char* start = ptr; + ptr = _upb_Decoder_DecodeSubMessage(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_Decoder_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); } - } else if (wire_type == kUpb_WireType_StartGroup) { - ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + } else { + if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, + &d->arena) == kUpb_MapInsertStatus_OutOfMemory) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } + return ptr; +} + +static const char* _upb_Decoder_DecodeToSubMessage( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTableSub* subs, const upb_MiniTableField* field, wireval* val, + int op) { + void* mem = UPB_PTR_AT(msg, field->offset, void); + int type = field->descriptortype; + + if (UPB_UNLIKELY(op == kUpb_DecodeOp_Enum) && + !_upb_Decoder_CheckEnum(d, ptr, msg, subs[field->submsg_index].subenum, + field, val)) { + return ptr; + } + + /* 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 == kUpb_DecodeOp_SubMessage && *oneof_case != field->number) { + memset(mem, 0, sizeof(void*)); + } + *oneof_case = field->number; + } + + /* Store into message. */ + switch (op) { + case kUpb_DecodeOp_SubMessage: { + upb_Message** submsgp = mem; + upb_Message* submsg = *submsgp; + if (!submsg) { + submsg = _upb_Decoder_NewSubMessage(d, subs, field); + *submsgp = submsg; + } + if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { + ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field); + } else { + ptr = _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field, + val->size); + } + break; + } + case kUpb_DecodeOp_String: + _upb_Decoder_VerifyUtf8(d, ptr, val->size); + /* Fallthrough. */ + case kUpb_DecodeOp_Bytes: + return _upb_Decoder_ReadString(d, ptr, val->size, mem); + case kUpb_DecodeOp_Scalar8Byte: + memcpy(mem, val, 8); + break; + case kUpb_DecodeOp_Enum: + case kUpb_DecodeOp_Scalar4Byte: + memcpy(mem, val, 4); + break; + case kUpb_DecodeOp_Scalar1Byte: + memcpy(mem, val, 1); + break; + default: + UPB_UNREACHABLE(); } + return ptr; } UPB_NOINLINE -static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable* layout) { - int last_field_index = 0; +const char* _upb_Decoder_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 _upb_Decoder_TryFastDispatch(upb_Decoder* d, const char** ptr, + upb_Message* msg, + const upb_MiniTable* layout) { #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 (!_upb_Decoder_IsDone(d, &ptr)) goto nofast; + if (layout && layout->table_mask != (unsigned char)-1) { + uint16_t tag = _upb_FastDecoder_LoadTag(*ptr); + intptr_t table = decode_totable(layout); + *ptr = _upb_FastDecoder_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 _upb_Decoder_DecodeVarint(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 _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + default: + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + } +} + +enum { + kStartItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_StartGroup), + kEndItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_EndGroup), + kTypeIdTag = ((kUpb_MsgSet_TypeId << 3) | kUpb_WireType_Varint), + kMessageTag = ((kUpb_MsgSet_Message << 3) | kUpb_WireType_Delimited), +}; + +static void upb_Decoder_AddKnownMessageSetItem( + upb_Decoder* d, upb_Message* msg, const upb_MiniTableExtension* item_mt, + const char* data, uint32_t size) { + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, item_mt, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + upb_Message* submsg = + _upb_Decoder_NewSubMessage(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) _upb_Decoder_ErrorJmp(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)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } +} + +static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, + const upb_MiniTable* t, + uint32_t type_id, const char* data, + uint32_t size) { + const upb_MiniTableExtension* item_mt = + upb_ExtensionRegistry_Lookup(d->extreg, t, type_id); + if (item_mt) { + upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); + } else { + upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); + } +} + +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 (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + switch (tag) { + case kEndItemTag: + return ptr; + case kTypeIdTag: { + uint64_t tmp; + ptr = _upb_Decoder_DecodeVarint(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; + } + } + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +} + +static const upb_MiniTableField* _upb_Decoder_FindField(upb_Decoder* d, + const upb_MiniTable* t, + uint32_t field_number, + int* last_field_index) { + static upb_MiniTableField none = { + 0, 0, 0, 0, kUpb_FakeFieldType_FieldNotFound, 0}; + if (t == NULL) return &none; + + size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX + if (idx < t->dense_below) { + /* Fastest case: index into dense fields. */ + goto found; + } + + if (t->dense_below < t->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 < t->field_count; idx++) { + if (t->fields[idx].number == field_number) { + goto found; + } + } + + for (idx = t->dense_below; idx < last; idx++) { + if (t->fields[idx].number == field_number) { + goto found; + } + } + } + + if (d->extreg) { + switch (t->ext) { + case kUpb_ExtMode_Extendable: { + const upb_MiniTableExtension* ext = + upb_ExtensionRegistry_Lookup(d->extreg, t, field_number); + if (ext) return &ext->field; + break; + } + case kUpb_ExtMode_IsMessageSet: + if (field_number == kUpb_MsgSet_Item) { + static upb_MiniTableField item = { + 0, 0, 0, 0, kUpb_FakeFieldType_MessageSetItem, 0}; + return &item; + } + break; + } + } + + return &none; /* Unknown field. */ + +found: + UPB_ASSERT(t->fields[idx].number == field_number); + *last_field_index = idx; + return &t->fields[idx]; +} + +int _upb_Decoder_GetVarintOp(const upb_MiniTableField* field) { + static const int8_t kVarintOps[] = { + [kUpb_FakeFieldType_FieldNotFound] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_Scalar1Byte, + [kUpb_FieldType_String] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_Enum, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_Scalar4Byte, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_Scalar8Byte, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + }; + + return kVarintOps[field->descriptortype]; +} + +int _upb_Decoder_GetDelimitedOp(const upb_MiniTable* mt, + const upb_MiniTableField* field) { + enum { kRepeatedBase = 19 }; + + static const int8_t kDelimitedOps[] = { + /* For non-repeated field type. */ + [kUpb_FakeFieldType_FieldNotFound] = + kUpb_DecodeOp_UnknownField, // Field not found. + [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_UInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Int32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Bool] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kUpb_FieldType_UInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_Enum] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt32] = kUpb_DecodeOp_UnknownField, + [kUpb_FieldType_SInt64] = kUpb_DecodeOp_UnknownField, + [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, + // For repeated field type. */ + [kRepeatedBase + kUpb_FieldType_Double] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Float] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Int64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_UInt64] = OP_VARPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Int32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Fixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_Fixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Bool] = OP_VARPCK_LG2(0), + [kRepeatedBase + kUpb_FieldType_String] = kUpb_DecodeOp_String, + [kRepeatedBase + kUpb_FieldType_Group] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, + [kRepeatedBase + kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, + [kRepeatedBase + kUpb_FieldType_UInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_Enum] = kUpb_DecodeOp_PackedEnum, + [kRepeatedBase + kUpb_FieldType_SFixed32] = OP_FIXPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SFixed64] = OP_FIXPCK_LG2(3), + [kRepeatedBase + kUpb_FieldType_SInt32] = OP_VARPCK_LG2(2), + [kRepeatedBase + kUpb_FieldType_SInt64] = OP_VARPCK_LG2(3), + // Omitting kUpb_FakeFieldType_MessageSetItem, because we never emit a + // repeated msgset type + }; + + int ndx = field->descriptortype; + if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += kRepeatedBase; + int op = kDelimitedOps[ndx]; + + // If sub-message is not linked, treat as unknown. + if (op == kUpb_DecodeOp_SubMessage && + !(field->mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTableSub* sub = &mt->subs[field->submsg_index]; + if (!sub->submsg) { + op = kUpb_DecodeOp_UnknownField; + } + } + + return op; +} + +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeWireValue(upb_Decoder* d, const char* ptr, + const upb_MiniTable* mt, + const upb_MiniTableField* field, + int wire_type, wireval* val, + int* op) { + static const unsigned kFixed32OkMask = (1 << kUpb_FieldType_Float) | + (1 << kUpb_FieldType_Fixed32) | + (1 << kUpb_FieldType_SFixed32); + + static const unsigned kFixed64OkMask = (1 << kUpb_FieldType_Double) | + (1 << kUpb_FieldType_Fixed64) | + (1 << kUpb_FieldType_SFixed64); + + switch (wire_type) { + case kUpb_WireType_Varint: + ptr = _upb_Decoder_DecodeVarint(d, ptr, &val->uint64_val); + *op = _upb_Decoder_GetVarintOp(field); + _upb_Decoder_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 = kUpb_DecodeOp_Scalar4Byte; + if (((1 << field->descriptortype) & kFixed32OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr + 4; + case kUpb_WireType_64Bit: + memcpy(&val->uint64_val, ptr, 8); + val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val); + *op = kUpb_DecodeOp_Scalar8Byte; + if (((1 << field->descriptortype) & kFixed64OkMask) == 0) { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr + 8; + case kUpb_WireType_Delimited: + ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); + *op = _upb_Decoder_GetDelimitedOp(mt, field); + return ptr; + case kUpb_WireType_StartGroup: + val->uint32_val = field->number; + if (field->descriptortype == kUpb_FieldType_Group) { + *op = kUpb_DecodeOp_SubMessage; + } else if (field->descriptortype == kUpb_FakeFieldType_MessageSetItem) { + *op = kUpb_DecodeOp_MessageSetItem; + } else { + *op = kUpb_DecodeOp_UnknownField; + } + return ptr; + default: + break; + } + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); +} + +UPB_FORCEINLINE +static const char* _upb_Decoder_DecodeKnownField( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout, const upb_MiniTableField* field, int op, + wireval* val) { + const upb_MiniTableSub* subs = layout->subs; + uint8_t mode = field->mode; + + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { + const upb_MiniTableExtension* ext_layout = + (const upb_MiniTableExtension*)field; + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, ext_layout, &d->arena); + if (UPB_UNLIKELY(!ext)) { + _upb_Decoder_ErrorJmp(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 _upb_Decoder_DecodeToArray(d, ptr, msg, subs, field, val, op); + case kUpb_FieldMode_Map: + return _upb_Decoder_DecodeToMap(d, ptr, msg, subs, field, val); + case kUpb_FieldMode_Scalar: + return _upb_Decoder_DecodeToSubMessage(d, ptr, msg, subs, field, val, op); + default: + UPB_UNREACHABLE(); + } +} + +static const char* _upb_Decoder_ReverseSkipVarint(const char* ptr, + uint32_t val) { + uint32_t seen = 0; + do { + ptr--; + seen <<= 7; + seen |= *ptr & 0x7f; + } while (seen != val); + return ptr; +} + +static const char* _upb_Decoder_DecodeUnknownField(upb_Decoder* d, + const char* ptr, + upb_Message* msg, + int field_number, + int wire_type, wireval val) { + if (field_number == 0) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); + + // 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; + + 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; + } + + assert(start == d->debug_valstart); + uint32_t tag = ((uint32_t)field_number << 3) | wire_type; + start = _upb_Decoder_ReverseSkipVarint(start, tag); + assert(start == d->debug_tagstart); + + if (wire_type == kUpb_WireType_StartGroup) { + d->unknown = start; + d->unknown_msg = msg; + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + start = d->unknown; + d->unknown = NULL; + } + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory); + } + } else if (wire_type == kUpb_WireType_StartGroup) { + ptr = _upb_Decoder_DecodeUnknownGroup(d, ptr, field_number); + } + return ptr; +} + +UPB_NOINLINE +static const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, + upb_Message* msg, + const upb_MiniTable* layout) { + int last_field_index = 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 (!_upb_Decoder_IsDone(d, &ptr)) goto nofast; +#endif + + while (!_upb_Decoder_IsDone(d, &ptr)) { + uint32_t tag; + const upb_MiniTableField* field; + int field_number; + int wire_type; + wireval val; + int op; + + if (_upb_Decoder_TryFastDispatch(d, &ptr, msg, layout)) break; + +#if UPB_FASTTABLE + nofast: +#endif + +#ifndef NDEBUG + d->debug_tagstart = ptr; +#endif + + UPB_ASSERT(ptr < d->limit_ptr); + ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); + field_number = tag >> 3; + wire_type = tag & 7; + +#ifndef NDEBUG + d->debug_valstart = ptr; +#endif + + if (wire_type == kUpb_WireType_EndGroup) { + d->end_group = field_number; + return ptr; + } + + field = _upb_Decoder_FindField(d, layout, field_number, &last_field_index); + ptr = _upb_Decoder_DecodeWireValue(d, ptr, layout, field, wire_type, &val, + &op); + + if (op >= 0) { + ptr = _upb_Decoder_DecodeKnownField(d, ptr, msg, layout, field, op, &val); + } else { + switch (op) { + case kUpb_DecodeOp_UnknownField: + ptr = _upb_Decoder_DecodeUnknownField(d, ptr, msg, field_number, + wire_type, val); + break; + case kUpb_DecodeOp_MessageSetItem: + ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); + break; + } + } + } + + return UPB_UNLIKELY(layout && layout->required_count) + ? _upb_Decoder_CheckRequired(d, ptr, msg, layout) + : ptr; +} + +const char* _upb_FastDecoder_DecodeGeneric(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 _upb_Decoder_DecodeMessage(d, ptr, msg, decode_totablep(table)); +} + +static upb_DecodeStatus _upb_Decoder_DecodeTop(struct upb_Decoder* d, + const char* buf, void* msg, + const upb_MiniTable* l) { + if (!_upb_Decoder_TryFastDispatch(d, &buf, msg, l)) { + _upb_Decoder_DecodeMessage(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_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 = _upb_Decoder_DecodeTop(&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; +} + +#undef OP_FIXPCK_LG2 +#undef OP_VARPCK_LG2 + +// 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 _upb_FastDecoder_DecodeGeneric(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 = _upb_Decoder_IsDoneFallbackInline(d, ptr, overrun, &status); + if (ptr == NULL) _upb_FastDecoder_ErrorJmp(d, status); + data = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_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) + ? _upb_Decoder_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 = _upb_FastDecoder_LoadTag(ptr); + UPB_MUSTTAIL return _upb_FastDecoder_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 = _upb_Decoder_PushLimit(d, ptr, len); + ptr = func(d, ptr, ctx); + _upb_Decoder_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->capacity; + 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->capacity = 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->size = + (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(!_upb_Decoder_IsDone(d, ptr))) { + ret.tag = _upb_FastDecoder_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->capacity * valbytes); + *data = _upb_FastDecoder_LoadTag(ptr); + return begin + (farr->arr->size * 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) _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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 (!_upb_Decoder_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)) { \ + _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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)) { \ + _upb_FastDecoder_ErrorJmp(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) { \ + _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ + } \ + } else { \ + _upb_Array_Resize(arr, elems, &d->arena); \ + } \ + \ + char* dst = _upb_array_ptr(arr); \ + memcpy(dst, ptr, size); \ + arr->size = 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 (!_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { + _upb_FastDecoder_ErrorJmp(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; \ + _upb_FastDecoder_ErrorJmp(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) { \ + _upb_FastDecoder_ErrorJmp(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 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_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 && \ + !_upb_Decoder_VerifyUtf8Inline(dst->data, dst->size)) { \ + _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + } \ + goto again; \ + case FD_NEXT_OTHERFIELD: \ + data = ret.tag; \ + UPB_MUSTTAIL return _upb_FastDecoder_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); - while (!_upb_Decoder_IsDone(d, &ptr)) { - uint32_t tag; - const upb_MiniTable_Field* field; - int field_number; - int wire_type; - wireval val; - int op; +/* Generate all combinations: + * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ - if (_upb_Decoder_TryFastDispatch(d, &ptr, msg, layout)) break; +#define s_VALIDATE true +#define b_VALIDATE false -#if UPB_FASTTABLE - nofast: -#endif +#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); \ + } -#ifndef NDEBUG - d->debug_tagstart = ptr; -#endif +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) - UPB_ASSERT(ptr < d->limit_ptr); - ptr = _upb_Decoder_DecodeTag(d, ptr, &tag); - field_number = tag >> 3; - wire_type = tag & 7; +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) -#ifndef NDEBUG - d->debug_valstart = ptr; -#endif +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) - if (wire_type == kUpb_WireType_EndGroup) { - d->end_group = field_number; - return ptr; - } +#undef s_VALIDATE +#undef b_VALIDATE +#undef F +#undef TAGBYTES +#undef FASTDECODE_LONGSTRING +#undef FASTDECODE_COPYSTRING +#undef FASTDECODE_STRING - field = _upb_Decoder_FindField(d, layout, field_number, &last_field_index); - ptr = _upb_Decoder_DecodeWireValue(d, ptr, layout, field, wire_type, &val, - &op); +/* message fields *************************************************************/ - if (op >= 0) { - ptr = _upb_Decoder_DecodeKnownField(d, ptr, msg, layout, field, op, &val); - } else { - switch (op) { - case kUpb_DecodeOp_UnknownField: - ptr = _upb_Decoder_DecodeUnknownField(d, ptr, msg, field_number, - wire_type, val); - break; - case kUpb_DecodeOp_MessageSetItem: - ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); - break; - } - } +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 UPB_UNLIKELY(layout && layout->required_count) - ? _upb_Decoder_CheckRequired(d, ptr, msg, layout) - : ptr; + return msg_data + sizeof(upb_Message_Internal); } -const char* _upb_FastDecoder_DecodeGeneric(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 _upb_Decoder_DecodeMessage(d, ptr, msg, decode_totablep(table)); -} +typedef struct { + intptr_t table; + upb_Message* msg; +} fastdecode_submsgdata; -static upb_DecodeStatus _upb_Decoder_DecodeTop(struct upb_Decoder* d, - const char* buf, void* msg, - const upb_MiniTable* l) { - if (!_upb_Decoder_TryFastDispatch(d, &buf, msg, l)) { - _upb_Decoder_DecodeMessage(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_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; } -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; +#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) { \ + _upb_FastDecoder_ErrorJmp(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)) { \ + _upb_FastDecoder_ErrorJmp(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 _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ + case FD_NEXT_ATLIMIT: \ + d->depth++; \ + return ptr; \ + } \ + } \ + \ + d->depth++; \ + UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS); - 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; +#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); \ } - 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; +#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) - upb_DecodeStatus status = UPB_SETJMP(state.err); - if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) { - status = _upb_Decoder_DecodeTop(&state, buf, msg, l); - } +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) - arena->head.ptr = state.arena.head.ptr; - arena->head.end = state.arena.head.end; - arena->cleanup_metadata = state.arena.cleanup_metadata; - return status; -} +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) -#undef OP_FIXPCK_LG2 -#undef OP_VARPCK_LG2 +#undef TAGBYTES +#undef SIZES +#undef F +#undef FASTDECODE_SUBMSG + +#endif /* UPB_FASTTABLE */ // We encode backwards, to avoid pre-computing lengths (one-pass encode). @@ -12365,8 +12953,8 @@ 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 upb_MiniTableSub* subs, + const upb_MiniTableField* f) { const char* field_mem = _field_mem; int wire_type; @@ -12448,8 +13036,8 @@ static void encode_scalar(upb_encstate* e, const void* _field_mem, } static void encode_array(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { + const upb_MiniTableSub* subs, + const upb_MiniTableField* 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; @@ -12556,8 +13144,8 @@ static void encode_array(upb_encstate* e, const upb_Message* msg, 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]; + const upb_MiniTableField* key_field = &layout->fields[0]; + const upb_MiniTableField* 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); @@ -12568,8 +13156,8 @@ static void encode_mapentry(upb_encstate* e, uint32_t number, } static void encode_map(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { + const upb_MiniTableSub* subs, + const upb_MiniTableField* 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); @@ -12586,11 +13174,10 @@ static void encode_map(upb_encstate* e, const upb_Message* msg, } _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); + intptr_t iter = UPB_STRTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&map->table, &key, &val, &iter)) { upb_MapEntry ent; _upb_map_fromkey(key, &ent.k, map->key_size); _upb_map_fromvalue(val, &ent.v, map->val_size); @@ -12600,12 +13187,12 @@ static void encode_map(upb_encstate* e, const upb_Message* msg, } static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* f) { + const upb_MiniTableSub* subs, + const upb_MiniTableField* 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) { + switch (_upb_MiniTableField_GetRep(f)) { case kUpb_FieldRep_1Byte: { char ch; memcpy(&ch, mem, 1); @@ -12638,8 +13225,8 @@ static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, } static void encode_field(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable_Sub* subs, - const upb_MiniTable_Field* field) { + const upb_MiniTableSub* subs, + const upb_MiniTableField* field) { switch (upb_FieldMode_Get(field)) { case kUpb_FieldMode_Array: encode_array(e, msg, subs, field); @@ -12655,22 +13242,16 @@ static void encode_field(upb_encstate* e, const upb_Message* msg, } } -/* 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_tag(e, kUpb_MsgSet_Item, 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_tag(e, kUpb_MsgSet_Message, kUpb_WireType_Delimited); encode_varint(e, ext->ext->field.number); - encode_tag(e, 2, kUpb_WireType_Varint); - encode_tag(e, 1, kUpb_WireType_StartGroup); + encode_tag(e, kUpb_MsgSet_TypeId, kUpb_WireType_Varint); + encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup); } static void encode_message(upb_encstate* e, const upb_Message* msg, @@ -12714,8 +13295,8 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, } if (m->field_count) { - const upb_MiniTable_Field* f = &m->fields[m->field_count]; - const upb_MiniTable_Field* first = &m->fields[0]; + const upb_MiniTableField* f = &m->fields[m->field_count]; + const upb_MiniTableField* first = &m->fields[0]; while (f != first) { f--; if (encode_shouldencode(e, msg, m->subs, f)) { @@ -12766,7 +13347,7 @@ upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l, return status; } -/* See port_def.inc. This should #undef all macros #defined there. */ +// This should #undef all macros #defined in def.inc #undef UPB_SIZE #undef UPB_PTR_AT diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index 615018c950..fc544cb2bf 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -3,10 +3,9 @@ /* Amalgamated source file */ /* - * This is where we define macros used across upb. + * This is where we define internal portability macros used across upb. * - * All of these macros are undef'd in port_undef.inc to avoid leaking them to - * users. + * All of these macros are undef'd in undef.inc to avoid leaking them to users. * * The correct usage is: * @@ -14,13 +13,13 @@ * #include "upb/baz.h" * * // MUST be last included header. - * #include "upb/port_def.inc" + * #include "upb/port/def.inc" * * // Code for this file. * // <...> * * // Can be omitted for .c files, required for .h. - * #include "upb/port_undef.inc" + * #include "upb/port/undef.inc" * * This file is private and must not be included by users! */ @@ -45,6 +44,7 @@ #include #include #include +#include #if UINTPTR_MAX == 0xffffffff #define UPB_SIZE(size32, size64) size32 @@ -57,11 +57,6 @@ */ #define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) -#define UPB_READ_ONEOF(msg, fieldtype, offset, case_offset, case_val, default) \ - *UPB_PTR_AT(msg, case_offset, int) == case_val \ - ? *UPB_PTR_AT(msg, offset, fieldtype) \ - : default - #define UPB_WRITE_ONEOF(msg, fieldtype, offset, value, case_offset, case_val) \ *UPB_PTR_AT(msg, case_offset, int) = case_val; \ *UPB_PTR_AT(msg, offset, fieldtype) = value; @@ -83,16 +78,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)) @@ -115,8 +110,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() @@ -269,30 +263,43 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #define UPB_DEPRECATED #endif -#ifndef UPB_INTERNAL_ATOI_H_ -#define UPB_INTERNAL_ATOI_H_ +#ifndef UPB_BASE_STATUS_H_ +#define UPB_BASE_STATUS_H_ + +#include // Must be last. +#define _kUpb_Status_MaxMessage 127 + +typedef struct { + bool ok; + char msg[_kUpb_Status_MaxMessage]; // Error message; NULL-terminated. +} upb_Status; + #ifdef __cplusplus extern "C" { #endif -// 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. -// Return the new position of the pointer after parsing the int, or NULL on -// integer overflow. +const char* upb_Status_ErrorMessage(const upb_Status* status); +bool upb_Status_IsOk(const upb_Status* status); -const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val); -const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, - bool* is_neg); +// These are no-op if |status| is NULL. +void upb_Status_Clear(upb_Status* status); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) + UPB_PRINTF(2, 3); +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_INTERNAL_ATOI_H_ */ +#endif /* UPB_BASE_STATUS_H_ */ #ifndef UPB_INTERNAL_ARRAY_INTERNAL_H_ #define UPB_INTERNAL_ARRAY_INTERNAL_H_ @@ -304,21 +311,167 @@ const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, #define UPB_COLLECTIONS_ARRAY_H_ +#ifndef UPB_BASE_DESCRIPTOR_CONSTANTS_H_ +#define UPB_BASE_DESCRIPTOR_CONSTANTS_H_ + +// The types a field can have. Note that this list is not identical to the +// types defined in descriptor.proto, which gives INT32 and SINT32 separate +// types (we distinguish the two with the "integer encoding" enum below). +// This enum is an internal convenience only and has no meaning outside of upb. +typedef enum { + kUpb_CType_Bool = 1, + kUpb_CType_Float = 2, + kUpb_CType_Int32 = 3, + kUpb_CType_UInt32 = 4, + kUpb_CType_Enum = 5, // Enum values are int32. + kUpb_CType_Message = 6, + kUpb_CType_Double = 7, + kUpb_CType_Int64 = 8, + kUpb_CType_UInt64 = 9, + kUpb_CType_String = 10, + kUpb_CType_Bytes = 11 +} upb_CType; + +// The repeated-ness of each field; this matches descriptor.proto. +typedef enum { + kUpb_Label_Optional = 1, + kUpb_Label_Required = 2, + kUpb_Label_Repeated = 3 +} upb_Label; + +// Descriptor types, as defined in descriptor.proto. +typedef enum { + kUpb_FieldType_Double = 1, + kUpb_FieldType_Float = 2, + kUpb_FieldType_Int64 = 3, + kUpb_FieldType_UInt64 = 4, + kUpb_FieldType_Int32 = 5, + kUpb_FieldType_Fixed64 = 6, + kUpb_FieldType_Fixed32 = 7, + kUpb_FieldType_Bool = 8, + kUpb_FieldType_String = 9, + kUpb_FieldType_Group = 10, + kUpb_FieldType_Message = 11, + kUpb_FieldType_Bytes = 12, + kUpb_FieldType_UInt32 = 13, + kUpb_FieldType_Enum = 14, + kUpb_FieldType_SFixed32 = 15, + kUpb_FieldType_SFixed64 = 16, + kUpb_FieldType_SInt32 = 17, + kUpb_FieldType_SInt64 = 18, +} upb_FieldType; + +#define kUpb_FieldType_SizeOf 19 + +#endif /* UPB_BASE_DESCRIPTOR_CONSTANTS_H_ */ + +// Users should include array.h or map.h instead. +// IWYU pragma: private, include "upb/collections/array.h" + #ifndef UPB_MESSAGE_VALUE_H_ #define UPB_MESSAGE_VALUE_H_ -/* - * Public APIs for message operations that do not require descriptors. - * These functions can be used even in build that does not want to depend on - * reflection or descriptors. - * - * Descriptor-based reflection functionality lives in reflection.h. - */ +#ifndef UPB_BASE_STRING_VIEW_H_ +#define UPB_BASE_STRING_VIEW_H_ + +#include + +// Must be last. + +#define UPB_STRINGVIEW_INIT(ptr, len) \ + { ptr, len } + +#define UPB_STRINGVIEW_FORMAT "%.*s" +#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data + +// LINT.IfChange(struct_definition) +typedef struct { + const char* data; + size_t size; +} upb_StringView; +// LINT.ThenChange(GoogleInternalName0) + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, + size_t size) { + upb_StringView ret; + ret.data = data; + ret.size = size; + return ret; +} + +UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { + return upb_StringView_FromDataAndSize(data, strlen(data)); +} + +UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { + return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_STRING_VIEW_H_ */ + +#ifndef UPB_MINI_TABLE_TYPES_H_ +#define UPB_MINI_TABLE_TYPES_H_ + +typedef void upb_Message; + +typedef struct upb_MiniTable upb_MiniTable; +typedef struct upb_MiniTableEnum upb_MiniTableEnum; +typedef struct upb_MiniTableExtension upb_MiniTableExtension; +typedef struct upb_MiniTableField upb_MiniTableField; +typedef struct upb_MiniTableFile upb_MiniTableFile; +typedef union upb_MiniTableSub upb_MiniTableSub; + +#endif /* UPB_MINI_TABLE_TYPES_H_ */ + +// Must be last. + +typedef struct upb_Array upb_Array; +typedef struct upb_Map upb_Map; + +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_Array* array_val; + const upb_Map* map_val; + const upb_Message* msg_val; + upb_StringView str_val; +} upb_MessageValue; + +typedef union { + upb_Array* array; + upb_Map* map; + upb_Message* msg; +} upb_MutableMessageValue; -#ifndef UPB_MSG_H_ -#define UPB_MSG_H_ +#endif /* UPB_MESSAGE_VALUE_H_ */ + +/* upb_Arena is a specific allocator implementation that uses arena allocation. + * The user provides an allocator that will be used to allocate the underlying + * arena blocks. Arenas by nature do not require the individual allocations + * to be freed. However the Arena does allow users to register cleanup + * functions that will run when the arena is destroyed. + * + * A upb_Arena is *not* thread-safe. + * + * You could write a thread-safe arena allocator that satisfies the + * upb_alloc interface, but it would not be as efficient for the + * single-threaded case. */ #ifndef UPB_MEM_ARENA_H_ #define UPB_MEM_ARENA_H_ @@ -398,26 +551,10 @@ UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } // Must be last. -#ifdef __cplusplus -extern "C" { -#endif - -/* upb_Arena is a specific allocator implementation that uses arena allocation. - * The user provides an allocator that will be used to allocate the underlying - * arena blocks. Arenas by nature do not require the individual allocations - * to be freed. However the Arena does allow users to register cleanup - * functions that will run when the arena is destroyed. - * - * A upb_Arena is *not* thread-safe. - * - * You could write a thread-safe arena allocator that satisfies the - * upb_alloc interface, but it would not be as efficient for the - * single-threaded case. */ - -typedef void upb_CleanupFunc(void* ud); - typedef struct upb_Arena upb_Arena; +typedef void upb_CleanupFunc(void* context); + typedef struct { /* We implement the allocator interface. * This must be the first member of upb_Arena! @@ -427,6 +564,10 @@ typedef struct { char *ptr, *end; } _upb_ArenaHead; +#ifdef __cplusplus +extern "C" { +#endif + /* Creates an arena from the given initial block (if any -- n may be 0). * Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this * is a fixed-size arena and cannot grow. */ @@ -445,7 +586,13 @@ UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) { return (size_t)(h->end - h->ptr); } -UPB_INLINE void* _upb_Arena_FastMalloc(upb_Arena* a, size_t size) { +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); + } + + // We have enough space to do a fast malloc. _upb_ArenaHead* h = (_upb_ArenaHead*)a; void* ret = h->ptr; UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret); @@ -468,16 +615,6 @@ UPB_INLINE void* _upb_Arena_FastMalloc(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 @@ -535,40 +672,48 @@ UPB_INLINE upb_Arena* upb_Arena_New(void) { extern "C" { #endif -typedef void upb_Message; +/* 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); -/* For users these are opaque. They can be obtained from - * upb_MessageDef_MiniTable() but users cannot access any of the members. */ -typedef struct upb_MiniTable upb_MiniTable; +/* Returns the number of elements in the array. */ +size_t upb_Array_Size(const upb_Array* arr); -/* Creates a new message with the given mini_table on the given arena. */ -upb_Message* upb_Message_New(const upb_MiniTable* mini_table, upb_Arena* arena); +/* 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); -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ -void upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, - upb_Arena* arena); +/* 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); -/* Returns a reference to the message's unknown data. */ -const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len); +/* Appends an element to the array. Returns false on allocation failure. */ +bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); -/* Removes partial unknown data from message. */ -void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len); +/* 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); -/* Returns the number of extensions present in this message. */ -size_t upb_Message_ExtensionCount(const upb_Message* msg); +/* 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); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_MSG_INT_H_ */ - -#ifndef UPB_STRING_VIEW_H_ -#define UPB_STRING_VIEW_H_ - -#include +#endif /* UPB_COLLECTIONS_ARRAY_H_ */ // Must be last. @@ -576,296 +721,14 @@ size_t upb_Message_ExtensionCount(const upb_Message* msg); extern "C" { #endif -typedef struct { - const char* data; - size_t size; -} upb_StringView; - -UPB_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data, - size_t size) { - upb_StringView ret; - ret.data = data; - ret.size = size; - return ret; -} - -UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) { - return upb_StringView_FromDataAndSize(data, strlen(data)); -} - -UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { - return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; -} - -#define UPB_STRINGVIEW_INIT(ptr, len) \ - { ptr, len } - -#define UPB_STRINGVIEW_FORMAT "%.*s" -#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_STRING_VIEW_H_ */ - -/* - * This file contains shared definitions that are widely used across upb. - */ - -#ifndef UPB_H_ -#define UPB_H_ - -#include -#include -#include -#include -#include -#include - -// TODO(b/232091617): Remove these and fix everything that breaks as a result. - -#ifndef UPB_STATUS_H_ -#define UPB_STATUS_H_ - -#include - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -#define _kUpb_Status_MaxMessage 127 - -typedef struct { - bool ok; - char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */ -} upb_Status; - -const char* upb_Status_ErrorMessage(const upb_Status* status); -bool upb_Status_IsOk(const upb_Status* status); - -/* These are no-op if |status| is NULL. */ -void upb_Status_Clear(upb_Status* status); -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) - UPB_PRINTF(2, 3); -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_STATUS_H_ */ - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -// These types appear in circular references so we need to forward-declare them. -// There is no obviously good place for this so let's just put it here. -typedef struct upb_Array upb_Array; -typedef struct upb_Map upb_Map; - -/* Constants ******************************************************************/ - -/* A list of types as they are encoded on-the-wire. */ -typedef enum { - kUpb_WireType_Varint = 0, - kUpb_WireType_64Bit = 1, - kUpb_WireType_Delimited = 2, - kUpb_WireType_StartGroup = 3, - kUpb_WireType_EndGroup = 4, - kUpb_WireType_32Bit = 5 -} upb_WireType; - -/* The types a field can have. Note that this list is not identical to the - * types defined in descriptor.proto, which gives INT32 and SINT32 separate - * types (we distinguish the two with the "integer encoding" enum below). */ -typedef enum { - kUpb_CType_Bool = 1, - kUpb_CType_Float = 2, - kUpb_CType_Int32 = 3, - kUpb_CType_UInt32 = 4, - kUpb_CType_Enum = 5, /* Enum values are int32. */ - kUpb_CType_Message = 6, - kUpb_CType_Double = 7, - kUpb_CType_Int64 = 8, - kUpb_CType_UInt64 = 9, - kUpb_CType_String = 10, - kUpb_CType_Bytes = 11 -} upb_CType; - -/* The repeated-ness of each field; this matches descriptor.proto. */ -typedef enum { - kUpb_Label_Optional = 1, - kUpb_Label_Required = 2, - kUpb_Label_Repeated = 3 -} upb_Label; - -/* Descriptor types, as defined in descriptor.proto. */ -typedef enum { - kUpb_FieldType_Double = 1, - kUpb_FieldType_Float = 2, - kUpb_FieldType_Int64 = 3, - kUpb_FieldType_UInt64 = 4, - kUpb_FieldType_Int32 = 5, - kUpb_FieldType_Fixed64 = 6, - kUpb_FieldType_Fixed32 = 7, - kUpb_FieldType_Bool = 8, - kUpb_FieldType_String = 9, - kUpb_FieldType_Group = 10, - kUpb_FieldType_Message = 11, - kUpb_FieldType_Bytes = 12, - kUpb_FieldType_UInt32 = 13, - kUpb_FieldType_Enum = 14, - kUpb_FieldType_SFixed32 = 15, - kUpb_FieldType_SFixed64 = 16, - kUpb_FieldType_SInt32 = 17, - kUpb_FieldType_SInt64 = 18, -} upb_FieldType; - -#define kUpb_FieldType_SizeOf 19 - -#define kUpb_Map_Begin ((size_t)-1) - -UPB_INLINE bool _upb_IsLittleEndian(void) { - int x = 1; - return *(char*)&x == 1; -} - -UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) { - if (_upb_IsLittleEndian()) { - return val; - } else { - return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | - ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); - } -} - -UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { - if (_upb_IsLittleEndian()) { - return val; - } else { - return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | - _upb_BigEndian_Swap32((uint32_t)(val >> 32)); - } -} - -UPB_INLINE int _upb_Log2Ceiling(int x) { - if (x <= 1) return 0; -#ifdef __GNUC__ - return 32 - __builtin_clz(x - 1); -#else - int lg2 = 0; - while (1 << lg2 < x) lg2++; - return lg2; -#endif -} - -UPB_INLINE int _upb_Log2CeilingSize(int x) { return 1 << _upb_Log2Ceiling(x); } - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_H_ */ - -// Must be last. - -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_Array* array_val; - const upb_Map* map_val; - const upb_Message* msg_val; - upb_StringView str_val; -} upb_MessageValue; - -typedef union { - upb_Array* array; - upb_Map* map; - upb_Message* msg; -} upb_MutableMessageValue; - - -#endif /* UPB_MESSAGE_VALUE_H_ */ - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -/* 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 number of elements in 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); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_COLLECTIONS_ARRAY_H_ */ - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -// Our internal representation for repeated fields. -struct upb_Array { - uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ - size_t size; /* The number of elements in the array. */ - size_t capacity; /* Allocated storage. Measured in elements. */ -}; +// LINT.IfChange(struct_definition) +// Our internal representation for repeated fields. +struct upb_Array { + uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ + size_t size; /* The number of elements in the array. */ + size_t capacity; /* Allocated storage. Measured in elements. */ +}; +// LINT.ThenChange(GoogleInternalName1) UPB_INLINE const void* _upb_array_constptr(const upb_Array* arr) { UPB_ASSERT((arr->data & 7) <= 4); @@ -1048,11 +911,9 @@ bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, 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 @@ -1070,22 +931,36 @@ UPB_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key, kUpb_MapInsertStatus_OutOfMemory; } -/* Deletes this key from the table. Returns true if the key was present. */ +// 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; +// upb_MessageValue key, val; +// while (upb_Map_Next(map, &key, &val, &iter)) { +// ... +// } + +#define kUpb_Map_Begin ((size_t)-1) + +// Advances to the next entry. Returns false if no more entries are present. +// Otherwise returns true and populates both *key and *value. +bool upb_Map_Next(const upb_Map* map, upb_MessageValue* key, + upb_MessageValue* val, size_t* iter); + +// DEPRECATED iterator, slated for removal. + /* 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. */ +// 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 @@ -1097,11 +972,6 @@ bool upb_MapIterator_Done(const upb_Map* map, size_t iter); 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 @@ -1109,91 +979,15 @@ void upb_MapIterator_SetValue(upb_Map* map, size_t iter, #endif /* UPB_COLLECTIONS_MAP_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 - - -#ifndef UPB_EXTENSION_REGISTRY_H_ -#define UPB_EXTENSION_REGISTRY_H_ - - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -/* Extension registry: a dynamic data structure that stores a map of: - * (upb_MiniTable, number) -> extension info - * - * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing - * binary format. - * - * upb_ExtensionRegistry is part of the mini-table (msglayout) family of - * objects. Like all mini-table objects, it is suitable for reflection-less - * builds that do not want to expose names into the binary. - * - * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory - * allocation and dynamic initialization: - * * If reflection is being used, then upb_DefPool will construct an appropriate - * upb_ExtensionRegistry automatically. - * * For a mini-table only build, the user must manually construct the - * upb_ExtensionRegistry and populate it with all of the extensions the user - * cares about. - * * A third alternative is to manually unpack relevant extensions after the - * main parse is complete, similar to how Any works. This is perhaps the - * nicest solution from the perspective of reducing dependencies, avoiding - * dynamic memory allocation, and avoiding the need to parse uninteresting - * extensions. The downsides are: - * (1) parse errors are not caught during the main parse - * (2) the CPU hit of parsing comes during access, which could cause an - * undesirable stutter in application performance. - * - * Users cannot directly get or put into this map. Users can only add the - * extensions from a generated module and pass the extension registry to the - * binary decoder. - * - * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use - * reflection do not need to populate a upb_ExtensionRegistry directly. - */ - -typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; -typedef struct upb_MiniTable_Extension upb_MiniTable_Extension; - -// Creates a upb_ExtensionRegistry in the given arena. -// The arena must outlive any use of the extreg. -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); - -// Adds the given extension info for the array |e| of size |count| into the -// registry. If there are any errors, the entire array is backed out. -// The extensions must outlive the registry. -// Possible errors include OOM or an extension number that already exists. -// TODO: There is currently no way to determine the exact reason for failure. -bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, - size_t count); +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// -// Looks up the extension (if any) defined for message type |t| and field -// number |num|. Returns the extension if found, otherwise NULL. -const upb_MiniTable_Extension* upb_ExtensionRegistry_Lookup( - const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num); +#ifndef UPB_COLLECTIONS_MAP_INTERNAL_H_ +#define UPB_COLLECTIONS_MAP_INTERNAL_H_ -#ifdef __cplusplus -} /* extern "C" */ -#endif +#ifndef UPB_HASH_STR_TABLE_H_ +#define UPB_HASH_STR_TABLE_H_ -#endif /* UPB_EXTENSION_REGISTRY_H_ */ /* * upb_table @@ -1214,8 +1008,8 @@ const upb_MiniTable_Extension* upb_ExtensionRegistry_Lookup( * mode, we check this on insert and lookup. */ -#ifndef UPB_INTERNAL_TABLE_H_ -#define UPB_INTERNAL_TABLE_H_ +#ifndef UPB_HASH_COMMON_H_ +#define UPB_HASH_COMMON_H_ #include @@ -1347,67 +1141,63 @@ typedef struct { upb_tabent* entries; } upb_table; -typedef struct { - upb_table t; -} upb_strtable; - -typedef struct { - upb_table t; /* For entries that don't fit in the array part. */ - const upb_tabval* array; /* Array part of the table. See const note above. */ - size_t array_size; /* Array part size. */ - size_t array_count; /* Array part number of elements. */ -} upb_inttable; - UPB_INLINE size_t upb_table_size(const upb_table* t) { - if (t->size_lg2 == 0) - return 0; - else - return 1 << t->size_lg2; + return t->size_lg2 ? 1 << t->size_lg2 : 0; } -/* Internal-only functions, in .h file only out of necessity. */ +// Internal-only functions, in .h file only out of necessity. UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; } -/* Initialize and uninitialize a table, respectively. If memory allocation - * failed, false is returned that the table is uninitialized. */ -bool upb_inttable_init(upb_inttable* table, upb_Arena* a); +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_HASH_COMMON_H_ */ + +// Must be last. + +typedef struct { + upb_table t; +} upb_strtable; + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize a table. If memory allocation failed, false is returned and +// the table is uninitialized. bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a); -/* Returns the number of values in the table. */ -size_t upb_inttable_count(const upb_inttable* t); +// Returns the number of values in the table. UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) { return t->t.count; } void upb_strtable_clear(upb_strtable* t); -/* Inserts the given key into the hashtable with the given value. The key must - * not already exist in the hash table. For strtables, the key is not required - * to be NULL-terminated, and the table will make an internal copy of the key. - * Inttables must not insert a value of UINTPTR_MAX. - * - * If a table resize was required but memory allocation failed, false is - * returned and the table is unchanged. */ -bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, - upb_Arena* a); +// Inserts the given key into the hashtable with the given value. +// The key must not already exist in the hash table. The key is not required +// to be NULL-terminated, and the table will make an internal copy of the key. +// +// If a table resize was required but memory allocation failed, false is +// returned and the table is unchanged. */ bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len, upb_value val, upb_Arena* a); -/* Looks up key in this table, returning "true" if the key was found. - * If v is non-NULL, copies the value for this key into *v. */ -bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); +// Looks up key in this table, returning "true" if the key was found. +// If v is non-NULL, copies the value for this key into *v. bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, upb_value* v); -/* For NULL-terminated strings. */ +// For NULL-terminated strings. UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key, upb_value* v) { return upb_strtable_lookup2(t, key, strlen(key), v); } -/* Removes an item from the table. Returns true if the remove was successful, - * and stores the removed item in *val if non-NULL. */ -bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); +// Removes an item from the table. Returns true if the remove was successful, +// and stores the removed item in *val if non-NULL. bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, upb_value* val); @@ -1416,40 +1206,12 @@ UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key, return upb_strtable_remove2(t, key, strlen(key), v); } -/* Updates an existing entry in an inttable. If the entry does not exist, - * returns false and does nothing. Unlike insert/remove, this does not - * invalidate iterators. */ -bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); - -/* Optimizes the table for the current set of entries, for both memory use and - * lookup time. Client should call this after all entries have been inserted; - * inserting more entries is legal, but will likely require a table resize. */ -void upb_inttable_compact(upb_inttable* t, upb_Arena* a); - -/* Exposed for testing only. */ +// Exposed for testing only. bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a); -/* Iterators ******************************************************************/ - -/* Iteration over inttable. - * - * intptr_t iter = UPB_INTTABLE_BEGIN; - * uintptr_t key; - * upb_value val; - * while (upb_inttable_next2(t, &key, &val, &iter)) { - * // ... - * } - */ - -#define UPB_INTTABLE_BEGIN -1 - -bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val, - intptr_t* iter); -void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); - -/* Iteration over strtable. +/* Iteration over strtable: * - * intptr_t iter = UPB_INTTABLE_BEGIN; + * intptr_t iter = UPB_STRTABLE_BEGIN; * upb_StringView key; * upb_value val; * while (upb_strtable_next2(t, &key, &val, &iter)) { @@ -1465,7 +1227,7 @@ void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); /* DEPRECATED iterators, slated for removal. * - * Iterators for int and string tables. We are subject to some kind of unusual + * Iterators for string tables. We are subject to some kind of unusual * design constraints: * * For high-level languages: @@ -1485,7 +1247,6 @@ void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter); * an invalidated iterator yields unspecified elements from the table, but it is * guaranteed not to crash and to return real table elements (except when done() * is true). */ - /* upb_strtable_iter **********************************************************/ /* upb_strtable_iter i; @@ -1502,6 +1263,10 @@ typedef struct { size_t index; } upb_strtable_iter; +UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { + return &i->t->t.entries[i->index]; +} + void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t); void upb_strtable_next(upb_strtable_iter* i); bool upb_strtable_done(const upb_strtable_iter* i); @@ -1511,104 +1276,345 @@ void upb_strtable_iter_setdone(upb_strtable_iter* i); bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, const upb_strtable_iter* i2); -/* upb_inttable_iter **********************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* upb_inttable_iter i; - * upb_inttable_begin(&i, t); - * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - * uintptr_t key = upb_inttable_iter_key(&i); - * upb_value val = upb_inttable_iter_value(&i); - * // ... - * } - */ -typedef struct { - const upb_inttable* t; - size_t index; - bool array_part; -} upb_inttable_iter; +#endif /* UPB_HASH_STR_TABLE_H_ */ -UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) { - return &i->t->t.entries[i->index]; -} +// Must be last. -void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t); -void upb_inttable_next(upb_inttable_iter* i); -bool upb_inttable_done(const upb_inttable_iter* i); -uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i); -upb_value upb_inttable_iter_value(const upb_inttable_iter* i); -void upb_inttable_iter_setdone(upb_inttable_iter* i); -bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, - const upb_inttable_iter* i2); +struct upb_Map { + // Size of key and val, based on the map type. + // Strings are represented as '0' because they must be handled specially. + char key_size; + char val_size; -uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); + upb_strtable table; +}; #ifdef __cplusplus -} /* extern "C" */ +extern "C" { #endif +// Converting between internal table representation and user values. +// +// _upb_map_tokey() and _upb_map_fromkey() are inverses. +// _upb_map_tovalue() and _upb_map_fromvalue() are inverses. +// +// These functions account for the fact that strings are treated differently +// from other types when stored in a map. -#endif /* UPB_INTERNAL_TABLE_H_ */ +UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + return *(upb_StringView*)key; + } else { + return upb_StringView_FromDataAndSize((const char*)key, size); + } +} -// Must be last. +UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + memcpy(out, &key, sizeof(key)); + } else { + memcpy(out, key.data, size); + } +} -#ifdef __cplusplus -extern "C" { -#endif +UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, + upb_value* msgval, upb_Arena* a) { + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); + if (!strp) return false; + *strp = *(upb_StringView*)val; + *msgval = upb_value_ptr(strp); + } else { + memcpy(msgval, val, size); + } + return true; +} -/** upb_*Int* conversion routines ********************************************/ +UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { + if (size == UPB_MAPTYPE_STRING) { + const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); + memcpy(out, strp, sizeof(upb_StringView)); + } else { + memcpy(out, &val, size); + } +} -UPB_INLINE int32_t _upb_Int32_FromI(int v) { return (int32_t)v; } +UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { + upb_strtable_iter it; + it.t = &map->table; + it.index = *iter; + upb_strtable_next(&it); + *iter = it.index; + if (upb_strtable_done(&it)) return NULL; + return (void*)str_tabent(&it); +} -UPB_INLINE int64_t _upb_Int64_FromLL(long long v) { return (int64_t)v; } +UPB_INLINE void _upb_Map_Clear(upb_Map* map) { + upb_strtable_clear(&map->table); +} -UPB_INLINE uint32_t _upb_UInt32_FromU(unsigned v) { return (uint32_t)v; } +UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, + size_t key_size) { + upb_StringView k = _upb_map_tokey(key, key_size); + return upb_strtable_remove2(&map->table, k.data, k.size, NULL); +} -UPB_INLINE uint64_t _upb_UInt64_FromULL(unsigned long long v) { - return (uint64_t)v; +UPB_INLINE bool _upb_Map_Get(const upb_Map* map, const void* key, + size_t key_size, void* val, size_t val_size) { + upb_value tabval; + upb_StringView k = _upb_map_tokey(key, key_size); + bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); + if (ret && val) { + _upb_map_fromvalue(tabval, val, val_size); + } + return ret; } -extern const float kUpb_FltInfinity; -extern const double kUpb_Infinity; +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 kUpb_MapInsertStatus_OutOfMemory; + } -/** upb_MiniTable *************************************************************/ + // TODO(haberman): add overwrite operation to minimize number of lookups. + 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_MiniTable represents the memory layout of a given upb_MessageDef. The - * members are public so generated code can initialize them, but users MUST NOT - * read or write any of its members. */ +UPB_INLINE size_t _upb_Map_Size(const upb_Map* map) { + return map->table.t.count; +} -typedef struct { - uint32_t number; - uint16_t offset; - int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index - 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; +// Creates a new map on the given arena with this key/value type. +upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); -#define kUpb_NoSub ((uint16_t)-1) +#ifdef __cplusplus +} /* extern "C" */ +#endif -typedef enum { - kUpb_FieldMode_Map = 0, - kUpb_FieldMode_Array = 1, - kUpb_FieldMode_Scalar = 2, -} upb_FieldMode; -// Mask to isolate the upb_FieldMode from field.mode. -#define kUpb_FieldMode_Mask 3 +#endif /* UPB_COLLECTIONS_MAP_INTERNAL_H_ */ -/* Extra flags on the mode field. */ -typedef enum { - kUpb_LabelFlags_IsPacked = 4, - kUpb_LabelFlags_IsExtension = 8, - // Indicates that this descriptor type is an "alternate type": - // - for Int32, this indicates that the actual type is Enum (but was - // rewritten to Int32 because it is an open enum that requires no check). - // - for Bytes, this indicates that the actual type is String (but does - // not require any UTF-8 check). - kUpb_LabelFlags_IsAlternate = 16, -} upb_LabelFlags; +// Public APIs for message operations that do not require descriptors. +// These functions can be used even in build that does not want to depend on +// reflection or descriptors. +// +// Descriptor-based reflection functionality lives in reflection.h. + +#ifndef UPB_MESSAGE_MESSAGE_H_ +#define UPB_MESSAGE_MESSAGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates a new message with the given mini_table on the given arena. +upb_Message* upb_Message_New(const upb_MiniTable* mini_table, upb_Arena* arena); + +// Adds unknown data (serialized protobuf data) to the given message. +// The data is copied into the message instance. +void upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, + upb_Arena* arena); + +// Returns a reference to the message's unknown data. +const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len); + +// Removes partial unknown data from message. +void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len); + +// Returns the number of extensions present in this message. +size_t upb_Message_ExtensionCount(const upb_Message* msg); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_MESSAGE_H_ */ + +#ifndef UPB_BASE_LOG2_H_ +#define UPB_BASE_LOG2_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE int upb_Log2Ceiling(int x) { + if (x <= 1) return 0; +#ifdef __GNUC__ + return 32 - __builtin_clz(x - 1); +#else + int lg2 = 0; + while (1 << lg2 < x) lg2++; + return lg2; +#endif +} + +UPB_INLINE int upb_Log2CeilingSize(int x) { return 1 << upb_Log2Ceiling(x); } + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_BASE_LOG2_H_ */ + +// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// + +#ifndef UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ +#define UPB_COLLECTIONS_MAP_SORTER_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_MESSAGE_INTERNAL_H_ +#define UPB_MESSAGE_INTERNAL_H_ + +#include +#include + + +#ifndef UPB_EXTENSION_REGISTRY_H_ +#define UPB_EXTENSION_REGISTRY_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +/* Extension registry: a dynamic data structure that stores a map of: + * (upb_MiniTable, number) -> extension info + * + * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing + * binary format. + * + * upb_ExtensionRegistry is part of the mini-table (msglayout) family of + * objects. Like all mini-table objects, it is suitable for reflection-less + * builds that do not want to expose names into the binary. + * + * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory + * allocation and dynamic initialization: + * * If reflection is being used, then upb_DefPool will construct an appropriate + * upb_ExtensionRegistry automatically. + * * For a mini-table only build, the user must manually construct the + * upb_ExtensionRegistry and populate it with all of the extensions the user + * cares about. + * * A third alternative is to manually unpack relevant extensions after the + * main parse is complete, similar to how Any works. This is perhaps the + * nicest solution from the perspective of reducing dependencies, avoiding + * dynamic memory allocation, and avoiding the need to parse uninteresting + * extensions. The downsides are: + * (1) parse errors are not caught during the main parse + * (2) the CPU hit of parsing comes during access, which could cause an + * undesirable stutter in application performance. + * + * Users cannot directly get or put into this map. Users can only add the + * extensions from a generated module and pass the extension registry to the + * binary decoder. + * + * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use + * reflection do not need to populate a upb_ExtensionRegistry directly. + */ + +typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; + +// Creates a upb_ExtensionRegistry in the given arena. +// The arena must outlive any use of the extreg. +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); + +// Adds the given extension info for the array |e| of size |count| into the +// registry. If there are any errors, the entire array is backed out. +// The extensions must outlive the registry. +// Possible errors include OOM or an extension number that already exists. +// TODO: There is currently no way to determine the exact reason for failure. +bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r, + const upb_MiniTableExtension** e, + size_t count); + +// Looks up the extension (if any) defined for message type |t| and field +// number |num|. Returns the extension if found, otherwise NULL. +const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( + const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_EXTENSION_REGISTRY_H_ */ + +#ifndef UPB_MESSAGE_EXTENSION_INTERNAL_H_ +#define UPB_MESSAGE_EXTENSION_INTERNAL_H_ + + +#ifndef UPB_MINI_TABLE_EXTENSION_INTERNAL_H_ +#define UPB_MINI_TABLE_EXTENSION_INTERNAL_H_ + + +#ifndef UPB_MINI_TABLE_FIELD_INTERNAL_H_ +#define UPB_MINI_TABLE_FIELD_INTERNAL_H_ + + +// Must be last. + +struct upb_MiniTableField { + uint32_t number; + uint16_t offset; + int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index + uint16_t submsg_index; // kUpb_NoSub if descriptortype != MESSAGE/GROUP/ENUM + uint8_t descriptortype; + + // upb_FieldMode | upb_LabelFlags | (upb_FieldRep << kUpb_FieldRep_Shift) + uint8_t mode; +}; + +#define kUpb_NoSub ((uint16_t)-1) + +typedef enum { + kUpb_FieldMode_Map = 0, + kUpb_FieldMode_Array = 1, + kUpb_FieldMode_Scalar = 2, +} 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, + kUpb_LabelFlags_IsExtension = 8, + // Indicates that this descriptor type is an "alternate type": + // - for Int32, this indicates that the actual type is Enum (but was + // rewritten to Int32 because it is an open enum that requires no check). + // - for Bytes, this indicates that the actual type is String (but does + // not require any UTF-8 check). + kUpb_LabelFlags_IsAlternate = 16, +} upb_LabelFlags; // Note: we sort by this number when calculating layout order. typedef enum { @@ -1617,82 +1623,215 @@ typedef enum { kUpb_FieldRep_StringView = 2, kUpb_FieldRep_8Byte = 3, - kUpb_FieldRep_Shift = 6, // 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) { +#define kUpb_FieldRep_Shift 6 + +UPB_INLINE upb_FieldRep +_upb_MiniTableField_GetRep(const upb_MiniTableField* field) { + return (upb_FieldRep)(field->mode >> kUpb_FieldRep_Shift); +} + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTableField* field) { return (upb_FieldMode)(field->mode & 3); } -UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTable_Field* field) { - /* This works because upb_FieldMode has no value 3. */ +UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTableField* field) { + // This works because upb_FieldMode has no value 3. return !(field->mode & kUpb_FieldMode_Scalar); } -UPB_INLINE bool upb_IsSubMessage(const upb_MiniTable_Field* field) { +UPB_INLINE bool upb_IsSubMessage(const upb_MiniTableField* field) { return field->descriptortype == kUpb_FieldType_Message || field->descriptortype == kUpb_FieldType_Group; } -struct upb_Decoder; -struct upb_MiniTable; +// LINT.IfChange(presence_logic) -typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, - uint64_t hasbits, uint64_t data); +// Hasbit access /////////////////////////////////////////////////////////////// -typedef struct { - uint64_t field_data; - _upb_FieldParser* field_parser; -} _upb_FastTable_Entry; +UPB_INLINE size_t _upb_hasbit_ofs(size_t idx) { return idx / 8; } -typedef struct { - uint32_t mask_limit; // Limit enum value that can be tested with mask. - uint32_t value_count; // Number of values after the bitfield. - uint32_t data[]; // Bitmask + enumerated values follow. -} upb_MiniTable_Enum; +UPB_INLINE char _upb_hasbit_mask(size_t idx) { return 1 << (idx % 8); } -typedef enum { - _kUpb_FastEnumCheck_ValueIsInEnum = 0, - _kUpb_FastEnumCheck_ValueIsNotInEnum = 1, - _kUpb_FastEnumCheck_CannotCheckFast = 2, -} _kUpb_FastEnumCheck_Status; +UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) { + return (*UPB_PTR_AT(msg, _upb_hasbit_ofs(idx), const char) & + _upb_hasbit_mask(idx)) != 0; +} -UPB_INLINE _kUpb_FastEnumCheck_Status -_upb_MiniTable_CheckEnumValueFast(const upb_MiniTable_Enum* e, uint32_t val) { - if (UPB_UNLIKELY(val >= 64)) return _kUpb_FastEnumCheck_CannotCheckFast; - uint64_t mask = e->data[0] | ((uint64_t)e->data[1] << 32); - return (mask & (1ULL << val)) ? _kUpb_FastEnumCheck_ValueIsInEnum - : _kUpb_FastEnumCheck_ValueIsNotInEnum; +UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) { + (*UPB_PTR_AT(msg, _upb_hasbit_ofs(idx), char)) |= _upb_hasbit_mask(idx); } -UPB_INLINE bool _upb_MiniTable_CheckEnumValueSlow(const upb_MiniTable_Enum* e, - uint32_t val) { - if (val < e->mask_limit) return e->data[val / 32] & (1ULL << (val % 32)); - // OPT: binary search long lists? - const uint32_t* start = &e->data[e->mask_limit / 32]; - const uint32_t* limit = &e->data[(e->mask_limit / 32) + e->value_count]; - for (const uint32_t* p = start; p < limit; p++) { - if (*p == val) return true; - } - return false; +UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) { + (*UPB_PTR_AT(msg, _upb_hasbit_ofs(idx), char)) &= ~_upb_hasbit_mask(idx); } -// Validates enum value against range defined by enum mini table. -UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, - uint32_t val) { - _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, val); - if (UPB_UNLIKELY(status == _kUpb_FastEnumCheck_CannotCheckFast)) { - return _upb_MiniTable_CheckEnumValueSlow(e, val); - } - return status == _kUpb_FastEnumCheck_ValueIsInEnum ? true : false; +UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTableField* f) { + UPB_ASSERT(f->presence > 0); + return f->presence; } -typedef union { - const struct upb_MiniTable* submsg; - const upb_MiniTable_Enum* subenum; -} upb_MiniTable_Sub; +UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg, + const upb_MiniTableField* f) { + return _upb_hasbit(msg, _upb_Message_Hasidx(f)); +} + +UPB_INLINE void _upb_sethas_field(const upb_Message* msg, + const upb_MiniTableField* f) { + _upb_sethas(msg, _upb_Message_Hasidx(f)); +} + +UPB_INLINE void _upb_clearhas_field(const upb_Message* msg, + const upb_MiniTableField* f) { + _upb_clearhas(msg, _upb_Message_Hasidx(f)); +} + +// Oneof case access /////////////////////////////////////////////////////////// + +UPB_INLINE uint32_t* _upb_oneofcase(upb_Message* msg, size_t case_ofs) { + return UPB_PTR_AT(msg, case_ofs, uint32_t); +} + +UPB_INLINE uint32_t _upb_getoneofcase(const void* msg, size_t case_ofs) { + return *UPB_PTR_AT(msg, case_ofs, uint32_t); +} + +UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTableField* f) { + UPB_ASSERT(f->presence < 0); + return ~(ptrdiff_t)f->presence; +} + +UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg, + const upb_MiniTableField* f) { + return _upb_oneofcase(msg, _upb_oneofcase_ofs(f)); +} + +UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg, + const upb_MiniTableField* f) { + return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f)); +} + +UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_Message* msg, size_t ofs) { + return *UPB_PTR_AT(msg, ofs, const upb_Message*) != NULL; +} + +// LINT.ThenChange(GoogleInternalName2) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_FIELD_INTERNAL_H_ */ + +#ifndef UPB_MINI_TABLE_SUB_INTERNAL_H_ +#define UPB_MINI_TABLE_SUB_INTERNAL_H_ + + +union upb_MiniTableSub { + const upb_MiniTable* submsg; + const upb_MiniTableEnum* subenum; +}; + +#endif /* UPB_MINI_TABLE_SUB_INTERNAL_H_ */ + +// Must be last. + +struct upb_MiniTableExtension { + upb_MiniTableField field; + const upb_MiniTable* extendee; + upb_MiniTableSub sub; // NULL unless submessage or proto2 enum +}; + + +#endif /* UPB_MINI_TABLE_EXTENSION_INTERNAL_H_ */ + +// Must be last. + +// The internal representation of an extension is self-describing: it contains +// enough information that we can serialize it to binary format without needing +// to look it up in a upb_ExtensionRegistry. +// +// This representation allocates 16 bytes to data on 64-bit platforms. +// This is rather wasteful for scalars (in the extreme case of bool, +// it wastes 15 bytes). We accept this because we expect messages to be +// the most common extension type. +typedef struct { + const upb_MiniTableExtension* ext; + union { + upb_StringView str; + void* ptr; + char scalar_data[8]; + } data; +} upb_Message_Extension; + +#ifdef __cplusplus +extern "C" { +#endif + +// 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_GetOrCreateExtension( + upb_Message* msg, const upb_MiniTableExtension* ext, upb_Arena* arena); + +// Returns an array of extensions for this message. +// Note: the array is ordered in reverse relative to the order of creation. +const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, + size_t* count); + +// Returns an extension for the given field number, or NULL if no extension +// exists for this field number. +const upb_Message_Extension* _upb_Message_Getext( + const upb_Message* msg, const upb_MiniTableExtension* ext); + +void _upb_Message_Clearext(upb_Message* msg, const upb_MiniTableExtension* ext); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_EXTENSION_INTERNAL_H_ */ + +#ifndef UPB_MINI_TABLE_FILE_INTERNAL_H_ +#define UPB_MINI_TABLE_FILE_INTERNAL_H_ + + +// Must be last. + +struct upb_MiniTableFile { + const upb_MiniTable** msgs; + const upb_MiniTableEnum** enums; + const upb_MiniTableExtension** exts; + int msg_count; + int enum_count; + int ext_count; +}; + + +#endif /* UPB_MINI_TABLE_FILE_INTERNAL_H_ */ + +#ifndef UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ +#define UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ + + +// Must be last. + +struct upb_Decoder; +typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, + upb_Message* msg, intptr_t table, + uint64_t hasbits, uint64_t data); +typedef struct { + uint64_t field_data; + _upb_FieldParser* field_parser; +} _upb_FastTable_Entry; typedef enum { kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. @@ -1706,51 +1845,32 @@ typedef enum { kUpb_ExtMode_IsMapEntry = 4, } upb_ExtMode; -/* MessageSet wire format is: - * message MessageSet { - * repeated group Item = 1 { - * required int32 type_id = 2; - * required bytes message = 3; - * } - * } - */ -typedef enum { - _UPB_MSGSET_ITEM = 1, - _UPB_MSGSET_TYPEID = 2, - _UPB_MSGSET_MESSAGE = 3, -} upb_msgext_fieldnum; - +// upb_MiniTable represents the memory layout of a given upb_MessageDef. +// The members are public so generated code can initialize them, +// but users MUST NOT directly read or write any of its members. struct upb_MiniTable { - const upb_MiniTable_Sub* subs; - const upb_MiniTable_Field* fields; - /* Must be aligned to sizeof(void*). Doesn't include internal members like - * unknown fields, extension dict, pointer to msglayout, etc. */ + const upb_MiniTableSub* subs; + const upb_MiniTableField* fields; + + // Must be aligned to sizeof(void*). Doesn't include internal members like + // unknown fields, extension dict, pointer to msglayout, etc. uint16_t size; + uint16_t field_count; uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1 uint8_t dense_below; uint8_t table_mask; uint8_t required_count; // Required fields have the lowest hasbits. - /* To statically initialize the tables of variable length, we need a flexible - * array member, and we need to compile in gnu99 mode (constant initialization - * of flexible array members is a GNU extension, not in C99 unfortunately. */ - _upb_FastTable_Entry fasttable[]; -}; -struct upb_MiniTable_Extension { - upb_MiniTable_Field field; - const upb_MiniTable* extendee; - upb_MiniTable_Sub sub; /* NULL unless submessage or proto2 enum */ + // To statically initialize the tables of variable length, we need a flexible + // array member, and we need to compile in gnu99 mode (constant initialization + // of flexible array members is a GNU extension, not in C99 unfortunately. + _upb_FastTable_Entry fasttable[]; }; -typedef struct { - const upb_MiniTable** msgs; - const upb_MiniTable_Enum** enums; - const upb_MiniTable_Extension** exts; - int msg_count; - int enum_count; - int ext_count; -} upb_MiniTable_File; +#ifdef __cplusplus +extern "C" { +#endif // Computes a bitmask in which the |l->required_count| lowest bits are set, // except that we skip the lowest bit (because upb never uses hasbit 0). @@ -1764,7 +1884,22 @@ UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) { return ((1ULL << n) - 1) << 1; } -/** upb_Message ***************************************************************/ +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +extern const float kUpb_FltInfinity; +extern const double kUpb_Infinity; +extern const double kUpb_NaN; /* Internal members of a upb_Message that track unknown fields and/or * extensions. We can change this without breaking binary compatibility. We put @@ -1803,437 +1938,850 @@ typedef struct { /* Maps upb_CType -> memory size. */ extern char _upb_CTypeo_size[12]; -UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) { - return l->size + sizeof(upb_Message_Internal); +UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* t) { + return t->size + sizeof(upb_Message_Internal); +} + +// Inline version upb_Message_New(), for internal use. +UPB_INLINE upb_Message* _upb_Message_New(const upb_MiniTable* mini_table, + upb_Arena* arena) { + size_t size = upb_msg_sizeof(mini_table); + void* mem = upb_Arena_Malloc(arena, size + sizeof(upb_Message_Internal)); + if (UPB_UNLIKELY(!mem)) return NULL; + upb_Message* msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message); + memset(mem, 0, size); + return msg; +} + +UPB_INLINE upb_Message_Internal* upb_Message_Getinternal( + const upb_Message* msg) { + ptrdiff_t size = sizeof(upb_Message_Internal); + return (upb_Message_Internal*)((char*)msg - size); +} + +// Clears the given message. +void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l); + +// Discards the unknown fields for this message only. +void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); + +// Adds unknown data (serialized protobuf data) to the given message. +// The data is copied into the message instance. +bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, + upb_Arena* arena); + +/* Map entries aren't actually stored, they are only used during parsing. For + * parsing, it helps a lot if all map entry messages have the same layout. + * The compiler and def.c must ensure that all map entries have this layout. */ +typedef struct { + upb_Message_Internal internal; + union { + upb_StringView str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } k; + union { + upb_StringView str; /* For str/bytes. */ + upb_value val; /* For all other types. */ + } v; +} upb_MapEntry; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MESSAGE_INTERNAL_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// _upb_mapsorter sorts maps and provides ordered iteration over the entries. +// Since maps can be recursive (map values can be messages which contain other +// maps), _upb_mapsorter can contain a stack of maps. + +typedef struct { + upb_tabent const** entries; + int size; + int cap; +} _upb_mapsorter; + +typedef struct { + int start; + int pos; + int end; +} _upb_sortedmap; + +UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { + s->entries = NULL; + s->size = 0; + s->cap = 0; +} + +UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { + if (s->entries) free(s->entries); +} + +UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, + _upb_sortedmap* sorted, upb_MapEntry* ent) { + if (sorted->pos == sorted->end) return false; + const upb_tabent* tabent = s->entries[sorted->pos++]; + upb_StringView key = upb_tabstrview(tabent->key); + _upb_map_fromkey(key, &ent->k, map->key_size); + upb_value val = {tabent->val.val}; + _upb_map_fromvalue(val, &ent->v, map->val_size); + return true; +} + +UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, + _upb_sortedmap* sorted) { + s->size = sorted->start; +} + +bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, + const upb_Map* map, _upb_sortedmap* sorted); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ */ + +#ifndef UPB_MINI_TABLE_ENUM_INTERNAL_H_ +#define UPB_MINI_TABLE_ENUM_INTERNAL_H_ + + +// Must be last. + +struct upb_MiniTableEnum { + uint32_t mask_limit; // Limit enum value that can be tested with mask. + uint32_t value_count; // Number of values after the bitfield. + uint32_t data[]; // Bitmask + enumerated values follow. +}; + +typedef enum { + _kUpb_FastEnumCheck_ValueIsInEnum = 0, + _kUpb_FastEnumCheck_ValueIsNotInEnum = 1, + _kUpb_FastEnumCheck_CannotCheckFast = 2, +} _kUpb_FastEnumCheck_Status; + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE _kUpb_FastEnumCheck_Status +_upb_MiniTable_CheckEnumValueFast(const upb_MiniTableEnum* e, uint32_t val) { + if (UPB_UNLIKELY(val >= 64)) return _kUpb_FastEnumCheck_CannotCheckFast; + uint64_t mask = e->data[0] | ((uint64_t)e->data[1] << 32); + return (mask & (1ULL << val)) ? _kUpb_FastEnumCheck_ValueIsInEnum + : _kUpb_FastEnumCheck_ValueIsNotInEnum; +} + +UPB_INLINE bool _upb_MiniTable_CheckEnumValueSlow(const upb_MiniTableEnum* e, + uint32_t val) { + if (val < e->mask_limit) return e->data[val / 32] & (1ULL << (val % 32)); + // OPT: binary search long lists? + const uint32_t* start = &e->data[e->mask_limit / 32]; + const uint32_t* limit = &e->data[(e->mask_limit / 32) + e->value_count]; + for (const uint32_t* p = start; p < limit; p++) { + if (*p == val) return true; + } + return false; +} + +// Validates enum value against range defined by enum mini table. +UPB_INLINE bool upb_MiniTableEnum_CheckValue(const upb_MiniTableEnum* e, + uint32_t val) { + _kUpb_FastEnumCheck_Status status = _upb_MiniTable_CheckEnumValueFast(e, val); + if (UPB_UNLIKELY(status == _kUpb_FastEnumCheck_CannotCheckFast)) { + return _upb_MiniTable_CheckEnumValueSlow(e, val); + } + return status == _kUpb_FastEnumCheck_ValueIsInEnum ? true : false; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_MINI_TABLE_ENUM_INTERNAL_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_ + + +// These functions are only used by generated code. + +#ifndef UPB_COLLECTIONS_MAP_GENCODE_UTIL_H_ +#define UPB_COLLECTIONS_MAP_GENCODE_UTIL_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// Message map operations, these get the map from the message first. + +UPB_INLINE size_t _upb_msg_map_size(const upb_Message* msg, size_t ofs) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + return map ? _upb_Map_Size(map) : 0; +} + +UPB_INLINE bool _upb_msg_map_get(const upb_Message* msg, size_t ofs, + const void* key, size_t key_size, void* val, + size_t val_size) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return false; + return _upb_Map_Get(map, key, key_size, val, val_size); +} + +UPB_INLINE void* _upb_msg_map_next(const upb_Message* msg, size_t ofs, + size_t* iter) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return NULL; + return _upb_map_next(map, iter); +} + +UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, + size_t key_size, void* val, size_t val_size, + upb_Arena* arena) { + upb_Map** map = UPB_PTR_AT(msg, ofs, upb_Map*); + if (!*map) { + *map = _upb_Map_New(arena, key_size, val_size); + } + 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, + const void* key, size_t key_size) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return false; + return _upb_Map_Delete(map, key, key_size); +} + +UPB_INLINE void _upb_msg_map_clear(upb_Message* msg, size_t ofs) { + upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); + if (!map) return; + _upb_Map_Clear(map); +} + +UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { + const upb_tabent* ent = (const upb_tabent*)msg; + uint32_t u32len; + upb_StringView k; + k.data = upb_tabstr(ent->key, &u32len); + k.size = u32len; + _upb_map_fromkey(k, key, size); } -/* Inline version upb_Message_New(), for internal use */ -UPB_INLINE upb_Message* _upb_Message_New(const upb_MiniTable* mini_table, - upb_Arena* arena) { - size_t size = upb_msg_sizeof(mini_table); - void* mem = upb_Arena_Malloc(arena, size + sizeof(upb_Message_Internal)); - if (UPB_UNLIKELY(!mem)) return NULL; - upb_Message* msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message); - memset(mem, 0, size); - return msg; +UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { + const upb_tabent* ent = (const upb_tabent*)msg; + upb_value v = {ent->val.val}; + _upb_map_fromvalue(v, val, size); } -UPB_INLINE upb_Message_Internal* upb_Message_Getinternal(upb_Message* msg) { - ptrdiff_t size = sizeof(upb_Message_Internal); - return (upb_Message_Internal*)((char*)msg - size); +UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, + size_t size) { + upb_tabent* ent = (upb_tabent*)msg; + // This is like _upb_map_tovalue() except the entry already exists + // so we can reuse the allocated upb_StringView for string fields. + if (size == UPB_MAPTYPE_STRING) { + upb_StringView* strp = (upb_StringView*)(uintptr_t)ent->val.val; + memcpy(strp, val, sizeof(*strp)); + } else { + memcpy(&ent->val.val, val, size); + } } -/* Clears the given message. */ -void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l); +#ifdef __cplusplus +} /* extern "C" */ +#endif -/* Discards the unknown fields for this message only. */ -void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ -bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, - upb_Arena* arena); +#endif /* UPB_COLLECTIONS_MAP_GENCODE_UTIL_H_ */ -/** upb_Message_Extension *****************************************************/ +#ifndef UPB_MESSAGE_ACCESSORS_H_ +#define UPB_MESSAGE_ACCESSORS_H_ -/* The internal representation of an extension is self-describing: it contains - * enough information that we can serialize it to binary format without needing - * to look it up in a upb_ExtensionRegistry. - * - * This representation allocates 16 bytes to data on 64-bit platforms. This is - * rather wasteful for scalars (in the extreme case of bool, it wastes 15 - * bytes). We accept this because we expect messages to be the most common - * extension type. */ -typedef struct { - const upb_MiniTable_Extension* ext; - union { - upb_StringView str; - void* ptr; - char scalar_data[8]; - } data; -} upb_Message_Extension; -/* 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_GetOrCreateExtension( - upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena); +#ifndef UPB_MINI_TABLE_COMMON_H_ +#define UPB_MINI_TABLE_COMMON_H_ -/* Returns an array of extensions for this message. Note: the array is - * ordered in reverse relative to the order of creation. */ -const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg, - size_t* count); -/* Returns an extension for the given field number, or NULL if no extension - * exists for this field number. */ -const upb_Message_Extension* _upb_Message_Getext( - const upb_Message* msg, const upb_MiniTable_Extension* ext); +// Must be last. -void _upb_Message_Clearext(upb_Message* msg, - const upb_MiniTable_Extension* ext); +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; -/** Hasbit access *************************************************************/ +typedef enum { + kUpb_MessageModifier_ValidateUtf8 = 1 << 0, + kUpb_MessageModifier_DefaultIsPacked = 1 << 1, + kUpb_MessageModifier_IsExtendable = 1 << 2, +} kUpb_MessageModifier; -UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) { - return (*UPB_PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) { - (*UPB_PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); -} +const upb_MiniTableField* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number); -UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) { - (*UPB_PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); -} +upb_FieldType upb_MiniTableField_Type(const upb_MiniTableField* field); -UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTable_Field* f) { - UPB_ASSERT(f->presence > 0); - return f->presence; +UPB_INLINE bool upb_MiniTableField_IsExtension( + const upb_MiniTableField* field) { + return field->mode & kUpb_LabelFlags_IsExtension; } -UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_hasbit(msg, _upb_Message_Hasidx(f)); +UPB_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* mini_table, const upb_MiniTableField* field) { + return mini_table->subs[field->submsg_index].submsg; } -UPB_INLINE void _upb_sethas_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - _upb_sethas(msg, _upb_Message_Hasidx(f)); +UPB_INLINE const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable( + const upb_MiniTable* mini_table, const upb_MiniTableField* field) { + return mini_table->subs[field->submsg_index].subenum; } -UPB_INLINE void _upb_clearhas_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - _upb_clearhas(msg, _upb_Message_Hasidx(f)); -} +#ifdef __cplusplus +} /* extern "C" */ +#endif -/** Oneof case access *********************************************************/ -UPB_INLINE uint32_t* _upb_oneofcase(upb_Message* msg, size_t case_ofs) { - return UPB_PTR_AT(msg, case_ofs, uint32_t); -} +#endif /* UPB_MINI_TABLE_COMMON_H_ */ -UPB_INLINE uint32_t _upb_getoneofcase(const void* msg, size_t case_ofs) { - return *UPB_PTR_AT(msg, case_ofs, uint32_t); -} +// Must be last. -UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTable_Field* f) { - UPB_ASSERT(f->presence < 0); - return ~(ptrdiff_t)f->presence; -} +#ifdef __cplusplus +extern "C" { +#endif -UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_oneofcase(msg, _upb_oneofcase_ofs(f)); +UPB_INLINE bool _upb_MiniTableField_InOneOf(const upb_MiniTableField* field) { + return field->presence < 0; } -UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg, - const upb_MiniTable_Field* f) { - return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f)); +UPB_INLINE void* _upb_MiniTableField_GetPtr(upb_Message* msg, + const upb_MiniTableField* field) { + return (char*)msg + field->offset; } -UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_Message* msg, size_t ofs) { - return *UPB_PTR_AT(msg, ofs, const upb_Message*) != NULL; +UPB_INLINE const void* _upb_MiniTableField_GetConstPtr( + const upb_Message* msg, const upb_MiniTableField* field) { + return (char*)msg + field->offset; } -/** upb_Map *******************************************************************/ - -/* Right now we use strmaps for everything. We'll likely want to use - * integer-specific maps for integer-keyed maps.*/ -struct upb_Map { - /* Size of key and val, based on the map type. Strings are represented as '0' - * because they must be handled specially. */ - char key_size; - char val_size; - - upb_strtable table; -}; - -/* Map entries aren't actually stored, they are only used during parsing. For - * parsing, it helps a lot if all map entry messages have the same layout. - * The compiler and def.c must ensure that all map entries have this layout. */ -typedef struct { - upb_Message_Internal internal; - union { - upb_StringView str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } k; - union { - upb_StringView str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } v; -} upb_MapEntry; - -/* Creates a new map on the given arena with this key/value type. */ -upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size); - -/* Converting between internal table representation and user values. - * - * _upb_map_tokey() and _upb_map_fromkey() are inverses. - * _upb_map_tovalue() and _upb_map_fromvalue() are inverses. - * - * These functions account for the fact that strings are treated differently - * from other types when stored in a map. - */ - -UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - return *(upb_StringView*)key; - } else { - return upb_StringView_FromDataAndSize((const char*)key, size); +UPB_INLINE void _upb_MiniTable_SetPresence(upb_Message* msg, + const upb_MiniTableField* field) { + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (_upb_MiniTableField_InOneOf(field)) { + *_upb_oneofcase_field(msg, field) = field->number; } } -UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - memcpy(out, &key, sizeof(key)); - } else { - memcpy(out, key.data, size); +UPB_INLINE bool upb_MiniTable_HasField(const upb_Message* msg, + const upb_MiniTableField* field); + +UPB_INLINE bool _upb_MiniTable_DefaultIsNonZero( + const void* default_val, const upb_MiniTableField* field) { + char zero[16] = {0}; + switch (_upb_MiniTableField_GetRep(field)) { + case kUpb_FieldRep_1Byte: + return memcmp(&zero, default_val, 1) != 0; + case kUpb_FieldRep_4Byte: + return memcmp(&zero, default_val, 4) != 0; + case kUpb_FieldRep_8Byte: + return memcmp(&zero, default_val, 8) != 0; + case kUpb_FieldRep_StringView: { + const upb_StringView* sv = (const upb_StringView*)default_val; + return sv->size != 0; + } } + UPB_UNREACHABLE(); } -UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size, - upb_value* msgval, upb_Arena* a) { - if (size == UPB_MAPTYPE_STRING) { - upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp)); - if (!strp) return false; - *strp = *(upb_StringView*)val; - *msgval = upb_value_ptr(strp); - } else { - memcpy(msgval, val, size); +UPB_INLINE void _upb_MiniTable_CopyFieldData(void* to, const void* from, + const upb_MiniTableField* field) { + switch (_upb_MiniTableField_GetRep(field)) { + case kUpb_FieldRep_1Byte: + memcpy(to, from, 1); + return; + case kUpb_FieldRep_4Byte: + memcpy(to, from, 4); + return; + case kUpb_FieldRep_8Byte: + memcpy(to, from, 8); + return; + case kUpb_FieldRep_StringView: { + memcpy(to, from, sizeof(upb_StringView)); + return; + } } - return true; + UPB_UNREACHABLE(); } -UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val); - memcpy(out, strp, sizeof(upb_StringView)); - } else { - memcpy(out, &val, size); +// Here we define universal getter/setter functions for message fields. +// These look very branchy and inefficient, but as long as the MiniTableField +// values are known at compile time, all the branches are optimized away and +// we are left with ideal code. This can happen either through through +// literals or UPB_ASSUME(): +// +// // Via string literals. +// bool FooMessage_set_bool_field(const upb_Message* msg, bool val) { +// const upb_MiniTableField field = {1, 0, 0, /* etc... */}; +// // All value in "field" are compile-time known. +// _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +// } +// +// // Via UPB_ASSUME(). +// UPB_INLINE void upb_MiniTable_SetBool(upb_Message* msg, +// const upb_MiniTableField* field, +// bool value) { +// UPB_ASSUME(field->descriptortype == kUpb_FieldType_Bool); +// UPB_ASSUME(!upb_IsRepeatedOrMap(field)); +// UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte); +// _upb_MiniTable_SetNonExtensionField(msg, field, &value); +// } +// +// As a result, we can use these universal getters/setters for *all* message +// accessors: generated code, MiniTable accessors, and reflection. The only +// exception is the binary encoder/decoder, which need to be a bit more clever +// about how the read/write the message data, for efficiency. + +static UPB_FORCEINLINE void _upb_MiniTable_GetNonExtensionField( + const upb_Message* msg, const upb_MiniTableField* field, + const void* default_val, void* val) { + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + if ((_upb_MiniTableField_InOneOf(field) || + _upb_MiniTable_DefaultIsNonZero(default_val, field)) && + !upb_MiniTable_HasField(msg, field)) { + _upb_MiniTable_CopyFieldData(val, default_val, field); + return; } + _upb_MiniTable_CopyFieldData(val, _upb_MiniTableField_GetConstPtr(msg, field), + field); } -/* Map operations, shared by reflection and generated code. */ - -UPB_INLINE size_t _upb_Map_Size(const upb_Map* map) { - return map->table.t.count; +UPB_INLINE void _upb_MiniTable_GetExtensionField( + const upb_Message* msg, const upb_MiniTableExtension* mt_ext, + const void* default_val, void* val) { + UPB_ASSUME(upb_MiniTableField_IsExtension(&mt_ext->field)); + const upb_Message_Extension* ext = _upb_Message_Getext(msg, mt_ext); + if (ext) { + _upb_MiniTable_CopyFieldData(val, &ext->data, &mt_ext->field); + } else { + _upb_MiniTable_CopyFieldData(val, default_val, &mt_ext->field); + } } -UPB_INLINE bool _upb_Map_Get(const upb_Map* map, const void* key, - size_t key_size, void* val, size_t val_size) { - upb_value tabval; - upb_StringView k = _upb_map_tokey(key, key_size); - bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); - if (ret && val) { - _upb_map_fromvalue(tabval, val, val_size); +UPB_INLINE void _upb_MiniTable_GetField(const upb_Message* msg, + const upb_MiniTableField* field, + const void* default_val, void* val) { + if (upb_MiniTableField_IsExtension(field)) { + _upb_MiniTable_GetExtensionField(msg, (upb_MiniTableExtension*)field, + default_val, val); + } else { + _upb_MiniTable_GetNonExtensionField(msg, field, default_val, val); } - return ret; } -UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { - upb_strtable_iter it; - it.t = &map->table; - it.index = *iter; - upb_strtable_next(&it); - *iter = it.index; - if (upb_strtable_done(&it)) return NULL; - return (void*)str_tabent(&it); +UPB_INLINE void _upb_MiniTable_SetNonExtensionField( + upb_Message* msg, const upb_MiniTableField* field, const void* val) { + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + _upb_MiniTable_SetPresence(msg, field); + _upb_MiniTable_CopyFieldData(_upb_MiniTableField_GetPtr(msg, field), val, + field); } -typedef enum { - // LINT.IfChange - _kUpb_MapInsertStatus_Inserted = 0, - _kUpb_MapInsertStatus_Replaced = 1, - _kUpb_MapInsertStatus_OutOfMemory = 2, - // LINT.ThenChange(//depot/google3/third_party/upb/upb/map.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 _kUpb_MapInsertStatus_OutOfMemory; - } +UPB_INLINE bool _upb_MiniTable_SetExtensionField( + upb_Message* msg, const upb_MiniTableExtension* mt_ext, const void* val, + upb_Arena* a) { + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, mt_ext, a); + if (!ext) return false; + _upb_MiniTable_CopyFieldData(&ext->data, val, &mt_ext->field); + return true; +} - /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - 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; +UPB_INLINE bool _upb_MiniTable_SetField(upb_Message* msg, + const upb_MiniTableField* field, + const void* val, upb_Arena* a) { + if (upb_MiniTableField_IsExtension(field)) { + return _upb_MiniTable_SetExtensionField( + msg, (const upb_MiniTableExtension*)field, val, a); + } else { + _upb_MiniTable_SetNonExtensionField(msg, field, val); + return true; } - return removed ? _kUpb_MapInsertStatus_Replaced - : _kUpb_MapInsertStatus_Inserted; } -UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, - size_t key_size) { - upb_StringView k = _upb_map_tokey(key, key_size); - return upb_strtable_remove2(&map->table, k.data, k.size, NULL); -} +// EVERYTHING ABOVE THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// -UPB_INLINE void _upb_Map_Clear(upb_Map* map) { - upb_strtable_clear(&map->table); -} +void upb_MiniTable_ClearField(upb_Message* msg, + const upb_MiniTableField* field); -/* Message map operations, these get the map from the message first. */ +UPB_INLINE bool upb_MiniTable_HasField(const upb_Message* msg, + const upb_MiniTableField* field) { + if (_upb_MiniTableField_InOneOf(field)) { + return _upb_getoneofcase_field(msg, field) == field->number; + } -UPB_INLINE size_t _upb_msg_map_size(const upb_Message* msg, size_t ofs) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - return map ? _upb_Map_Size(map) : 0; + UPB_ASSERT(field->presence > 0); + return _upb_hasbit_field(msg, field); } -UPB_INLINE bool _upb_msg_map_get(const upb_Message* msg, size_t ofs, - const void* key, size_t key_size, void* val, - size_t val_size) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return false; - return _upb_Map_Get(map, key, key_size, val, val_size); +UPB_INLINE bool upb_MiniTable_GetBool(const upb_Message* msg, + const upb_MiniTableField* field, + bool default_val) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_Bool); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte); + bool ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; } -UPB_INLINE void* _upb_msg_map_next(const upb_Message* msg, size_t ofs, - size_t* iter) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return NULL; - return _upb_map_next(map, iter); +UPB_INLINE void upb_MiniTable_SetBool(upb_Message* msg, + const upb_MiniTableField* field, + bool value) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_Bool); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE int32_t upb_MiniTable_GetInt32(const upb_Message* msg, + const upb_MiniTableField* field, + int32_t default_val) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_Int32 || + field->descriptortype == kUpb_FieldType_SInt32 || + field->descriptortype == kUpb_FieldType_SFixed32 || + field->descriptortype == kUpb_FieldType_Enum); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + int32_t ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; } -UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, - size_t key_size, void* val, size_t val_size, - upb_Arena* arena) { - upb_Map** map = UPB_PTR_AT(msg, ofs, upb_Map*); - if (!*map) { - *map = _upb_Map_New(arena, key_size, val_size); - } - return _upb_Map_Insert(*map, key, key_size, val, val_size, arena) != - _kUpb_MapInsertStatus_OutOfMemory; +UPB_INLINE void upb_MiniTable_SetInt32(upb_Message* msg, + const upb_MiniTableField* field, + int32_t value) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_Int32 || + field->descriptortype == kUpb_FieldType_SInt32 || + field->descriptortype == kUpb_FieldType_SFixed32); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE uint32_t upb_MiniTable_GetUInt32(const upb_Message* msg, + const upb_MiniTableField* field, + uint32_t default_val) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_UInt32 || + field->descriptortype == kUpb_FieldType_Fixed32); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + uint32_t ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; } -UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs, - const void* key, size_t key_size) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return false; - return _upb_Map_Delete(map, key, key_size); +UPB_INLINE void upb_MiniTable_SetUInt32(upb_Message* msg, + const upb_MiniTableField* field, + uint32_t value) { + UPB_ASSUME(field->descriptortype == kUpb_FieldType_UInt32 || + field->descriptortype == kUpb_FieldType_Fixed32); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE void upb_MiniTable_SetEnumProto2(upb_Message* msg, + const upb_MiniTable* msg_mini_table, + const upb_MiniTableField* field, + int32_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + UPB_ASSERT(upb_MiniTableEnum_CheckValue( + upb_MiniTable_GetSubEnumTable(msg_mini_table, field), value)); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE int64_t upb_MiniTable_GetInt64(const upb_Message* msg, + const upb_MiniTableField* field, + uint64_t default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int64 || + field->descriptortype == kUpb_FieldType_SInt64 || + field->descriptortype == kUpb_FieldType_SFixed64); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + int64_t ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; } -UPB_INLINE void _upb_msg_map_clear(upb_Message* msg, size_t ofs) { - upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*); - if (!map) return; - _upb_Map_Clear(map); +UPB_INLINE void upb_MiniTable_SetInt64(upb_Message* msg, + const upb_MiniTableField* field, + int64_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int64 || + field->descriptortype == kUpb_FieldType_SInt64 || + field->descriptortype == kUpb_FieldType_SFixed64); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE uint64_t upb_MiniTable_GetUInt64(const upb_Message* msg, + const upb_MiniTableField* field, + uint64_t default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt64 || + field->descriptortype == kUpb_FieldType_Fixed64); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + uint64_t ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; } -/* Accessing map key/value from a pointer, used by generated code only. */ - -UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { - const upb_tabent* ent = (const upb_tabent*)msg; - uint32_t u32len; - upb_StringView k; - k.data = upb_tabstr(ent->key, &u32len); - k.size = u32len; - _upb_map_fromkey(k, key, size); +UPB_INLINE void upb_MiniTable_SetUInt64(upb_Message* msg, + const upb_MiniTableField* field, + uint64_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt64 || + field->descriptortype == kUpb_FieldType_Fixed64); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE float upb_MiniTable_GetFloat(const upb_Message* msg, + const upb_MiniTableField* field, + float default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Float); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + float ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; } -UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { - const upb_tabent* ent = (const upb_tabent*)msg; - upb_value v = {ent->val.val}; - _upb_map_fromvalue(v, val, size); +UPB_INLINE void upb_MiniTable_SetFloat(upb_Message* msg, + const upb_MiniTableField* field, + float value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Float); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); } -UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, - size_t size) { - upb_tabent* ent = (upb_tabent*)msg; - /* This is like _upb_map_tovalue() except the entry already exists so we can - * reuse the allocated upb_StringView for string fields. */ - if (size == UPB_MAPTYPE_STRING) { - upb_StringView* strp = (upb_StringView*)(uintptr_t)ent->val.val; - memcpy(strp, val, sizeof(*strp)); - } else { - memcpy(&ent->val.val, val, size); - } +UPB_INLINE double upb_MiniTable_GetDouble(const upb_Message* msg, + const upb_MiniTableField* field, + double default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Double); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + double ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; } -#ifdef __cplusplus -} /* extern "C" */ -#endif +UPB_INLINE void upb_MiniTable_SetDouble(upb_Message* msg, + const upb_MiniTableField* field, + double value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Double); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} +UPB_INLINE upb_StringView +upb_MiniTable_GetString(const upb_Message* msg, const upb_MiniTableField* field, + upb_StringView def_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bytes || + field->descriptortype == kUpb_FieldType_String); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_StringView); + upb_StringView ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &def_val, &ret); + return ret; +} -#endif /* UPB_MSG_INT_H_ */ +UPB_INLINE void upb_MiniTable_SetString(upb_Message* msg, + const upb_MiniTableField* field, + upb_StringView value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bytes || + field->descriptortype == kUpb_FieldType_String); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_StringView); + _upb_MiniTable_SetNonExtensionField(msg, field, &value); +} + +UPB_INLINE const upb_Message* upb_MiniTable_GetMessage( + const upb_Message* msg, const upb_MiniTableField* field, + upb_Message* default_val) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + upb_Message* ret; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} -// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// +UPB_INLINE void upb_MiniTable_SetMessage(upb_Message* msg, + const upb_MiniTable* mini_table, + const upb_MiniTableField* field, + upb_Message* sub_message) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + UPB_ASSUME(!upb_IsRepeatedOrMap(field)); + UPB_ASSUME(_upb_MiniTableField_GetRep(field) == + UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)); + UPB_ASSERT(mini_table->subs[field->submsg_index].submsg); + _upb_MiniTable_SetNonExtensionField(msg, field, &sub_message); +} + +UPB_INLINE upb_Message* upb_MiniTable_GetMutableMessage( + upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTableField* field, upb_Arena* arena) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group); + upb_Message* sub_message = *UPB_PTR_AT(msg, field->offset, upb_Message*); + if (!sub_message) { + const upb_MiniTable* sub_mini_table = + mini_table->subs[field->submsg_index].submsg; + UPB_ASSERT(sub_mini_table); + sub_message = _upb_Message_New(sub_mini_table, arena); + *UPB_PTR_AT(msg, field->offset, upb_Message*) = sub_message; + _upb_MiniTable_SetPresence(msg, field); + } + return sub_message; +} -#ifndef UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ -#define UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ +UPB_INLINE const upb_Array* upb_MiniTable_GetArray( + const upb_Message* msg, const upb_MiniTableField* field) { + const upb_Array* ret; + const upb_Array* default_val = NULL; + _upb_MiniTable_GetNonExtensionField(msg, field, &default_val, &ret); + return ret; +} +UPB_INLINE upb_Array* upb_MiniTable_GetMutableArray( + upb_Message* msg, const upb_MiniTableField* field) { + return (upb_Array*)upb_MiniTable_GetArray(msg, field); +} -// Must be last. +void* upb_MiniTable_ResizeArray(upb_Message* msg, + const upb_MiniTableField* field, size_t len, + upb_Arena* arena); +typedef enum { + kUpb_GetExtension_Ok, + kUpb_GetExtension_NotPresent, + kUpb_GetExtension_ParseError, + kUpb_GetExtension_OutOfMemory, +} upb_GetExtension_Status; -#ifdef __cplusplus -extern "C" { -#endif +typedef enum { + kUpb_GetExtensionAsBytes_Ok, + kUpb_GetExtensionAsBytes_NotPresent, + kUpb_GetExtensionAsBytes_EncodeError, +} upb_GetExtensionAsBytes_Status; -// _upb_mapsorter sorts maps and provides ordered iteration over the entries. -// Since maps can be recursive (map values can be messages which contain other -// maps), _upb_mapsorter can contain a stack of maps. +// Returns a message extension or promotes an unknown field to +// an extension. +// +// TODO(ferhat): Only supports extension fields that are messages, +// expand support to include non-message types. +upb_GetExtension_Status upb_MiniTable_GetOrPromoteExtension( + upb_Message* msg, const upb_MiniTableExtension* ext_table, + int decode_options, upb_Arena* arena, + const upb_Message_Extension** extension); + +// Returns a message extension or unknown field matching the extension +// data as bytes. +// +// If an extension has already been decoded it will be re-encoded +// to bytes. +upb_GetExtensionAsBytes_Status upb_MiniTable_GetExtensionAsBytes( + const upb_Message* msg, const upb_MiniTableExtension* ext_table, + int encode_options, upb_Arena* arena, const char** extension_data, + size_t* len); -typedef struct { - upb_tabent const** entries; - int size; - int cap; -} _upb_mapsorter; +typedef enum { + kUpb_FindUnknown_Ok, + kUpb_FindUnknown_NotPresent, + kUpb_FindUnknown_ParseError, +} upb_FindUnknown_Status; typedef struct { - int start; - int pos; - int end; -} _upb_sortedmap; - -UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) { - s->entries = NULL; - s->size = 0; - s->cap = 0; -} + upb_FindUnknown_Status status; + // Start of unknown field data in message arena. + const char* ptr; + // Size of unknown field data. + size_t len; +} upb_FindUnknownRet; -UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) { - if (s->entries) free(s->entries); -} +// Finds first occurrence of unknown data by tag id in message. +upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg, + uint32_t field_number); -UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map, - _upb_sortedmap* sorted, upb_MapEntry* ent) { - if (sorted->pos == sorted->end) return false; - const upb_tabent* tabent = s->entries[sorted->pos++]; - upb_StringView key = upb_tabstrview(tabent->key); - _upb_map_fromkey(key, &ent->k, map->key_size); - upb_value val = {tabent->val.val}; - _upb_map_fromvalue(val, &ent->v, map->val_size); - return true; -} +typedef enum { + kUpb_UnknownToMessage_Ok, + kUpb_UnknownToMessage_ParseError, + kUpb_UnknownToMessage_OutOfMemory, + kUpb_UnknownToMessage_NotFound, +} upb_UnknownToMessage_Status; -UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s, - _upb_sortedmap* sorted) { - s->size = sorted->start; -} +typedef struct { + upb_UnknownToMessage_Status status; + upb_Message* message; +} upb_UnknownToMessageRet; -bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, - const upb_Map* map, _upb_sortedmap* sorted); +// Promotes unknown data inside message to a upb_Message parsing the unknown. +// +// The unknown data is removed from message after field value is set +// using upb_MiniTable_SetMessage. +upb_UnknownToMessageRet upb_MiniTable_PromoteUnknownToMessage( + upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTableField* field, const upb_MiniTable* sub_mini_table, + int decode_options, upb_Arena* arena); + +// Promotes all unknown data that matches field tag id to repeated messages +// in upb_Array. +// +// The unknown data is removed from message after upb_Array is populated. +// Since repeated messages can't be packed we remove each unknown that +// contains the target tag id. +upb_UnknownToMessage_Status upb_MiniTable_PromoteUnknownToMessageArray( + upb_Message* msg, const upb_MiniTableField* field, + const upb_MiniTable* mini_table, int decode_options, upb_Arena* arena); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_COLLECTIONS_MAP_SORTER_INTERNAL_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_ - +#endif // UPB_MESSAGE_ACCESSORS_H_ // upb_decode: parsing into a upb_Message using a upb_MiniTable. @@ -2436,9 +2984,7 @@ TAGBYTES(r) #endif /* UPB_WIRE_DECODE_FAST_H_ */ -/* - * upb_Encode: parsing from a upb_Message using a upb_MiniTable. - */ +// upb_Encode: parsing from a upb_Message using a upb_MiniTable. #ifndef UPB_WIRE_ENCODE_H_ #define UPB_WIRE_ENCODE_H_ @@ -2606,13 +3152,13 @@ typedef enum { } google_protobuf_MethodOptions_IdempotencyLevel; -extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enum_init; -extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enum_init; -extern const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enum_init; -extern const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enum_init; -extern const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enum_init; -extern const upb_MiniTable_Enum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init; -extern const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enum_init; +extern const upb_MiniTableEnum google_protobuf_FieldDescriptorProto_Label_enum_init; +extern const upb_MiniTableEnum google_protobuf_FieldDescriptorProto_Type_enum_init; +extern const upb_MiniTableEnum google_protobuf_FieldOptions_CType_enum_init; +extern const upb_MiniTableEnum google_protobuf_FieldOptions_JSType_enum_init; +extern const upb_MiniTableEnum google_protobuf_FileOptions_OptimizeMode_enum_init; +extern const upb_MiniTableEnum google_protobuf_GeneratedCodeInfo_Annotation_Semantic_enum_init; +extern const upb_MiniTableEnum google_protobuf_MethodOptions_IdempotencyLevel_enum_init; /* google.protobuf.FileDescriptorSet */ @@ -2650,24 +3196,24 @@ UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_pro return ptr; } UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_FileDescriptorSet_clear_file(const google_protobuf_FileDescriptorSet* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_FileDescriptorProto**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -2715,7 +3261,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_name(const google_prot _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(40, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 2); @@ -2725,7 +3275,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_package(const google_p _upb_clearhas(msg, 2); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(48, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(48, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_FileDescriptorProto_clear_dependency(const google_protobuf_FileDescriptorProto* msg) { _upb_array_detach(msg, UPB_SIZE(4, 40)); @@ -2777,7 +3331,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_options(const google_p _upb_clearhas(msg, 3); } UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 80), const google_protobuf_FileOptions*); + const google_protobuf_FileOptions* default_val = NULL; + const google_protobuf_FileOptions* ret; + const upb_MiniTableField field = {8, UPB_SIZE(24, 80), 3, 4, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 4); @@ -2787,7 +3345,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_source_code_info(const _upb_clearhas(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(28, 88), const google_protobuf_SourceCodeInfo*); + const google_protobuf_SourceCodeInfo* default_val = NULL; + const google_protobuf_SourceCodeInfo* ret; + const upb_MiniTableField field = {9, UPB_SIZE(28, 88), 4, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_FileDescriptorProto_clear_public_dependency(const google_protobuf_FileDescriptorProto* msg) { _upb_array_detach(msg, UPB_SIZE(32, 96)); @@ -2809,7 +3371,11 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_syntax(const google_pr _upb_clearhas(msg, 5); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(56, 112), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {12, UPB_SIZE(56, 112), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileDescriptorProto_has_edition(const google_protobuf_FileDescriptorProto* msg) { return _upb_hasbit(msg, 6); @@ -2819,18 +3385,20 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_clear_edition(const google_p _upb_clearhas(msg, 6); } UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_edition(const google_protobuf_FileDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {13, UPB_SIZE(64, 128), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(40, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(48, 24), upb_StringView) = value; -} -UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { + const upb_MiniTableField field = {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(48, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(4, 40), len); } UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { @@ -2888,28 +3456,24 @@ UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDesc 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(24, 80), google_protobuf_FileOptions*) = value; -} -UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {8, UPB_SIZE(24, 80), 3, 4, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_FileDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_FileDescriptorProto_set_options(msg, sub); } return sub; } 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(28, 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) { + const upb_MiniTableField field = {9, UPB_SIZE(28, 88), 4, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msg_init, arena); - if (!sub) return NULL; - google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); + if (sub) google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); } return sub; } @@ -2932,14 +3496,12 @@ UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_p return _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 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(56, 112), upb_StringView) = value; + const upb_MiniTableField field = {12, UPB_SIZE(56, 112), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileDescriptorProto_set_edition(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {13, UPB_SIZE(64, 128), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } -UPB_INLINE void google_protobuf_FileDescriptorProto_set_edition(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(64, 128), upb_StringView) = value; -} - /* google.protobuf.DescriptorProto */ UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_new(upb_Arena* arena) { @@ -2983,7 +3545,11 @@ UPB_INLINE void google_protobuf_DescriptorProto_clear_name(const google_protobuf _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(40, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 24)); @@ -3038,7 +3604,11 @@ UPB_INLINE void google_protobuf_DescriptorProto_clear_options(const google_proto _upb_clearhas(msg, 2); } UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 64), const google_protobuf_MessageOptions*); + const google_protobuf_MessageOptions* default_val = NULL; + const google_protobuf_MessageOptions* ret; + const upb_MiniTableField field = {7, UPB_SIZE(24, 64), 2, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 72)); @@ -3066,10 +3636,9 @@ UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(c } 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(40, 8), upb_StringView) = value; -} -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto* msg, size_t* len) { + const upb_MiniTableField field = {1, UPB_SIZE(40, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(4, 24), len); } UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { @@ -3130,15 +3699,13 @@ UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_Descript 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(24, 64), google_protobuf_MessageOptions*) = value; -} -UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {7, UPB_SIZE(24, 64), 2, 5, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_DescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_DescriptorProto_set_options(msg, sub); } return sub; } @@ -3215,21 +3782,29 @@ UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const g 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return _upb_hasbit(msg, 3); @@ -3239,27 +3814,27 @@ UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_clear_options(con _upb_clearhas(msg, 3); } 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*); + const google_protobuf_ExtensionRangeOptions* default_val = NULL; + const google_protobuf_ExtensionRangeOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_start(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_end(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(google_protobuf_DescriptorProto_ExtensionRange *msg, google_protobuf_ExtensionRangeOptions* value) { - _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) { + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_end(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(google_protobuf_DescriptorProto_ExtensionRange *msg, google_protobuf_ExtensionRangeOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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_msg_init, arena); - if (!sub) return NULL; - google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); + if (sub) google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); } return sub; } @@ -3303,32 +3878,38 @@ UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const go 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_start(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } - /* google.protobuf.ExtensionRangeOptions */ UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_new(upb_Arena* arena) { @@ -3365,24 +3946,24 @@ UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google return ptr; } UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_ExtensionRangeOptions_clear_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3430,7 +4011,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_name(const google_pro _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(28, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(28, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 2); @@ -3440,37 +4025,53 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_extendee(const google _upb_clearhas(msg, 2); } UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(36, 40), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(36, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(4, 4), int32_t); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {3, 4, 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(8, 8), int32_t) : 1; + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {4, 8, 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(12, 12), int32_t) : 1; + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {5, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 6); @@ -3480,7 +4081,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_type_name(const googl _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(44, 56), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {6, UPB_SIZE(44, 56), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 7); @@ -3490,7 +4095,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_default_value(const g _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(52, 72), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {7, UPB_SIZE(52, 72), 7, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 8); @@ -3500,7 +4109,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_options(const google_ _upb_clearhas(msg, 8); } UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 88), const google_protobuf_FieldOptions*); + const google_protobuf_FieldOptions* default_val = NULL; + const google_protobuf_FieldOptions* ret; + const upb_MiniTableField field = {8, UPB_SIZE(16, 88), 8, 2, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 9); @@ -3510,7 +4123,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_oneof_index(const goo _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(20, 16), int32_t); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {9, UPB_SIZE(20, 16), 9, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 10); @@ -3520,7 +4137,11 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_json_name(const googl _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(60, 96), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {10, UPB_SIZE(60, 96), 10, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { return _upb_hasbit(msg, 11); @@ -3530,63 +4151,55 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_clear_proto3_optional(const _upb_clearhas(msg, 11); } UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(24, 20), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {17, UPB_SIZE(24, 20), 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(28, 24), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(36, 40), upb_StringView) = value; -} -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(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(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(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); - *UPB_PTR_AT(msg, UPB_SIZE(44, 56), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(52, 72), upb_StringView) = value; -} -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(16, 88), google_protobuf_FieldOptions*) = value; -} -UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(28, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(36, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {3, 4, 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {4, 8, 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {5, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {6, UPB_SIZE(44, 56), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {7, UPB_SIZE(52, 72), 7, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) { + const upb_MiniTableField field = {8, UPB_SIZE(16, 88), 8, 2, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_FieldDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_FieldDescriptorProto_set_options(msg, sub); } return sub; } UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_protobuf_FieldDescriptorProto *msg, int32_t value) { - _upb_sethas(msg, 9); - *UPB_PTR_AT(msg, UPB_SIZE(20, 16), int32_t) = value; -} -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(60, 96), upb_StringView) = value; + const upb_MiniTableField field = {9, UPB_SIZE(20, 16), 9, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {10, UPB_SIZE(60, 96), 10, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { + const upb_MiniTableField field = {17, UPB_SIZE(24, 20), 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { - _upb_sethas(msg, 11); - *UPB_PTR_AT(msg, UPB_SIZE(24, 20), bool) = value; -} - /* google.protobuf.OneofDescriptorProto */ UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_new(upb_Arena* arena) { @@ -3626,11 +4239,15 @@ UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_proto return _upb_hasbit(msg, 1); } UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_name(const google_protobuf_OneofDescriptorProto* msg) { - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + *UPB_PTR_AT(msg, 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(8, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, 8, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto* msg) { return _upb_hasbit(msg, 2); @@ -3640,23 +4257,24 @@ UPB_INLINE void google_protobuf_OneofDescriptorProto_clear_options(const google_ _upb_clearhas(msg, 2); } UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 24), const google_protobuf_OneofOptions*); + const google_protobuf_OneofOptions* default_val = NULL; + const google_protobuf_OneofOptions* ret; + const upb_MiniTableField field = {2, UPB_SIZE(4, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto *msg, google_protobuf_OneofOptions* value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(4, 24), google_protobuf_OneofOptions*) = value; -} -UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {1, 8, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto *msg, google_protobuf_OneofOptions* value) { + const upb_MiniTableField field = {2, UPB_SIZE(4, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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_msg_init, arena); - if (!sub) return NULL; - google_protobuf_OneofDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_OneofDescriptorProto_set_options(msg, sub); } return sub; } @@ -3704,7 +4322,11 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_name(const google_prot _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(20, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(20, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 24)); @@ -3723,7 +4345,11 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_clear_options(const google_p _upb_clearhas(msg, 2); } UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 32), const google_protobuf_EnumOptions*); + const google_protobuf_EnumOptions* default_val = NULL; + const google_protobuf_EnumOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 40)); @@ -3742,10 +4368,9 @@ UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_na } 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(20, 8), upb_StringView) = value; -} -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto* msg, size_t* len) { + const upb_MiniTableField field = {1, UPB_SIZE(20, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(4, 24), len); } UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { @@ -3758,15 +4383,13 @@ UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_Enum 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(8, 32), google_protobuf_EnumOptions*) = value; -} -UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_EnumDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_EnumDescriptorProto_set_options(msg, sub); } return sub; } @@ -3831,32 +4454,38 @@ UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start( 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; + const upb_MiniTableField field = {1, 4, 1, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } -UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} - /* google.protobuf.EnumValueDescriptorProto */ UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_new(upb_Arena* arena) { @@ -3900,17 +4529,25 @@ UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_name(const google _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {2, 4, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto* msg) { return _upb_hasbit(msg, 3); @@ -3920,27 +4557,27 @@ UPB_INLINE void google_protobuf_EnumValueDescriptorProto_clear_options(const goo _upb_clearhas(msg, 3); } UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 24), const google_protobuf_EnumValueOptions*); + const google_protobuf_EnumValueOptions* default_val = NULL; + const google_protobuf_EnumValueOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto *msg, google_protobuf_EnumValueOptions* value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(8, 24), google_protobuf_EnumValueOptions*) = value; -} -UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value) { + const upb_MiniTableField field = {2, 4, 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto *msg, google_protobuf_EnumValueOptions* value) { + const upb_MiniTableField field = {3, UPB_SIZE(8, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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_msg_init, arena); - if (!sub) return NULL; - google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); } return sub; } @@ -3988,7 +4625,11 @@ UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_name(const google_p _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 24)); @@ -4007,14 +4648,17 @@ UPB_INLINE void google_protobuf_ServiceDescriptorProto_clear_options(const googl _upb_clearhas(msg, 2); } UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 32), const google_protobuf_ServiceOptions*); + const google_protobuf_ServiceOptions* default_val = NULL; + const google_protobuf_ServiceOptions* ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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(12, 8), upb_StringView) = value; -} -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto* msg, size_t* len) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(4, 24), len); } UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto* msg, size_t len, upb_Arena* arena) { @@ -4027,15 +4671,13 @@ UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_Service 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(8, 32), google_protobuf_ServiceOptions*) = value; -} -UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {3, UPB_SIZE(8, 32), 2, 1, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); if (sub == NULL) { sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msg_init, arena); - if (!sub) return NULL; - google_protobuf_ServiceDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_ServiceDescriptorProto_set_options(msg, sub); } return sub; } @@ -4083,7 +4725,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_name(const google_pr _upb_clearhas(msg, 1); } UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 2); @@ -4093,7 +4739,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_input_type(const goo _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(20, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 3); @@ -4103,7 +4753,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_output_type(const go _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(28, 40), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(28, 40), 3, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 4); @@ -4113,7 +4767,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_options(const google _upb_clearhas(msg, 4); } UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(4, 56), const google_protobuf_MethodOptions*); + const google_protobuf_MethodOptions* default_val = NULL; + const google_protobuf_MethodOptions* ret; + const upb_MiniTableField field = {4, UPB_SIZE(4, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 5); @@ -4123,7 +4781,11 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_client_streaming(con _upb_clearhas(msg, 5); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(8, 1), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, UPB_SIZE(8, 1), 5, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { return _upb_hasbit(msg, 6); @@ -4133,43 +4795,40 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_clear_server_streaming(con _upb_clearhas(msg, 6); } UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(9, 2), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {6, UPB_SIZE(9, 2), 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(12, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(4, 56), google_protobuf_MethodOptions*) = value; -} -UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena) { + const upb_MiniTableField field = {1, UPB_SIZE(12, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) { + const upb_MiniTableField field = {3, UPB_SIZE(28, 40), 3, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value) { + const upb_MiniTableField field = {4, UPB_SIZE(4, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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_msg_init, arena); - if (!sub) return NULL; - google_protobuf_MethodDescriptorProto_set_options(msg, sub); + if (sub) google_protobuf_MethodDescriptorProto_set_options(msg, sub); } return sub; } UPB_INLINE void google_protobuf_MethodDescriptorProto_set_client_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(8, 1), bool) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(9, 2), bool) = value; + const upb_MiniTableField field = {5, UPB_SIZE(8, 1), 5, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { + const upb_MiniTableField field = {6, UPB_SIZE(9, 2), 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } - /* google.protobuf.FileOptions */ UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_new(upb_Arena* arena) { @@ -4209,11 +4868,15 @@ UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protob 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(24, 24), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + *UPB_PTR_AT(msg, 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(24, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, 24, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 2); @@ -4223,27 +4886,39 @@ UPB_INLINE void google_protobuf_FileOptions_clear_java_outer_classname(const goo _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(32, 40), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {8, UPB_SIZE(32, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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; + int32_t default_val = 1; + int32_t ret; + const upb_MiniTableField field = {9, 4, 3, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {10, 8, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 5); @@ -4253,77 +4928,109 @@ UPB_INLINE void google_protobuf_FileOptions_clear_go_package(const google_protob _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(40, 56), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {11, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {16, 9, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {17, 10, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {18, 11, 8, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {20, 12, 9, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {23, 13, 10, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {27, 14, 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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; + bool default_val = true; + bool ret; + const upb_MiniTableField field = {31, 15, 12, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 13); @@ -4333,7 +5040,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_objc_class_prefix(const google _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(48, 72), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {36, UPB_SIZE(48, 72), 13, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 14); @@ -4343,7 +5054,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_csharp_namespace(const google_ _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(56, 88), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {37, UPB_SIZE(56, 88), 14, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 15); @@ -4353,7 +5068,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_swift_prefix(const google_prot _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(64, 104), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {39, UPB_SIZE(64, 104), 15, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 16); @@ -4363,7 +5082,11 @@ UPB_INLINE void google_protobuf_FileOptions_clear_php_class_prefix(const google_ _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(72, 120), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {40, UPB_SIZE(72, 120), 16, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 17); @@ -4373,17 +5096,25 @@ UPB_INLINE void google_protobuf_FileOptions_clear_php_namespace(const google_pro _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(80, 136), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {41, UPB_SIZE(80, 136), 17, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {42, 16, 18, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions* msg) { return _upb_hasbit(msg, 19); @@ -4393,109 +5124,97 @@ UPB_INLINE void google_protobuf_FileOptions_clear_php_metadata_namespace(const g _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(88, 152), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {44, UPB_SIZE(88, 152), 19, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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(96, 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(96, 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(20, 184)); -} -UPB_INLINE void google_protobuf_FileOptions_clear_uninterpreted_option(const google_protobuf_FileOptions* msg) { - _upb_array_detach(msg, UPB_SIZE(20, 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(20, 184), len); -} - -UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, int32_t value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 8); - *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 9); - *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 10); - *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 11); - *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 12); - *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 13); - *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 14); - *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 15); - *UPB_PTR_AT(msg, UPB_SIZE(64, 104), upb_StringView) = value; + return _upb_hasbit(msg, 20); } -UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 16); - *UPB_PTR_AT(msg, UPB_SIZE(72, 120), upb_StringView) = value; +UPB_INLINE void google_protobuf_FileOptions_clear_ruby_package(const google_protobuf_FileOptions* msg) { + *UPB_PTR_AT(msg, UPB_SIZE(96, 168), upb_StringView) = upb_StringView_FromDataAndSize(NULL, 0); + _upb_clearhas(msg, 20); } -UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 17); - *UPB_PTR_AT(msg, UPB_SIZE(80, 136), upb_StringView) = value; +UPB_INLINE upb_StringView google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions* msg) { + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {45, UPB_SIZE(96, 168), 20, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } -UPB_INLINE void google_protobuf_FileOptions_set_php_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 18); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; +UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 184)); } -UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 19); - *UPB_PTR_AT(msg, UPB_SIZE(88, 152), upb_StringView) = value; +UPB_INLINE void google_protobuf_FileOptions_clear_uninterpreted_option(const google_protobuf_FileOptions* msg) { + _upb_array_detach(msg, UPB_SIZE(20, 184)); } -UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions *msg, upb_StringView value) { - _upb_sethas(msg, 20); - *UPB_PTR_AT(msg, UPB_SIZE(96, 168), upb_StringView) = value; +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(20, 184), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions* msg, size_t* len) { + +UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {1, 24, 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {8, UPB_SIZE(32, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, int32_t value) { + const upb_MiniTableField field = {9, 4, 3, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {10, 8, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {11, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {16, 9, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {17, 10, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {18, 11, 8, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {20, 12, 9, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {23, 13, 10, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {27, 14, 11, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {31, 15, 12, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {36, UPB_SIZE(48, 72), 13, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {37, UPB_SIZE(56, 88), 14, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {39, UPB_SIZE(64, 104), 15, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {40, UPB_SIZE(72, 120), 16, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {41, UPB_SIZE(80, 136), 17, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_php_generic_services(google_protobuf_FileOptions *msg, bool value) { + const upb_MiniTableField field = {42, 16, 18, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {44, UPB_SIZE(88, 152), 19, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions *msg, upb_StringView value) { + const upb_MiniTableField field = {45, UPB_SIZE(96, 168), 20, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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(20, 184), len); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions* msg, size_t len, upb_Arena* arena) { @@ -4547,77 +5266,89 @@ UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 3, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {7, 4, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); + return _upb_has_submsg_nohasbit(msg, 8); } UPB_INLINE void google_protobuf_MessageOptions_clear_uninterpreted_option(const google_protobuf_MessageOptions* msg) { - _upb_array_detach(msg, UPB_SIZE(8, 8)); + _upb_array_detach(msg, 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); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, 8, len); } UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_no_standard_descriptor_accessor(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_deprecated(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_MessageOptions *msg, bool value) { - _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) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); + const upb_MiniTableField field = {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MessageOptions_set_no_standard_descriptor_accessor(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {2, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MessageOptions_set_deprecated(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {3, 3, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_MessageOptions *msg, bool value) { + const upb_MiniTableField field = {7, 4, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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, 8, len); } 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); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, 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, 8, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4661,71 +5392,99 @@ UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_Fie 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_PTR_AT(msg, 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); + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {1, 4, 1, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(8, 8), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(9, 9), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 9, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(10, 10), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {5, 10, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(12, 12), int32_t); + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {6, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(16, 16), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {10, 16, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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(17, 17), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {15, 17, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); @@ -4738,34 +5497,27 @@ UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_Fie } UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { - _upb_sethas(msg, 2); - *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(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(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(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(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(17, 17), bool) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t* len) { + const upb_MiniTableField field = {1, 4, 1, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {2, 8, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {3, 9, 3, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {5, 10, 4, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, int32_t value) { + const upb_MiniTableField field = {6, 12, 5, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {10, 16, 6, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_FieldOptions_set_unverified_lazy(google_protobuf_FieldOptions *msg, bool value) { + const upb_MiniTableField field = {15, 17, 7, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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); } UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t len, upb_Arena* arena) { @@ -4814,24 +5566,24 @@ UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf return ptr; } UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_OneofOptions_clear_uninterpreted_option(const google_protobuf_OneofOptions* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4875,21 +5627,29 @@ UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobu 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {3, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); @@ -4902,14 +5662,12 @@ UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_Enu } UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} -UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumOptions *msg, bool value) { - _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) { + const upb_MiniTableField field = {2, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumOptions *msg, bool value) { + const upb_MiniTableField field = {3, 2, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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) { @@ -4961,11 +5719,15 @@ UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_pro 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); @@ -4978,10 +5740,9 @@ UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_Enu } 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) { + const upb_MiniTableField field = {1, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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) { @@ -5033,11 +5794,15 @@ UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_proto 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); @@ -5050,10 +5815,9 @@ UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_Ser } 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) { + const upb_MiniTableField field = {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}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) { @@ -5105,49 +5869,55 @@ UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protob 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_PTR_AT(msg, 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(1, 1), bool); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {34, 4, 2, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); + return _upb_has_submsg_nohasbit(msg, 8); } UPB_INLINE void google_protobuf_MethodOptions_clear_uninterpreted_option(const google_protobuf_MethodOptions* msg) { - _upb_array_detach(msg, UPB_SIZE(8, 8)); + _upb_array_detach(msg, 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); + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, 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(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(8, 8), len); + const upb_MiniTableField field = {33, 1, 1, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, int32_t value) { + const upb_MiniTableField field = {34, 4, 2, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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, 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(8, 8), len, UPB_SIZE(2, 3), arena); + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, 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_msg_init, 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, 8, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -5204,7 +5974,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_identifier_value(const _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(8, 16), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 16), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 2); @@ -5214,7 +5988,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_positive_int_value(con _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(16, 32), uint64_t); + uint64_t default_val = (uint64_t)0ull; + uint64_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(16, 32), 2, kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 3); @@ -5224,7 +6002,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_negative_int_value(con _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(24, 40), int64_t); + int64_t default_val = (int64_t)0ll; + int64_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(24, 40), 3, kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 4); @@ -5234,7 +6016,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_double_value(const goo _upb_clearhas(msg, 4); } UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(32, 48), double); + double default_val = 0; + double ret; + const upb_MiniTableField field = {6, UPB_SIZE(32, 48), 4, kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 5); @@ -5244,7 +6030,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_string_value(const goo _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, 56), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {7, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption* msg) { return _upb_hasbit(msg, 6); @@ -5254,7 +6044,11 @@ UPB_INLINE void google_protobuf_UninterpretedOption_clear_aggregate_value(const _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, 72), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {8, UPB_SIZE(48, 72), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption* msg, size_t* len) { @@ -5270,30 +6064,24 @@ UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_ 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(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(16, 32), 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(24, 40), int64_t) = value; + const upb_MiniTableField field = {3, UPB_SIZE(8, 16), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(16, 32), 2, kUpb_NoSub, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(24, 40), 3, kUpb_NoSub, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) { + const upb_MiniTableField field = {6, UPB_SIZE(32, 48), 4, kUpb_NoSub, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { + const upb_MiniTableField field = {7, UPB_SIZE(40, 56), 5, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) { + const upb_MiniTableField field = {8, UPB_SIZE(48, 72), 6, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(32, 48), 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, 56), 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, 72), upb_StringView) = value; -} - /* google.protobuf.UninterpretedOption.NamePart */ UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_new(upb_Arena* arena) { @@ -5337,28 +6125,34 @@ UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_clear_name_part(con _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_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {1, UPB_SIZE(4, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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_PTR_AT(msg, 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); + bool default_val = false; + bool ret; + const upb_MiniTableField field = {2, 1, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart *msg, upb_StringView value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; + const upb_MiniTableField field = {1, UPB_SIZE(4, 8), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value) { + const upb_MiniTableField field = {2, 1, 2, kUpb_NoSub, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); } - /* google.protobuf.SourceCodeInfo */ UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new(upb_Arena* arena) { @@ -5395,24 +6189,24 @@ UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protob return ptr; } UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_SourceCodeInfo_clear_location(const google_protobuf_SourceCodeInfo* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_SourceCodeInfo_Location**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -5472,7 +6266,11 @@ UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_comments(c _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(16, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {3, UPB_SIZE(16, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { return _upb_hasbit(msg, 2); @@ -5482,7 +6280,11 @@ UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_trailing_comments( _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(24, 40), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {4, UPB_SIZE(24, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_clear_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg) { _upb_array_detach(msg, UPB_SIZE(12, 56)); @@ -5510,14 +6312,12 @@ UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf 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(16, 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(24, 40), upb_StringView) = value; -} -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + const upb_MiniTableField field = {3, UPB_SIZE(16, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { + const upb_MiniTableField field = {4, UPB_SIZE(24, 40), 2, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &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(12, 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) { @@ -5563,24 +6363,24 @@ UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_pro return ptr; } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo* msg) { - return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); + return _upb_has_submsg_nohasbit(msg, 0); } UPB_INLINE void google_protobuf_GeneratedCodeInfo_clear_annotation(const google_protobuf_GeneratedCodeInfo* msg) { - _upb_array_detach(msg, UPB_SIZE(0, 0)); + _upb_array_detach(msg, 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); + return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, 0, 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); + return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, 0, len); } 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); + return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_Array_Resize_accessor2(msg, 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) { struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msg_init, 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, 0, UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -5634,7 +6434,11 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_source_file(c _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(20, 24), upb_StringView); + upb_StringView default_val = upb_StringView_FromString(""); + upb_StringView ret; + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return _upb_hasbit(msg, 2); @@ -5644,7 +6448,11 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_begin(const g _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(8, 4), int32_t); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {3, UPB_SIZE(8, 4), 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return _upb_hasbit(msg, 3); @@ -5654,7 +6462,11 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_end(const goo _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(12, 8), int32_t); + int32_t default_val = (int32_t)0; + int32_t ret; + const upb_MiniTableField field = {4, UPB_SIZE(12, 8), 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return _upb_hasbit(msg, 4); @@ -5664,268 +6476,120 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_clear_semantic(cons _upb_clearhas(msg, 4); } UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_semantic(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { - return *UPB_PTR_AT(msg, UPB_SIZE(16, 12), int32_t); + int32_t default_val = 0; + int32_t ret; + const upb_MiniTableField field = {5, UPB_SIZE(16, 12), 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_GetNonExtensionField(msg, &field, &default_val, &ret); + return ret; } 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(4, 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(4, 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(4, 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(20, 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(8, 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(12, 8), int32_t) = value; -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_semantic(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(16, 12), 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_ */ - -/* - * Internal implementation details of the decoder that are shared between - * decode.c and decode_fast.c. - */ - -#ifndef UPB_WIRE_DECODE_INTERNAL_H_ -#define UPB_WIRE_DECODE_INTERNAL_H_ - - -#ifndef UPB_MEM_ARENA_INTERNAL_H_ -#define UPB_MEM_ARENA_INTERNAL_H_ - - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -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; -}; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MEM_ARENA_INTERNAL_H_ */ -#include "third_party/utf8_range/utf8_range.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* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status); - -extern const uint8_t upb_utf8_offsets[]; - -UPB_INLINE -bool _upb_Decoder_VerifyUtf8Inline(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* _upb_Decoder_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* _upb_Decoder_IsDoneFallbackInline(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; - } -} +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(4, 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(4, 16), 2, &val, arena); +} +UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_StringView value) { + const upb_MiniTableField field = {2, UPB_SIZE(20, 24), 1, kUpb_NoSub, 12, kUpb_FieldMode_Scalar | kUpb_LabelFlags_IsAlternate | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + const upb_MiniTableField field = {3, UPB_SIZE(8, 4), 2, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + const upb_MiniTableField field = {4, UPB_SIZE(12, 8), 3, kUpb_NoSub, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +}UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_semantic(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { + const upb_MiniTableField field = {5, UPB_SIZE(16, 12), 4, 0, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}; + _upb_MiniTable_SetNonExtensionField(msg, &field, &value); +} +extern const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout; -const char* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, - int overrun); +/* Max size 32 is google.protobuf.FileOptions */ +/* Max size 64 is google.protobuf.FileOptions */ +#define _UPB_MAXOPT_SIZE UPB_SIZE(104, 192) -UPB_INLINE -bool _upb_Decoder_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 = _upb_Decoder_IsDoneFallback(d, *ptr, overrun); - return false; - } -} +#ifdef __cplusplus +} /* extern "C" */ +#endif -#if UPB_FASTTABLE -UPB_INLINE -const char* _upb_FastDecoder_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 /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ + +#ifndef UPB_HASH_INT_TABLE_H_ +#define UPB_HASH_INT_TABLE_H_ + + +// Must be last. + +typedef struct { + upb_table t; // For entries that don't fit in the array part. + const upb_tabval* array; // Array part of the table. See const note above. + size_t array_size; // Array part size. + size_t array_count; // Array part number of elements. +} upb_inttable; + +#ifdef __cplusplus +extern "C" { #endif -UPB_INLINE uint32_t _upb_FastDecoder_LoadTag(const char* ptr) { - uint16_t tag; - memcpy(&tag, ptr, 2); - return tag; -} +// Initialize a table. If memory allocation failed, false is returned and +// the table is uninitialized. +bool upb_inttable_init(upb_inttable* table, upb_Arena* a); -UPB_INLINE void _upb_Decoder_CheckLimit(upb_Decoder* d) { - UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); -} +// Returns the number of values in the table. +size_t upb_inttable_count(const upb_inttable* t); -UPB_INLINE int _upb_Decoder_PushLimit(upb_Decoder* d, const char* ptr, - int size) { - int limit = size + (int)(ptr - d->end); - int delta = d->limit - limit; - _upb_Decoder_CheckLimit(d); - d->limit = limit; - d->limit_ptr = d->end + UPB_MIN(0, limit); - _upb_Decoder_CheckLimit(d); - return delta; -} +// Inserts the given key into the hashtable with the given value. +// The key must not already exist in the hash table. +// The value must not be UINTPTR_MAX. +// +// If a table resize was required but memory allocation failed, false is +// returned and the table is unchanged. +bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, + upb_Arena* a); -UPB_INLINE void _upb_Decoder_PopLimit(upb_Decoder* d, const char* ptr, - int saved_delta) { - UPB_ASSERT(ptr - d->end == d->limit); - _upb_Decoder_CheckLimit(d); - d->limit += saved_delta; - d->limit_ptr = d->end + UPB_MIN(0, d->limit); - _upb_Decoder_CheckLimit(d); -} +// Looks up key in this table, returning "true" if the key was found. +// If v is non-NULL, copies the value for this key into *v. +bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v); +// Removes an item from the table. Returns true if the remove was successful, +// and stores the removed item in *val if non-NULL. +bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val); + +// Updates an existing entry in an inttable. +// If the entry does not exist, returns false and does nothing. +// Unlike insert/remove, this does not invalidate iterators. +bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val); + +// Optimizes the table for the current set of entries, for both memory use and +// lookup time. Client should call this after all entries have been inserted; +// inserting more entries is legal, but will likely require a table resize. +void upb_inttable_compact(upb_inttable* t, upb_Arena* a); + +// Iteration over inttable: +// +// intptr_t iter = UPB_INTTABLE_BEGIN; +// uintptr_t key; +// upb_value val; +// while (upb_inttable_next(t, &key, &val, &iter)) { +// // ... +// } + +#define UPB_INTTABLE_BEGIN -1 + +bool upb_inttable_next(const upb_inttable* t, uintptr_t* key, upb_value* val, + intptr_t* iter); +void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter); + +#ifdef __cplusplus +} /* extern "C" */ +#endif -#endif /* UPB_WIRE_DECODE_INTERNAL_H_ */ + +#endif /* UPB_HASH_INT_TABLE_H_ */ #ifndef UPB_JSON_DECODE_H_ #define UPB_JSON_DECODE_H_ @@ -5935,13 +6599,13 @@ UPB_INLINE void _upb_Decoder_PopLimit(upb_Decoder* d, const char* ptr, #define UPB_REFLECTION_DEF_H_ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_DEF_POOL_H_ #define UPB_REFLECTION_DEF_POOL_H_ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" // Declarations common to all public def types. @@ -5954,11 +6618,13 @@ typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; // Forward declarations for circular references. typedef struct upb_DefPool upb_DefPool; typedef struct upb_EnumDef upb_EnumDef; +typedef struct upb_EnumReservedRange upb_EnumReservedRange; typedef struct upb_EnumValueDef upb_EnumValueDef; typedef struct upb_ExtensionRange upb_ExtensionRange; typedef struct upb_FieldDef upb_FieldDef; typedef struct upb_FileDef upb_FileDef; typedef struct upb_MessageDef upb_MessageDef; +typedef struct upb_MessageReservedRange upb_MessageReservedRange; typedef struct upb_MethodDef upb_MethodDef; typedef struct upb_OneofDef upb_OneofDef; typedef struct upb_ServiceDef upb_ServiceDef; @@ -6051,7 +6717,7 @@ const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, size_t len); const upb_FieldDef* upb_DefPool_FindExtensionByMiniTable( - const upb_DefPool* s, const upb_MiniTable_Extension* ext); + const upb_DefPool* s, const upb_MiniTableExtension* ext); const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, const char* sym); @@ -6090,7 +6756,7 @@ const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, #endif /* UPB_REFLECTION_DEF_POOL_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_ENUM_DEF_H_ #define UPB_REFLECTION_ENUM_DEF_H_ @@ -6122,6 +6788,14 @@ bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, const char* upb_EnumDef_Name(const upb_EnumDef* e); const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); + +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); + const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); int upb_EnumDef_ValueCount(const upb_EnumDef* e); @@ -6132,7 +6806,7 @@ int upb_EnumDef_ValueCount(const upb_EnumDef* e); #endif /* UPB_REFLECTION_ENUM_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_ENUM_VALUE_DEF_H_ #define UPB_REFLECTION_ENUM_VALUE_DEF_H_ @@ -6160,7 +6834,7 @@ const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( #endif /* UPB_REFLECTION_ENUM_VALUE_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_EXTENSION_RANGE_H_ #define UPB_REFLECTION_EXTENSION_RANGE_H_ @@ -6186,7 +6860,7 @@ const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( #endif /* UPB_REFLECTION_EXTENSION_RANGE_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_FIELD_DEF_H_ #define UPB_REFLECTION_FIELD_DEF_H_ @@ -6232,7 +6906,7 @@ const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, upb_StringView* out); -const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f); +const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f); const char* upb_FieldDef_Name(const upb_FieldDef* f); uint32_t upb_FieldDef_Number(const upb_FieldDef* f); const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f); @@ -6246,7 +6920,7 @@ upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); #endif /* UPB_REFLECTION_FIELD_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_FILE_DEF_H_ #define UPB_REFLECTION_FILE_DEF_H_ @@ -6293,7 +6967,7 @@ int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); #endif /* UPB_REFLECTION_FILE_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_MESSAGE_DEF_H_ #define UPB_REFLECTION_MESSAGE_DEF_H_ @@ -6417,6 +7091,14 @@ const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); int upb_MessageDef_OneofCount(const upb_MessageDef* m); const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m); + +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); + upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); @@ -6427,7 +7109,7 @@ upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); #endif /* UPB_REFLECTION_MESSAGE_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_METHOD_DEF_H_ #define UPB_REFLECTION_METHOD_DEF_H_ @@ -6457,7 +7139,7 @@ const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); #endif /* UPB_REFLECTION_METHOD_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_ONEOF_DEF_H_ #define UPB_REFLECTION_ONEOF_DEF_H_ @@ -6494,7 +7176,7 @@ const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o); #endif /* UPB_REFLECTION_ONEOF_DEF_H_ */ -// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" +// IWYU pragma: private, include "upb/reflection/def.h" #ifndef UPB_REFLECTION_SERVICE_DEF_H_ #define UPB_REFLECTION_SERVICE_DEF_H_ @@ -6545,8 +7227,33 @@ bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, #endif /* UPB_JSONDECODE_H_ */ -#ifndef UPB_INTERNAL_UNICODE_H_ -#define UPB_INTERNAL_UNICODE_H_ +#ifndef UPB_LEX_ATOI_H_ +#define UPB_LEX_ATOI_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +// 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. +// Return the new position of the pointer after parsing the int, or NULL on +// integer overflow. + +const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val); +const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, + bool* is_neg); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_ATOI_H_ */ + +#ifndef UPB_LEX_UNICODE_H_ +#define UPB_LEX_UNICODE_H_ // Must be last. @@ -6592,7 +7299,7 @@ int upb_Unicode_ToUTF8(uint32_t cp, char* out); #endif -#endif /* UPB_INTERNAL_UNICODE_H_ */ +#endif /* UPB_LEX_UNICODE_H_ */ #ifndef UPB_REFLECTION_MESSAGE_H_ #define UPB_REFLECTION_MESSAGE_H_ @@ -6708,10 +7415,35 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #endif /* UPB_JSONENCODE_H_ */ -#ifndef UPB_INTERNAL_VSNPRINTF_COMPAT_H_ -#define UPB_INTERNAL_VSNPRINTF_COMPAT_H_ +#ifndef UPB_LEX_ROUND_TRIP_H_ +#define UPB_LEX_ROUND_TRIP_H_ -#include +// Must be last. + +// 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 }; + +#ifdef __cplusplus +extern "C" { +#endif + +void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); +void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_LEX_ROUND_TRIP_H_ */ + +#ifndef UPB_PORT_VSNPRINTF_COMPAT_H_ +#define UPB_PORT_VSNPRINTF_COMPAT_H_ // Must be last. @@ -6730,10 +7462,10 @@ UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, } -#endif // UPB_INTERNAL_VSNPRINTF_COMPAT_H_ +#endif // UPB_PORT_VSNPRINTF_COMPAT_H_ -#ifndef UPB_WIRE_ENCODE_INTERNAL_H_ -#define UPB_WIRE_ENCODE_INTERNAL_H_ +#ifndef UPB_LEX_STRTOD_H_ +#define UPB_LEX_STRTOD_H_ // Must be last. @@ -6741,68 +7473,70 @@ UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, extern "C" { #endif -// 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); +double _upb_NoLocaleStrtod(const char *str, char **endptr); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_WIRE_ENCODE_INTERNAL_H_ */ +#endif /* UPB_LEX_STRTOD_H_ */ -#ifndef UPB_MINI_TABLE_COMMON_H_ -#define UPB_MINI_TABLE_COMMON_H_ +#ifndef UPB_MEM_ARENA_INTERNAL_H_ +#define UPB_MEM_ARENA_INTERNAL_H_ // Must be last. -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 enum { - kUpb_MessageModifier_ValidateUtf8 = 1 << 0, - kUpb_MessageModifier_DefaultIsPacked = 1 << 1, - kUpb_MessageModifier_IsExtendable = 1 << 2, -} kUpb_MessageModifier; +typedef struct _upb_MemBlock _upb_MemBlock; -#ifdef __cplusplus -extern "C" { -#endif +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; -const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( - const upb_MiniTable* table, uint32_t number); + /* Allocator to allocate arena blocks. We are responsible for freeing these + * when we are destroyed. */ + upb_alloc* block_alloc; + uint32_t last_size; -upb_FieldType upb_MiniTableField_Type(const upb_MiniTable_Field* field); + /* 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; -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; -} + /* Linked list of blocks to free/cleanup. */ + _upb_MemBlock *freelist, *freelist_tail; +}; -UPB_INLINE const upb_MiniTable_Enum* upb_MiniTable_GetSubEnumTable( - const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { - return mini_table->subs[field->submsg_index].subenum; -} +#ifdef __cplusplus +extern "C" { +#endif #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_MINI_TABLE_COMMON_H_ */ +#endif /* UPB_MEM_ARENA_INTERNAL_H_ */ + +#ifndef UPB_WIRE_TYPES_H_ +#define UPB_WIRE_TYPES_H_ + +// A list of types as they are encoded on the wire. +typedef enum { + kUpb_WireType_Varint = 0, + kUpb_WireType_64Bit = 1, + kUpb_WireType_Delimited = 2, + kUpb_WireType_StartGroup = 3, + kUpb_WireType_EndGroup = 4, + kUpb_WireType_32Bit = 5 +} upb_WireType; + +#endif /* UPB_WIRE_TYPES_H_ */ #ifndef UPB_MINI_TABLE_COMMON_INTERNAL_H_ #define UPB_MINI_TABLE_COMMON_INTERNAL_H_ @@ -6930,23 +7664,31 @@ upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, // as unknown. However there is no synchronization for this operation, which // means parallel mutation requires external synchronization. void upb_MiniTable_SetSubMessage(upb_MiniTable* table, - upb_MiniTable_Field* field, + upb_MiniTableField* field, const upb_MiniTable* sub); // Links an enum field to a MiniTable for that enum. All enum fields must // be linked prior to parsing. -void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, - const upb_MiniTable_Enum* sub); +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTableField* field, + const upb_MiniTableEnum* sub); + +const char* _upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, + upb_MiniTableSub sub, + upb_MiniTablePlatform platform, + upb_Status* status); -const char* upb_MiniTable_BuildExtension(const char* data, size_t len, - upb_MiniTable_Extension* ext, - const upb_MiniTable* extendee, - upb_MiniTable_Sub sub, - upb_Status* status); +UPB_INLINE const char* upb_MiniTable_BuildExtension( + const char* data, size_t len, upb_MiniTableExtension* ext, + const upb_MiniTable* extendee, upb_MiniTableSub sub, upb_Status* status) { + return _upb_MiniTable_BuildExtension(data, len, ext, extendee, sub, + kUpb_MiniTablePlatform_Native, status); +} -upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, - upb_Arena* arena, - upb_Status* status); +upb_MiniTableEnum* 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(). @@ -7064,7 +7806,7 @@ upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s); size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s); upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s); -bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext, +bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, upb_FieldDef* f); bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, upb_Status* status); @@ -7077,7 +7819,7 @@ size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s); // For generated code only: loads a generated descriptor. typedef struct _upb_DefPool_Init { struct _upb_DefPool_Init** deps; // Dependencies of this file. - const upb_MiniTable_File* layout; + const upb_MiniTableFile* layout; const char* filename; upb_StringView descriptor; // Serialized descriptor. } _upb_DefPool_Init; @@ -7123,7 +7865,7 @@ struct upb_DefBuilder { upb_Arena* arena; // Allocate defs here. upb_Arena* tmp_arena; // For temporary allocations. upb_Status* status; // Record errors here. - const upb_MiniTable_File* layout; // NULL if we should build layouts. + const upb_MiniTableFile* 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. @@ -7246,7 +7988,7 @@ extern "C" { upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i); bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a); -const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); +const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); // Allocate and initialize an array of |n| enum defs. upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, @@ -7300,7 +8042,7 @@ extern "C" { upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i); -const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable( +const upb_MiniTableExtension* _upb_FieldDef_ExtensionMiniTable( const upb_FieldDef* f); bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f); bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f); @@ -7337,7 +8079,7 @@ const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, extern "C" { #endif -const upb_MiniTable_Extension* _upb_FileDef_ExtensionMiniTable( +const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( const upb_FileDef* f, int i); const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f); const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f); @@ -7437,14 +8179,62 @@ UPB_INLINE void _upb_DescState_Init(upb_DescState* d) { d->ptr = NULL; } -bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a); +bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_DESC_STATE_INTERNAL_H_ */ + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ + + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r); +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |e|. +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* UPB_REFLECTION_DESC_STATE_INTERNAL_H_ */ +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ */ #ifndef UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ #define UPB_REFLECTION_EXTENSION_RANGE_INTERNAL_H_ @@ -7499,6 +8289,54 @@ size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); #endif /* UPB_REFLECTION_ONEOF_DEF_INTERNAL_H_ */ +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ + + +// IWYU pragma: private, include "upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r); +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ */ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |m|. +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ */ + #ifndef UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ #define UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ @@ -7523,7 +8361,244 @@ upb_MethodDef* _upb_MethodDefs_New( #endif /* UPB_REFLECTION_METHOD_DEF_INTERNAL_H_ */ -/* See port_def.inc. This should #undef all macros #defined there. */ +#ifndef UPB_WIRE_COMMON_INTERNAL_H_ +#define UPB_WIRE_COMMON_INTERNAL_H_ + +// Must be last. + +// MessageSet wire format is: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required bytes message = 3; +// } +// } + +enum { + kUpb_MsgSet_Item = 1, + kUpb_MsgSet_TypeId = 2, + kUpb_MsgSet_Message = 3, +}; + + +#endif /* UPB_WIRE_COMMON_INTERNAL_H_ */ + +/* + * Internal implementation details of the decoder that are shared between + * decode.c and decode_fast.c. + */ + +#ifndef UPB_WIRE_DECODE_INTERNAL_H_ +#define UPB_WIRE_DECODE_INTERNAL_H_ + +#include "third_party/utf8_range/utf8_range.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* _upb_FastDecoder_ErrorJmp(upb_Decoder* d, int status); + +extern const uint8_t upb_utf8_offsets[]; + +UPB_INLINE +bool _upb_Decoder_VerifyUtf8Inline(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* _upb_Decoder_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* _upb_Decoder_IsDoneFallbackInline(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* _upb_Decoder_IsDoneFallback(upb_Decoder* d, const char* ptr, + int overrun); + +UPB_INLINE +bool _upb_Decoder_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 = _upb_Decoder_IsDoneFallback(d, *ptr, overrun); + return false; + } +} + +#if UPB_FASTTABLE +UPB_INLINE +const char* _upb_FastDecoder_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 _upb_FastDecoder_LoadTag(const char* ptr) { + uint16_t tag; + memcpy(&tag, ptr, 2); + return tag; +} + +UPB_INLINE void _upb_Decoder_CheckLimit(upb_Decoder* d) { + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +} + +UPB_INLINE int _upb_Decoder_PushLimit(upb_Decoder* d, const char* ptr, + int size) { + int limit = size + (int)(ptr - d->end); + int delta = d->limit - limit; + _upb_Decoder_CheckLimit(d); + d->limit = limit; + d->limit_ptr = d->end + UPB_MIN(0, limit); + _upb_Decoder_CheckLimit(d); + return delta; +} + +UPB_INLINE void _upb_Decoder_PopLimit(upb_Decoder* d, const char* ptr, + int saved_delta) { + UPB_ASSERT(ptr - d->end == d->limit); + _upb_Decoder_CheckLimit(d); + d->limit += saved_delta; + d->limit_ptr = d->end + UPB_MIN(0, d->limit); + _upb_Decoder_CheckLimit(d); +} + + +#endif /* UPB_WIRE_DECODE_INTERNAL_H_ */ + +#ifndef UPB_WIRE_SWAP_INTERNAL_H_ +#define UPB_WIRE_SWAP_INTERNAL_H_ + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool _upb_IsLittleEndian(void) { + int x = 1; + return *(char*)&x == 1; +} + +UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) { + if (_upb_IsLittleEndian()) return val; + + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); +} + +UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { + if (_upb_IsLittleEndian()) return val; + + return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | + _upb_BigEndian_Swap32((uint32_t)(val >> 32)); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_WIRE_SWAP_INTERNAL_H_ */ + +// This should #undef all macros #defined in def.inc #undef UPB_SIZE #undef UPB_PTR_AT