Theolizer  Version.1.2.0
serializer for C++ / Do you want to update your classes easily ?
使用方法(全体)

ここでは、Theolizerの使い方を説明します。

TheolizerはAPIの機能テストをできるだけ自動化してます。
そして、APIの機能テストは詳細仕様を規定することでもあります。複雑なプログラムでは文書として読み取ることは困難ですが、単純なプログラムであれば、文書としての機能を果たせるのではないかと考えています。

そこで、各機能についてそれをテストするための多数のテスト群の内、代表的なものを使って説明し、詳細テストの関連部分のソースも提示します。できるだけ読み取るのに苦労しない形式でプログラムを記述し、詳細仕様書として有用であることを目指します。

まず、1~3節で全体的な説明を行い、4節以降で各機能について説明します。


1.名前の付け方

TheolizerのAPIは名前空間に入れています。また、マクロは決まったプリフィクスを付けています。 少し意味を持たせていますので説明します。

1-1.名前空間

ほぼ全てのシンボルを theolizer 名前空間へ入れています。
一部、入れると実装が難しいものについては、シンボルに Theolizer を含みます。
これにより既存のコードと被ることはまずない筈です。

次に、内部的に使用するシンボルは internal 名前空間へ入れています。
これらのシンボルが付けられたクラスや関数等は、Theolizerのアップデート時、上位互換性を考慮しませんので使用しないようお願いします。

1-2.マクロ名

全てのマクロは THEOLIZER_ で始めています。
これにより既存のコードと被ることはまずない筈です。

次に、内部的に使用するマクロは、 THEOLIZER_INTERNAL_ で始めています。
また、Theolizerが自動生成するマクロを、 THEOLIZER_GENERATED_ で始めています。
これらのマクロは、Theolizerのアップデート時、上位互換性を考慮しませんので使用しないようお願いします。

2.基本的な使い方

Theolizerをインストールした後、あなたのデータをTheolizerでシリアライズするために、あなたのプログラムを下記の順序を守るようにして下さい。

  1. Theolizerヘッダをインクルード
  2. シリアライズするクラスとenum型の定義
  3. Theolizerの自動生成ファイルをインクルード
  4. シリアライズ処理

2-1.Theolizerヘッダをインクルード

一部例外(*1)はありますが原則として、シリアライズするクラスとenum型の定義 前にシリアライザのヘッダをインクルードして下さい。

Json形式シリアライザ・ヘッダのインクルードと型定義の例:(source/samples/example/example.cpp)

#include "ユーザ定義.h"
(*1) 例外:非侵入型(1-2.シリアライズ可能な型についての補足事項)のクラスやenum型の非侵入型完全自動については、シリアライザのヘッダをインクルードする前でも定義できます。

現在、サポートしているシリアライザはJson形式、独自Binary形式、Xml形式、メモリ内専用のFast形式の4種類です。 それぞれ、下記ヘッダをインクールドして下さい。

形式インクルードするヘッダ注意事項
Json形式<theolizer/serializer_json.h>fstreamはテキスト・モードでオープンする
独自Binary形式<theolizer/serializer_binary.h>fstreamはバイナリ・モード(std::ios_base::binary)でオープンする
Xml形式<theolizer/serializer_xml.h>fstreamはテキスト・モードでオープンする
メモリ内専用Fast形式上記のどちから、もしくは、<theolizer/serializer.h>fstreamはバイナリ・モード(std::ios_base::binary)でオープンする


2-2.シリアライズするクラスとenum型の定義

シリアライズするクラスとenum型の定義後に、Theolizerの自動生成ファイルをインスクルード します。この順序に例外はありません。

なお、シリアライズ対象の型を含まないヘッダ・ファイルは、Theolizerに関する順序制限はありません。

2-3.Theolizerの自動生成ファイルをインクルード

4.Theolizerの仕組み で説明したようにTheolizerはシリアライズに必要なソース・コードを自動生成します。
このファイルはコンパイル単位(通常は.cppファイル)毎に生成され、当該.cppファイルと同じフォルダへ自動的に生成されます。
Theolizerは、バージョンを上げた時に古いクラス定義やenum型定義をここに残します。これにより古いシリアライズ・データを回復できます。
そこで、このファイルをお使いのバージョン管理システム(gitやsvn等)へ登録することをお勧めします。

自動生成するファイルのファイル名は、そのコンパイル単位のファイル名に".theolzier.hpp"を繋げたものです。
例えば、example.cpp の場合は、example.cpp.theolizer.hpp となります。

