以前書いたエントリのboost::asioの続き的なもの。
boost::streambufというものをを使うと、バッファの細かいことを意識せずにread/writeをできるので便利そうだと感じた。
ただ、コレって内部実装によって性能に大きな影響が出るんじゃないかな?という疑問から調査。
今回知りたかったポイントは
- バッファの内部構造(リングバッファ?キュー?)
- 特にキューの場合はnew/deleteのような動作がread/writeごとに走る?
結論
バッファ内部はただのリニアなメモリ。(std::vector)
これをstd::streambufの機能を使って使いまわす。
バッファは常に先頭からデータが並んでいるように管理される。
(つまり、consumeでメモリコピーを行い、残りのデータをバッファ先頭にもっていく。)
使い道としてはソケット通信とかなので、よっぽど大きなデータを転送しない限りは問題にならないと思う。
大きなデータをバッファリングしつつ使う用途では避けたほうがよさそう
(バッファリングしたデータすべてがmemmoveで移動されてしまうので。。。)
というわけで、以降はboost::streambufについての調査メモだらだらと
調査メモ
boostバージョン 1.41
/usr/include/boost/asio
streambuf.hppでの定義
typedef basic_streambuf<> streambuf
このことから、basic_streambufの調査だけ行えばよい
basic_streambufの定義
basic_streambuf
: public std::streambuf,
private noncopyable
内部バッファ
std::size_t max_size_;
std::vector<char_type, Allocator> buffer_;
basic_streambuf コンストラクタ
内部バッファbuffer_を初期化する
これは、128(buffer_delte)もしくはmax_size_の何れかの要素数をもつよう初期化される。
その後親クラス(std::streambf)のsetg, setpを呼び出し、入力シーケンスと出力シーケンスの初期化を行う。
std::streambufの入出力シーケンスの扱いは次のとおり
beginning current position end
(beginning pointers) (get/put pointer) (end pointers)
Input sequence eback gptr egptr
Output sequence pbase pptr epptr
prepare()の動作
reserve()でバッファを予約する。
output-sequenceのcurrent-positionポインタを返す。
戻り値はmutable-buffer形式(mutable-bufferの内部はpointerとsizeのpair)
commit()の動作
ポインタの計算を行い、output-sequence, input-sequenceのポインタを更新する
・output-sequenceの current-pointerを更新する
・input-sequenceの begin, current, endそれぞれのポインタを更新する
data()の動作
constバッファを構築して返す。(const_bufferの内部はconst-pointerとsizeのpair)
const-bufferの指すポインタは、input-sequenceのcurrentにセットされる
sizeはoutput_current - input_currentである。
consume()の動作
gptrを進める
reserve()の動作
Input-sequenceのcurrentが、バッファ先頭にないとき(つまり、残っているデータがある?)
memmoveでバッファ先頭へデータを移動する。
Output-sequenceの残りサイズよりも大きなバッファを要求されたときは、
resizeを行う
overflow, underflow
- 未調査