バッファプロトコル (buffer Protocol)
************************************

Pythonで利用可能ないくつかのオブジェクトは、下層にあるメモリ配列または
*buffer* へのアクセスを提供します。このようなオブジェクトとして、組み
込みの "bytes" や "bytearray" 、 "array.array" のようないくつかの拡張
型が挙げられます。サードバーティのライブラリは画像処理や数値解析のよう
な特別な目的のために、それら自身の型を定義することができます。

それぞれの型はそれ自身のセマンティクスを持ちますが、おそらく大きなメモ
リバッファからなるという共通の特徴を共有します。いくつかの状況では仲介
するコピーを行うことなく直接バッファにアクセスすることが望まれます。

Pythonは buffer protocol の形式で C レベルの仕組みを提供します。このプ
ロトコルには二つの側面があります:

* 提供する側では、ある型は、そのオブジェクトの下層にあるバッファに関す
  る情報を提供できる "buffer インターフェース" をエクスポートすること
  ができます。このインターフェースは バッファオブジェクト構造体
  (buffer object structure) の節で説明します。

* 利用する側では、オブジェクトの下層にある生データへのポインタを得るい
  くつかの手段が利用できます（たとえばメソッド引数）。

"bytes" や "bytearray" などのシンプルなオブジェクトは、内部のバッファ
ーをバイト列の形式で公開します。 バイト列以外の形式も利用可能です。例
えば、 "array.array" が公開する要素はマルチバイト値になることがありま
す。

bufferインターフェースの利用者の一例は、ファイルオブジェクトの
"write()" メソッドです: bufferインターフェースを通して一連のバイト列を
提供できるどんなオブジェクトでもファイルに書き込むことができます。
"write()" は、その引数として渡されたオブジェクトの内部要素に対する読み
出し専用アクセスのみを必要としますが、 "readinto()" のような他のメソッ
ドでは、その引数の内容に対する書き込みアクセスが必要です。bufferインタ
ーフェースにより、オブジェクトは読み書き両方、読み出し専用バッファへの
アクセスを許可するかそれとも拒否するか選択することができます。

bufferインターフェースの利用者には、対象となるオブジェクトのバッファを
得る二つの方法があります:

* 正しい引数で "PyObject_GetBuffer()" を呼び出す;

* "PyArg_ParseTuple()" (またはその同族のひとつ) を "y*" 、 "w*" または
  "s*" format codes のいずれかとともに呼び出す。

どちらのケースでも、bufferが必要なくなった時に "PyBuffer_Release()" を
呼び出さなければなりません。これを怠ると、リソースリークのような様々な
問題につながる恐れがあります。


buffer 構造体
=============

バッファ構造体（または単純に "buffers"）は別のオブジェクトのバイナリデ
ータをPythonプログラマに提供するのに便利です。これはまた、ゼロコピース
ライシング機構としても使用できます。このメモリブロックを参照する機能を
使うことで、どんなデータでもとても簡単にPythonプログラマに提供すること
ができます。メモリは、C 拡張の大きな配列定数かもしれませんし、オペレー
ティングシステムライブラリに渡す前のメモリブロックかもしれませんし、構
造化データをネイティブのインメモリ形式受け渡すのに使用されるかもしれま
せん。

Pythonインタプリタによって提供される多くのデータ型とは異なり、バッファ
は "PyObject" ポインタではなく、シンプルなC 構造体です。そのため、作成
とコピーが非常に簡単に行えます。バッファの一般的なラッパーが必要なとき
は、 memoryview オブジェクトが作成されます。

エクスポートされるオブジェクトを書く方法の短い説明には、 Buffer Object
Structures を参照してください。バッファを取得するには、
"PyObject_GetBuffer()" を参照してください。

