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;
}
posted @ 2021-01-16 15:54  空水  阅读(1052)  评论(0编辑  收藏  举报