parent
4e362b66bf
commit
a6977fef4c
6 changed files with 589 additions and 0 deletions
@ -0,0 +1,248 @@ |
|||||||
|
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DECL_H__ |
||||||
|
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DECL_H__ |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
#include <limits> |
||||||
|
|
||||||
|
#include "absl/log/absl_check.h" |
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace internal { |
||||||
|
namespace v2 { |
||||||
|
|
||||||
|
// Field layout enums.
|
||||||
|
//
|
||||||
|
// Structural information about fields is packed into a 8-bit value. The enum
|
||||||
|
// types below represent bitwise fields, along with their respective widths,
|
||||||
|
// shifts, and masks. To pack into one byte, some mutually exclusive types share
|
||||||
|
// bits in [5, 7].
|
||||||
|
//
|
||||||
|
// <<Numeric Fields>>
|
||||||
|
// Bit:
|
||||||
|
// +---------------+---------------+
|
||||||
|
// |7 ... 4|3 ... 0|
|
||||||
|
// +---------------+---------------+
|
||||||
|
// : . : . : . : . : 3|===========| [3] FieldKind
|
||||||
|
// : . : . : 5|=======| . : . : . : [2] Cardinality
|
||||||
|
// : . : 6|===| . : . : . : . : . : [1] NumericKind
|
||||||
|
// +---------------+---------------+
|
||||||
|
//
|
||||||
|
// <<Message Fields>>
|
||||||
|
// Bit:
|
||||||
|
// +---------------+---------------+
|
||||||
|
// |7 ... 4|3 ... 0|
|
||||||
|
// +---------------+---------------+
|
||||||
|
// : . : . : . : . : 3|===========| [3] FieldKind
|
||||||
|
// : . : . : 5|=======| . : . : . : [2] Cardinality
|
||||||
|
// : 7|=======| . : . : . : . : . : [2] MessageKind
|
||||||
|
// +---------------+---------------+
|
||||||
|
//
|
||||||
|
// <<String Fields>>
|
||||||
|
// Bit:
|
||||||
|
// +---------------+---------------+
|
||||||
|
// |7 ... 4|3 ... 0|
|
||||||
|
// +---------------+---------------+
|
||||||
|
// : . : . : . : . : 3|===========| [3] FieldKind
|
||||||
|
// : . : . : 5|=======| . : . : . : [2] Cardinality
|
||||||
|
// |===========| . : . : . : . : . : [3] StringKind
|
||||||
|
// +---------------+---------------+
|
||||||
|
//
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
// FieldKind (3 bits):
|
||||||
|
// These values broadly represent a wire type and an in-memory storage class.
|
||||||
|
namespace FieldKind { |
||||||
|
constexpr int kShift = 0; |
||||||
|
constexpr int kBits = 3; |
||||||
|
constexpr int kMask = ((1 << kBits) - 1) << kShift; |
||||||
|
|
||||||
|
enum Kinds : uint8_t { |
||||||
|
kFixed8 = 0, // bool
|
||||||
|
kFixed16, // place holder
|
||||||
|
kFixed32, // (s|u)?int32, (s)?fixed32, float, enum
|
||||||
|
kFixed64, // (s|u)?int64, (s)?fixed64, double
|
||||||
|
kBytes, // bytes
|
||||||
|
kString, // string
|
||||||
|
kMessage, // group, message
|
||||||
|
kMap, // map<...>
|
||||||
|
}; |
||||||
|
|
||||||
|
static_assert(kMap < (1 << kBits), "too many types"); |
||||||
|
} // namespace FieldKind
|
||||||
|
|
||||||
|
// Cardinality (2 bits):
|
||||||
|
// These values determine how many values a field can have and its presence.
|
||||||
|
namespace Cardinality { |
||||||
|
constexpr int kShift = FieldKind::kShift + FieldKind::kBits; |
||||||
|
constexpr int kBits = 2; |
||||||
|
constexpr int kMask = ((1 << kBits) - 1) << kShift; |
||||||
|
|
||||||
|
enum Kinds : uint8_t { |
||||||
|
kSingular = 0, |
||||||
|
kOptional = 1 << kShift, |
||||||
|
kRepeated = 2 << kShift, |
||||||
|
kOneof = 3 << kShift, |
||||||
|
}; |
||||||
|
} // namespace Cardinality
|
||||||
|
|
||||||
|
// NumericKind, MessageKind, StringKind are mutually exclusive and share the
|
||||||
|
// same bit-space (i.e. the same shift).
|
||||||
|
|
||||||
|
// NumericKind (1 bit):
|
||||||
|
// Indicates whether a numeric is signed.
|
||||||
|
namespace NumericKind { |
||||||
|
constexpr int kShift = Cardinality::kShift + Cardinality::kBits; |
||||||
|
constexpr int kBits = 1; |
||||||
|
constexpr int kMask = ((1 << kBits) - 1) << kShift; |
||||||
|
|
||||||
|
enum Kinds : uint8_t { |
||||||
|
kUnsigned = 0, |
||||||
|
kSigned = 1 << kShift, |
||||||
|
}; |
||||||
|
} // namespace NumericKind
|
||||||
|
|
||||||
|
// MessageKind (2 bits):
|
||||||
|
// Indicates if it's LazyField or eager message / group.
|
||||||
|
namespace MessageKind { |
||||||
|
constexpr int kShift = Cardinality::kShift + Cardinality::kBits; |
||||||
|
constexpr int kBits = 2; |
||||||
|
constexpr int kMask = ((1 << kBits) - 1) << kShift; |
||||||
|
|
||||||
|
enum Kinds : uint8_t { |
||||||
|
kEager = 0, |
||||||
|
kLazy = 1 << kShift, |
||||||
|
kGroup = 2 << kShift, |
||||||
|
}; |
||||||
|
} // namespace MessageKind
|
||||||
|
|
||||||
|
// StringKind (3 bits):
|
||||||
|
// Indicates if it's LazyField or eager message / group.
|
||||||
|
namespace StringKind { |
||||||
|
constexpr int kShift = Cardinality::kShift + Cardinality::kBits; |
||||||
|
constexpr int kBits = 3; |
||||||
|
constexpr int kMask = ((1 << kBits) - 1) << kShift; |
||||||
|
|
||||||
|
enum Kinds : uint8_t { |
||||||
|
kArenaPtr = 0, |
||||||
|
kInlined = 1 << kShift, |
||||||
|
kView = 2 << kShift, |
||||||
|
kCord = 3 << kShift, |
||||||
|
kStringPiece = 4 << kShift, |
||||||
|
kStringPtr = 5 << kShift, |
||||||
|
}; |
||||||
|
} // namespace StringKind
|
||||||
|
|
||||||
|
// Convenience aliases except cardinality (8 bits, with format):
|
||||||
|
enum FieldType : uint8_t { |
||||||
|
// Numeric types:
|
||||||
|
kBool = 0 | FieldKind::kFixed8 | NumericKind::kUnsigned, |
||||||
|
|
||||||
|
kInt32 = 0 | FieldKind::kFixed32 | NumericKind::kSigned, |
||||||
|
kSInt32 = 0 | FieldKind::kFixed32 | NumericKind::kSigned, |
||||||
|
kSFixed32 = 0 | FieldKind::kFixed32 | NumericKind::kSigned, |
||||||
|
kUInt32 = 0 | FieldKind::kFixed32 | NumericKind::kUnsigned, |
||||||
|
kFixed32 = 0 | FieldKind::kFixed32 | NumericKind::kUnsigned, |
||||||
|
kFloat = 0 | FieldKind::kFixed32 | NumericKind::kUnsigned, |
||||||
|
kEnum = 0 | FieldKind::kFixed32 | NumericKind::kSigned, |
||||||
|
|
||||||
|
kInt64 = 0 | FieldKind::kFixed64 | NumericKind::kSigned, |
||||||
|
kSInt64 = 0 | FieldKind::kFixed64 | NumericKind::kSigned, |
||||||
|
kSFixed64 = 0 | FieldKind::kFixed64 | NumericKind::kSigned, |
||||||
|
kUInt64 = 0 | FieldKind::kFixed64 | NumericKind::kUnsigned, |
||||||
|
kFixed64 = 0 | FieldKind::kFixed64 | NumericKind::kUnsigned, |
||||||
|
kDouble = 0 | FieldKind::kFixed64 | NumericKind::kUnsigned, |
||||||
|
|
||||||
|
// String types:
|
||||||
|
kBytes = FieldKind::kBytes, |
||||||
|
kString = FieldKind::kString, |
||||||
|
|
||||||
|
// Message types:
|
||||||
|
kMessage = 0 | FieldKind::kMessage | MessageKind::kEager, |
||||||
|
kLazyMessage = 0 | FieldKind::kMessage | MessageKind::kLazy, |
||||||
|
kGroup = 0 | FieldKind::kMessage | MessageKind::kGroup, |
||||||
|
|
||||||
|
// Map types:
|
||||||
|
kMap = FieldKind::kMap, |
||||||
|
}; |
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
struct FieldEntry { |
||||||
|
// Constructors without aux index. (Should be common cases.)
|
||||||
|
constexpr FieldEntry(uint8_t type, uint8_t hasbit_index, uint16_t offset, |
||||||
|
uint16_t number) |
||||||
|
: field_type(type), |
||||||
|
hasbit_index(hasbit_index), |
||||||
|
offset(offset), |
||||||
|
field_number(number), |
||||||
|
aux_index(kNoAuxIdx) {} |
||||||
|
|
||||||
|
// If any of hasbit_index, offset, field_number is too big to fit, fallback to
|
||||||
|
// aux entry for all.
|
||||||
|
constexpr FieldEntry(uint8_t type, uint16_t aux_index) |
||||||
|
: field_type(type), |
||||||
|
hasbit_index(kHasbitFallbackToAux), |
||||||
|
offset(kFallbackToAux), |
||||||
|
field_number(kFallbackToAux), |
||||||
|
aux_index(aux_index) {} |
||||||
|
|
||||||
|
constexpr bool ShouldLookupAuxEntry() const { return aux_index != kNoAuxIdx; } |
||||||
|
|
||||||
|
uint8_t GetFieldKind() const { return field_type & FieldKind::kMask; } |
||||||
|
uint8_t GetCardinality() const { return field_type & Cardinality::kMask; } |
||||||
|
uint8_t GetNumericKind() const { |
||||||
|
ABSL_DCHECK_LT(GetFieldKind(), FieldKind::kBytes); |
||||||
|
return field_type & NumericKind::kMask; |
||||||
|
} |
||||||
|
uint8_t GetMessageKind() const { |
||||||
|
ABSL_DCHECK_EQ(GetFieldKind(), FieldKind::kMessage); |
||||||
|
return field_type & MessageKind::kMask; |
||||||
|
} |
||||||
|
uint8_t GetStringKind() const { |
||||||
|
ABSL_DCHECK(GetFieldKind() == FieldKind::kBytes || |
||||||
|
GetFieldKind() == FieldKind::kString); |
||||||
|
return field_type & StringKind::kMask; |
||||||
|
} |
||||||
|
|
||||||
|
bool IsSigned() const { return GetNumericKind() == NumericKind::kSigned; } |
||||||
|
bool IsUTF8() const { |
||||||
|
ABSL_DCHECK(GetFieldKind() == FieldKind::kBytes || |
||||||
|
GetFieldKind() == FieldKind::kString); |
||||||
|
return GetFieldKind() == FieldKind::kString; |
||||||
|
} |
||||||
|
|
||||||
|
bool IsRepeated() const { return GetCardinality() == Cardinality::kRepeated; } |
||||||
|
|
||||||
|
// Field type consists of FieldKind, Cardinality and type-specific Kind.
|
||||||
|
uint8_t field_type; |
||||||
|
// Covers up to 256 fields. Fallback to aux if 0xFF.
|
||||||
|
uint8_t hasbit_index; |
||||||
|
// Covers sizeof(Message) up to 64 KiB. Fallback to aux if 0xFFFF.
|
||||||
|
uint16_t offset; |
||||||
|
// Most field numbers should fit 16 bits. Fallback to aux if 0xFFFF.
|
||||||
|
uint16_t field_number; |
||||||
|
// Only up to 2^16 fallback cases are supported.
|
||||||
|
uint16_t aux_index; |
||||||
|
|
||||||
|
static constexpr uint16_t kHasbitFallbackToAux = 0xFF; |
||||||
|
static constexpr uint16_t kFallbackToAux = 0xFFFF; |
||||||
|
static constexpr uint16_t kNoAuxIdx = 0xFFFF; |
||||||
|
|
||||||
|
// These constants are same as the above but compared against values from
|
||||||
|
// reflection or protoc (hence different types) to determine whether to use
|
||||||
|
// aux entries.
|
||||||
|
static constexpr uint32_t kHasbitIdxLimit = |
||||||
|
std::numeric_limits<uint8_t>::max(); |
||||||
|
static constexpr uint32_t kOffsetLimit = std::numeric_limits<uint16_t>::max(); |
||||||
|
static constexpr int kFieldNumberLimit = std::numeric_limits<uint16_t>::max(); |
||||||
|
}; |
||||||
|
|
||||||
|
static_assert(sizeof(FieldEntry) == sizeof(uint64_t), ""); |
||||||
|
|
||||||
|
} // namespace v2
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
||||||
|
|
||||||
|
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DECL_H__
|
@ -0,0 +1,100 @@ |
|||||||
|
#include "google/protobuf/generated_message_table_gen.h" |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
|
||||||
|
#include "absl/log/absl_check.h" |
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
#include "google/protobuf/generated_message_table.h" |
||||||
|
#include "google/protobuf/port.h" |
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace internal { |
||||||
|
namespace v2 { |
||||||
|
|
||||||
|
using CppStringType = FieldDescriptor::CppStringType; |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
uint8_t GenerateStringKind(const FieldDescriptor* field, bool is_inlined) { |
||||||
|
switch (field->cpp_string_type()) { |
||||||
|
// VIEW fields are treated as strings for now.
|
||||||
|
case CppStringType::kView: |
||||||
|
case CppStringType::kString: |
||||||
|
return field->is_repeated() ? StringKind::kStringPtr |
||||||
|
: is_inlined ? StringKind::kInlined |
||||||
|
: StringKind::kArenaPtr; |
||||||
|
case CppStringType::kCord: |
||||||
|
ABSL_CHECK(!is_inlined); |
||||||
|
return StringKind::kCord; |
||||||
|
default: |
||||||
|
Unreachable(); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
uint8_t MakeTypeCardForField(const FieldDescriptor* field, FieldTypeInfo info) { |
||||||
|
constexpr uint8_t field_type_to_type_card[] = { |
||||||
|
0, // placeholder as type starts from 1.
|
||||||
|
FieldType::kDouble, // TYPE_DOUBLE
|
||||||
|
FieldType::kFloat, // TYPE_FLOAT
|
||||||
|
FieldType::kInt64, // TYPE_INT64
|
||||||
|
FieldType::kUInt64, // TYPE_UINT64
|
||||||
|
FieldType::kInt32, // TYPE_INT32
|
||||||
|
FieldType::kFixed64, // TYPE_FIXED64
|
||||||
|
FieldType::kFixed32, // TYPE_FIXED32
|
||||||
|
FieldType::kBool, // TYPE_BOOL
|
||||||
|
FieldType::kBytes, // TYPE_STRING
|
||||||
|
FieldType::kGroup, // TYPE_GROUP
|
||||||
|
FieldType::kMessage, // TYPE_MESSAGE
|
||||||
|
FieldType::kBytes, // TYPE_BYTES
|
||||||
|
FieldType::kUInt32, // TYPE_UINT32
|
||||||
|
FieldType::kEnum, // TYPE_ENUM
|
||||||
|
FieldType::kSFixed32, // TYPE_SFIXED32
|
||||||
|
FieldType::kSFixed64, // TYPE_SFIXED64
|
||||||
|
FieldType::kSInt32, // TYPE_SINT32
|
||||||
|
FieldType::kSInt64, // TYPE_SINT64
|
||||||
|
}; |
||||||
|
static_assert( |
||||||
|
sizeof(field_type_to_type_card) == (FieldDescriptor::MAX_TYPE + 1), ""); |
||||||
|
|
||||||
|
if (field->is_map()) return FieldType::kMap; |
||||||
|
|
||||||
|
auto field_type = field->type(); |
||||||
|
uint8_t type_card = field_type_to_type_card[field_type]; |
||||||
|
// Override previously set type for lazy message and UTF8 strings.
|
||||||
|
switch (field_type) { |
||||||
|
case FieldDescriptor::TYPE_MESSAGE: |
||||||
|
if (info.is_lazy) type_card = FieldType::kLazyMessage; |
||||||
|
break; |
||||||
|
case FieldDescriptor::TYPE_STRING: |
||||||
|
if (field->requires_utf8_validation()) type_card = FieldType::kString; |
||||||
|
break; |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
// Set cardinality.
|
||||||
|
if (field->is_repeated()) { |
||||||
|
type_card |= Cardinality::kRepeated; |
||||||
|
} else if (field->real_containing_oneof()) { |
||||||
|
type_card |= Cardinality::kOneof; |
||||||
|
} else if (field->has_presence()) { |
||||||
|
type_card |= Cardinality::kOptional; |
||||||
|
} else { |
||||||
|
type_card |= Cardinality::kSingular; |
||||||
|
} |
||||||
|
|
||||||
|
// Set StringKind for string fields. Note that numerics (signedness) and
|
||||||
|
// messages (lazy) are already specified.
|
||||||
|
return field->cpp_type() != FieldDescriptor::CPPTYPE_STRING |
||||||
|
? type_card |
||||||
|
: type_card | GenerateStringKind(field, info.is_inlined); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace v2
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
@ -0,0 +1,36 @@ |
|||||||
|
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_GEN_H__ |
||||||
|
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_GEN_H__ |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
|
||||||
|
#include "google/protobuf/descriptor.h" |
||||||
|
|
||||||
|
// Must be included last.
|
||||||
|
#include "google/protobuf/port_def.inc" |
||||||
|
|
||||||
|
// This file contains types and APIs to generate tables for v2 wireformat.
|
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace internal { |
||||||
|
namespace v2 { |
||||||
|
|
||||||
|
struct FieldTypeInfo { |
||||||
|
bool is_inlined; |
||||||
|
bool is_lazy; |
||||||
|
}; |
||||||
|
|
||||||
|
// Returns 8 bit type card for a given field. Type cards contains information
|
||||||
|
// about field types and cardinality that are needed to iterate fields per
|
||||||
|
// message.
|
||||||
|
PROTOBUF_EXPORT uint8_t MakeTypeCardForField(const FieldDescriptor* field, |
||||||
|
FieldTypeInfo info); |
||||||
|
|
||||||
|
} // namespace v2
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
||||||
|
|
||||||
|
#include "google/protobuf/port_undef.inc" |
||||||
|
|
||||||
|
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_GEN_H__
|
@ -0,0 +1,182 @@ |
|||||||
|
#include "google/protobuf/generated_message_table_gen.h" |
||||||
|
|
||||||
|
#include <cctype> |
||||||
|
#include <cstdint> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <gtest/gtest.h> |
||||||
|
#include "absl/algorithm/container.h" |
||||||
|
#include "absl/log/absl_check.h" |
||||||
|
#include "google/protobuf/generated_message_table.h" |
||||||
|
#include "google/protobuf/port.h" |
||||||
|
#include "google/protobuf/unittest.pb.h" |
||||||
|
#include "google/protobuf/unittest_mset.pb.h" |
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace internal { |
||||||
|
namespace v2 { |
||||||
|
|
||||||
|
class V2TableGenTester { |
||||||
|
public: |
||||||
|
static uint32_t HasBitIndex(const Reflection* reflection, |
||||||
|
const FieldDescriptor* field) { |
||||||
|
return reflection->schema_.HasBitIndex(field); |
||||||
|
} |
||||||
|
static uint32_t GetFieldOffset(const Reflection* reflection, |
||||||
|
const FieldDescriptor* field) { |
||||||
|
return reflection->schema_.GetFieldOffset(field); |
||||||
|
} |
||||||
|
static bool IsLazyField(const Reflection* reflection, |
||||||
|
const FieldDescriptor* field) { |
||||||
|
ABSL_CHECK(!field->is_extension()); |
||||||
|
return reflection->IsLazyField(field); |
||||||
|
} |
||||||
|
static bool IsInlined(const Reflection* reflection, |
||||||
|
const FieldDescriptor* field) { |
||||||
|
return reflection->schema_.IsFieldInlined(field); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
using ::protobuf_unittest::TestAllTypes; |
||||||
|
using ::protobuf_unittest::TestMessageSetExtension1; |
||||||
|
|
||||||
|
// Creates FieldEntry that won't require AuxEntry, which requires all fields to
|
||||||
|
// fit into smaller (but common) limit. Specifically, hasbit_index for 1B,
|
||||||
|
// offset and field number for 2B.
|
||||||
|
FieldEntry CreateFieldEntryWithoutAux(const Reflection* reflection, |
||||||
|
const Message* message, |
||||||
|
const FieldDescriptor* field) { |
||||||
|
ABSL_CHECK_EQ(reflection, message->GetReflection()); |
||||||
|
|
||||||
|
uint32_t hasbit_index = V2TableGenTester::HasBitIndex(reflection, field); |
||||||
|
uint32_t offset = V2TableGenTester::GetFieldOffset(reflection, field); |
||||||
|
|
||||||
|
// CHECK if "field" cannot fit into FieldEntry alone and require AuxEntry.
|
||||||
|
static constexpr uint32_t kNoHasbit = static_cast<uint32_t>(-1); |
||||||
|
ABSL_CHECK(hasbit_index == kNoHasbit || |
||||||
|
hasbit_index < FieldEntry::kHasbitIdxLimit); |
||||||
|
ABSL_CHECK_LT(offset, FieldEntry::kOffsetLimit); |
||||||
|
ABSL_CHECK_LT(field->number(), FieldEntry::kFieldNumberLimit); |
||||||
|
|
||||||
|
bool is_lazy = V2TableGenTester::IsLazyField(reflection, field); |
||||||
|
bool is_inlined = V2TableGenTester::IsInlined(reflection, field); |
||||||
|
|
||||||
|
return FieldEntry(MakeTypeCardForField(field, {is_inlined, is_lazy}), |
||||||
|
hasbit_index, offset, field->number()); |
||||||
|
} |
||||||
|
|
||||||
|
class TableGenTest : public testing::TestWithParam<const Message*> { |
||||||
|
public: |
||||||
|
TableGenTest() |
||||||
|
: message_(GetParam()), reflection_(message_->GetReflection()) {} |
||||||
|
|
||||||
|
protected: |
||||||
|
const Message* message_; |
||||||
|
const Reflection* reflection_; |
||||||
|
}; |
||||||
|
|
||||||
|
TEST_P(TableGenTest, ValidateTypeCardForField) { |
||||||
|
const Descriptor* desc = message_->GetDescriptor(); |
||||||
|
for (int i = 0, count = desc->field_count(); i < count; ++i) { |
||||||
|
const FieldDescriptor* field = desc->field(i); |
||||||
|
auto field_entry = CreateFieldEntryWithoutAux(reflection_, message_, field); |
||||||
|
|
||||||
|
// Validate cardinality.
|
||||||
|
EXPECT_EQ(field->is_repeated(), field_entry.IsRepeated()); |
||||||
|
uint8_t cardinality = field_entry.GetCardinality(); |
||||||
|
switch (cardinality) { |
||||||
|
case Cardinality::kRepeated: |
||||||
|
EXPECT_TRUE(field->is_repeated()); |
||||||
|
break; |
||||||
|
case Cardinality::kOptional: |
||||||
|
EXPECT_FALSE(field->is_repeated()); |
||||||
|
EXPECT_TRUE(field->has_presence()); |
||||||
|
break; |
||||||
|
case Cardinality::kSingular: |
||||||
|
EXPECT_FALSE(field->is_repeated()); |
||||||
|
EXPECT_FALSE(field->has_presence()); |
||||||
|
break; |
||||||
|
case Cardinality::kOneof: |
||||||
|
EXPECT_FALSE(field->is_repeated()); |
||||||
|
EXPECT_TRUE(field->real_containing_oneof()); |
||||||
|
break; |
||||||
|
default: |
||||||
|
Unreachable(); |
||||||
|
break; |
||||||
|
} |
||||||
|
EXPECT_EQ(field->is_repeated(), field_entry.IsRepeated()); |
||||||
|
|
||||||
|
// Validate field types, etc.
|
||||||
|
switch (field->cpp_type()) { |
||||||
|
case FieldDescriptor::CPPTYPE_ENUM: |
||||||
|
case FieldDescriptor::CPPTYPE_INT32: |
||||||
|
EXPECT_EQ(field_entry.GetFieldKind(), FieldKind::kFixed32); |
||||||
|
EXPECT_TRUE(field_entry.IsSigned()); |
||||||
|
break; |
||||||
|
case FieldDescriptor::CPPTYPE_INT64: |
||||||
|
EXPECT_EQ(field_entry.GetFieldKind(), FieldKind::kFixed64); |
||||||
|
EXPECT_TRUE(field_entry.IsSigned()); |
||||||
|
break; |
||||||
|
case FieldDescriptor::CPPTYPE_FLOAT: |
||||||
|
case FieldDescriptor::CPPTYPE_UINT32: |
||||||
|
EXPECT_EQ(field_entry.GetFieldKind(), FieldKind::kFixed32); |
||||||
|
EXPECT_FALSE(field_entry.IsSigned()); |
||||||
|
break; |
||||||
|
case FieldDescriptor::CPPTYPE_DOUBLE: |
||||||
|
case FieldDescriptor::CPPTYPE_UINT64: |
||||||
|
EXPECT_EQ(field_entry.GetFieldKind(), FieldKind::kFixed64); |
||||||
|
EXPECT_FALSE(field_entry.IsSigned()); |
||||||
|
break; |
||||||
|
case FieldDescriptor::CPPTYPE_BOOL: |
||||||
|
EXPECT_EQ(field_entry.GetFieldKind(), FieldKind::kFixed8); |
||||||
|
EXPECT_FALSE(field_entry.IsSigned()); |
||||||
|
break; |
||||||
|
case FieldDescriptor::CPPTYPE_STRING: |
||||||
|
EXPECT_EQ(field->requires_utf8_validation(), field_entry.IsUTF8()) |
||||||
|
<< field->full_name(); |
||||||
|
|
||||||
|
switch (field->cpp_string_type()) { |
||||||
|
case FieldDescriptor::CppStringType::kView: |
||||||
|
EXPECT_EQ(field_entry.GetStringKind(), StringKind::kView); |
||||||
|
break; |
||||||
|
case FieldDescriptor::CppStringType::kCord: |
||||||
|
EXPECT_EQ(field_entry.GetStringKind(), StringKind::kCord); |
||||||
|
break; |
||||||
|
case FieldDescriptor::CppStringType::kString: |
||||||
|
if (field->is_repeated()) { |
||||||
|
EXPECT_EQ(field_entry.GetStringKind(), StringKind::kStringPtr); |
||||||
|
} else if (V2TableGenTester::IsInlined(reflection_, field)) { |
||||||
|
EXPECT_EQ(field_entry.GetStringKind(), StringKind::kInlined); |
||||||
|
} else { |
||||||
|
EXPECT_EQ(field_entry.GetStringKind(), StringKind::kArenaPtr); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
break; |
||||||
|
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||||
|
break; |
||||||
|
default: |
||||||
|
Unreachable(); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P( |
||||||
|
V2, TableGenTest, |
||||||
|
testing::Values(&TestAllTypes::default_instance(), |
||||||
|
&TestMessageSetExtension1::default_instance()), |
||||||
|
[](const testing::TestParamInfo<TableGenTest::ParamType>& info) { |
||||||
|
std::string name = info.param->GetTypeName(); |
||||||
|
absl::c_replace_if(name, [](char c) { return !std::isalnum(c); }, '_'); |
||||||
|
return name; |
||||||
|
}); |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace v2
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
Loading…
Reference in new issue