type Py_buffer

   void *buf

      バッファフィールドが表している論理構造の先頭を指すポインタ。 バ
      ッファを提供するオブジェクトの下層物理メモリブロック中のどの位置
      にもなりえます。 例えば "strides" が負だと、この値はメモリブロッ
      クの末尾かもしれません。

      *連続* 配列の場合この値はメモリブロックの先頭を指します。

   PyObject *obj

      A new reference to the exporting object. The reference is owned
      by the consumer and automatically released (i.e. reference count
      decremented) and set to "NULL" by "PyBuffer_Release()". The
      field is the equivalent of the return value of any standard
      C-API function.

      "PyMemoryView_FromBuffer()" または "PyBuffer_FillInfo()" によっ
      てラップされた *一時的な* バッファである特別なケースでは、このフ
      ィールドは "NULL" です。一般的に、エクスポートオブジェクトはこの
      方式を使用してはなりません。

   Py_ssize_t len

      "product(shape) * itemsize"。contiguous配列では、下層のメモリブ
      ロックの長さになります。非contiguous 配列では、contiguous表現に
      コピーされた場合に論理構造がもつ長さです。

      "((char *)buf)[0]" から "((char *)buf)[len-1]" の範囲へのアクセ
      スは、連続性 (contiguity) を保証するリクエストによって取得された
      バッファに対してのみ許されます。 多くの場合に、そのようなリクエ
      ストは "PyBUF_SIMPLE" または "PyBUF_WRITABLE" です。

   int readonly

      バッファが読み出し専用であるか示します。このフィールドは
      "PyBUF_WRITABLE" フラグで制御できます。

   Py_ssize_t itemsize

      要素一つ分のbyte単位のサイズ。 "struct.calcsize()" を非 "NULL"
      の "format" 値に対して呼び出した結果と同じです。

      重要な例外: 消費者が "PyBUF_FORMAT" フラグを設定することなくバッ
      ファを要求した場合、 "format" は "NULL" に設定されます。 しかし
      "itemsize" は元のフォーマットに従った値を保持します。

      "shape" が存在する場合、 "product(shape) * itemsize == len" の等
      式が守られ、利用者は "itemsize" を buffer を読むために利用できま
      す。

      "PyBUF_SIMPLE" または "PyBUF_WRITABLE" で要求した結果、 "shape"
      が "NULL" であれば、消費者は "itemsize" を無視して "itemsize ==
      1" と見なさなければなりません。

   const char *format

      要素一つ分の内容を指定する、 "struct" モジュールスタイル文法の、
      *NUL* 終端文字列。 このポインタの値が "NULL" なら、 ""B"" (符号
      無しバイト) として扱われます。

      このフィールドは "PyBUF_FORMAT" フラグによって制御されます。

   int ndim

      メモリがN次元配列を表している時の次元数。 "0" の場合、 "buf" は
      スカラ値を表す1つの要素を指しています。 この場合、 "shape",
      "strides", "suboffsets" は "NULL" でなければなりません。

      "PyBUF_MAX_NDIM" は次元数の最大値を64に制限しています。 提供側は
      この制限を尊重しなければなりません。 多次元配列の消費側は
      "PyBUF_MAX_NDIM" 次元までを扱えるようにするべきです。

   Py_ssize_t *shape

      メモリ上のN次元配列の形を示す、長さが "ndim" である "Py_ssize_t"
      の配列です。 "shape[0] * ... * shape[ndim-1] * itemsize" は
      "len" と等しくなければなりません。

      shape の値は "shape[n] >= 0" に制限されます。 "shape[n] == 0" の
      場合に特に注意が必要です。 詳細は complex arrays を参照してくだ
      さい。

      shepe (形状) 配列は利用者からは読み出し専用です。

   Py_ssize_t *strides

      各次元において新しい値を得るためにスキップするバイト数を示す、長
      さ "ndim" の "Py_ssize_t" の配列。

      ストライド値は、任意の整数を指定できます。規定の配列では、ストラ
      イドは通常でいけば有効です。しかし利用者は、"strides[n] <= 0" の
      ケースを処理することができる必要があります。詳細については
      complex arrays を参照してください。

      消費者にとって、この strides 配列は読み出し専用です。

   Py_ssize_t *suboffsets

      "Py_ssize_t" 型の要素を持つ長さ "ndim" の配列。 "suboffsets[n]
      >= 0" の場合は、 n 番目の次元に沿って保存されている値はポインタ
      で、 suboffset 値は各ポインタの参照を解決した後に何バイト加えれ
      ばいいかを示しています。 suboffset の値が負の数の場合は、ポイン
      タの参照解決は不要 (連続したメモリブロック内に直接配置されいる)
      ということになります。

      全ての suboffset が負数の場合 (つまり参照解決が不要) な場合、こ
      のフィールドは "NULL" (デフォルト値) でなければなりません。

      この種の配列表現は Python Imaging Library (PIL) で使われています
      。 このような配列で要素にアクセスする方法についてさらに詳しこと
      は complex arrays を参照してください。

      消費者にとって、suboffsets 配列は読み出し専用です。

   void *internal

      バッファを提供する側のオブジェクトが内部的に利用するための変数で
      す。例えば、提供側はこの変数に整数型をキャストして、shape,
      strides, suboffsets といった配列をバッファを開放するときに同時に
      解放するべきかどうかを管理するフラグに使うことができるでしょう。
      バッファを受け取る側は、この値を決して変更してはなりません。


バッファリクエストのタイプ
==========================

バッファは通常、 "PyObject_GetBuffer()" を使うことで、エクスポートする
オブジェクトにバッファリクエストを送ることで得られます。メモリの論理的
な構造の複雑性は多岐にわたるため、消費者は *flags* 引数を使って、自身
が扱えるバッファの種類を指定します。

"Py_buffer" の全フィールドは、リクエストの種類によって曖昧さを残さずに
定義されます。


リクエストに依存しないフィールド
--------------------------------

下記のフィールドは *flags* の影響を受けずに、常に正しい値で設定されま
す。: "obj", "buf", "len", "itemsize", "ndim".


readonly, format
----------------

   PyBUF_WRITABLE

      "readonly" フィールドを制御します。もしこのフラグが設定されてい
      る場合、exporter は、書き込み可能なバッファを提供するか、さもな
      ければ失敗を報告しなければなりません。フラグが設定されていない場
      合、exporterは、読み出し専用と書き込み可能なバッファのどちらを提
      供しても構いませんが、どちらで提供するかどうかは全ての消費者に対
      して一貫性がなければなりません。

   PyBUF_FORMAT

      "format" フィールドを制御します。もしフラグが設定されていれば、
      このフィールドを正しく埋めなければなりません。フラグが設定されて
      いなければ、このフィールドを "NULL" に設定しなければなりません。

"PyBUF_WRITABLE" は、次の節に出てくるどのフラグとも | を取ってかまいま
せん。 "PyBUF_SIMPLE" は 0 と定義されているので、 "PyBUF_WRITABLE" は
単純な書き込み可能なバッファを要求する単独のフラグとして使えます。

"PyBUF_FORMAT" は、"PyBUF_SIMPLE" 以外のどのフラグとも | を取ってかま
いません。 後者のフラグは "B" (符号なしバイト) フォーマットを既に指示
しています。


shape, strides, suboffsets
--------------------------

このフラグは、以下で複雑性が大きい順に並べたメモリの論理的な構造を制御
します。個々のフラグは、それより下に記載されたフラグのすべてのビットを
含むことに注意してください。

+-------------------------------+---------+-----------+--------------+
| リクエスト                    | shape   | strides   | suboffsets   |
|===============================|=========|===========|==============|
| PyBUF_INDIRECT                | yes     | yes       | 必要な場合   |
+-------------------------------+---------+-----------+--------------+
| PyBUF_STRIDES                 | yes     | yes       | NULL         |
+-------------------------------+---------+-----------+--------------+
| PyBUF_ND                      | yes     | NULL      | NULL         |
+-------------------------------+---------+-----------+--------------+
| PyBUF_SIMPLE                  | NULL    | NULL      | NULL         |
+-------------------------------+---------+-----------+--------------+


隣接性のリクエスト
------------------

ストライドの情報があってもなくても、C または Fortran の *連続性* が明
確に要求される可能性があります。 ストライド情報なしに、バッファーは C
と隣接している必要があります。

+-------------------------------------+---------+-----------+--------------+----------+
| リクエスト                          | shape   | strides   | suboffsets   | contig   |
|=====================================|=========|===========|==============|==========|
| PyBUF_C_CONTIGUOUS                  | yes     | yes       | NULL         | C        |
+-------------------------------------+---------+-----------+--------------+----------+
| PyBUF_F_CONTIGUOUS                  | yes     | yes       | NULL         | F        |
+-------------------------------------+---------+-----------+--------------+----------+
| PyBUF_ANY_CONTIGUOUS                | yes     | yes       | NULL         | C か F   |
+-------------------------------------+---------+-----------+--------------+----------+
| "PyBUF_ND"                          | yes     | NULL      | NULL         | C        |
+-------------------------------------+---------+-----------+--------------+----------+


複合リクエスト
--------------

有り得る全てのリクエストの値は、前の節でのフラグの組み合わせで網羅的に
定義されています。 便利なように、バッファープロトコルでは頻繁に使用さ
れる組み合わせを単一のフラグとして提供してます。