クラス定義と*.theolizer.hppインクルード指定例:(source/samples/example/example.cpp)

#include <iostream>
#include <fstream>
#include <string>
struct Foo
{
std::string name;
int age;
};
#include "example.cpp.theolizer.hpp" // Theolizer自動生成先

この例では、example.cppの頭でクラスを定義していますが、example.hで定義し、#include "example.h" にてインクルードするのが一般的です。

2-4.シリアライズ処理

シリアライズは下記の3つで行います。

  • シリアライザ・インスタンスの生成
  • シリアライズ処理要求(シリアライズするインスタンスを指定する)
  • シリアライザ・インスタンスの破棄

2-4-1.シリアライザ・インスタンスの生成

その際、シリアライズ先のデータ・ストリームを指定します。ファイル・ストリームやTCP/IPストリームを指定して下さい。
保存や送信時はstd::ostreamを、回復や受信時はstd::istreamを与えて下さい。

2-4-2.シリアライズ処理要求

下記マクロでシリアライズします。保存用シリアライザを指定すると保存、回復用シリアライザを指定すると回復動作となります。
これはいつくでも記述して良いです。

THEOLIZER_PROCESS(dSerializer, dInstance)

  • dSerializer : シリアライザのインスタンスを指定します。
  • dInstance : 保存/回復するインスタンスを指定します。

dInstanceを保存/回復します。
ポインタ型を指定した場合は、アドレス回復のためにポイント先のオブジェクト追跡を行います。

THEOLIZER_PROCESS_POINTEE(dSerializer, dInstance)

  • dSerializer : シリアライザのインスタンスを指定します。
  • dInstance : 保存/回復する被ポインタでもあるインスタンスを指定します。

THEOLIZER_PROCESS_OWNER(dSerializer, dInstance)

  • dSerializer : シリアライザのインスタンスを指定します。
  • dInstance : 保存/回復する所有権を持つインスタンスへのポインタを指定します。
参照
オブジェクト追跡について
このようにシリアライザを問わず、全て同じマクロでシリアライズ処理できます。

2-4-3.シリアライザ・インスタンスの破棄

最後にシリアライザ・インスタンスを破棄することでシリアライズ処理を完了します。
生成時に例外発生を禁止していた場合に、エラー状態をリセットしないまま破棄すると、プロセスをアボートします。これはエラー状態の見逃しを回避するための仕様です。
例外発生を禁止している場合は、破棄する前には必ずエラー情報をチェクした上で、エラー状態をリセットして下さい。
具体的手順はエラー報告 にて説明します。

ファイルへの保存例:(source/samples/example/example.cpp)

// 保存
{
Foo foo;
foo.name="Taro Yamada";
foo.age=22;
std::ofstream ofs("sample.txt");
theolizer::JsonOSerializer<> jos(ofs); // シリアライザを生成
THEOLIZER_PROCESS(jos, foo); // ファイルへfooを保存
}

ファイルからの回復例:(source/samples/example/example.cpp)

// 回復
{
Foo foo;
std::ifstream ifs("sample.txt");
theolizer::JsonISerializer<> jis(ifs); // デシリアライザを生成
THEOLIZER_PROCESS(jis, foo); // ファイルからfooを回復
THEOLIZER_PROCESS(jos, foo); // 回復結果の簡易表示
}


3.各シリアライザの説明

現在、サポートしているシリアライザはJson形式、独自Binary形式、メモリ内専用のFast形式の3種類です。
ここではそれぞれの使い方を説明します。

3-1.共通事項

全てのシリアライザについて共通な事項について説明します。

3-1-1.型チェック・モード

Theolizerのシリアライザは回復時に型が一致していることをチェックできます。
その方法としてシリライズ・データ内に「型名を保存する方法」と「型に割り当てたインデックス番号(TypeIndex)を保存する方法」の2種類を用意しています。

theolizer::CheckMode

列挙値意味
NoTypeCheck型チェック無し
TypeCheck型名による型チェック
TypeCheckByIndexTypeIndexによる型チェック

NoTypeCheckは型情報をシリライズ・データに含みませんのでデータ量が少ない場合の効率は良いです。しかし、メンバ名をヘッダではなくデータ側に含むためデータ量が多くなると効率は悪化します。
TypeCheckはテキスト型の場合、データを目視確認し易いです。データ量が少ない時の効率はNoTypeCheckの次に良いです。
TypeCheckByIndexはデータ量が多い時は3種のCheckModeの中で最大の効率を発揮します。

