YamaKen
yamak****@bp*****
2005年 10月 10日 (月) 02:53:45 JST
At Sat, 8 Oct 2005 21:51:31 -0700, jun.l****@gmail***** wrote: > > On Sun, 09 Oct 2005 12:14:49 +0900 > YamaKen <yamak****@bp*****> wrote: > > > Schemeのコード上でportの実装を識別したい場合があるという事ですか? > > Schemeのコード上でportの実装を識別したい場合があるという事じゃなかったん > ですか? なかったんです。 > Soft port の実装が同じ (Scheme level) 関数を使いまわすことを想定してるの > かなと思ったんですが、それは soft port 実装側が user data に tag を置い > とけば済みますね。 ですね。そのへんの情報に対してSigScheme本体が関知するのは避けた いです。 > > 私はCレベルでのダウンキャスト向け型情報としか考えてなかったんで > > すが(get-output-string等で必要)。 > > う〜、それなら enum でいいような。STRING ^ FILE ^ SOFT の三つで十分。こ > れなら cell も消費しないし、簡単。 せっかくportを抽象化するんだから、最初から3つで十分と決め付けて しまうのはもったいないですよね。そもそもstring portやsoft portの 存在なんてSigScheme本体のレイヤからは見えないように隠蔽したい。 soft portの存在意義を認めているという事は未知のportタイプを抽象 化する必要性が確かにあるという事で、それはC(で書きたい|でしか書 けない)類のものかもしれない。そしてCで書かれたportならSchemeの procedure経由ではなく直接呼んでパフォーマンスを出したい、という 事です。 それから、特定のportタイプに固有な操作 Scm_fooport_bar(ScmCPort port) をCから直接呼ばれた場合にはScmCPort自身が型情報を保持して ないとダウンキャストできません。portタイプ毎に型IDとして1 cons cellとvtbl のメンバに1wordを消費するぐらいは無視できる負担だと思 います。cons cellを使うのがいやだったらシリアルID発行用のカウン タを用意してもいいと思います。 …とここまで書いて気付いたんですが、vtblのアドレス自身を型IDと見 なせば何も消費しませんね。vtbl全体をconstにもできるし。 > > これはSchemeのportオブジェクトレベルでやっとけば十分でしたね。 > > > > close_input_port(ScmObj port) > > { > > SCM_PORT_DIRECTION(port) &= ~SCM_PORTDIR_INPUT; > > if (SCM_PORT_DIRECTION(port) == SCM_PORTDIR_NONE) > > SCM_PORT_CLOSE(port); /* also frees port->cport */ > > } > > そういうネタ元だったのね。そうそう、それは bit mask で十分。 > あ、ところで member 変数名は cport より info か desc の方がよいでする。 ScmCPortは抽象portの実体そのものなので、infoやdescといった具象デー タを想起させるような名前は誤解の元だと思います。むしろimplとかに してしまった方がいいかも。 > > > これは get_byte(), peek_byte(), byte_readyp() or number_of_bytes_ready > > > () にしましょう。Multibyte port を読むとき次の文字が何 bytes 含むかの判 > > > 定は SigScheme 側で書きたいところです。 > > > > その方がいいですね。3つ目の関数名はbytelen_ready()なんてどうでしょ > > う。 > > 意味はわかるけど何か変ですねぇ… > bytes_ready (port, SCM_MB_MAX_LEN); > => SCM_MB_MAX_LEN 以下の非負整数 > みたいな使い方を想定しています。File port に毎回 file 終端までのサイズを > 返させるわけにはいきませんので。 そういう目的でしたか。その例を見て気付いたんですが、 encoding-awareなport(QtのQTextStreamをwrapするportとか)に対して はcharを直接入出力できた方が嬉しいですね。 というわけで、以下のような2段構成はどうでしょうか? この場合上記 の例はScmStdCharPortのrbufが溜まるまでbyte_readp()を繰り返す事で 実現できます。 R5RSがinteger->char, char->integerという形でcharを扱うので、Cレ ベルではintとして扱うようにしています。char自体にはencoding情報 が保持できないのでプログラマが明示的に管理する必要がありますが、 (with-encoding enc thunk)とかでデフォルトencodingが切り換えられ るようになってれば十分だと思います。少なくともuim的には。 encoding変換機能はSigScheme本体で提供する必要はないと思います。 enum ScmPortDirection { SCM_PORTDIR_NONE = 0, SCM_PORTDIR_OUTPUT = 1 << 0, SCM_PORTDIR_INPUT = 1 << 1 }; struct ScmPortCell_ { enum ScmPortDirection direction; ScmCharPort *impl; } port; struct ScmCharPortVTbl_ { int (*close)(ScmCharPort cport); /* returns "UTF-8", "eucJP" and so on */ const char *(*encoding)(ScmCharPort cport); /* input */ int (*get_char)(ScmCharPort cport); int (*peek_char)(ScmCharPort cport); int (char_readyp)(ScmCharPort cport); /* output */ int (*vprintf)(ScmCharPort cport, const char *str, va_list args); /* tmp */ int (*put_char)(ScmCharPort cport, int ch); int (*flush)(ScmCharPort cport); }; struct ScmBytePortVTbl_ { int (*close)(ScmBytePort bport); /* input */ int (*get_byte)(ScmBytePort bport); int (*peek_byte)(ScmBytePort bport); int (*byte_readyp)(ScmBytePort bport); /* output */ int (*vprintf)(ScmBytePort bport, const char *str, va_list args); /* tmp */ int (*put_str)(ScmBytePort bport, const char *str); size_t (*put_bytestr)(ScmBytePort bport, size_t len, const char *str); int (*flush)(ScmBytePort bport); }; struct ScmCharPort_ { const ScmCharPortVTbl *vptr; }; struct ScmStdCharPort_ { const ScmCharPortVTbl *vptr; ScmBytePort *bport; unsigned char rbuf[SCM_MB_MAX_LEN + 1]; unsigned char wbuf[SCM_MB_MAX_LEN + 1]; }; /* wraps Qt's encoding-aware QTextStream */ struct ScmQTextStreamPort_ { const ScmCharPortVTbl *vptr; QTextStream *qstream; }; struct ScmBytePort_ { const ScmBytePortVTbl *vptr; }; struct ScmFilePort_ { const ScmBytePortVTbl *vptr; FILE *file; }; struct ScmStrPort_ { const ScmBytePortVTbl *vptr; char *str; char *cur_pos; size_t buf_size; }; ------------------------------- ヤマケン yamak****@bp*****