次のテーブルの *U* は連続性が未定義であることを表します。 利用者は
"PyBuffer_IsContiguous()" を呼び出して連続性を判定する必要があるでしょ
う。

+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| リクエスト                      | shape   | strides   | suboffsets   | contig   | readonly   | format   |
|=================================|=========|===========|==============|==========|============|==========|
| PyBUF_FULL                      | yes     | yes       | 必要な場合   | U        | 0          | yes      |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_FULL_RO                   | yes     | yes       | 必要な場合   | U        | 1 か 0     | yes      |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_RECORDS                   | yes     | yes       | NULL         | U        | 0          | yes      |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_RECORDS_RO                | yes     | yes       | NULL         | U        | 1 か 0     | yes      |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_STRIDED                   | yes     | yes       | NULL         | U        | 0          | NULL     |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_STRIDED_RO                | yes     | yes       | NULL         | U        | 1 か 0     | NULL     |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_CONTIG                    | yes     | NULL      | NULL         | C        | 0          | NULL     |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_CONTIG_RO                 | yes     | NULL      | NULL         | C        | 1 か 0     | NULL     |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+


複雑な配列
==========


NumPy スタイル: shape, strides
------------------------------

NumPy スタイルの配列の論理的構造は "itemsize", "ndim", "shape",
"strides" で定義されます。

"ndim == 0" の場合は、 "buf" が指すメモリの場所は、サイズが "itemsize"
のスカラ値として解釈されます。 この場合、 "shape" と "strides" の両方
とも "NULL" です。

"strides" が "NULL" の場合は、配列は標準の n 次元 C 配列として解釈され
ます。 そうでない場合は、利用者は次のように n 次元配列にアクセスしなけ
ればなりません:

   ptr = (char *)buf + indices[0] * strides[0] + ... + indices[n-1] * strides[n-1];
   item = *((typeof(item) *)ptr);

上記のように、 "buf" はメモリブロック内のどの場所でも指すことが可能で
す。エクスポーターはこの関数を使用することによってバッファの妥当性を確
認出来ます。

   def verify_structure(memlen, itemsize, ndim, shape, strides, offset):
       """Verify that the parameters represent a valid array within
          the bounds of the allocated memory:
              char *mem: start of the physical memory block
              memlen: length of the physical memory block
              offset: (char *)buf - mem
       """
       if offset % itemsize:
           return False
       if offset < 0 or offset+itemsize > memlen:
           return False
       if any(v % itemsize for v in strides):
           return False

       if ndim <= 0:
           return ndim == 0 and not shape and not strides
       if 0 in shape:
           return True

       imin = sum(strides[j]*(shape[j]-1) for j in range(ndim)
                  if strides[j] <= 0)
       imax = sum(strides[j]*(shape[j]-1) for j in range(ndim)
                  if strides[j] > 0)

       return 0 <= offset+imin and offset+imax+itemsize <= memlen


PIL スタイル: shape, strides, suboffsets
----------------------------------------

PIL スタイルの配列では通常の要素の他に、ある次元の上で次の要素を取得す
るために辿るポインタを持てます。 例えば、通常の3次元 C 配列 "char
v[2][2][3]" は、2次元配列への 2 つのポインタからなる配列 "char
(*v[2])[2][3]" と見ることもできます。 suboffset 表現では、これらの 2
つのポインタは "buf" の先頭に埋め込め、メモリのどこにでも配置できる 2
つの "char x[2][3]" 配列を指します。

次の例は、 strides も suboffsets も "NULL" でない場合の、N 次元インデ
ックスによって指されている N 次元配列内の要素へのポインタを返す関数で
す:

   void *get_item_pointer(int ndim, void *buf, Py_ssize_t *strides,
                          Py_ssize_t *suboffsets, Py_ssize_t *indices) {
       char *pointer = (char*)buf;
       int i;
       for (i = 0; i < ndim; i++) {
           pointer += strides[i] * indices[i];
           if (suboffsets[i] >=0 ) {
               pointer = *((char**)pointer) + suboffsets[i];
           }
       }
       return (void*)pointer;
   }


バッファ関連の関数
==================

int PyObject_CheckBuffer(PyObject *obj)

   *obj* がbuffer インターフェースをサポートしている場合は "1" を返し
   、そうでない場合は "0" を返します。 "1" を返したとしても、
   "PyObject_GetBuffer()" が成功することは保証されません。 この関数は
   常に成功します。