型情報等の管理データを下記のように記録します。

  • シリアライズ・データのヘッダ部
    NoTypeCheck:型情報を記録しません。
    TypeCheck:クラスについて、各メンバのメンバ名(名前対応時)と型名を記録します。
    TypeCheckByIndex:全ての型について、TypeIndexに対応する型名を記録します。 更にクラスについては、各メンバのメンバ名(名前対応時)とTypeIndexを記録します。

  • シリアライズ・データの各データ部
    NoTypeCheck:クラスについて、各メンバのデータとメンバ名(名前対応時)をセットで記録します。
    TypeCheck:THEOLIZER_PROCESS()マクロで指定したデータと共にその型名を記録します。
    TypeCheckByIndex:THEOLIZER_PROCESS()マクロで指定したデータと共にそのTypeIndexを記録します。

回復時に回復先の変数の型と上記の情報と照らし合わせることで型チェックを行います。

3-1-2.メンバ関数

幾つかの制御のため、各シリアライザは下記のメンバ関数を公開しています。

メンバ名意味
unsigned getGlobalVersionNo() const;処理中のグローバル・バージョン番号を返却します。
void clearTracking() ;オブジェクト追跡の区切り(オブジェクト追跡について 参照)
bool getRequireClearTracking() const;clearTracking()が必要な時trueを返却します。
theolizer::CheckMode getCheckMode() const;現在のCheckModeを返却します。
void setCharIsMultiByte();Windowsにおいて、EncodedStringがtrueのシリアライザにおいて
std::string変数の文字エンコードをMultiByte文字列として処理するかどうかを指定します。
theolizer::ErrorInfo const& getErrorInfo() const;エラー情報を返却します。
bool isError() const;エラーが発生している時trueを返却します。
void resetError();エラー状態を解除します。(3.Theolizerで検出したエラーの通知方法 参照)

3-1-3.プロパティ

各シリアライザは、その属性をプロバティとして提供しています。

プロバティ名意味JsonBinaryFast
IsSaver保存処理用ならtrue、回復処理用ならfalse
EncodedString文字列のエンコードを処理するtruefalsefalse
SupportModifyingクラスやenum型の定義変更に対応するtruetruefalse
BinaryOpenfstreamをstd::ios_base::binaryモードでオープンする必要がある<td>falsetruetrue

プロパテイは以下の構文で受け取ります。

bool property = <シリアライザ・クラス>::hasProperty(theolizer::Property::<プロパティ名>);


3-1-4.EncodedStringについて補足

テキスト型のシリアライザは、文字列を読める形式で記録されます。
そのため、例えばJsonフォーマットはデフォルトではUTF-8でエンコードすると規定されています。
そして、C++の各std::stringシリーズもUnicodeでエンコードされることが期待されます。(そうしないことも可能です。)

そこで、TheolizerのEncodedStringプロパティをサポートしたシリアライザ(現在はJsonのみ)は、下記のようにstd::stringシリーズを処理します。

  • setCharIsMultiByte(false)(デフォルト)
    全ての文字列を特定のUnicodeエンコードで記録する。(JsonシリアライザはUTF-8)
    std::stringはUnicodeでエンコードされているものとして処理する。(そのまま保存/回復する。)
    以下は全てUnicodeへ変換して保存し、読み出し後当該エンコードへ変換する。
    std::wstringはUTF-16かUTF-32(wchar_tのサイズによる)でエンコードされているものとして処理する。
    std::u16stringはUTF-16でエンコードされているものとして処理する。
    std::u32stringはUTF-32でエンコードされているものとして処理する。

  • setCharIsMultiByte(true)
    std::stringはMultiByte文字列としてエンコードされているものとして処理する。(Unicodeへ変換して保存/回復する。)
    その他は、デフォルトと同じ。

つまり、例えば、UTF-8でエンコードされたstd::string型の変数を保存し、それをUTF-16でエンコードされたstd::u16string型の変数へ回復できます。

サンプル・ソース(source/reference_and_test/basic/test_basic_process.cpp)

