グローバルナビゲーションへ

本文へ

フッターへ

お役立ち情報Blog



<Goのパッケージ放浪記> ioパッケージに定義されている「Writerインターフェイス」について

今日は前回のReaderインターフェイスに続き、ioパッケージのWriterインターフェイスまわりを覗いていきます。

今回覗いていくソースのバージョンは「go1.14.4」です。

Writerインターフェイス

WriterインターフェイスはReaderのすぐ下で定義されています。

実装は以下のような挙動が求められています。

  • 引数に与えられた p の内容を len(p) バイトまでデータストリームに書き込む
  • 書き込んだバイト数と、書き込みを停止させる原因となったエラーを返す
    • 書き込んだバイト数は、 0 <= n <= len(p) 以下になる
  • 一時的であっても、 p の内容を変更してはいけない
  • 実装するときに p を保持してはいけない

Writerインターフェイスの実装を確認する

Writerインターフェイスの実装として今回は、bytesパッケージのBufferを調査して実装を探っていきます。

 tryGrowByReslice  grow は、書き込みされるインデックスを返してきます。 バッファーのキャパシティを確認、調整して、返された位置から最後までに p をコピーしています。

実際に両方のメソッドを確認してみます。

残りのキャパシティが書き込むバイトの要素数以上の場合、つまり、キャパシティが十分にある場合は、 b.buf の最初から、 l+n までの長さのスライスにして、 l を書き込み位置のインデックスとして返しています。
残りのキャパシティが十分の場合は、アロケートする必要がないのでスライス操作で高速に処理できることがわかります。

次はgrowメソッドを確認します。

growメソッドはバッファのサイズを伸ばして書き込むインデックスを返します。
growメソッドの内部を見ていく前に、growメソッドが利用しているメソッドや変数を確認しておきます。

Lenメソッドは、バッファのまだ読み込まれていないバイト数(以下、未読バイト数)を返します。

maxIntは、一度符号無しの32ビットもしくは64ビットの「0」からビットを反転させてビットをすべて「1」にし、符号分の最初の1ビットをシフトしたのちに、int型に変換してIntの最大数を保存しているようです。
64ビットの場合のイメージは以下のようになります。

では、growメソッドの内部を覗いていきます。 前半はバッファが空だったり先ほどの tryGrowByReslice で対応できる場合のチェックをしています。
後半からは、 tryGrowByReslice では対応できない場合、すなわちキャパシティが十分に足りない場合の処理になっているようです。

ここからは具体的にバッファのスライスの状態とその処理を見ていきます。 下の図は、「o」がキャパシティ「x」が未読バイト、「-」が既読バイトのそれぞれ1バイトを表しています。

最初の例として、c=12、l=9、m=7の場合の状態を図で表してみます。

キャパシティが12バイトあり、そのうち9バイトにデータが入っていて、7バイトまで既読の状態です。
この状態で4バイト追加しようとすると、 tryGrowByReslice では、空きのキャパシティが3バイトなので対応できません。

そこで、 n <= c/2-m が評価され true になります。

キャパシティの半分から、未読バイトを差し引いてもnより大きい場合、つまり、未読バイトと n の合計の二倍のキャパシティが残っている場合は、 既読バイトを捨て、以下のように現在の読み込み済みのインデックスから最後までをコピーしています。

この状態だと、 n バイト書き込まれても二倍のキャパシティを確保できます。

次に、 n <= c/2-m   に評価される場合を見ていきます。 この状態は、どうやってもキャパシティが十分に足らない場合です。

この場合は、既読バイトを捨ててもキャパシティが足らないので、アロケートして新たなスライスを作成しています。

まとめ

Writerインターフェイスの実装を覗いていたのですが、いつのまにかBufferの実装の調査になっていました。不思議。
このあたりから、処理の内容は理解できるが、何をしたいのかが理解できない箇所が増え、それを調べたり考えるのに時間がかかりました。

とはいえ、Bufferはバイトのスライスを直接ユーザが制御せずとも、効率よく扱えるように実装されていることがわかりましたし、Intの最大値の出し方や、キャパシティの成長方法などとても学ぶものが多かったです。 今後の実装の参考になりそうです。


この記事のカテゴリ

FOLLOW US

最新の情報をお届けします