An Embedded Engineer’s Blog

とある組み込みエンジニアの備忘録的なブログです。

C++で任意のデータ型をシリアライズ - その4 使い方編

まえがき

C++で任意のデータをシリアライズするためのクラスの実装方法を紹介します。

今回は前回に引き続き任意のデータ型(クラス/構造体)に対してシリアライズできるようにする方法について説明します。

ソース一式はGitHubで公開しています。


前提条件

今回実装したソースは以下の環境でビルド、動作確認しています。

OS Ver Compiler Remarks
Windows 11 Visual Studio 2022(C++14)


実装

ユーザデータ型定義

まずは、ユーザが使用する任意のデータ型を定義します。
今回はサンプルとして、プリミティブ型、STLコンテナ型、列挙型、構造体型でそれぞれデータ型を定義しています。

/* 論理型 */
using BoolMessage = bool_t;

/* 符号付整数型(8bit) */
using Int8Message = int8_t;

/* 符号付整数型(16bit) */
using Int16Message = int16_t;

/* 符号付整数型(32bit) */
using Int32Message = int32_t;

/* 符号付整数型(64bit) */
using Int64Message = int64_t;

/* 符号無整数型(8bit) */
using UInt8Message = uint8_t;

/* 符号無整数型(16bit) */
using UInt16Message = uint16_t;

/* 符号無整数型(32bit) */
using UInt32Message = uint32_t;

/* 符号無整数型(64bit) */
using UInt64Message = uint64_t;

/* 浮動小数型(32bit) */
using Float32Message = float32_t;

/* 浮動小数型(64bit) */
using Float64Message = float64_t;

/* 文字列型 */
using StringMessage = string_t;

/* std::array型 */
using ArrayMessage = std::array<int32_t, 4>;

/* std::vector型 */
using VectorMessage = std::vector<float64_t>;

/* std::map型 */
using MapMessage = std::map<int32_t, float64_t>;

/* 列挙型(enum class) */
enum class EnumMessage1
{
    VALUE1,
    VALUE2,
    VALUE3,
    VALUE4,
};

/* 列挙型(enum) */
enum EnumMessage2
{
    ENUM_MSG2_VALUE1,
    ENUM_MSG2_VALUE2,
    ENUM_MSG2_VALUE3,
    ENUM_MSG2_VALUE4,
    ENUM_MSG2_VALUE5,
};

/* 構造体型1 */
struct StrucMessage1
{
    bool_t bool_value;
    uint32_t uint_value;
    float32_t float_value;
};

/* 構造体型2 */
struct StrucMessage2
{
    std::array<float32_t, 8> float_array;
    std::vector<uint64_t> ulong_vec;
};

/* 列挙型(メンバ用) */
enum class EnumType1
{
    ENUM_VALUE1,
    ENUM_VALUE2,
    ENUM_VALUE3,
};

/* 構造体型3 */
struct StrucMessage3
{
    string_t string_value;
    std::map<EnumType1, string_t> enum_str_map;
};

ユーザデータ型特性定義

リアライザクラスが参照するtype_traits::DataTypeTraits<T>GetMembersAsTuple()およびGetNamedMembersAsTuple()を定義します。

GetMembersAsTuple()では、シリアライズ対象となるすべてのメンバ変数をstd::tieで列挙して返すようにします。
GetNamedMembersAsTuple()では、シリアライズ対象となるメンバ変数とそのメンバ変数名をstd::tieで列挙し、さらにstd::make_tuple()でタプル型として返すようにします。
GetMembersAsTuple()GetNamedMembersAsTuple()のいずれも変更可能なもの(constなし)と、変更不可のもの(const付き)の2種類を定義します。

using namespace cpp_lib::type_traits;

/* app::StrucMessage1 */
template <>
struct DataTypeTraits<app::StrucMessage1>
{
    /* メンバをタプルで取得(変更不可) */
    static auto GetMembersAsTuple(const app::StrucMessage1& data)
    {
        return std::tie(data.bool_value, data.uint_value, data.float_value);
    }

    /* メンバをタプルで取得(変更可) */
    static auto GetMembersAsTuple(app::StrucMessage1& data)
    {
        return std::tie(data.bool_value, data.uint_value, data.float_value);
    }

    /* メンバを名前付きタプルで取得(変更不可) */
    static auto GetNamedMembersAsTuple(const app::StrucMessage1& data)
    {
        return std::make_tuple(std::tie("bool_value", data.bool_value), std::tie("uint_value", data.uint_value), std::tie("float_value", data.float_value));
    }