#if defined(_WIN32)
// CP932で"[こんにちは。]"
const char gHelloCP932[] = "\x5B\x82\xB1\x82\xF1\x82\xC9\x82\xBF\x82\xCD\x81\x42\x5D";
#else
// UTF-8で"[こんにちは。]" 非Windows用
const char gHelloCP932[] = u8"[こんにちは。]";
#endif
void tutoriseBasic()
{
//----------------------------------------------------------------------------
// 保存
//----------------------------------------------------------------------------
{
std::ofstream aStream("tutorise_basic.json");
theolizer::JsonOSerializer<> aSerializer(aStream);
// ---<<< Shift-JISコードのテスト >>>---
// MultiByte指定
aSerializer.setCharIsMultiByte(true);
std::string aString = gHelloCP932;
THEOLIZER_PROCESS(aSerializer, aString);
// UTF-8へ戻す
aSerializer.setCharIsMultiByte(false);
aString = u8"ユニコードUTF-8";
THEOLIZER_PROCESS(aSerializer, aString);
// ---<<< 文字列互換テスト >>>---
// charをwchar_t, char16_t, char32_tへ回復
THEOLIZER_PROCESS(aSerializer, aString);
THEOLIZER_PROCESS(aSerializer, aString);
THEOLIZER_PROCESS(aSerializer, aString);
}
//----------------------------------------------------------------------------
// 回復
//----------------------------------------------------------------------------
{
std::ifstream aStream("tutorise_basic.json");
theolizer::JsonISerializer<> aSerializer(aStream);
// ---<<< Shift-JISコードのテスト >>>---
// MultiByte指定
aSerializer.setCharIsMultiByte(true);
std::string aString = "";
THEOLIZER_PROCESS(aSerializer, aString);
THEOLIZER_EQUAL(aString, gHelloCP932);
// UTF-8へ戻す
aSerializer.setCharIsMultiByte(false);
aString = "";
THEOLIZER_PROCESS(aSerializer, aString);
THEOLIZER_EQUAL(aString, u8"ユニコードUTF-8");
// ---<<< 文字列互換テスト >>>---
std::wstring aWString;
std::u16string aU16String;
std::u32string aU32String;
// charをwchar_t, char16_t, char32_tへ回復
THEOLIZER_PROCESS(aSerializer, aWString);
THEOLIZER_EQUAL(aWString, L"ユニコードUTF-8");
THEOLIZER_PROCESS(aSerializer, aU16String);
THEOLIZER_EQUAL(aU16String, u"ユニコードUTF-8");
THEOLIZER_PROCESS(aSerializer, aU32String);
THEOLIZER_EQUAL(aU32String, U"ユニコードUTF-8");
}
}

3-1-5.BinaryOpenについて補足

バイナリ形式のシリアライザをfstreamで用いる時は、必ずバイナリ・モード(std::ios_base::binary)でfstreamをオープンする必要があります。
Windowsの場合、fstreamがテキスト・モードでオープンされ、ストリームへ数値26(0x1A)が出力されると、0x1AはWindowsではEOFコードなので回復時にEOFエラーになります。また、Windowsで数値10(0x0A)が出力されるとCR LFへ展開されてしまい、適切に回復できません。
このような事態をさけるため、Theolizer側でエラーにしたいのですが、iostreamではそのオープン・モードを確認できないためチェックが困難なのです。

バイナリ形式のシリアライザは、hasProperty(theolzier::Property::BinaryOpen)がtrueになります。 また、各シリアライザはstd::ios_base::openmode型の静的定数kOpenModeを定義しています。 バイナリ形式のシリアライザではstd::ios_base::binary、それ以外のシリアライザで 0 となっています。

サンプル・ソース(source/reference_and_test/basic/test_basic_process.cpp)

// Json
{
std::ofstream aStream("openmode_json.json", theolizer::JsonOSerializer<>::kOpenMode);
theolizer::JsonOSerializer<> aSerializer(aStream);
int aInt=0x1a;
THEOLIZER_PROCESS(aSerializer, aInt);
}
// Binary
{
std::ofstream aStream("openmode_binary.bin", theolizer::BinaryOSerializer<>::kOpenMode);
theolizer::BinaryOSerializer<> aSerializer(aStream);
int aInt=0x1a;
THEOLIZER_PROCESS(aSerializer, aInt);
}


3-2.Json形式(JsonSerializer)

Json形式でシリアライズする場合は、theolizer/serializer_json.hをインクルードして下さい。

3-2-1.保存用JsonSerialzier

通常のコンストラクタ

JsonOSerializer
(
std::ostream& iOStream,
unsigned iGlobalVersionNo=kLastGlobalVersionNo,
CheckMode iCheckMode=CheckMode::NoTypeCheck,
bool iNoPrettyPrint=false,
bool iNoThrowException=false
);

GlobalVersionNo以外のオプションを指定するコンストラクタ

