Theolizer  Version.1.2.0
serializer for C++ / Do you want to update your classes easily ?
7f.modify_enum.h
[詳解]
1 //############################################################################
2 /*!
3  @brief ドキュメント・ファイル-使用方法(個別)
4  @ingroup Documents
5  @file 7f.modify_enum.h
6  @author Yoshinori Tahara
7  @date 2017/03/07 Created
8 */
9 /*
10  © 2016 Theoride Technology (http://theolizer.com/) All Rights Reserved.
11  "Theolizer" is a registered trademark of Theoride Technology.
12 
13  "Theolizer" License
14  In the case where you are in possession of a valid “Theolizer” License,
15  you may use this file in accordance with the terms and conditions of
16  the use license determined by Theoride Technology.
17 
18  General Public License Version 3 ("GPLv3")
19  You may use this file in accordance with the terms and conditions of
20  GPLv3 published by Free Software Foundation.
21  Please confirm the contents of GPLv3 at https://www.gnu.org/licenses/gpl.txt .
22  A copy of GPLv3 is also saved in a LICENSE.TXT file.
23 
24  商用ライセンス
25  あなたが有効なTheolizer商用ライセンスを保持している場合、
26  セオライド テクノロジーの定める使用許諾書の条件に従って、
27  このファイルを取り扱うことができます。
28 
29  General Public License Version 3(以下GPLv3)
30  Free Software Foundationが公表するGPLv3の使用条件に従って、
31  あなたはこのファイルを取り扱うことができます。
32  GPLv3の内容を https://www.gnu.org/licenses/gpl.txt にて確認して下さい。
33  またGPLv3のコピーをLICENSE.TXTファイルにおいてます。
34 */
35 //############################################################################
36 
37 /*!
38  @page ChangingEnum enum型のアップデート/バージョン・アップ方法
39 ここでは、enum型を修正した時、古いプログラムが保存したデータを回復するための各種指定方法を説明します。<br>
40 
41 ### デフォルト値について
42 
43 最初にデフォルト値について説明します。<br>
44 enumのシンボルを定義している先頭のシンボルの値をTheolizerは「デフォルト値」として用います。<br>
45 THEOLIZER_ANNOTATE(ES)による指定を間違った場合、enum値保存/回復やバージョン・アップ/ダウン時に対応するシンボルが見つからない場合があります。その時、警告を報告(例外にはなりません。)し、変換先の値を「デフォルト値」にします。
46 
47 <br>
48 //############################################################################
49 @section HowToModifyEnum1 1.バージョン番号を変えないでenum型を修正
50 //############################################################################
51 
52 バージョン番号を変えない場合に可能なenum型の修正は以下のものがあります。
53 
54 1. シンボル名保存の場合
55  - シンボル値の変更<br>
56 シリライズ・データ中にシンボル値は記録されないため、シリアライズ処理とは無関係な変更です。<br>
57 従って、特にシリアライズ用に指定する必要はありません。<br>
58  - シンボル名の変更<br>
59 変更前のシンボル名で保存されたシリアライズ・データを回復できるようにするためには、変更前のシンボル名がどのシンボルへ対応するのか、Theolizerへ教える必要があります。<br>
60 そのためにTHEOLIZER_ANNOTATE(ES:)の第1パラメータを使います。<br>
61 <br>
62 2. シンボル値保存の場合
63  - シンボル名の変更<br>
64 シリライズ・データ中にシンボル名は記録されないため、シリアライズ処理とは無関係な変更です。<br>
65 従って、特にシリアライズ用に指定する必要はありません。<br>
66  - シンボル値の変更<br>
67 変更前のシンボル値で保存されたシリアライズ・データを回復できるようにするためには、変更前のシンボル値がどのシンボルへ対応するのか、Theolizerへ教える必要があります。<br>
68 そのためにTHEOLIZER_ANNOTATE(ES:)の第2パラメータを使います。<br>
69 <br>
70 3. 共通
71  - シンボルの追加<br>
72 古いシリアライズ・データに、新規追加したシンボル名/値が記録されることはありませんので、シリアライズ用の対応は何もありません。
73  - シンボルの削除<br>
74 削除前のシンボル名/値に対応するシンボルをTHEOLIZER_ANNOTATE(ES:)で指定していない場合、削除されたシンボル名/値を回復する時に警告が報告されます。それを避けるためには、例えば「デフォルト値」へシンボル名/値が変更されたように指定して下さい。複数の旧シンボルを1つの現シンボルへ指定可能ですので複数のシンボルを削除した場合にも対応できます。<br>
75 
76 注:シンボル値保存/シンボル名保存の指定方法については@ref EnumVariation を参照下さい。
77 
78 THEOLIZER_ANNOTATE(ES:)の指定方法は以下の通りです。
79 
80 @code
81 enumシンボル THEOLIZER_ANNOTATE(ES:シンボル名リスト:シンボル値リスト)=値,
82  :
83 @endcode
84 「シンボル名リスト」はシンボル名保存時に指定します。<br>
85 「シンボル値リスト」はシンボル値保存時に指定します。
86 「=値」は通常のenum型と同じく省略可能です。
87 
88 <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333; border-radius: 10px; background-color: #d0d0d0;">
89 <b>THEOLIZER_ANNOTATE(ES:)を記述する位置が直感的な位置ではないですので、ご注意下さい。</b><br>
90 シンボルの<b>直後</b>です。この機能の実装にclangの属性指定(__attribute__())機能を使っていますが、enum型のシンボルの属性指定は、この位置のみ書けます。
91 </div>
92 
93 <br>
94 @subsection HowToModifyEnum11 1-1.シンボル名保存の変更サンプル
95 
96 下記の修正を行うサンプルです。
97 
98 - eesnName11をeesnName10へ変更
99 - eesnName20, eesnName21, eesnName22をeesnName20へ統合<br>
100 「eesnName21, eesnName22を削除して、eesnName20へ割り当てた」のと同じです。
101 
102 <b>変更前(ver1a)のソース</b>(source/reference_and_test/ver1a/test_modify_enum.h)
103 
104 @dontinclude ver1a/test_modify_enum.h
105 @skip EnumSymName
106 @until {
107 @skip eesnName11
108 @until eesnName22
109 (後略)
110 
111 <b>変更後(ver1b)のソース</b>(source/reference_and_test/ver1b/test_modify_enum.h)
112 
113 @dontinclude ver1b/test_modify_enum.h
114 @skip EnumSymName
115 @until {
116 @skip eesnName10
117 @until eesnName20
118 (後略)
119 
120 <br>
121 @subsection HowToModifyEnum12 1-2.シンボル値保存の変更サンプル
122 
123 修正内容はEnumSymNameの場合と同等です。
124 
125 <b>変更前(ver1a)のソース</b>(source/reference_and_test/ver1a/test_modify_enum.h)
126 
127 @dontinclude ver1a/test_modify_enum.h
128 @skip EnumSymVal
129 @until {
130 @skip eesvValue11
131 @until eesvValue22
132 (後略)
133 
134 <b>変更後(ver1b)のソース</b>(source/reference_and_test/ver1b/test_modify_enum.h)
135 
136 @dontinclude ver1b/test_modify_enum.h
137 @skip EnumSymVal
138 @until {
139 @skip eesvValue10
140 @until eesvValue20
141 (後略)
142 
143 <br>
144 //############################################################################
145 @section HowToMakeGlobalVersionNoTable 2.グローバル・バージョン番号テーブル生成
146 //############################################################################
147 
148 enum型解説の途中ですが、ここでバージョン・アップ前の準備について説明します。<br>
149 今までバージョン管理していなかった時にバージョン管理を始める時、@ref Basic32 で説明した「グローバル・バージョン番号テーブル」の生成が必要になります。
150 
151 そのために必要な作業は以下の通りです。
152 - グローバル・バージョン番号テーブルの宣言
153 - グローバル・バージョン番号テーブル実体定義
154 
155 <br>
156 @subsection HowToMakeGlobalVersionNoTable21 2-1.グローバル・バージョン番号テーブルの宣言
157 
158 シリライズ処理するコンパイル単位全てがインクルードするヘッダファイルで宣言して下さい。<br>
159 具体的には下記書式で宣言します。
160 
161 @code
162 THEOLIZER_DEFINE_GLOBAL_VERSION_TABLE(テーブル名, グローバル・バージョン番号);
163 @endcode
164 
165 テーブル名は任意の識別子です。これはtheolizer::internal::global_table名前空間内で必要なコードを定義する時の識別子の一部として用いられます。<br>
166 グローバル・バージョン番号は最初は必ず1として下さい。その後、バージョンを上げる度に1づつインクリメントして下さい。
167 
168 <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333; border-radius: 10px; background-color: #d0d0d0;">
169 グローバル・バージョン番号が1つ増える度にクラスやenum型のローカル・バージョン番号も最大1つ上げることができます。既に現在のグローバル・バージョン番号でクラスかenum型のローカル・バージョンを上げており、それを更に上げる場合はグローバル・バージョン番号も上げる必要があります。<br>
170 グローバル・バージョン番号が決まればクラスやenum型のローカル・バージョン番号も決まるようにする必要があるためです。</div>
171 
172 <b>サンプルをver1cに用意してます。</b>(source/reference_and_test/ver1c/common.h)
173 
174 @dontinclude ver1c/common.h
175 @skip THEOLIZER_DEFINE_GLOBAL_VERSION_TABLE
176 @until THEOLIZER_DEFINE_GLOBAL_VERSION_TABLE
177 
178 <br>
179 @subsection HowToMakeGlobalVersionNoTable22 2-2.グローバル・バージョン番号テーブル実体定義
180 
181 グローバル・バージョン番号テーブル実体は通常のグローバル変数(配列)として定義されますので、どれか1つのコンパイル単位でのみ実体定義します。
182 
183 @code
184 #define THEOLIZER_GLOBAL_VERSION_TABLE
185 @endcode
186 
187 そのコンパイル単位のソース・ファイル(.cpp)の先頭付近で下記を定義することで、Theolizerドライバがこのマクロ定義を認識し、実体をその.cppファイル用の*.theolizer.hpp内に自動生成します。
188 
189 また、そのコンパイル単位をTheolizerドライバが解析する時に、シリアライズする全てのクラスとenum型の定義とそのシリアライズ指定が必要になります。そこで、当該コンパイル単位ではシリアライズする全ての型を定義したヘッダ・ファイルをインクルードして下さい。
190 
191 <b>サンプルをver1cに用意してます。</b>(source/reference_and_test/ver1c/main.cpp)
192 
193 @dontinclude ver1c/main.cpp
194 @skip theolizerライブラリ
195 @until main.cpp.theolizer.hpp
196 
197 <br>
198 //############################################################################
199 @section HowToModifyEnum3 3.バージョン番号を変えてenum型を修正
200 //############################################################################
201 
202 バージョン番号を更新して、enum型をバージョン・アップすることで次の変更ができます。
203 
204 - 過去割り当てていたシンボルを別の意味で再割当て<br>
205 バージョン番号を変えない場合、古いプログラムで保存したシンボルを他のシンボルへ割り当てるため、古いシンボルも割り当てが存在するため変更できません。<br>
206 バージョン番号を更新することで、新しいバージョンでは古いシンボルは未定義なので、それを新たに割り当てしても混乱を生じません。<br>
207 <br>
208 - シンボル名保存とシンボル値保存の切り替え<br>
209 ローカル・バージョン番号を1つ上げて、シリアライズ指定マクロ名を変えるだけです。
210 
211 @subsection HowToModifyEnum31 3-1.バージョン・アップ手順
212 
213 enum型をバージョン・アップする時の手順は次の通りです。
214 
215 1. まだ作っていないなら、グローバル・バージョン番号テーブルを作成しておきます。<br>
216 <br>
217 2. 対象enum型が非侵入型<b>完全自動</b>ならば非侵入型<b>半自動</b>へ変更します。<br>
218 完全自動のバージョン・アップに対応していません。<br>
219 <br>
220 3. ビルドし、Theolizerドライバにて自動生成ソースへ反映します。<br>
221 <br>
222 4. 必要な場合はグローバル・バージョン番号をインクリメントします。<br>
223 @ref HowToMakeGlobalVersionNoTable21 参照。<br>
224 <br>
225 5. 対象enum型のローカル・バージョン番号をインクリメントします。<br>
226 @ref HalfAutoEnum 参照。<br>
227 この時、バージョン・アップ前のバージョンで付けていたTHEOLIZER_ANNOTATE()を一旦全て削除します。<br>
228 前バージョンで付けていたものは全て前バージョンへ指定ですので、次のバージョンでは指定内容が完全に異なります。<br>
229 <br>
230 6. 対象enum型の定義を変更し、前バージョンとの対応付けを行います。<br>
231 具体的には後述します。<br>
232 <br>
233 7. ビルドします。<br>
234 
235 <br>
236 @subsection HowToModifyEnum32 3-2.非侵入型半自動への変更方法
237 単純にTHEOLIZER_ENUM()マクロで指定しするだけです。対象のenum型定義よりも後、*.theolizer.hppをインクルードする前にTHEOLIZER_ENUM()マクロを置いて下さい。なお、THEOLIZER_ENUM_VALUE()でシンボル値保存へ直接変更することはできません。シンボル値保存へ変更する場合は、ローカル・バージョン番号を更新する時に行って下さい。<br>
238 
239 <b>サンプル</b><br>
240 test_modify_enum.hで定義しているEnumFullAutoとScopedEnumFullAutoはver1a, ver1bまでは非侵入型完全自動ですが、ver1cにて非侵入型半自動へ修正しています。<br>
241 
242 <b>半自動型へ変更した(ver1c)のソース</b>(source/reference_and_test/ver1c/test_modify_enum.h)
243 
244 @code
245 
246 enum EnumFullAuto
247 {
248  // 中略
249 };
250 THEOLIZER_ENUM(EnumFullAuto, 1); // バージョン・アップに備え半自動型へ変更
251 
252 enum class ScopedEnumFullAuto : long
253 {
254  // 中略
255 };
256 THEOLIZER_ENUM(ScopedEnumFullAuto, 1); // バージョン・アップに備え半自動型へ変更
257 
258 @endcode
259 
260 <br>
261 @subsection HowToModifyEnum33 3-3.バージョン・アップ時のシンボル対応
262 enum型はバージョン・アップする時、前バージョンと現バージョン間のシンボル値の対応を指定することができます。現バージョンのシンボルに対して、対応する前バージョンのシンボル値を指定します。<br>
263 
264 この場合、THEOLIZER_ANNOTATE(ES:)の第3パラメータで指定します。
265 
266 @code
267 enumシンボル THEOLIZER_ANNOTATE(ES:::対応する前バージョンのシンボル値)=値,
268  :
269 @endcode
270 
271 「対応する前バージョンのシンボル値」はenumシンボルではなく直接数値で指定して下さい。前バージョンのenum型そのものは存在しません。しかし、旧版のenum型シンホルの値を変更することも有りえませんので指定可能です。<br>
272 また、前バージョンとシンボル値が変化していない場合は「対応する前バージョンのシンボル値」の指定を省略できます。
273 <br>
274 @subsubsection HowToModifyEnum331 3-3-1.内部処理概要
275 
276 - バージョン・アップ処理<br>
277 前バージョンのシンボル値に対して、次のバージョンの各シンボルを先頭から順に枚挙し、「対応する前バージョンのシンボル値」が一致するものを探します。最初に一致したシンボルへ変換します。<br>
278 複数のシンボルが一致する時は、先に定義されたシンポルへ変換されます。<br>
279 なお、一致するものが見つからなかった時は、デフォルト値を設定し、警告を報告します。<br>
280 <br>
281 - バージョン・ダウン処理<br>
282 前バージョンの各シンボルを先頭から順に枚挙し、現バージョンのシンボルの「対応する前バージョンのシンボル値」と一致するものを探します。最初に一致したシンボルへ変換します。<br>
283 複数のシンボルが一致する時は、先に定義されたシンポルへ変換されます。<br>
284 なお、一致するものが見つからなかった時は、デフォルト値を設定し、警告を報告します。<br>
285 <br>
286 @subsubsection HowToModifyEnum332 3-3-2.以前使用したシンボルの再割当て
287 これは、シンボルを名前変更したり削除(デフォルト値へ割り当て)したりした後、変更前に使っていたシンボルを他の意味で使いたいケースを想定しています。<br>
288 この場合、バージョン・アップすることで、そのシンボルを他のシンボルへの再割当てすることができます。その際、@ref HowToModifyEnum33 の方法で指定します。<br>
289 
290 再割当てしたいシンボルを「enumシンボル」に追加します。<br>
291 この時、「対応する前バージョンのシンボル値」には前バージョンにおける「デフォルト値」を指定して下さい。<br>
292 <br>
293 
294 なお、上記の指定方法で、バージョン・アップ前のバージョンの特定のシンボルを、以前使っていたシンボルへ戻すことも可能です。ただし、これはシンボルの意味の変更を伴いませんので、バージョン・アップしても問題ないですが、バージョン・アップする必要はありません。
295 
296 下記の修正を行うサンプルです。
297 
298 - 旧バージョンの各種指定を削除する
299 - 以前使っていたeesnName11を新しいバージョンのenum型へ新規追加する
300 
301 
302 <b>バージョン・アップ前(ver1c)のソース</b>(source/reference_and_test/ver1c/test_modify_enum.h)
303 
304 @dontinclude ver1c/test_modify_enum.h
305 @skip EnumSymName
306 @until eesnDefault
307 @skip eesnValue1
308 @until eesnValue1
309 @skip eesnName10
310 @until eesnName10
311 @skip eesnName20
312 @until eesnName42
313 @skip eesnName30
314 @until eesnName52
315 @skip eesnDeleted
316 @until };
317 
318 <b>バージョン・アップ後(ver2a)のソース</b>(source/reference_and_test/ver2a/test_modify_enum.h)
319 
320 @dontinclude ver2a/test_modify_enum.h
321 @skip EnumSymName
322 @until };
323 
324 <br>
325 @subsubsection HowToModifyEnum34 3-4.シンボル名保存とシンボル値保存の切り替え
326 開発当初は変更対応しやすいシンボル名保存が使い勝手が良いです。(`C#`での経験ですが、シンボル値を気にしないで良いのはたいへんありがたかったです。)<br>
327 ある程度枯れてきたら、シンボル名では効率が悪いのでシンボル値へ変更したくなります。<br>
328 そして、再度、大改造する際に一旦シンボル名へ戻したい時もあるでしょう。<br>
329 このようなシナリオに対応することを想定しています。
330 
331 変更は@ref HowToModifyEnum31 の手順に従います。この6.の手順にて下記マクロ名を切り替えます。<br>
332 
333 - THEOLIZER_ENUM
334 - THEOLIZER_ENUM_VALUE
335 
336 下記の修正を行うサンプルです。
337 
338 - 旧バージョンのシンボル名保存enum型をシンボル値保存enum型へ変更(EnumSymName)
339 
340 
341 <b>バージョン・アップ前(ver2a)のソース</b>(source/reference_and_test/ver2a/test_modify_enum.h)
342 
343 @dontinclude ver2a/test_modify_enum.h
344 @skip EnumSymName
345 @skip THEOLIZER_ENUM
346 @until THEOLIZER_ENUM
347 
348 <b>バージョン・アップ後(ver3a)のソース</b>(source/reference_and_test/ver3a/test_modify_enum.h)
349 
350 @dontinclude ver3a/test_modify_enum.h
351 @skip EnumSymName
352 @skip THEOLIZER_ENUM_VALUE
353 @until THEOLIZER_ENUM_VALUE
354 <br>
355 //############################################################################
356 @section HowToModifyEnum4 4.網羅的な使用例(自動テスト)の説明
357 //############################################################################
358 enum型の修正に関する網羅的なテストは @ref TestProgram で説明した各フォルダの下記2つのファイルにて実装しています。
359 
360 - test_modify_enum.h
361 - test_modify_enum.cpp
362 
363 unscoped enum型とscoped enum型について下記の修正を行い、@ref TestProgram412 の各バージョン間で正しく回復できることを確認しています。
364 
365 |バージョン|修正点|特記事項|
366 |----------|------|--------|
367 |ver1a→ver1b|1.シンボル値変更<br>2.シンボル名変更(a→b)<br>3.シンボル名変更(a,b,c→a)<br>4.シンボル名変更(a,b,c→d)<br>5.シンボル名削除(指定ミス)|<br>単純変更<br>3つから先頭の1つへ対応<br>3つから別の1つへ対応<br>指定ミスは対応先指定漏れ警告が出ることを確認|
368 |ver1b→ver1c|1.グローバル・バージョン番号テーブル作成<br>2.完全自動型を半自動型へ変更<br>3.シンボル名削除指定ミスの修正|警告が消えることを確認|
369 |ver1c→ver2a|1.バージョン・アップ<br>2.以前使っていたシンボルの再割当て| |
370 |ver2a→ver3a|1.バージョン名保存→バージョン値保存<br>2.バージョン値保存→バージョン名保存<br>3.前バージョンとの対応指定ミス|バージョン・アップ処理と回復処理で警告が出ることを確認<br>(元完全自動型はバージョン・アップ無し)|
371 |ver3a→ver3b|指定ミスの修正|警告が消えることを確認<br>(元完全自動型はバージョン・アップ無し)|
372 
373 ver3a/test_modify_enum.cppのtutoriseModifyEnum()関数にて対応シンボルが無い時のバージョン・ダウン処理、および、保存処理に於ける警告検出をjson形式を用いてテストしています。
374 
375 ver3b/test_modify_enum.cppのtutoriseModifyEnum()関数にて上記警告が消えることをテストしています。
376 
377 */