diff options
author | Matus Valo <matusvalo@users.noreply.github.com> | 2022-10-08 09:30:49 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-08 08:30:49 +0100 |
commit | e1364b5a4b546be34829360d0d1471bc33c01262 (patch) | |
tree | 011ce01eac6ae8c7e6a97ddcfca0b08cc21d0e00 /docs | |
parent | 1e84f30a4a397cecb888997fc97f5c2604af0733 (diff) | |
download | cython-e1364b5a4b546be34829360d0d1471bc33c01262.tar.gz |
Docs: Migrate buffer userguide to pure python (#5069)
Diffstat (limited to 'docs')
-rw-r--r-- | docs/examples/userguide/buffer/matrix.py | 15 | ||||
-rw-r--r-- | docs/examples/userguide/buffer/matrix.pyx | 3 | ||||
-rw-r--r-- | docs/examples/userguide/buffer/matrix_with_buffer.py | 48 | ||||
-rw-r--r-- | docs/examples/userguide/buffer/matrix_with_buffer.pyx | 5 | ||||
-rw-r--r-- | docs/examples/userguide/buffer/view_count.py | 30 | ||||
-rw-r--r-- | docs/examples/userguide/buffer/view_count.pyx | 3 | ||||
-rw-r--r-- | docs/src/userguide/buffer.rst | 34 |
7 files changed, 131 insertions, 7 deletions
diff --git a/docs/examples/userguide/buffer/matrix.py b/docs/examples/userguide/buffer/matrix.py new file mode 100644 index 000000000..79a3d3f12 --- /dev/null +++ b/docs/examples/userguide/buffer/matrix.py @@ -0,0 +1,15 @@ +# distutils: language = c++ + +from cython.cimports.libcpp.vector import vector + +@cython.cclass +class Matrix: + ncols: cython.unsigned + v: vector[cython.float] + + def __cinit__(self, ncols: cython.unsigned): + self.ncols = ncols + + def add_row(self): + """Adds a row, initially zero-filled.""" + self.v.resize(self.v.size() + self.ncols) diff --git a/docs/examples/userguide/buffer/matrix.pyx b/docs/examples/userguide/buffer/matrix.pyx index ca597c2f2..f2547f6c3 100644 --- a/docs/examples/userguide/buffer/matrix.pyx +++ b/docs/examples/userguide/buffer/matrix.pyx @@ -1,9 +1,8 @@ # distutils: language = c++ -# matrix.pyx - from libcpp.vector cimport vector + cdef class Matrix: cdef unsigned ncols cdef vector[float] v diff --git a/docs/examples/userguide/buffer/matrix_with_buffer.py b/docs/examples/userguide/buffer/matrix_with_buffer.py new file mode 100644 index 000000000..34ccc6591 --- /dev/null +++ b/docs/examples/userguide/buffer/matrix_with_buffer.py @@ -0,0 +1,48 @@ +# distutils: language = c++ +from cython.cimports.cpython import Py_buffer +from cython.cimports.libcpp.vector import vector + +@cython.cclass +class Matrix: + ncols: cython.Py_ssize_t + shape: cython.Py_ssize_t[2] + strides: cython.Py_ssize_t[2] + v: vector[cython.float] + + def __cinit__(self, ncols: cython.Py_ssize_t): + self.ncols = ncols + + def add_row(self): + """Adds a row, initially zero-filled.""" + self.v.resize(self.v.size() + self.ncols) + + def __getbuffer__(self, buffer: cython.pointer(Py_buffer), flags: cython.int): + itemsize: cython.Py_ssize_t = cython.sizeof(self.v[0]) + + self.shape[0] = self.v.size() // self.ncols + self.shape[1] = self.ncols + + # Stride 1 is the distance, in bytes, between two items in a row; + # this is the distance between two adjacent items in the vector. + # Stride 0 is the distance between the first elements of adjacent rows. + self.strides[1] = cython.cast(cython.Py_ssize_t, ( + cython.cast(cython.p_char, cython.address(self.v[1])) + - cython.cast(cython.p_char, cython.address(self.v[0])) + ) + ) + self.strides[0] = self.ncols * self.strides[1] + + buffer.buf = cython.cast(cython.p_char, cython.address(self.v[0])) + buffer.format = 'f' # float + buffer.internal = cython.NULL # see References + buffer.itemsize = itemsize + buffer.len = self.v.size() * itemsize # product(shape) * itemsize + buffer.ndim = 2 + buffer.obj = self + buffer.readonly = 0 + buffer.shape = self.shape + buffer.strides = self.strides + buffer.suboffsets = cython.NULL # for pointer arrays only + + def __releasebuffer__(self, buffer: cython.pointer(Py_buffer)): + pass diff --git a/docs/examples/userguide/buffer/matrix_with_buffer.pyx b/docs/examples/userguide/buffer/matrix_with_buffer.pyx index 46af91b07..16239d199 100644 --- a/docs/examples/userguide/buffer/matrix_with_buffer.pyx +++ b/docs/examples/userguide/buffer/matrix_with_buffer.pyx @@ -1,8 +1,8 @@ # distutils: language = c++ - from cpython cimport Py_buffer from libcpp.vector cimport vector + cdef class Matrix: cdef Py_ssize_t ncols cdef Py_ssize_t shape[2] @@ -27,6 +27,9 @@ cdef class Matrix: # Stride 0 is the distance between the first elements of adjacent rows. self.strides[1] = <Py_ssize_t>( <char *>&(self.v[1]) - <char *>&(self.v[0])) + + + self.strides[0] = self.ncols * self.strides[1] buffer.buf = <char *>&(self.v[0]) diff --git a/docs/examples/userguide/buffer/view_count.py b/docs/examples/userguide/buffer/view_count.py new file mode 100644 index 000000000..6a0554abc --- /dev/null +++ b/docs/examples/userguide/buffer/view_count.py @@ -0,0 +1,30 @@ +# distutils: language = c++ + +from cython.cimports.cpython import Py_buffer +from cython.cimports.libcpp.vector import vector + +@cython.cclass +class Matrix: + + view_count: cython.int + + ncols: cython.Py_ssize_t + v: vector[cython.float] + # ... + + def __cinit__(self, ncols: cython.Py_ssize_t): + self.ncols = ncols + self.view_count = 0 + + def add_row(self): + if self.view_count > 0: + raise ValueError("can't add row while being viewed") + self.v.resize(self.v.size() + self.ncols) + + def __getbuffer__(self, buffer: cython.pointer(Py_buffer), flags: cython.int): + # ... as before + + self.view_count += 1 + + def __releasebuffer__(self, buffer: cython.pointer(Py_buffer)): + self.view_count -= 1 diff --git a/docs/examples/userguide/buffer/view_count.pyx b/docs/examples/userguide/buffer/view_count.pyx index 8027f3ee9..8c4b1d524 100644 --- a/docs/examples/userguide/buffer/view_count.pyx +++ b/docs/examples/userguide/buffer/view_count.pyx @@ -3,6 +3,7 @@ from cpython cimport Py_buffer from libcpp.vector cimport vector + cdef class Matrix: cdef int view_count @@ -26,4 +27,4 @@ cdef class Matrix: self.view_count += 1 def __releasebuffer__(self, Py_buffer *buffer): - self.view_count -= 1
\ No newline at end of file + self.view_count -= 1 diff --git a/docs/src/userguide/buffer.rst b/docs/src/userguide/buffer.rst index 08661a184..3687cf2fd 100644 --- a/docs/src/userguide/buffer.rst +++ b/docs/src/userguide/buffer.rst @@ -3,6 +3,10 @@ Implementing the buffer protocol ================================ +.. include:: + ../two-syntax-variants-used + + Cython objects can expose memory buffers to Python code by implementing the "buffer protocol". This chapter shows how to implement the protocol @@ -16,7 +20,15 @@ The following Cython/C++ code implements a matrix of floats, where the number of columns is fixed at construction time but rows can be added dynamically. -.. literalinclude:: ../../examples/userguide/buffer/matrix.pyx +.. tabs:: + + .. group-tab:: Pure Python + + .. literalinclude:: ../../examples/userguide/buffer/matrix.py + + .. group-tab:: Cython + + .. literalinclude:: ../../examples/userguide/buffer/matrix.pyx There are no methods to do anything productive with the matrices' contents. We could implement custom ``__getitem__``, ``__setitem__``, etc. for this, @@ -27,7 +39,15 @@ Implementing the buffer protocol requires adding two methods, ``__getbuffer__`` and ``__releasebuffer__``, which Cython handles specially. -.. literalinclude:: ../../examples/userguide/buffer/matrix_with_buffer.pyx +.. tabs:: + + .. group-tab:: Pure Python + + .. literalinclude:: ../../examples/userguide/buffer/matrix_with_buffer.py + + .. group-tab:: Cython + + .. literalinclude:: ../../examples/userguide/buffer/matrix_with_buffer.pyx The method ``Matrix.__getbuffer__`` fills a descriptor structure, called a ``Py_buffer``, that is defined by the Python C-API. @@ -75,7 +95,15 @@ This is where ``__releasebuffer__`` comes in. We can add a reference count to each matrix, and lock it for mutation whenever a view exists. -.. literalinclude:: ../../examples/userguide/buffer/view_count.pyx +.. tabs:: + + .. group-tab:: Pure Python + + .. literalinclude:: ../../examples/userguide/buffer/view_count.py + + .. group-tab:: Cython + + .. literalinclude:: ../../examples/userguide/buffer/view_count.pyx Flags ----- |