buffers.pxd 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. """Python version-independent methods for C/Python buffers.
  2. This file was copied and adapted from mpi4py.
  3. Authors
  4. -------
  5. * MinRK
  6. """
  7. #-----------------------------------------------------------------------------
  8. # Copyright (c) 2010 Lisandro Dalcin
  9. # All rights reserved.
  10. # Used under BSD License: http://www.opensource.org/licenses/bsd-license.php
  11. #
  12. # Retrieval:
  13. # Jul 23, 2010 18:00 PST (r539)
  14. # http://code.google.com/p/mpi4py/source/browse/trunk/src/MPI/asbuffer.pxi
  15. #
  16. # Modifications from original:
  17. # Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
  18. #
  19. # Distributed under the terms of the New BSD License. The full license is in
  20. # the file COPYING.BSD, distributed as part of this software.
  21. #-----------------------------------------------------------------------------
  22. #-----------------------------------------------------------------------------
  23. # Python includes.
  24. #-----------------------------------------------------------------------------
  25. # get version-independent aliases:
  26. cdef extern from "pyversion_compat.h":
  27. pass
  28. # Python 3 buffer interface (PEP 3118)
  29. cdef extern from "Python.h":
  30. int PY_MAJOR_VERSION
  31. int PY_MINOR_VERSION
  32. ctypedef int Py_ssize_t
  33. ctypedef struct PyMemoryViewObject:
  34. pass
  35. ctypedef struct Py_buffer:
  36. void *buf
  37. Py_ssize_t len
  38. int readonly
  39. char *format
  40. int ndim
  41. Py_ssize_t *shape
  42. Py_ssize_t *strides
  43. Py_ssize_t *suboffsets
  44. Py_ssize_t itemsize
  45. void *internal
  46. cdef enum:
  47. PyBUF_SIMPLE
  48. PyBUF_WRITABLE
  49. PyBUF_FORMAT
  50. PyBUF_ANY_CONTIGUOUS
  51. int PyObject_CheckBuffer(object)
  52. int PyObject_GetBuffer(object, Py_buffer *, int) except -1
  53. void PyBuffer_Release(Py_buffer *)
  54. int PyBuffer_FillInfo(Py_buffer *view, object obj, void *buf,
  55. Py_ssize_t len, int readonly, int infoflags) except -1
  56. object PyMemoryView_FromBuffer(Py_buffer *info)
  57. object PyMemoryView_FromObject(object)
  58. # Python 2 buffer interface (legacy)
  59. cdef extern from "Python.h":
  60. Py_ssize_t Py_END_OF_BUFFER
  61. int PyObject_CheckReadBuffer(object)
  62. int PyObject_AsReadBuffer (object, const void **, Py_ssize_t *) except -1
  63. int PyObject_AsWriteBuffer(object, void **, Py_ssize_t *) except -1
  64. object PyBuffer_FromMemory(void *ptr, Py_ssize_t s)
  65. object PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t s)
  66. object PyBuffer_FromObject(object, Py_ssize_t offset, Py_ssize_t size)
  67. object PyBuffer_FromReadWriteObject(object, Py_ssize_t offset, Py_ssize_t size)
  68. #-----------------------------------------------------------------------------
  69. # asbuffer: C buffer from python object
  70. #-----------------------------------------------------------------------------
  71. cdef inline int memoryview_available():
  72. return PY_MAJOR_VERSION >= 3 or (PY_MAJOR_VERSION >=2 and PY_MINOR_VERSION >= 7)
  73. cdef inline int oldstyle_available():
  74. return PY_MAJOR_VERSION < 3
  75. cdef inline int check_buffer(object ob):
  76. """Version independent check for whether an object is a buffer.
  77. Parameters
  78. ----------
  79. object : object
  80. Any Python object
  81. Returns
  82. -------
  83. int : 0 if no buffer interface, 3 if newstyle buffer interface, 2 if oldstyle.
  84. """
  85. if PyObject_CheckBuffer(ob):
  86. return 3
  87. if oldstyle_available():
  88. return PyObject_CheckReadBuffer(ob) and 2
  89. return 0
  90. cdef inline object asbuffer(object ob, int writable, int format,
  91. void **base, Py_ssize_t *size,
  92. Py_ssize_t *itemsize):
  93. """Turn an object into a C buffer in a Python version-independent way.
  94. Parameters
  95. ----------
  96. ob : object
  97. The object to be turned into a buffer.
  98. Must provide a Python Buffer interface
  99. writable : int
  100. Whether the resulting buffer should be allowed to write
  101. to the object.
  102. format : int
  103. The format of the buffer. See Python buffer docs.
  104. base : void **
  105. The pointer that will be used to store the resulting C buffer.
  106. size : Py_ssize_t *
  107. The size of the buffer(s).
  108. itemsize : Py_ssize_t *
  109. The size of an item, if the buffer is non-contiguous.
  110. Returns
  111. -------
  112. An object describing the buffer format. Generally a str, such as 'B'.
  113. """
  114. cdef void *bptr = NULL
  115. cdef Py_ssize_t blen = 0, bitemlen = 0
  116. cdef Py_buffer view
  117. cdef int flags = PyBUF_SIMPLE
  118. cdef int mode = 0
  119. bfmt = None
  120. mode = check_buffer(ob)
  121. if mode == 0:
  122. raise TypeError("%r does not provide a buffer interface."%ob)
  123. if mode == 3:
  124. flags = PyBUF_ANY_CONTIGUOUS
  125. if writable:
  126. flags |= PyBUF_WRITABLE
  127. if format:
  128. flags |= PyBUF_FORMAT
  129. PyObject_GetBuffer(ob, &view, flags)
  130. bptr = view.buf
  131. blen = view.len
  132. if format:
  133. if view.format != NULL:
  134. bfmt = view.format
  135. bitemlen = view.itemsize
  136. PyBuffer_Release(&view)
  137. else: # oldstyle
  138. if writable:
  139. PyObject_AsWriteBuffer(ob, &bptr, &blen)
  140. else:
  141. PyObject_AsReadBuffer(ob, <const void **>&bptr, &blen)
  142. if format:
  143. try: # numpy.ndarray
  144. dtype = ob.dtype
  145. bfmt = dtype.char
  146. bitemlen = dtype.itemsize
  147. except AttributeError:
  148. try: # array.array
  149. bfmt = ob.typecode
  150. bitemlen = ob.itemsize
  151. except AttributeError:
  152. if isinstance(ob, bytes):
  153. bfmt = b"B"
  154. bitemlen = 1
  155. else:
  156. # nothing found
  157. bfmt = None
  158. bitemlen = 0
  159. if base: base[0] = <void *>bptr
  160. if size: size[0] = <Py_ssize_t>blen
  161. if itemsize: itemsize[0] = <Py_ssize_t>bitemlen
  162. if PY_MAJOR_VERSION >= 3 and bfmt is not None:
  163. return bfmt.decode('ascii')
  164. return bfmt
  165. cdef inline object asbuffer_r(object ob, void **base, Py_ssize_t *size):
  166. """Wrapper for standard calls to asbuffer with a readonly buffer."""
  167. asbuffer(ob, 0, 0, base, size, NULL)
  168. return ob
  169. cdef inline object asbuffer_w(object ob, void **base, Py_ssize_t *size):
  170. """Wrapper for standard calls to asbuffer with a writable buffer."""
  171. asbuffer(ob, 1, 0, base, size, NULL)
  172. return ob
  173. #------------------------------------------------------------------------------
  174. # frombuffer: python buffer/view from C buffer
  175. #------------------------------------------------------------------------------
  176. cdef inline object frombuffer_3(void *ptr, Py_ssize_t s, int readonly):
  177. """Python 3 version of frombuffer.
  178. This is the Python 3 model, but will work on Python >= 2.6. Currently,
  179. we use it only on >= 3.0.
  180. """
  181. cdef Py_buffer pybuf
  182. cdef Py_ssize_t *shape = [s]
  183. cdef str astr=""
  184. PyBuffer_FillInfo(&pybuf, astr, ptr, s, readonly, PyBUF_SIMPLE)
  185. pybuf.format = "B"
  186. pybuf.shape = shape
  187. pybuf.ndim = 1
  188. return PyMemoryView_FromBuffer(&pybuf)
  189. cdef inline object frombuffer_2(void *ptr, Py_ssize_t s, int readonly):
  190. """Python 2 version of frombuffer.
  191. This must be used for Python <= 2.6, but we use it for all Python < 3.
  192. """
  193. if oldstyle_available():
  194. if readonly:
  195. return PyBuffer_FromMemory(ptr, s)
  196. else:
  197. return PyBuffer_FromReadWriteMemory(ptr, s)
  198. else:
  199. raise NotImplementedError("Old style buffers not available.")
  200. cdef inline object frombuffer(void *ptr, Py_ssize_t s, int readonly):
  201. """Create a Python Buffer/View of a C array.
  202. Parameters
  203. ----------
  204. ptr : void *
  205. Pointer to the array to be copied.
  206. s : size_t
  207. Length of the buffer.
  208. readonly : int
  209. whether the resulting object should be allowed to write to the buffer.
  210. Returns
  211. -------
  212. Python Buffer/View of the C buffer.
  213. """
  214. # oldstyle first priority for now
  215. if oldstyle_available():
  216. return frombuffer_2(ptr, s, readonly)
  217. else:
  218. return frombuffer_3(ptr, s, readonly)
  219. cdef inline object frombuffer_r(void *ptr, Py_ssize_t s):
  220. """Wrapper for readonly view frombuffer."""
  221. return frombuffer(ptr, s, 1)
  222. cdef inline object frombuffer_w(void *ptr, Py_ssize_t s):
  223. """Wrapper for writable view frombuffer."""
  224. return frombuffer(ptr, s, 0)
  225. #------------------------------------------------------------------------------
  226. # viewfromobject: python buffer/view from python object, refcounts intact
  227. # frombuffer(asbuffer(obj)) would lose track of refs
  228. #------------------------------------------------------------------------------
  229. cdef inline object viewfromobject(object obj, int readonly):
  230. """Construct a Python Buffer/View object from another Python object.
  231. This work in a Python version independent manner.
  232. Parameters
  233. ----------
  234. obj : object
  235. The input object to be cast as a buffer
  236. readonly : int
  237. Whether the result should be prevented from overwriting the original.
  238. Returns
  239. -------
  240. Buffer/View of the original object.
  241. """
  242. if not memoryview_available():
  243. if readonly:
  244. return PyBuffer_FromObject(obj, 0, Py_END_OF_BUFFER)
  245. else:
  246. return PyBuffer_FromReadWriteObject(obj, 0, Py_END_OF_BUFFER)
  247. else:
  248. return PyMemoryView_FromObject(obj)
  249. cdef inline object viewfromobject_r(object obj):
  250. """Wrapper for readonly viewfromobject."""
  251. return viewfromobject(obj, 1)
  252. cdef inline object viewfromobject_w(object obj):
  253. """Wrapper for writable viewfromobject."""
  254. return viewfromobject(obj, 0)