    /* メンバを名前付きタプルで取得(変更可) */
    static auto GetNamedMembersAsTuple(app::StrucMessage1& data)
    {
        return std::make_tuple(std::tie("bool_value", data.bool_value), std::tie("uint_value", data.uint_value), std::tie("float_value", data.float_value));
    }
};

/* app::StrucMessage2 */
template <>
struct DataTypeTraits<app::StrucMessage2>
{
    /* メンバをタプルで取得(変更不可) */
    static auto GetMembersAsTuple(const app::StrucMessage2& data)
    {
        return std::tie(data.float_array, data.ulong_vec);
    }

    /* メンバをタプルで取得(変更可) */
    static auto GetMembersAsTuple(app::StrucMessage2& data)
    {
        return std::tie(data.float_array, data.ulong_vec);
    }

    /* メンバを名前付きタプルで取得(変更不可) */
    static auto GetNamedMembersAsTuple(const app::StrucMessage2& data)
    {
        return std::make_tuple(std::tie("float_array", data.float_array), std::tie("ulong_vec", data.ulong_vec));
    }

    /* メンバを名前付きタプルで取得(変更可) */
    static auto GetNamedMembersAsTuple(app::StrucMessage2& data)
    {
        return std::make_tuple(std::tie("float_array", data.float_array), std::tie("ulong_vec", data.ulong_vec));
    }
};

/* app::StrucMessage3 */
template <>
struct DataTypeTraits<app::StrucMessage3>
{
    /* メンバをタプルで取得(変更不可) */
    static auto GetMembersAsTuple(const app::StrucMessage3& data)
    {
        return std::tie(data.string_value, data.enum_str_map);
    }

    /* メンバをタプルで取得(変更可) */
    static auto GetMembersAsTuple(app::StrucMessage3& data)
    {
        return std::tie(data.string_value, data.enum_str_map);
    }

    /* メンバを名前付きタプルで取得(変更不可) */
    static auto GetNamedMembersAsTuple(const app::StrucMessage3& data)
    {
        return std::make_tuple(std::tie("string_value", data.string_value), std::tie("enum_str_map", data.enum_str_map));
    }

    /* メンバを名前付きタプルで取得(変更可) */
    static auto GetNamedMembersAsTuple(app::StrucMessage3& data)
    {
        return std::make_tuple(std::tie("string_value", data.string_value), std::tie("enum_str_map", data.enum_str_map));
    }
};

ヘッダインクルード

ユーザデータ型特性を定義したヘッダ、シリアライザ(BinarySerialization、TextSerialization)のヘッダを同時にインクルードします。

これにより、独自で定義したデータ型に対するシリアライズ処理が実現できます。

/* 型定義&型特性定義 */
#include "UserDataTypes.h"
#include "UserDataTypeTraits.h"

/* シリアライザ */
#include "BinarySerialization.h"
#include "TextSerialization.h"
#include "Serializer.h"
#include "SerializerFactory.h"

明示的インスタンス

こちらは必須ではありませんが、テンプレートの明示的インスタンス化を行うことで、ユーザが定義した任意のデータ型に対するインスタンス化の回数を抑制し、プログラムの実行サイズやコンパイル時間を削減することができます。

前述のヘッダインクルードと合わせてUserTypeOperations.h/.cppなどのように1つのヘッダ・ソースにまとめて定義しておくと良いと思います。

明示的インスタンス化宣言(ヘッダ側)

ヘッダ側では明示的インスタンス化宣言を行います。
これにより、どこかで明示的インスタンス化が行われていることが宣言され、ヘッダインクルード側(利用側)でのインスタンス化が抑制されます(コンパイル時間の削減)。

namespace serialization
{
    /* バイナリ形式シリアライズ明示的インスタンス化宣言 */
    /* app::StrucMessage1 */
    extern template void BinarySerialization::Calculate<app::StrucMessage1>(const app::StrucMessage1& in_data, size_t& out_size, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);
    extern template void BinarySerialization::Serialize<app::StrucMessage1>(const app::StrucMessage1& in_data, size_t& offset, serialization::Archive& out_archive, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);
    extern template void BinarySerialization::Deserialize<app::StrucMessage1>(const serialization::Archive& in_archive, size_t& offset, app::StrucMessage1& out_data, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);

    /* app::StrucMessage2 */
    extern template void BinarySerialization::Calculate<app::StrucMessage2>(const app::StrucMessage2& in_data, size_t& out_size, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);
    extern template void BinarySerialization::Serialize<app::StrucMessage2>(const app::StrucMessage2& in_data, size_t& offset, serialization::Archive& out_archive, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);
    extern template void BinarySerialization::Deserialize<app::StrucMessage2>(const serialization::Archive& in_archive, size_t& offset, app::StrucMessage2& out_data, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);

    /* app::StrucMessage3 */
    extern template void BinarySerialization::Calculate<app::StrucMessage3>(const app::StrucMessage3& in_data, size_t& out_size, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);
    extern template void BinarySerialization::Serialize<app::StrucMessage3>(const app::StrucMessage3& in_data, size_t& offset, serialization::Archive& out_archive, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);
    extern template void BinarySerialization::Deserialize<app::StrucMessage3>(const serialization::Archive& in_archive, size_t& offset, app::StrucMessage3& out_data, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);


    /* テキスト形式シリアライズ明示的インスタンス化宣言 */
    /* app::StrucMessage1 */
    extern template void TextSerialization::Serialize<app::StrucMessage1>(const app::StrucMessage1& in_data, Node& out_node, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);
    extern template void TextSerialization::Deserialize<app::StrucMessage1>(const Node& in_node, app::StrucMessage1& out_data, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);

    /* app::StrucMessage2 */
    extern template void TextSerialization::Serialize<app::StrucMessage2>(const app::StrucMessage2& in_data, Node& out_node, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);
    extern template void TextSerialization::Deserialize<app::StrucMessage2>(const Node& in_node, app::StrucMessage2& out_data, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);

    /* app::StrucMessage3 */
    extern template void TextSerialization::Serialize<app::StrucMessage3>(const app::StrucMessage3& in_data, Node& out_node, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);
    extern template void TextSerialization::Deserialize<app::StrucMessage3>(const Node& in_node, app::StrucMessage3& out_data, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);
}

明示的インスタンス化定義(ソース側)

ソース側では明示的インスタンス化定義を行います。
これにより、ユーザが定義した任意のデータ型に対するインスタンス化があらかじめ行われ、シリアライザを利用する(呼び出す)側では、インスタンス化が抑制されます(実行ファイルのサイズ削減)。

namespace serialization
{
    /* バイナリ形式シリアライズ明示的インスタンス化 */
    /* app::StrucMessage1 */
    template void BinarySerialization::Calculate<app::StrucMessage1>(const app::StrucMessage1& in_data, size_t& out_size, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);
    template void BinarySerialization::Serialize<app::StrucMessage1>(const app::StrucMessage1& in_data, size_t& offset, serialization::Archive& out_archive, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);
    template void BinarySerialization::Deserialize<app::StrucMessage1>(const serialization::Archive& in_archive, size_t& offset, app::StrucMessage1& out_data, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);

    /* app::StrucMessage2 */
    template void BinarySerialization::Calculate<app::StrucMessage2>(const app::StrucMessage2& in_data, size_t& out_size, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);
    template void BinarySerialization::Serialize<app::StrucMessage2>(const app::StrucMessage2& in_data, size_t& offset, serialization::Archive& out_archive, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);
    template void BinarySerialization::Deserialize<app::StrucMessage2>(const serialization::Archive& in_archive, size_t& offset, app::StrucMessage2& out_data, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);

    /* app::StrucMessage3 */
    template void BinarySerialization::Calculate<app::StrucMessage3>(const app::StrucMessage3& in_data, size_t& out_size, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);
    template void BinarySerialization::Serialize<app::StrucMessage3>(const app::StrucMessage3& in_data, size_t& offset, serialization::Archive& out_archive, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);
    template void BinarySerialization::Deserialize<app::StrucMessage3>(const serialization::Archive& in_archive, size_t& offset, app::StrucMessage3& out_data, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);


    /* テキスト形式シリアライズ明示的インスタンス化 */
    /* app::StrucMessage1 */
    template void TextSerialization::Serialize<app::StrucMessage1>(const app::StrucMessage1& in_data, Node& out_node, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);
    template void TextSerialization::Deserialize<app::StrucMessage1>(const Node& in_node, app::StrucMessage1& out_data, typename std::enable_if<std::is_class<app::StrucMessage1>::value>::type*);

