blob: bca311a4f8ac44f31c031eb9d35557f009a68930 [file] [log] [blame]
#ifndef GOOGLE_PROTOBUF_REFLECTION_VISIT_FIELD_INFO_H__
#define GOOGLE_PROTOBUF_REFLECTION_VISIT_FIELD_INFO_H__
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/log/absl_check.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/arenastring.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/extension_set.h"
#include "google/protobuf/inlined_string_field.h"
#include "google/protobuf/map_field.h"
#include "google/protobuf/message.h"
#include "google/protobuf/port.h"
#include "google/protobuf/wire_format_lite.h"
// clang-format off
#include "google/protobuf/port_def.inc"
// clang-format on
namespace google {
namespace protobuf {
namespace internal {
// A range adaptor for a pair of iterators.
//
// This just wraps two iterators into a range-compatible interface. Nothing
// fancy at all.
template <typename IteratorT>
class iterator_range {
public:
using iterator = IteratorT;
using const_iterator = IteratorT;
using value_type = typename std::iterator_traits<IteratorT>::value_type;
iterator_range() : begin_iterator_(), end_iterator_() {}
iterator_range(IteratorT begin_iterator, IteratorT end_iterator)
: begin_iterator_(std::move(begin_iterator)),
end_iterator_(std::move(end_iterator)) {}
IteratorT begin() const { return begin_iterator_; }
IteratorT end() const { return end_iterator_; }
// Returns the size of the wrapped range. Does not participate in overload
// resolution for non-random-access iterators, since in those cases this is a
// slow operation (it must walk the entire range and maintain a count).
//
// Users who need to know the "size" of a non-random-access iterator_range
// should pass the range to `absl::c_distance()` instead.
template <class It = IteratorT>
typename std::enable_if<std::is_base_of<std::random_access_iterator_tag,
typename std::iterator_traits<
It>::iterator_category>::value,
size_t>::type
size() const {
return std::distance(begin_iterator_, end_iterator_);
}
// Returns true if this iterator range refers to an empty sequence, and false
// otherwise.
bool empty() const { return begin_iterator_ == end_iterator_; }
private:
IteratorT begin_iterator_, end_iterator_;
};
#ifdef __cpp_if_constexpr
template <bool is_oneof>
struct DynamicFieldInfoHelper {
template <typename T>
static T Get(const Reflection* reflection, const Message& message,
const FieldDescriptor* field) {
if constexpr (is_oneof) {
return reflection->GetRaw<T>(message, field);
} else {
return reflection->GetRawNonOneof<T>(message, field);
}
}
template <typename T>
static T& GetRef(const Reflection* reflection, const Message& message,
const FieldDescriptor* field) {
if constexpr (is_oneof) {
return reflection->GetRaw<T>(message, field);
} else {
return reflection->GetRawNonOneof<T>(message, field);
}
}
template <typename T>
static T& Mutable(const Reflection* reflection, Message& message,
const FieldDescriptor* field) {
if constexpr (is_oneof) {
return *reflection->MutableRaw<T>(&message, field);
} else {
return *reflection->MutableRawNonOneof<T>(&message, field);
}
}
static void ClearField(const Reflection* reflection, Message& message,
const FieldDescriptor* field) {
if constexpr (is_oneof) {
reflection->ClearOneofField(&message, field);
} else {
reflection->ClearField(&message, field);
}
}
static absl::string_view GetStringView(const Reflection* reflection,
const Message& message,
const FieldDescriptor* field) {
auto ctype = cpp::EffectiveStringCType(field);
ABSL_DCHECK_NE(ctype, FieldOptions::CORD);
ABSL_DCHECK(!is_oneof || reflection->HasOneofField(message, field));
auto str = Get<ArenaStringPtr>(reflection, message, field);
ABSL_DCHECK(!str.IsDefault());
return str.Get();
}
};
struct DynamicExtensionInfoHelper {
using Extension = ExtensionSet::Extension;
#define PROTOBUF_SINGULAR_PRIMITIVE_METHOD(NAME, FIELD_TYPE, VAR) \
static FIELD_TYPE Get##NAME(const Extension& ext) { \
return ext.VAR##_value; \
} \
static void Set##NAME(Extension& ext, FIELD_TYPE value) { \
ext.VAR##_value = value; \
} \
static void Clear##NAME(Extension& ext) { ext.is_cleared = true; }
PROTOBUF_SINGULAR_PRIMITIVE_METHOD(Int32, int32_t, int32_t);
PROTOBUF_SINGULAR_PRIMITIVE_METHOD(Int64, int64_t, int64_t);
PROTOBUF_SINGULAR_PRIMITIVE_METHOD(UInt32, uint32_t, uint32_t);
PROTOBUF_SINGULAR_PRIMITIVE_METHOD(UInt64, uint64_t, uint64_t);
PROTOBUF_SINGULAR_PRIMITIVE_METHOD(Float, float, float);
PROTOBUF_SINGULAR_PRIMITIVE_METHOD(Double, double, double);
PROTOBUF_SINGULAR_PRIMITIVE_METHOD(Bool, bool, bool);
PROTOBUF_SINGULAR_PRIMITIVE_METHOD(Enum, int, enum);
#undef PROTOBUF_SINGULAR_PRIMITIVE_METHOD
#define PROTOBUF_REPEATED_FIELD_METHODS(NAME, FIELD_TYPE, VAR) \
static const RepeatedField<FIELD_TYPE>* GetRepeated##NAME( \
const Extension& ext) { \
return ext.repeated_##VAR##_value; \
} \
static RepeatedField<FIELD_TYPE>* MutableRepeated##NAME(Extension& ext) { \
return ext.repeated_##VAR##_value; \
} \
static void ClearRepeated##NAME(Extension& ext) { \
return ext.repeated_##VAR##_value->Clear(); \
}
PROTOBUF_REPEATED_FIELD_METHODS(Int32, int32_t, int32_t);
PROTOBUF_REPEATED_FIELD_METHODS(Int64, int64_t, int64_t);
PROTOBUF_REPEATED_FIELD_METHODS(UInt32, uint32_t, uint32_t);
PROTOBUF_REPEATED_FIELD_METHODS(UInt64, uint64_t, uint64_t);
PROTOBUF_REPEATED_FIELD_METHODS(Float, float, float);
PROTOBUF_REPEATED_FIELD_METHODS(Double, double, double);
PROTOBUF_REPEATED_FIELD_METHODS(Bool, bool, bool);
PROTOBUF_REPEATED_FIELD_METHODS(Enum, int, enum);
#undef PROTOBUF_REPEATED_FIELD_METHODS
#define PROTOBUF_REPEATED_PTR_FIELD_METHODS(FIELD_TYPE, NAME, VAR) \
static const RepeatedPtrField<FIELD_TYPE>* GetRepeated##NAME( \
const Extension& ext) { \
return ext.repeated_##VAR##_value; \
} \
static RepeatedPtrField<FIELD_TYPE>* MutableRepeated##NAME(Extension& ext) { \
return ext.repeated_##VAR##_value; \
} \
static void ClearRepeated##NAME(Extension& ext) { \
return ext.repeated_##VAR##_value->Clear(); \
}
PROTOBUF_REPEATED_PTR_FIELD_METHODS(std::string, String, string);
PROTOBUF_REPEATED_PTR_FIELD_METHODS(MessageLite, Message, message);
#undef PROTOBUF_REPEATED_PTR_FIELD_METHODS
static absl::string_view GetStringView(const Extension& ext) {
return *ext.string_value;
}
static void SetStringView(Extension& ext, absl::string_view value) {
ext.string_value->assign(value.data(), value.size());
}
static void ClearStringView(Extension& ext) {
ext.is_cleared = true;
ext.string_value->clear();
}
static const Message& GetMessage(const Extension& ext) {
return DownCast<const Message&>(*ext.message_value);
}
static Message& MutableMessage(Extension& ext) {
return DownCast<Message&>(*ext.message_value);
}
static void ClearMessage(Extension& ext) {
ext.is_cleared = true;
ext.message_value->Clear();
}
static const Message& GetLazyMessage(const Extension& ext,
const Message& prototype, Arena* arena) {
return DownCast<const Message&>(
ext.lazymessage_value->GetMessage(prototype, arena));
}
static const Message& GetLazyMessageIgnoreUnparsed(const Extension& ext,
const Message& prototype,
Arena* arena) {
return DownCast<const Message&>(
ext.lazymessage_value->GetMessageIgnoreUnparsed(prototype, arena));
}
static Message& MutableLazyMessage(Extension& ext, const Message& prototype,
Arena* arena) {
return DownCast<Message&>(
*ext.lazymessage_value->MutableMessage(prototype, arena));
}
static void ClearLazyMessage(Extension& ext) {
ext.is_cleared = true;
return ext.lazymessage_value->Clear();
}
static size_t ByteSizeLongLazyMessage(const Extension& ext) {
return ext.lazymessage_value->ByteSizeLong();
}
};
////////////////////////////////////////////////////////////////////////
// Primitive fields
////////////////////////////////////////////////////////////////////////
template <typename MessageT, typename FieldT,
FieldDescriptor::CppType cpp_type_parameter, bool is_oneof_parameter>
struct SingularPrimitive {
constexpr SingularPrimitive(const Reflection* r, MessageT& m,
const FieldDescriptor* f)
: reflection(r), message(m), field(f) {}
int number() const { return field->number(); }
FieldDescriptor::Type type() const { return field->type(); }
FieldT Get() const {
return DynamicFieldInfoHelper<is_oneof>::template Get<FieldT>(
reflection, message, field);
}
void Set(FieldT value) {
DynamicFieldInfoHelper<is_oneof>::template Mutable<FieldT>(
reflection, message, field) = value;
}
void Clear() {
DynamicFieldInfoHelper<is_oneof>::ClearField(reflection, message, field);
}
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
cpp_type_parameter;
static constexpr bool is_repeated = false; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = false; // NOLINT
static constexpr bool is_oneof = is_oneof_parameter; // NOLINT
const Reflection* reflection;
MessageT& message;
const FieldDescriptor* field;
};
#define PROTOBUF_DYN_FIELD_INFO_VARINT(NAME, CPPTYPE, FIELD_TYPE) \
template <typename MessageT, bool is_oneof> \
struct NAME##DynamicFieldInfo \
: SingularPrimitive<MessageT, FIELD_TYPE, \
FieldDescriptor::CPPTYPE_##CPPTYPE, is_oneof> { \
using BaseT = \
SingularPrimitive<MessageT, FIELD_TYPE, \
FieldDescriptor::CPPTYPE_##CPPTYPE, is_oneof>; \
\
constexpr NAME##DynamicFieldInfo(const Reflection* r, MessageT& m, \
const FieldDescriptor* f) \
: BaseT(r, m, f) {} \
size_t FieldByteSize() const { \
return WireFormatLite::NAME##Size(BaseT::Get()); \
} \
};
#define PROTOBUF_DYN_FIELD_INFO_FIXED(NAME, CPPTYPE, FIELD_TYPE) \
template <typename MessageT, bool is_oneof> \
struct NAME##DynamicFieldInfo \
: SingularPrimitive<MessageT, FIELD_TYPE, \
FieldDescriptor::CPPTYPE_##CPPTYPE, is_oneof> { \
using BaseT = \
SingularPrimitive<MessageT, FIELD_TYPE, \
FieldDescriptor::CPPTYPE_##CPPTYPE, is_oneof>; \
\
constexpr NAME##DynamicFieldInfo(const Reflection* r, MessageT& m, \
const FieldDescriptor* f) \
: BaseT(r, m, f) {} \
constexpr size_t FieldByteSize() const { \
return WireFormatLite::k##NAME##Size; \
} \
};
PROTOBUF_DYN_FIELD_INFO_VARINT(Int32, INT32, int32_t);
PROTOBUF_DYN_FIELD_INFO_VARINT(Int64, INT64, int64_t);
PROTOBUF_DYN_FIELD_INFO_VARINT(UInt32, UINT32, uint32_t);
PROTOBUF_DYN_FIELD_INFO_VARINT(UInt64, UINT64, uint64_t);
PROTOBUF_DYN_FIELD_INFO_VARINT(SInt32, INT32, int32_t);
PROTOBUF_DYN_FIELD_INFO_VARINT(SInt64, INT64, int64_t);
PROTOBUF_DYN_FIELD_INFO_FIXED(Fixed32, UINT32, uint32_t);
PROTOBUF_DYN_FIELD_INFO_FIXED(Fixed64, UINT64, uint64_t);
PROTOBUF_DYN_FIELD_INFO_FIXED(SFixed32, INT32, int32_t);
PROTOBUF_DYN_FIELD_INFO_FIXED(SFixed64, INT64, int64_t);
PROTOBUF_DYN_FIELD_INFO_FIXED(Double, DOUBLE, double);
PROTOBUF_DYN_FIELD_INFO_FIXED(Float, FLOAT, float);
PROTOBUF_DYN_FIELD_INFO_FIXED(Bool, BOOL, bool);
#undef PROTOBUF_DYN_FIELD_INFO_VARINT
#undef PROTOBUF_DYN_FIELD_INFO_FIXED
////////////////////////////////////////////////////////////////////////
// Extension primitive fields
////////////////////////////////////////////////////////////////////////
#define PROTOBUF_DYN_EXTENSION_INFO_VARINT(NAME, CPPNAME, CPPTYPE, FIELD_TYPE) \
template <typename ExtensionT> \
struct NAME##DynamicExtensionInfo { \
constexpr NAME##DynamicExtensionInfo(ExtensionT& e, int n) \
: ext(e), ext_number(n) {} \
int number() const { return ext_number; } \
FieldDescriptor::Type type() const { \
return static_cast<FieldDescriptor::Type>(ext.type); \
} \
FIELD_TYPE Get() const { \
return DynamicExtensionInfoHelper::Get##CPPNAME(ext); \
} \
void Set(FIELD_TYPE value) { \
DynamicExtensionInfoHelper::Set##CPPNAME(ext, value); \
} \
void Clear() { DynamicExtensionInfoHelper::Clear##CPPNAME(ext); } \
size_t FieldByteSize() const { return WireFormatLite::NAME##Size(Get()); } \
\
static constexpr FieldDescriptor::CppType cpp_type = \
FieldDescriptor::CPPTYPE_##CPPTYPE; \
static constexpr bool is_repeated = false; \
static constexpr bool is_map = false; \
static constexpr bool is_extension = true; \
static constexpr bool is_oneof = false; \
\
ExtensionT& ext; \
int ext_number; \
};
#define PROTOBUF_DYN_EXTENSION_INFO_FIXED(NAME, CPPNAME, CPPTYPE, FIELD_TYPE) \
template <typename ExtensionT> \
struct NAME##DynamicExtensionInfo { \
constexpr NAME##DynamicExtensionInfo(ExtensionT& e, int n) \
: ext(e), ext_number(n) {} \
int number() const { return ext_number; } \
FieldDescriptor::Type type() const { \
return static_cast<FieldDescriptor::Type>(ext.type); \
} \
FIELD_TYPE Get() const { \
return DynamicExtensionInfoHelper::Get##CPPNAME(ext); \
} \
void Set(FIELD_TYPE value) { \
DynamicExtensionInfoHelper::Set##CPPNAME(ext, value); \
} \
void Clear() { DynamicExtensionInfoHelper::Clear##CPPNAME(ext); } \
constexpr size_t FieldByteSize() const { \
return WireFormatLite::k##NAME##Size; \
} \
\
static constexpr FieldDescriptor::CppType cpp_type = \
FieldDescriptor::CPPTYPE_##CPPTYPE; \
static constexpr bool is_repeated = false; \
static constexpr bool is_map = false; \
static constexpr bool is_extension = true; \
static constexpr bool is_oneof = false; \
\
ExtensionT& ext; \
int ext_number; \
};
PROTOBUF_DYN_EXTENSION_INFO_VARINT(Int32, Int32, INT32, int32_t);
PROTOBUF_DYN_EXTENSION_INFO_VARINT(Int64, Int64, INT64, int64_t);
PROTOBUF_DYN_EXTENSION_INFO_VARINT(UInt32, UInt32, UINT32, uint32_t);
PROTOBUF_DYN_EXTENSION_INFO_VARINT(UInt64, UInt64, UINT64, uint64_t);
PROTOBUF_DYN_EXTENSION_INFO_VARINT(SInt32, Int32, INT32, int32_t);
PROTOBUF_DYN_EXTENSION_INFO_VARINT(SInt64, Int64, INT64, int64_t);
PROTOBUF_DYN_EXTENSION_INFO_VARINT(Enum, Enum, ENUM, int);
PROTOBUF_DYN_EXTENSION_INFO_FIXED(Fixed32, UInt32, UINT32, uint32_t);
PROTOBUF_DYN_EXTENSION_INFO_FIXED(Fixed64, UInt64, UINT64, uint64_t);
PROTOBUF_DYN_EXTENSION_INFO_FIXED(SFixed32, Int32, INT32, int32_t);
PROTOBUF_DYN_EXTENSION_INFO_FIXED(SFixed64, Int64, INT64, int64_t);
PROTOBUF_DYN_EXTENSION_INFO_FIXED(Double, Double, DOUBLE, double);
PROTOBUF_DYN_EXTENSION_INFO_FIXED(Float, Float, FLOAT, float);
PROTOBUF_DYN_EXTENSION_INFO_FIXED(Bool, Bool, BOOL, bool);
#undef PROTOBUF_DYN_EXTENSION_INFO_VARINT
#undef PROTOBUF_DYN_EXTENSION_INFO_FIXED
////////////////////////////////////////////////////////////////////////
// Enum fields (to handle closed enums).
////////////////////////////////////////////////////////////////////////
template <typename MessageT, bool is_oneof_parameter>
struct EnumDynamicFieldInfo {
constexpr EnumDynamicFieldInfo(const Reflection* r, MessageT& m,
const FieldDescriptor* f)
: reflection(r), message(m), field(f) {}
int number() const { return field->number(); }
FieldDescriptor::Type type() const { return field->type(); }
int Get() const {
if constexpr (is_oneof) {
return reflection->GetEnumValue(message, field);
} else {
return DynamicFieldInfoHelper<false>::Get<int>(reflection, message,
field);
}
}
void Set(int value) { reflection->SetEnumValue(&message, field, value); }
void Clear() {
DynamicFieldInfoHelper<is_oneof>::ClearField(reflection, message, field);
}
size_t FieldByteSize() const { return WireFormatLite::EnumSize(Get()); }
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_ENUM;
static constexpr bool is_repeated = false; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = false; // NOLINT
static constexpr bool is_oneof = is_oneof_parameter; // NOLINT
const Reflection* reflection;
MessageT& message;
const FieldDescriptor* field;
};
////////////////////////////////////////////////////////////////////////
// String fields
////////////////////////////////////////////////////////////////////////
template <typename MessageT, bool is_oneof_parameter>
struct StringDynamicFieldInfo {
constexpr StringDynamicFieldInfo(const Reflection* r, MessageT& m,
const FieldDescriptor* f)
: reflection(r), message(m), field(f) {}
int number() const { return field->number(); }
FieldDescriptor::Type type() const { return field->type(); }
absl::string_view Get() const {
return DynamicFieldInfoHelper<is_oneof>::GetStringView(reflection, message,
field);
}
void Set(std::string value) {
reflection->SetString(&message, field, std::move(value));
}
void Clear() {
DynamicFieldInfoHelper<is_oneof>::ClearField(reflection, message, field);
}
size_t FieldByteSize() const { return WireFormatLite::StringSize(Get()); }
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_STRING;
static constexpr bool is_repeated = false; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = false; // NOLINT
static constexpr bool is_oneof = is_oneof_parameter; // NOLINT
static constexpr bool is_cord = false; // NOLINT
const Reflection* reflection;
MessageT& message;
const FieldDescriptor* field;
};
////////////////////////////////////////////////////////////////////////
// Extension string fields
////////////////////////////////////////////////////////////////////////
template <typename ExtensionT>
struct StringDynamicExtensionInfo {
constexpr StringDynamicExtensionInfo(ExtensionT& e, int n)
: ext(e), ext_number(n) {}
int number() const { return ext_number; }
FieldDescriptor::Type type() const {
return static_cast<FieldDescriptor::Type>(ext.type);
}
absl::string_view Get() const {
return DynamicExtensionInfoHelper::GetStringView(ext);
}
void Set(absl::string_view value) {
DynamicExtensionInfoHelper::SetStringView(ext, value);
}
void Clear() { DynamicExtensionInfoHelper::ClearStringView(ext); }
size_t FieldByteSize() const { return WireFormatLite::StringSize(Get()); }
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_STRING;
static constexpr bool is_repeated = false; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = true; // NOLINT
static constexpr bool is_oneof = false; // NOLINT
static constexpr bool is_cord = false; // NOLINT
ExtensionT& ext;
int ext_number;
};
////////////////////////////////////////////////////////////////////////
// Cord fields
////////////////////////////////////////////////////////////////////////
template <typename MessageT, bool is_oneof_parameter>
struct CordDynamicFieldInfo {
constexpr CordDynamicFieldInfo(const Reflection* r, MessageT& m,
const FieldDescriptor* f)
: reflection(r), message(m), field(f) {}
int number() const { return field->number(); }
FieldDescriptor::Type type() const { return field->type(); }
::absl::Cord Get() const { return reflection->GetCord(message, field); }
void Set(const ::absl::Cord& value) {
reflection->SetString(&message, field, value);
}
void Clear() {
DynamicFieldInfoHelper<is_oneof>::ClearField(reflection, message, field);
}
size_t FieldByteSize() const { return WireFormatLite::StringSize(Get()); }
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_STRING;
static constexpr bool is_repeated = false; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = false; // NOLINT
static constexpr bool is_oneof = is_oneof_parameter; // NOLINT
static constexpr bool is_cord = true; // NOLINT
const Reflection* reflection;
MessageT& message;
const FieldDescriptor* field;
};
////////////////////////////////////////////////////////////////////////
// Message fields
////////////////////////////////////////////////////////////////////////
template <typename MessageT, bool is_oneof_parameter>
struct MessageDynamicFieldInfo {
constexpr MessageDynamicFieldInfo(const Reflection* r, MessageT& m,
const FieldDescriptor* f)
: reflection(r), message(m), field(f) {}
int number() const { return field->number(); }
FieldDescriptor::Type type() const { return field->type(); }
const Message& Get(MessageFactory* factory = nullptr) {
return reflection->GetMessage(message, field, factory);
}
Message& Mutable(MessageFactory* factory = nullptr) {
return *reflection->MutableMessage(&message, field, factory);
}
void Clear() { reflection->ClearField(&message, field); }
size_t FieldByteSize(MessageFactory* factory = nullptr) {
return Get(factory).ByteSizeLong();
}
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_MESSAGE;
static constexpr bool is_repeated = false; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = false; // NOLINT
static constexpr bool is_oneof = is_oneof_parameter; // NOLINT
static constexpr bool is_lazy = false; // NOLINT
const Reflection* reflection;
MessageT& message;
const FieldDescriptor* field;
};
////////////////////////////////////////////////////////////////////////
// Extension message fields
////////////////////////////////////////////////////////////////////////
struct SingularMessageDynamicExtensionInfo {
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_MESSAGE;
static constexpr bool is_repeated = false; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = true; // NOLINT
static constexpr bool is_oneof = false; // NOLINT
static constexpr bool is_lazy = false; // NOLINT
};
template <typename ExtensionT>
struct MessageDynamicExtensionInfo : SingularMessageDynamicExtensionInfo {
constexpr MessageDynamicExtensionInfo(ExtensionT& e, int n, bool mset)
: ext(e), ext_number(n), is_message_set(mset) {}
int number() const { return ext_number; }
FieldDescriptor::Type type() const {
return static_cast<FieldDescriptor::Type>(ext.type);
}
const Message& Get() const {
return DynamicExtensionInfoHelper::GetMessage(ext);
}
Message& Mutable() { return DynamicExtensionInfoHelper::MutableMessage(ext); }
void Clear() { DynamicExtensionInfoHelper::ClearMessage(ext); }
size_t FieldByteSize() const {
return DynamicExtensionInfoHelper::GetMessage(ext).ByteSizeLong();
}
ExtensionT& ext;
int ext_number;
bool is_message_set;
};
template <typename ExtensionT>
struct GroupDynamicExtensionInfo : SingularMessageDynamicExtensionInfo {
constexpr GroupDynamicExtensionInfo(ExtensionT& e, int n)
: ext(e), ext_number(n), is_message_set(false) {}
int number() const { return ext_number; }
FieldDescriptor::Type type() const {
return static_cast<FieldDescriptor::Type>(ext.type);
}
const Message& Get() const {
return DynamicExtensionInfoHelper::GetMessage(ext);
}
Message& Mutable() { return DynamicExtensionInfoHelper::MutableMessage(ext); }
void Clear() { DynamicExtensionInfoHelper::ClearMessage(ext); }
size_t FieldByteSize() const {
return DynamicExtensionInfoHelper::GetMessage(ext).ByteSizeLong();
}
ExtensionT& ext;
int ext_number;
bool is_message_set;
};
struct SingularLazyMessageDynamicExtensionInfo {
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_MESSAGE;
static constexpr bool is_repeated = false; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = true; // NOLINT
static constexpr bool is_oneof = false; // NOLINT
static constexpr bool is_lazy = true; // NOLINT
};
template <typename ExtensionT>
struct LazyMessageDynamicExtensionInfo
: SingularLazyMessageDynamicExtensionInfo {
LazyMessageDynamicExtensionInfo(ExtensionT& e, int n, bool mset,
const Message& p, Arena* a)
: ext(e), ext_number(n), is_message_set(mset), prototype(p), arena(a) {}
int number() const { return ext_number; }
FieldDescriptor::Type type() const {
return static_cast<FieldDescriptor::Type>(ext.type);
}
const Message& Get() const {
return DynamicExtensionInfoHelper::GetLazyMessage(ext, prototype, arena);
}
const Message& GetIgnoreUnparsed() const {
return DynamicExtensionInfoHelper::GetLazyMessageIgnoreUnparsed(
ext, prototype, arena);
}
Message& Mutable() {
return DynamicExtensionInfoHelper::MutableLazyMessage(ext, prototype,
arena);
}
void Clear() { DynamicExtensionInfoHelper::ClearLazyMessage(ext); }
size_t FieldByteSize() const {
return DynamicExtensionInfoHelper::ByteSizeLongLazyMessage(ext);
}
ExtensionT& ext;
int ext_number;
bool is_message_set;
const Message& prototype;
Arena* arena;
};
////////////////////////////////////////////////////////////////////////
// Repeated fields
////////////////////////////////////////////////////////////////////////
template <typename MessageT, typename FieldT>
struct RepeatedEntityDynamicFieldInfoBase {
constexpr RepeatedEntityDynamicFieldInfoBase(const Reflection* r, MessageT& m,
const FieldDescriptor* f,
const RepeatedField<FieldT>& rep)
: reflection(r), message(m), field(f), const_repeated(rep) {}
int number() const { return field->number(); }
FieldDescriptor::Type type() const { return field->type(); }
bool is_packed() const { return field->is_packed(); }
int size() const { return const_repeated.size(); }
iterator_range<typename RepeatedField<FieldT>::const_iterator> Get() const {
return {const_repeated.cbegin(), const_repeated.cend()};
}
iterator_range<typename RepeatedField<FieldT>::iterator> Mutable() {
auto& rep = *reflection->MutableRepeatedField<FieldT>(&message, field);
return {rep.begin(), rep.end()};
}
void Clear() {
reflection->MutableRepeatedField<FieldT>(&message, field)->Clear();
}
const Reflection* reflection;
MessageT& message;
const FieldDescriptor* field;
const RepeatedField<FieldT>& const_repeated;
};
#define PROTOBUF_DYN_FIELD_INFO_REPEATED_VARINT(NAME, CPPTYPE, FIELD_TYPE) \
template <typename MessageT> \
struct Repeated##NAME##DynamicFieldInfo \
: RepeatedEntityDynamicFieldInfoBase<MessageT, FIELD_TYPE> { \
using BaseT = RepeatedEntityDynamicFieldInfoBase<MessageT, FIELD_TYPE>; \
\
constexpr Repeated##NAME##DynamicFieldInfo( \
const Reflection* r, MessageT& m, const FieldDescriptor* f, \
const RepeatedField<FIELD_TYPE>& rep) \
: BaseT(r, m, f, rep) {} \
\
size_t FieldByteSize() const { \
size_t byte_size = 0; \
for (auto it : BaseT::const_repeated) { \
byte_size += WireFormatLite::NAME##Size(it); \
} \
return byte_size; \
} \
\
static constexpr FieldDescriptor::CppType cpp_type = \
FieldDescriptor::CPPTYPE_##CPPTYPE; \
static constexpr bool is_repeated = true; \
static constexpr bool is_map = false; \
static constexpr bool is_extension = false; \
static constexpr bool is_oneof = false; \
};
#define PROTOBUF_DYN_FIELD_INFO_REPEATED_FIXED(NAME, CPPTYPE, FIELD_TYPE) \
template <typename MessageT> \
struct Repeated##NAME##DynamicFieldInfo \
: RepeatedEntityDynamicFieldInfoBase<MessageT, FIELD_TYPE> { \
using BaseT = RepeatedEntityDynamicFieldInfoBase<MessageT, FIELD_TYPE>; \
\
constexpr Repeated##NAME##DynamicFieldInfo( \
const Reflection* r, MessageT& m, const FieldDescriptor* f, \
const RepeatedField<FIELD_TYPE>& rep) \
: BaseT(r, m, f, rep) {} \
\
size_t FieldByteSize() const { \
return static_cast<size_t>(BaseT::size()) * \
WireFormatLite::k##NAME##Size; \
} \
\
static constexpr FieldDescriptor::CppType cpp_type = \
FieldDescriptor::CPPTYPE_##CPPTYPE; \
static constexpr bool is_repeated = true; \
static constexpr bool is_map = false; \
static constexpr bool is_extension = false; \
static constexpr bool is_oneof = false; \
};
PROTOBUF_DYN_FIELD_INFO_REPEATED_VARINT(Int32, INT32, int32_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_VARINT(Int64, INT64, int64_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_VARINT(UInt32, UINT32, uint32_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_VARINT(UInt64, UINT64, uint64_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_VARINT(SInt32, INT32, int32_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_VARINT(SInt64, INT64, int64_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_VARINT(Enum, ENUM, int);
PROTOBUF_DYN_FIELD_INFO_REPEATED_FIXED(Fixed32, UINT32, uint32_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_FIXED(Fixed64, UINT64, uint64_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_FIXED(SFixed32, INT32, int32_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_FIXED(SFixed64, INT64, int64_t);
PROTOBUF_DYN_FIELD_INFO_REPEATED_FIXED(Double, DOUBLE, double);
PROTOBUF_DYN_FIELD_INFO_REPEATED_FIXED(Float, FLOAT, float);
PROTOBUF_DYN_FIELD_INFO_REPEATED_FIXED(Bool, BOOL, bool);
#undef PROTOBUF_DYN_FIELD_INFO_REPEATED_VARINT
#undef PROTOBUF_DYN_FIELD_INFO_REPEATED_FIXED
template <typename MessageT, typename FieldT>
struct RepeatedPtrEntityDynamicFieldInfoBase {
constexpr RepeatedPtrEntityDynamicFieldInfoBase(
const Reflection* r, MessageT& m, const FieldDescriptor* f,
const RepeatedPtrField<FieldT>& rep)
: reflection(r), message(m), field(f), const_repeated(rep) {}
int number() const { return field->number(); }
FieldDescriptor::Type type() const { return field->type(); }
bool is_packed() const { return field->is_packed(); }
int size() const { return const_repeated.size(); }
iterator_range<typename RepeatedPtrField<FieldT>::const_iterator> Get()
const {
return {const_repeated.cbegin(), const_repeated.cend()};
}
iterator_range<typename RepeatedPtrField<FieldT>::iterator> Mutable() {
auto& rep = *reflection->MutableRepeatedPtrField<FieldT>(&message, field);
return {rep.begin(), rep.end()};
}
void Clear() {
reflection->MutableRepeatedPtrField<FieldT>(&message, field)->Clear();
}
const Reflection* reflection;
MessageT& message;
const FieldDescriptor* field;
const RepeatedPtrField<FieldT>& const_repeated;
};
template <typename MessageT, typename FieldT>
struct RepeatedStringDynamicFieldInfoBase
: RepeatedPtrEntityDynamicFieldInfoBase<MessageT, FieldT> {
using BaseT = RepeatedPtrEntityDynamicFieldInfoBase<MessageT, FieldT>;
constexpr RepeatedStringDynamicFieldInfoBase(
const Reflection* r, MessageT& m, const FieldDescriptor* f,
const RepeatedPtrField<FieldT>& rep)
: BaseT(r, m, f, rep) {}
size_t FieldByteSize() const {
size_t byte_size = 0;
for (auto& it : BaseT::const_repeated) {
byte_size += WireFormatLite::LengthDelimitedSize(it.size());
}
return byte_size;
}
};
template <typename MessageT>
struct RepeatedStringDynamicFieldInfo
: RepeatedStringDynamicFieldInfoBase<MessageT, std::string> {
constexpr RepeatedStringDynamicFieldInfo(
const Reflection* r, MessageT& m, const FieldDescriptor* f,
const RepeatedPtrField<std::string>& rep)
: RepeatedStringDynamicFieldInfoBase<MessageT, std::string>(r, m, f,
rep) {}
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_STRING;
static constexpr bool is_repeated = true; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = false; // NOLINT
static constexpr bool is_oneof = false; // NOLINT
static constexpr bool is_cord = false; // NOLINT
static constexpr bool is_string_piece = false; // NOLINT
};
struct RepeatedMessageDynamicFieldInfoMeta {
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_MESSAGE;
static constexpr bool is_repeated = true; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = false; // NOLINT
static constexpr bool is_oneof = false; // NOLINT
};
template <typename MessageT>
struct RepeatedMessageDynamicFieldInfo
: RepeatedPtrEntityDynamicFieldInfoBase<MessageT, Message>,
RepeatedMessageDynamicFieldInfoMeta {
using BaseT = RepeatedPtrEntityDynamicFieldInfoBase<MessageT, Message>;
constexpr RepeatedMessageDynamicFieldInfo(
const Reflection* r, MessageT& m, const FieldDescriptor* f,
const RepeatedPtrField<Message>& rep)
: BaseT(r, m, f, rep) {}
size_t FieldByteSize() const {
size_t byte_size = 0;
for (auto& it : BaseT::const_repeated) {
byte_size += WireFormatLite::LengthDelimitedSize(it.ByteSizeLong());
}
return byte_size;
}
};
template <typename MessageT>
struct RepeatedGroupDynamicFieldInfo
: RepeatedPtrEntityDynamicFieldInfoBase<MessageT, Message>,
RepeatedMessageDynamicFieldInfoMeta {
using BaseT = RepeatedPtrEntityDynamicFieldInfoBase<MessageT, Message>;
constexpr RepeatedGroupDynamicFieldInfo(const Reflection* r, MessageT& m,
const FieldDescriptor* f,
const RepeatedPtrField<Message>& rep)
: BaseT(r, m, f, rep) {}
size_t FieldByteSize() const {
size_t byte_size = 0;
for (auto& it : BaseT::const_repeated) {
byte_size += it.ByteSizeLong();
}
return byte_size;
}
};
////////////////////////////////////////////////////////////////////////
// Extension repeated fields
////////////////////////////////////////////////////////////////////////
#define PROTOBUF_DYN_EXTENSION_INFO_REPEATED_VARINT(NAME, CPPNAME, CPPTYPE, \
FIELD_TYPE) \
template <typename ExtensionT> \
struct Repeated##NAME##DynamicExtensionInfo { \
constexpr Repeated##NAME##DynamicExtensionInfo(ExtensionT& e, int n) \
: ext(e), ext_number(n) {} \
\
int number() const { return ext_number; } \
FieldDescriptor::Type type() const { \
return static_cast<FieldDescriptor::Type>(ext.type); \
} \
bool is_packed() const { return ext.is_packed; } \
\
int size() const { \
return DynamicExtensionInfoHelper::GetRepeated##CPPNAME(ext)->size(); \
} \
const RepeatedField<FIELD_TYPE>& Get() const { \
return *DynamicExtensionInfoHelper::GetRepeated##CPPNAME(ext); \
} \
RepeatedField<FIELD_TYPE>& Mutable() { \
return *DynamicExtensionInfoHelper::MutableRepeated##CPPNAME(ext); \
} \
void Clear() { \
DynamicExtensionInfoHelper::MutableRepeated##CPPNAME(ext)->Clear(); \
} \
size_t FieldByteSize() const { \
size_t byte_size = 0; \
for (auto it : Get()) { \
byte_size += WireFormatLite::NAME##Size(it); \
} \
return byte_size; \
} \
\
static constexpr FieldDescriptor::CppType cpp_type = \
FieldDescriptor::CPPTYPE_##CPPTYPE; \
static constexpr bool is_repeated = true; \
static constexpr bool is_map = false; \
static constexpr bool is_extension = true; \
static constexpr bool is_oneof = false; \
\
ExtensionT& ext; \
int ext_number; \
};
#define PROTOBUF_DYN_EXTENSION_INFO_REPEATED_FIXED(NAME, CPPNAME, CPPTYPE, \
FIELD_TYPE) \
template <typename ExtensionT> \
struct Repeated##NAME##DynamicExtensionInfo { \
constexpr Repeated##NAME##DynamicExtensionInfo(ExtensionT& e, int n) \
: ext(e), ext_number(n) {} \
\
int number() const { return ext_number; } \
FieldDescriptor::Type type() const { \
return static_cast<FieldDescriptor::Type>(ext.type); \
} \
bool is_packed() const { return ext.is_packed; } \
\
int size() const { \
return DynamicExtensionInfoHelper::GetRepeated##CPPNAME(ext)->size(); \
} \
const RepeatedField<FIELD_TYPE>& Get() const { \
return *DynamicExtensionInfoHelper::GetRepeated##CPPNAME(ext); \
} \
RepeatedField<FIELD_TYPE>& Mutable() { \
return *DynamicExtensionInfoHelper::MutableRepeated##CPPNAME(ext); \
} \
void Clear() { \
DynamicExtensionInfoHelper::MutableRepeated##CPPNAME(ext)->Clear(); \
} \
size_t FieldByteSize() const { \
return static_cast<size_t>(size()) * WireFormatLite::k##NAME##Size; \
} \
\
static constexpr FieldDescriptor::CppType cpp_type = \
FieldDescriptor::CPPTYPE_##CPPTYPE; \
static constexpr bool is_repeated = true; \
static constexpr bool is_map = false; \
static constexpr bool is_extension = true; \
static constexpr bool is_oneof = false; \
\
ExtensionT& ext; \
int ext_number; \
};
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_VARINT(Int32, Int32, INT32, int32_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_VARINT(Int64, Int64, INT64, int64_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_VARINT(UInt32, UInt32, UINT32, uint32_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_VARINT(UInt64, UInt64, UINT64, uint64_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_VARINT(SInt32, Int32, INT32, int32_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_VARINT(SInt64, Int64, INT64, int64_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_VARINT(Enum, Enum, ENUM, int);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_FIXED(Fixed32, UInt32, UINT32, uint32_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_FIXED(Fixed64, UInt64, UINT64, uint64_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_FIXED(SFixed32, Int32, INT32, int32_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_FIXED(SFixed64, Int64, INT64, int64_t);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_FIXED(Double, Double, DOUBLE, double);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_FIXED(Float, Float, FLOAT, float);
PROTOBUF_DYN_EXTENSION_INFO_REPEATED_FIXED(Bool, Bool, BOOL, bool);
#undef PROTOBUF_DYN_EXTENSION_INFO_REPEATED_VARINT
#undef PROTOBUF_DYN_EXTENSION_INFO_REPEATED_FIXED
template <typename ExtensionT>
struct RepeatedStringDynamicExtensionInfo {
constexpr RepeatedStringDynamicExtensionInfo(ExtensionT& ext, int n)
: ext(ext), ext_number(n) {}
int number() const { return ext_number; }
FieldDescriptor::Type type() const {
return static_cast<FieldDescriptor::Type>(ext.type);
}
constexpr bool is_packed() const { return false; }
int size() const {
return DynamicExtensionInfoHelper::GetRepeatedString(ext)->size();
}
const RepeatedPtrField<std::string>& Get() const {
return *DynamicExtensionInfoHelper::GetRepeatedString(ext);
}
RepeatedPtrField<std::string>& Mutable() {
return *DynamicExtensionInfoHelper::MutableRepeatedString(ext);
}
void Clear() {
DynamicExtensionInfoHelper::MutableRepeatedString(ext)->Clear();
}
size_t FieldByteSize() const {
size_t byte_size = 0;
for (auto& it : Get()) {
byte_size += WireFormatLite::LengthDelimitedSize(it.size());
}
return byte_size;
}
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_STRING;
static constexpr bool is_repeated = true; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = true; // NOLINT
static constexpr bool is_oneof = false; // NOLINT
static constexpr bool is_cord = false; // NOLINT
static constexpr bool is_string_piece = false; // NOLINT
ExtensionT& ext;
int ext_number;
};
template <typename ExtensionT>
struct RepeatedMessageDynamicExtensionInfoBase {
constexpr RepeatedMessageDynamicExtensionInfoBase(ExtensionT& e, int n)
: ext(e), ext_number(n) {}
int number() const { return ext_number; }
FieldDescriptor::Type type() const {
return static_cast<FieldDescriptor::Type>(ext.type);
}
constexpr bool is_packed() const { return false; }
int size() const {
return DynamicExtensionInfoHelper::GetRepeatedMessage(ext)->size();
}
const RepeatedPtrField<MessageLite>& Get() const {
return *DynamicExtensionInfoHelper::GetRepeatedMessage(ext);
}
RepeatedPtrField<MessageLite>& Mutable() {
return *DynamicExtensionInfoHelper::MutableRepeatedMessage(ext);
}
void Clear() {
DynamicExtensionInfoHelper::MutableRepeatedMessage(ext)->Clear();
}
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_MESSAGE;
static constexpr bool is_repeated = true; // NOLINT
static constexpr bool is_map = false; // NOLINT
static constexpr bool is_extension = true; // NOLINT
static constexpr bool is_oneof = false; // NOLINT
ExtensionT& ext;
int ext_number;
};
template <typename ExtensionT>
struct RepeatedMessageDynamicExtensionInfo
: RepeatedMessageDynamicExtensionInfoBase<ExtensionT> {
using BaseT = RepeatedMessageDynamicExtensionInfoBase<ExtensionT>;
constexpr RepeatedMessageDynamicExtensionInfo(ExtensionT& e, int n)
: BaseT(e, n) {}
size_t FieldByteSize() const {
size_t byte_size = 0;
for (auto& it : BaseT::Get()) {
byte_size += WireFormatLite::LengthDelimitedSize(it.ByteSizeLong());
}
return byte_size;
}
};
template <typename ExtensionT>
struct RepeatedGroupDynamicExtensionInfo
: RepeatedMessageDynamicExtensionInfoBase<ExtensionT> {
using BaseT = RepeatedMessageDynamicExtensionInfoBase<ExtensionT>;
constexpr RepeatedGroupDynamicExtensionInfo(ExtensionT& e, int n)
: BaseT(e, n) {}
size_t FieldByteSize() const {
size_t byte_size = 0;
for (auto& it : BaseT::Get()) {
byte_size += it.ByteSizeLong();
}
return byte_size;
}
};
////////////////////////////////////////////////////////////////////////
// Map fields
////////////////////////////////////////////////////////////////////////
// Returns the encoded size for (cpp_type, type, value). Some types are fixed
// sized; while others are variable. Dispatch done here at compile time frees
// users from a similar dispatch without creating KeyInfo or ValueInfo per type.
template <FieldDescriptor::CppType cpp_type, typename T>
inline size_t MapPrimitiveFieldByteSize(FieldDescriptor::Type type, T value) {
if constexpr (cpp_type == FieldDescriptor::CPPTYPE_INT32) {
static_assert(std::is_same_v<T, int32_t>, "type mismatch");
switch (type) {
case FieldDescriptor::TYPE_INT32:
return WireFormatLite::Int32Size(value);
case FieldDescriptor::TYPE_SINT32:
return WireFormatLite::SInt32Size(value);
case FieldDescriptor::TYPE_SFIXED32:
return WireFormatLite::kSFixed32Size;
default:
Unreachable();
}
} else if constexpr (cpp_type == FieldDescriptor::CPPTYPE_INT64) {
static_assert(std::is_same_v<T, int64_t>, "type mismatch");
switch (type) {
case FieldDescriptor::TYPE_INT64:
return WireFormatLite::Int64Size(value);
case FieldDescriptor::TYPE_SINT64:
return WireFormatLite::SInt64Size(value);
case FieldDescriptor::TYPE_SFIXED64:
return WireFormatLite::kSFixed64Size;
default:
Unreachable();
}
} else if constexpr (cpp_type == FieldDescriptor::CPPTYPE_UINT32) {
static_assert(std::is_same_v<T, uint32_t>, "type mismatch");
switch (type) {
case FieldDescriptor::TYPE_UINT32:
return WireFormatLite::UInt32Size(value);
case FieldDescriptor::TYPE_FIXED32:
return WireFormatLite::kSFixed32Size;
default:
Unreachable();
}
} else if constexpr (cpp_type == FieldDescriptor::CPPTYPE_UINT64) {
static_assert(std::is_same_v<T, uint64_t>, "type mismatch");
switch (type) {
case FieldDescriptor::TYPE_UINT64:
return WireFormatLite::UInt64Size(value);
case FieldDescriptor::TYPE_FIXED64:
return WireFormatLite::kSFixed64Size;
default:
Unreachable();
}
} else if constexpr (cpp_type == FieldDescriptor::CPPTYPE_ENUM) {
static_assert(std::is_same_v<T, int>, "type mismatch");
return WireFormatLite::EnumSize(value);
} else if constexpr (cpp_type == FieldDescriptor::CPPTYPE_BOOL) {
static_assert(std::is_same_v<T, bool>, "type mismatch");
return WireFormatLite::kBoolSize;
} else if constexpr (cpp_type == FieldDescriptor::CPPTYPE_FLOAT) {
static_assert(std::is_same_v<T, float>, "type mismatch");
return WireFormatLite::kFloatSize;
} else if constexpr (cpp_type == FieldDescriptor::CPPTYPE_DOUBLE) {
static_assert(std::is_same_v<T, double>, "type mismatch");
return WireFormatLite::kDoubleSize;
}
}
#define PROTOBUF_MAP_KEY_INFO(NAME, KEY_TYPE, CPPTYPE) \
struct MapDynamicField##NAME##KeyInfo { \
explicit MapDynamicField##NAME##KeyInfo(const MapKey& k) : key(k) { \
ABSL_DCHECK_EQ(cpp_type, key.type()); \
} \
\
KEY_TYPE Get() const { return key.Get##NAME##Value(); } \
/* Set() API doesn't make sense because MapIter always returns const \
* MapKey&. */ \
\
static constexpr FieldDescriptor::CppType cpp_type = \
FieldDescriptor::CPPTYPE_##CPPTYPE; \
\
const MapKey& key; \
};
PROTOBUF_MAP_KEY_INFO(Int32, int32_t, INT32);
PROTOBUF_MAP_KEY_INFO(Int64, int64_t, INT64);
PROTOBUF_MAP_KEY_INFO(UInt32, uint32_t, UINT32);
PROTOBUF_MAP_KEY_INFO(UInt64, uint64_t, UINT64);
PROTOBUF_MAP_KEY_INFO(Bool, bool, BOOL);
PROTOBUF_MAP_KEY_INFO(String, const std::string&, STRING);
#undef PROTOBUF_MAP_KEY_INFO
#define PROTOBUF_MAP_VALUE_INFO(NAME, VALUE_TYPE, CPPTYPE) \
template <typename MapValueRefT> \
struct MapDynamicField##NAME##ValueInfo { \
explicit MapDynamicField##NAME##ValueInfo(MapValueRefT& v) : value(v) { \
ABSL_DCHECK_EQ(cpp_type, value.type()); \
} \
\
VALUE_TYPE Get() const { return value.Get##NAME##Value(); } \
void Set(VALUE_TYPE val) { value.Set##NAME##Value(val); } \
\
static constexpr FieldDescriptor::CppType cpp_type = \
FieldDescriptor::CPPTYPE_##CPPTYPE; \
\
MapValueRefT& value; \
};
PROTOBUF_MAP_VALUE_INFO(Int32, int32_t, INT32);
PROTOBUF_MAP_VALUE_INFO(Int64, int64_t, INT64);
PROTOBUF_MAP_VALUE_INFO(UInt32, uint32_t, UINT32);
PROTOBUF_MAP_VALUE_INFO(UInt64, uint64_t, UINT64);
PROTOBUF_MAP_VALUE_INFO(Bool, bool, BOOL);
PROTOBUF_MAP_VALUE_INFO(Enum, int, ENUM);
PROTOBUF_MAP_VALUE_INFO(Float, float, FLOAT);
PROTOBUF_MAP_VALUE_INFO(Double, double, DOUBLE);
PROTOBUF_MAP_VALUE_INFO(String, const std::string&, STRING);
#undef PROTOBUF_MAP_VALUE_INFO
template <typename MapValueRefT>
struct MapDynamicFieldMessageValueInfo {
explicit constexpr MapDynamicFieldMessageValueInfo(MapValueRefT& v)
: value(v) {}
const Message& Get() const { return value.GetMessageValue(); }
Message* Mutable() { return value.MutableMessageValue(); }
static constexpr FieldDescriptor::CppType cpp_type = // NOLINT
FieldDescriptor::CPPTYPE_MESSAGE;
MapValueRefT& value;
};
// Calls "cb" with the corresponding ValueInfo. Typically called from
// MapDynamicFieldVisitKey.
template <typename MapValueRefT, typename MapValueCallback>
void MapDynamicFieldVisitValue(MapValueRefT& value, MapValueCallback&& cb) {
switch (value.type()) {
#define PROTOBUF_HANDLE_MAP_VALUE_CASE(NAME, VALUE_TYPE, CPPTYPE) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
cb(MapDynamicField##NAME##ValueInfo<MapValueRefT>{value}); \
break;
PROTOBUF_HANDLE_MAP_VALUE_CASE(Int32, int32_t, INT32);
PROTOBUF_HANDLE_MAP_VALUE_CASE(Int64, int64_t, INT64);
PROTOBUF_HANDLE_MAP_VALUE_CASE(UInt32, uint32_t, UINT32);
PROTOBUF_HANDLE_MAP_VALUE_CASE(UInt64, uint64_t, UINT64);
PROTOBUF_HANDLE_MAP_VALUE_CASE(Bool, bool, BOOL);
PROTOBUF_HANDLE_MAP_VALUE_CASE(Enum, int, ENUM);
PROTOBUF_HANDLE_MAP_VALUE_CASE(Float, float, FLOAT);
PROTOBUF_HANDLE_MAP_VALUE_CASE(Double, double, DOUBLE);
PROTOBUF_HANDLE_MAP_VALUE_CASE(String, std::string, STRING);
PROTOBUF_HANDLE_MAP_VALUE_CASE(Message, Message, MESSAGE);
default:
internal::Unreachable();
#undef PROTOBUF_HANDLE_MAP_VALUE_CASE
}
}
// Dispatches based on key type to instantiate a right KeyInfo, then calls
// MapDynamicFieldVisitValue to dispatch on the value type.
template <typename MapValueRefT, typename MapFieldCallback>
void MapDynamicFieldVisitKey(const MapKey& key, MapValueRefT& value,
const MapFieldCallback& user_cb) {
switch (key.type()) {
#define PROTOBUF_HANDLE_MAP_KEY_CASE(NAME, CPPTYPE) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
auto key_info = MapDynamicField##NAME##KeyInfo{key}; \
MapDynamicFieldVisitValue(value, [key_info, &user_cb](auto&& value_info) { \
user_cb(key_info, value_info); \
}); \
break; \
}
PROTOBUF_HANDLE_MAP_KEY_CASE(Int32, INT32);
PROTOBUF_HANDLE_MAP_KEY_CASE(Int64, INT64);
PROTOBUF_HANDLE_MAP_KEY_CASE(UInt32, UINT32);
PROTOBUF_HANDLE_MAP_KEY_CASE(UInt64, UINT64);
PROTOBUF_HANDLE_MAP_KEY_CASE(Bool, BOOL);
PROTOBUF_HANDLE_MAP_KEY_CASE(String, STRING);
#undef PROTOBUF_HANDLE_MAP_KEY_CASE
default:
internal::Unreachable();
break;
}
}
template <typename MessageT>
struct MapDynamicFieldInfo {
constexpr MapDynamicFieldInfo(const Reflection* r, MessageT& m,
const FieldDescriptor* f,
const FieldDescriptor* key_f,
const FieldDescriptor* val_f,
const MapFieldBase& map_field)
: reflection(r),
message(m),
field(f),
key(key_f),
value(val_f),
const_map_field(map_field) {
ABSL_DCHECK(f->is_map());
ABSL_DCHECK_NE(key_f, nullptr);
ABSL_DCHECK_NE(val_f, nullptr);
}
int number() const { return field->number(); }
FieldDescriptor::Type key_type() const { return key->type(); }
FieldDescriptor::Type value_type() const { return value->type(); }
int size() const { return const_map_field.size(); }
// go/ranked-overloads for the rationale.
struct Rank0 {};
struct Rank1 : Rank0 {};
// Preferred version when "msg" is non-const.
template <typename T, typename Callback,
typename = std::enable_if_t<!std::is_const_v<T>>>
static void VisitElementsImpl(T& msg, const Reflection* reflection,
const FieldDescriptor* field,
const MapFieldBase&, Callback&& cb, Rank1) {
auto& map_field =
DynamicFieldInfoHelper<false>::template Mutable<MapFieldBase>(
reflection, msg, field);
const Descriptor* descriptor = field->message_type();
MapIterator begin(&map_field, descriptor), end(&map_field, descriptor);
map_field.MapBegin(&begin);
map_field.MapEnd(&end);
for (auto it = begin; it != end; ++it) {
MapDynamicFieldVisitKey(it.GetKey(), *it.MutableValueRef(), cb);
}
}
// Fallback version otherwise.
template <typename T, typename Callback>
static void VisitElementsImpl(T& msg, const Reflection*,
const FieldDescriptor* field,
const MapFieldBase& const_map_field,
Callback&& cb, Rank0) {
// Unfortunately, we have to const_cast here because MapIterator only takes
// a mutable MapFieldBase pointer. This is still safe because value iterator
// is not mutable.
MapFieldBase* map_field = const_cast<MapFieldBase*>(&const_map_field);
const Descriptor* descriptor = field->message_type();
MapIterator begin(map_field, descriptor), end(map_field, descriptor);
const_map_field.MapBegin(&begin);
const_map_field.MapEnd(&end);
for (auto it = begin; it != end; ++it) {
MapDynamicFieldVisitKey(it.GetKey(), it.GetValueRef(), cb);
}
}
template <typename MapFieldCallback>
void VisitElements(MapFieldCallback&& cb) const {
VisitElementsImpl(message, reflection, field, const_map_field,
static_cast<MapFieldCallback&&>(cb), Rank1{});
}
void Clear() {
auto& map_field =
DynamicFieldInfoHelper<false>::template Mutable<MapFieldBase>(
reflection, message, field);
map_field.Clear();
}
static constexpr bool is_repeated = true; // NOLINT
static constexpr bool is_packed = false; // NOLINT
static constexpr bool is_map = true; // NOLINT
static constexpr bool is_extension = false; // NOLINT
static constexpr bool is_oneof = false; // NOLINT
const Reflection* reflection;
MessageT& message;
const FieldDescriptor* field;
const FieldDescriptor* key;
const FieldDescriptor* value;
const MapFieldBase& const_map_field;
};
#endif // __cpp_if_constexpr
} // namespace internal
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_REFLECTION_VISIT_FIELD_INFO_H__