Flatbuffers学习
flatbuffers简介
FlatBuffers 是一个(二进制 buffer)序列化开源库,由 Google 开源现在它支持C++, C#, C, Go, Java, Kotlin, JavaScript, Lobster, Lua, TypeScript, PHP, Python, Rust and Swift等。
官网:http://google.github.io/flatbuffers/
特点
- 无需解析/解包即可访问序列化数据;
- 强类型;
- 使用方便;
- 无依赖的跨平台代码;
与Protocol Buffers的比较(优点):
使用过程中,我觉得flat对比proto最大的优点就是“零拷贝”反序列化,如果你需要大量的反序列化,flat要比proto更合适一些。
FlatBuffers schema
#include "FbBasicType.fbs"; // 消息头的类型,时间戳等等
namespace Jflat;
table FbFunction{
func_id : uint32;
param_list : [string]; // vector类型
return_value : string;
}
root_type FbFunction; // root_type声明序列化数据的object
FlatBuffers schema compilation
使用flatc编译.fbs文件,它将为对应编程语言创建生成代码。
flatc --gen-mutable --gen-object-api --reflect-names --cpp-ptr-type flatbuffers::unique_ptr --gen-compare --json --cpp --java --js --python *.fbs #--gen-all
--gen-mutable Generate accessors that can mutate buffers in-place.
--gen-object-api Generate an additional object-based API.
--reflect-names Add minimal type/name reflection.
--gen-compare Generate operator== for object-based API types.
FlatBuffers serialization methods
.h文件
#ifndef JFUNCTION_H
#define JFUNCTION_H
#include "JflatHeader.h"
class JFunction : public JflatHeader
{
public:
uint32_t func_id;
std::vector<std::string> param_list;
std::string return_value;
public:
JFunction();
explicit JFunction(const uint8_t *tmp_data);
explicit JFunction(uint32_t tmp_func_id, std::vector<std::string> &tmp_param_list, const std::string &tmp_return_value);
JFunction(const JFunction &tmp);
JFunction &operator=(const JFunction &tmp);
~JFunction() = default;
std::string str();
const Jflat::FbMessage *getFbMessage(const uint8_t *data);
flatbuffers::Offset<Jflat::FbFunction> createFbFunction(flatbuffers::FlatBufferBuilder &builder) const;
flatbuffers::Offset<Jflat::FbMessage> createFbMessage(flatbuffers::FlatBufferBuilder &builder) const override;
std::shared_ptr<flatbuffers::DetachedBuffer> serializeAsFlat() const;
bool deserialize(const uint8_t *data) override;
bool getFbFunction(const Jflat::FbFunction *flat_function);
std::string serializeAsString() const;
private:
void assignmentVariable(const JFunction &tmp);
};
#endif //JFUNCTION_H
.cpp文件
#include "JFunction.h"
JFunction::JFunction() : func_id(0),
param_list(std::vector<std::string>()),
return_value("")
{
mObjType = Jflat::FbDataHeadType_FBT_RFC;
}
JFunction::JFunction(uint32_t tmp_func_id, std::vector<std::string> &tmp_param_list, const std::string &tmp_return_value)
: func_id(tmp_func_id),
param_list(tmp_param_list),
return_value(tmp_return_value)
{
mObjType = Jflat::FbDataHeadType_FBT_RFC;
}
JFunction::JFunction(const uint8_t *tmp_data)
{
mObjType = Jflat::FbDataHeadType_FBT_RFC;
deserialize(tmp_data);
}
JFunction::JFunction(const JFunction &tmp)
{
mObjType = Jflat::FbDataHeadType_FBT_RFC;
assignmentVariable(tmp);
}
JFunction &JFunction::operator=(const JFunction &tmp)
{
if (this != &tmp) assignmentVariable(tmp);
return *this;
}
void JFunction::assignmentVariable(const JFunction &tmp)
{
QObject::assignmentVariable(tmp.mStamp, tmp.mId, tmp.mObjType);
param_list.assign(tmp.param_list.begin(), tmp.param_list.end());
func_id = tmp.func_id;
return_value = tmp.return_value;
}
std::string JFunction::str()
{
return flatbuffers::FlatBufferToString(serializeAsFlat()->data(), Qflat::FbMessageTypeTable(), true);
}
std::string JFunction::serializeAsString() const
{
auto detached_buffer = serializeAsFlat();
if (detached_buffer)
return std::string((char *) detached_buffer->data(), detached_buffer->size());
else
return "";
}
std::shared_ptr<flatbuffers::DetachedBuffer> JFunction::serializeAsFlat() const
{
flatbuffers::FlatBufferBuilder builder;
auto flat = createFbMessage(builder);
builder.Finish(flat);
return std::make_shared<flatbuffers::DetachedBuffer>(builder.Release());
}
const Jflat::FbMessage *JFunction::getFbMessage(const uint8_t *data)
{
auto data_flat = Jflat::GetFbMessage(data);
obj_type = data_flat->header()->type();
stamp = data_flat->header()->stamp();
id = data_flat->header()->id();
return data_flat;
}
flatbuffers::Offset<Jflat::FbFunction> JFunction::createFbFunction(flatbuffers::FlatBufferBuilder &builder) const
{
auto flat_param_list = builder.CreateVectorOfStrings(param_list);
auto flat_return_value = builder.CreateString(return_value);
auto flat_function = Jflat::CreateFbFunction(builder, func_id, flat_param_list, flat_return_value);
return flat_function;
}
flatbuffers::Offset<Jflat::FbMessage> JFunction::createFbMessage(flatbuffers::FlatBufferBuilder &builder) const
{
auto header_function = Jflat::CreateFbMsgHeader(builder, Jflat::FbDataHeadType_FBT_RFC, mStamp, mId);
auto flat_function = createFbFunction(builder);
auto flat = Jflat::CreateFbMessage(builder, header_function, Jflat::FbMsgBody_FbFunction, flat_function.Union());
return flat;
}
bool JFunction::deserialize(const uint8_t *data)
{
auto data_flat = getFbMessage(data);
auto flat_function = data_flat->data_as_FbFunction();
getFbFunction(flat_function);
return true;
}
bool JFunction::getFbFunction(const Jflat::FbFunction *flat_function)
{
func_id = flat_function->func_id();
param_list.clear();
for (const auto &flat_data : *flat_function->param_list())
param_list.emplace_back(std::string(flat_data->data(), flat_data->size()));
return_value = std::string(flat_function->return_value()->data(), flat_function->return_value()->size());
return true;
}
FlatBuffers example
#include "JFunction.h"
#include <iostream>
#define FLAT_DATA_DIFF(before_data, after_data) \
{ \
if(!(before_data == after_data)) \
{ \
std::cout << #before_data << " : line" << __LINE__ << "========================== before =================================" << std::endl; \
std::cout << before_data << std::endl; \
std::cout << #after_data << " : line" << __LINE__ << "========================== after =================================" << std::endl; \
std::cout << after_data << std::endl; \
} \
}
void assignment_JFunction_instance(JFunction &jFunction_1)
{
jFunction_1.func_id = 222;
for (uint16_t i = 0; i < GENERIC_16_ARRAY_SIZE; ++i)
jFunction_1.param_list.push_back(std::to_string(i));
jFunction_1.return_value = "return_value pi pi sha"; /// 嘿嘿嘿,我女朋友
}
int main(void)
{
JFunction jFunction_1;
assignment_JFunction_instance(jFunction_1);
auto buf = jFunction_1.serializeAsFlat();
JFunction jFunction_2(buf->data());
FLAT_DATA_DIFF(jFunction_1.str(), jFunction_2.str());
return 0;
}