    /* app::StrucMessage2 */
    template void TextSerialization::Serialize<app::StrucMessage2>(const app::StrucMessage2& in_data, Node& out_node, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);
    template void TextSerialization::Deserialize<app::StrucMessage2>(const Node& in_node, app::StrucMessage2& out_data, typename std::enable_if<std::is_class<app::StrucMessage2>::value>::type*);

    /* app::StrucMessage3 */
    template void TextSerialization::Serialize<app::StrucMessage3>(const app::StrucMessage3& in_data, Node& out_node, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);
    template void TextSerialization::Deserialize<app::StrucMessage3>(const Node& in_node, app::StrucMessage3& out_data, typename std::enable_if<std::is_class<app::StrucMessage3>::value>::type*);
}

使用例

定義したユーザデータ型に対するシリアライズ/デシリアライズを行うサンプルコードを示します。

モード切替えコンパイルスイッチ

バイナリ形式のシリアライズとテキスト形式のシリアライズを切り替えるためのコンパイルスイッチマクロを定義しています。

/* シリアライズモード:バイナリ形式 */
#define SERIALIZE_MODE_BINARY   (0)
/* シリアライズモード:テキスト形式 */
#define SERIALIZE_MODE_TEXT     (1)

/* シリアライズモード切替え */
#define SERIALIZE_MODE          (SERIALIZE_MODE_BINARY)
シリアライズテスト関数

シリアライズのテストを行う共通関数を定義します。
正しくシリアライズ/デシリアライズ出来ているかを確認するために、入力データを乱数で生成し、入力データおよび、シリアライズ⇒デシリアライズ後の出力データの内容をダンプして比較できるようにしています。

乱数でのデータ生成およびデータのダンプ処理も、今回紹介したSwallowイディオムおよびIndex Tupleイディオムを用いて実装しています。
詳細はGitHubのコードを参照してください。
機会があれば別途紹介したいと思います。

/* シリアライズテスト */
template <typename T>
void SerializeTest(const std::string& type_name)
{
    /* ログダンプ用文字列ストリーム */
    std::stringstream ss;

    /* 入力データ */
    T in_data{};

    ss << "Serialize Test : " << type_name << std::endl;

    /* 入力データを乱数で生成 */
    cpp_lib::random::RandomDataGenerator::Generate(in_data);

    ss << "-----Before Dump----" << std::endl;
    /* 入力データをダンプ */
    ss << cpp_lib::dump::DataDumper::ToString(type_name, in_data);
    ss << "--------------------" << std::endl;

#if SERIALIZE_MODE == SERIALIZE_MODE_BINARY
    /* バイナリ形式用シリアライザインスタンス生成 */
    cpp_lib::serialization::Serializer<T>& serializer = cpp_lib::serialization::SerializerFactory<T>::CreateBinarySerializer();
#elif SERIALIZE_MODE == SERIALIZE_MODE_TEXT
    /* テキスト形式用シリアライザインスタンス生成 */
    cpp_lib::serialization::Serializer<T>& serializer = cpp_lib::serialization::SerializerFactory<T>::CreateTextSerializer();
#else
#error Invalid Serialize Mode : SERIALIZE_MODE
#endif

    /* アーカイブ */
    cpp_lib::serialization::Archive archive;

    /* シリアライズ */
    serializer.Serialize(in_data, archive);

    /* シリアライズ後のデータサイズ出力 */
    ss << std::endl;
    ss << "Serialized Size : " << archive.GetSize() << std::endl;

    /* テキスト形式の場合はテキストデータをダンプ */
#if SERIALIZE_MODE == SERIALIZE_MODE_TEXT
    ss << "------XML Dump------" << std::endl;
    ss << archive.GetDataPtr();
    ss << "--------------------" << std::endl;
#endif

    ss << std::endl;

    /* 出力データ */
    T out_data{};

    /* アーカイブをデシリアライズ */
    serializer.Deserialize(archive, out_data);

    ss << "-----After Dump----" << std::endl;
    /* 出力データをダンプ */
    ss << cpp_lib::dump::DataDumper::ToString(type_name, out_data);
    ss << "--------------------" << std::endl;;

    /* 文字列ストリームをコンソールに出力 */
    std::cout << ss.str() << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;
}
メイン関数

メイン関数で定義した各ユーザデータ型に対するシリアライズテスト関数を呼び出します。

