mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
Add 8-bit and 16-bit enum support to TcTable parsing and Reflection
This change introduces Protobuf C++ runtime primitives for 8-bit and 16-bit enum fields: - Added kRep16Bits and 8-bit/16-bit enum FieldType definitions to generated_message_tctable_impl.h. - Implemented fast-path and miniparse routines for 8-bit and 16-bit enums in generated_message_tctable_lite.cc without memory overwrites. - Added 8-bit and 16-bit offset tagging support in generated_message_reflection.h and updated GetEnumValue/SetEnumValueInternal in generated_message_reflection.cc. - Added comprehensive unit tests in generated_message_tctable_lite_test.cc and generated_message_reflection_unittest.cc. PiperOrigin-RevId: 969068446
This commit is contained in:
parent
a55c302e3f
commit
65b6764369
9 changed files with 749 additions and 53 deletions
|
|
@ -993,8 +993,19 @@ void SwapFieldHelper::SwapNonMessageNonStringField(
|
|||
SWAP_VALUES(FLOAT, float);
|
||||
SWAP_VALUES(DOUBLE, double);
|
||||
SWAP_VALUES(BOOL, bool);
|
||||
SWAP_VALUES(ENUM, int);
|
||||
#undef SWAP_VALUES
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
if (r->schema_.IsEnum8(field)) {
|
||||
std::swap(*r->MutableRaw<uint8_t>(lhs, field),
|
||||
*r->MutableRaw<uint8_t>(rhs, field));
|
||||
} else if (r->schema_.IsEnum16(field)) {
|
||||
std::swap(*r->MutableRaw<uint16_t>(lhs, field),
|
||||
*r->MutableRaw<uint16_t>(rhs, field));
|
||||
} else {
|
||||
std::swap(*r->MutableRaw<int>(lhs, field),
|
||||
*r->MutableRaw<int>(rhs, field));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ABSL_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
|
||||
}
|
||||
|
|
@ -1617,8 +1628,26 @@ void Reflection::ClearField(Message* message,
|
|||
#undef CLEAR_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
*MutableRaw<int>(message, field) =
|
||||
field->default_value_enum()->number();
|
||||
if (schema_.IsEnum8(field)) {
|
||||
if (schema_.IsEnumSigned(field)) {
|
||||
*MutableRaw<int8_t>(message, field) =
|
||||
static_cast<int8_t>(field->default_value_enum()->number());
|
||||
} else {
|
||||
*MutableRaw<uint8_t>(message, field) =
|
||||
static_cast<uint8_t>(field->default_value_enum()->number());
|
||||
}
|
||||
} else if (schema_.IsEnum16(field)) {
|
||||
if (schema_.IsEnumSigned(field)) {
|
||||
*MutableRaw<int16_t>(message, field) =
|
||||
static_cast<int16_t>(field->default_value_enum()->number());
|
||||
} else {
|
||||
*MutableRaw<uint16_t>(message, field) =
|
||||
static_cast<uint16_t>(field->default_value_enum()->number());
|
||||
}
|
||||
} else {
|
||||
*MutableRaw<int>(message, field) =
|
||||
field->default_value_enum()->number();
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING: {
|
||||
|
|
@ -2433,6 +2462,18 @@ int Reflection::GetEnumValue(const Message& message,
|
|||
field->number(), field->default_value_enum()->number());
|
||||
} else if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
|
||||
value = field->default_value_enum()->number();
|
||||
} else if (schema_.IsEnum8(field)) {
|
||||
if (schema_.IsEnumSigned(field)) {
|
||||
value = GetField<int8_t>(message, field);
|
||||
} else {
|
||||
value = GetField<uint8_t>(message, field);
|
||||
}
|
||||
} else if (schema_.IsEnum16(field)) {
|
||||
if (schema_.IsEnumSigned(field)) {
|
||||
value = GetField<int16_t>(message, field);
|
||||
} else {
|
||||
value = GetField<uint16_t>(message, field);
|
||||
}
|
||||
} else {
|
||||
value = GetField<int>(message, field);
|
||||
}
|
||||
|
|
@ -2468,6 +2509,18 @@ void Reflection::SetEnumValueInternal(Message* message,
|
|||
if (field->is_extension()) {
|
||||
MutableExtensionSet(message)->Set<int>(message->GetArena(), field->number(),
|
||||
field->type(), value, field);
|
||||
} else if (schema_.IsEnum8(field)) {
|
||||
if (schema_.IsEnumSigned(field)) {
|
||||
SetField<int8_t>(message, field, static_cast<int8_t>(value));
|
||||
} else {
|
||||
SetField<uint8_t>(message, field, static_cast<uint8_t>(value));
|
||||
}
|
||||
} else if (schema_.IsEnum16(field)) {
|
||||
if (schema_.IsEnumSigned(field)) {
|
||||
SetField<int16_t>(message, field, static_cast<int16_t>(value));
|
||||
} else {
|
||||
SetField<uint16_t>(message, field, static_cast<uint16_t>(value));
|
||||
}
|
||||
} else {
|
||||
SetField<int>(message, field, value);
|
||||
}
|
||||
|
|
@ -3245,6 +3298,11 @@ bool Reflection::IsImplicitPresenceFieldNonEmpty(
|
|||
"Code assumes uint64_t and double are the same size.");
|
||||
return absl::bit_cast<uint64_t>(GetRaw<double>(message, field)) != 0;
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
if (schema_.IsEnum8(field)) {
|
||||
return GetRaw<uint8_t>(message, field) != 0;
|
||||
} else if (schema_.IsEnum16(field)) {
|
||||
return GetRaw<uint16_t>(message, field) != 0;
|
||||
}
|
||||
return GetRaw<int>(message, field) != 0;
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->cpp_string_type()) {
|
||||
|
|
@ -3795,6 +3853,13 @@ const internal::TcParseTableBase* Reflection::CreateTcParseTable() const {
|
|||
}
|
||||
return std::monostate{};
|
||||
};
|
||||
const auto enum_rep = [&]() -> FieldOptions::EnumRep {
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
|
||||
if (schema_.IsEnum8(field)) return FieldOptions::kEnum8;
|
||||
if (schema_.IsEnum16(field)) return FieldOptions::kEnum16;
|
||||
}
|
||||
return FieldOptions::kEnum32;
|
||||
};
|
||||
fields.push_back({
|
||||
field, //
|
||||
static_cast<int>(schema_.HasBitIndex(field)),
|
||||
|
|
@ -3807,6 +3872,7 @@ const internal::TcParseTableBase* Reflection::CreateTcParseTable() const {
|
|||
/* use_direct_tcparser_table */ false,
|
||||
schema_.IsSplit(field),
|
||||
str_options(),
|
||||
enum_rep(),
|
||||
});
|
||||
}
|
||||
std::sort(fields.begin(), fields.end(), [](const auto& a, const auto& b) {
|
||||
|
|
|
|||
|
|
@ -65,10 +65,14 @@ inline constexpr uint32_t kSplitFieldOffsetTag = 0x80000000u;
|
|||
inline constexpr uint32_t kLazyOffsetTag = 0x40000000u;
|
||||
inline constexpr uint32_t kInlinedOffsetTag = 0x40000000u;
|
||||
inline constexpr uint32_t kMicroStringOffsetTag = 0x20000000u;
|
||||
inline constexpr uint32_t kEnum8OffsetTag = 0x20000000u;
|
||||
inline constexpr uint32_t kEnum16OffsetTag = 0x40000000u;
|
||||
inline constexpr uint32_t kEnumSignedOffsetTag = 0x10000000u;
|
||||
|
||||
inline constexpr uint32_t kAllOffsetTags = kSplitFieldOffsetTag |
|
||||
kLazyOffsetTag | kInlinedOffsetTag |
|
||||
kMicroStringOffsetTag;
|
||||
inline constexpr uint32_t kAllOffsetTags =
|
||||
kSplitFieldOffsetTag | kLazyOffsetTag | kInlinedOffsetTag |
|
||||
kMicroStringOffsetTag | kEnum8OffsetTag | kEnum16OffsetTag |
|
||||
kEnumSignedOffsetTag;
|
||||
|
||||
// Structs that the code generator emits directly to describe a message.
|
||||
// These should never used directly except to build a ReflectionSchema
|
||||
|
|
@ -158,6 +162,18 @@ class ReflectionSchema {
|
|||
return IsMicroString(offsets_[field->index()], field->type());
|
||||
}
|
||||
|
||||
bool IsEnum8(const FieldDescriptor* field) const {
|
||||
return IsEnum8(offsets_[field->index()], field->type());
|
||||
}
|
||||
|
||||
bool IsEnum16(const FieldDescriptor* field) const {
|
||||
return IsEnum16(offsets_[field->index()], field->type());
|
||||
}
|
||||
|
||||
bool IsEnumSigned(const FieldDescriptor* field) const {
|
||||
return IsEnumSigned(offsets_[field->index()], field->type());
|
||||
}
|
||||
|
||||
uint32_t GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const {
|
||||
return static_cast<uint32_t>(oneof_case_offset_) +
|
||||
static_cast<uint32_t>(
|
||||
|
|
@ -263,6 +279,19 @@ class ReflectionSchema {
|
|||
return (v & kMicroStringOffsetTag) != 0u;
|
||||
}
|
||||
|
||||
static bool IsEnum8(uint32_t v, FieldDescriptor::Type type) {
|
||||
return type == FieldDescriptor::TYPE_ENUM && (v & kEnum8OffsetTag) != 0u;
|
||||
}
|
||||
|
||||
static bool IsEnum16(uint32_t v, FieldDescriptor::Type type) {
|
||||
return type == FieldDescriptor::TYPE_ENUM && (v & kEnum16OffsetTag) != 0u;
|
||||
}
|
||||
|
||||
static bool IsEnumSigned(uint32_t v, FieldDescriptor::Type type) {
|
||||
return type == FieldDescriptor::TYPE_ENUM &&
|
||||
(v & kEnumSignedOffsetTag) != 0u;
|
||||
}
|
||||
|
||||
const Message* default_instance_;
|
||||
const uint32_t* offsets_;
|
||||
const uint32_t* has_bit_indices_;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#include "google/protobuf/generated_message_reflection.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -2043,6 +2045,69 @@ TEST(CppNamespaceOption, NewNamespaceSymbolSameProtoName) {
|
|||
"cpp.file.options.test");
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflection, Enum8And16BitFields) {
|
||||
const Descriptor* desc = unittest::TestAllTypes::descriptor();
|
||||
const FieldDescriptor* field = desc->FindFieldByName("optional_nested_enum");
|
||||
ASSERT_NE(field, nullptr);
|
||||
|
||||
std::vector<uint32_t> offsets(desc->field_count(), 0);
|
||||
std::vector<uint32_t> has_bits(desc->field_count(), 0);
|
||||
|
||||
// Test 8-bit unsigned enum
|
||||
{
|
||||
offsets[field->index()] = 100 | internal::kEnum8OffsetTag;
|
||||
internal::ReflectionSchema schema(
|
||||
&unittest::TestAllTypes::default_instance(), offsets.data(),
|
||||
has_bits.data(), /*has_bits_offset=*/-1, /*extensions_offset=*/-1,
|
||||
/*oneof_case_offset=*/-1, sizeof(unittest::TestAllTypes),
|
||||
/*split_offset=*/-1, /*sizeof_split=*/-1);
|
||||
EXPECT_TRUE(schema.IsEnum8(field));
|
||||
EXPECT_FALSE(schema.IsEnum16(field));
|
||||
EXPECT_FALSE(schema.IsEnumSigned(field));
|
||||
}
|
||||
|
||||
// Test 8-bit signed enum
|
||||
{
|
||||
offsets[field->index()] =
|
||||
100 | internal::kEnum8OffsetTag | internal::kEnumSignedOffsetTag;
|
||||
internal::ReflectionSchema schema(
|
||||
&unittest::TestAllTypes::default_instance(), offsets.data(),
|
||||
has_bits.data(), /*has_bits_offset=*/-1, /*extensions_offset=*/-1,
|
||||
/*oneof_case_offset=*/-1, sizeof(unittest::TestAllTypes),
|
||||
/*split_offset=*/-1, /*sizeof_split=*/-1);
|
||||
EXPECT_TRUE(schema.IsEnum8(field));
|
||||
EXPECT_FALSE(schema.IsEnum16(field));
|
||||
EXPECT_TRUE(schema.IsEnumSigned(field));
|
||||
}
|
||||
|
||||
// Test 16-bit unsigned enum
|
||||
{
|
||||
offsets[field->index()] = 100 | internal::kEnum16OffsetTag;
|
||||
internal::ReflectionSchema schema(
|
||||
&unittest::TestAllTypes::default_instance(), offsets.data(),
|
||||
has_bits.data(), /*has_bits_offset=*/-1, /*extensions_offset=*/-1,
|
||||
/*oneof_case_offset=*/-1, sizeof(unittest::TestAllTypes),
|
||||
/*split_offset=*/-1, /*sizeof_split=*/-1);
|
||||
EXPECT_FALSE(schema.IsEnum8(field));
|
||||
EXPECT_TRUE(schema.IsEnum16(field));
|
||||
EXPECT_FALSE(schema.IsEnumSigned(field));
|
||||
}
|
||||
|
||||
// Test 16-bit signed enum
|
||||
{
|
||||
offsets[field->index()] =
|
||||
100 | internal::kEnum16OffsetTag | internal::kEnumSignedOffsetTag;
|
||||
internal::ReflectionSchema schema(
|
||||
&unittest::TestAllTypes::default_instance(), offsets.data(),
|
||||
has_bits.data(), /*has_bits_offset=*/-1, /*extensions_offset=*/-1,
|
||||
/*oneof_case_offset=*/-1, sizeof(unittest::TestAllTypes),
|
||||
/*split_offset=*/-1, /*sizeof_split=*/-1);
|
||||
EXPECT_FALSE(schema.IsEnum8(field));
|
||||
EXPECT_TRUE(schema.IsEnum16(field));
|
||||
EXPECT_TRUE(schema.IsEnumSigned(field));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
|
|
|||
|
|
@ -190,22 +190,46 @@ TailCallTableInfo::FastFieldInfo::Field MakeFastFieldEntry(
|
|||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastF64);
|
||||
break;
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
if (TreatEnumAsInt(field)) {
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV32);
|
||||
if (options.is_enum_8()) {
|
||||
if (TreatEnumAsInt(field)) {
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV8);
|
||||
} else {
|
||||
int32_t first, last;
|
||||
if (GetEnumValidationRange(field->enum_type(), first, last)) {
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr8);
|
||||
} else {
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEv8);
|
||||
}
|
||||
}
|
||||
} else if (options.is_enum_16()) {
|
||||
if (TreatEnumAsInt(field)) {
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV16);
|
||||
} else {
|
||||
int32_t first, last;
|
||||
if (GetEnumValidationRange(field->enum_type(), first, last)) {
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr16);
|
||||
} else {
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEv16);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (GetEnumRangeInfo(field, info.aux_idx)) {
|
||||
case EnumRangeInfo::kNone:
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEv);
|
||||
break;
|
||||
case EnumRangeInfo::kContiguous:
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr);
|
||||
break;
|
||||
case EnumRangeInfo::kContiguous0:
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr0);
|
||||
break;
|
||||
case EnumRangeInfo::kContiguous1:
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr1);
|
||||
break;
|
||||
if (TreatEnumAsInt(field)) {
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV32);
|
||||
} else {
|
||||
switch (GetEnumRangeInfo(field, info.aux_idx)) {
|
||||
case EnumRangeInfo::kNone:
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEv);
|
||||
break;
|
||||
case EnumRangeInfo::kContiguous:
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr);
|
||||
break;
|
||||
case EnumRangeInfo::kContiguous0:
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr0);
|
||||
break;
|
||||
case EnumRangeInfo::kContiguous1:
|
||||
picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -255,6 +279,10 @@ bool IsFieldEligibleForFastParsing(
|
|||
return false;
|
||||
}
|
||||
|
||||
if (field->is_repeated() && (options.is_enum_8() || options.is_enum_16())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasLazyRep(field, options) && !message_options.uses_codegen) {
|
||||
// Can't use TDP on lazy fields if we can't do codegen.
|
||||
return false;
|
||||
|
|
@ -548,24 +576,62 @@ uint16_t MakeTypeCardForField(const FieldDescriptor* field, bool has_hasbit,
|
|||
: fl::kBool;
|
||||
break;
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
if (TreatEnumAsInt(field)) {
|
||||
// No validation is required.
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedOpenEnum
|
||||
: fl::kOpenEnum;
|
||||
} else {
|
||||
int32_t first;
|
||||
int32_t last;
|
||||
if (GetEnumValidationRange(field->enum_type(), first, last)) {
|
||||
// Validation is done by range check (start/length in FieldAux).
|
||||
if (options.is_enum_8()) {
|
||||
if (TreatEnumAsInt(field)) {
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedEnumRange
|
||||
: fl::kEnumRange;
|
||||
? fl::kPackedOpenEnum8
|
||||
: fl::kOpenEnum8;
|
||||
} else {
|
||||
// Validation uses the generated _IsValid function.
|
||||
int32_t first;
|
||||
int32_t last;
|
||||
if (GetEnumValidationRange(field->enum_type(), first, last)) {
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedEnumRange8
|
||||
: fl::kEnumRange8;
|
||||
} else {
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedEnum8
|
||||
: fl::kEnum8;
|
||||
}
|
||||
}
|
||||
} else if (options.is_enum_16()) {
|
||||
if (TreatEnumAsInt(field)) {
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedEnum
|
||||
: fl::kEnum;
|
||||
? fl::kPackedOpenEnum16
|
||||
: fl::kOpenEnum16;
|
||||
} else {
|
||||
int32_t first;
|
||||
int32_t last;
|
||||
if (GetEnumValidationRange(field->enum_type(), first, last)) {
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedEnumRange16
|
||||
: fl::kEnumRange16;
|
||||
} else {
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedEnum16
|
||||
: fl::kEnum16;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (TreatEnumAsInt(field)) {
|
||||
// No validation is required.
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedOpenEnum
|
||||
: fl::kOpenEnum;
|
||||
} else {
|
||||
int32_t first;
|
||||
int32_t last;
|
||||
if (GetEnumValidationRange(field->enum_type(), first, last)) {
|
||||
// Validation is done by range check (start/length in FieldAux).
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedEnumRange
|
||||
: fl::kEnumRange;
|
||||
} else {
|
||||
// Validation uses the generated _IsValid function.
|
||||
type_card |= field->is_repeated() && field->is_packed()
|
||||
? fl::kPackedEnum
|
||||
: fl::kEnum;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,11 @@ struct PROTOBUF_EXPORT TailCallTableInfo {
|
|||
|
||||
using StrOptions = std::variant<std::monostate, StringInlined, MicroString>;
|
||||
StrOptions str_options;
|
||||
|
||||
enum EnumRep { kEnum32 = 0, kEnum8, kEnum16 };
|
||||
EnumRep enum_rep = kEnum32;
|
||||
bool is_enum_8() const { return enum_rep == kEnum8; }
|
||||
bool is_enum_16() const { return enum_rep == kEnum16; }
|
||||
};
|
||||
|
||||
struct FieldEntryInfo;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ enum FieldRep : uint16_t {
|
|||
|
||||
// Numeric types (used for optional and repeated fields):
|
||||
kRep8Bits = 0,
|
||||
kRep16Bits = 1 << kRepShift,
|
||||
kRep32Bits = 2 << kRepShift,
|
||||
kRep64Bits = 3 << kRepShift,
|
||||
// String types:
|
||||
|
|
@ -201,6 +202,14 @@ enum FieldType : uint16_t {
|
|||
// Numeric types:
|
||||
kBool = 0 | kFkVarint | kRep8Bits,
|
||||
|
||||
kEnum8 = 0 | kFkVarint | kRep8Bits | kFmtEnum | kTvEnum,
|
||||
kEnumRange8 = 0 | kFkVarint | kRep8Bits | kFmtEnum | kTvRange,
|
||||
kOpenEnum8 = 0 | kFkVarint | kRep8Bits | kFmtEnum,
|
||||
|
||||
kEnum16 = 0 | kFkVarint | kRep16Bits | kFmtEnum | kTvEnum,
|
||||
kEnumRange16 = 0 | kFkVarint | kRep16Bits | kFmtEnum | kTvRange,
|
||||
kOpenEnum16 = 0 | kFkVarint | kRep16Bits | kFmtEnum,
|
||||
|
||||
kFixed32 = 0 | kFkFixed | kRep32Bits | kFmtUnsigned,
|
||||
kUInt32 = 0 | kFkVarint | kRep32Bits | kFmtUnsigned,
|
||||
kSFixed32 = 0 | kFkFixed | kRep32Bits | kFmtSigned,
|
||||
|
|
@ -220,6 +229,14 @@ enum FieldType : uint16_t {
|
|||
|
||||
kPackedBool = 0 | kFkPackedVarint | kRep8Bits,
|
||||
|
||||
kPackedEnum8 = 0 | kFkPackedVarint | kRep8Bits | kFmtEnum | kTvEnum,
|
||||
kPackedEnumRange8 = 0 | kFkPackedVarint | kRep8Bits | kFmtEnum | kTvRange,
|
||||
kPackedOpenEnum8 = 0 | kFkPackedVarint | kRep8Bits | kFmtEnum,
|
||||
|
||||
kPackedEnum16 = 0 | kFkPackedVarint | kRep16Bits | kFmtEnum | kTvEnum,
|
||||
kPackedEnumRange16 = 0 | kFkPackedVarint | kRep16Bits | kFmtEnum | kTvRange,
|
||||
kPackedOpenEnum16 = 0 | kFkPackedVarint | kRep16Bits | kFmtEnum,
|
||||
|
||||
kPackedFixed32 = 0 | kFkPackedFixed | kRep32Bits | kFmtUnsigned,
|
||||
kPackedUInt32 = 0 | kFkPackedVarint | kRep32Bits | kFmtUnsigned,
|
||||
kPackedSFixed32 = 0 | kFkPackedFixed | kRep32Bits | kFmtSigned,
|
||||
|
|
@ -251,6 +268,8 @@ enum FieldType : uint16_t {
|
|||
} // namespace field_layout
|
||||
|
||||
#ifndef NDEBUG
|
||||
[[noreturn]] PROTOBUF_EXPORT void AlignFail(std::integral_constant<size_t, 2>,
|
||||
std::uintptr_t address);
|
||||
[[noreturn]] PROTOBUF_EXPORT void AlignFail(std::integral_constant<size_t, 4>,
|
||||
std::uintptr_t address);
|
||||
[[noreturn]] PROTOBUF_EXPORT void AlignFail(std::integral_constant<size_t, 8>,
|
||||
|
|
@ -334,6 +353,7 @@ inline void AlignFail(std::integral_constant<size_t, 1>,
|
|||
#define PROTOBUF_TC_PARSE_FUNCTION_LIST \
|
||||
/* These functions have the Fast entry ABI */ \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV8) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV16) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV32) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV64) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastZ32) \
|
||||
|
|
@ -344,6 +364,10 @@ inline void AlignFail(std::integral_constant<size_t, 1>,
|
|||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr0) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr1) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEv8) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr8) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEv16) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr16) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastB) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastU) \
|
||||
PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastBi) \
|
||||
|
|
@ -481,6 +505,18 @@ class PROTOBUF_EXPORT TcParser final {
|
|||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV8P2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV16S1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV16S2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV16R1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV16R2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV16P1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV16P2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV32S1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV32S2(
|
||||
|
|
@ -537,14 +573,17 @@ class PROTOBUF_EXPORT TcParser final {
|
|||
if (sizeof(FieldType) == 1) {
|
||||
return &FastV8S1;
|
||||
}
|
||||
if (sizeof(FieldType) == 2) {
|
||||
return &FastV16S1;
|
||||
}
|
||||
if (sizeof(FieldType) == 4) {
|
||||
return &FastV32S1;
|
||||
}
|
||||
if (sizeof(FieldType) == 8) {
|
||||
return &FastV64S1;
|
||||
}
|
||||
static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 4 ||
|
||||
sizeof(FieldType) == 8,
|
||||
static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 2 ||
|
||||
sizeof(FieldType) == 4 || sizeof(FieldType) == 8,
|
||||
"");
|
||||
ABSL_LOG(FATAL) << "This should be unreachable";
|
||||
}
|
||||
|
|
@ -604,6 +643,56 @@ class PROTOBUF_EXPORT TcParser final {
|
|||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr1P2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr8S1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr8S2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr8R1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr8R2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr8P1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr8P2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv8S1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv8S2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv8R1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv8R2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv8P1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv8P2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr16S1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr16S2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr16R1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr16R2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr16P1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr16P2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv16S1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv16S2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv16R1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv16R2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv16P1(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEv16P2(
|
||||
PROTOBUF_TC_PARAM_DECL);
|
||||
|
||||
// Functions referenced by generated fast tables (string types):
|
||||
// B: bytes U: UTF-8 string
|
||||
// (empty): ArenaStringPtr i: InlinedString c: Cord m: MicroString
|
||||
|
|
@ -972,7 +1061,7 @@ class PROTOBUF_EXPORT TcParser final {
|
|||
PROTOBUF_TC_PARAM_DECL);
|
||||
|
||||
// Implementations for fast enum field parsing functions:
|
||||
template <typename TagType, uint16_t xform_val>
|
||||
template <typename FieldType, typename TagType, uint16_t xform_val>
|
||||
PROTOBUF_CC static inline const char* SingularEnum(PROTOBUF_TC_PARAM_DECL);
|
||||
template <typename TagType, uint8_t min>
|
||||
PROTOBUF_CC static inline const char* SingularEnumSmallRange(
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ using FieldEntry = TcParseTableBase::FieldEntry;
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NDEBUG
|
||||
[[noreturn]] void AlignFail(std::integral_constant<size_t, 2>,
|
||||
std::uintptr_t address) {
|
||||
ABSL_LOG(FATAL) << "Unaligned (2) access at " << address;
|
||||
}
|
||||
[[noreturn]] void AlignFail(std::integral_constant<size_t, 4>,
|
||||
std::uintptr_t address) {
|
||||
ABSL_LOG(FATAL) << "Unaligned (4) access at " << address;
|
||||
|
|
@ -140,8 +144,14 @@ absl::Status TcParser::VerifyHasBitConsistency(const MessageLite* msg,
|
|||
if (has_bit) break;
|
||||
switch (entry.type_card & fl::kRepMask) {
|
||||
case fl::kRep8Bits:
|
||||
if (RefAt<bool>(base, entry.offset) !=
|
||||
RefAt<bool>(default_base, entry.offset)) {
|
||||
if (RefAt<uint8_t>(base, entry.offset) !=
|
||||
RefAt<uint8_t>(default_base, entry.offset)) {
|
||||
return make_error_status();
|
||||
}
|
||||
break;
|
||||
case fl::kRep16Bits:
|
||||
if (RefAt<uint16_t>(base, entry.offset) !=
|
||||
RefAt<uint16_t>(default_base, entry.offset)) {
|
||||
return make_error_status();
|
||||
}
|
||||
break;
|
||||
|
|
@ -240,6 +250,7 @@ bool TcParser::RepeatedFieldIsEmptySlow(const MessageLite* msg,
|
|||
msg, is_split);
|
||||
return repeated_field.empty();
|
||||
}
|
||||
case fl::kRep16Bits:
|
||||
case fl::kRep32Bits: {
|
||||
const auto& repeated_field =
|
||||
GetRepeatedFieldAt<RepeatedField<uint32_t>>(base, entry.offset,
|
||||
|
|
@ -1243,6 +1254,26 @@ PROTOBUF_NOINLINE const char* TcParser::FastV8P1(PROTOBUF_TC_PARAM_DECL) {
|
|||
PROTOBUF_NOINLINE const char* TcParser::FastV8P2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return PackedVarint<bool, uint16_t>(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastV16S1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularVarint<uint16_t, uint8_t>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastV16S2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularVarint<uint16_t, uint16_t>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastV16R1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastV32R1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastV16R2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastV32R2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastV16P1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastV32P1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastV16P2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastV32P2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastV32P1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return PackedVarint<uint32_t, uint8_t>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
|
|
@ -1313,7 +1344,7 @@ PROTOBUF_NOINLINE const char* TcParser::MpUnknownEnumFallback(
|
|||
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
|
||||
}
|
||||
|
||||
template <typename TagType, uint16_t xform_val>
|
||||
template <typename FieldType, typename TagType, uint16_t xform_val>
|
||||
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnum(
|
||||
PROTOBUF_TC_PARAM_DECL) {
|
||||
if (ABSL_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
|
||||
|
|
@ -1334,24 +1365,70 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnum(
|
|||
PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
SetCachedHasBit(hasbits, data.hasbit_idx());
|
||||
RefAt<int32_t>(msg, data.offset()) = tmp;
|
||||
RefAt<FieldType>(msg, data.offset()) = static_cast<FieldType>(tmp);
|
||||
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastErS1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, field_layout::kTvRange>(
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<int32_t, uint8_t,
|
||||
field_layout::kTvRange>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastErS2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, field_layout::kTvRange>(
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<int32_t, uint16_t,
|
||||
field_layout::kTvRange>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEvS1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, field_layout::kTvEnum>(
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<int32_t, uint8_t,
|
||||
field_layout::kTvEnum>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEvS2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, field_layout::kTvEnum>(
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<int32_t, uint16_t,
|
||||
field_layout::kTvEnum>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr8S1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, uint8_t,
|
||||
field_layout::kTvRange>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr8S2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, uint16_t,
|
||||
field_layout::kTvRange>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv8S1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, uint8_t,
|
||||
field_layout::kTvEnum>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv8S2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, uint16_t,
|
||||
field_layout::kTvEnum>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr16S1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, uint8_t,
|
||||
field_layout::kTvRange>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr16S2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, uint16_t,
|
||||
field_layout::kTvRange>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv16S1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, uint8_t,
|
||||
field_layout::kTvEnum>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv16S2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, uint16_t,
|
||||
field_layout::kTvEnum>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
|
||||
|
|
@ -1505,6 +1582,56 @@ PROTOBUF_NOINLINE const char* TcParser::FastEvP2(PROTOBUF_TC_PARAM_DECL) {
|
|||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr8R1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastErR1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr8R2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastErR2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv8R1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastEvR1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv8R2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastEvR2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr8P1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastErP1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr8P2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastErP2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv8P1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastEvP1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv8P2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastEvP2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr16R1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastErR1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr16R2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastErR2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv16R1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastEvR1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv16R2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastEvR2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr16P1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastErP1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEr16P2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastErP2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv16P1(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastEvP1(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
PROTOBUF_NOINLINE const char* TcParser::FastEv16P2(PROTOBUF_TC_PARAM_DECL) {
|
||||
PROTOBUF_MUSTTAIL return FastEvP2(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
|
||||
template <typename TagType, uint8_t min>
|
||||
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnumSmallRange(
|
||||
PROTOBUF_TC_PARAM_DECL) {
|
||||
|
|
@ -2263,6 +2390,21 @@ PROTOBUF_NOINLINE const char* TcParser::MpVarint(PROTOBUF_TC_PARAM_DECL) {
|
|||
} else if (is_zigzag) {
|
||||
tmp = WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
|
||||
}
|
||||
} else if (rep == field_layout::kRep16Bits) {
|
||||
if (is_validated_enum) {
|
||||
if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
|
||||
ptr = ptr2;
|
||||
PROTOBUF_MUSTTAIL return MpUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ABSL_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
|
||||
if (is_validated_enum) {
|
||||
if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
|
||||
ptr = ptr2;
|
||||
PROTOBUF_MUSTTAIL return MpUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the field as present:
|
||||
|
|
@ -2279,9 +2421,15 @@ PROTOBUF_NOINLINE const char* TcParser::MpVarint(PROTOBUF_TC_PARAM_DECL) {
|
|||
RefAt<uint64_t>(base, entry.offset) = tmp;
|
||||
} else if (rep == field_layout::kRep32Bits) {
|
||||
RefAt<uint32_t>(base, entry.offset) = static_cast<uint32_t>(tmp);
|
||||
} else if (rep == field_layout::kRep16Bits) {
|
||||
RefAt<uint16_t>(base, entry.offset) = static_cast<uint16_t>(tmp);
|
||||
} else {
|
||||
ABSL_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
|
||||
RefAt<bool>(base, entry.offset) = static_cast<bool>(tmp);
|
||||
if ((type_card & field_layout::kFmtMask) == field_layout::kFmtEnum) {
|
||||
RefAt<uint8_t>(base, entry.offset) = static_cast<uint8_t>(tmp);
|
||||
} else {
|
||||
RefAt<bool>(base, entry.offset) = static_cast<bool>(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
|
||||
|
|
@ -2370,6 +2518,7 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint(
|
|||
is_split, uint64_t, (is_split ? 0 : field_layout::kTvZigZag)>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
case field_layout::kRep16Bits >> field_layout::kRepShift:
|
||||
case field_layout::kRep32Bits >> field_layout::kRepShift:
|
||||
switch (xform_val >> field_layout::kTvShift) {
|
||||
case 0:
|
||||
|
|
@ -2391,8 +2540,21 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint(
|
|||
Unreachable();
|
||||
}
|
||||
case field_layout::kRep8Bits >> field_layout::kRepShift:
|
||||
PROTOBUF_MUSTTAIL return MpRepeatedVarintT<is_split, bool, 0>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
switch (xform_val >> field_layout::kTvShift) {
|
||||
case 0:
|
||||
PROTOBUF_MUSTTAIL return MpRepeatedVarintT<is_split, bool, 0>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
case field_layout::kTvEnum >> field_layout::kTvShift:
|
||||
PROTOBUF_MUSTTAIL return MpRepeatedVarintT<
|
||||
is_split, uint32_t, (is_split ? 0 : field_layout::kTvEnum)>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
case field_layout::kTvRange >> field_layout::kTvShift:
|
||||
PROTOBUF_MUSTTAIL return MpRepeatedVarintT<
|
||||
is_split, uint32_t, (is_split ? 0 : field_layout::kTvRange)>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
default:
|
||||
Unreachable();
|
||||
}
|
||||
|
||||
default:
|
||||
Unreachable();
|
||||
|
|
@ -2470,6 +2632,7 @@ PROTOBUF_NOINLINE const char* TcParser::MpPackedVarint(PROTOBUF_TC_PARAM_DECL) {
|
|||
is_split, uint64_t, (is_split ? 0 : field_layout::kTvZigZag)>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
}
|
||||
case field_layout::kRep16Bits >> field_layout::kRepShift:
|
||||
case field_layout::kRep32Bits >> field_layout::kRepShift:
|
||||
switch (xform_val >> field_layout::kTvShift) {
|
||||
case 0:
|
||||
|
|
@ -2491,8 +2654,21 @@ PROTOBUF_NOINLINE const char* TcParser::MpPackedVarint(PROTOBUF_TC_PARAM_DECL) {
|
|||
Unreachable();
|
||||
}
|
||||
case field_layout::kRep8Bits >> field_layout::kRepShift:
|
||||
PROTOBUF_MUSTTAIL return MpPackedVarintT<is_split, bool, 0>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
switch (xform_val >> field_layout::kTvShift) {
|
||||
case 0:
|
||||
PROTOBUF_MUSTTAIL return MpPackedVarintT<is_split, bool, 0>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
case field_layout::kTvEnum >> field_layout::kTvShift:
|
||||
PROTOBUF_MUSTTAIL return MpPackedVarintT<
|
||||
is_split, uint32_t, (is_split ? 0 : field_layout::kTvEnum)>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
case field_layout::kTvRange >> field_layout::kTvShift:
|
||||
PROTOBUF_MUSTTAIL return MpPackedVarintT<
|
||||
is_split, uint32_t, (is_split ? 0 : field_layout::kTvRange)>(
|
||||
PROTOBUF_TC_PARAM_PASS);
|
||||
default:
|
||||
Unreachable();
|
||||
}
|
||||
|
||||
default:
|
||||
Unreachable();
|
||||
|
|
@ -3209,6 +3385,12 @@ std::string TypeCardToString(uint16_t type_card) {
|
|||
case fl::kFkPackedFixed: {
|
||||
switch (type_card & ~fl::kFcMask & ~fl::kSplitMask) {
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(Bool);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(Enum8);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(EnumRange8);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(OpenEnum8);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(Enum16);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(EnumRange16);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(OpenEnum16);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(Fixed32);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(UInt32);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(SFixed32);
|
||||
|
|
@ -3225,6 +3407,12 @@ std::string TypeCardToString(uint16_t type_card) {
|
|||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(SInt64);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(Double);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedBool);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnum8);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnumRange8);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedOpenEnum8);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnum16);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnumRange16);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedOpenEnum16);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFixed32);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedUInt32);
|
||||
PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSFixed32);
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ TEST(FastVarints, NameHere) {
|
|||
};
|
||||
uint8_t serialize_buffer[64];
|
||||
|
||||
for (int size : {8, 32, 64}) {
|
||||
for (int size : {8, 16, 32, 64}) {
|
||||
SCOPED_TRACE(size);
|
||||
auto next_i = [](uint64_t i) {
|
||||
// if i + 1 is a power of two, return that.
|
||||
|
|
@ -201,6 +201,9 @@ TEST(FastVarints, NameHere) {
|
|||
case 8:
|
||||
fn = &TcParser::FastV8S1;
|
||||
break;
|
||||
case 16:
|
||||
fn = &TcParser::FastV16S1;
|
||||
break;
|
||||
case 32:
|
||||
fn = &TcParser::FastV32S1;
|
||||
break;
|
||||
|
|
@ -239,6 +242,13 @@ TEST(FastVarints, NameHere) {
|
|||
EXPECT_EQ(actual_field, static_cast<decltype(actual_field)>(i)) //
|
||||
<< " hex: " << absl::StrCat(absl::Hex(actual_field));
|
||||
}; break;
|
||||
case 16: {
|
||||
ASSERT_EQ(end_ptr - ptr, serialized.size());
|
||||
|
||||
auto actual_field = ReadAndReset<uint16_t>(&fake_msg[kFieldOffset]);
|
||||
EXPECT_EQ(actual_field, static_cast<decltype(actual_field)>(i)) //
|
||||
<< " hex: " << absl::StrCat(absl::Hex(actual_field));
|
||||
}; break;
|
||||
case 32: {
|
||||
ASSERT_TRUE(end_ptr);
|
||||
ASSERT_EQ(end_ptr - ptr, serialized.size());
|
||||
|
|
@ -1071,6 +1081,179 @@ TEST(TcParserTest, OobGenReproduction) {
|
|||
(void)msg->ParseFromString(payload);
|
||||
}
|
||||
|
||||
TEST(TcParserTest, Enum8And16TypeCardToString) {
|
||||
namespace fl = internal::field_layout;
|
||||
EXPECT_EQ(
|
||||
TypeCardToString(static_cast<uint16_t>(fl::kFcOptional) | fl::kEnum8),
|
||||
"::_fl::kFcOptional | ::_fl::kEnum8");
|
||||
EXPECT_EQ(TypeCardToString(static_cast<uint16_t>(fl::kFcOptional) |
|
||||
fl::kEnumRange8),
|
||||
"::_fl::kFcOptional | ::_fl::kEnumRange8");
|
||||
EXPECT_EQ(
|
||||
TypeCardToString(static_cast<uint16_t>(fl::kFcOptional) | fl::kOpenEnum8),
|
||||
"::_fl::kFcOptional | ::_fl::kOpenEnum8");
|
||||
EXPECT_EQ(
|
||||
TypeCardToString(static_cast<uint16_t>(fl::kFcOptional) | fl::kEnum16),
|
||||
"::_fl::kFcOptional | ::_fl::kEnum16");
|
||||
EXPECT_EQ(TypeCardToString(static_cast<uint16_t>(fl::kFcOptional) |
|
||||
fl::kEnumRange16),
|
||||
"::_fl::kFcOptional | ::_fl::kEnumRange16");
|
||||
EXPECT_EQ(TypeCardToString(static_cast<uint16_t>(fl::kFcOptional) |
|
||||
fl::kOpenEnum16),
|
||||
"::_fl::kFcOptional | ::_fl::kOpenEnum16");
|
||||
|
||||
EXPECT_EQ(TypeCardToString(static_cast<uint16_t>(fl::kFcRepeated) |
|
||||
fl::kPackedEnum8),
|
||||
"::_fl::kFcRepeated | ::_fl::kPackedEnum8");
|
||||
EXPECT_EQ(TypeCardToString(static_cast<uint16_t>(fl::kFcRepeated) |
|
||||
fl::kPackedEnumRange8),
|
||||
"::_fl::kFcRepeated | ::_fl::kPackedEnumRange8");
|
||||
EXPECT_EQ(TypeCardToString(static_cast<uint16_t>(fl::kFcRepeated) |
|
||||
fl::kPackedOpenEnum8),
|
||||
"::_fl::kFcRepeated | ::_fl::kPackedOpenEnum8");
|
||||
EXPECT_EQ(TypeCardToString(static_cast<uint16_t>(fl::kFcRepeated) |
|
||||
fl::kPackedEnum16),
|
||||
"::_fl::kFcRepeated | ::_fl::kPackedEnum16");
|
||||
EXPECT_EQ(TypeCardToString(static_cast<uint16_t>(fl::kFcRepeated) |
|
||||
fl::kPackedEnumRange16),
|
||||
"::_fl::kFcRepeated | ::_fl::kPackedEnumRange16");
|
||||
EXPECT_EQ(TypeCardToString(static_cast<uint16_t>(fl::kFcRepeated) |
|
||||
fl::kPackedOpenEnum16),
|
||||
"::_fl::kFcRepeated | ::_fl::kPackedOpenEnum16");
|
||||
}
|
||||
|
||||
TEST(TcParserTest, FastEnum8And16Parsing) {
|
||||
constexpr uint8_t kHasBitsOffset = 4;
|
||||
constexpr uint8_t kHasBitIndex = 0;
|
||||
constexpr uint8_t kFieldOffset = 24;
|
||||
|
||||
const ClassData class_data(nullptr, nullptr, MessageCreator(), nullptr,
|
||||
nullptr, nullptr, nullptr,
|
||||
/*cached_size_offset=*/16, "type_name");
|
||||
|
||||
alignas(16) char fake_msg[64];
|
||||
memset(fake_msg, kDND, sizeof(fake_msg));
|
||||
memset(&fake_msg[kHasBitsOffset], 0, sizeof(uint32_t));
|
||||
|
||||
TcParseTable<1, 1, 2, 0, 2> parse_table = {
|
||||
// header:
|
||||
{
|
||||
kHasBitsOffset,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
offsetof(decltype(parse_table), field_lookup_table),
|
||||
0xFFFFFFFF - 1,
|
||||
offsetof(decltype(parse_table), field_entries),
|
||||
1,
|
||||
2,
|
||||
offsetof(decltype(parse_table), aux_entries),
|
||||
&class_data,
|
||||
nullptr,
|
||||
&FastParserGaveUp,
|
||||
},
|
||||
// Fast entries:
|
||||
{{
|
||||
{},
|
||||
}},
|
||||
// Field Lookup Table:
|
||||
{{65535, 65535}},
|
||||
// Field Entries:
|
||||
{{
|
||||
{kFieldOffset, kHasBitsOffset + 0, 0, field_layout::kEnum8},
|
||||
}},
|
||||
// Aux Entries:
|
||||
{{
|
||||
{0, 10}, // range 0..10
|
||||
{FieldAuxEnumData{},
|
||||
EnumTraits<proto2_unittest::ForeignEnum>::validation_data()},
|
||||
}},
|
||||
};
|
||||
|
||||
uint8_t serialize_buffer[64];
|
||||
auto serialize_ptr = WireFormatLite::WriteUInt32ToArray(
|
||||
/* field_number= */ 1, 5, serialize_buffer);
|
||||
absl::string_view serialized{
|
||||
reinterpret_cast<char*>(&serialize_buffer[0]),
|
||||
static_cast<size_t>(serialize_ptr - serialize_buffer)};
|
||||
|
||||
// Test FastEr8S1 (range validation for 8-bit enum)
|
||||
{
|
||||
memset(fake_msg, kDND, sizeof(fake_msg));
|
||||
memset(&fake_msg[kHasBitsOffset], 0, sizeof(uint32_t));
|
||||
const char* ptr = nullptr;
|
||||
ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
|
||||
/* aliasing= */ false, &ptr, serialized);
|
||||
TcFieldData data(/*coded_tag=*/8, kHasBitIndex, /*aux_idx=*/0,
|
||||
kFieldOffset);
|
||||
const char* end_ptr = TcParser::FastEr8S1(
|
||||
reinterpret_cast<MessageLite*>(fake_msg), ptr, &ctx,
|
||||
Xor2SerializedBytes(data, ptr), &parse_table.header, /*hasbits=*/0);
|
||||
ASSERT_EQ(end_ptr - ptr, serialized.size());
|
||||
auto actual_field = ReadAndReset<uint8_t>(&fake_msg[kFieldOffset]);
|
||||
EXPECT_EQ(actual_field, 5);
|
||||
auto hasbits = ReadAndReset<uint32_t>(&fake_msg[kHasBitsOffset]);
|
||||
EXPECT_EQ(hasbits, 1 << kHasBitIndex);
|
||||
}
|
||||
|
||||
// Test FastEv8S1 (function validation for 8-bit enum)
|
||||
{
|
||||
memset(fake_msg, kDND, sizeof(fake_msg));
|
||||
memset(&fake_msg[kHasBitsOffset], 0, sizeof(uint32_t));
|
||||
const char* ptr = nullptr;
|
||||
ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
|
||||
/* aliasing= */ false, &ptr, serialized);
|
||||
TcFieldData data(/*coded_tag=*/8, kHasBitIndex, /*aux_idx=*/1,
|
||||
kFieldOffset);
|
||||
const char* end_ptr = TcParser::FastEv8S1(
|
||||
reinterpret_cast<MessageLite*>(fake_msg), ptr, &ctx,
|
||||
Xor2SerializedBytes(data, ptr), &parse_table.header, /*hasbits=*/0);
|
||||
ASSERT_EQ(end_ptr - ptr, serialized.size());
|
||||
auto actual_field = ReadAndReset<uint8_t>(&fake_msg[kFieldOffset]);
|
||||
EXPECT_EQ(actual_field, 5);
|
||||
auto hasbits = ReadAndReset<uint32_t>(&fake_msg[kHasBitsOffset]);
|
||||
EXPECT_EQ(hasbits, 1 << kHasBitIndex);
|
||||
}
|
||||
|
||||
// Test FastEr16S1 (range validation for 16-bit enum)
|
||||
{
|
||||
memset(fake_msg, kDND, sizeof(fake_msg));
|
||||
memset(&fake_msg[kHasBitsOffset], 0, sizeof(uint32_t));
|
||||
const char* ptr = nullptr;
|
||||
ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
|
||||
/* aliasing= */ false, &ptr, serialized);
|
||||
TcFieldData data(/*coded_tag=*/8, kHasBitIndex, /*aux_idx=*/0,
|
||||
kFieldOffset);
|
||||
const char* end_ptr = TcParser::FastEr16S1(
|
||||
reinterpret_cast<MessageLite*>(fake_msg), ptr, &ctx,
|
||||
Xor2SerializedBytes(data, ptr), &parse_table.header, /*hasbits=*/0);
|
||||
ASSERT_EQ(end_ptr - ptr, serialized.size());
|
||||
auto actual_field = ReadAndReset<uint16_t>(&fake_msg[kFieldOffset]);
|
||||
EXPECT_EQ(actual_field, 5);
|
||||
auto hasbits = ReadAndReset<uint32_t>(&fake_msg[kHasBitsOffset]);
|
||||
EXPECT_EQ(hasbits, 1 << kHasBitIndex);
|
||||
}
|
||||
|
||||
// Test FastEv16S1 (function validation for 16-bit enum)
|
||||
{
|
||||
memset(fake_msg, kDND, sizeof(fake_msg));
|
||||
memset(&fake_msg[kHasBitsOffset], 0, sizeof(uint32_t));
|
||||
const char* ptr = nullptr;
|
||||
ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
|
||||
/* aliasing= */ false, &ptr, serialized);
|
||||
TcFieldData data(/*coded_tag=*/8, kHasBitIndex, /*aux_idx=*/1,
|
||||
kFieldOffset);
|
||||
const char* end_ptr = TcParser::FastEv16S1(
|
||||
reinterpret_cast<MessageLite*>(fake_msg), ptr, &ctx,
|
||||
Xor2SerializedBytes(data, ptr), &parse_table.header, /*hasbits=*/0);
|
||||
ASSERT_EQ(end_ptr - ptr, serialized.size());
|
||||
auto actual_field = ReadAndReset<uint16_t>(&fake_msg[kFieldOffset]);
|
||||
EXPECT_EQ(actual_field, 5);
|
||||
auto hasbits = ReadAndReset<uint32_t>(&fake_msg[kHasBitsOffset]);
|
||||
EXPECT_EQ(hasbits, 1 << kHasBitIndex);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
|
|
|||
|
|
@ -1901,6 +1901,11 @@ void Reflection::VerifyFieldType(const FieldDescriptor* field) const {
|
|||
<< error();
|
||||
} else {
|
||||
auto cpp_type = field->cpp_type();
|
||||
if (cpp_type == field->CPPTYPE_ENUM &&
|
||||
(std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> ||
|
||||
std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t>)) {
|
||||
return;
|
||||
}
|
||||
// Collapse ENUM to INT32 because they are the same through reflection.
|
||||
if (cpp_type == field->CPPTYPE_ENUM) cpp_type = field->CPPTYPE_INT32;
|
||||
ABSL_DCHECK_EQ(+cpp_type, +internal::GetCppType<T>()) << error();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue