[[C++のiostream]] [[C++ iostream 実装資料2]]では、最小限 - int sync() - int_type underflow() - int_type uflow() - int_type overflow(int_type c = traits::eof()) の4つを実装すればよいということを述べた。ここでは、これらの 規格を調べ、考察を行う。なお、 - int_type pbackfail(int_type c = traits::eof()) についても、挙げておく。 ** sync [#iaefe940] - int sync() 効果 制御される列と配列を同期させる。すなわち、pbase() が空でない場合、pbase() と pptr() との間の文字が、 制御される列に書き出される。ポインタは、適切な状態にリセットされてよい。 返却値 失敗した場合 -1 を返す。何が失敗であるかは、派生したクラスごとに定められる。 省略時動作 0 を返す。 要するに、現在出力 buffer に溜め込まれている data を全部出力装置へ出力 しろということである。pbase() と pptr() 間の文字というのは、直前の overflow 呼び出し以降に溜め込まれた data であるが、実際には overflow の 時に全部は出力できていない(していない)場合も有り得る(overflow の要請は 少なくとも1文字分の書き込み space を作ればよいだけなので)。 その場合は、前に出力し損ねた(しなかった) data も含め、全部出力する 必要がある。ここで出力を残してはいけない。 その場合は、前に出力し損ねた(しなかった) data も含め、全部出力する。 1文字たりとも出力せずに残してはいけない。 ** underflow [#o6c7b66b] - int_type underflow() 規格では、この関数に関して 参考: basic_streambuf の公開メンバは、gptr() がナルであるか、 gptr() >= egptr() である場合にだけ、この関数を呼ぶことができる。 としている。限定公開メンバ関数である uflow() は、省略時動作として underflow() を呼び出すとしてる。この場合は上記条件は必ずしも満たされていない。 規格では、この関数の返却値は 入力列の位置を進めることなく、traits::to_int_type(c) を返す。 ここで、c は、未解決列の最初の文字とする。 未解決列がナルの場合、この関数は失敗を表すために traits::eof() を返す。 となっている。また未解決列とは、規格で次に挙げるものの連結を呼ぶとしている。 a) gptr() がナルでない場合、gptr() から始まる egptr() - gptr() 個の文字。それ以外の場合、空列。 b) 入力列から読み込まれる(空かも知れない)列。 効果 この関数は、gptr() 及び egptr() を、次のとおりにセットする。 a) 未解決列が空でない場合、egptr() は、非ナルとなり、gptr() から始まる egptr() - gptr() 個の文字は、未解決列内の文字となる。 b) 未解決列が空の場合、gptr() がナルになるか、gptr() 及び egptr() が同じ非ナルポインタとなる。 eback() 及び gptr() がナルでない場合、この関数は特別な制約を設けないが、次に示す通常のバックアップ条件を適用する。 a) バックアップ列が、少なくとも gptr() - eback() 個の文字を持つ場合、eback() から始まる gptr() - eback() 個の文字は、バックアップ列の最後の gptr() - eback() 個の文字と等しい。 b) 又は、gptr() - n から始まる n 個の文字が、バックアップ列と等しい(ここで n は、バックアップ列の長さとする。) 従って、underflow はバッファ内の現在位置に文字があれば、その文字を、無ければ入力列の先頭文字を返すことになる。問題は、読込み位置を進めることなく読み出す機能が 入力装置に無い(あるいは使わない)場合、少なくとも1文字分のバッファが必要となることである。 ** uflow [#c8a89f4c] - int_type uflow() 要件 結果の文字が、未解決列からバックアップ列に転送されること及び転送以前に、未解決列は、 空ではないかもしれないことを除き、制約条件は、underflow() と同じとする。 省略時動作 underflow() を呼び出す。underflow() が traits::eof() を返した場合、traits::eof() を返す。 そうでない場合、traits::to_int_type(*gptr()) を返し、入力列の次位置ポインタを一つ進める。 返却値 失敗を表すため、traits::eof() を返す。 要するに buffer pointer が適切に設定されていれば、 int_type c = underflow(); if(c == traits::eof()) return c; gbump(1); return c; ということである。従って、setg()、setp() などを使って buffer 操作する のであれば、underflow() さえ実装できていれば uflow() は実装する 必要は無い。 ** pbackfail [#gcf47d00] - int_type pbackfail(int_type c = traits::eof()) 参考 basic_stream の公開関数は、gptr() がナルである場合、gptr() == eback() である場合 又は traits::eq(traits::to_char_type(c),gptr()[-1])が偽を返す場合に限って、 この仮想関数を呼ぶことができる。他の呼出しも、この制約条件を満たさなければならない。 事後条件 この関数から戻った時点で、gptr()、eback() 及び egptr() に対する制約条件は、 underflow() の場合に等しい。 返却値 失敗を表すために、traits::eof() を返す。失敗が起きるのは、次に示す場合とする。 - 入力列を戻すことができない場合。 - 何らかの原因によって、制約条件を満足するようにポインタを設定できない場合。 pbackfial() は、書き戻しが本当に失敗した場合だけ呼出される。成功を表すには、traits::eof() 以外の値を返す。 ** overflow [#jed57cd9] - int_type overflow(int_type c = traits::eof()) 効果 未解決列の先頭部にある文字の部分列を消費する。未解決列は、次に示すものの連結とする。 a) pbase() が NULL の場合、空列。そうでない場合、pbase() で始まる pptr() - pbase() 個の文字 b) traits::eq_int_type(c,traits::eof()) が真を返す場合、空列。そうでない場合、c から構成される列。 参考 メンバ関数 sputc() 及び sputn() は、実引数として与えられた文字の列を書き出す余地が バッファに存在しなかった場合、この関数を呼び出す。 要件 この関数を上書きする定義は、次に挙げる制約に従わなければならない。 1) 文字を消費することによる関連する出力列への影響は処理系定義とする。 2) r を未解決列中の消費されていない文字の個数とする。r がゼロでないときは、pbase() 及び pptr() は、pptr() - pbase() = r であり、かつ pbase() から始まる r 個の文字は、 将来、関連付けられた出力ストリームに出力しなければならない。r がゼロのとき(未解決列中の すべての文字が消費されたとき)は、pbase() が NULL に設定されるか、pbase() 及び pptr() が 同じ非 NULL 値でなければならない。 3) この関数は、関連するストリームに対する文字追加に失敗した場合、及び 2) の規則に従うように pbase() 及び pptr() を設定できなかった場合、失敗する。 返却値 この関数が失敗した場合、traits::eof() を返すか、例外を送出する。そうでない場合、 成功を表すため traits::eof() 以外の値を返す。 注:典型的には、overflow は、成功を表すために c を返す。ただし traits::eq_int_type(c,traits::eof()) が 真を返す場合には、traits::not_eof(c) を返す。 要するに少なくとも1文字分書き込み buffer を空けてくれという指示である。 実際に出力して空けるかどうかは問わないが、現在書き込み buffer に書き込まれて いる data は将来必ず順番を変えずに出力すること(実際には、ここで 出力しない場合は sync() の時に行うことになるだろう)。 - c が traits::eof() 以外の時は、空けた buffer の先頭位置に c を置いて、 次書き込み位置をその次の位置に設定する。 - c が traits::eof() の時は、空けた buffer の先頭位置を 次書き込み位置に設定する。 それを難しく言うと上のようになる。 書き込み buffer を用意していない時はどうすればよいか? - c が traits::eof() でない時は、c を出力装置へ直接送る。 - c が traits::eof() の時は何もしない。 buffer 的観点から見ると、buffer を用意したが、すぐに消費してしまったと いう振る舞い。