int main()
{
    /* 各ユーザ定義型に対するシリアライズテスト実行 */
    SerializeTest<app::BoolMessage>("BoolMessage");
    SerializeTest<app::Int8Message>("Int8Message");
    SerializeTest<app::Int16Message>("Int16Message");
    SerializeTest<app::Int32Message>("Int32Message");
    SerializeTest<app::Int64Message>("Int64Message");
    SerializeTest<app::UInt8Message>("UInt8Message");
    SerializeTest<app::UInt16Message>("UInt16Message");
    SerializeTest<app::UInt32Message>("UInt32Message");
    SerializeTest<app::UInt64Message>("UInt64Message");
    SerializeTest<app::Float32Message>("Float32Message");
    SerializeTest<app::Float64Message>("Float64Message");
    SerializeTest<app::StringMessage>("StringMessage");
    SerializeTest<app::ArrayMessage>("ArrayMessage");
    SerializeTest<app::VectorMessage>("VectorMessage");
    SerializeTest<app::MapMessage>("MapMessage");
    SerializeTest<app::EnumMessage1>("EnumMessage1");
    SerializeTest<app::EnumMessage2>("EnumMessage2");
    SerializeTest<app::StrucMessage1>("StrucMessage1");
    SerializeTest<app::StrucMessage2>("StrucMessage2");
    SerializeTest<app::StrucMessage3>("StrucMessage3");

    return 0;
}

実行結果

バイナリ形式、テキスト形式それぞれの実行結果を示します。
乱数でデータを生成しているため、実行するたびに異なる結果となります。

バイナリ形式

Serialize Test : BoolMessage
-----Before Dump----
- BoolMessage : true
--------------------

Serialized Size : 1

-----After Dump----
- BoolMessage : true
--------------------



Serialize Test : Int8Message
-----Before Dump----
- Int8Message : -97
--------------------

Serialized Size : 1

-----After Dump----
- Int8Message : -97
--------------------



Serialize Test : Int16Message
-----Before Dump----
- Int16Message : 557
--------------------

Serialized Size : 2

-----After Dump----
- Int16Message : 557
--------------------



Serialize Test : Int32Message
-----Before Dump----
- Int32Message : -470
--------------------

Serialized Size : 4

-----After Dump----
- Int32Message : -470
--------------------



Serialize Test : Int64Message
-----Before Dump----
- Int64Message : -113
--------------------

Serialized Size : 8

-----After Dump----
- Int64Message : -113
--------------------



Serialize Test : UInt8Message
-----Before Dump----
- UInt8Message : 85
--------------------

Serialized Size : 1

-----After Dump----
- UInt8Message : 85
--------------------



Serialize Test : UInt16Message
-----Before Dump----
- UInt16Message : 247
--------------------

Serialized Size : 2

-----After Dump----
- UInt16Message : 247
--------------------



Serialize Test : UInt32Message
-----Before Dump----
- UInt32Message : 1981
--------------------

Serialized Size : 4

-----After Dump----
- UInt32Message : 1981
--------------------



Serialize Test : UInt64Message
-----Before Dump----
- UInt64Message : 1620
--------------------

Serialized Size : 8

-----After Dump----
- UInt64Message : 1620
--------------------



Serialize Test : Float32Message
-----Before Dump----
- Float32Message : 0.276794
--------------------

Serialized Size : 4

-----After Dump----
- Float32Message : 0.276794
--------------------



Serialize Test : Float64Message
-----Before Dump----
- Float64Message : 921.443368
--------------------

Serialized Size : 8

-----After Dump----
- Float64Message : 921.443368
--------------------



Serialize Test : StringMessage
-----Before Dump----
- StringMessage : NsPtoRr6l
--------------------

Serialized Size : 18

-----After Dump----
- StringMessage : NsPtoRr6l
--------------------



Serialize Test : ArrayMessage
-----Before Dump----
- ArrayMessage
  -377, 887, -930, 571
--------------------

Serialized Size : 24

-----After Dump----
- ArrayMessage
  -377, 887, -930, 571
--------------------



Serialize Test : VectorMessage
-----Before Dump----
- VectorMessage
  886.725027, -888.930458, 653.026661, 600.011359, 17.384446, 923.696587, -418.051060, 560.708495, -860.235959
--------------------

Serialized Size : 80

-----After Dump----
- VectorMessage
  886.725027, -888.930458, 653.026661, 600.011359, 17.384446, 923.696587, -418.051060, 560.708495, -860.235959
--------------------



