こんにちは、高木です。
今回もTcl_Obj型について見ていきます。前回はTcl_Obj型のオブジェクトに文字列を格納する話題でしたが、今回は数値を格納していきます。
Tclが扱える数値には次のものがあります。
- int型
- long型
- WideInt型
- Boolean型
- Bignum型
- double型
それぞれの型についてTcl_Obj型のオブジェクトを生成や値を取得するAPIが用意されています。詳しくは公式ドキュメントを参照してください。
ただ、先ほど挙げたすべての型に対応する必要はないと考えています。たとえば、long型は環境によって32ビットの場合と64ビットの場合があり、int型かWideint型のどちらかと同じサイズになります。よって、32ビット整数であるint型と64ビット整数であるWideInt型に対応すれば十分でしょう。
Bignum型というのは、LibTomMathという多倍長整数ライブラリーを使用しているのですが、外部ライブラリーのLibTomMathを要求するのではなく、Tclの中にLibTomMathを取り込んでしまっています。結果として、本来のLibTomMathを使いたい場合にいろいろ面倒が起きますので、文字列として扱うようにした方がよさそうです。
今回は、検討の結果残ったint型、WideInt型、Boolean型、double型についてのみ対応することにします。では、その部分のコードを抜粋してみましょう。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
obj(std::int_least32_t value) : obj_(Tcl_NewIntObj(static_cast<int>(value))) { Tcl_IncrRefCount(this->obj_); } obj(std::int_least64_t value) : obj_(Tcl_NewWideIntObj(static_cast<Tcl_WideInt>(value))) { Tcl_IncrRefCount(this->obj_); } obj(bool value) : obj_(Tcl_NewBooleanObj(value)) { Tcl_IncrRefCount(this->obj_); } obj(double value) : obj_(Tcl_NewDoubleObj(value)) { Tcl_IncrRefCount(this->obj_); } std::optional<std::int_least32_t> get_int() const { extern Tcl_Interp* root_interp; int value; if (Tcl_GetIntFromObj(root_interp, this->obj_, &value) == TCL_OK) return static_cast<std::int_least32_t>(value); return {}; } std::optional<std::int_least64_t> get_wide_int() const { extern Tcl_Interp* root_interp; Tcl_WideInt value; if (Tcl_GetWideIntFromObj(root_interp, this->obj_, &value) == TCL_OK) return static_cast<std::int_least64_t>(value); return {}; } std::optional<bool> get_boolean() const { extern Tcl_Interp* root_interp; int value; if (Tcl_GetBooleanFromObj(root_interp, this->obj_, &value) == TCL_OK) return static_cast<bool>(value); return {}; } std::optional<double> get_double() const { extern Tcl_Interp* root_interp; double value; if (Tcl_GetDoubleFromObj(root_interp, this->obj_, &value) == TCL_OK) return static_cast<double>(value); return {}; } |
ほとんど同じことの繰り返しになっています。こういうコードは、本来であればPHPで前処理して自動生成したいところですね。
int型とWideInt型には、C++のコードではstd::int_least32_t型とstd::int_least64_t型を使うようにしました。その方が意図が明確になりますので。また、get_*メンバー関数内ではroot_interpというTcl_Interp*型のグローバル変数を参照しています。Tcl_Obj型から数値を取り出すためにはどうしても必要になるからです。いまいちなのですが、インタープリターについてはまだラッパークラスを用意していませんので、今のところはとりあえずこれで進めます。
これで一通りTcl_Obj型と数値の相互変換ができるようになりました。まだ少しだけTcl_Obj型のラッパークラスであるobjクラスについては触れておかないといけないことがありますので、次回はその話題を取り上げることにします。