PerlIO実装メモ#3 PerlIOレイヤのデータ構造
PerlIOのデータ構造は以下の通り。
typedef struct _PerlIO PerlIOl; typedef struct _PerlIO_funcs PerlIO_funcs; typedef PerlIOl* PerlIO; struct _PerlIO { PerlIOl* next; /* Lower layer */ PerlIO_funcs* tab; /* Functions for this layer */ U32 flags; /* Various flags for state */ };
ここで、"PerlIO* fp;"という変数があるとすると、fpの型は"PerlIO*"であり、"PerlIOl**"であり、"struct _PerlIO**"である。ここで、"PerlIOl"はリンクリストとなっており、PerlIO_push()は以下のような処理を行う。
/* オリジナルのPerlIO_push()の簡略版 */ PerlIO* PerlIO_push(pTHX_ PerlIO *fp, PerlIO_funcs* tab, const char *mode, SV *arg){ PerlIOl* layer = (PerlIOl*)malloc(tab->size); layer->next = *fp; *fp = layer; layer->tab = (PerlIO_funcs*) tab; layer->tab->Pushed(aTHX_ fp, mode, arg, tab); return fp; }
まず、前半の3文はPerlIOクラスのインスタンスであるtabから得たPerlIOレイヤインスタンスのサイズ分のメモリを確保し、新しく割り当てたlayerのnextに元のレイヤーを代入しつつ、fpの参照先を新しいlayerで置き換える。PerlIO*がPerlIOlのポインタのポインタとなっているのは、PerlIO*がリンクリストの最上部を参照しているからだ。
そして、後半2文ではPerlIOオブジェクトのクラス(tab)を設定し、イニシャライザメソッドPushed()を呼んでいる*1。
もっとも、このレベルのデータ構造にはマクロを使ってアクセスするので、通常はあまりデータ構造を意識することはない。
#define PerlIOBase(f) (*(f)) #define PerlIOSelf(f,type) ((type *)PerlIOBase(f)) #define PerlIONext(f) (&(PerlIOBase(f)->next)) #define PerlIOValid(f) ((f) && *(f))
ただし、perlio.cを読むつもりなら、データ構造を理解しなければらないない。マクロを使わずにアクセスしている箇所が多々あるためだ*2。
See Also perliol / Data Structures.