読者です 読者をやめる 読者になる 読者になる

catalinaの備忘録

ソフトウェアやハードウェアの備忘録。後で逆引きできるように。

boost::streambufの内部構造の調査

プログラム C++

以前書いたエントリの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
    - 未調査