Auto-generate files after cl/593821827
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c
index bcfca4d..27aa17e 100644
--- a/ruby/ext/google/protobuf_c/ruby-upb.c
+++ b/ruby/ext/google/protobuf_c/ruby-upb.c
@@ -12487,7 +12487,7 @@
}
static void _upb_Decoder_MungeInt32(wireval* val) {
- if (!_upb_IsLittleEndian()) {
+ if (!UPB_PRIVATE(_upb_IsLittleEndian)()) {
/* The next stage will memcpy(dst, &val, 4) */
val->uint32_val = val->uint64_val;
}
@@ -12707,7 +12707,7 @@
arr->UPB_PRIVATE(size) += count;
// Note: if/when the decoder supports multi-buffer input, we will need to
// handle buffer seams here.
- if (_upb_IsLittleEndian()) {
+ if (UPB_PRIVATE(_upb_IsLittleEndian)()) {
ptr = upb_EpsCopyInputStream_Copy(&d->input, ptr, mem, val->size);
} else {
int delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size);
@@ -13031,7 +13031,7 @@
}
uint64_t msg_head;
memcpy(&msg_head, msg, 8);
- msg_head = _upb_BigEndian_Swap64(msg_head);
+ msg_head = UPB_PRIVATE(_upb_BigEndian64)(msg_head);
if (UPB_PRIVATE(_upb_MiniTable_RequiredMask)(m) & ~msg_head) {
d->missing_required = true;
}
@@ -13660,6 +13660,626 @@
#undef OP_FIXPCK_LG2
#undef OP_VARPCK_LG2
+// We encode backwards, to avoid pre-computing lengths (one-pass encode).
+
+
+#include <setjmp.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+
+// Must be last.
+
+#define UPB_PB_VARINT_MAX_LEN 10
+
+UPB_NOINLINE
+static size_t encode_varint64(uint64_t val, char* buf) {
+ size_t i = 0;
+ do {
+ uint8_t byte = val & 0x7fU;
+ val >>= 7;
+ if (val) byte |= 0x80U;
+ buf[i++] = byte;
+ } while (val);
+ return i;
+}
+
+static uint32_t encode_zz32(int32_t n) {
+ return ((uint32_t)n << 1) ^ (n >> 31);
+}
+static uint64_t encode_zz64(int64_t n) {
+ return ((uint64_t)n << 1) ^ (n >> 63);
+}
+
+typedef struct {
+ upb_EncodeStatus status;
+ jmp_buf err;
+ upb_Arena* arena;
+ char *buf, *ptr, *limit;
+ int options;
+ int depth;
+ _upb_mapsorter sorter;
+} upb_encstate;
+
+static size_t upb_roundup_pow2(size_t bytes) {
+ size_t ret = 128;
+ while (ret < bytes) {
+ ret *= 2;
+ }
+ return ret;
+}
+
+UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) {
+ UPB_ASSERT(s != kUpb_EncodeStatus_Ok);
+ e->status = s;
+ UPB_LONGJMP(e->err, 1);
+}
+
+UPB_NOINLINE
+static void encode_growbuffer(upb_encstate* e, size_t bytes) {
+ size_t old_size = e->limit - e->buf;
+ size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr));
+ char* new_buf = upb_Arena_Realloc(e->arena, e->buf, old_size, new_size);
+
+ if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory);
+
+ // We want previous data at the end, realloc() put it at the beginning.
+ // TODO: This is somewhat inefficient since we are copying twice.
+ // Maybe create a realloc() that copies to the end of the new buffer?
+ if (old_size > 0) {
+ memmove(new_buf + new_size - old_size, e->buf, old_size);
+ }
+
+ e->ptr = new_buf + new_size - (e->limit - e->ptr);
+ e->limit = new_buf + new_size;
+ e->buf = new_buf;
+
+ e->ptr -= bytes;
+}
+
+/* Call to ensure that at least "bytes" bytes are available for writing at
+ * e->ptr. Returns false if the bytes could not be allocated. */
+UPB_FORCEINLINE
+static void encode_reserve(upb_encstate* e, size_t bytes) {
+ if ((size_t)(e->ptr - e->buf) < bytes) {
+ encode_growbuffer(e, bytes);
+ return;
+ }
+
+ e->ptr -= bytes;
+}
+
+/* Writes the given bytes to the buffer, handling reserve/advance. */
+static void encode_bytes(upb_encstate* e, const void* data, size_t len) {
+ if (len == 0) return; /* memcpy() with zero size is UB */
+ encode_reserve(e, len);
+ memcpy(e->ptr, data, len);
+}
+
+static void encode_fixed64(upb_encstate* e, uint64_t val) {
+ val = UPB_PRIVATE(_upb_BigEndian64)(val);
+ encode_bytes(e, &val, sizeof(uint64_t));
+}
+
+static void encode_fixed32(upb_encstate* e, uint32_t val) {
+ val = UPB_PRIVATE(_upb_BigEndian32)(val);
+ encode_bytes(e, &val, sizeof(uint32_t));
+}
+
+UPB_NOINLINE
+static void encode_longvarint(upb_encstate* e, uint64_t val) {
+ size_t len;
+ char* start;
+
+ encode_reserve(e, UPB_PB_VARINT_MAX_LEN);
+ len = encode_varint64(val, e->ptr);
+ start = e->ptr + UPB_PB_VARINT_MAX_LEN - len;
+ memmove(start, e->ptr, len);
+ e->ptr = start;
+}
+
+UPB_FORCEINLINE
+static void encode_varint(upb_encstate* e, uint64_t val) {
+ if (val < 128 && e->ptr != e->buf) {
+ --e->ptr;
+ *e->ptr = val;
+ } else {
+ encode_longvarint(e, val);
+ }
+}
+
+static void encode_double(upb_encstate* e, double d) {
+ uint64_t u64;
+ UPB_ASSERT(sizeof(double) == sizeof(uint64_t));
+ memcpy(&u64, &d, sizeof(uint64_t));
+ encode_fixed64(e, u64);
+}
+
+static void encode_float(upb_encstate* e, float d) {
+ uint32_t u32;
+ UPB_ASSERT(sizeof(float) == sizeof(uint32_t));
+ memcpy(&u32, &d, sizeof(uint32_t));
+ encode_fixed32(e, u32);
+}
+
+static void encode_tag(upb_encstate* e, uint32_t field_number,
+ uint8_t wire_type) {
+ encode_varint(e, (field_number << 3) | wire_type);
+}
+
+static void encode_fixedarray(upb_encstate* e, const upb_Array* arr,
+ size_t elem_size, uint32_t tag) {
+ size_t bytes = arr->UPB_PRIVATE(size) * elem_size;
+ const char* data = _upb_array_constptr(arr);
+ const char* ptr = data + bytes - elem_size;
+
+ if (tag || !UPB_PRIVATE(_upb_IsLittleEndian)()) {
+ while (true) {
+ if (elem_size == 4) {
+ uint32_t val;
+ memcpy(&val, ptr, sizeof(val));
+ val = UPB_PRIVATE(_upb_BigEndian32)(val);
+ encode_bytes(e, &val, elem_size);
+ } else {
+ UPB_ASSERT(elem_size == 8);
+ uint64_t val;
+ memcpy(&val, ptr, sizeof(val));
+ val = UPB_PRIVATE(_upb_BigEndian64)(val);
+ encode_bytes(e, &val, elem_size);
+ }
+
+ if (tag) encode_varint(e, tag);
+ if (ptr == data) break;
+ ptr -= elem_size;
+ }
+ } else {
+ encode_bytes(e, data, bytes);
+ }
+}
+
+static void encode_message(upb_encstate* e, const upb_Message* msg,
+ const upb_MiniTable* m, size_t* size);
+
+static void encode_TaggedMessagePtr(upb_encstate* e,
+ upb_TaggedMessagePtr tagged,
+ const upb_MiniTable* m, size_t* size) {
+ if (upb_TaggedMessagePtr_IsEmpty(tagged)) {
+ m = UPB_PRIVATE(_upb_MiniTable_Empty)();
+ }
+ encode_message(e, _upb_TaggedMessagePtr_GetMessage(tagged), m, size);
+}
+
+static void encode_scalar(upb_encstate* e, const void* _field_mem,
+ const upb_MiniTableSub* subs,
+ const upb_MiniTableField* f) {
+ const char* field_mem = _field_mem;
+ int wire_type;
+
+#define CASE(ctype, type, wtype, encodeval) \
+ { \
+ ctype val = *(ctype*)field_mem; \
+ encode_##type(e, encodeval); \
+ wire_type = wtype; \
+ break; \
+ }
+
+ switch (f->UPB_PRIVATE(descriptortype)) {
+ case kUpb_FieldType_Double:
+ CASE(double, double, kUpb_WireType_64Bit, val);
+ case kUpb_FieldType_Float:
+ CASE(float, float, kUpb_WireType_32Bit, val);
+ case kUpb_FieldType_Int64:
+ case kUpb_FieldType_UInt64:
+ CASE(uint64_t, varint, kUpb_WireType_Varint, val);
+ case kUpb_FieldType_UInt32:
+ CASE(uint32_t, varint, kUpb_WireType_Varint, val);
+ case kUpb_FieldType_Int32:
+ case kUpb_FieldType_Enum:
+ CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val);
+ case kUpb_FieldType_SFixed64:
+ case kUpb_FieldType_Fixed64:
+ CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val);
+ case kUpb_FieldType_Fixed32:
+ case kUpb_FieldType_SFixed32:
+ CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val);
+ case kUpb_FieldType_Bool:
+ CASE(bool, varint, kUpb_WireType_Varint, val);
+ case kUpb_FieldType_SInt32:
+ CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val));
+ case kUpb_FieldType_SInt64:
+ CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val));
+ case kUpb_FieldType_String:
+ case kUpb_FieldType_Bytes: {
+ upb_StringView view = *(upb_StringView*)field_mem;
+ encode_bytes(e, view.data, view.size);
+ encode_varint(e, view.size);
+ wire_type = kUpb_WireType_Delimited;
+ break;
+ }
+ case kUpb_FieldType_Group: {
+ size_t size;
+ upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem;
+ const upb_MiniTable* subm =
+ upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
+ if (submsg == 0) {
+ return;
+ }
+ if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
+ encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_EndGroup);
+ encode_TaggedMessagePtr(e, submsg, subm, &size);
+ wire_type = kUpb_WireType_StartGroup;
+ e->depth++;
+ break;
+ }
+ case kUpb_FieldType_Message: {
+ size_t size;
+ upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem;
+ const upb_MiniTable* subm =
+ upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
+ if (submsg == 0) {
+ return;
+ }
+ if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
+ encode_TaggedMessagePtr(e, submsg, subm, &size);
+ encode_varint(e, size);
+ wire_type = kUpb_WireType_Delimited;
+ e->depth++;
+ break;
+ }
+ default:
+ UPB_UNREACHABLE();
+ }
+#undef CASE
+
+ encode_tag(e, f->UPB_PRIVATE(number), wire_type);
+}
+
+static void encode_array(upb_encstate* e, const upb_Message* msg,
+ const upb_MiniTableSub* subs,
+ const upb_MiniTableField* f) {
+ const upb_Array* arr = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), upb_Array*);
+ bool packed = upb_MiniTableField_IsPacked(f);
+ size_t pre_len = e->limit - e->ptr;
+
+ if (arr == NULL || arr->UPB_PRIVATE(size) == 0) {
+ return;
+ }
+
+#define VARINT_CASE(ctype, encode) \
+ { \
+ const ctype* start = _upb_array_constptr(arr); \
+ const ctype* ptr = start + arr->UPB_PRIVATE(size); \
+ uint32_t tag = \
+ packed ? 0 : (f->UPB_PRIVATE(number) << 3) | kUpb_WireType_Varint; \
+ do { \
+ ptr--; \
+ encode_varint(e, encode); \
+ if (tag) encode_varint(e, tag); \
+ } while (ptr != start); \
+ } \
+ break;
+
+#define TAG(wire_type) (packed ? 0 : (f->UPB_PRIVATE(number) << 3 | wire_type))
+
+ switch (f->UPB_PRIVATE(descriptortype)) {
+ case kUpb_FieldType_Double:
+ encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit));
+ break;
+ case kUpb_FieldType_Float:
+ encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit));
+ break;
+ case kUpb_FieldType_SFixed64:
+ case kUpb_FieldType_Fixed64:
+ encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit));
+ break;
+ case kUpb_FieldType_Fixed32:
+ case kUpb_FieldType_SFixed32:
+ encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit));
+ break;
+ case kUpb_FieldType_Int64:
+ case kUpb_FieldType_UInt64:
+ VARINT_CASE(uint64_t, *ptr);
+ case kUpb_FieldType_UInt32:
+ VARINT_CASE(uint32_t, *ptr);
+ case kUpb_FieldType_Int32:
+ case kUpb_FieldType_Enum:
+ VARINT_CASE(int32_t, (int64_t)*ptr);
+ case kUpb_FieldType_Bool:
+ VARINT_CASE(bool, *ptr);
+ case kUpb_FieldType_SInt32:
+ VARINT_CASE(int32_t, encode_zz32(*ptr));
+ case kUpb_FieldType_SInt64:
+ VARINT_CASE(int64_t, encode_zz64(*ptr));
+ case kUpb_FieldType_String:
+ case kUpb_FieldType_Bytes: {
+ const upb_StringView* start = _upb_array_constptr(arr);
+ const upb_StringView* ptr = start + arr->UPB_PRIVATE(size);
+ do {
+ ptr--;
+ encode_bytes(e, ptr->data, ptr->size);
+ encode_varint(e, ptr->size);
+ encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited);
+ } while (ptr != start);
+ return;
+ }
+ case kUpb_FieldType_Group: {
+ const upb_TaggedMessagePtr* start = _upb_array_constptr(arr);
+ const upb_TaggedMessagePtr* ptr = start + arr->UPB_PRIVATE(size);
+ const upb_MiniTable* subm =
+ upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
+ if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
+ do {
+ size_t size;
+ ptr--;
+ encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_EndGroup);
+ encode_TaggedMessagePtr(e, *ptr, subm, &size);
+ encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_StartGroup);
+ } while (ptr != start);
+ e->depth++;
+ return;
+ }
+ case kUpb_FieldType_Message: {
+ const upb_TaggedMessagePtr* start = _upb_array_constptr(arr);
+ const upb_TaggedMessagePtr* ptr = start + arr->UPB_PRIVATE(size);
+ const upb_MiniTable* subm =
+ upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
+ if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
+ do {
+ size_t size;
+ ptr--;
+ encode_TaggedMessagePtr(e, *ptr, subm, &size);
+ encode_varint(e, size);
+ encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited);
+ } while (ptr != start);
+ e->depth++;
+ return;
+ }
+ }
+#undef VARINT_CASE
+
+ if (packed) {
+ encode_varint(e, e->limit - e->ptr - pre_len);
+ encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited);
+ }
+}
+
+static void encode_mapentry(upb_encstate* e, uint32_t number,
+ const upb_MiniTable* layout,
+ const upb_MapEntry* ent) {
+ const upb_MiniTableField* key_field = &layout->UPB_PRIVATE(fields)[0];
+ const upb_MiniTableField* val_field = &layout->UPB_PRIVATE(fields)[1];
+ size_t pre_len = e->limit - e->ptr;
+ size_t size;
+ encode_scalar(e, &ent->data.v, layout->UPB_PRIVATE(subs), val_field);
+ encode_scalar(e, &ent->data.k, layout->UPB_PRIVATE(subs), key_field);
+ size = (e->limit - e->ptr) - pre_len;
+ encode_varint(e, size);
+ encode_tag(e, number, kUpb_WireType_Delimited);
+}
+
+static void encode_map(upb_encstate* e, const upb_Message* msg,
+ const upb_MiniTableSub* subs,
+ const upb_MiniTableField* f) {
+ const upb_Map* map = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), const upb_Map*);
+ const upb_MiniTable* layout =
+ upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
+ UPB_ASSERT(layout->UPB_PRIVATE(field_count) == 2);
+
+ if (map == NULL) return;
+
+ if (e->options & kUpb_EncodeOption_Deterministic) {
+ _upb_sortedmap sorted;
+ _upb_mapsorter_pushmap(
+ &e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype),
+ map, &sorted);
+ upb_MapEntry ent;
+ while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
+ encode_mapentry(e, f->UPB_PRIVATE(number), layout, &ent);
+ }
+ _upb_mapsorter_popmap(&e->sorter, &sorted);
+ } else {
+ 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.data.k, map->key_size);
+ _upb_map_fromvalue(val, &ent.data.v, map->val_size);
+ encode_mapentry(e, f->UPB_PRIVATE(number), layout, &ent);
+ }
+ }
+}
+
+static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg,
+ 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->UPB_PRIVATE(offset), void);
+ switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) {
+ case kUpb_FieldRep_1Byte: {
+ char ch;
+ memcpy(&ch, mem, 1);
+ return ch != 0;
+ }
+ case kUpb_FieldRep_4Byte: {
+ uint32_t u32;
+ memcpy(&u32, mem, 4);
+ return u32 != 0;
+ }
+ case kUpb_FieldRep_8Byte: {
+ uint64_t u64;
+ memcpy(&u64, mem, 8);
+ return u64 != 0;
+ }
+ case kUpb_FieldRep_StringView: {
+ const upb_StringView* str = (const upb_StringView*)mem;
+ return str->size != 0;
+ }
+ default:
+ UPB_UNREACHABLE();
+ }
+ } else if (f->presence > 0) {
+ // Proto2 presence: hasbit.
+ return UPB_PRIVATE(_upb_Message_GetHasbit)(msg, f);
+ } else {
+ // Field is in a oneof.
+ return UPB_PRIVATE(_upb_Message_GetOneofCase)(msg, f) ==
+ f->UPB_PRIVATE(number);
+ }
+}
+
+static void encode_field(upb_encstate* e, const upb_Message* msg,
+ const upb_MiniTableSub* subs,
+ const upb_MiniTableField* field) {
+ switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) {
+ case kUpb_FieldMode_Array:
+ encode_array(e, msg, subs, field);
+ break;
+ case kUpb_FieldMode_Map:
+ encode_map(e, msg, subs, field);
+ break;
+ case kUpb_FieldMode_Scalar:
+ encode_scalar(e, UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void), subs,
+ field);
+ break;
+ default:
+ UPB_UNREACHABLE();
+ }
+}
+
+static void encode_msgset_item(upb_encstate* e, const upb_Extension* ext) {
+ size_t size;
+ encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_EndGroup);
+ encode_message(e, ext->data.ptr,
+ upb_MiniTableExtension_GetSubMessage(ext->ext), &size);
+ encode_varint(e, size);
+ encode_tag(e, kUpb_MsgSet_Message, kUpb_WireType_Delimited);
+ encode_varint(e, upb_MiniTableExtension_Number(ext->ext));
+ encode_tag(e, kUpb_MsgSet_TypeId, kUpb_WireType_Varint);
+ encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup);
+}
+
+static void encode_ext(upb_encstate* e, const upb_Extension* ext,
+ bool is_message_set) {
+ if (UPB_UNLIKELY(is_message_set)) {
+ encode_msgset_item(e, ext);
+ } else {
+ encode_field(e, (upb_Message*)&ext->data, &ext->ext->UPB_PRIVATE(sub),
+ &ext->ext->UPB_PRIVATE(field));
+ }
+}
+
+static void encode_message(upb_encstate* e, const upb_Message* msg,
+ const upb_MiniTable* m, size_t* size) {
+ size_t pre_len = e->limit - e->ptr;
+
+ if ((e->options & kUpb_EncodeOption_CheckRequired) &&
+ m->UPB_PRIVATE(required_count)) {
+ uint64_t msg_head;
+ memcpy(&msg_head, msg, 8);
+ msg_head = UPB_PRIVATE(_upb_BigEndian64)(msg_head);
+ if (UPB_PRIVATE(_upb_MiniTable_RequiredMask)(m) & ~msg_head) {
+ encode_err(e, kUpb_EncodeStatus_MissingRequired);
+ }
+ }
+
+ if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) {
+ size_t unknown_size;
+ const char* unknown = upb_Message_GetUnknown(msg, &unknown_size);
+
+ if (unknown) {
+ encode_bytes(e, unknown, unknown_size);
+ }
+ }
+
+ if (m->UPB_PRIVATE(ext) != kUpb_ExtMode_NonExtendable) {
+ /* Encode all extensions together. Unlike C++, we do not attempt to keep
+ * these in field number order relative to normal fields or even to each
+ * other. */
+ size_t ext_count;
+ const upb_Extension* ext =
+ UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count);
+ if (ext_count) {
+ if (e->options & kUpb_EncodeOption_Deterministic) {
+ _upb_sortedmap sorted;
+ _upb_mapsorter_pushexts(&e->sorter, ext, ext_count, &sorted);
+ while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
+ encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
+ }
+ _upb_mapsorter_popmap(&e->sorter, &sorted);
+ } else {
+ const upb_Extension* end = ext + ext_count;
+ for (; ext != end; ext++) {
+ encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
+ }
+ }
+ }
+ }
+
+ if (m->UPB_PRIVATE(field_count)) {
+ const upb_MiniTableField* f =
+ &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)];
+ const upb_MiniTableField* first = &m->UPB_PRIVATE(fields)[0];
+ while (f != first) {
+ f--;
+ if (encode_shouldencode(e, msg, m->UPB_PRIVATE(subs), f)) {
+ encode_field(e, msg, m->UPB_PRIVATE(subs), f);
+ }
+ }
+ }
+
+ *size = (e->limit - e->ptr) - pre_len;
+}
+
+static upb_EncodeStatus upb_Encoder_Encode(upb_encstate* const encoder,
+ const upb_Message* const msg,
+ const upb_MiniTable* const l,
+ char** const buf,
+ size_t* const size) {
+ // Unfortunately we must continue to perform hackery here because there are
+ // code paths which blindly copy the returned pointer without bothering to
+ // check for errors until much later (b/235839510). So we still set *buf to
+ // NULL on error and we still set it to non-NULL on a successful empty result.
+ if (UPB_SETJMP(encoder->err) == 0) {
+ encode_message(encoder, msg, l, size);
+ *size = encoder->limit - encoder->ptr;
+ if (*size == 0) {
+ static char ch;
+ *buf = &ch;
+ } else {
+ UPB_ASSERT(encoder->ptr);
+ *buf = encoder->ptr;
+ }
+ } else {
+ UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok);
+ *buf = NULL;
+ *size = 0;
+ }
+
+ _upb_mapsorter_destroy(&encoder->sorter);
+ return encoder->status;
+}
+
+upb_EncodeStatus upb_Encode(const upb_Message* msg, const upb_MiniTable* l,
+ int options, upb_Arena* arena, char** buf,
+ size_t* size) {
+ upb_encstate e;
+ unsigned depth = (unsigned)options >> 16;
+
+ e.status = kUpb_EncodeStatus_Ok;
+ e.arena = arena;
+ e.buf = NULL;
+ e.limit = NULL;
+ e.ptr = NULL;
+ e.depth = depth ? depth : kUpb_WireFormat_DefaultDepthLimit;
+ e.options = options;
+ _upb_mapsorter_init(&e.sorter);
+
+ return upb_Encoder_Encode(&e, msg, l, buf, size);
+}
+
// Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64.
// Also the table size grows by 2x.
//
@@ -14648,633 +15268,16 @@
#endif /* UPB_FASTTABLE */
-// We encode backwards, to avoid pre-computing lengths (one-pass encode).
-
-#include <setjmp.h>
-#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
-#include <string.h>
// Must be last.
-#define UPB_PB_VARINT_MAX_LEN 10
-
-UPB_NOINLINE
-static size_t encode_varint64(uint64_t val, char* buf) {
- size_t i = 0;
- do {
- uint8_t byte = val & 0x7fU;
- val >>= 7;
- if (val) byte |= 0x80U;
- buf[i++] = byte;
- } while (val);
- return i;
-}
-
-static uint32_t encode_zz32(int32_t n) {
- return ((uint32_t)n << 1) ^ (n >> 31);
-}
-static uint64_t encode_zz64(int64_t n) {
- return ((uint64_t)n << 1) ^ (n >> 63);
-}
-
-typedef struct {
- upb_EncodeStatus status;
- jmp_buf err;
- upb_Arena* arena;
- char *buf, *ptr, *limit;
- int options;
- int depth;
- _upb_mapsorter sorter;
-} upb_encstate;
-
-static size_t upb_roundup_pow2(size_t bytes) {
- size_t ret = 128;
- while (ret < bytes) {
- ret *= 2;
- }
- return ret;
-}
-
-UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) {
- UPB_ASSERT(s != kUpb_EncodeStatus_Ok);
- e->status = s;
- UPB_LONGJMP(e->err, 1);
-}
-
-UPB_NOINLINE
-static void encode_growbuffer(upb_encstate* e, size_t bytes) {
- size_t old_size = e->limit - e->buf;
- size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr));
- char* new_buf = upb_Arena_Realloc(e->arena, e->buf, old_size, new_size);
-
- if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory);
-
- // We want previous data at the end, realloc() put it at the beginning.
- // TODO: This is somewhat inefficient since we are copying twice.
- // Maybe create a realloc() that copies to the end of the new buffer?
- if (old_size > 0) {
- memmove(new_buf + new_size - old_size, e->buf, old_size);
- }
-
- e->ptr = new_buf + new_size - (e->limit - e->ptr);
- e->limit = new_buf + new_size;
- e->buf = new_buf;
-
- e->ptr -= bytes;
-}
-
-/* Call to ensure that at least "bytes" bytes are available for writing at
- * e->ptr. Returns false if the bytes could not be allocated. */
-UPB_FORCEINLINE
-static void encode_reserve(upb_encstate* e, size_t bytes) {
- if ((size_t)(e->ptr - e->buf) < bytes) {
- encode_growbuffer(e, bytes);
- return;
- }
-
- e->ptr -= bytes;
-}
-
-/* Writes the given bytes to the buffer, handling reserve/advance. */
-static void encode_bytes(upb_encstate* e, const void* data, size_t len) {
- if (len == 0) return; /* memcpy() with zero size is UB */
- encode_reserve(e, len);
- memcpy(e->ptr, data, len);
-}
-
-static void encode_fixed64(upb_encstate* e, uint64_t val) {
- val = _upb_BigEndian_Swap64(val);
- encode_bytes(e, &val, sizeof(uint64_t));
-}
-
-static void encode_fixed32(upb_encstate* e, uint32_t val) {
- val = _upb_BigEndian_Swap32(val);
- encode_bytes(e, &val, sizeof(uint32_t));
-}
-
-UPB_NOINLINE
-static void encode_longvarint(upb_encstate* e, uint64_t val) {
- size_t len;
- char* start;
-
- encode_reserve(e, UPB_PB_VARINT_MAX_LEN);
- len = encode_varint64(val, e->ptr);
- start = e->ptr + UPB_PB_VARINT_MAX_LEN - len;
- memmove(start, e->ptr, len);
- e->ptr = start;
-}
-
-UPB_FORCEINLINE
-static void encode_varint(upb_encstate* e, uint64_t val) {
- if (val < 128 && e->ptr != e->buf) {
- --e->ptr;
- *e->ptr = val;
- } else {
- encode_longvarint(e, val);
- }
-}
-
-static void encode_double(upb_encstate* e, double d) {
- uint64_t u64;
- UPB_ASSERT(sizeof(double) == sizeof(uint64_t));
- memcpy(&u64, &d, sizeof(uint64_t));
- encode_fixed64(e, u64);
-}
-
-static void encode_float(upb_encstate* e, float d) {
- uint32_t u32;
- UPB_ASSERT(sizeof(float) == sizeof(uint32_t));
- memcpy(&u32, &d, sizeof(uint32_t));
- encode_fixed32(e, u32);
-}
-
-static void encode_tag(upb_encstate* e, uint32_t field_number,
- uint8_t wire_type) {
- encode_varint(e, (field_number << 3) | wire_type);
-}
-
-static void encode_fixedarray(upb_encstate* e, const upb_Array* arr,
- size_t elem_size, uint32_t tag) {
- size_t bytes = arr->UPB_PRIVATE(size) * elem_size;
- const char* data = _upb_array_constptr(arr);
- const char* ptr = data + bytes - elem_size;
-
- if (tag || !_upb_IsLittleEndian()) {
- while (true) {
- if (elem_size == 4) {
- uint32_t val;
- memcpy(&val, ptr, sizeof(val));
- val = _upb_BigEndian_Swap32(val);
- encode_bytes(e, &val, elem_size);
- } else {
- UPB_ASSERT(elem_size == 8);
- uint64_t val;
- memcpy(&val, ptr, sizeof(val));
- val = _upb_BigEndian_Swap64(val);
- encode_bytes(e, &val, elem_size);
- }
-
- if (tag) encode_varint(e, tag);
- if (ptr == data) break;
- ptr -= elem_size;
- }
- } else {
- encode_bytes(e, data, bytes);
- }
-}
-
-static void encode_message(upb_encstate* e, const upb_Message* msg,
- const upb_MiniTable* m, size_t* size);
-
-static void encode_TaggedMessagePtr(upb_encstate* e,
- upb_TaggedMessagePtr tagged,
- const upb_MiniTable* m, size_t* size) {
- if (upb_TaggedMessagePtr_IsEmpty(tagged)) {
- m = UPB_PRIVATE(_upb_MiniTable_Empty)();
- }
- encode_message(e, _upb_TaggedMessagePtr_GetMessage(tagged), m, size);
-}
-
-static void encode_scalar(upb_encstate* e, const void* _field_mem,
- const upb_MiniTableSub* subs,
- const upb_MiniTableField* f) {
- const char* field_mem = _field_mem;
- int wire_type;
-
-#define CASE(ctype, type, wtype, encodeval) \
- { \
- ctype val = *(ctype*)field_mem; \
- encode_##type(e, encodeval); \
- wire_type = wtype; \
- break; \
- }
-
- switch (f->UPB_PRIVATE(descriptortype)) {
- case kUpb_FieldType_Double:
- CASE(double, double, kUpb_WireType_64Bit, val);
- case kUpb_FieldType_Float:
- CASE(float, float, kUpb_WireType_32Bit, val);
- case kUpb_FieldType_Int64:
- case kUpb_FieldType_UInt64:
- CASE(uint64_t, varint, kUpb_WireType_Varint, val);
- case kUpb_FieldType_UInt32:
- CASE(uint32_t, varint, kUpb_WireType_Varint, val);
- case kUpb_FieldType_Int32:
- case kUpb_FieldType_Enum:
- CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val);
- case kUpb_FieldType_SFixed64:
- case kUpb_FieldType_Fixed64:
- CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val);
- case kUpb_FieldType_Fixed32:
- case kUpb_FieldType_SFixed32:
- CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val);
- case kUpb_FieldType_Bool:
- CASE(bool, varint, kUpb_WireType_Varint, val);
- case kUpb_FieldType_SInt32:
- CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val));
- case kUpb_FieldType_SInt64:
- CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val));
- case kUpb_FieldType_String:
- case kUpb_FieldType_Bytes: {
- upb_StringView view = *(upb_StringView*)field_mem;
- encode_bytes(e, view.data, view.size);
- encode_varint(e, view.size);
- wire_type = kUpb_WireType_Delimited;
- break;
- }
- case kUpb_FieldType_Group: {
- size_t size;
- upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem;
- const upb_MiniTable* subm =
- upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
- if (submsg == 0) {
- return;
- }
- if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
- encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_EndGroup);
- encode_TaggedMessagePtr(e, submsg, subm, &size);
- wire_type = kUpb_WireType_StartGroup;
- e->depth++;
- break;
- }
- case kUpb_FieldType_Message: {
- size_t size;
- upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem;
- const upb_MiniTable* subm =
- upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
- if (submsg == 0) {
- return;
- }
- if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
- encode_TaggedMessagePtr(e, submsg, subm, &size);
- encode_varint(e, size);
- wire_type = kUpb_WireType_Delimited;
- e->depth++;
- break;
- }
- default:
- UPB_UNREACHABLE();
- }
-#undef CASE
-
- encode_tag(e, f->UPB_PRIVATE(number), wire_type);
-}
-
-static void encode_array(upb_encstate* e, const upb_Message* msg,
- const upb_MiniTableSub* subs,
- const upb_MiniTableField* f) {
- const upb_Array* arr = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), upb_Array*);
- bool packed = upb_MiniTableField_IsPacked(f);
- size_t pre_len = e->limit - e->ptr;
-
- if (arr == NULL || arr->UPB_PRIVATE(size) == 0) {
- return;
- }
-
-#define VARINT_CASE(ctype, encode) \
- { \
- const ctype* start = _upb_array_constptr(arr); \
- const ctype* ptr = start + arr->UPB_PRIVATE(size); \
- uint32_t tag = \
- packed ? 0 : (f->UPB_PRIVATE(number) << 3) | kUpb_WireType_Varint; \
- do { \
- ptr--; \
- encode_varint(e, encode); \
- if (tag) encode_varint(e, tag); \
- } while (ptr != start); \
- } \
- break;
-
-#define TAG(wire_type) (packed ? 0 : (f->UPB_PRIVATE(number) << 3 | wire_type))
-
- switch (f->UPB_PRIVATE(descriptortype)) {
- case kUpb_FieldType_Double:
- encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit));
- break;
- case kUpb_FieldType_Float:
- encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit));
- break;
- case kUpb_FieldType_SFixed64:
- case kUpb_FieldType_Fixed64:
- encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit));
- break;
- case kUpb_FieldType_Fixed32:
- case kUpb_FieldType_SFixed32:
- encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit));
- break;
- case kUpb_FieldType_Int64:
- case kUpb_FieldType_UInt64:
- VARINT_CASE(uint64_t, *ptr);
- case kUpb_FieldType_UInt32:
- VARINT_CASE(uint32_t, *ptr);
- case kUpb_FieldType_Int32:
- case kUpb_FieldType_Enum:
- VARINT_CASE(int32_t, (int64_t)*ptr);
- case kUpb_FieldType_Bool:
- VARINT_CASE(bool, *ptr);
- case kUpb_FieldType_SInt32:
- VARINT_CASE(int32_t, encode_zz32(*ptr));
- case kUpb_FieldType_SInt64:
- VARINT_CASE(int64_t, encode_zz64(*ptr));
- case kUpb_FieldType_String:
- case kUpb_FieldType_Bytes: {
- const upb_StringView* start = _upb_array_constptr(arr);
- const upb_StringView* ptr = start + arr->UPB_PRIVATE(size);
- do {
- ptr--;
- encode_bytes(e, ptr->data, ptr->size);
- encode_varint(e, ptr->size);
- encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited);
- } while (ptr != start);
- return;
- }
- case kUpb_FieldType_Group: {
- const upb_TaggedMessagePtr* start = _upb_array_constptr(arr);
- const upb_TaggedMessagePtr* ptr = start + arr->UPB_PRIVATE(size);
- const upb_MiniTable* subm =
- upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
- if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
- do {
- size_t size;
- ptr--;
- encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_EndGroup);
- encode_TaggedMessagePtr(e, *ptr, subm, &size);
- encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_StartGroup);
- } while (ptr != start);
- e->depth++;
- return;
- }
- case kUpb_FieldType_Message: {
- const upb_TaggedMessagePtr* start = _upb_array_constptr(arr);
- const upb_TaggedMessagePtr* ptr = start + arr->UPB_PRIVATE(size);
- const upb_MiniTable* subm =
- upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
- if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded);
- do {
- size_t size;
- ptr--;
- encode_TaggedMessagePtr(e, *ptr, subm, &size);
- encode_varint(e, size);
- encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited);
- } while (ptr != start);
- e->depth++;
- return;
- }
- }
-#undef VARINT_CASE
-
- if (packed) {
- encode_varint(e, e->limit - e->ptr - pre_len);
- encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited);
- }
-}
-
-static void encode_mapentry(upb_encstate* e, uint32_t number,
- const upb_MiniTable* layout,
- const upb_MapEntry* ent) {
- const upb_MiniTableField* key_field = &layout->UPB_PRIVATE(fields)[0];
- const upb_MiniTableField* val_field = &layout->UPB_PRIVATE(fields)[1];
- size_t pre_len = e->limit - e->ptr;
- size_t size;
- encode_scalar(e, &ent->data.v, layout->UPB_PRIVATE(subs), val_field);
- encode_scalar(e, &ent->data.k, layout->UPB_PRIVATE(subs), key_field);
- size = (e->limit - e->ptr) - pre_len;
- encode_varint(e, size);
- encode_tag(e, number, kUpb_WireType_Delimited);
-}
-
-static void encode_map(upb_encstate* e, const upb_Message* msg,
- const upb_MiniTableSub* subs,
- const upb_MiniTableField* f) {
- const upb_Map* map = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), const upb_Map*);
- const upb_MiniTable* layout =
- upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]);
- UPB_ASSERT(layout->UPB_PRIVATE(field_count) == 2);
-
- if (map == NULL) return;
-
- if (e->options & kUpb_EncodeOption_Deterministic) {
- _upb_sortedmap sorted;
- _upb_mapsorter_pushmap(
- &e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype),
- map, &sorted);
- upb_MapEntry ent;
- while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
- encode_mapentry(e, f->UPB_PRIVATE(number), layout, &ent);
- }
- _upb_mapsorter_popmap(&e->sorter, &sorted);
- } else {
- 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.data.k, map->key_size);
- _upb_map_fromvalue(val, &ent.data.v, map->val_size);
- encode_mapentry(e, f->UPB_PRIVATE(number), layout, &ent);
- }
- }
-}
-
-static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg,
- 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->UPB_PRIVATE(offset), void);
- switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) {
- case kUpb_FieldRep_1Byte: {
- char ch;
- memcpy(&ch, mem, 1);
- return ch != 0;
- }
- case kUpb_FieldRep_4Byte: {
- uint32_t u32;
- memcpy(&u32, mem, 4);
- return u32 != 0;
- }
- case kUpb_FieldRep_8Byte: {
- uint64_t u64;
- memcpy(&u64, mem, 8);
- return u64 != 0;
- }
- case kUpb_FieldRep_StringView: {
- const upb_StringView* str = (const upb_StringView*)mem;
- return str->size != 0;
- }
- default:
- UPB_UNREACHABLE();
- }
- } else if (f->presence > 0) {
- // Proto2 presence: hasbit.
- return UPB_PRIVATE(_upb_Message_GetHasbit)(msg, f);
- } else {
- // Field is in a oneof.
- return UPB_PRIVATE(_upb_Message_GetOneofCase)(msg, f) ==
- f->UPB_PRIVATE(number);
- }
-}
-
-static void encode_field(upb_encstate* e, const upb_Message* msg,
- const upb_MiniTableSub* subs,
- const upb_MiniTableField* field) {
- switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) {
- case kUpb_FieldMode_Array:
- encode_array(e, msg, subs, field);
- break;
- case kUpb_FieldMode_Map:
- encode_map(e, msg, subs, field);
- break;
- case kUpb_FieldMode_Scalar:
- encode_scalar(e, UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void), subs,
- field);
- break;
- default:
- UPB_UNREACHABLE();
- }
-}
-
-static void encode_msgset_item(upb_encstate* e, const upb_Extension* ext) {
- size_t size;
- encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_EndGroup);
- encode_message(e, ext->data.ptr,
- upb_MiniTableExtension_GetSubMessage(ext->ext), &size);
- encode_varint(e, size);
- encode_tag(e, kUpb_MsgSet_Message, kUpb_WireType_Delimited);
- encode_varint(e, upb_MiniTableExtension_Number(ext->ext));
- encode_tag(e, kUpb_MsgSet_TypeId, kUpb_WireType_Varint);
- encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup);
-}
-
-static void encode_ext(upb_encstate* e, const upb_Extension* ext,
- bool is_message_set) {
- if (UPB_UNLIKELY(is_message_set)) {
- encode_msgset_item(e, ext);
- } else {
- encode_field(e, (upb_Message*)&ext->data, &ext->ext->UPB_PRIVATE(sub),
- &ext->ext->UPB_PRIVATE(field));
- }
-}
-
-static void encode_message(upb_encstate* e, const upb_Message* msg,
- const upb_MiniTable* m, size_t* size) {
- size_t pre_len = e->limit - e->ptr;
-
- if ((e->options & kUpb_EncodeOption_CheckRequired) &&
- m->UPB_PRIVATE(required_count)) {
- uint64_t msg_head;
- memcpy(&msg_head, msg, 8);
- msg_head = _upb_BigEndian_Swap64(msg_head);
- if (UPB_PRIVATE(_upb_MiniTable_RequiredMask)(m) & ~msg_head) {
- encode_err(e, kUpb_EncodeStatus_MissingRequired);
- }
- }
-
- if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) {
- size_t unknown_size;
- const char* unknown = upb_Message_GetUnknown(msg, &unknown_size);
-
- if (unknown) {
- encode_bytes(e, unknown, unknown_size);
- }
- }
-
- if (m->UPB_PRIVATE(ext) != kUpb_ExtMode_NonExtendable) {
- /* Encode all extensions together. Unlike C++, we do not attempt to keep
- * these in field number order relative to normal fields or even to each
- * other. */
- size_t ext_count;
- const upb_Extension* ext =
- UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count);
- if (ext_count) {
- if (e->options & kUpb_EncodeOption_Deterministic) {
- _upb_sortedmap sorted;
- _upb_mapsorter_pushexts(&e->sorter, ext, ext_count, &sorted);
- while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
- encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
- }
- _upb_mapsorter_popmap(&e->sorter, &sorted);
- } else {
- const upb_Extension* end = ext + ext_count;
- for (; ext != end; ext++) {
- encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
- }
- }
- }
- }
-
- if (m->UPB_PRIVATE(field_count)) {
- const upb_MiniTableField* f =
- &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)];
- const upb_MiniTableField* first = &m->UPB_PRIVATE(fields)[0];
- while (f != first) {
- f--;
- if (encode_shouldencode(e, msg, m->UPB_PRIVATE(subs), f)) {
- encode_field(e, msg, m->UPB_PRIVATE(subs), f);
- }
- }
- }
-
- *size = (e->limit - e->ptr) - pre_len;
-}
-
-static upb_EncodeStatus upb_Encoder_Encode(upb_encstate* const encoder,
- const upb_Message* const msg,
- const upb_MiniTable* const l,
- char** const buf,
- size_t* const size) {
- // Unfortunately we must continue to perform hackery here because there are
- // code paths which blindly copy the returned pointer without bothering to
- // check for errors until much later (b/235839510). So we still set *buf to
- // NULL on error and we still set it to non-NULL on a successful empty result.
- if (UPB_SETJMP(encoder->err) == 0) {
- encode_message(encoder, msg, l, size);
- *size = encoder->limit - encoder->ptr;
- if (*size == 0) {
- static char ch;
- *buf = &ch;
- } else {
- UPB_ASSERT(encoder->ptr);
- *buf = encoder->ptr;
- }
- } else {
- UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok);
- *buf = NULL;
- *size = 0;
- }
-
- _upb_mapsorter_destroy(&encoder->sorter);
- return encoder->status;
-}
-
-upb_EncodeStatus upb_Encode(const upb_Message* msg, const upb_MiniTable* l,
- int options, upb_Arena* arena, char** buf,
- size_t* size) {
- upb_encstate e;
- unsigned depth = (unsigned)options >> 16;
-
- e.status = kUpb_EncodeStatus_Ok;
- e.arena = arena;
- e.buf = NULL;
- e.limit = NULL;
- e.ptr = NULL;
- e.depth = depth ? depth : kUpb_WireFormat_DefaultDepthLimit;
- e.options = options;
- _upb_mapsorter_init(&e.sorter);
-
- return upb_Encoder_Encode(&e, msg, l, buf, size);
-}
-
-
-
-// Must be last.
-
-UPB_NOINLINE _upb_WireReader_ReadLongVarintRet
-_upb_WireReader_ReadLongVarint(const char* ptr, uint64_t val) {
- _upb_WireReader_ReadLongVarintRet ret = {NULL, 0};
+UPB_NOINLINE UPB_PRIVATE(_upb_WireReader_LongVarint)
+ UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val) {
+ UPB_PRIVATE(_upb_WireReader_LongVarint) ret = {NULL, 0};
uint64_t byte;
int i;
for (i = 1; i < 10; i++) {
@@ -15289,9 +15292,9 @@
return ret;
}
-const char* _upb_WireReader_SkipGroup(const char* ptr, uint32_t tag,
- int depth_limit,
- upb_EpsCopyInputStream* stream) {
+const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)(
+ const char* ptr, uint32_t tag, int depth_limit,
+ upb_EpsCopyInputStream* stream) {
if (--depth_limit == 0) return NULL;
uint32_t end_group_tag = (tag & ~7ULL) | kUpb_WireType_EndGroup;
while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) {
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h
index 005e234..d644416 100755
--- a/ruby/ext/google/protobuf_c/ruby-upb.h
+++ b/ruby/ext/google/protobuf_c/ruby-upb.h
@@ -1356,8 +1356,9 @@
// Must be last.
struct upb_Decoder;
+struct upb_Message;
typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr,
- upb_Message* msg, intptr_t table,
+ struct upb_Message* msg, intptr_t table,
uint64_t hasbits, uint64_t data);
typedef struct {
uint64_t field_data;
@@ -4006,6 +4007,72 @@
#endif /* UPB_WIRE_DECODE_H_ */
+// upb_Encode: parsing from a upb_Message using a upb_MiniTable.
+
+#ifndef UPB_WIRE_ENCODE_H_
+#define UPB_WIRE_ENCODE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+// Must be last.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ /* If set, the results of serializing will be deterministic across all
+ * instances of this binary. There are no guarantees across different
+ * binary builds.
+ *
+ * If your proto contains maps, the encoder will need to malloc()/free()
+ * memory during encode. */
+ kUpb_EncodeOption_Deterministic = 1,
+
+ // When set, unknown fields are not printed.
+ kUpb_EncodeOption_SkipUnknown = 2,
+
+ // When set, the encode will fail if any required fields are missing.
+ kUpb_EncodeOption_CheckRequired = 4,
+};
+
+typedef enum {
+ kUpb_EncodeStatus_Ok = 0,
+ kUpb_EncodeStatus_OutOfMemory = 1, // Arena alloc failed
+ kUpb_EncodeStatus_MaxDepthExceeded = 2,
+
+ // kUpb_EncodeOption_CheckRequired failed but the parse otherwise succeeded.
+ kUpb_EncodeStatus_MissingRequired = 3,
+} upb_EncodeStatus;
+
+UPB_INLINE uint32_t upb_EncodeOptions_MaxDepth(uint16_t depth) {
+ return (uint32_t)depth << 16;
+}
+
+UPB_INLINE uint16_t upb_EncodeOptions_GetMaxDepth(uint32_t options) {
+ return options >> 16;
+}
+
+// Enforce an upper bound on recursion depth.
+UPB_INLINE int upb_Encode_LimitDepth(uint32_t encode_options, uint32_t limit) {
+ uint32_t max_depth = upb_EncodeOptions_GetMaxDepth(encode_options);
+ if (max_depth > limit) max_depth = limit;
+ return upb_EncodeOptions_MaxDepth(max_depth) | (encode_options & 0xffff);
+}
+
+UPB_API upb_EncodeStatus upb_Encode(const upb_Message* msg,
+ const upb_MiniTable* l, int options,
+ upb_Arena* arena, char** buf, size_t* size);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif /* UPB_WIRE_ENCODE_H_ */
+
// These are the specialized field parser functions for the fast parser.
// Generated tables will refer to these by name.
//
@@ -4040,8 +4107,8 @@
// - '1' for one-byte tags (field numbers 1-15)
// - '2' for two-byte tags (field numbers 16-2048)
-#ifndef UPB_WIRE_DECODE_FAST_H_
-#define UPB_WIRE_DECODE_FAST_H_
+#ifndef UPB_WIRE_DECODE_INTERNAL_FAST_H_
+#define UPB_WIRE_DECODE_INTERNAL_FAST_H_
// Must be last.
@@ -4142,73 +4209,7 @@
#endif
-#endif /* UPB_WIRE_DECODE_FAST_H_ */
-
-// upb_Encode: parsing from a upb_Message using a upb_MiniTable.
-
-#ifndef UPB_WIRE_ENCODE_H_
-#define UPB_WIRE_ENCODE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-
-// Must be last.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum {
- /* If set, the results of serializing will be deterministic across all
- * instances of this binary. There are no guarantees across different
- * binary builds.
- *
- * If your proto contains maps, the encoder will need to malloc()/free()
- * memory during encode. */
- kUpb_EncodeOption_Deterministic = 1,
-
- // When set, unknown fields are not printed.
- kUpb_EncodeOption_SkipUnknown = 2,
-
- // When set, the encode will fail if any required fields are missing.
- kUpb_EncodeOption_CheckRequired = 4,
-};
-
-typedef enum {
- kUpb_EncodeStatus_Ok = 0,
- kUpb_EncodeStatus_OutOfMemory = 1, // Arena alloc failed
- kUpb_EncodeStatus_MaxDepthExceeded = 2,
-
- // kUpb_EncodeOption_CheckRequired failed but the parse otherwise succeeded.
- kUpb_EncodeStatus_MissingRequired = 3,
-} upb_EncodeStatus;
-
-UPB_INLINE uint32_t upb_EncodeOptions_MaxDepth(uint16_t depth) {
- return (uint32_t)depth << 16;
-}
-
-UPB_INLINE uint16_t upb_EncodeOptions_GetMaxDepth(uint32_t options) {
- return options >> 16;
-}
-
-// Enforce an upper bound on recursion depth.
-UPB_INLINE int upb_Encode_LimitDepth(uint32_t encode_options, uint32_t limit) {
- uint32_t max_depth = upb_EncodeOptions_GetMaxDepth(encode_options);
- if (max_depth > limit) max_depth = limit;
- return upb_EncodeOptions_MaxDepth(max_depth) | (encode_options & 0xffff);
-}
-
-UPB_API upb_EncodeStatus upb_Encode(const upb_Message* msg,
- const upb_MiniTable* l, int options,
- upb_Arena* arena, char** buf, size_t* size);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-
-#endif /* UPB_WIRE_ENCODE_H_ */
+#endif /* UPB_WIRE_DECODE_INTERNAL_FAST_H_ */
// IWYU pragma: end_exports
#endif // UPB_GENERATED_CODE_SUPPORT_H_
@@ -13533,8 +13534,8 @@
#endif /* UPB_WIRE_INTERNAL_DECODE_H_ */
-#ifndef UPB_WIRE_INTERNAL_SWAP_H_
-#define UPB_WIRE_INTERNAL_SWAP_H_
+#ifndef UPB_WIRE_INTERNAL_ENDIAN_H_
+#define UPB_WIRE_INTERNAL_ENDIAN_H_
#include <stdint.h>
@@ -13544,23 +13545,23 @@
extern "C" {
#endif
-UPB_INLINE bool _upb_IsLittleEndian(void) {
- int x = 1;
+UPB_INLINE bool UPB_PRIVATE(_upb_IsLittleEndian)(void) {
+ const int x = 1;
return *(char*)&x == 1;
}
-UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) {
- if (_upb_IsLittleEndian()) return val;
+UPB_INLINE uint32_t UPB_PRIVATE(_upb_BigEndian32)(uint32_t val) {
+ if (UPB_PRIVATE(_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;
+UPB_INLINE uint64_t UPB_PRIVATE(_upb_BigEndian64)(uint64_t val) {
+ if (UPB_PRIVATE(_upb_IsLittleEndian)()) return val;
- return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) |
- _upb_BigEndian_Swap32((uint32_t)(val >> 32));
+ return ((uint64_t)UPB_PRIVATE(_upb_BigEndian32)((uint32_t)val) << 32) |
+ UPB_PRIVATE(_upb_BigEndian32)((uint32_t)(val >> 32));
}
#ifdef __cplusplus
@@ -13568,12 +13569,65 @@
#endif
-#endif /* UPB_WIRE_INTERNAL_SWAP_H_ */
+#endif /* UPB_WIRE_INTERNAL_ENDIAN_H_ */
#ifndef UPB_WIRE_READER_H_
#define UPB_WIRE_READER_H_
+#ifndef UPB_WIRE_INTERNAL_READER_H_
+#define UPB_WIRE_INTERNAL_READER_H_
+
+// Must be last.
+
+#define kUpb_WireReader_WireTypeBits 3
+#define kUpb_WireReader_WireTypeMask 7
+
+typedef struct {
+ const char* ptr;
+ uint64_t val;
+} UPB_PRIVATE(_upb_WireReader_LongVarint);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UPB_PRIVATE(_upb_WireReader_LongVarint)
+UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val);
+
+static UPB_FORCEINLINE const char* UPB_PRIVATE(_upb_WireReader_ReadVarint)(
+ const char* ptr, uint64_t* val, int maxlen, uint64_t maxval) {
+ uint64_t byte = (uint8_t)*ptr;
+ if (UPB_LIKELY((byte & 0x80) == 0)) {
+ *val = (uint32_t)byte;
+ return ptr + 1;
+ }
+ const char* start = ptr;
+ UPB_PRIVATE(_upb_WireReader_LongVarint)
+ res = UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(ptr, byte);
+ if (!res.ptr || (maxlen < 10 && res.ptr - start > maxlen) ||
+ res.val > maxval) {
+ return NULL; // Malformed.
+ }
+ *val = res.val;
+ return res.ptr;
+}
+
+UPB_INLINE uint32_t UPB_PRIVATE(_upb_WireReader_GetFieldNumber)(uint32_t tag) {
+ return tag >> kUpb_WireReader_WireTypeBits;
+}
+
+UPB_INLINE uint8_t UPB_PRIVATE(_upb_WireReader_GetWireType)(uint32_t tag) {
+ return tag & kUpb_WireReader_WireTypeMask;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif // UPB_WIRE_INTERNAL_READER_H_
+
#ifndef UPB_WIRE_TYPES_H_
#define UPB_WIRE_TYPES_H_
@@ -13591,46 +13645,15 @@
// Must be last.
-#ifdef __cplusplus
-extern "C" {
-#endif
-
// The upb_WireReader interface is suitable for general-purpose parsing of
-// protobuf binary wire format. It is designed to be used along with
+// protobuf binary wire format. It is designed to be used along with
// upb_EpsCopyInputStream for buffering, and all parsing routines in this file
// assume that at least kUpb_EpsCopyInputStream_SlopBytes worth of data is
// available to read without any bounds checks.
-#define kUpb_WireReader_WireTypeMask 7
-#define kUpb_WireReader_WireTypeBits 3
-
-typedef struct {
- const char* ptr;
- uint64_t val;
-} _upb_WireReader_ReadLongVarintRet;
-
-_upb_WireReader_ReadLongVarintRet _upb_WireReader_ReadLongVarint(
- const char* ptr, uint64_t val);
-
-static UPB_FORCEINLINE const char* _upb_WireReader_ReadVarint(const char* ptr,
- uint64_t* val,
- int maxlen,
- uint64_t maxval) {
- uint64_t byte = (uint8_t)*ptr;
- if (UPB_LIKELY((byte & 0x80) == 0)) {
- *val = (uint32_t)byte;
- return ptr + 1;
- }
- const char* start = ptr;
- _upb_WireReader_ReadLongVarintRet res =
- _upb_WireReader_ReadLongVarint(ptr, byte);
- if (!res.ptr || (maxlen < 10 && res.ptr - start > maxlen) ||
- res.val > maxval) {
- return NULL; // Malformed.
- }
- *val = res.val;
- return res.ptr;
-}
+#ifdef __cplusplus
+extern "C" {
+#endif
// Parses a tag into `tag`, and returns a pointer past the end of the tag, or
// NULL if there was an error in the tag data.
@@ -13641,7 +13664,7 @@
static UPB_FORCEINLINE const char* upb_WireReader_ReadTag(const char* ptr,
uint32_t* tag) {
uint64_t val;
- ptr = _upb_WireReader_ReadVarint(ptr, &val, 5, UINT32_MAX);
+ ptr = UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, &val, 5, UINT32_MAX);
if (!ptr) return NULL;
*tag = val;
return ptr;
@@ -13649,17 +13672,17 @@
// Given a tag, returns the field number.
UPB_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag) {
- return tag >> kUpb_WireReader_WireTypeBits;
+ return UPB_PRIVATE(_upb_WireReader_GetFieldNumber)(tag);
}
// Given a tag, returns the wire type.
UPB_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag) {
- return tag & kUpb_WireReader_WireTypeMask;
+ return UPB_PRIVATE(_upb_WireReader_GetWireType)(tag);
}
UPB_INLINE const char* upb_WireReader_ReadVarint(const char* ptr,
uint64_t* val) {
- return _upb_WireReader_ReadVarint(ptr, val, 10, UINT64_MAX);
+ return UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, val, 10, UINT64_MAX);
}
// Skips data for a varint, returning a pointer past the end of the varint, or
@@ -13695,7 +13718,7 @@
UPB_INLINE const char* upb_WireReader_ReadFixed32(const char* ptr, void* val) {
uint32_t uval;
memcpy(&uval, ptr, 4);
- uval = _upb_BigEndian_Swap32(uval);
+ uval = UPB_PRIVATE(_upb_BigEndian32)(uval);
memcpy(val, &uval, 4);
return ptr + 4;
}
@@ -13708,14 +13731,14 @@
UPB_INLINE const char* upb_WireReader_ReadFixed64(const char* ptr, void* val) {
uint64_t uval;
memcpy(&uval, ptr, 8);
- uval = _upb_BigEndian_Swap64(uval);
+ uval = UPB_PRIVATE(_upb_BigEndian64)(uval);
memcpy(val, &uval, 8);
return ptr + 8;
}
-const char* _upb_WireReader_SkipGroup(const char* ptr, uint32_t tag,
- int depth_limit,
- upb_EpsCopyInputStream* stream);
+const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)(
+ const char* ptr, uint32_t tag, int depth_limit,
+ upb_EpsCopyInputStream* stream);
// Skips data for a group, returning a pointer past the end of the group, or
// NULL if there was an error parsing the group. The `tag` argument should be
@@ -13728,7 +13751,7 @@
// control over this?
UPB_INLINE const char* upb_WireReader_SkipGroup(
const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) {
- return _upb_WireReader_SkipGroup(ptr, tag, 100, stream);
+ return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, 100, stream);
}
UPB_INLINE const char* _upb_WireReader_SkipValue(
@@ -13749,7 +13772,8 @@
return ptr;
}
case kUpb_WireType_StartGroup:
- return _upb_WireReader_SkipGroup(ptr, tag, depth_limit, stream);
+ return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, depth_limit,
+ stream);
case kUpb_WireType_EndGroup:
return NULL; // Should be handled before now.
default: