LoginSignup
38
33

More than 5 years have passed since last update.

C++でデータを保存する(FlatBuffers編)

Last updated at Posted at 2014-08-20

cocos2d-xでデータを保存するにはUserDefaultかsqlite3を利用していたが、汎用性のあるライブラリがあったのでその調査メモ。

FlatBuffers

Googleがオープンソース化したC++シリアライズライブラリとして2014/6に公開。
ゲーム開発者のためのライブラリとして高いパフォーマンスを発揮する模様。

C++だけでなくGoやJavaでも利用可能。

C++だとヘッダのみで利用できるので色々な環境に対応できる。

特徴

  • パーズ/アンパッキングなしにシリアル化されたデータにアクセスできる
  • メモリ効率と速度
  • 柔軟性
  • ライブラリのコード量の少なさ
  • 型安全性
  • 利便性
  • クロスプラットフォーム

RapidJsonはJSONのパーサで高速であるがFlatBuffersは更に高速に動作する模様。

URL

C++でFlatBuffersを利用できるようにする

FlatBuffersは以下の手順で利用できる。

  • スキーマファイルを作成する
  • flatcコマンドでスキーマファイルをコンパイルする
  • 生成されたヘッダとflatbuffers.h(場合によってはflatbuffersのidl_parser.cppなどのcppもコンパイルしてリンクする)をincludeする
  • FlatBufferBuilderでファイルの読み書きを行なう

スキーマファイルをコンパイルできるようにする

  • 環境

    • Mac OS X 10.9.4
    • XCode 5.1.1
  • GitHubからリポジトリをcloneする

    git clone https://github.com/google/flatbuffers.git
  • XCodeでコンパイルする
    cd flatbuffers
    open build/Xcode/FlatBuffers.xcodeproj

schemeにflatcを選択してビルドする。
flatbuffersディレクトリにflatcというバイナリができる。
以下はflatcのヘルプ

usage: ./flatc [OPTION]... FILE... [-- FILE...]
  -b      Generate wire format binaries for any data definitions.
  -t      Generate text output for any data definitions.
  -c      Generate C++ headers for tables/structs.
  -g      Generate Go files for tables/structs.
  -j      Generate Java classes for tables/structs.
  -o PATH Prefix PATH to all generated files.
  -S      Strict JSON: add quotes to field names.
FILEs may depend on declarations in earlier files.
FILEs after the -- must be binary flatbuffer format files.
Output files are named using the base file name of the input,and written to the current directory or the path given by -o.
example: ./flatc -c -b schema1.fbs schema2.fbs data.json

スキーマファイルを書いてC++用ヘッダを作成する

以下ではサンプルをそのまま利用する。独自クラスでも同様にスキーマを書けば良い。

以下のコマンドでスキーマファイルをコンパイルする。

  cd samples
  ../flatc -c monster.fbs

monster_generated.hというヘッダが生成されるのでこれをincludeして利用する。

データの読み書きをしてみる

JSONはサンプルにあるので、バイナリデータを利用してみる。

flatbuffers関連ヘッダはincludeディレクトリに配置。
monster_generated.hはsamplesディレクトリに配置.

C++のコンパイルコマンドはこんな感じ

clang++ -g -Wall -std=c++11 -I include main.cc

以下、main.ccのコード。

main.cc
#include <iostream>

#include "samples/monster_generated.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/util.h"

int main(int /*argc*/, const char * /*argv*/[]) {
  using namespace MyGame::Sample;

  {
    // 新規にデータを作成
    flatbuffers::FlatBufferBuilder builder;
    auto vec = Vec3(1, 2, 3);
    auto name = builder.CreateString("Test");
    unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    auto inventory = builder.CreateVector(inv_data, 10);
    auto mloc = CreateMonster(builder, &vec, 100, 50, name, inventory, Color_Blue);
    builder.Finish(mloc);

    auto monster = GetMonster(builder.GetBufferPointer());
    printf("### 作成したデータ: hp=%d, mana=%d, name=%s\n",
           monster->hp(), monster->mana(), monster->name()->c_str());

    // データファイル書き込み
    auto ok = flatbuffers::SaveFile("samples/monsterdata.bin",
                                    reinterpret_cast<const char *>(builder.GetBufferPointer()),
                                    builder.GetSize(),
                                    true);
    if (!ok) {
      printf("couldn't save files!\n");
      return 1;
    }
  }

  {
    // データファイル読み込み
    std::string binfile;
    auto ok = flatbuffers::LoadFile("samples/monsterdata.bin", true, &binfile);
    if (!ok) {
      printf("couldn't load files!\n");
      return 1;
    }

    auto monster = GetMonster(binfile.data());
    printf("### ロードしたデータ: hp=%d, mana=%d, name=%s\n",
           monster->hp(), monster->mana(), monster->name()->c_str());
  }

  return 0;

}

スキーマに関する更なる情報は、flatbuffers/testsディレクトリにあるmonster_test.fbsを参照

38
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
33