Serialize Test : MapMessage
-----Before Dump----
- MapMessage
  - [0]
    - first : -972
    - second : -76.153916
  - [1]
    - first : -786
    - second : -671.554764
  - [2]
    - first : -722
    - second : -101.852106
  - [3]
    - first : -698
    - second : -818.168871
  - [4]
    - first : -415
    - second : 912.755329
  - [5]
    - first : -242
    - second : -645.595839
  - [6]
    - first : 39
    - second : -959.489234
  - [7]
    - first : 369
    - second : -821.034684
  - [8]
    - first : 428
    - second : 79.652055
  - [9]
    - first : 597
    - second : 808.364866
  - [10]
    - first : 876
    - second : 794.861590
--------------------

Serialized Size : 140

-----After Dump----
- MapMessage
  - [0]
    - first : -972
    - second : -76.153916
  - [1]
    - first : -786
    - second : -671.554764
  - [2]
    - first : -722
    - second : -101.852106
  - [3]
    - first : -698
    - second : -818.168871
  - [4]
    - first : -415
    - second : 912.755329
  - [5]
    - first : -242
    - second : -645.595839
  - [6]
    - first : 39
    - second : -959.489234
  - [7]
    - first : 369
    - second : -821.034684
  - [8]
    - first : 428
    - second : 79.652055
  - [9]
    - first : 597
    - second : 808.364866
  - [10]
    - first : 876
    - second : 794.861590
--------------------



Serialize Test : EnumMessage1
-----Before Dump----
- EnumMessage1 : 1
--------------------

Serialized Size : 4

-----After Dump----
- EnumMessage1 : 1
--------------------



Serialize Test : EnumMessage2
-----Before Dump----
- EnumMessage2 : 2
--------------------

Serialized Size : 4

-----After Dump----
- EnumMessage2 : 2
--------------------



Serialize Test : StrucMessage1
-----Before Dump----
- StrucMessage1
  - bool_value : true
  - uint_value : 345
  - float_value : -412.287720
--------------------

Serialized Size : 9

-----After Dump----
- StrucMessage1
  - bool_value : true
  - uint_value : 345
  - float_value : -412.287720
--------------------



Serialize Test : StrucMessage2
-----Before Dump----
- StrucMessage2
  - float_array
    -945.414795, 771.739014, 445.108154, -849.261414, 124.613403, 327.225830, 341.188965, 99.228516
  - ulong_vec
    967, 415, 1863, 1580, 864, 1263, 1044, 173, 1742, 63, 1885, 247, 724, 1333, 378, 1391, 424, 1067, 617, 1894, 1574, 926, 1232, 1594, 1023, 746, 1857, 22, 1394, 1710
--------------------

Serialized Size : 288

-----After Dump----
- StrucMessage2
  - float_array
    -945.414795, 771.739014, 445.108154, -849.261414, 124.613403, 327.225830, 341.188965, 99.228516
  - ulong_vec
    967, 415, 1863, 1580, 864, 1263, 1044, 173, 1742, 63, 1885, 247, 724, 1333, 378, 1391, 424, 1067, 617, 1894, 1574, 926, 1232, 1594, 1023, 746, 1857, 22, 1394, 1710
--------------------



Serialize Test : StrucMessage3
-----Before Dump----
- StrucMessage3
  - string_value : neb5hpDH
  - enum_str_map
    - [0]
      - first : 1
      - second : tPhNWivV6ywsRz8
--------------------

Serialized Size : 53

-----After Dump----
- StrucMessage3
  - string_value : neb5hpDH
  - enum_str_map
    - [0]
      - first : 1
      - second : tPhNWivV6ywsRz8
--------------------

テキスト形式

Serialize Test : BoolMessage
-----Before Dump----
- BoolMessage : true
--------------------

Serialized Size : 24
------XML Dump------
{
    "root": "true"
}
--------------------

-----After Dump----
- BoolMessage : true
--------------------



Serialize Test : Int8Message
-----Before Dump----
- Int8Message : -66
--------------------

Serialized Size : 23
------XML Dump------
{
    "root": "-66"
}
--------------------

-----After Dump----
- Int8Message : -66
--------------------



Serialize Test : Int16Message
-----Before Dump----
- Int16Message : -660
--------------------

Serialized Size : 24
------XML Dump------
{
    "root": "-660"
}
--------------------

-----After Dump----
- Int16Message : -660
--------------------



Serialize Test : Int32Message
-----Before Dump----
- Int32Message : -450
--------------------

Serialized Size : 24
------XML Dump------
{
    "root": "-450"
}
--------------------

-----After Dump----
- Int32Message : -450
--------------------



