Protocolo de Buffer
*******************

Certos objetos disponíveis em Python envolvem o acesso a uma matriz de
memória subjacente ou * buffer >>*<<. Esses objetos incluem o built-
in: class: *bytes* e: class:` bytearray`, e alguns tipos de extensão
como: class: *array.array*. As bibliotecas de terceiros podem definir
seus próprios tipos para fins especiais, como processamento de imagem
ou análise numérica.

Embora cada um desses tipos tenha sua própria semântica, eles
compartilham a característica comum de serem suportados por um buffer
de memória possivelmente grande. É desejável, em algumas situações,
acessar esse buffer diretamente e sem cópia intermediária.

Python fornece essa facilidade no nível C sob a forma de: ref:
>>`<<buffer protocol 1 <bufferobjects>'. Este protocolo tem dois
lados:

* do lado do produtor, um tipo pode exportar uma "interface de buffer"
  que permite que objetos desse tipo exponham informações sobre o
  buffer subjacente. Esta interface é descrita na seção: ref: *buffer-
  structs*;

* do lado do consumidor, vários meios estão disponíveis para obter o
  ponteiro para os dados subjacentes de um objeto (por exemplo, um
  parâmetro de método).

Objetos simples como "bytes" e "bytearray" expõem seu buffer
subjacente em forma de byte-oriented. Outras formas são possíveis; por
exemplo, os elementos expostos por uma "array.array" podem ser valores
de vários bytes.

Um exemplo de consumidor da interface de buffer é o método:
meth:*~io.BufferedIOBase.write* de objetos de arquivo: qualquer objeto
que pode exportar uma série de bytes através da interface de buffer
pode ser gravado em um arquivo. Enquanto: "write()" só precisa de
acesso somente leitura aos conteúdos internos do objeto passado,
outros métodos, tais como "readinto()" precisam de acesso de gravação
ao conteúdo de seu argumento. A interface de buffer permite aos
objetos permitir ou rejeitar seletivamente a exportação de buffers de
leitura-gravação e somente leitura.

Existem duas maneiras para um usuário da interface de buffer adquirir
um buffer em um objeto alvo:

* chamada "PyObject_GetBuffer()" com os parâmetros certos;

* chamada "PyArg_ParseTuple()"  (ou um dos seus irmãos) com um dos
  "y*", "w*" or "s*" *format codes 1*.

Em ambos os casos, "PyBuffer_Release()" deve ser chamado quando o
buffer não é mais necessário. A falta de tal pode levar a várias
questões, tais como vazamentos de recursos.


Estrutura de Buffer
===================

As estruturas de buffer (ou simplesmente "buffers") são úteis como uma
maneira de expor os dados binários de outro objeto para o programador
Python. Eles também podem ser usados como um mecanismo  de cópia
silenciosa. Usando sua capacidade de fazer referência a um bloco de
memória, é possível expor facilmente qualquer dado ao programador
Python. A memória pode ser uma matriz grande e constante em uma
extensão C, pode ser um bloco bruto de memória para manipulação antes
de passar para uma biblioteca do sistema operacional, ou pode ser
usado para transmitir dados estruturados no formato nativo e formato
de memória .

Ao contrário da maioria dos tipos de dados expostos pelo intérprete
Python, os buffers não são ponteiros "PyObject" mas sim estruturas C
simples. Isso permite que eles sejam criados e copiados de forma muito
simples. Quando um invólucro genérico em torno de um buffer é
necessário, um objeto *memoryview 1* pode ser criado.

Para obter instruções curtas sobre como escrever um objeto exportador,
consulte *Buffer Object Structures 1*. Para obter um buffer, veja
"PyObject_GetBuffer()".

Py_buffer

   void *buf

      Um ponteiro para o início da estrutura lógica descrita pelos
      campos do buffer. Este pode ser qualquer local dentro do bloco
      de memória física subjacente do exportador. Por exemplo, com
      negativo "strides" o valor pode apontar para o final do bloco de
      memória.

      Para: termo: matrizes 'contíguas', o valor aponta para o início
      do bloco de memória.

   void *obj

      Uma nova referência ao objeto exportador. A referência é de
      propriedade do consumidor e automaticamente diminuída e definida
      como *NULL* por "PyBuffer_Release()". O campo é o equivalente ao
      valor de retorno de qualquer função C-API padrão.

      Como um caso especial, para buffers * temporários * que são
      envolvidos por "PyMemoryView_FromBuffer()" ou
      "PyBuffer_FillInfo()" este campo é *NULL*. Em geral, a
      exportação de objetos NÃO DEVE usar este esquema.

   Py_ssize_t len

      "product(shape) * itemsize". Para matrizes contíguas, este é o
      comprimento do bloco de memória subjacente. Para matrizes não
      contíguas, é o comprimento que a estrutura lógica teria se fosse
      copiado para uma representação contígua.

      Acessando "((char *)buf)[0] up to ((char *)buf)[len-1]" só é
      válido se o buffer tiver sido obtido por uma solicitação que
      garanta a contiguidade. Na maioria dos casos, esse pedido será
      "PyBUF_SIMPLE" ou  "PyBUF_WRITABLE".

   int readonly

      Um indicador de se o buffer é somente leitura. Este campo é
      controlado pelo sinalizador "PyBUF_WRITABLE".

   Py_ssize_t itemsize

      Tamanho do item em bytes de um único elemento. Igual ao valor
      de:func:*struct.calcsize* chamado valores não-NULL "format".

      Exceção importante: se um consumidor solicitar um buffer sem a
      "PyBUF_FORMAT" flag, "format" será definido como *NULL*, mas
      "itemsize"  ainda tem o valor para o formato original.

      Se "shape"  está presente, a igualdade "product(shape) *
      itemsize == len" ainda é válida e o usuário pode usar "itemsize"
      para navegar o buffer.

      Se:c:member:*~Py_buffer.shape* é *NULL* como resultado de uma
      "PyBUF_SIMPLE" ou uma solicitação "PyBUF_WRITABLE", o consumidor
      deve ignorar "itemsize" e assume "itemsize == 1".

   const char *format

      A *NUL* terminou string em :mod: sintaxe de estilo de módulo
      *struct* descrevendo o conteúdo de um único item. Se isso for
      *NULL*, ""B"" (bytes não assinados) é assumido.

      Este campo é controlado pelo sinalizador "PyBUF_FORMAT".

   int ndim

      O número de dimensões que a memória representa como uma matriz
      n-dimensional. Se for  "0", "buf" aponta para um único item que
      representa um escalar. Neste caso,
      >>:c:membro:`~Py_buffer.shape`<<, "strides" e
      :c:member:>>`<<~Py_buffer.suboffsets DEVE ser *NULL*.

      A macro "PyBUF_MAX_NDIM" limita o número máximo de dimensões a
      64. Os exportadores DEVEM respeitar esse limite, os consumidores
      de buffers multidimensionais DEVEM ser capazes de lidar com
      dimensões "PyBUF_MAX_NDIM".

   Py_ssize_t *shape

      Uma matriz de "Py_ssize_t" do comprimento "ndim" indicando a
      forma da memória como uma matriz n-dimensional. Observe que a
      forma "shape[0] * ... * shape[ndim-1] * itemsize" DEVE ser igual
      a "len".

      Os valores da forma são restritos a "shape[n] >= 0". The case
      "shape[n] == 0" requer atenção especial. Veja *arrays complexos*
      para mais informações.

      A forma de acesso a matriz é de somente leitura para o usuário.

   Py_ssize_t *strides

      Uma matriz de "Py_ssize_t" de
      comprimento:c:member:*~Py_buffer.ndim* dando o número de bytes
      para saltar para obter um novo elemento em cada dimensão.

      Os valores de Stride podem ser qualquer número inteiro. Para
      arrays regulares, os passos são geralmente positivos, mas um
      consumidor DEVE ser capaz de lidar com o caso "strides[n] <= 0".
      Veja complex arrays para mais informações.

      A matriz de passos é somente leitura para o consumidor.

   Py_ssize_t *suboffsets

      Uma matriz de "Py_ssize_t"  de comprimento "ndim". If
      "suboffsets[n] >= 0", os valores armazenados ao longo da n-ésima
      dimensão são ponteiros e o valor suboffset determina quantos
      bytes para adicionar a cada ponteiro após desreferenciar. Um
      valor de subconjunto que é negativo indica que não deve ocorrer
      desratização (caminhar em um bloco de memória contíguo).

      If all suboffsets are negative (i.e. no de-referencing is
      needed), then this field must be NULL (the default value).

      Esse tipo de representação de matriz é usado pela Python Imaging
      Library (PIL). Veja complex arrays para obter mais informações
      sobre como acessar elementos dessa matriz.a matriz.

      A matriz de subconjuntos é somente leitura para o consumidor.

   void *internal

      Isso é para uso interno pelo objeto exportador. Por exemplo,
      isso pode ser re-moldado como um número inteiro pelo exportador
      e usado para armazenar bandeiras sobre se os conjuntos de forma,
      passos e suboffsets devem ou não ser liberados quando o buffer é
      liberado. O consumidor NÃO DEVE alterar esse valor.


