Skip to content

Instantly share code, notes, and snippets.

@yugui yugui/extension.ja.rdoc
Last active Aug 29, 2015

Embed
What would you like to do?
extension.ja.rdoc -- extension library

CのデータをRubyオブジェクトにする

Cの世界で定義されたデータ(構造体)をRubyのオブジェクトとして 取り扱いたい場合がありえます.このような場合はTypedData_XXX マクロ群を用いて構造体へのポインタとRubyのオブジェクトとを互 いに変換できます.

# 古い(非Typedな)Data_XXXマクロ群は非推奨になりました.

# 将来のバージョンのRubyでは古いマクロは動作しなくなる可能性があります.

構造体からオブジェクトへ

構造体へのポインタsvalをRubyオブジェクトに変換するには次の マクロを使います。

TypedData_Wrap_Struct(klass, data_type, sval)

このマクロの戻り値は生成されたオブジェクトを表すVALUE値です.

klassはこのオブジェクトのクラスです.data_typeはこの構造体 をRubyが管理するための情報を記述したconst rb_data_type_t型への ポインタです.

なお, klassは, Objectや他のクラスではなくData (rb_cData)と いう特別なクラスから派生することが推奨されます. Dataから派生しない場合には, 必ずrb_undef_alloc_func(klass) を呼び出してください.

rb_data_type_tは次のように定義されています.

struct rb_data_type_struct {
        const char *wrap_struct_name;
        struct {
                void (*dmark)(void*);
                void (*dfree)(void*);
                size_t (*dsize)(const void *);
                void *reserved[2];
        } function;
        const rb_data_type_t *parent;
        void *data;
        VALUE flags;
};

wrap_struct_nameはこの構造体を識別する名前です.主に統計情報の 収集と出力に用いられます.プロセス内で一意であれば特にCやRuby の識別子として有効である必要はありません.

dmarkおよびdfree関数はGC実行中に呼び出されます. なお, GC実行中はRubyオブジェクトのアロケーションは禁止されま す. よって, dmarkおよびdfree関数でRubyオブジェクトのアロケーシ ョンは行わないでください.

dmarkはガーベージコレクタがオブジェクトへの参照をマークする ときに用いる関数です.この構造体がRubyのオブジェクトへの参照 を保持するときには, dmarkではrb_gc_markなどを用いて構造体内の すべての参照をマークしなければなりません. そのような参照を含まない時には0を指定します.

# そのような参照は勧められません.

dfreeはこの構造体がもう不要になった時に呼ばれる関数です.この 関数がガーベージコレクタから呼ばれます.これが-1の場合は,単 純に構造体が解放されます.

dsizeは構造体が消費しているメモリのバイト数を返す関数です. 引数として構造体へのポインタが渡されます.実装困難であれば0を 渡しても差し支えありませんが, できるだけ指定するようにしてく ださい.

reservedとparentは0で埋めなければなりません.

dataにはユーザー定義の任意の値を指定できます.Rubyはこの値に は関知しないので,好きに使ってください.

flagsには次のフラグのうち当てはまるもののビット和を指定します. いずれもRubyのガーベージコレクタについての深い理解を必要としますので, 良くわからない場合には0を指定すると良いでしょう.

RUBY_TYPED_FREE_IMMEDIATELY

このフラグを指定すると,ガーベージコレクタはこの構造体が 不要になった場合にはGC中に直ちにdfreeを呼び出します. dfreeがRuby内部のロック(GVL)を解放する可能性がない場合は このフラグを指定できます.

指定しない場合はdfree呼び出しは遅延され, ファイナライザ と同じタイミングで実行されます.

RUBY_TYPED_WB_PROTECTED

オブジェクトの実装がライトバリアをサポート していることを示します.このフラグを指定す るとRubyはそのオブジェクトに対してGCをより 効率的に実行できます. ただし,指定する場合はユーザーはそのオブ ジェクトのすべてのメソッドの実装に適切に ライトバリアを挿入する責任があります. さもなくばRubyは実行時にクラッシュする可能 性があります.

ライトバリアについては付録Dの「世代別GC」も 参照してください.

Cの構造体の割当と対応するオブジェクトの生成を同時 に行うマクロとして以下のものが提供されています.

TypedData_Make_Struct(klass, type, data_type, sval)

このマクロの戻り値は生成されたオブジェクトのVALUE値 です.このマクロは以下の式のように働きます:

(sval = ZALLOC(type), TypedData_Wrap_Struct(klass, data_type, sval))

klass, data_typeはData_Wrap_Structと同じ働きをします.type は割り当てるC構造体の型です.割り当てられた構造体は変数sval に代入されます.この変数の型は (type*) である必要があります.

オブジェクトから構造体へ

TypedData_Wrap_StructやTypedData_Make_Structで生成したオブ ジェクトから構造体へのポインタを復元するには 以下のマクロを用います.

TypedData_Get_Struct(obj, type, &data_type, sval)

Cの構造体へのポインタは変数svalに代入されます.

これらのマクロの使い方はちょっと分かりにくいので,後で説明する 例題を参照してください.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.