JsonOSerializer
(
std::ostream& iOStream,
CheckMode iCheckMode,
bool iNoPrettyPrint=false,
bool iNoThrowException=false
);
パラメータ名意味
iOStream出力先のストリーム(ofstreamはテキスト・モードでオープンして下さい)
iGlobalVersionNo保存するグローバル・バージョン番号(省略時は最新版)
iCheckMode型チェック・モード(省略時はNoTypeCheck)
iNoPrettyPrint整形出力しない時true(省略時はfalse)
iNoThrowException例外禁止時true(省略時はfalse)

専用継承関数

void setCharIsMultiByte(bool iCharIsMultiByte);
iCharIsMultiByte=trueの時、std::stringをWindowsマルチ・バイト文字コードとして取り扱います。
コンストラクト直後はiCharIsMultiByte=falseです。
Windowsのみ機能します。それ以外のOSではUTF-8のままです。

3-2-2.回復用JsonSerialzier

コンストラクタ

JsonISerializer
(
std::istream& iIStream,
bool iNoThrowException=false
);
パラメータ名意味
iIStream入力元のストリーム(ofstreamならテキスト・モードでオープンして下さい)
iNoThrowException例外禁止時true(省略時はfalse)

専用継承関数

void setCharIsMultiByte(bool iCharIsMultiByte);
iCharIsMultiByte=trueの時、std::stringをWindowsマルチ・バイト文字コードとして取り扱います。
コンストラクト直後はiCharIsMultiByte=falseです。
Windowsのみ機能します。それ以外のOSではUTF-8のままです。


3-3.独自Binary形式(BinarySerializer)

独自Binary形式でシリアライズする場合は、theolizer/serializer_binary.hをインクルードして下さい。

Big Endianでエンコードします。Little Endianの処理系の場合Big Endianとの間で自動変換します。
整数型は値を表現するために十分なバイト数で保存します。例えば、long long型でも値が10ならタグと値で合わせて2バイトで保存します。
浮動小数点型はIEEE754フォーマットのみサポートします。バイト単位でEndian変換します。
long doubleは「radix==2、digits==64、max_exponent==16384」の80ビット拡張精度形式である処理系(gcc)とbinary64である処理系(msvc)に対応しています。
文字コードの変換は行いません。Endianのみ変換してシリアライズします。

3-3-1.保存用BinarySerialzier

通常のコンストラクタ

BinaryOSerializer
(
std::ostream& iOStream,
unsigned iGlobalVersionNo=kLastGlobalVersionNo,
CheckMode iCheckMode=CheckMode::NoTypeCheck,
bool iNoThrowException=false
);

GlobalVersionNo以外のオプションを指定するコンストラクタ

BinaryOSerializer
(
std::ostream& iOStream,
CheckMode iCheckMode,
bool iNoThrowException=false
);
パラメータ名意味
iOStream出力先のストリーム(ofstreamはstd::ios_base::binaryでオープンして下さい)
iGlobalVersionNo保存するグローバル・バージョン番号(省略時は最新版)
iCheckMode型チェック・モード(省略時はNoTypeCheck)
iNoThrowException例外禁止時true(省略時はfalse)

3-3-2.回復用BinarySerialzier

通常のコンストラクタ

BinaryISerializer
(
std::istream& iIStream,
bool iNoThrowException=false
);
パラメータ名意味
iIStream入力元のストリーム(ofstreamはstd::ios_base::binaryでオープンして下さい)
iNoThrowException例外禁止時true(省略時はfalse)


3-4.Xml形式(XmlSerializer)

3-4-1.仕様

Xml形式でシリアライズする場合は、theolizer/serializer_xml.hをインクルードして下さい。

名前空間
名前空間としてhttps://theolizer.com/theoride/xml-1を使います。(特に何も置いていません。識別用だけです。) 現時点では下記要素名と属性名を定義しています。(接頭辞はthを用いていますので接頭辞付きで表記します。)