Tipos de solicitação do buffer
==============================

Os buffers geralmente são obtidos enviando uma solicitação de buffer
para um objeto exportador via "PyObject_GetBuffer()". Uma vez que a
complexidade da estrutura lógica da memória pode variar drasticamente,
o consumidor usa o argumento *flags* para especificar o tipo de buffer
exato que pode manipular.

Todos "Py_buffer" são inequivocamente definidos pelo tipo de
solicitação.


campos independentes do pedido
------------------------------

Os seguintes campos não são influenciados por *flags* e devem sempre
ser preenchidos com os valores corretos: "obj", "buf", "len",
"itemsize", "ndim".


apenas em formato
-----------------

   PyBUF_WRITABLE

      Controla o campo "readonly". Se configurado, o exportador DEVE
      fornecer um buffer gravável ou então reportar falha. Caso
      contrário, o exportador pode fornecer um buffer de somente
      leitura ou gravável, mas a escolha DEVE ser consistente para
      todos os consumidores.

   PyBUF_FORMAT

      Controla o campo "format". Se configurado, este campo DEVE ser
      preenchido corretamente. Caso contrário, este campo DEVE ser
      *NULL*.

:"PyBUF_WRITABLE" pode ser |'d para qualquer um dos sinalizadores na
próxima seção. Uma vez que "PyBUF_WRITABLE" é definido como 0,
"PyBUF_WRITABLE" pode ser usado como uma bandeira autônoma para
solicitar um buffer simples gravável.

