Contents
CopyFrom MergeFrom PackFrom 区别与实现
// Make this message into a copy of the given message.
// 基本等价与 Clear() + MergeFrom(from);
void Message::CopyFrom(const Message& from) {
if (&from == this) return;
auto* class_to = GetClassData();
auto* class_from = from.GetClassData();
auto* copy_to_from = class_to ? class_to->copy_to_from : nullptr;
if (class_to == nullptr || class_to != class_from) {
const Descriptor* descriptor = GetDescriptor();
GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
<< ": Tried to copy from a message with a different type. "
"to: "
<< descriptor->full_name()
<< ", "
"from: "
<< from.GetDescriptor()->full_name();
copy_to_from = [](Message* to, const Message& from) {
ReflectionOps::Copy(from, to);
};
}
copy_to_from(this, from);
}
void ReflectionOps::Copy(const Message& from, Message* to) {
if (&from == to) return;
Clear(to);
Merge(from, to);
}
// Singular fields will be overwritten, Repeated fields will be concatenated
void Message::MergeFrom(const Message& from) {
auto* class_to = GetClassData();
auto* class_from = from.GetClassData();
auto* merge_to_from = class_to ? class_to->merge_to_from : nullptr;
if (class_to == nullptr || class_to != class_from) {
merge_to_from = [](Message* to, const Message& from) {
ReflectionOps::Merge(from, to);
};
}
merge_to_from(this, from);
}
描述器(Descriptor)、字段描述器(FieldDescriptor)、反射(Reflection)
Descriptor & FieldDescriptor
- Descriptor 描述器包含了通过 Protobuf 定义的消息类的相关信息。这实际上实现了所谓的「自省」(Introspection)。对于一个具体的消息类对象,可以使用 GetDescriptor() 接口来获取其描述器.
- FieldDescriptor 包含了对于消息类中某个字段的描述。在概念上,近似于 C++ 中类的成员指针.
#include <google/protobuf/descriptor.h>
const google::protobuf::Descriptor* des = message.GetDescriptor();
const google::protobuf::FieldDescriptor* fdes = des->FindFieldByName("field_name");
Reflection-反射操作
One key feature provided by protocol message classes is reflection.
- You can iterate over the fields of a message and manipulate their values without writing your code against any specific message type.
- One very useful way to use reflection is for converting protocol messages to and from other encodings, such as XML or JSON.
- A more advanced use of reflection might be to find differences between two messages of the same type, or to develop a sort of “regular expressions for protocol messages” in which you can write expressions that match certain message contents.
If you use your imagination, it’s possible to apply Protocol Buffers to a much wider range of problems than you might initially expect!
- 反射定义了一系列接口,用以在运行时动态地访问、修改消息类中的成员。对于一个具体的消息类对象,可以用 GetReflection() 接口来获取其反射
#include <google/protobuf/message.h>
// 获取 proto反射
const google::protobuf::Reflection* ref = message.GetReflection();
// 获取消息中的某一个field
const Message& GetMessage(const Message& message, const FieldDescriptor* field,
MessageFactory* factory = nullptr) const
参考文档
-
Protocol Buffer Basics: C++. 一个C++语言使用Protobuf的基本介绍和简单的教程
-
C++ API Reference
Message 、反射、等常用方法的API -
C++ Generated Code Guide For more information on exactly what members the protocol compiler generates for any particular field definition
-
Encoding Reference.
附录
Merge源码
void ReflectionOps::Merge(const Message& from, Message* to) {
GOOGLE_CHECK_NE(&from, to);
const Descriptor* descriptor = from.GetDescriptor();
GOOGLE_CHECK_EQ(to->GetDescriptor(), descriptor)
<< "Tried to merge messages of different types "
<< "(merge " << descriptor->full_name() << " to "
<< to->GetDescriptor()->full_name() << ")";
const Reflection* from_reflection = GetReflectionOrDie(from);
const Reflection* to_reflection = GetReflectionOrDie(*to);
bool is_from_generated = (from_reflection->GetMessageFactory() ==
google::protobuf::MessageFactory::generated_factory());
bool is_to_generated = (to_reflection->GetMessageFactory() ==
google::protobuf::MessageFactory::generated_factory());
std::vector<const FieldDescriptor*> fields;
from_reflection->ListFieldsOmitStripped(from, &fields);
for (const FieldDescriptor* field : fields) {
if (field->is_repeated()) {
// Use map reflection if both are in map status and have the
// same map type to avoid sync with repeated field.
// Note: As from and to messages have the same descriptor, the
// map field types are the same if they are both generated
// messages or both dynamic messages.
if (is_from_generated == is_to_generated && field->is_map()) {
const MapFieldBase* from_field =
from_reflection->GetMapData(from, field);
MapFieldBase* to_field = to_reflection->MutableMapData(to, field);
if (to_field->IsMapValid() && from_field->IsMapValid()) {
to_field->MergeFrom(*from_field);
continue;
}
}
int count = from_reflection->FieldSize(from, field);
for (int j = 0; j < count; j++) {
switch (field->cpp_type()) {
#define HANDLE_TYPE(CPPTYPE, METHOD) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
to_reflection->Add##METHOD( \
to, field, from_reflection->GetRepeated##METHOD(from, field, j)); \
break;
HANDLE_TYPE(INT32, Int32);
HANDLE_TYPE(INT64, Int64);
HANDLE_TYPE(UINT32, UInt32);
HANDLE_TYPE(UINT64, UInt64);
HANDLE_TYPE(FLOAT, Float);
HANDLE_TYPE(DOUBLE, Double);
HANDLE_TYPE(BOOL, Bool);
HANDLE_TYPE(STRING, String);
HANDLE_TYPE(ENUM, Enum);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE:
const Message& from_child =
from_reflection->GetRepeatedMessage(from, field, j);
if (from_reflection == to_reflection) {
to_reflection
->AddMessage(to, field,
from_child.GetReflection()->GetMessageFactory())
->MergeFrom(from_child);
} else {
to_reflection->AddMessage(to, field)->MergeFrom(from_child);
}
break;
}
}
} else {
switch (field->cpp_type()) {
#define HANDLE_TYPE(CPPTYPE, METHOD) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
to_reflection->Set##METHOD(to, field, \
from_reflection->Get##METHOD(from, field)); \
break;
HANDLE_TYPE(INT32, Int32);
HANDLE_TYPE(INT64, Int64);
HANDLE_TYPE(UINT32, UInt32);
HANDLE_TYPE(UINT64, UInt64);
HANDLE_TYPE(FLOAT, Float);
HANDLE_TYPE(DOUBLE, Double);
HANDLE_TYPE(BOOL, Bool);
HANDLE_TYPE(STRING, String);
HANDLE_TYPE(ENUM, Enum);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE:
const Message& from_child = from_reflection->GetMessage(from, field);
if (from_reflection == to_reflection) {
to_reflection
->MutableMessage(
to, field, from_child.GetReflection()->GetMessageFactory())
->MergeFrom(from_child);
} else {
to_reflection->MutableMessage(to, field)->MergeFrom(from_child);
}
break;
}
}
}
to_reflection->MutableUnknownFields(to)->MergeFrom(
from_reflection->GetUnknownFields(from));
}