識別子要素名/
属性名
c++の型 or 意味
th:bool要素名bool 型
th:int8要素名int8_t 型
th:int16要素名int16_t 型
th:int32要素名int32_t 型
th:int64要素名int64_t 型
th:unit8要素名unit8_t 型
th:uint16要素名uint16_t 型
th:uint32要素名uint32_t 型
th:uint64要素名uint64_t 型
th:float32要素名IEEE754のbinary32型
th:float64要素名IEEE754のbinary64型
th:float80要素名IEEE754の拡張型(仮数部64bit、指数部15bit)
th:string要素名UTF-8文字列
th:Array要素名配列(ネストすることで多次元配列を表現する)
th:Pointer要素名ポインタ型(1.オブジェクト追跡の使い方 参照)
th:Pointee要素名被ポインタ(1.オブジェクト追跡の使い方 参照)
th:OwnerPointer要素名オーナ-・ポインタ(1.オブジェクト追跡の使い方 参照)
th:Reference要素名動的ポリモーフィズムされた参照(1-2-3.参照について 参照)
th:Type属性名ポインタの指す先の型
th:ObjectId属性名ポインタ or 被ポインタのオブジェクトID
(2-4.同じ領域を複数回シリアライズする時の動作について特記事項 参照)
th:MemberName属性名メンバ変数名
th:GlobalVersionNo属性名グローバル・バージョン番号(ヘッダにのみ出現する)
ユーザ・クラス名要素名ユーザ定義のクラス名
ユーザenum型名要素名ユーザ定義のenum型名

各数値型(intやdouble等)は処理系に毎に異なりますが、適切なth:int??, th:float??名が割り当てられます。
std::numelic_limitsのis_signed, digits, max_exponentを用いて振り分けています。

型チェックと要素名の使い方について
Xmlフォーマットを用いるシリアライザは、要素名としてメンバ変数名を用いるものが多いですが、当Xmlシリアライザは要素名として型名を用いることにしました。

  1. Theolizerとしての要件
    Theolizerは、クラスのメンバ変数を回復する際、名前対応と順序対応の2つを用意しています。「新しい」クラスは変更が予想されるため名前で対応することで変更を容易にしています。「枯れた」クラスは名前を保存する記憶スペースを省略し効率を上げます。Xmlの場合、重複する文字列の保存が多いため後者のメリットはあまり効果的ではありませんが、他のシリアライザと同等の扱いとしています。
    従って、クラスのメンバ変数の名前をシリアライズしないケースがあります。
  2. トップ・レベルの変数名や配列の各要素、ヒープ上のオブジェクト
    トップ・レベルの(プログラマが直接保存/回復を指示する)変数は、保存時と回復時の変数名が一致しない場合も少なくないと思います。また、C++の場合、配列全体に名前は付いている場合が多いですが、配列の各要素には名前がありません。更に、ヒープ上のオブジェクトにはそもそも名前がありません。ポインタには名前がありますが、オブジェクト自身には名前がありません。
    これらの名前を付けたくないものや名前の無いものは、変数名をシリアライズしない方が自然です。
  3. C++は静的型付け言語
    ですので、変数には必ず型が存在し、型の異なる変数への回復をエラーチェックすると好ましいです。

以上に理由により、要素名(Xml要素が必ず必要とする名前)を「型名」とし、回復時に必ず型チェックするようにしました。

従って、CheckModeパラメータは指定しません。

3-4-2.保存用XmlSerialzier

通常のコンストラクタ

XmlOSerializer
(
std::ostream& iOStream,
unsigned iGlobalVersionNo=kLastGlobalVersionNo,
bool iNoPrettyPrint=false,
bool iNoThrowException=false
);

GlobalVersionNo以外のオプションを指定するコンストラクタ

XmlOSerializer
(
std::ostream& iOStream,
bool iNoPrettyPrint=false,
bool iNoThrowException=false
);
パラメータ名意味
iOStream出力先のストリーム(ofstreamはstd::ios_base::binaryでオープンして下さい)
iGlobalVersionNo保存するグローバル・バージョン番号(省略時は最新版)
iNoPrettyPrint整形出力しない時true(省略時はfalse)
iNoThrowException例外禁止時true(省略時はfalse)

3-4-3.回復用XmlSerialzier

コンストラクタ

XmlISerializer
(
std::istream& iIStream,
bool iNoThrowException=false
);
パラメータ名意味
iIStream入力元のストリーム(ofstreamはstd::ios_base::binaryでオープンして下さい)
iNoThrowException例外禁止時true(省略時はfalse)

3-4-4.使い方

サンプルのsource/samples/example/example.cppをxml用に修正した場合の出力例です。

#include <iostream>
#include <fstream>
#include <string>
struct Foo
{
std::string name;
int age;
};
#include "example.cpp.theolizer.hpp" // Theolizer自動生成先
int main()
{
// 保存
{
Foo foo;
foo.name="Taro Yamada";
foo.age=22;
std::ofstream ofs("sample.txt");
theolizer::XmlOSerializer<> xos(ofs); // シリアライザを生成
THEOLIZER_PROCESS(xos, foo); // ファイルへfooを保存
}
// 回復
{
Foo foo;
std::ifstream ifs("sample.txt");
theolizer::XmlISerializer<> xis(ifs); // デシリアライザを生成
THEOLIZER_PROCESS(xis, foo); // ファイルからfooを回復
THEOLIZER_PROCESS(xos, foo); // 回復結果の簡易表示
}
}