"PyBUF_FORMAT" pode ser |'d para qualquer um dos sinalizadores, exceto
"PyBUF_SIMPLE". O último já implica o formato "B" (bytes não
assinados).


forma, avanços, suboffsets
--------------------------

As bandeiras que controlam a estrutura lógica da memória estão
listadas em ordem decrescente de complexidade. Observe que cada
bandeira contém todos os bits das bandeiras abaixo.

+-------------------------------+---------+-----------+--------------+
| Solicitação                   | Forma   | Avanços   | suboffsets   |
|===============================|=========|===========|==============|
| PyBUF_INDIRECT                | sim     | sim       | se           |
|                               |         |           | necessário   |
+-------------------------------+---------+-----------+--------------+
| PyBUF_STRIDES                 | sim     | sim       | NULL         |
+-------------------------------+---------+-----------+--------------+
| PyBUF_ND                      | sim     | NULL      | NULL         |
+-------------------------------+---------+-----------+--------------+
| PyBUF_SIMPLE                  | NULL    | NULL      | NULL         |
+-------------------------------+---------+-----------+--------------+


requisições contíguas
---------------------

*contiguity* do C ou Fortran podem ser explicitamente solicitadas, com
ou sem informação de avanço. Sem informação de avanço, o buffer deve
ser C-contíguo.

+-------------------------------------+---------+-----------+--------------+----------+
| Solicitação                         | Forma   | Avanços   | suboffsets   | contig   |
|=====================================|=========|===========|==============|==========|
| PyBUF_C_CONTIGUOUS                  | sim     | sim       | NULL         | C        |
+-------------------------------------+---------+-----------+--------------+----------+
| PyBUF_F_CONTIGUOUS                  | sim     | sim       | NULL         | F        |
+-------------------------------------+---------+-----------+--------------+----------+
| PyBUF_ANY_CONTIGUOUS                | sim     | sim       | NULL         | C ou F   |
+-------------------------------------+---------+-----------+--------------+----------+
| PyBUF_ND                            | sim     | NULL      | NULL         | C        |
+-------------------------------------+---------+-----------+--------------+----------+


requisições compostas
---------------------

Todas as requisições possíveis foram completamente definidas por
alguma combinação dos sinalizadores na seção anterior. Por
conveniência, o protocolo do buffer fornece combinações frequentemente
utilizadas como sinalizadores únicos.

Na seguinte tabela *U* siginifica contíguidade indefinida. O
consumidor deve chamar "PyBuffer_IsContiguous()" para determinar a
contíguidade.

+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| Solicitação                     | Forma   | Avanços   | suboffsets   | contig   | readonly   | formato  |
|=================================|=========|===========|==============|==========|============|==========|
| PyBUF_FULL                      | sim     | sim       | se           | U        | 0          | sim      |
|                                 |         |           | necessário   |          |            |          |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_FULL_RO                   | sim     | sim       | se           | U        | 1 ou 0     | sim      |
|                                 |         |           | necessário   |          |            |          |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_RECORDS                   | sim     | sim       | NULL         | U        | 0          | sim      |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_RECORDS_RO                | sim     | sim       | NULL         | U        | 1 ou 0     | sim      |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_STRIDED                   | sim     | sim       | NULL         | U        | 0          | NULL     |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_STRIDED_RO                | sim     | sim       | NULL         | U        | 1 ou 0     | NULL     |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_CONTIG                    | sim     | NULL      | NULL         | C        | 0          | NULL     |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+
| PyBUF_CONTIG_RO                 | sim     | NULL      | NULL         | C        | 1 ou 0     | NULL     |
+---------------------------------+---------+-----------+--------------+----------+------------+----------+


