#include <iostream.h> typedef long streampos; typedef long streamoff; class ios : virtual public unsafe_ios, public stream_MT { public: enum open_mode { in = 0x01, // 読み取りのためにオープン out = 0x02, // 書き込みのためにオープン ate = 0x04, // 最初のオープン時に EOF までシーク app = 0x08, // 追加モード: EOF にすべて追加 trunc = 0x10, // ファイルがすでに存在する場合ファイルを切り捨て nocreate = 0x20, // ファイルが存在しない場合オープンが失敗 noreplace= 0x40 // ファイルがすでに存在する場合オープンが失敗 };
// ストリームシーク方向 enum seek_dir { beg=0, cur=1, end=2 };
// 残りについては ios(3CC4) を参照...
} ;
class streambuf : public stream_MT { public: streambuf() ; streambuf(char* p, int len); void dbp() ; protected: int allocate(); char* base(); int blen(); char* eback(); char* ebuf(); char* egptr(); char* epptr(); void gbump(int n); char* gptr(); char* pbase(); void pbump(int n); char* pptr(); void setg(char* eb, char* g, char* eg); void setp(char* p, char* ep); void setb(char* b, char* eb, int a=0); int unbuffered(); void unbuffered(int);
virtual int doallocate(); virtual ~streambuf() ;
int allocate_unlocked(); char* base_unlocked(); int blen_unlocked(); char* eback_unlocked(); char* ebuf_unlocked(); char* egptr_unlocked(); char* epptr_unlocked(); void gbump_unlocked(int n); char* gptr_unlocked(); char* pbase_unlocked(); void pbump_unlocked(int n); char* pptr_unlocked(); void setg_unlocked(char* eb, char* g, char* eg); void setp_unlocked(char* p, char* ep); int unbuffered_unlocked(); void unbuffered_unlocked(int);
public: virtual int pbackfail(int c); virtual int overflow(int c=EOF); virtual int underflow(); virtual streambuf* setbuf(char* p, int len); streambuf* setbuf(unsigned char* p, in len); virtual streampos seekpos(streampos, int =ios::in|ios:out); virtual streampos seekoff(streamoff, seek_dir, int =ios::in|ios:out); virtual int sync(); };
streambuf のパブリック (public) インタフェースについては、sbufpub(3CC4) で説明しています。ここでは、使用可能なバッファークラスを派生するために必要な保護された (protected) インタフェースについて説明します。streambuf クラスは基底クラスとすることのみを目的としています。streambuf オブジェクトを構築することを目的としていません。3 つの定義済みの派生バッファークラスが提供されています。filebuf(3CC4)、ssbuf(3CC4)、stdiobuf(3CC4) を参照してください。
一般的に、ここで説明している非仮想関数は、オーバーライドすることを目的としていません。それらは低レベルバッファー管理関数を提供します。
ここでは、仮想関数について、それらの機能、およびそれらのデフォルトの動作に関して説明します。デフォルトの動作が派生バッファークラスに適切である場合、関数をオーバーライドする必要はありません。たとえば、入力ソースを持たないバッファークラスは、アンダーフロー時に EOF を返す (デフォルトの動作) 以外、何も行う必要はありません。デフォルトの動作が適切でない場合は、関数のクラス固有のバージョンを提供してください。たとえば、ファイルに接続されている入力バッファーは、アンダーフロー時にもさらにデータを読み込もうと試みるようにしてください。置き換える仮想関数は、streambuf バージョンに指定された仕様に準拠して、この動作に依存するほかの関数が機能し続けるようにしてください。
streambuf の保護された (protected) 各メンバー関数では、ロックを使用して、streambuf をマルチスレッド環境で正しく動作させることができます。
streambuf を MT-安全にすることに関係するロックを実装しない、ロックされていない一連の関数が提供されています。これらの関数は関数名に付加された接尾辞 _unlocked によって区別されます。
このコンストラクタは空の入力ストリーム用の空のバッファーを作成します。
このコンストラクタは空のバッファー、または ptr が指す位置から始まる len バイトを使用して、予約領域 (下記参照) を作成します。
コピーコンストラクタおよび代入演算子は、プライベート (private) であり、streambuf をコピーできないようにするために実装されていません。streambuf をコピーするのではなく、それへのポインタを渡すことを考えます。
streambuf のバッファーは、get 領域、put 領域、および予約領域 (バッファー領域と同じ) の 3 つの部分を持つとみなすことができます。get 領域には、入力にすぐに使用できる文字が含まれます。put 領域は、最終的な出力先によってまだ消費されていない (フラッシュされていない) 出力用に保存された文字を保持します。get および put 領域は、バラバラでも、重複させることもできます。予約領域はバッファー全体であり、get 領域と put 領域が重複しています。get および put 領域は予約領域の残りの部分に拡大できます。入力および出力操作中に、get および put 領域のサイズは、常に合計バッファーサイズの範囲内で、拡大したり縮小したりします。
バッファーとその領域は、保護された (protected) メンバー関数を介して読み取りおよび設定できるプライベート (private) ポインタ変数によって定義されます。後述のポインタは、文字間を指しているものと考えてください。つまり、ポインタは 1 つの文字を指していますが、文字の直前を指しているものと見る方が便利です。これにより、 sbufpub (3CC4) で説明されている抽象への対応関係が確立されます。
予約領域の先頭へのポインタを返します。
予約領域の終端の直後を指すポインタを返します。base() から ebuf()-1 までの領域が予約領域です。ebuf()==base() の場合、ストリームはバッファリングされません。
get 領域の先頭、つまり次にフェッチする文字 (存在する場合) へのポインタを返します。ただちに使用できる文字は、gptr() から egptr()-1 までです。egptr()<=gptr() の場合、使用できる文字はありません。
get 領域の終端の直後のポインタ、gptr() で可能な最大値を返します。
gptr() で可能な最小値を返します。文字を書き戻す (get ポインタをバックアップする) ために eback() から gptr()-1 までの領域を使用できます。eback()==gptr() の場合、書き戻し操作を試みても失敗することがあります。
put 領域の先頭、つまり、次に格納できる文字の位置へのポインタを返します。
put 領域に使用できる領域の先頭へのポインタ、pptr() で可能な最小値を返します。pbase() から pptr()-1 までの領域はバッファーに格納されているが、まだ消費されていない文字を表します。
put 領域の終端の直後のポインタ、pptr() で可能な最大値を返します。pptr() から epptr() までの領域は、フラッシュ操作なしで、文字を格納するために、すぐに使用できます。
これらの関数はポインタを設定するための唯一の方法です。各種ポインタ間の整合性を確保するため、直接アクセスすることはできません。関数へのポインタ引数は、領域 (get、put、予約) がないことを示すためにすべてゼロにしてください。ゼロ以外の等しいポインタを使用すると、正しくない動作が行われることがあります。
予約領域 (バッファー) を確立します。base() を buf に、ebuf() を end に設定します。del がゼロ以外の場合、base() が setb() への別の呼び出しによって変更されるたび、または streambuf のデストラクタが呼び出されると、バッファーが delete (削除) されます。del がゼロの場合、これらの関数によってバッファーが自動的に削除されることはありません。
get 領域を確立します。eback() を back に、gptr() を g に、および egptr() を eg に設定します。
put 領域を確立します。pptr() を p に、および epptr() を ep に設定します。
この関数は、streambuf のどの非仮想メンバーによっても呼び出されません。不特定のデフォルトのサイズの予約領域のセットアップを試みます。予約領域がすでに存在する場合、または streambuf がバッファリングされないとマークされている場合は、ゼロを返して何も行いません。それ以外の場合、仮想関数 doallocate() を呼び出すことによって領域の割り当てを試みます。成功時は 1、失敗時は EOF を返します。unbuffered() と doallocate() については、下記を参照してください。
予約領域 ebuf()-base() のサイズを char で返します。
符号付きの量 n を妥当性検査なしで get ポインタに追加します。
符号付きの量 n を妥当性検査なしで put ポインタに追加します。
streambuf は、予約領域が割り当てられているかどうかに関係なく、ストリームがバッファリングされているか、バッファリングされていないかを追跡するプライベート (private) 変数を持ちます。この変数の主な用途は allocate() によって予約領域を実際に割り当てるかどうかを制御することです。最初の形式の関数は、変数が設定されていない場合ゼロ以外、それ以外の場合ゼロを返します。2 つ目の形式では、i がゼロ以外の場合に変数を設定し、それ以外の場合にそれをクリアします。
streambuf のすべての状態変数をテキストとして、ファイル記述子 1 (標準出力) に直接書き込みます。このデータは、実装のデバッグに役立ちます。これはパブリック (public) 関数であるため、これが論理的に保護された (protected) インタフェースに含まれていても、デバッグの目的でどこでも呼び出すことができます。
これらは、前述のように、専門のバッファークラスによって再定義できるか、または再定義すべき仮想関数です。置き換える関数は、それらに依存する可能性のあるほかの関数の正しい動作を確保するため、ここに示す仕様を満たすようにしてください。このセクションではこれらの関数の基底クラスバージョンのデフォルトの動作についても説明します。
この関数は、unbuffered() がゼロで、base() がゼロの場合、allocate によって呼び出されます。適切なサイズのバッファーを使用可能にしようと試みます。成功時に、setb を呼び出して、予約領域を確立し、ゼロよりも大きい値を返す必要があります。失敗時は EOF を返します。デフォルトの動作は new を使用してバッファーを割り当てることです。
この関数は、通常 put 領域がいっぱいになり、別の文字の格納の試みが行われたときに呼び出され、文字を消費 (それらを出力にフラッシュ) します。c が EOF でない場合、overflow は、put 領域にすでに存在する文字の後ろに続く文字を格納するか、消費する必要があります。エラー時に EOF を返し、成功時にほかの任意の値を返します。基底クラスバージョンのデフォルトの動作は不定であるため、各派生クラスでは独自の overflow を定義する必要があります。派生クラスバージョンの通常のアクションは put 領域内の文字 (pbase() と pptr() の間にあるもの) を消費し、setp() を呼び出して新しい put 領域をセットアップしてから、c が EOF でない場合に (sputc() を使用して) それを格納します。
この関数は、文字 c を書き戻す試みが行われ、書き戻し領域に空きがない (つまり eback()==gptr()) 場合に呼び出されます。外部デバイスの再配置などによってこの状況を処理できる場合、pbackfail の派生クラスバージョンはそれを実行して c を返すようにしてください。何らかの理由で文字を書き戻しできない場合は、EOF を返してください。基底クラスバージョンのデフォルトの動作は、EOF を返すことです。
この関数のパラメータ、戻り値、目的については、sbufpub(3CC4) を参照してください。特に gptr() や pptr() とは対照的に、抽象 get および put ポインタは可能であればこの関数によって変更されます。派生クラスバージョンは、ストリームが再配置をサポートしていないか、何らかのエラーがあった場合は EOF を、それ以外の場合は新しい位置を返すようにしてください。基底クラスバージョンのデフォルトの動作は、EOF を返すことです。
この関数のパラメータ、戻り値、目的については、sbufpub(3CC4) を参照してください。特に gptr() や pptr() とは対照的に、抽象 get および put ポインタは可能であればこの関数によって変更されます。基底クラスバージョンのデフォルトの動作は、単に次の値を返すことです。
sbuf.seekoff( (streamoff)pos, ios::beg, mode )
これは通常、派生クラスで seekoff を実装し、基底クラス seekpos を継承すればよいことを意味します。
この関数の呼び出しは、ptr が指す位置から始まる len バイトの配列をバッファー領域として使用する要求です。ptr をゼロに、または len をゼロ以下に設定することは、バッファーなし状態を要求します。派生クラスバージョンでは、要求を無視するように選択できます。要求を受け付ける場合は sbuf のアドレス、それ以外の場合は EOF を返すようにしてください。基底クラスバージョンのデフォルトの動作は、予約領域がない場合に要求を受け取ることです。
この関数は streambuf をその実際の文字のストリームと同期させます。派生クラスバージョンでは、put 領域内のすべての文字をそれらの最終的な出力先にフラッシュし、可能であれば入力バッファー内のすべての文字をそれらの入力元に戻すようにしてください。エラー時に EOF、成功時にゼロを返すようにしてください。基底クラスバージョンのデフォルトの動作は、保留中の入力文字または出力文字がない (in_avail() と out_waiting() の両方がゼロ) 場合、ゼロを返し、それ以外の場合 EOF を返すことです。
この関数は、get 領域が空の場合に、(何らかのソースから) 入力用の文字を提供するために呼び出しますが、ほかのときでも呼び出すことができます。get 領域が空でない場合は、(get ポインタは進めずに) 先頭の文字を返すだけにしてください。get 領域が空の場合は、新しい get 領域を確立し、新しい入力があればそれを取得し、その先頭の文字を返してください。入力文字がない場合は、get 領域を空のままにして、EOF を返してください。基底クラスバージョンのデフォルトの動作は未定であるため、各派生クラスで独自の underflow を定義する必要があります。
filebuf (3CC4) , ios (3CC4) , ios.intro (3CC4) , sbufpub (3CC4) , ssbuf (3CC4) , stdiobuf (3CC4)
『C++ ライブラリリファレンス』の第 3 章「従来型の iostream ライブラリ」および第 4 章「マルチスレッド環境での従来型の iostreams ライブラリの使用」