Call RepeatedField::Reserve for small packed enums.

It's a pretty good guess that if all enum values are in [0, 128), that all the
varint values will be one byte long.  So we can call Reserve() on the
RepeatedField, saving some malloc's while parsing.

PiperOrigin-RevId: 533489111
pull/12854/head
Justin Lebar 2 years ago committed by Copybara-Service
parent eb5dbfd788
commit d9b7132d47
  1. 16
      src/google/protobuf/generated_message_tctable_lite.cc
  2. 14
      src/google/protobuf/parse_context.h

@ -1389,12 +1389,22 @@ const char* TcParser::PackedEnumSmallRange(PROTOBUF_TC_PARAM_DECL) {
auto* field = &RefAt<RepeatedField<int32_t>>(msg, data.offset()); auto* field = &RefAt<RepeatedField<int32_t>>(msg, data.offset());
const uint8_t max = data.aux_idx(); const uint8_t max = data.aux_idx();
return ctx->ReadPackedVarint(ptr, [=](int32_t v) { return ctx->ReadPackedVarint(
ptr,
[=](int32_t v) {
if (PROTOBUF_PREDICT_FALSE(min > v || v > max)) { if (PROTOBUF_PREDICT_FALSE(min > v || v > max)) {
AddUnknownEnum(msg, table, FastDecodeTag(saved_tag), v); AddUnknownEnum(msg, table, FastDecodeTag(saved_tag), v);
} else { } else {
field->Add(v); // The size_callback below ensures that we have enough capacity.
} field->AddAlreadyReserved(v);
}
},
/*size_callback=*/
[=](int32_t size_bytes) {
// For enums that fit in one varint byte, optimistically assume that all
// the values are one byte long (i.e. no large unknown values). If so,
// we know exactly how many values we're going to get.
field->Reserve(field->size() + size_bytes);
}); });
} }

@ -245,7 +245,12 @@ class PROTOBUF_EXPORT EpsCopyInputStream {
PROTOBUF_NODISCARD const char* ReadPackedFixed(const char* ptr, int size, PROTOBUF_NODISCARD const char* ReadPackedFixed(const char* ptr, int size,
RepeatedField<T>* out); RepeatedField<T>* out);
template <typename Add> template <typename Add>
PROTOBUF_NODISCARD const char* ReadPackedVarint(const char* ptr, Add add); PROTOBUF_NODISCARD const char* ReadPackedVarint(const char* ptr, Add add) {
return ReadPackedVarint(ptr, add, [](int) {});
}
template <typename Add, typename SizeCb>
PROTOBUF_NODISCARD const char* ReadPackedVarint(const char* ptr, Add add,
SizeCb size_callback);
uint32_t LastTag() const { return last_tag_minus_1_ + 1; } uint32_t LastTag() const { return last_tag_minus_1_ + 1; }
bool ConsumeEndGroup(uint32_t start_tag) { bool ConsumeEndGroup(uint32_t start_tag) {
@ -1235,9 +1240,12 @@ const char* ReadPackedVarintArray(const char* ptr, const char* end, Add add) {
return ptr; return ptr;
} }
template <typename Add> template <typename Add, typename SizeCb>
const char* EpsCopyInputStream::ReadPackedVarint(const char* ptr, Add add) { const char* EpsCopyInputStream::ReadPackedVarint(const char* ptr, Add add,
SizeCb size_callback) {
int size = ReadSize(&ptr); int size = ReadSize(&ptr);
size_callback(size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
int chunk_size = static_cast<int>(buffer_end_ - ptr); int chunk_size = static_cast<int>(buffer_end_ - ptr);
while (size > chunk_size) { while (size > chunk_size) {

Loading…
Cancel
Save