#
10.7 バッファオブジェクト構造体 (buffer object structure)

バッファインタフェースは、あるオブジェクトの内部データを一連の データチャンク (chunk) として見せるモデルを外部から利用できるようにします。 各チャンクはポインタ/データ長からなるペアで指定します。 チャンクはセグメント(segment) と呼ばれ、 メモリ内に不連続的に配置されるものと想定されています。

バッファインタフェースを利用できるようにしたくないオブジェクト では、`PyTypeObject` 構造体の `tp_as_buffer` メンバを `NULL`にしなくてはなりません。利用できるようにする場合、 `tp_as_buffer` は`PyBufferProcs` 構造体を 指さねばなりません。

注意: `PyTypeObject` 構造体の `tp_flags` メンバ の値を `0` でなく `Py_TPFLAGS_DEFAULT` に しておくことがとても重要です。この設定は、 `PyBufferProcs` 構造体に `bf_getcharbuffer` スロットが入っていることを Python ランタイムに教えます。 Python の古いバージョンには `bf_getcharbuffer` メンバが 存在しないので、古い拡張モジュールを使おうとしている新しいバージョンの Python インタプリタは、このメンバがあるかどうかテストしてから 使えるようにする必要があるのです。

`PyBufferProcs`
  バッファプロトコルの実装を定義している関数群へのポインタを 保持するのに使われる構造体です。

  最初のスロットは`bf_getreadbuffer` で、 `getreadbufferproc` 型です。 このスロットが `NULL`の場合、オブジェクトは内部データの 読み出しをサポートしません。そのような仕様には意味がないので、 実装を行う側はこのスロットに値を埋めるはずですが、呼び出し側では 非 `NULL` の値かどうかきちんと調べておくべきです。

  次のスロットは `bf_getwritebuffer` で、 `getwritebufferproc` 型です。オブジェクトが返すバッファに 対して書き込みを許可しない場合はこのスロットを`NULL` にできます。

  第三のスロットは `bf_getsegcount` で、 `getsegcountproc` 型です。このスロットは `NULL` であっては ならず、オブジェクトにいくつセグメントが入っているかを呼び出し側に 教えるために使われます。`PyString_Type` や `PyBuffer_Type` オブジェクトのような単純なオブジェクトには単一のセグメントしか入って いません。

  最後のスロットは `bf_getcharbuffer` で、 `getcharbufferproc` です。オブジェクトの `PyTypeObject` 構造体における `tp_flags` フィールドに、 `Py_TPFLAGS_HAVE_GETCHARBUFFER` ビットフラグがセットされている 場合にのみ、このスロットが存在することになります。 このスロットの使用に先立って、呼び出し側は `PyType_HasFeature()` を使ってスロットが存在するか調べねばなりません。 スロットが存在する場合、値は `NULL`のときもあり、`NULL`は オブジェクトの内容を 8 ビット文字列 として利用できない ことを示します。 このスロットに入る関数も、オブジェクトの内容を 8 ビット文字列に 変換できない場合に例外を送出することがあります。例えば、 オブジェクトが浮動小数点数を保持するように設定されたアレイの場合、 呼び出し側が `bf_getcharbuffer` を使って 8 ビット文字列 としてデータを取り出そうとすると例外を送出するようにできます。 この、内部バッファを ``テキスト'' として取り出すという概念は、 本質的にはバイナリで、文字ベースの内容を持ったオブジェクト間の 区別に使われます。

  注意: 現在のポリシでは、文字 (character) はマルチバイト文字 でもかまわないと決めているように思われます。従って、 サイズ N のバッファが N 個のキャラクタからなる とはかぎらないことになります。

`Py_TPFLAGS_HAVE_GETCHARBUFFER`
  型構造体中のフラグビットで、`bf_getcharbuffer` スロットが 既知の値になっていることを示します。このフラグビットがセット されていたとしても、オブジェクトがバッファインタフェースをサポート していることや、`bf_getcharbuffer` スロットが `NULL`でない ことを示すわけではありません。

`int (*getreadbufferproc) (PyObject *self, int segment, void **ptrptr)`
  読み出し可能なバッファセグメントへのポインタを返します。この関数は 例外を送出してもよく、送出する場合には `-1` を返さねばなりません。 segment に渡す値はゼロまたは正の値で、`bf_getsegcount` スロット関数が返すセグメント数よりも必ず小さな値でなければなりません。 成功すると、バッファメモリのサイズを返し、 `*ptrptr` を バッファメモリを指すポインタ値にセットします。

`int (*getwritebufferproc) (PyObject *self, int segment, void **ptrptr)`
  読み出し可能なバッファセグメントへのポインタを `*ptrptr` に 返し、セグメントの長さを関数の戻り値として返します。エラーによる例外の 場合には `-1` を`-1` を返さねばなりません。 オブジェクトが呼び出し専用バッファしかサポートしていない場合には `TypeError` を、segment が存在しないセグメントを 指している場合には `SystemError` を送出しなければなりません。

`int (*getsegcountproc) (PyObject *self, int *lenp)`
  バッファを構成するメモリセグメントの数を返します。 lenp が `NULL`でない場合、この関数の実装は全てのセグメント のサイズ (バイト単位) の合計値を `*lenp` を介して 報告しなければなりません。この関数呼び出しは失敗させられません。

`int (*getcharbufferproc) (PyObject *self, int segment, const char **ptrptr)`
  セグメント segment のメモリバッファを ptrptr に入れ、 メモリバッファのサイズを返します。`*ptrptr` がメモリバッファ を表す値になるようにセットされます。