Skip to content

Commit

Permalink
Add v2 FieldEntry
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 661433949
  • Loading branch information
protobuf-github-bot authored and copybara-github committed Aug 12, 2024
1 parent 6739739 commit 50f5b18
Show file tree
Hide file tree
Showing 10 changed files with 476 additions and 6 deletions.
226 changes: 226 additions & 0 deletions src/google/protobuf/generated_message_table.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DECL_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DECL_H__

#include <cstdint>

#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].
//
// <<Numerif 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.
enum FieldKind : uint8_t {
kFkShift = 0,
kFkBits = 3,
kFkMask = ((1 << kFkBits) - 1) << kFkShift,

kFkFixed8 = 0, // bool
kFkFixed16, // place holder
kFkFixed32, // (s|u)?int32, (s)?fixed32, float, enum
kFkFixed64, // (s|u)?int64, (s)?fixed64, double
kFkBytes, // bytes
kFkString, // string
kFkMessage, // group, message
kFkMap, // map<...>
};

static_assert(kFkMap < (1 << kFkBits), "too many types");

// Cardinality (2 bits):
// These values determine how many values a field can have and its presence.
enum Cardinality : uint8_t {
kFcShift = kFkShift + kFkBits,
kFcBits = 2,
kFcMask = ((1 << kFcBits) - 1) << kFcShift,

kFcSingular = 0,
kFcOptional = 1 << kFcShift,
kFcRepeated = 2 << kFcShift,
kFcOneof = 3 << kFcShift,
};

// 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.
enum NumericKind : uint8_t {
kNkShift = kFcShift + kFcBits,
kNkBits = 1,
kNkMask = ((1 << kNkBits) - 1) << kNkShift,

kNkUnsigned = 0,
kNkSigned = 1 << kNkShift,
};

// MessageKind (2 bits):
// Indicates if it's LazyField or eager message / group.
enum MessageKind : uint8_t {
kMkShift = kFcShift + kFcBits,
kMkBits = 2,
kMkMask = ((1 << kMkBits) - 1) << kMkShift,

kMkEager = 0,
kMkLazy = 1 << kMkShift,
kMkGroup = 2 << kMkShift,
};

// StringKind (3 bits):
// Indicates if it's LazyField or eager message / group.
enum StringKind : uint8_t {
kSkShift = kFcShift + kFcBits,
kSkBits = 3,
kSkMask = ((1 << kSkBits) - 1) << kSkShift,

kSkArenaPtr = 0,
kSkInlined = 1 << kSkShift,
kSkView = 2 << kSkShift,
kSkCord = 3 << kSkShift,
kSkStringPiece = 4 << kSkShift,
kSkStringPtr = 5 << kSkShift,
};

// Convenience aliases except cardinality (8 bits, with format):
enum FieldType : uint8_t {
// Numeric types:
kBool = 0 | kFkFixed8 | kNkUnsigned,

kInt32 = 0 | kFkFixed32 | kNkSigned,
kSInt32 = 0 | kFkFixed32 | kNkSigned,
kSFixed32 = 0 | kFkFixed32 | kNkSigned,
kUInt32 = 0 | kFkFixed32 | kNkUnsigned,
kFixed32 = 0 | kFkFixed32 | kNkUnsigned,
kFloat = 0 | kFkFixed32 | kNkUnsigned,
kEnum = 0 | kFkFixed32 | kNkSigned,

kInt64 = 0 | kFkFixed64 | kNkSigned,
kSInt64 = 0 | kFkFixed64 | kNkSigned,
kSFixed64 = 0 | kFkFixed64 | kNkSigned,
kUInt64 = 0 | kFkFixed64 | kNkUnsigned,
kFixed64 = 0 | kFkFixed64 | kNkUnsigned,
kDouble = 0 | kFkFixed64 | kNkUnsigned,

// String types:
kBytes = kFkBytes,
kString = kFkString,

// Message types:
kMessage = 0 | kFkMessage | kMkEager,
kLazyMessage = 0 | kFkMessage | kMkLazy,
kGroup = 0 | kFkMessage | kMkGroup,

// Map types:
kMap = kFkMap,
};
// 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::kFkMask; }
uint8_t GetCardinality() const { return field_type & Cardinality::kFcMask; }
uint8_t GetNumericKind() const {
ABSL_DCHECK_LT(GetFieldKind(), FieldKind::kFkBytes);
return field_type & NumericKind::kNkMask;
}
uint8_t GetMessageKind() const {
ABSL_DCHECK_EQ(GetFieldKind(), FieldKind::kFkMessage);
return field_type & MessageKind::kMkMask;
}
uint8_t GetStringKind() const {
ABSL_DCHECK(GetFieldKind() == FieldKind::kFkBytes ||
GetFieldKind() == FieldKind::kFkString);
return field_type & StringKind::kSkMask;
}

bool IsSigned() const { return GetNumericKind() == NumericKind::kNkSigned; }

bool IsRepeated() const {
return GetCardinality() == Cardinality::kFcRepeated;
}

// 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;
};

static_assert(sizeof(FieldEntry) == sizeof(uint64_t), "");

} // namespace v2
} // namespace internal
} // namespace protobuf
} // namespace google

#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DECL_H__
92 changes: 92 additions & 0 deletions src/google/protobuf/generated_message_table_gen.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#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;

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::kString, // 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 == FieldDescriptor::TYPE_MESSAGE
? info.is_lazy ? FieldType::kLazyMessage : FieldType::kMessage
: field_type_to_type_card[field_type];

// Set cardinality.
if (field->is_repeated()) {
type_card |= Cardinality::kFcRepeated;
} else if (field->real_containing_oneof()) {
type_card |= Cardinality::kFcOneof;
} else if (field->has_presence()) {
type_card |= Cardinality::kFcOptional;
} else {
type_card |= Cardinality::kFcSingular;
}

// Set string type specific kind. Note that numerics (signedness) and messages
// (lazy) are already specified.
if (field->cpp_type() != FieldDescriptor::CPPTYPE_STRING) return type_card;

uint8_t string_kind = 0;
switch (field->cpp_string_type()) {
// VIEW fields are treated as
case CppStringType::kView:
case CppStringType::kString:
string_kind = field->is_repeated() ? StringKind::kSkStringPtr
: info.is_inlined ? StringKind::kSkInlined
: StringKind::kSkArenaPtr;
break;
case CppStringType::kCord:
ABSL_CHECK(!info.is_inlined);
string_kind = StringKind::kSkCord;
break;
case CppStringType::kStringPiece:
ABSL_CHECK(!info.is_inlined);
string_kind = StringKind::kSkStringPiece;
break;
default:
Unreachable();
break;
}
return type_card | string_kind;
}

} // namespace v2
} // namespace internal
} // namespace protobuf
} // namespace google
27 changes: 27 additions & 0 deletions src/google/protobuf/generated_message_table_gen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_GEN_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_GEN_H__

#include <cstdint>

#include "google/protobuf/descriptor.h"

// 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;
};

uint8_t MakeTypeCardForField(const FieldDescriptor* field, FieldTypeInfo info);

} // namespace v2
} // namespace internal
} // namespace protobuf
} // namespace google

#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_GEN_H__
Loading

0 comments on commit 50f5b18

Please sign in to comment.