Serialize Test : Int64Message
-----Before Dump----
- Int64Message : 968
--------------------

Serialized Size : 23
------XML Dump------
{
    "root": "968"
}
--------------------

-----After Dump----
- Int64Message : 968
--------------------



Serialize Test : UInt8Message
-----Before Dump----
- UInt8Message : 130
--------------------

Serialized Size : 23
------XML Dump------
{
    "root": "130"
}
--------------------

-----After Dump----
- UInt8Message : 130
--------------------



Serialize Test : UInt16Message
-----Before Dump----
- UInt16Message : 1021
--------------------

Serialized Size : 24
------XML Dump------
{
    "root": "1021"
}
--------------------

-----After Dump----
- UInt16Message : 1021
--------------------



Serialize Test : UInt32Message
-----Before Dump----
- UInt32Message : 451
--------------------

Serialized Size : 23
------XML Dump------
{
    "root": "451"
}
--------------------

-----After Dump----
- UInt32Message : 451
--------------------



Serialize Test : UInt64Message
-----Before Dump----
- UInt64Message : 569
--------------------

Serialized Size : 23
------XML Dump------
{
    "root": "569"
}
--------------------

-----After Dump----
- UInt64Message : 569
--------------------



Serialize Test : Float32Message
-----Before Dump----
- Float32Message : 131.467041
--------------------

Serialized Size : 30
------XML Dump------
{
    "root": "0x43037790"
}
--------------------

-----After Dump----
- Float32Message : 131.467041
--------------------



Serialize Test : Float64Message
-----Before Dump----
- Float64Message : 676.831881
--------------------

Serialized Size : 38
------XML Dump------
{
    "root": "0x408526a7b15eee50"
}
--------------------

-----After Dump----
- Float64Message : 676.831881
--------------------



Serialize Test : StringMessage
-----Before Dump----
- StringMessage : r4LhVs
--------------------

Serialized Size : 26
------XML Dump------
{
    "root": "r4LhVs"
}
--------------------

-----After Dump----
- StringMessage : r4LhVs
--------------------



Serialize Test : ArrayMessage
-----Before Dump----
- ArrayMessage
  711, 671, 775, -248
--------------------

Serialized Size : 117
------XML Dump------
{
    "root": {
        "item": "711",
        "item": "671",
        "item": "775",
        "item": "-248"
    }
}
--------------------

-----After Dump----
- ArrayMessage
  711, 671, 775, -248
--------------------



Serialize Test : VectorMessage
-----Before Dump----
- VectorMessage
  -918.270491, 567.724274, -829.875955, -347.300835
--------------------

Serialized Size : 176
------XML Dump------
{
    "root": {
        "item": "0xc08cb229f73fc5ba",
        "item": "0x4081bdcb5028a146",
        "item": "0xc089ef01f46f728d",
        "item": "0xc075b4d038311c5c"
    }
}
--------------------

-----After Dump----
- VectorMessage
  -918.270491, 567.724274, -829.875955, -347.300835
--------------------



Serialize Test : MapMessage
-----Before Dump----
- MapMessage
  - [0]
    - first : -572
    - second : 534.903451
  - [1]
    - first : -454
    - second : 717.369277
  - [2]
    - first : -344
    - second : -404.941074
  - [3]
    - first : -207
    - second : -824.382721
  - [4]
    - first : -170
    - second : 266.270653
  - [5]
    - first : 64
    - second : -5.214582
  - [6]
    - first : 178
    - second : 705.179553
  - [7]
    - first : 233
    - second : -208.877004
  - [8]
    - first : 545
    - second : 897.333639
  - [9]
    - first : 656
    - second : 875.125018
--------------------

Serialized Size : 1028
------XML Dump------
{
    "root": {
        "item": {
            "first": "-572",
            "second": "0x4080b73a445b0786"
        },
        "item": {
            "first": "-454",
            "second": "0x40866af4476c006c"
        },
        "item": {
            "first": "-344",
            "second": "0xc0794f0ea393ca94"
        },
        "item": {
            "first": "-207",
            "second": "0xc089c30fcff65380"
        },
        "item": {
            "first": "-170",
            "second": "0x4070a454981c5d8c"
        },
        "item": {
            "first": "64",
            "second": "0xc014dbbb4f84c080"
        },
        "item": {
            "first": "178",
            "second": "0x4086096fb9bb75ee"
        },
        "item": {
            "first": "233",
            "second": "0xc06a1c1069c4df70"
        },
        "item": {
            "first": "545",
            "second": "0x408c0aab4aab4776"
        },
        "item": {
            "first": "656",
            "second": "0x408b590009a903e0"
        }
    }
}
--------------------