出力

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<th:XmlTheolizer xmlns:th="https://theolizer.com/theoride/xml-1" th:GlobalVersionNo="1">
<Foo>
<th:string th:MemberName="name">Taro Yamada</th:string>
<th:int32 th:MemberName="age">22</th:int32>
</Foo>
</th:XmlTheolizer>


3-5.メモリ内専用のFast形式(FastSerializer)

FastSerializerの使用目的はデータ構造のプログラム内コピーです。外部プログラムとのデータ交換は想定していません

Theolizerが内部的に使用していますので、他のシリアライザのヘッダをインクルードすれば改めてヘッダをインクルードする必要はありません。
もし、他のシリアライザを使用しない時は、theolizer/serializer.hをインクルードして下さい。
また、ストリームはstd::stringstreamを用いることを想定していますが、もしも、ファイル・ストリームを与える場合は必ず std::ios_base::binaryモード でオープンして下さい。
FastSerializerはデータ変換しません。バージョンの相違にも対応していません。
オーナー指定ポインタでない通常のポインタは、ポイント先をシリアライズしていない場合はシャロー・コピーになります。(ポインタ値を単純にコピーする。)

3-5-1.保存用FastSerializer

コンストラクタ

FastOSerializer
(
std::ostream& iOStream,
bool iNoThrowException=false
);
パラメータ名意味
iOStream出力先のストリーム(ofstreamはstd::ios_base::binaryでオープンして下さい)
iNoThrowException例外禁止時true(省略時はfalse)

3-5-2.回復用FastSerializer

コンストラクタ

FastISerializer
(
std::istream& iIStream,
bool iNoThrowException=false
);
パラメータ名意味
iIStream入力元のストリーム(ofstreamはstd::ios_base::binaryでオープンして下さい)
iNoThrowException例外禁止時true(省略時はfalse)

FastSerializerを用いたグローバル関数

template<typename tType>
void copySerializable(tType const& iSource, tType& oDestination);

tType型の変数iSourceをoDestinationへコピーします。
iSourceをFastSerializerでメモリ・ストリームへシリアライズし、続けてoDestinationへ回復することでコピーします。
保存先指定も有効ですので、柔軟なデータ構造のコピーを容易に実装できます。


4.テスト・プログラムの構造


4-1.テスト・プログラムの全体構造

4-1-1.アップデートとバージョンのバリエーション

主な機能テスト・プログラムは、 source/reference_and_test 以下にアップデート/バージョン・アップによる変更(修正版)毎にフォルダを分けて保存しています。

Theolizerはenum型とclass/struct型について定義変更に対応しています。そのテストも行うため、以下のように分類してテストを行います。

  1. 基本的なシリアライズ機能の定義変更を除く様々なバリエーションのテスト
  2. バージョン番号を更新しない定義変更のテスト
  3. バージョン番号を更新する定義変更のテスト

現時点では下記修正版を用意しています。

フォルダ名バージョン番号説明
basic無し基本的なシリアライズ機能の定義変更を除く様々なバリエーションのテスト
basic2無し同上
ver1a1最初のバージョン
ver1b1バージョン番号を変えずに可能な定義変更のテスト
ver1c1バージョン番号を変えるための準備のテスト
ver2a2バージョン番号を変更した時の定義変更のテスト
ver3a3更にバージョン番号を変更のテスト
ver3b3そしてバージョン番号を変えずに定義変更のテスト

class/structでメンバ変数を削除した場合、1つ前のバージョンの自動生成ソースに削除されたことを反映します。なので、最新版と1つ前のバージョンと、更にもう1つ前に問題が出ないかテストするため、3つのバージョンでテストします。

各変更テスト・プログラムは他の変更テスト・プログラムが出力したデータを読み込んで回復できることやエラーを検出できることをテストします。

4-1-2.テストの組み合わせ

下記組み合わせとなります。1行毎に各修正版プログラムが出力するデータ概要を記述しています。
列に記載した各バージョンのプログラムが当該データの回復テストをする時◯印を付けています。

