RapidJSONでは、rapidjson::StreamはJSONを読み書きするための概念です。まず、用意されているストリームの使い方を示し、次に独自のストリームの作り方を説明します。
メモリーストリーム
メモリーストリームは、JSONをメモリー内へ保存します。
StringStream(入力)
StringStreamは、最も基本的な入力ストリームです。メモリー内に保存された、完全な読み取り専用のJSONを表します。rapidjson/rapidjson.hに定義されています。
これは非常によくある使い方なので、上とまったく同じ処理を行うDocument::Parse(const char*)が用意されています。
StringStreamはGenericStringStream<UTF8<> >のtypedefです。ストリームの文字集合を表すために、別のエンコーディングを使うこともできます。
StringBuffer(出力)
StringBufferは、簡単な出力ストリームです。JSON全体を書き込むためのメモリーバッファーを確保します。バッファーの取得にはGetString()を使います。
バッファーがいっぱいになると、容量を自動的に増やします。既定の容量は256文字です(UTF8では256バイト、UTF16では512バイトなど)。アロケーターと初期容量を指定できます。
既定では、StringBufferは内部アロケーターのインスタンスを作成します。
同様に、StringBufferはGenericStringBuffer<UTF8<> >のtypedefです。
ファイルストリーム
ファイルからJSONを解析する場合は、JSON全体をメモリーへ読み込み、上のStringStreamを使えます。
ただし、JSONが大きい場合やメモリーが限られる場合には、FileReadStreamを使えます。ファイルからJSONの一部だけをバッファーへ読み込み、その部分を解析します。バッファー内の文字を使い切ると、ファイルから次の部分を読み込みます。
FileReadStream(入力)
FileReadStreamは、FILEポインターを通じてファイルを読みます。バッファーは利用者が用意する必要があります。
文字列ストリームと異なり、FileReadStreamはバイトストリームなので、エンコーディングは扱いません。ファイルがUTF-8でなければ、バイトストリームをEncodedInputStreamで包めます。これはすぐ後で説明します。
ファイルだけでなく、FileReadStreamでstdinも読み取れます。
FileWriteStream(出力)
FileWriteStreamは、バッファー付きの出力ストリームです。使い方はFileReadStreamとよく似ています。
出力をstdoutへ送ることもできます。
iostreamラッパー
利用者の要望に応え、RapidJSONはstd::basic_istreamとstd::basic_ostreamの公式ラッパーを提供しています。ただし、上記の他のストリームより性能が大幅に低くなることに注意してください。
IStreamWrapper
IStreamWrapperは、std::istringstream、std::stringstream、std::ifstream、std::fstreamなど、std::istreamから派生したクラスをRapidJSONの入力ストリームへ変換します。
std::wistreamから派生したクラスには、WIStreamWrapperを使ってください。
OStreamWrapper
同様に、OStreamWrapperは、std::ostringstream、std::stringstream、std::ofstream、std::fstreamなど、std::ostreamから派生したクラスをRapidJSONの入力ストリームへ変換します。
std::wostreamから派生したクラスには、WOStreamWrapperを使ってください。
エンコーディング付きストリーム
エンコーディング付きストリーム自体はJSONを保持せず、バイトストリームを包んで基本的な符号化・復号機能を提供します。
前述のように、UTF-8のバイトストリームは直接読み取れます。ただし、UTF-16とUTF-32にはバイト順の問題があります。バイト順を正しく扱うには、読み取り時にバイトを文字(UTF-16ならwchar_tなど)へ変換し、書き込み時には文字をバイトへ変換する必要があります。
さらに、バイト順マーク(BOM)も扱う必要があります。バイトストリームから読み取るときは、BOMがあれば検出するか読み飛ばします。バイトストリームへ書き込むときは、任意でBOMを出力できます。
ストリームのエンコーディングがコンパイル時に分かる場合は、EncodedInputStreamとEncodedOutputStreamを使えます。JSONストリームがUTF-8、UTF-16LE、UTF-16BE、UTF-32LE、UTF-32BEのいずれかで、それが実行時にしか分からない場合は、AutoUTFInputStreamとAutoUTFOutputStreamを使えます。これらのストリームはrapidjson/encodedstream.hに定義されています。
これらのエンコーディング付きストリームは、ファイル以外のストリームにも適用できます。たとえば、メモリー内のファイルや独自のバイトストリームを包めます。
EncodedInputStream
EncodedInputStreamにはテンプレート引数が2つあります。第1引数は、rapidjson/encodings.hに定義されたUTF8やUTF16LEなどのEncodingクラスです。第2引数は、包むストリームのクラスです。
EncodedOutputStream
EncodedOutputStreamも同様ですが、コンストラクターにbool putBOM引数があり、出力バイトストリームへBOMを書き込むかどうかを制御します。
AutoUTFInputStream
対応するすべてのJSONエンコーディングを扱いたい場合があります。AutoUTFInputStreamは、まずBOMでエンコーディングを検出します。BOMがなければ、妥当なJSONの特徴を利用して検出します。どちらの方法でも検出できなければ、コンストラクターで指定したUTF型へフォールバックします。
文字(コード単位)は8ビット、16ビット、32ビットのいずれかになり得るため、AutoUTFInputStreamは少なくとも32ビットを保持できる文字型を必要とします。次のテンプレート引数のように、unsignedを使えます。
ストリームのエンコーディングを指定するときは、上のParseStream()のようにAutoUTF<CharType>を使います。
UTFType GetType()でUTFの種類を取得できます。HasBOM()でBOMが見つかったかどうかを確認できます。
AutoUTFOutputStream
同様に、実行時に出力エンコーディングを選ぶには、AutoUTFOutputStreamを使えます。このクラスはそれ自体で自動的というわけではありません。UTFの種類とBOMを出力するかどうかを、実行時に指定する必要があります。
AutoUTFInputStreamとAutoUTFOutputStreamは、EncodedInputStreamとEncodedOutputStreamより便利で、実行時のオーバーヘッドも少量です。
独自のストリーム
メモリーストリームやファイルストリーム以外にも、RapidJSONのAPIに適合する独自のストリームクラスを作れます。ネットワークストリームや圧縮ファイル用ストリームなどが例です。
RapidJSONはテンプレートでさまざまな型を組み合わせます。必要なインターフェースをすべて備えるクラスはストリームとして使えます。Streamのインターフェースは、rapidjson/rapidjson.hのコメントに定義されています。
入力ストリームにはPeek()、Take()、Tell()、出力ストリームにはPut()とFlush()の実装が必要です。in situ解析だけに使う特別なインターフェースとして、PutBegin()とPutEnd()があります。通常のストリームはこれらを実装しません。ただし、特定のストリームでそのインターフェースを使わなくても、ダミーの実装が必要です。そうしなければコンパイルエラーになります。
例:istreamラッパー
以下は、3つの関数だけを実装する、簡単なstd::istreamのラッパーの例です。
std::stringstreamやstd::ifstreamのインスタンスを包むために使えます。
標準ライブラリー内部のオーバーヘッドにより、この実装はRapidJSONのメモリーストリームやファイルストリームほど効率的でない場合があります。
例:ostreamラッパー
以下は、2つの関数だけを実装する、簡単なstd::istreamのラッパーの例です。
std::stringstreamやstd::ofstreamのインスタンスを包むために使えます。
標準ライブラリー内部のオーバーヘッドにより、この実装はRapidJSONのメモリーストリームやファイルストリームほど効率的でない場合があります。
まとめ
この節では、RapidJSONで利用できるストリームクラスを説明しました。メモリーストリームは単純です。JSONをファイルシステムに保存する場合、ファイルストリームによって解析・生成中に必要なメモリーを減らせます。エンコーディング付きストリームは、バイトストリームと文字ストリームの間で変換します。最後に、簡単なインターフェースで独自のストリームを作れます。