Arrays Complexos
================


NumPy-style: forma e avanços
----------------------------

A estrutura lógica de vetores do estilo NumPy é definida por
"itemsize", "ndim", "shape" e "strides".

If "ndim == 0", the memory location pointed to by "buf" is interpreted
as a scalar of size "itemsize". In that case, both "shape" and
"strides" are *NULL*.

If "strides" is *NULL*, the array is interpreted as a standard
n-dimensional C-array. Otherwise, the consumer must access an
n-dimensional array as follows:

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

Como notado acima, "buf" pode apontar para qualquer localização dentro
do bloco de memória em si. Um exportador pode verificar a validade de
um buffer com essa função:

   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


Estilo-PIL: forma, avanços e suboffsets
---------------------------------------

Além dos itens normais, uma matriz em estilo PIL pode conter ponteiros
que devem ser seguidos para se obter o próximo elemento em uma
dimensão. Por exemplo, a matriz tridimensional em C "char v[2][2][3]"
também pode ser vista como um vetor de 2 ponteiros para duas matrizes
bidimensionais: "char (*v[2])[2][3]". Na representação por suboffsets,
esses dois ponteiros podem ser embutidos no início de "buf", apontando
para duas matrizes "char x[2][3]" que podem estar localizadas em
qualquer lugar na memória.

Here is a function that returns a pointer to the element in an N-D
array pointed to by an N-dimensional index when there are both non-
NULL strides and suboffsets:

   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;
   }


Buffer-related functions
========================

int PyObject_CheckBuffer(PyObject *obj)

   Return "1" if *obj* supports the buffer interface otherwise "0".
   When "1" is returned, it doesn't guarantee that
   "PyObject_GetBuffer()" will succeed.  This function always
   succeeds.

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

   Send a request to *exporter* to fill in *view* as specified by
   *flags*. If the exporter cannot provide a buffer of the exact type,
   it MUST raise "PyExc_BufferError", set "view->obj" to *NULL* and
   return "-1".

   On success, fill in *view*, set "view->obj" to a new reference to
   *exporter* and return 0. In the case of chained buffer providers
   that redirect requests to a single object, "view->obj" MAY refer to
   this object instead of *exporter* (See Buffer Object Structures).

   Successful calls to "PyObject_GetBuffer()" must be paired with
   calls to "PyBuffer_Release()", similar to "malloc()" and "free()".
   Thus, after the consumer is done with the buffer,
   "PyBuffer_Release()" must be called exactly once.

void PyBuffer_Release(Py_buffer *view)

   Release the buffer *view* and decrement the reference count for
   "view->obj". This function MUST be called when the buffer is no
   longer being used, otherwise reference leaks may occur.

   It is an error to call this function on a buffer that was not
   obtained via "PyObject_GetBuffer()".

Py_ssize_t PyBuffer_SizeFromFormat(const char *)

   Return the implied "itemsize" from "format". This function is not
   yet implemented.

int PyBuffer_IsContiguous(Py_buffer *view, char order)

   Return "1" if the memory defined by the *view* is C-style (*order*
   is "'C'") or Fortran-style (*order* is "'F'") *contiguous* or
   either one (*order* is "'A'").  Return "0" otherwise.  This
   function always succeeds.

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

   Copy *len* bytes from *src* to its contiguous representation in
   *buf*. *order* can be "'C'" or "'F'" (for C-style or Fortran-style
   ordering). "0" is returned on success, "-1" on error.

   This function fails if *len* != *src->len*.

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

   Fill the *strides* array with byte-strides of a *contiguous*
   (C-style if *order* is "'C'" or Fortran-style if *order* is "'F'")
   array of the given shape with the given number of bytes per
   element.

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

   Handle buffer requests for an exporter that wants to expose *buf*
   of size *len* with writability set according to *readonly*. *buf*
   is interpreted as a sequence of unsigned bytes.

   The *flags* argument indicates the request type. This function
   always fills in *view* as specified by flags, unless *buf* has been
   designated as read-only and "PyBUF_WRITABLE" is set in *flags*.

   On success, set "view->obj" to a new reference to *exporter* and
   return 0. Otherwise, raise "PyExc_BufferError", set "view->obj" to
   *NULL* and return "-1";

   If this function is used as part of a getbufferproc, *exporter*
   MUST be set to the exporting object and *flags* must be passed
   unmodified. Otherwise, *exporter* MUST be NULL.
