目录
本节主要解决上节遗留的问题,caffe中的数据结构文件在\src\caffe\proto\caffe.proto是个什么东东?如何才能看懂?需要先行补充下Protobuf的基础知识
Protobuf
介绍
Protobuf是由google开发的一套开源序列化协议框架,类似于XML,JSON,采用协议序列化用于数据存储与读取,与XML相比,定义了数据格式更加简单,数据访问接口可以自动化生成,加快了开发者开发速度,最新的版本为proto3已经支持Java,C++, Python, Java Lite, Ruby,JavaScript, Objective-c 以及C#, go,等常用语言.目前很多项目都在使用Protobuf.
官方链接(不需要翻墙):https://developers.google.cn/protocol-buffers/
官方文档:https://developers.google.cn/protocol-buffers/docs/overview#whynotxml
优势
既然xml已经使用非常广泛,那么为什么还需要Protocol Buffer?其优势主要有以下几点:
- 简单
- 比xml要小3到10倍,proto文件被编译成bin二进制文件
- 比xml要快20到100倍
- 结构更加清晰,不会产生歧义
- 生成数据操作类更加容易,编程更加容易上手,访问接口代码基本都是自动生产
例如定义一个person数据结构,里面包含name和email两个个人信息,xml定义如下:
<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>
而使用protobuf定义时,其txt定义格式如下:
# Textual representation of a protocol buffer.
# This is *not* the binary format used on the wire.
person {
name: "John Doe"
email: "jdoe@example.com"
}
是不是有点像python中的元组,采用key-value形式.
protobuf语法
上述是采用txt格式进行定义的,但是一般protobuf都是使用.proto文件,其语法格式使用Message定义
采用Message定义,person定义如下:
message Person {
required string name = 1;
required string email= 2;
}
意思是Person中的第一个字段为name,其数据类型为string,比选项;第二个字段为email,其数据类型为string,比选项.数据结构前加message关键词,意思是定义一个名为Person的数据结构,Message结构里面的每个成员结构格式如下:
[rules][data_type] [data_name] = [number]
分别解释其各个字段意思
Specifying Field Rules
该字段主要是定义该变量的规则,主要有三种规则:
- required:该字段变量为必须的,实例中必须包含的字段.如果是在调试模式下编译 libprotobuf,则序列化一个未初始化的message 将将导致断言失败。在优化的构建中,将跳过检查并始终写入消息。但是,解析未初始化的消息将始终失败(通过从解析方法返回 false)
- optional:该字段是可选的,可以设置也可以不设置该字段.如果未设置可选字段值,则使用默认值。对于简单类型,你可以指定自己的默认值,就像我们在示例中为电话号码类型所做的那样。否则,使用系统默认值:数字类型为 0,字符串为空字符串,bools 为 false。对于嵌入 message,默认值始终是消息的 “默认实例” 或 “原型”,其中没有设置任何字段。调用访问器以获取尚未显式设置的 optional(或 required)字段的值始终返回该字段的默认值。
- repeated:该字段可以重复任意次数(包括零次).重复值的顺序将保留在 protocol buffer 中。可以将 repeated 字段视为动态大小的数组。
官方文档解释如下:
Data type
Protobuf支持常用的数据类型,支持的数据类型如下表:
.proto Type | Notes | C++ Type | Java Type | Python Type[2] | Go Type |
---|---|---|---|---|---|
double | double | double | float | *float64 | |
float | float | float | float | *float32 | |
int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | *int32 |
int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long[3] | *int64 |
uint32 | Uses variable-length encoding. | uint32 | int[1] | int/long[3] | *uint32 |
uint64 | Uses variable-length encoding. | uint64 | long[1] | int/long[3] | *uint64 |
sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | *int32 |
sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long[3] | *int64 |
fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 228. | uint32 | int[1] | int/long[3] | *uint32 |
fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 256. | uint64 | long[1] | int/long[3] | *uint64 |
sfixed32 | Always four bytes. | int32 | int | int | *int32 |
sfixed64 | Always eight bytes. | int64 | long | int/long[3] | *int64 |
bool | bool | boolean | bool | *bool | |
string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | unicode (Python 2) or str (Python 3) | *string |
bytes | May contain any arbitrary sequence of bytes. | string | ByteString | bytes | []byte |
基本能够满足其使用要求
Data name
data name为数据成员名
Number
Protobuf是采用key-value形式,将成员名映射为number,这样就能实现数据的序列化.每个数据字段都有唯一的数值型标识符.这些标识符用于标识字段在消息中的二进制格式,使用中的类型不应该随意改动。需要注意的是,[1-15]内的标识在编码时只占用一个字节,包含标识符和字段类型。[16-2047]之间的标识符占用2个字节。建议为频繁出现的消息元素使用[1-15]间的标识符。如果考虑到以后可能或扩展频繁元素,可以预留一些标识符。number最小为为1,最大为229 - 1, or 536,870,911, 其中19000到19999为Protocol内部使用
Protobuf注释
在proto文件中经常需要添加注释对某个字段进行注释,支持C风格的双斜线//单行注释
保留字段与标识符
可以使用reserved关键字指定保留字段和保留标识符
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}
syntax关键词
sysntax关键字经常用到proto文件开头用来表明使用的是哪个proto版本
syntax = "proto2"
分号
行与行之间需要加分号,类似C语言.
Protocol字段设置
在对数据操作过程中经常需要对某个成员变量值进行修该,protocol提供了一系列很方便的API, 使用set函数,其格式为
set_[data_name]
例如定一个下面一个message
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
分别设置其中的name,id以及email,其操作为:
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");
获取成员值
获取成员值同样很简单,只有直接访问其成员即可,如下例子
fstream input("myfile", ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
Packed 编码
在 proto2 中为我们提供了可选的设置 [packed = true],而这一可选项在 proto3 中已成默认设置。
packed 目前只能用于 repeated类型。
packed = true 主要使让 ProtoBuf 为我们把 repeated primitive 的编码结果打包,从而进一步压缩空间,进一步提高效率、速度。这里打包的含义其实就是:原先的 repeated 字段的编码结构为 Tag-Length-Value-Tag-Length-Value-Tag-Length-Value...,因为这些 Tag 都是相同的(同一字段),因此可以将这些字段的 Value 打包,即将编码结构变为 Tag-Length-Value-Value-Value...
optional default设置
optional字段的默认值可以使用default来设置,例如:
optional int32 num = 1 [default = 0];
将默认值设值为0
用例
下面使用一个简单的例子说明Protobuf的基本使用方法.
proto文件
首先编写proto文件中,数据格式定义,代码如下:
syntax = "proto2";
message Person {
required int32 age = 1;
required string name = 2;
}
message Family {
repeated Person person = 1;
}
编译proto文件
使用proto编译器编译proto文件,Protobuf安装不在详细描述,可自行网上查找,安装成功后,可以查看其版本
使用protoc命令编译proto文件,编译完成之后会自动生产.h和.cpp的代码
protoc --cpp_out=./ family.proto
自动生成的family.pb.cc和family.pb.h文件,以供后面使用
protoc命令还可以将proto文件生成python和java文件接口,以供python和java使用,可以使用--help命令来查看protoc参数:
其中--cpp_out是生成c++接口文件以及源码,--jave_out是生成java接口,--python_out是生成python接口.
Family头文件
生成的Family头文件如下:
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: family.proto
#ifndef PROTOBUF_family_2eproto__INCLUDED
#define PROTOBUF_family_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 2006000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 2006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/unknown_field_set.h>
// @@protoc_insertion_point(includes)
// Internal implementation detail -- do not call these.
void protobuf_AddDesc_family_2eproto();
void protobuf_AssignDesc_family_2eproto();
void protobuf_ShutdownFile_family_2eproto();
class Person;
class Family;
// ===================================================================
class Person : public ::google::protobuf::Message {
public:
Person();
virtual ~Person();
Person(const Person& from);
inline Person& operator=(const Person& from) {
CopyFrom(from);
return *this;
}
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
static const ::google::protobuf::Descriptor* descriptor();
static const Person& default_instance();
void Swap(Person* other);
// implements Message ----------------------------------------------
Person* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
void CopyFrom(const Person& from);
void MergeFrom(const Person& from);
void Clear();
bool IsInitialized() const;
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
public:
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// required int32 age = 1;
inline bool has_age() const;
inline void clear_age();
static const int kAgeFieldNumber = 1;
inline ::google::protobuf::int32 age() const;
inline void set_age(::google::protobuf::int32 value);
// required string name = 2;
inline bool has_name() const;
inline void clear_name();
static const int kNameFieldNumber = 2;
inline const ::std::string& name() const;
inline void set_name(const ::std::string& value);
inline void set_name(const char* value);
inline void set_name(const char* value, size_t size);
inline ::std::string* mutable_name();
inline ::std::string* release_name();
inline void set_allocated_name(::std::string* name);
// @@protoc_insertion_point(class_scope:Person)
private:
inline void set_has_age();
inline void clear_has_age();
inline void set_has_name();
inline void clear_has_name();
::google::protobuf::UnknownFieldSet _unknown_fields_;
::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
::std::string* name_;
::google::protobuf::int32 age_;
friend void protobuf_AddDesc_family_2eproto();
friend void protobuf_AssignDesc_family_2eproto();
friend void protobuf_ShutdownFile_family_2eproto();
void InitAsDefaultInstance();
static Person* default_instance_;
};
// -------------------------------------------------------------------
class Family : public ::google::protobuf::Message {
public:
Family();
virtual ~Family();
Family(const Family& from);
inline Family& operator=(const Family& from) {
CopyFrom(from);
return *this;
}
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
return _unknown_fields_;
}
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
return &_unknown_fields_;
}
static const ::google::protobuf::Descriptor* descriptor();
static const Family& default_instance();
void Swap(Family* other);
// implements Message ----------------------------------------------
Family* New() const;
void CopyFrom(const ::google::protobuf::Message& from);
void MergeFrom(const ::google::protobuf::Message& from);
void CopyFrom(const Family& from);
void MergeFrom(const Family& from);
void Clear();
bool IsInitialized() const;
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
public:
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// repeated .Person person = 1;
inline int person_size() const;
inline void clear_person();
static const int kPersonFieldNumber = 1;
inline const ::Person& person(int index) const;
inline ::Person* mutable_person(int index);
inline ::Person* add_person();
inline const ::google::protobuf::RepeatedPtrField< ::Person >&
person() const;
inline ::google::protobuf::RepeatedPtrField< ::Person >*
mutable_person();
// @@protoc_insertion_point(class_scope:Family)
private:
::google::protobuf::UnknownFieldSet _unknown_fields_;
::google::protobuf::uint32 _has_bits_[1];
mutable int _cached_size_;
::google::protobuf::RepeatedPtrField< ::Person > person_;
friend void protobuf_AddDesc_family_2eproto();
friend void protobuf_AssignDesc_family_2eproto();
friend void protobuf_ShutdownFile_family_2eproto();
void InitAsDefaultInstance();
static Family* default_instance_;
};
// ===================================================================
// ===================================================================
// Person
可以看到其提供set_name(),set_age()接口,以及其他接口以供使用
Family源码
family.pb.cc为自动生成的源码文件,是其接口实现,有兴趣可以分析一波
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: family.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "family.pb.h"
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)
namespace {
const ::google::protobuf::Descriptor* Person_descriptor_ = NULL;
const ::google::protobuf::internal::GeneratedMessageReflection*
Person_reflection_ = NULL;
const ::google::protobuf::Descriptor* Family_descriptor_ = NULL;
const ::google::protobuf::internal::GeneratedMessageReflection*
Family_reflection_ = NULL;
} // namespace
void protobuf_AssignDesc_family_2eproto() {
protobuf_AddDesc_family_2eproto();
const ::google::protobuf::FileDescriptor* file =
::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
"family.proto");
GOOGLE_CHECK(file != NULL);
Person_descriptor_ = file->message_type(0);
static const int Person_offsets_[2] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Person, age_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Person, name_),
};
Person_reflection_ =
new ::google::protobuf::internal::GeneratedMessageReflection(
Person_descriptor_,
Person::default_instance_,
Person_offsets_,
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Person, _has_bits_[0]),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Person, _unknown_fields_),
-1,
::google::protobuf::DescriptorPool::generated_pool(),
::google::protobuf::MessageFactory::generated_factory(),
sizeof(Person));
Family_descriptor_ = file->message_type(1);
static const int Family_offsets_[1] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Family, person_),
};
Family_reflection_ =
new ::google::protobuf::internal::GeneratedMessageReflection(
Family_descriptor_,
Family::default_instance_,
Family_offsets_,
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Family, _has_bits_[0]),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Family, _unknown_fields_),
-1,
::google::protobuf::DescriptorPool::generated_pool(),
::google::protobuf::MessageFactory::generated_factory(),
sizeof(Family));
}
namespace {
GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
inline void protobuf_AssignDescriptorsOnce() {
::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
&protobuf_AssignDesc_family_2eproto);
}
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
Person_descriptor_, &Person::default_instance());
::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
Family_descriptor_, &Family::default_instance());
}
} // namespace
void protobuf_ShutdownFile_family_2eproto() {
delete Person::default_instance_;
delete Person_reflection_;
delete Family::default_instance_;
delete Family_reflection_;
}
void protobuf_AddDesc_family_2eproto() {
static bool already_here = false;
if (already_here) return;
already_here = true;
GOOGLE_PROTOBUF_VERIFY_VERSION;
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
"\n\014family.proto\"#\n\006Person\022\013\n\003age\030\001 \002(\005\022\014\n"
"\004name\030\002 \002(\t\"!\n\006Family\022\027\n\006person\030\001 \003(\0132\007."
"Person", 86);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"family.proto", &protobuf_RegisterTypes);
Person::default_instance_ = new Person();
Family::default_instance_ = new Family();
Person::default_instance_->InitAsDefaultInstance();
Family::default_instance_->InitAsDefaultInstance();
::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_family_2eproto);
}
// Force AddDescriptors() to be called at static initialization time.
struct StaticDescriptorInitializer_family_2eproto {
StaticDescriptorInitializer_family_2eproto() {
protobuf_AddDesc_family_2eproto();
}
} static_descriptor_initializer_family_2eproto_;
// ===================================================================
#ifndef _MSC_VER
const int Person::kAgeFieldNumber;
const int Person::kNameFieldNumber;
#endif // !_MSC_VER
Person::Person()
: ::google::protobuf::Message() {
SharedCtor();
// @@protoc_insertion_point(constructor:Person)
}
void Person::InitAsDefaultInstance() {
}
Person::Person(const Person& from)
: ::google::protobuf::Message() {
SharedCtor();
MergeFrom(from);
// @@protoc_insertion_point(copy_constructor:Person)
}
void Person::SharedCtor() {
::google::protobuf::internal::GetEmptyString();
_cached_size_ = 0;
age_ = 0;
name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
Person::~Person() {
// @@protoc_insertion_point(destructor:Person)
SharedDtor();
}
void Person::SharedDtor() {
if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
delete name_;
}
if (this != default_instance_) {
}
}
void Person::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* Person::descriptor() {
protobuf_AssignDescriptorsOnce();
return Person_descriptor_;
}
const Person& Person::default_instance() {
if (default_instance_ == NULL) protobuf_AddDesc_family_2eproto();
return *default_instance_;
}
Person* Person::default_instance_ = NULL;
Person* Person::New() const {
return new Person;
}
void Person::Clear() {
if (_has_bits_[0 / 32] & 3) {
age_ = 0;
if (has_name()) {
if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
name_->clear();
}
}
}
::memset(_has_bits_, 0, sizeof(_has_bits_));
mutable_unknown_fields()->Clear();
}
bool Person::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:Person)
for (;;) {
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
tag = p.first;
if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// required int32 age = 1;
case 1: {
if (tag == 8) {
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
input, &age_)));
set_has_age();
} else {
goto handle_unusual;
}
if (input->ExpectTag(18)) goto parse_name;
break;
}
// required string name = 2;
case 2: {
if (tag == 18) {
parse_name:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_name()));
::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
::google::protobuf::internal::WireFormat::PARSE,
"name");
} else {
goto handle_unusual;
}
if (input->ExpectAtEnd()) goto success;
break;
}
default: {
handle_unusual:
if (tag == 0 ||
::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:Person)
return true;
failure:
// @@protoc_insertion_point(parse_failure:Person)
return false;
#undef DO_
}
void Person::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:Person)
// required int32 age = 1;
if (has_age()) {
::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->age(), output);
}
// required string name = 2;
if (has_name()) {
::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
::google::protobuf::internal::WireFormat::SERIALIZE,
"name");
::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
2, this->name(), output);
}
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
// @@protoc_insertion_point(serialize_end:Person)
}
::google::protobuf::uint8* Person::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:Person)
// required int32 age = 1;
if (has_age()) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->age(), target);
}
// required string name = 2;
if (has_name()) {
::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
this->name().data(), this->name().length(),
::google::protobuf::internal::WireFormat::SERIALIZE,
"name");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
2, this->name(), target);
}
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
// @@protoc_insertion_point(serialize_to_array_end:Person)
return target;
}
int Person::ByteSize() const {
int total_size = 0;
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// required int32 age = 1;
if (has_age()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->age());
}
// required string name = 2;
if (has_name()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->name());
}
}
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
}
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = total_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
return total_size;
}
void Person::MergeFrom(const ::google::protobuf::Message& from) {
GOOGLE_CHECK_NE(&from, this);
const Person* source =
::google::protobuf::internal::dynamic_cast_if_available<const Person*>(
&from);
if (source == NULL) {
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
MergeFrom(*source);
}
}
void Person::MergeFrom(const Person& from) {
GOOGLE_CHECK_NE(&from, this);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_age()) {
set_age(from.age());
}
if (from.has_name()) {
set_name(from.name());
}
}
mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}
void Person::CopyFrom(const ::google::protobuf::Message& from) {
if (&from == this) return;
Clear();
MergeFrom(from);
}
void Person::CopyFrom(const Person& from) {
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool Person::IsInitialized() const {
if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false;
return true;
}
void Person::Swap(Person* other) {
if (other != this) {
std::swap(age_, other->age_);
std::swap(name_, other->name_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
_unknown_fields_.Swap(&other->_unknown_fields_);
std::swap(_cached_size_, other->_cached_size_);
}
}
::google::protobuf::Metadata Person::GetMetadata() const {
protobuf_AssignDescriptorsOnce();
::google::protobuf::Metadata metadata;
metadata.descriptor = Person_descriptor_;
metadata.reflection = Person_reflection_;
return metadata;
}
// ===================================================================
#ifndef _MSC_VER
const int Family::kPersonFieldNumber;
#endif // !_MSC_VER
Family::Family()
: ::google::protobuf::Message() {
SharedCtor();
// @@protoc_insertion_point(constructor:Family)
}
void Family::InitAsDefaultInstance() {
}
Family::Family(const Family& from)
: ::google::protobuf::Message() {
SharedCtor();
MergeFrom(from);
// @@protoc_insertion_point(copy_constructor:Family)
}
void Family::SharedCtor() {
_cached_size_ = 0;
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
Family::~Family() {
// @@protoc_insertion_point(destructor:Family)
SharedDtor();
}
void Family::SharedDtor() {
if (this != default_instance_) {
}
}
void Family::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* Family::descriptor() {
protobuf_AssignDescriptorsOnce();
return Family_descriptor_;
}
const Family& Family::default_instance() {
if (default_instance_ == NULL) protobuf_AddDesc_family_2eproto();
return *default_instance_;
}
Family* Family::default_instance_ = NULL;
Family* Family::New() const {
return new Family;
}
void Family::Clear() {
person_.Clear();
::memset(_has_bits_, 0, sizeof(_has_bits_));
mutable_unknown_fields()->Clear();
}
bool Family::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:Family)
for (;;) {
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
tag = p.first;
if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// repeated .Person person = 1;
case 1: {
if (tag == 10) {
parse_person:
DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
input, add_person()));
} else {
goto handle_unusual;
}
if (input->ExpectTag(10)) goto parse_person;
if (input->ExpectAtEnd()) goto success;
break;
}
default: {
handle_unusual:
if (tag == 0 ||
::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, mutable_unknown_fields()));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:Family)
return true;
failure:
// @@protoc_insertion_point(parse_failure:Family)
return false;
#undef DO_
}
void Family::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:Family)
// repeated .Person person = 1;
for (int i = 0; i < this->person_size(); i++) {
::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
1, this->person(i), output);
}
if (!unknown_fields().empty()) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
unknown_fields(), output);
}
// @@protoc_insertion_point(serialize_end:Family)
}
::google::protobuf::uint8* Family::SerializeWithCachedSizesToArray(
::google::protobuf::uint8* target) const {
// @@protoc_insertion_point(serialize_to_array_start:Family)
// repeated .Person person = 1;
for (int i = 0; i < this->person_size(); i++) {
target = ::google::protobuf::internal::WireFormatLite::
WriteMessageNoVirtualToArray(
1, this->person(i), target);
}
if (!unknown_fields().empty()) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
unknown_fields(), target);
}
// @@protoc_insertion_point(serialize_to_array_end:Family)
return target;
}
int Family::ByteSize() const {
int total_size = 0;
// repeated .Person person = 1;
total_size += 1 * this->person_size();
for (int i = 0; i < this->person_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
this->person(i));
}
if (!unknown_fields().empty()) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
unknown_fields());
}
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = total_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
return total_size;
}
void Family::MergeFrom(const ::google::protobuf::Message& from) {
GOOGLE_CHECK_NE(&from, this);
const Family* source =
::google::protobuf::internal::dynamic_cast_if_available<const Family*>(
&from);
if (source == NULL) {
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
MergeFrom(*source);
}
}
void Family::MergeFrom(const Family& from) {
GOOGLE_CHECK_NE(&from, this);
person_.MergeFrom(from.person_);
mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}
void Family::CopyFrom(const ::google::protobuf::Message& from) {
if (&from == this) return;
Clear();
MergeFrom(from);
}
void Family::CopyFrom(const Family& from) {
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool Family::IsInitialized() const {
if (!::google::protobuf::internal::AllAreInitialized(this->person())) return false;
return true;
}
void Family::Swap(Family* other) {
if (other != this) {
person_.Swap(&other->person_);
mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}
void Family::CopyFrom(const ::google::protobuf::Message& from) {
if (&from == this) return;
Clear();
MergeFrom(from);
}
void Family::CopyFrom(const Family& from) {
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool Family::IsInitialized() const {
if (!::google::protobuf::internal::AllAreInitialized(this->person())) return false;
return true;
}
void Family::Swap(Family* other) {
if (other != this) {
person_.Swap(&other->person_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
_unknown_fields_.Swap(&other->_unknown_fields_);
std::swap(_cached_size_, other->_cached_size_);
}
}
::google::protobuf::Metadata Family::GetMetadata() const {
protobuf_AssignDescriptorsOnce();
::google::protobuf::Metadata metadata;
metadata.descriptor = Family_descriptor_;
metadata.reflection = Family_reflection_;
return metadata;
}
// @@protoc_insertion_point(namespace_scope)
// @@protoc_insertion_point(global_scope)
用例
使用用例要求对Famyily添加两个成员,并分别设置其name和age, 用例先后先要加载生成的头文件famiy.pb.h,用例代码如下较为简单:
#include "family.pb.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
GOOGLE_PROTOBUF_VERIFY_VERSION;
Family family;
Person* person;
person = family.add_person();
person->set_age(25);
person->set_name("John");
person = family.add_person();
person->set_age(40);
person->set_name("Tony");
int size = family.person_size();
printf("size : %d \r\n", size);
for(int i = 0; i<size; i++)
{
Person psn=family.person(i);
cout <<"Name :"<<psn.name()<<", age: "<<psn.age()<<endl;
}
return 0;
}
Makfile
编写makefile,不仅要编译编写的用例文件,还要编译自动生成的family.pb.cc文件,编译选项要加上
pkg-config --cflags --libs protobuf`
Makfile源码如下:
CC=g++
LIB_PATH=
HEAD_PATH=
TARGET = test
CPPFLAGS = -v -std=c++11
LIB_NAME =
CPP_FILE = family.pb.cc main.cpp
$(TARGET):
$(CC) $(CPPFLAGS) $(CPP_FILE) $(LIB_PATH) $(LIB_NAME) $(HEAD_PATH) `pkg-config --cflags --libs protobuf` -o $@
clean:
rm -f $(TARGET)
运行
用例运行结果:
Caffe.proto文件
到目前为止Protobuf应该有所了解,上述资料足以我们能够了解src\caffe\proto\caffe.proto文件,Protobuf这层洋葱应该也可以剥掉.见caffe.proto文件开头
syntax = "proto2";
package caffe;
// Specifies the shape (dimensions) of a Blob.
message BlobShape {
repeated int64 dim = 1 [packed = true];
}
message BlobProto {
optional BlobShape shape = 7;
repeated float data = 5 [packed = true];
repeated float diff = 6 [packed = true];
repeated double double_data = 8 [packed = true];
repeated double double_diff = 9 [packed = true];
// 4D dimensions -- deprecated. Use "shape" instead.
optional int32 num = 1 [default = 0];
optional int32 channels = 2 [default = 0];
optional int32 height = 3 [default = 0];
optional int32 width = 4 [default = 0];
}
文件开头 syntax = "proto2";表明使用的是proto2版本
- 在下行代码中看到一个关键字package,主要一个声名符,用来防止不同的消息类型有命名冲突。包的声明符会根据使用语言的不同影响生成的代码。对于C++,产生的类会被包装在C++的命名空间。package caffe,表明是在caffe的命名空间
- 接下来定义一个BlobShape数据结构,数据结构中只包含一个字段dim,数据类型为int64,该数据类型为repeated,可以包含多个dim, 使用之前可以使用dim_size来计算其数据中有多少个dim,例如:
- BlobProto结构定义,是Blob中比较关键的数据结构。在该数据中首先可以看到首先定义一个 BlobShape字段(ProtoBuf字段定义可以包含之前定义的数据结构),该字段是可选的,但是其number并不是为1,而是放到了后面。由此可以看到message中的字段定义并不是定义的第一个其number就为1,而是按照其经常使用频率进行调整。在BlobProto中经常使用到的就是4维参数,所以将4维参数放到前面,从1到4依次维num, channels, heigt, width。紧接着存放数据顺序维data, diff, shape, double_data, double_diff。在我们实际使用中定义message字段,也可以将经常使用到的频率较高的放到前面以提高访问效率及速度。
- 接下来定义BlobProtoVector数据结构,包含字段类型为可选的BlobProto
剩余其他的不再解释,应该自己可以足够看懂,是不是并没有想象中的那么复杂,限于篇幅大小,将在下节中介绍protobuf中的文件读写:
参考资料
https://developers.google.cn/protocol-buffers/docs/overview#whynotxml