-----After Dump----
- MapMessage
  - [0]
    - first : -572
    - second : 534.903451
  - [1]
    - first : -454
    - second : 717.369277
  - [2]
    - first : -344
    - second : -404.941074
  - [3]
    - first : -207
    - second : -824.382721
  - [4]
    - first : -170
    - second : 266.270653
  - [5]
    - first : 64
    - second : -5.214582
  - [6]
    - first : 178
    - second : 705.179553
  - [7]
    - first : 233
    - second : -208.877004
  - [8]
    - first : 545
    - second : 897.333639
  - [9]
    - first : 656
    - second : 875.125018
--------------------



Serialize Test : EnumMessage1
-----Before Dump----
- EnumMessage1 : 1
--------------------

Serialized Size : 21
------XML Dump------
{
    "root": "1"
}
--------------------

-----After Dump----
- EnumMessage1 : 1
--------------------



Serialize Test : EnumMessage2
-----Before Dump----
- EnumMessage2 : 3
--------------------

Serialized Size : 21
------XML Dump------
{
    "root": "3"
}
--------------------

-----After Dump----
- EnumMessage2 : 3
--------------------



Serialize Test : StrucMessage1
-----Before Dump----
- StrucMessage1
  - bool_value : true
  - uint_value : 1306
  - float_value : -944.752625
--------------------

Serialized Size : 121
------XML Dump------
{
    "root": {
        "bool_value": "true",
        "uint_value": "1306",
        "float_value": "0xc46c302b"
    }
}
--------------------

-----After Dump----
- StrucMessage1
  - bool_value : true
  - uint_value : 1306
  - float_value : -944.752625
--------------------



Serialize Test : StrucMessage2
-----Before Dump----
- StrucMessage2
  - float_array
    737.617188, 87.140381, -413.917358, 613.480347, 576.777954, 985.471558, -609.963989, -687.853149
  - ulong_vec
    1334, 1720, 1684, 935, 1735, 1085, 314, 977, 403, 1725, 392, 517, 1157
--------------------

Serialized Size : 722
------XML Dump------
{
    "root": {
        "float_array": {
            "item": "0x44386780",
            "item": "0x42ae47e0",
            "item": "0xc3cef56c",
            "item": "0x44195ebe",
            "item": "0x441031ca",
            "item": "0x44765e2e",
            "item": "0xc4187db2",
            "item": "0xc42bf69a"
        },
        "ulong_vec": {
            "item": "1334",
            "item": "1720",
            "item": "1684",
            "item": "935",
            "item": "1735",
            "item": "1085",
            "item": "314",
            "item": "977",
            "item": "403",
            "item": "1725",
            "item": "392",
            "item": "517",
            "item": "1157"
        }
    }
}
--------------------

-----After Dump----
- StrucMessage2
  - float_array
    737.617188, 87.140381, -413.917358, 613.480347, 576.777954, 985.471558, -609.963989, -687.853149
  - ulong_vec
    1334, 1720, 1684, 935, 1735, 1085, 314, 977, 403, 1725, 392, 517, 1157
--------------------



Serialize Test : StrucMessage3
-----Before Dump----
- StrucMessage3
  - string_value : 5Gx0tVhsKrhvw
  - enum_str_map
    - [0]
      - first : 1
      - second : oB
    - [1]
      - first : 2
      - second : kr7k2
--------------------

Serialized Size : 300
------XML Dump------
{
    "root": {
        "string_value": "5Gx0tVhsKrhvw",
        "enum_str_map": {
            "item": {
                "first": "1",
                "second": "oB"
            },
            "item": {
                "first": "2",
                "second": "kr7k2"
            }
        }
    }
}
--------------------

-----After Dump----
- StrucMessage3
  - string_value : 5Gx0tVhsKrhvw
  - enum_str_map
    - [0]
      - first : 1
      - second : oB
    - [1]
      - first : 2
      - second : kr7k2
--------------------

あとがき

今回は任意のデータ型(クラス/構造体)に対してシリアライズできるようにする方法について説明しました。
次回はおまけとして、SwallowイディオムおよびIndex Tupleイディオムを用いた、乱数でのデータ生成およびデータのダンプ処理について説明したいと思います。