Writing a generic type descriptor with HCL RTist の翻訳版です。
HCL RTistによる汎用型記述子の記述
2021年11月9日
著者: Mattias Mohlin / Senior Solutions Architect for HCL Software
型記述子は、クラス、typedef、型の別名など、モデル内のユーザー定義の型に関するメタデータを提供します。TargetRTSは、型記述子の情報を使って、その型のオブジェクトをどのように初期化、コピー、エンコードするかなどを知ります。多くの場合、モデルコンパイラは型に対して自動的に型記述子を生成しますが、場合によっては手動で型記述子を書く必要があります。型記述子に慣れていない方は、この記事を読んでから先に進むことをお勧めします。
ここでは、型がジェネリックである場合、つまり、1つまたは複数のテンプレートパラメータを持つ場合について見てみましょう。以前は,テンプレート型の具体的なインスタンスごとにtypedefやtype aliasを作成し,そのテンプレートのインスタンスに合わせて型記述子を記述する必要がありました.これは明らかに面倒で、しばしばコードの重複を招きました。RTist 11.1 2021.24からは、型と同じテンプレートパラメータを使用するジェネリックな型記述子を書くことができるようになりました。これにより、多くの時間を節約し、コードの重複を避けることができます。
例として,異なる種類の要素を持つベクトルを2つのカプセル間で送信する場合を考えてみましょう.まず最初に,std::vectorの型のエイリアスを定義し,vector型の型テンプレートパラメータを追加します.この場合、テンプレートパラメータを持つ型が必要なので、typedefは使えません。
次に、tを書きます。
target = new (target) std::vector<T>();
Copy 関数
target = new(target) std::vector<T>(*source);
Destroy 関数
target->~StdVector<T>();
今回の例では、これら3つの型記述子関数があれば十分ですが、汎用的なエンコードの実装方法を示すために、Encode関数も実装してみましょう。
const RTObject_class *elementTypeDescriptor = RTObject_class::fromType<T>();
if (!elementTypeDescriptor)
return 0; // Element type descriptor not available
int sum = 0;
bool first = true;
sum += coding->write_string(type->name());
sum += coding->write_string("{");
for (auto i = source->begin(); i != source->end(); i++) {
if (!first)
sum += coding->write_string(",");
first = false;
sum += elementTypeDescriptor->encode(&*i, coding);
}
sum += coding->write_string("}");
return sum;
この実装では、TargetRTSの新しいテンプレート関数であるRTObject_class::fromType
TargetRTSでは、すべての組み込みC++型に対してRTObject_class::fromType
Decode関数は、解析を必要とするため、通常、型記述子関数の中で最も実装が難しい関数です。この関数を実装することは、このニュースレターの範囲外です。しかし、モデルコンパイラが型記述子を生成しないため、完全に空けることはできません。
デコード関数
// NOT IMPLEMENTED
return 1;
最後に、StdVector用のコードスニペットを2つ用意しておきます。
Header Preface
#include <vector>
これにより、StdVector型を使用する際に、基礎となるstd::vector型が利用できるようになります。
Header Ending
template <> const char* RTName_StdVector<int>::name = "StdVector<int>";
template <> const char* RTName_StdVector<char>::name = "StdVector<char>";
これらのテンプレートの特殊化は厳密には必要ではありませんが、デバッグの際に役立ちます。デフォルトでは、型記述子の名前はモデル型の名前(この例ではStdVector)に設定され、その名前は型記述子のすべてのインスタンスで同じになります。使用するテンプレートのインスタンスに対して特殊化を行うことで,より具体的な名前を得ることができます.
なお,すべてのコンパイラが,このような特殊化をヘッダファイルに記述できるわけではありません。
それでは、StdVector型記述子をテストしてみましょう。2つのカプセルを持つサンプルモデルを作成し、1つ目のカプセルから2つ目のカプセルにintのベクターを送信し、2つ目のカプセルから1つ目のカプセルにcharsのベクターを送信します。自分でモデルを作りたくない場合は、添付のモデルを使うことができます。そのモデルを構築して実行すると、このような出力が出力されます。
Reached Cap2 State 1
Reached Cap1 State1 and sending Integer
Success: Received sendInteger event with data at Cap2.
Received: StdVector<int>{1,2,3}
Reached Cap2 State2 and sending Chars
Success: Received sendChar event with data at Cap1.
Received: StdVector<char>{'a','b','c'}
Reached Cap1 State2 and received Chars