プロ
グラ
バー
ジョン
指定
ファイル名basicbasic2ver1aver1bver1cver2aver3aver3b
basic 指定無し ①-basic-②
basic 1 ①-basic-basic-②
basic2指定無し ①-basic2-②
basic21 ①-basic-basic2-②
ver1a 指定無し ①-ver1a-②
ver1a 1 ①-ver1a-ver1a-②
ver1b 指定無し ①-ver1b-②
ver1b 1 ①-ver1b-ver1b-②
ver1c 指定無し ①-ver1c-②
ver1c 1 ①-ver1c-ver1c-②
ver2a 指定無し ①-ver2a-②
ver2a 1 ①-ver1c-ver2a-②
ver2a 2 ①-ver2a-ver2a-②
ver3a 指定無し ①-ver3a-②
ver3a 1 ①-ver1c-ver3a-②
ver3a 2 ①-ver2a-ver3a-②
ver3a 3 ①-ver3a-ver3a-②
ver3b 指定無し ①-ver3b-②
ver3b 1 ①-ver1c-ver3b-②
ver3b 2 ①-ver2a-ver3b-②
ver3b 3 ①-ver3b-ver3b-②

①にはシリアライザ名と一部のオプションが入ります。

  • json-np (非整形出力)
  • json-pp (整形出力)
  • binary
  • xml-np (非整形出力)
  • xml-pp (整形出力)
  • fast

②は以下の通りです。

  • 残りのオプション指定
    • jsonとbinaryの場合
      • NoTypeCheck
      • TypeCheck
      • TypeCheckByIndex
    • xmlの場合
      • NoTypeCheck(実際には型チェックします)
    • fastの場合は、最新版のみ対応でオプションもないため、上記表の「指定無し」のみです。

  • 保存先指定用のサフィックス
    • 無印
    • A(保存先DestA)
    • B(保存先DestB)
    • AB(保存先DestA | DestB)

  • 拡張子
    • jsonの拡張子はjson
    • binaryとfastの拡張子はbin

例えば、json整形出力で、ver3aのプログラムがver1cデータを型チェック無し、保存先指定無しで出力したファイル名は、"json-pp-ver1c-ver3a-NoTypeCheck.json"となります。


4-2.テスト・プログラムの構造

basic、および、各変更テスト用プログラムは共通部分があります。それらはreference_and_testフォルダ直下に配置し、ビルドする時に各サブ・フォルダへコピーしています。

共通部

ファイル関数概要
disable_test.h 各個別テストをディセーブルするシンボル定義。
デバッグ時の便利のために用意。
all_common.h テスト用の全バージョン共通定義。
アップデートとバージョン名とバージョン番号対応表のgVersionListを定義。
main.inc main() 各サブ・フォルダ内のmain.cppから::includeされる。
コマンドライン解析を行い、パラメータが無い時は保存処理、ある時は回復処理を実行する。
4-1節 表の全組み合わせを生成し、callTests()を呼び出す。
callTests()各シリアライザのパラメータを振ってインスタンスを生成し、
saveBasic(), loadBasic(),callSaveDestinations(),callLoadDestinations()を呼び出す。

各サブフォルダ部

ファイル関数概要
main.cpp 各個別フォルダ内テスト関数を呼び出す。
saveBasic()自動テスト基本部の保存処理。個別テストを呼び出す。
loadBasic()自動テスト基本部の回復処理。個別テストを呼び出す。
callSaveDestinations()自動テスト保存先指定部の保存処理。個別テストを呼び出す。
callLoadDestinations()自動テスト保存先指定部の回復処理。個別テストを呼び出す。

各個別テストは別途*.cppファイルを用意し、その中で定義しています。
それぞれについては 使用方法(個別) にて解説します。


4-3.説明で用いるマクロについて

テスト用のマクロはtest_tool.hで定義しています。
その内、使い方の説明(兼 自動テスト)で用いるマクロについてここで簡単に説明します。

1.THEOLIZER_EQUAL(dLhs, dRhs, ...)

(dLhs == dRhs) ならばPASS、そうでないならFAILと判定します。
PASSならば、テストの数とPASS数をインクリメントします。
FAILならば、テストの数とFAIL数をインクリメントし、テストを失敗させます。
また、dRhsとそれ以降のアイテム(1個以上7個まで)を標準出力へ出力します。

下記はシリアライザを使って回復したint型のaIntの値が-3000であることをチェックしています。

int aInt=0;
THEOLIZER_PROCESS(aSerializer, aInt);
THEOLIZER_EQUAL(aInt, 0x1a);