关于flatbuffer的union结构

今天研究flatbuffers,想用二进制存储一些指令,想设计成存储到一个vector里,数据是union型的,这样就能通过union里的int标记判断数据类型。于是我用了flatbuffers的schema模板生成union代码,可是问题是union怎么描述的是enum类型的?

//设想中的union结构大概是这个样子
union  commond {
    struct{ int,char}common,
    struct{...}cmd1,
    struct{...}cmd2,
    ...
}

哎马,我天,我总算看懂它的源码了。汗。使用的时候能用data_type()获取类型(可以用enum的标记),data()获取数据。
我的schema是这个结构

// Example IDL file for our monster's schema.
namespace modrim;

table TextCmd {
  msg_len:short;
  name:string;
}
table GotoCmd {
  goto_label:long;
  name:string;
}
union Cmd {
  text:TextCmd,
  goto_cmd:GotoCmd
}
table Root {
  data:[Cmd];
}
root_type Root;

最主要的是包含union的Vector。下面这个函数是最关键的函数。这个函数是生成器生成的。对应上面的Root

inline flatbuffers::Offset<Root> CreateRoot(
    flatbuffers::FlatBufferBuilder &_fbb,
    flatbuffers::Offset<flatbuffers::Vector<uint8_t>> data_type = 0,
    flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<void>>> data = 0) {
  RootBuilder builder_(_fbb);
  builder_.add_data(data);
  builder_.add_data_type(data_type);
  return builder_.Finish();
}

union在函数里被分成两个部分,一个是类型data_type,一个是保存的数据data,放在两个Vector(flatbutters的Vector,注意类型)里面,创建的时候要一一对应创建。要注意data数组要注入的类型,接口是.Union()

    flatbuffers::FlatBufferBuilder builder;
    std::vector<uint8_t> data_types;
    std::vector<flatbuffers::Offset<void>> data;
    auto cmd1 = CreateTextCmd(builder,312,builder.CreateString("woshiyigedaguaishou"));
    auto cmd2 = CreateGotoCmd(builder,245,builder.CreateString("dddkeo"));
    data_types.push_back(Cmd_text);//enum类型标记
    data.push_back(cmd1.Union());//注入数据
    data_types.push_back(Cmd_goto_cmd);//另一个enum类型标记
    data.push_back(cmd2.Union());//注入另一个数据
    auto vec_types = builder.CreateVector(data_types);
    auto vec_data = builder.CreateVector(data);
    auto root = CreateRoot(builder,vec_types,vec_data);
    builder.Finish(root);
    cout<<builder.GetSize()<<endl;//
    //save
    fstream outfile("test.bin",ios::out | ios::binary);
    outfile.write((char*)builder.GetBufferPointer(), builder.GetSize());
    outfile.close();

接下来就是读取数据了。

    std::fstream infile;
    infile.open("test.bin",ios::binary | ios::in);
    if (!infile)
    {
        return 0;
    }
    infile.seekg(0, ios::end);
    int length = (int)infile.tellg();
    infile.seekg(0, ios::beg);
    char* data = new char[length];
    infile.read(data, length);
    infile.close();
    auto root = GetRoot(data);

    cout<<(int)root->data_type()->Get(1)<<endl;//类型输出
    cout<<root->data()->GetAs<GotoCmd>(1)->name()->c_str()<<endl;//已经知道第二个是goto指令,这里就直接转换了。

有两个接口data_type()获得保存类型标记的数组,data获得数据数组,然后就根据标记进行类型转换即可。

真爱生命,远离C艹,尤其是模版。就这么简简单单的原理,看了我一个下午+晚上,而且,我只看懂了flatbuffers的union类型的应用思路,库文件的技术细节根本没看明白!