int PyObject_GetBuffer(PyObject *exporter, Py_buffer *view, int flags)

   *exporter* に *flags* で指定された方法で *view* を埋めるように要求
   します。 もし exporter が指定されたとおりにバッファを提供できない場
   合、 "PyExc_BufferError" を送出し、 "view->obj" を "NULL" に設定し
   た上で、 "-1" を返さなければなりません。

   成功したときは、 *view* を埋め、 "view->obj" に *exporter* への新し
   い参照を設定し、0を返します。チェイン状のバッファプロバイダがリクエ
   ストを単一のオブジェクトにリダイレクトするケースでは、 "view->obj"
   は *exporter* の代わりにこのオブジェクトを参照します (バッファオブ
   ジェクト構造体 を参照してください)。

   "malloc()" と "free()" のように、呼び出しに成功した
   "PyObject_GetBuffer()" と対になる "PyBuffer_Release()" の呼び出しが
   なけれなればなりません。 従って、バッファの利用が済んだら
   "PyBuffer_Release()" が厳密に1回だけ呼び出されなければなりません。

void PyBuffer_Release(Py_buffer *view)

   Release the buffer *view* and release the *strong reference* (i.e.
   decrement the reference count) to the view's supporting object,
   "view->obj". This function MUST be called when the buffer is no
   longer being used, otherwise reference leaks may occur.

   "PyObject_GetBuffer()" を通して取得していないバッファに対してこの関
   数を呼び出すのは間違いです。

Py_ssize_t PyBuffer_SizeFromFormat(const char *format)

   Return the implied "itemsize" from "format". On error, raise an
   exception and return -1.

   バージョン 3.9 で追加.

int PyBuffer_IsContiguous(Py_buffer *view, char order)

   *view* で定義されているメモリが、 C スタイル (*order* == "'C'") の
   ときか、 Fortran スタイル (*order* == "'F'") *連続* のときか、その
   いずれか (*order* == "'A'") であれば "1" を返します。 それ以外の場
   合は "0" を返します。 この関数は常に成功します。

void *PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices)

   与えられた *view* 内にある *indices* が指すメモリ領域を取得します。
   *indices* は "view->ndim" 個のインデックスからなる配列を指していな
   ければなりません。

int PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort)

   連続する *len* バイトを *buf* から *view* にコピーします。*fort* に
   は "'C'" か "'F'" を指定できます（それぞれC言語スタイルとFortranス
   タイルの順序を表します)。成功時には "0"、エラー時には "-1" を返しま
   す。

int PyBuffer_ToContiguous(void *buf, Py_buffer *src, Py_ssize_t len, char order)

   *src* から *len* バイトを連続表現で *buf* 上にコピーします。
   *order* は "'C'" または "'F'" または "'A'" (C スタイル順序または
   Fortran スタイル順序またはそれ以外) が指定できます。 成功したら "0"
   が返り、エラーなら "-1" が返ります。

   *len* != *src->len* の場合、この関数は失敗します。

void PyBuffer_FillContiguousStrides(int ndims, Py_ssize_t *shape, Py_ssize_t *strides, int itemsize, char order)

   *strides* 配列を、 *itemsize* の大きさの要素がバイト単位の、
   *shape* の形をした *連続な* (*order* が "'C'" なら C-style 、 "'F'"
   なら Fortran-style の) 多次元配列として埋める。

int PyBuffer_FillInfo(Py_buffer *view, PyObject *exporter, void *buf, Py_ssize_t len, int readonly, int flags)

   サイズが *len* の *buf* を *readonly* に従った書き込み可/不可の設定
   で公開するバッファリクエストを処理します。 *buf* は符号無しバイトの
   列として解釈されます。

   *flags* 引数はリクエストのタイプを示します。 この関数は、 *buf* が
   読み出し専用と指定されていて、 *flags* に "PyBUF_WRITABLE" が設定さ
   れていない限り、常にフラグに指定された通りに *view* を埋めます。

   成功したときは、 "view->obj" に *exporter* への新しい参照を設定し、
   0 を返します。 失敗したときは、 "PyExc_BufferError" を送出し、
   "view->obj" に "NULL" を設定し、 "-1" を返します;

   この関数を getbufferproc の一部として使う場合には、 *exporter* はエ
   クスポートするオブジェクトに設定しなければならず、さらに *flags* は
   変更せずに渡さなければなりません。 そうでない場合は、 *exporter* は
   "NULL" でなければなりません。
